1 /* Copyright (c) 2009, 2010 The Regents of the University of California
2 * See LICENSE for details.
4 * Barret Rhoden <brho@cs.berkeley.edu>
5 * Original by Paul Pearce <pearce@eecs.berkeley.edu> */
14 #include <arch/pci_defs.h>
16 /* List of all discovered devices */
17 struct pcidev_stailq pci_devices = STAILQ_HEAD_INITIALIZER(pci_devices);
19 static char STD_PCI_DEV[] = "Standard PCI Device";
20 static char PCI2PCI[] = "PCI-to-PCI Bridge";
21 static char PCI2CARDBUS[] = "PCI-Cardbus Bridge";
23 /* memory bars have a little dance you go through to detect what the size of the
24 * memory region is. for 64 bit bars, i'm assuming you only need to do this to
25 * the lower part (no device will need > 4GB, right?). */
26 uint32_t pci_membar_get_sz(struct pci_device *pcidev, int bar)
28 /* save the old value, write all 1s, invert, add 1, restore.
29 * http://wiki.osdev.org/PCI for details. */
30 uint8_t bar_off = PCI_BAR0_STD + bar * PCI_BAR_OFF;
31 uint32_t old_val = pcidev_read32(pcidev, bar_off);
33 pcidev_write32(pcidev, bar_off, 0xffffffff);
34 /* Don't forget to mask the lower 3 bits! */
35 retval = pcidev_read32(pcidev, bar_off) & PCI_BAR_MEM_MASK;
37 pcidev_write32(pcidev, bar_off, old_val);
41 /* process the bars. these will tell us what address space (PIO or memory) and
42 * where the base is. fills results into pcidev. i don't know if you can have
43 * multiple bars with conflicting/different regions (like two separate PIO
44 * ranges). I'm assuming you don't, and will warn if we see one. */
45 static void pci_handle_bars(struct pci_device *pcidev)
47 /* only handling standards for now */
49 int max_bars = pcidev->header_type == STD_PCI_DEV ? MAX_PCI_BAR : 0;
50 for (int i = 0; i < max_bars; i++) {
51 bar_val = pci_getbar(pcidev, i);
52 pcidev->bar[i].raw_bar = bar_val;
53 if (!bar_val) /* (0 denotes no valid data) */
55 if (pci_is_iobar(bar_val)) {
56 pcidev->bar[i].pio_base = pci_getiobar32(bar_val);
58 if (pci_is_membar32(bar_val)) {
59 pcidev->bar[i].mmio_base32 = bar_val & PCI_BAR_MEM_MASK;
60 pcidev->bar[i].mmio_sz = pci_membar_get_sz(pcidev, i);
61 } else if (pci_is_membar64(bar_val)) {
62 /* 64 bit, the lower 32 are in this bar, the upper
63 * are in the next bar */
64 pcidev->bar[i].mmio_base64 = bar_val & PCI_BAR_MEM_MASK;
65 assert(i < max_bars - 1);
66 bar_val = pci_getbar(pcidev, i + 1); /* read next bar */
67 /* note we don't check for IO or memsize. the entire next bar
68 * is supposed to be for the upper 32 bits. */
69 pcidev->bar[i].mmio_base64 |= (uint64_t)bar_val << 32;
70 pcidev->bar[i].mmio_sz = pci_membar_get_sz(pcidev, i);
74 /* this will track the maximum bar we've had. it'll include the 64 bit
75 * uppers, as well as devices that have only higher numbered bars. */
76 pcidev->nr_bars = i + 1;
80 /* Scans the PCI bus. Won't actually work for anything other than bus 0, til we
81 * sort out how to handle bridge devices. */
84 uint16_t dev_id, ven_id;
85 struct pci_device *pcidev;
86 for (int i = 0; i < PCI_MAX_BUS - 1; i++) /* phantoms at 0xff */
87 for (int j = 0; j < PCI_MAX_DEV; j++)
88 for (int k = 0; k < PCI_MAX_FUNC; k++) {
89 result = pci_read32(i, j, k, PCI_DEV_VEND_REG);
90 dev_id = result >> PCI_DEVICE_OFFSET;
91 ven_id = result & PCI_VENDOR_MASK;
92 /* Skip invalid IDs (not a device) */
93 if (ven_id == INVALID_VENDOR_ID)
95 pcidev = kzmalloc(sizeof(struct pci_device), 0);
99 pcidev->dev_id = dev_id;
100 pcidev->ven_id = ven_id;
101 /* Get the Class/subclass */
102 result = pcidev_read32(pcidev, PCI_CLASS_REG);
103 pcidev->class = result >> 24;
104 pcidev->subclass = (result >> 16) & 0xff;
105 pcidev->progif = (result >> 8) & 0xff;
106 /* All device types (0, 1, 2) have the IRQ in the same place */
107 result = pcidev_read32(pcidev, PCI_IRQ_STD);
108 /* This is the PIC IRQ the device is wired to */
109 pcidev->irqline = result & PCI_IRQLINE_MASK;
110 /* This is the interrupt pin the device uses (INTA# - INTD#) */
111 pcidev->irqpin = (result & PCI_IRQPIN_MASK) >> PCI_IRQPIN_SHFT;
112 if (pcidev->irqpin != PCI_NOINT) {
113 /* TODO: use a list (check for collisions for now) (massive
114 * collisions on a desktop with bridge IRQs. */
115 //assert(!irq_pci_map[pcidev->irqline]);
116 irq_pci_map[pcidev->irqline] = pcidev;
118 switch ((pcidev_read32(pcidev, PCI_HEADER_REG) >> 16) & 0xff) {
120 pcidev->header_type = STD_PCI_DEV;
123 pcidev->header_type = PCI2PCI;
126 pcidev->header_type = PCI2CARDBUS;
129 pcidev->header_type = "Unknown Header Type";
131 pci_handle_bars(pcidev);
132 STAILQ_INSERT_TAIL(&pci_devices, pcidev, all_dev);
133 #ifdef CONFIG_PCI_VERBOSE
134 pcidev_print_info(pcidev, 4);
136 pcidev_print_info(pcidev, 0);
137 #endif /* CONFIG_PCI_VERBOSE */
141 /* Helper to read 32 bits from the config space of B:D:F. 'Offset' is how far
142 * into the config space we offset before reading, aka: where we are reading. */
143 uint32_t pci_read32(unsigned short bus, unsigned short dev, unsigned short func,
144 unsigned short offset)
146 /* Send type 1 requests for everything beyond bus 0. Note this does nothing
147 * until we configure the PCI bridges (which we don't do yet). */
150 outl(PCI_CONFIG_ADDR, MK_CONFIG_ADDR(bus, dev, func, offset));
151 return inl(PCI_CONFIG_DATA);
154 /* Same, but writes (doing 32bit at a time). Never actually tested (not sure if
155 * PCI lets you write back). */
156 void pci_write32(unsigned short bus, unsigned short dev, unsigned short func,
157 unsigned short offset, uint32_t value)
159 outl(PCI_CONFIG_ADDR, MK_CONFIG_ADDR(bus, dev, func, offset));
160 outl(PCI_CONFIG_DATA, value);
163 /* Helper to read from a specific device's config space. */
164 uint32_t pcidev_read32(struct pci_device *pcidev, unsigned short offset)
166 return pci_read32(pcidev->bus, pcidev->dev, pcidev->func, offset);
169 /* Helper to write to a specific device */
170 void pcidev_write32(struct pci_device *pcidev, unsigned short offset,
173 pci_write32(pcidev->bus, pcidev->dev, pcidev->func, offset, value);
176 /* Gets any old raw bar, with some catches based on type. */
177 uint32_t pci_getbar(struct pci_device *pcidev, unsigned int bar)
179 uint32_t value, type;
180 if (bar >= MAX_PCI_BAR)
181 panic("Nonexistant bar requested!");
182 value = pcidev_read32(pcidev, PCI_HEADER_REG);
183 type = (value >> 16) & 0xff;
184 /* Only types 0 and 1 have BARS */
185 if ((type != 0x00) && (type != 0x01))
187 /* Only type 0 has BAR2 - BAR5 */
188 if ((bar > 1) && (type != 0x00))
190 return pcidev_read32(pcidev, PCI_BAR0_STD + bar * PCI_BAR_OFF);
193 /* Determines if a given bar is IO (o/w, it's mem) */
194 bool pci_is_iobar(uint32_t bar)
196 return bar & PCI_BAR_IO;
199 bool pci_is_membar32(uint32_t bar)
201 if (pci_is_iobar(bar))
203 return (bar & PCI_MEMBAR_TYPE) == PCI_MEMBAR_32BIT;
206 bool pci_is_membar64(uint32_t bar)
208 if (pci_is_iobar(bar))
210 return (bar & PCI_MEMBAR_TYPE) == PCI_MEMBAR_64BIT;
213 /* Helper to get the address from a membar. Check the type beforehand */
214 uint32_t pci_getmembar32(uint32_t bar)
216 uint8_t type = bar & PCI_MEMBAR_TYPE;
217 if (type != PCI_MEMBAR_32BIT) {
218 warn("Unhandled PCI membar type: %02p\n", type >> 1);
221 return bar & 0xfffffff0;
224 /* Helper to get the address from an IObar. Check the type beforehand */
225 uint32_t pci_getiobar32(uint32_t bar)
227 return bar & 0xfffffffc;
230 /* Helper to get the class description strings. Adapted from
231 * http://www.pcidatabase.com/reports.php?type=c-header */
232 static void pcidev_get_cldesc(struct pci_device *pcidev, char **class,
233 char **subclass, char **progif)
236 *class = *subclass = *progif = "";
238 for (i = 0; i < PCI_CLASSCODETABLE_LEN; i++) {
239 if (PciClassCodeTable[i].BaseClass == pcidev->class) {
241 *class = PciClassCodeTable[i].BaseDesc;
242 if (PciClassCodeTable[i].SubClass == pcidev->subclass) {
244 *subclass = PciClassCodeTable[i].SubDesc;
245 if (PciClassCodeTable[i].ProgIf == pcidev->progif) {
246 *progif = PciClassCodeTable[i].ProgDesc;
254 /* Helper to get the vendor and device description strings */
255 static void pcidev_get_devdesc(struct pci_device *pcidev, char **vend_short,
256 char **vend_full, char **chip, char **chip_desc)
259 *vend_short = *vend_full = *chip = *chip_desc = "";
261 for (i = 0; i < PCI_VENTABLE_LEN; i++) {
262 if (PciVenTable[i].VenId == pcidev->ven_id) {
263 *vend_short = PciVenTable[i].VenShort;
264 *vend_full = PciVenTable[i].VenFull;
268 for (i = 0; i < PCI_DEVTABLE_LEN; i++) {
269 if ((PciDevTable[i].VenId == pcidev->ven_id) &&
270 (PciDevTable[i].DevId == pcidev->dev_id)) {
271 *chip = PciDevTable[i].Chip;
272 *chip_desc = PciDevTable[i].ChipDesc;
278 /* Prints info (like lspci) for a device */
279 void pcidev_print_info(struct pci_device *pcidev, int verbosity)
281 char *ven_sht, *ven_fl, *chip, *chip_txt, *class, *subcl, *progif;
282 pcidev_get_cldesc(pcidev, &class, &subcl, &progif);
283 pcidev_get_devdesc(pcidev, &ven_sht, &ven_fl, &chip, &chip_txt);
285 printk("%02x:%02x.%x %s: %s %s %s: %s\n",
293 pcidev->header_type);
294 if (verbosity < 1) /* whatever */
296 printk("\tIRQ: %02d IRQ pin: 0x%02x\n",
299 printk("\tVendor Id: 0x%04x Device Id: 0x%04x\n",
302 printk("\t%s %s %s\n",
306 for (int i = 0; i < pcidev->nr_bars; i++) {
307 if (pcidev->bar[i].raw_bar == 0)
309 printk("\tBAR %d: ", i);
310 if (pci_is_iobar(pcidev->bar[i].raw_bar)) {
311 assert(pcidev->bar[i].pio_base);
312 printk("IO port 0x%04x\n", pcidev->bar[i].pio_base);
314 bool bar_is_64 = pci_is_membar64(pcidev->bar[i].raw_bar);
315 printk("MMIO Base %p, MMIO Size %p\n",
316 bar_is_64 ? pcidev->bar[i].mmio_base64 :
317 pcidev->bar[i].mmio_base32,
318 pcidev->bar[i].mmio_sz);
319 /* Takes up two bars */
321 assert(!pcidev->bar[i].mmio_base32); /* double-check */
328 void pci_set_bus_master(struct pci_device *pcidev)
330 pcidev_write32(pcidev, PCI_STAT_CMD_REG,
331 pcidev_read32(pcidev, PCI_STAT_CMD_REG) |