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