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