xref: /openbmc/phosphor-ipmi-flash/tools/test/tools_pci_unittest.cpp (revision 8a9de2454aa5f2f0a2a928ff61ef53634eff6dee)
1 /*
2  * Copyright 2020 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "internal_sys_mock.hpp"
18 #include "pci.hpp"
19 #include "pciaccess_mock.hpp"
20 #include "tool_errors.hpp"
21 
22 #include <stdplus/raw.hpp>
23 
24 #include <algorithm>
25 #include <cstdlib>
26 #include <string>
27 #include <vector>
28 
29 #include <gtest/gtest.h>
30 
31 namespace host_tool
32 {
33 namespace
34 {
35 
36 using namespace std::string_literals;
37 
38 using ::testing::Assign;
39 using ::testing::ContainerEq;
40 using ::testing::DoAll;
41 using ::testing::Each;
42 using ::testing::Eq;
43 using ::testing::InSequence;
44 using ::testing::NotNull;
45 using ::testing::Return;
46 using ::testing::SetArgPointee;
47 
48 // TODO: switch to ConainerEq for C++20
49 MATCHER_P(SpanEq, s, "")
50 {
51     return arg.size() == s.size() && !memcmp(arg.data(), s.data(), s.size());
52 }
53 
54 MATCHER_P(PciIdMatch, m, "")
55 {
56     return (arg->vendor_id == m->vendor_id && arg->device_id == m->device_id &&
57             arg->subvendor_id == m->subvendor_id &&
58             arg->subdevice_id == m->subdevice_id);
59 }
60 
61 pci_device_iterator* mockIter = reinterpret_cast<pci_device_iterator*>(0x42);
62 
63 constexpr pciaddr_t mockBaseAddr = 0xdeadbeef;
64 constexpr pciaddr_t mockRegionSize = 0x20000;
65 
66 class Device
67 {
68   public:
69     virtual ~Device() = default;
70     virtual const struct pci_id_match* getMatch() const = 0;
71     virtual struct pci_device getDevice() const = 0;
72     virtual void expectSetup(PciAccessMock& pciMock,
73                              const struct pci_device& dev) const {};
74     virtual std::unique_ptr<PciBridgeIntf>
75         getBridge(PciAccess* pci, bool skipBridgeDisable = false) const = 0;
76     virtual std::string getName() const = 0;
77 };
78 
79 class NuvotonDevice : public Device
80 {
81   public:
82     const struct pci_id_match* getMatch() const override
83     {
84         return &match;
85     }
86 
87     struct pci_device getDevice() const override
88     {
89         struct pci_device dev;
90 
91         dev.vendor_id = match.vendor_id;
92         dev.device_id = match.device_id;
93 
94         dev.regions[0].is_IO = false;
95         dev.regions[0].base_addr = mockBaseAddr;
96         dev.regions[0].size = mockRegionSize;
97 
98         return dev;
99     }
100 
101     void expectSetup(PciAccessMock& pciMock,
102                      const struct pci_device& dev) const override
103     {
104         static constexpr std::uint8_t defaultVal = 0x40;
105 
106         InSequence in;
107 
108         EXPECT_CALL(pciMock,
109                     pci_device_cfg_read_u8(Eq(&dev), NotNull(), config))
110             .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0)));
111         EXPECT_CALL(pciMock, pci_device_cfg_write_u8(
112                                  Eq(&dev), defaultVal | bridgeEnabled, config))
113             .WillOnce(Return(0));
114 
115         EXPECT_CALL(pciMock,
116                     pci_device_cfg_read_u8(Eq(&dev), NotNull(), config))
117             .WillOnce(
118                 DoAll(SetArgPointee<1>(defaultVal | bridgeEnabled), Return(0)));
119         EXPECT_CALL(pciMock,
120                     pci_device_cfg_write_u8(Eq(&dev), defaultVal, config))
121             .WillOnce(Return(0));
122     }
123 
124     std::unique_ptr<PciBridgeIntf>
125         getBridge(PciAccess* pci, bool skipBridgeDisable = false) const override
126     {
127         return std::make_unique<NuvotonPciBridge>(pci, skipBridgeDisable);
128     }
129 
130     std::string getName() const override
131     {
132         return "Nuvoton"s;
133     }
134 
135     /* Offset to the config register */
136     static constexpr int config = 0x04;
137     /* Second bit determines whether bridge is enabled */
138     static constexpr std::uint8_t bridgeEnabled = 0x02;
139 
140   private:
141     static constexpr struct pci_id_match match
142     {
143         0x1050, 0x0750, PCI_MATCH_ANY, PCI_MATCH_ANY
144     };
145 };
146 
147 class AspeedDevice : public Device
148 {
149   public:
150     const struct pci_id_match* getMatch() const override
151     {
152         return &match;
153     }
154 
155     struct pci_device getDevice() const override
156     {
157         struct pci_device dev;
158 
159         dev.vendor_id = match.vendor_id;
160         dev.device_id = match.device_id;
161 
162         dev.regions[1].is_IO = false;
163         dev.regions[1].base_addr = mockBaseAddr;
164         dev.regions[1].size = mockRegionSize;
165 
166         return dev;
167     }
168 
169     std::unique_ptr<PciBridgeIntf>
170         getBridge(PciAccess* pci, bool skipBridgeDisable = false) const override
171     {
172         return std::make_unique<AspeedPciBridge>(pci, skipBridgeDisable);
173     }
174 
175     std::string getName() const override
176     {
177         return "Aspeed"s;
178     }
179 
180     /* Offset to the config region */
181     static constexpr int config = 0x0f000;
182     /* Lower bit determines whether bridge is enabled */
183     static constexpr std::uint8_t bridgeEnabled = 0x01;
184     /* Offset to the MMIO address configuration */
185     static constexpr int bridge = 0x0f004;
186 
187   private:
188     static constexpr struct pci_id_match match
189     {
190         0x1a03, 0x2000, PCI_MATCH_ANY, PCI_MATCH_ANY
191     };
192 };
193 
194 NuvotonDevice nuvotonDevice;
195 AspeedDevice aspeedDevice;
196 
197 class PciSetupTest : public testing::TestWithParam<Device*>
198 {};
199 
200 /* Handle device not found */
201 TEST_P(PciSetupTest, NotFound)
202 {
203     PciAccessMock pciMock;
204 
205     InSequence in;
206 
207     EXPECT_CALL(pciMock, pci_id_match_iterator_create(
208                              PciIdMatch(GetParam()->getMatch())))
209         .WillOnce(Return(mockIter));
210     EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
211         .WillOnce(Return(nullptr));
212     EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
213 
214     EXPECT_THROW(GetParam()->getBridge(&pciMock), NotFoundException);
215 }
216 
217 /* Test finding device but probe fails */
218 TEST_P(PciSetupTest, ProbeFail)
219 {
220     PciAccessMock pciMock;
221     struct pci_device dev;
222 
223     EXPECT_CALL(pciMock, pci_id_match_iterator_create(
224                              PciIdMatch(GetParam()->getMatch())))
225         .WillOnce(Return(mockIter));
226     EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
227         .WillOnce(Return(&dev))
228         .WillRepeatedly(Return(nullptr));
229 
230     EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev))).WillOnce(Return(EFAULT));
231 
232     EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
233 
234     EXPECT_THROW(GetParam()->getBridge(&pciMock), std::system_error);
235 }
236 
237 /* Test finding device but mapping fails */
238 TEST_P(PciSetupTest, MapFail)
239 {
240     PciAccessMock pciMock;
241     struct pci_device dev;
242 
243     EXPECT_CALL(pciMock, pci_id_match_iterator_create(
244                              PciIdMatch(GetParam()->getMatch())))
245         .WillOnce(Return(mockIter));
246     EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
247         .WillOnce(Return(&dev))
248         .WillRepeatedly(Return(nullptr));
249 
250     EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev)))
251         .WillOnce(DoAll(Assign(&dev, GetParam()->getDevice()), Return(0)));
252 
253     EXPECT_CALL(pciMock,
254                 pci_device_map_range(Eq(&dev), mockBaseAddr, mockRegionSize,
255                                      PCI_DEV_MAP_FLAG_WRITABLE, NotNull()))
256         .WillOnce(Return(EFAULT));
257 
258     EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
259 
260     EXPECT_THROW(GetParam()->getBridge(&pciMock), std::system_error);
261 }
262 
263 /* Test finding device but unmapping fails */
264 TEST_P(PciSetupTest, UnmapFail)
265 {
266     PciAccessMock pciMock;
267     struct pci_device dev;
268     std::vector<std::uint8_t> region(mockRegionSize);
269 
270     EXPECT_CALL(pciMock, pci_id_match_iterator_create(
271                              PciIdMatch(GetParam()->getMatch())))
272         .WillOnce(Return(mockIter));
273     EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
274         .WillOnce(Return(&dev))
275         .WillRepeatedly(Return(nullptr));
276 
277     EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev)))
278         .WillOnce(DoAll(Assign(&dev, GetParam()->getDevice()), Return(0)));
279 
280     EXPECT_CALL(pciMock,
281                 pci_device_map_range(Eq(&dev), mockBaseAddr, mockRegionSize,
282                                      PCI_DEV_MAP_FLAG_WRITABLE, NotNull()))
283         .WillOnce(DoAll(SetArgPointee<4>(region.data()), Return(0)));
284 
285     EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
286     EXPECT_CALL(pciMock, pci_device_unmap_range(Eq(&dev), Eq(region.data()),
287                                                 mockRegionSize))
288         .WillOnce(Return(EFAULT));
289 
290     GetParam()->expectSetup(pciMock, dev);
291     // This will print an error but not throw
292     GetParam()->getBridge(&pciMock);
293 }
294 
295 /* Create expectations on pciMock for finding device and mapping memory region
296  */
297 void expectSetup(PciAccessMock& pciMock, struct pci_device& dev, Device* param,
298                  std::uint8_t* region, bool deviceExpectations = true)
299 {
300     EXPECT_CALL(pciMock,
301                 pci_id_match_iterator_create(PciIdMatch(param->getMatch())))
302         .WillOnce(Return(mockIter));
303     EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
304         .WillOnce(Return(&dev))
305         .WillRepeatedly(Return(nullptr));
306 
307     EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev)))
308         .WillOnce(DoAll(Assign(&dev, param->getDevice()), Return(0)));
309 
310     EXPECT_CALL(pciMock,
311                 pci_device_map_range(Eq(&dev), mockBaseAddr, mockRegionSize,
312                                      PCI_DEV_MAP_FLAG_WRITABLE, NotNull()))
313         .WillOnce(DoAll(SetArgPointee<4>(region), Return(0)));
314 
315     EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
316     EXPECT_CALL(pciMock,
317                 pci_device_unmap_range(Eq(&dev), Eq(region), mockRegionSize))
318         .WillOnce(Return(0));
319 
320     if (deviceExpectations)
321         param->expectSetup(pciMock, dev);
322 }
323 
324 /* Test finding device and mapping memory region */
325 TEST_P(PciSetupTest, Success)
326 {
327     PciAccessMock pciMock;
328     struct pci_device dev;
329     std::vector<std::uint8_t> region(mockRegionSize);
330 
331     expectSetup(pciMock, dev, GetParam(), region.data());
332 
333     GetParam()->getBridge(&pciMock);
334 }
335 
336 INSTANTIATE_TEST_SUITE_P(Default, PciSetupTest,
337                          ::testing::Values(&nuvotonDevice, &aspeedDevice),
338                          [](const testing::TestParamInfo<Device*>& info) {
339                              return info.param->getName();
340                          });
341 
342 TEST(NuvotonWriteTest, TooLarge)
343 {
344     PciAccessMock pciMock;
345     struct pci_device dev;
346     std::vector<std::uint8_t> region(mockRegionSize);
347     std::vector<std::uint8_t> data(0x4001);
348 
349     expectSetup(pciMock, dev, &nuvotonDevice, region.data());
350 
351     std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock);
352     EXPECT_THROW(bridge->write(stdplus::span<std::uint8_t>(data)),
353                  ToolException);
354 }
355 
356 TEST(NuvotonWriteTest, Success)
357 {
358     PciAccessMock pciMock;
359     struct pci_device dev;
360     std::vector<std::uint8_t> region(mockRegionSize);
361     std::vector<std::uint8_t> data(0x4000);
362 
363     std::generate(data.begin(), data.end(), std::rand);
364 
365     expectSetup(pciMock, dev, &nuvotonDevice, region.data());
366 
367     std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock);
368     bridge->write(stdplus::span<std::uint8_t>(data));
369 
370     EXPECT_THAT(stdplus::span<uint8_t>(&region[0], data.size()),
371                 SpanEq(stdplus::span<uint8_t>(data)));
372 }
373 
374 TEST(NuvotonConfigureTest, Success)
375 {
376     PciAccessMock pciMock;
377     struct pci_device dev;
378     std::vector<std::uint8_t> region(mockRegionSize);
379     ipmi_flash::PciConfigResponse config{0x123bea51};
380 
381     expectSetup(pciMock, dev, &nuvotonDevice, region.data());
382 
383     std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock);
384     bridge->configure(config);
385 
386     /* No effect from calling configure(), so the whole region should be 0 */
387     EXPECT_THAT(region, Each(0));
388 }
389 
390 TEST(NuvotonDataLengthTest, Success)
391 {
392     PciAccessMock pciMock;
393     struct pci_device dev;
394     std::vector<std::uint8_t> region(mockRegionSize);
395 
396     expectSetup(pciMock, dev, &nuvotonDevice, region.data());
397 
398     std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock);
399     EXPECT_EQ(bridge->getDataLength(), 0x4000);
400 }
401 
402 /* Make sure config register is left alone if the bridge is already enabled */
403 TEST(NuvotonBridgeTest, AlreadyEnabledSuccess)
404 {
405     PciAccessMock pciMock;
406     struct pci_device dev;
407     std::vector<std::uint8_t> region(mockRegionSize);
408 
409     constexpr std::uint8_t defaultVal = 0x40;
410 
411     /* Only set standard expectations; not those from nuvotonDevice */
412     expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
413 
414     {
415         InSequence in;
416 
417         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
418                                                     NuvotonDevice::config))
419             .WillOnce(DoAll(
420                 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled),
421                 Return(0)));
422 
423         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
424                                                     NuvotonDevice::config))
425             .WillOnce(DoAll(
426                 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled),
427                 Return(0)));
428         EXPECT_CALL(pciMock, pci_device_cfg_write_u8(Eq(&dev), defaultVal,
429                                                      NuvotonDevice::config))
430             .WillOnce(Return(0));
431     }
432 
433     nuvotonDevice.getBridge(&pciMock);
434 }
435 
436 /* Read fails when attempting to setup the bridge */
437 TEST(NuvotonBridgeTest, ReadSetupFail)
438 {
439     PciAccessMock pciMock;
440     struct pci_device dev;
441     std::vector<std::uint8_t> region(mockRegionSize);
442 
443     /* Only set standard expectations; not those from nuvotonDevice */
444     expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
445 
446     EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
447                                                 NuvotonDevice::config))
448         .WillOnce(Return(EFAULT));
449 
450     EXPECT_THROW(nuvotonDevice.getBridge(&pciMock), std::system_error);
451 }
452 
453 /* Write fails when attempting to setup the bridge */
454 TEST(NuvotonBridgeTest, WriteSetupFail)
455 {
456     PciAccessMock pciMock;
457     struct pci_device dev;
458     std::vector<std::uint8_t> region(mockRegionSize);
459 
460     constexpr std::uint8_t defaultVal = 0x40;
461 
462     /* Only set standard expectations; not those from nuvotonDevice */
463     expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
464 
465     EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
466                                                 NuvotonDevice::config))
467         .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0)));
468     EXPECT_CALL(pciMock,
469                 pci_device_cfg_write_u8(
470                     Eq(&dev), defaultVal | NuvotonDevice::bridgeEnabled,
471                     NuvotonDevice::config))
472         .WillOnce(Return(EFAULT));
473 
474     EXPECT_THROW(nuvotonDevice.getBridge(&pciMock), std::system_error);
475 }
476 
477 /* Read fails when attempting to disable the bridge */
478 TEST(NuvotonBridgeTest, ReadDisableFail)
479 {
480     PciAccessMock pciMock;
481     struct pci_device dev;
482     std::vector<std::uint8_t> region(mockRegionSize);
483 
484     constexpr std::uint8_t defaultVal = 0x40;
485 
486     /* Only set standard expectations; not those from nuvotonDevice */
487     expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
488 
489     {
490         InSequence in;
491 
492         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
493                                                     NuvotonDevice::config))
494             .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0)));
495         EXPECT_CALL(pciMock,
496                     pci_device_cfg_write_u8(
497                         Eq(&dev), defaultVal | NuvotonDevice::bridgeEnabled,
498                         NuvotonDevice::config))
499             .WillOnce(Return(0));
500 
501         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
502                                                     NuvotonDevice::config))
503             .WillOnce(Return(EFAULT));
504     }
505 
506     nuvotonDevice.getBridge(&pciMock);
507 }
508 
509 /* Write fails when attempting to disable the bridge */
510 TEST(NuvotonBridgeTest, WriteDisableFail)
511 {
512     PciAccessMock pciMock;
513     struct pci_device dev;
514     std::vector<std::uint8_t> region(mockRegionSize);
515 
516     constexpr std::uint8_t defaultVal = 0x40;
517 
518     /* Only set standard expectations; not those from nuvotonDevice */
519     expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
520 
521     {
522         InSequence in;
523 
524         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
525                                                     NuvotonDevice::config))
526             .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0)));
527         EXPECT_CALL(pciMock,
528                     pci_device_cfg_write_u8(
529                         Eq(&dev), defaultVal | NuvotonDevice::bridgeEnabled,
530                         NuvotonDevice::config))
531             .WillOnce(Return(0));
532 
533         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
534                                                     NuvotonDevice::config))
535             .WillOnce(DoAll(
536                 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled),
537                 Return(0)));
538         EXPECT_CALL(pciMock, pci_device_cfg_write_u8(Eq(&dev), defaultVal,
539                                                      NuvotonDevice::config))
540             .WillOnce(Return(EFAULT));
541     }
542 
543     nuvotonDevice.getBridge(&pciMock);
544 }
545 
546 /* Make sure the bridge gets enabled when needed */
547 TEST(NuvotonBridgeTest, NotEnabledSuccess)
548 {
549     PciAccessMock pciMock;
550     struct pci_device dev;
551     std::vector<std::uint8_t> region(mockRegionSize);
552 
553     expectSetup(pciMock, dev, &nuvotonDevice, region.data());
554     nuvotonDevice.getBridge(&pciMock);
555 }
556 
557 /* Make sure it skips the disable bridge call when skipBridgeDisable is true */
558 TEST(NuvotonBridgeTest, SkipDisable)
559 {
560     PciAccessMock pciMock;
561     struct pci_device dev;
562     std::vector<std::uint8_t> region(mockRegionSize);
563 
564     constexpr std::uint8_t defaultVal = 0x40;
565 
566     /* Only set standard expectations; not those from nuvotonDevice */
567     expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
568 
569     {
570         InSequence in;
571 
572         /* Only expect call for enableBridge() */
573         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
574                                                     NuvotonDevice::config))
575             .WillOnce(DoAll(
576                 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled),
577                 Return(0)));
578     }
579 
580     /* Setting skipBridgeDisable to true */
581     nuvotonDevice.getBridge(&pciMock, true);
582 }
583 
584 TEST(AspeedWriteTest, TooLarge)
585 {
586     PciAccessMock pciMock;
587     struct pci_device dev;
588     std::vector<std::uint8_t> region(mockRegionSize);
589     std::vector<std::uint8_t> data(0x10001);
590 
591     expectSetup(pciMock, dev, &aspeedDevice, region.data());
592 
593     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
594     EXPECT_THROW(bridge->write(stdplus::span<std::uint8_t>(data)),
595                  ToolException);
596 }
597 
598 TEST(AspeedWriteTest, Success)
599 {
600     PciAccessMock pciMock;
601     struct pci_device dev;
602     std::vector<std::uint8_t> region(mockRegionSize);
603     std::vector<std::uint8_t> data(0x10000);
604 
605     std::generate(data.begin(), data.end(), std::rand);
606 
607     expectSetup(pciMock, dev, &aspeedDevice, region.data());
608 
609     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
610     bridge->write(stdplus::span<std::uint8_t>(data));
611 
612     EXPECT_THAT(stdplus::span<uint8_t>(&region[0x10000], data.size()),
613                 SpanEq(stdplus::span<uint8_t>(data)));
614 }
615 
616 TEST(AspeedConfigureTest, Success)
617 {
618     PciAccessMock pciMock;
619     struct pci_device dev;
620     std::vector<std::uint8_t> region(mockRegionSize);
621     ipmi_flash::PciConfigResponse config{0x123bea51};
622 
623     expectSetup(pciMock, dev, &aspeedDevice, region.data());
624 
625     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
626     bridge->configure(config);
627 
628     auto configSpan = stdplus::raw::asSpan<uint8_t>(config);
629     EXPECT_THAT(
630         stdplus::span<uint8_t>(&region[AspeedDevice::bridge], sizeof(config)),
631         SpanEq(configSpan));
632 }
633 
634 TEST(AspeedDataLengthTest, Success)
635 {
636     PciAccessMock pciMock;
637     struct pci_device dev;
638     std::vector<std::uint8_t> region(mockRegionSize);
639 
640     expectSetup(pciMock, dev, &aspeedDevice, region.data());
641 
642     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
643     EXPECT_EQ(bridge->getDataLength(), 0x10000);
644 }
645 
646 /* Make sure config region is left alone if the bridge is already enabled */
647 TEST(AspeedBridgeTest, AlreadyEnabledSuccess)
648 {
649     PciAccessMock pciMock;
650     struct pci_device dev;
651     std::vector<std::uint8_t> region(mockRegionSize);
652 
653     constexpr std::uint8_t defaultVal = 0x42;
654 
655     region[AspeedDevice::config] = defaultVal | AspeedDevice::bridgeEnabled;
656 
657     expectSetup(pciMock, dev, &aspeedDevice, region.data());
658 
659     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
660 
661     {
662         std::vector<std::uint8_t> enabledRegion(mockRegionSize);
663         enabledRegion[AspeedDevice::config] =
664             defaultVal | AspeedDevice::bridgeEnabled;
665         EXPECT_THAT(region, ContainerEq(enabledRegion));
666     }
667 
668     bridge.reset();
669 
670     {
671         std::vector<std::uint8_t> disabledRegion(mockRegionSize);
672         disabledRegion[AspeedDevice::config] = defaultVal;
673         EXPECT_THAT(region, ContainerEq(disabledRegion));
674     }
675 }
676 
677 /* Make sure the config region remains the same even after cleanup if
678  * skipBridgeDisable is true */
679 TEST(AspeedBridgeTest, SkipDisable)
680 {
681     PciAccessMock pciMock;
682     struct pci_device dev;
683     std::vector<std::uint8_t> region(mockRegionSize);
684 
685     constexpr std::uint8_t defaultVal = 0x42;
686 
687     region[AspeedDevice::config] = defaultVal | AspeedDevice::bridgeEnabled;
688 
689     expectSetup(pciMock, dev, &aspeedDevice, region.data());
690 
691     /* Setting skipBridgeDisable to true */
692     std::unique_ptr<PciBridgeIntf> bridge =
693         aspeedDevice.getBridge(&pciMock, true);
694 
695     {
696         std::vector<std::uint8_t> enabledRegion(mockRegionSize);
697         enabledRegion[AspeedDevice::config] =
698             defaultVal | AspeedDevice::bridgeEnabled;
699         EXPECT_THAT(region, ContainerEq(enabledRegion));
700     }
701 
702     bridge.reset();
703 
704     {
705         std::vector<std::uint8_t> disabledRegion(mockRegionSize);
706         disabledRegion[AspeedDevice::config] =
707             defaultVal | AspeedDevice::bridgeEnabled;
708         EXPECT_THAT(region, ContainerEq(disabledRegion));
709     }
710 }
711 
712 /* Make sure the bridge gets enabled when needed */
713 TEST(AspeedBridgeTest, NotEnabledSuccess)
714 {
715     PciAccessMock pciMock;
716     struct pci_device dev;
717     std::vector<std::uint8_t> region(mockRegionSize);
718 
719     constexpr std::uint8_t defaultVal = 0x42;
720 
721     region[AspeedDevice::config] = defaultVal;
722 
723     expectSetup(pciMock, dev, &aspeedDevice, region.data());
724 
725     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
726 
727     {
728         std::vector<std::uint8_t> enabledRegion(mockRegionSize);
729         enabledRegion[AspeedDevice::config] =
730             defaultVal | AspeedDevice::bridgeEnabled;
731         EXPECT_THAT(region, ContainerEq(enabledRegion));
732     }
733 
734     bridge.reset();
735 
736     {
737         std::vector<std::uint8_t> disabledRegion(mockRegionSize);
738         disabledRegion[AspeedDevice::config] = defaultVal;
739         EXPECT_THAT(region, ContainerEq(disabledRegion));
740     }
741 }
742 
743 } // namespace
744 } // namespace host_tool
745