1import os
2
3import infra.basetest
4
5
6class TestPCIUtils(infra.basetest.BRTest):
7    config = infra.basetest.BASIC_TOOLCHAIN_CONFIG + \
8        """
9        BR2_PACKAGE_PCIUTILS=y
10        BR2_TARGET_ROOTFS_CPIO=y
11        # BR2_TARGET_ROOTFS_TAR is not set
12        """
13
14    def test_run(self):
15        cpio_file = os.path.join(self.builddir, "images", "rootfs.cpio")
16
17        # Note: we add a qemu pci-testdev in order to have a stable
18        # device ID, and for writing in configuration space without
19        # interfering with the rest of the emulation. See:
20        # https://www.qemu.org/docs/master/specs/pci-testdev.html
21        self.emulator.boot(arch="armv5",
22                           kernel="builtin",
23                           options=["-initrd", cpio_file,
24                                    "-device", "pci-testdev"])
25        self.emulator.login()
26
27        # Check the program executes. This test also check that we
28        # have "lspci" from the pciutils package, rather than the
29        # busybox applet (which does not recognize the --version
30        # option)"
31        self.assertRunOk("lspci --version")
32
33        # Check few program invocations.
34        self.assertRunOk("lspci")
35        for lspci_opt in ["-t", "-n", "-v", "-vv", "-x"]:
36            self.assertRunOk(f"lspci {lspci_opt}")
37
38        # Check we can see the qemu pci-testdev.
39        # Vendor: 1b36: Red Hat, Inc.
40        # Device: 0005: QEMU PCI Test Device
41        pci_vendor_id = "1b36"
42        pci_device_id = "0005"
43        pci_dev = f"{pci_vendor_id}:{pci_device_id}"
44        cmd = f"lspci -d {pci_dev}"
45        output, exit_code = self.emulator.run(cmd)
46        self.assertEqual(exit_code, 0)
47        self.assertIn("Red Hat, Inc.", output[0])
48        self.assertIn("QEMU PCI Test Device", output[0])
49
50        # We disable INTx emulation by setting bit 10 of the COMMAND
51        # register in the configuration space. See:
52        # https://git.kernel.org/pub/scm/utils/pciutils/pciutils.git/tree/lib/header.h?h=v3.10.0#n26
53        dis_int_x = 0x400
54        data_mask = f"{hex(dis_int_x)}:{hex(dis_int_x)}"
55        cmd = f"setpci -d {pci_dev} COMMAND.w={data_mask}"
56        self.assertRunOk(cmd)
57
58        # We read back and check the value.
59        cmd = f"setpci -d {pci_dev} COMMAND.w"
60        output, exit_code = self.emulator.run(cmd)
61        read_value = int(output[0], 16)
62        self.assertEqual(exit_code, 0)
63        self.assertTrue((read_value & dis_int_x) == dis_int_x)
64
65        # We check lspci now see the disabled INTx emulation.
66        cmd = f"lspci -vv -d {pci_dev} | grep -F 'DisINTx+'"
67        self.assertRunOk(cmd)
68
69        # We re-enable the INTx emulation by clearing the bit 10.
70        data_mask = f"0x0:{hex(dis_int_x)}"
71        cmd = f"setpci -d {pci_dev} COMMAND.w={data_mask}"
72        self.assertRunOk(cmd)
73
74        # We read back and check the value, again.
75        cmd = f"setpci -d {pci_dev} COMMAND.w"
76        output, exit_code = self.emulator.run(cmd)
77        read_value = int(output[0], 16)
78        self.assertEqual(exit_code, 0)
79        self.assertTrue((read_value & dis_int_x) == 0)
80
81        # We check lspci now see the enabled INTx emulation.
82        cmd = f"lspci -vv -d {pci_dev} | grep -F 'DisINTx-'"
83        self.assertRunOk(cmd)
84