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