xref: /kvm-unit-tests/lib/pci.c (revision 4932b58a5ce9880c973402eff899cb8a46c38135)
1 #include <linux/pci_regs.h>
2 #include "pci.h"
3 
4 static void outl(unsigned short port, unsigned val)
5 {
6     asm volatile("outl %d0, %w1" : : "a"(val), "Nd"(port));
7 }
8 
9 static unsigned inl(unsigned short port)
10 {
11     unsigned data;
12     asm volatile("inl %w1, %d0" : "=a"(data) : "Nd"(port));
13     return data;
14 }
15 static uint32_t pci_config_read(pcidevaddr_t dev, uint8_t reg)
16 {
17     uint32_t index = reg | (dev << 8) | (0x1 << 31);
18     outl(0xCF8, index);
19     return inl(0xCFC);
20 }
21 
22 /* Scan bus look for a specific device. Only bus 0 scanned for now. */
23 pcidevaddr_t pci_find_dev(uint16_t vendor_id, uint16_t device_id)
24 {
25     unsigned dev;
26     for (dev = 0; dev < 256; ++dev) {
27     uint32_t id = pci_config_read(dev, 0);
28     if ((id & 0xFFFF) == vendor_id && (id >> 16) == device_id) {
29         return dev;
30     }
31     }
32     return PCIDEVADDR_INVALID;
33 }
34 
35 unsigned long pci_bar_addr(pcidevaddr_t dev, int bar_num)
36 {
37     uint32_t bar = pci_config_read(dev, PCI_BASE_ADDRESS_0 + bar_num * 4);
38     if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
39         return bar & PCI_BASE_ADDRESS_IO_MASK;
40     } else {
41         return bar & PCI_BASE_ADDRESS_MEM_MASK;
42     }
43 }
44 
45 bool pci_bar_is_memory(pcidevaddr_t dev, int bar_num)
46 {
47     uint32_t bar = pci_config_read(dev, PCI_BASE_ADDRESS_0 + bar_num * 4);
48     return !(bar & PCI_BASE_ADDRESS_SPACE_IO);
49 }
50 
51 bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num)
52 {
53     uint32_t bar = pci_config_read(dev, PCI_BASE_ADDRESS_0 + bar_num * 4);
54     return bar;
55 }
56