1 // Code to maintain and access the pci_device cache
2 //
3 // Copyright (C) 2008-2016  Kevin O'Connor <kevin@koconnor.net>
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6 
7 #include "malloc.h" // malloc_tmp
8 #include "output.h" // dprintf
9 #include "pci.h" // pci_config_writel
10 #include "pcidevice.h" // pci_probe_devices
11 #include "pci_regs.h" // PCI_VENDOR_ID
12 #include "romfile.h" // romfile_loadint
13 #include "stacks.h" // wait_preempt
14 #include "string.h" // memset
15 
16 struct hlist_head PCIDevices VARVERIFY32INIT;
17 int MaxPCIBus VARFSEG;
18 
19 // Find all PCI devices and populate PCIDevices linked list.
20 void
pci_probe_devices(void)21 pci_probe_devices(void)
22 {
23     dprintf(3, "PCI probe\n");
24     struct pci_device *busdevs[256];
25     memset(busdevs, 0, sizeof(busdevs));
26     struct hlist_node **pprev = &PCIDevices.first;
27     int extraroots = romfile_loadint("etc/extra-pci-roots", 0);
28     int bus = -1, lastbus = 0, rootbuses = 0, count=0;
29     while (bus < 0xff && (bus < MaxPCIBus || rootbuses < extraroots)) {
30         bus++;
31         int bdf;
32         foreachbdf(bdf, bus) {
33             // Create new pci_device struct and add to list.
34             struct pci_device *dev = malloc_tmp(sizeof(*dev));
35             if (!dev) {
36                 warn_noalloc();
37                 return;
38             }
39             memset(dev, 0, sizeof(*dev));
40             hlist_add(&dev->node, pprev);
41             pprev = &dev->node.next;
42             count++;
43 
44             // Find parent device.
45             int rootbus;
46             struct pci_device *parent = busdevs[bus];
47             if (!parent) {
48                 if (bus != lastbus)
49                     rootbuses++;
50                 lastbus = bus;
51                 rootbus = rootbuses;
52                 if (bus > MaxPCIBus)
53                     MaxPCIBus = bus;
54             } else {
55                 rootbus = parent->rootbus;
56             }
57 
58             // Populate pci_device info.
59             dev->bdf = bdf;
60             dev->parent = parent;
61             dev->rootbus = rootbus;
62             u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
63             dev->vendor = vendev & 0xffff;
64             dev->device = vendev >> 16;
65             u32 classrev = pci_config_readl(bdf, PCI_CLASS_REVISION);
66             dev->class = classrev >> 16;
67             dev->prog_if = classrev >> 8;
68             dev->revision = classrev & 0xff;
69             dev->header_type = pci_config_readb(bdf, PCI_HEADER_TYPE);
70             u8 v = dev->header_type & 0x7f;
71             if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
72                 u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
73                 dev->secondary_bus = secbus;
74                 if (secbus > bus && !busdevs[secbus])
75                     busdevs[secbus] = dev;
76                 if (secbus > MaxPCIBus)
77                     MaxPCIBus = secbus;
78             }
79             dprintf(4, "PCI device %pP (vd=%04x:%04x c=%04x)\n"
80                     , dev, dev->vendor, dev->device, dev->class);
81         }
82     }
83     dprintf(1, "Found %d PCI devices (max PCI bus is %02x)\n", count, MaxPCIBus);
84 }
85 
86 // Search for a device with the specified vendor and device ids.
87 struct pci_device *
pci_find_device(u16 vendid,u16 devid)88 pci_find_device(u16 vendid, u16 devid)
89 {
90     struct pci_device *pci;
91     foreachpci(pci) {
92         if (pci->vendor == vendid && pci->device == devid)
93             return pci;
94     }
95     return NULL;
96 }
97 
98 // Search for a device with the specified class id.
99 struct pci_device *
pci_find_class(u16 classid)100 pci_find_class(u16 classid)
101 {
102     struct pci_device *pci;
103     foreachpci(pci) {
104         if (pci->class == classid)
105             return pci;
106     }
107     return NULL;
108 }
109 
pci_init_device(const struct pci_device_id * ids,struct pci_device * pci,void * arg)110 int pci_init_device(const struct pci_device_id *ids
111                     , struct pci_device *pci, void *arg)
112 {
113     dprintf(1, "pci_init_device: vendor 0x%x device 0x%x\n",
114         pci->vendor, pci->device);
115     while (ids->vendid || ids->class_mask) {
116         if ((ids->vendid == PCI_ANY_ID || ids->vendid == pci->vendor) &&
117             (ids->devid == PCI_ANY_ID || ids->devid == pci->device) &&
118             !((ids->class ^ pci->class) & ids->class_mask)) {
119             if (ids->func)
120                 ids->func(pci, arg);
121             return 0;
122         }
123         ids++;
124     }
125     return -1;
126 }
127 
128 struct pci_device *
pci_find_init_device(const struct pci_device_id * ids,void * arg)129 pci_find_init_device(const struct pci_device_id *ids, void *arg)
130 {
131     struct pci_device *pci;
132     foreachpci(pci) {
133         if (pci_init_device(ids, pci, arg) == 0)
134             return pci;
135     }
136     return NULL;
137 }
138 
139 // Enable PCI bus-mastering (ie, DMA) support on a pci device
140 void
pci_enable_busmaster(struct pci_device * pci)141 pci_enable_busmaster(struct pci_device *pci)
142 {
143     wait_preempt();
144     pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
145     pci->have_driver = 1;
146 }
147 
148 // Verify an IO bar and return it to the caller
149 u16
pci_enable_iobar(struct pci_device * pci,u32 addr)150 pci_enable_iobar(struct pci_device *pci, u32 addr)
151 {
152     wait_preempt();
153     u32 bar = pci_config_readl(pci->bdf, addr);
154     if (!(bar & PCI_BASE_ADDRESS_SPACE_IO)) {
155         warn_internalerror();
156         return 0;
157     }
158     bar &= PCI_BASE_ADDRESS_IO_MASK;
159     if (bar == 0 || bar > 0xffff) {
160         warn_internalerror();
161         return 0;
162     }
163     pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_IO);
164     pci->have_driver = 1;
165     return bar;
166 }
167 
168 // Verify a memory bar and return it to the caller
169 void *
pci_enable_membar(struct pci_device * pci,u32 addr)170 pci_enable_membar(struct pci_device *pci, u32 addr)
171 {
172     wait_preempt();
173     u32 bar = pci_config_readl(pci->bdf, addr);
174     if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
175         warn_internalerror();
176         return NULL;
177     }
178     if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
179         u32 high = pci_config_readl(pci->bdf, addr+4);
180         if (high) {
181             dprintf(1, "Can not map memory bar over 4Gig\n");
182             return NULL;
183         }
184     }
185     bar &= PCI_BASE_ADDRESS_MEM_MASK;
186     if (bar + 4*1024*1024 < 20*1024*1024) {
187         // Bar doesn't look valid (it is in last 4M or first 16M)
188         warn_internalerror();
189         return NULL;
190     }
191     pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
192     pci->have_driver = 1;
193     return (void*)bar;
194 }
195