xref: /openbmc/phosphor-ipmi-flash/tools/test/tools_pci_unittest.cpp (revision f450486f238d6402b3ff9680ff50d2987b4f2d3d)
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     EXPECT_CALL(pciMock, pci_device_enable(Eq(&dev))).Times(1);
321 
322     if (deviceExpectations)
323         param->expectSetup(pciMock, dev);
324 }
325 
326 /* Test finding device and mapping memory region */
327 TEST_P(PciSetupTest, Success)
328 {
329     PciAccessMock pciMock;
330     struct pci_device dev;
331     std::vector<std::uint8_t> region(mockRegionSize);
332 
333     expectSetup(pciMock, dev, GetParam(), region.data());
334 
335     GetParam()->getBridge(&pciMock);
336 }
337 
338 INSTANTIATE_TEST_SUITE_P(Default, PciSetupTest,
339                          ::testing::Values(&nuvotonDevice, &aspeedDevice),
340                          [](const testing::TestParamInfo<Device*>& info) {
341                              return info.param->getName();
342                          });
343 
344 TEST(NuvotonWriteTest, TooLarge)
345 {
346     PciAccessMock pciMock;
347     struct pci_device dev;
348     std::vector<std::uint8_t> region(mockRegionSize);
349     std::vector<std::uint8_t> data(0x4001);
350 
351     expectSetup(pciMock, dev, &nuvotonDevice, region.data());
352 
353     std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock);
354     EXPECT_THROW(bridge->write(stdplus::span<std::uint8_t>(data)),
355                  ToolException);
356 }
357 
358 TEST(NuvotonWriteTest, Success)
359 {
360     PciAccessMock pciMock;
361     struct pci_device dev;
362     std::vector<std::uint8_t> region(mockRegionSize);
363     std::vector<std::uint8_t> data(0x4000);
364 
365     std::generate(data.begin(), data.end(), std::rand);
366 
367     expectSetup(pciMock, dev, &nuvotonDevice, region.data());
368 
369     std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock);
370     bridge->write(stdplus::span<std::uint8_t>(data));
371 
372     EXPECT_THAT(stdplus::span<uint8_t>(&region[0], data.size()),
373                 SpanEq(stdplus::span<uint8_t>(data)));
374 }
375 
376 TEST(NuvotonConfigureTest, Success)
377 {
378     PciAccessMock pciMock;
379     struct pci_device dev;
380     std::vector<std::uint8_t> region(mockRegionSize);
381     ipmi_flash::PciConfigResponse config{0x123bea51};
382 
383     expectSetup(pciMock, dev, &nuvotonDevice, region.data());
384 
385     std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock);
386     bridge->configure(config);
387 
388     /* No effect from calling configure(), so the whole region should be 0 */
389     EXPECT_THAT(region, Each(0));
390 }
391 
392 TEST(NuvotonDataLengthTest, Success)
393 {
394     PciAccessMock pciMock;
395     struct pci_device dev;
396     std::vector<std::uint8_t> region(mockRegionSize);
397 
398     expectSetup(pciMock, dev, &nuvotonDevice, region.data());
399 
400     std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock);
401     EXPECT_EQ(bridge->getDataLength(), 0x4000);
402 }
403 
404 /* Make sure config register is left alone if the bridge is already enabled */
405 TEST(NuvotonBridgeTest, AlreadyEnabledSuccess)
406 {
407     PciAccessMock pciMock;
408     struct pci_device dev;
409     std::vector<std::uint8_t> region(mockRegionSize);
410 
411     constexpr std::uint8_t defaultVal = 0x40;
412 
413     /* Only set standard expectations; not those from nuvotonDevice */
414     expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
415 
416     {
417         InSequence in;
418 
419         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
420                                                     NuvotonDevice::config))
421             .WillOnce(DoAll(
422                 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled),
423                 Return(0)));
424 
425         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
426                                                     NuvotonDevice::config))
427             .WillOnce(DoAll(
428                 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled),
429                 Return(0)));
430         EXPECT_CALL(pciMock, pci_device_cfg_write_u8(Eq(&dev), defaultVal,
431                                                      NuvotonDevice::config))
432             .WillOnce(Return(0));
433     }
434 
435     nuvotonDevice.getBridge(&pciMock);
436 }
437 
438 /* Read fails when attempting to setup the bridge */
439 TEST(NuvotonBridgeTest, ReadSetupFail)
440 {
441     PciAccessMock pciMock;
442     struct pci_device dev;
443     std::vector<std::uint8_t> region(mockRegionSize);
444 
445     /* Only set standard expectations; not those from nuvotonDevice */
446     expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
447 
448     EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
449                                                 NuvotonDevice::config))
450         .WillOnce(Return(EFAULT));
451 
452     EXPECT_THROW(nuvotonDevice.getBridge(&pciMock), std::system_error);
453 }
454 
455 /* Write fails when attempting to setup the bridge */
456 TEST(NuvotonBridgeTest, WriteSetupFail)
457 {
458     PciAccessMock pciMock;
459     struct pci_device dev;
460     std::vector<std::uint8_t> region(mockRegionSize);
461 
462     constexpr std::uint8_t defaultVal = 0x40;
463 
464     /* Only set standard expectations; not those from nuvotonDevice */
465     expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
466 
467     EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
468                                                 NuvotonDevice::config))
469         .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0)));
470     EXPECT_CALL(pciMock,
471                 pci_device_cfg_write_u8(
472                     Eq(&dev), defaultVal | NuvotonDevice::bridgeEnabled,
473                     NuvotonDevice::config))
474         .WillOnce(Return(EFAULT));
475 
476     EXPECT_THROW(nuvotonDevice.getBridge(&pciMock), std::system_error);
477 }
478 
479 /* Read fails when attempting to disable the bridge */
480 TEST(NuvotonBridgeTest, ReadDisableFail)
481 {
482     PciAccessMock pciMock;
483     struct pci_device dev;
484     std::vector<std::uint8_t> region(mockRegionSize);
485 
486     constexpr std::uint8_t defaultVal = 0x40;
487 
488     /* Only set standard expectations; not those from nuvotonDevice */
489     expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
490 
491     {
492         InSequence in;
493 
494         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
495                                                     NuvotonDevice::config))
496             .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0)));
497         EXPECT_CALL(pciMock,
498                     pci_device_cfg_write_u8(
499                         Eq(&dev), defaultVal | NuvotonDevice::bridgeEnabled,
500                         NuvotonDevice::config))
501             .WillOnce(Return(0));
502 
503         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
504                                                     NuvotonDevice::config))
505             .WillOnce(Return(EFAULT));
506     }
507 
508     nuvotonDevice.getBridge(&pciMock);
509 }
510 
511 /* Write fails when attempting to disable the bridge */
512 TEST(NuvotonBridgeTest, WriteDisableFail)
513 {
514     PciAccessMock pciMock;
515     struct pci_device dev;
516     std::vector<std::uint8_t> region(mockRegionSize);
517 
518     constexpr std::uint8_t defaultVal = 0x40;
519 
520     /* Only set standard expectations; not those from nuvotonDevice */
521     expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
522 
523     {
524         InSequence in;
525 
526         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
527                                                     NuvotonDevice::config))
528             .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0)));
529         EXPECT_CALL(pciMock,
530                     pci_device_cfg_write_u8(
531                         Eq(&dev), defaultVal | NuvotonDevice::bridgeEnabled,
532                         NuvotonDevice::config))
533             .WillOnce(Return(0));
534 
535         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
536                                                     NuvotonDevice::config))
537             .WillOnce(DoAll(
538                 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled),
539                 Return(0)));
540         EXPECT_CALL(pciMock, pci_device_cfg_write_u8(Eq(&dev), defaultVal,
541                                                      NuvotonDevice::config))
542             .WillOnce(Return(EFAULT));
543     }
544 
545     nuvotonDevice.getBridge(&pciMock);
546 }
547 
548 /* Make sure the bridge gets enabled when needed */
549 TEST(NuvotonBridgeTest, NotEnabledSuccess)
550 {
551     PciAccessMock pciMock;
552     struct pci_device dev;
553     std::vector<std::uint8_t> region(mockRegionSize);
554 
555     expectSetup(pciMock, dev, &nuvotonDevice, region.data());
556     nuvotonDevice.getBridge(&pciMock);
557 }
558 
559 /* Make sure it skips the disable bridge call when skipBridgeDisable is true */
560 TEST(NuvotonBridgeTest, SkipDisable)
561 {
562     PciAccessMock pciMock;
563     struct pci_device dev;
564     std::vector<std::uint8_t> region(mockRegionSize);
565 
566     constexpr std::uint8_t defaultVal = 0x40;
567 
568     /* Only set standard expectations; not those from nuvotonDevice */
569     expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
570 
571     {
572         InSequence in;
573 
574         /* Only expect call for enableBridge() */
575         EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
576                                                     NuvotonDevice::config))
577             .WillOnce(DoAll(
578                 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled),
579                 Return(0)));
580     }
581 
582     /* Setting skipBridgeDisable to true */
583     nuvotonDevice.getBridge(&pciMock, true);
584 }
585 
586 TEST(AspeedWriteTest, TooLarge)
587 {
588     PciAccessMock pciMock;
589     struct pci_device dev;
590     std::vector<std::uint8_t> region(mockRegionSize);
591     std::vector<std::uint8_t> data(0x10001);
592 
593     expectSetup(pciMock, dev, &aspeedDevice, region.data());
594 
595     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
596     EXPECT_THROW(bridge->write(stdplus::span<std::uint8_t>(data)),
597                  ToolException);
598 }
599 
600 TEST(AspeedWriteTest, Success)
601 {
602     PciAccessMock pciMock;
603     struct pci_device dev;
604     std::vector<std::uint8_t> region(mockRegionSize);
605     std::vector<std::uint8_t> data(0x10000);
606 
607     std::generate(data.begin(), data.end(), std::rand);
608 
609     expectSetup(pciMock, dev, &aspeedDevice, region.data());
610 
611     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
612     bridge->write(stdplus::span<std::uint8_t>(data));
613 
614     EXPECT_THAT(stdplus::span<uint8_t>(&region[0x10000], data.size()),
615                 SpanEq(stdplus::span<uint8_t>(data)));
616 }
617 
618 TEST(AspeedConfigureTest, Success)
619 {
620     PciAccessMock pciMock;
621     struct pci_device dev;
622     std::vector<std::uint8_t> region(mockRegionSize);
623     ipmi_flash::PciConfigResponse config{0x123bea51};
624 
625     expectSetup(pciMock, dev, &aspeedDevice, region.data());
626 
627     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
628     bridge->configure(config);
629 
630     auto configSpan = stdplus::raw::asSpan<uint8_t>(config);
631     EXPECT_THAT(
632         stdplus::span<uint8_t>(&region[AspeedDevice::bridge], sizeof(config)),
633         SpanEq(configSpan));
634 }
635 
636 TEST(AspeedDataLengthTest, Success)
637 {
638     PciAccessMock pciMock;
639     struct pci_device dev;
640     std::vector<std::uint8_t> region(mockRegionSize);
641 
642     expectSetup(pciMock, dev, &aspeedDevice, region.data());
643 
644     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
645     EXPECT_EQ(bridge->getDataLength(), 0x10000);
646 }
647 
648 /* Make sure config region is left alone if the bridge is already enabled */
649 TEST(AspeedBridgeTest, AlreadyEnabledSuccess)
650 {
651     PciAccessMock pciMock;
652     struct pci_device dev;
653     std::vector<std::uint8_t> region(mockRegionSize);
654 
655     constexpr std::uint8_t defaultVal = 0x42;
656 
657     region[AspeedDevice::config] = defaultVal | AspeedDevice::bridgeEnabled;
658 
659     expectSetup(pciMock, dev, &aspeedDevice, region.data());
660 
661     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
662 
663     {
664         std::vector<std::uint8_t> enabledRegion(mockRegionSize);
665         enabledRegion[AspeedDevice::config] =
666             defaultVal | AspeedDevice::bridgeEnabled;
667         EXPECT_THAT(region, ContainerEq(enabledRegion));
668     }
669 
670     bridge.reset();
671 
672     {
673         std::vector<std::uint8_t> disabledRegion(mockRegionSize);
674         disabledRegion[AspeedDevice::config] = defaultVal;
675         EXPECT_THAT(region, ContainerEq(disabledRegion));
676     }
677 }
678 
679 /* Make sure the config region remains the same even after cleanup if
680  * skipBridgeDisable is true */
681 TEST(AspeedBridgeTest, SkipDisable)
682 {
683     PciAccessMock pciMock;
684     struct pci_device dev;
685     std::vector<std::uint8_t> region(mockRegionSize);
686 
687     constexpr std::uint8_t defaultVal = 0x42;
688 
689     region[AspeedDevice::config] = defaultVal | AspeedDevice::bridgeEnabled;
690 
691     expectSetup(pciMock, dev, &aspeedDevice, region.data());
692 
693     /* Setting skipBridgeDisable to true */
694     std::unique_ptr<PciBridgeIntf> bridge =
695         aspeedDevice.getBridge(&pciMock, true);
696 
697     {
698         std::vector<std::uint8_t> enabledRegion(mockRegionSize);
699         enabledRegion[AspeedDevice::config] =
700             defaultVal | AspeedDevice::bridgeEnabled;
701         EXPECT_THAT(region, ContainerEq(enabledRegion));
702     }
703 
704     bridge.reset();
705 
706     {
707         std::vector<std::uint8_t> disabledRegion(mockRegionSize);
708         disabledRegion[AspeedDevice::config] =
709             defaultVal | AspeedDevice::bridgeEnabled;
710         EXPECT_THAT(region, ContainerEq(disabledRegion));
711     }
712 }
713 
714 /* Make sure the bridge gets enabled when needed */
715 TEST(AspeedBridgeTest, NotEnabledSuccess)
716 {
717     PciAccessMock pciMock;
718     struct pci_device dev;
719     std::vector<std::uint8_t> region(mockRegionSize);
720 
721     constexpr std::uint8_t defaultVal = 0x42;
722 
723     region[AspeedDevice::config] = defaultVal;
724 
725     expectSetup(pciMock, dev, &aspeedDevice, region.data());
726 
727     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
728 
729     {
730         std::vector<std::uint8_t> enabledRegion(mockRegionSize);
731         enabledRegion[AspeedDevice::config] =
732             defaultVal | AspeedDevice::bridgeEnabled;
733         EXPECT_THAT(region, ContainerEq(enabledRegion));
734     }
735 
736     bridge.reset();
737 
738     {
739         std::vector<std::uint8_t> disabledRegion(mockRegionSize);
740         disabledRegion[AspeedDevice::config] = defaultVal;
741         EXPECT_THAT(region, ContainerEq(disabledRegion));
742     }
743 }
744 
745 } // namespace
746 } // namespace host_tool
747