4284bbfa650752a35129c39a8e622b8ac8bea842
[akaros.git] / kern / arch / x86 / pci.c
1 /* Copyright (c) 2009, 2010 The Regents of the University of California
2  * See LICENSE for details.
3  *
4  * Barret Rhoden <brho@cs.berkeley.edu>
5  * Original by Paul Pearce <pearce@eecs.berkeley.edu> */
6
7 #include <arch/x86.h>
8 #include <arch/pci.h>
9 #include <trap.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <assert.h>
13 #include <kmalloc.h>
14 #include <arch/pci_defs.h>
15
16 /* List of all discovered devices */
17 struct pcidev_stailq pci_devices = STAILQ_HEAD_INITIALIZER(pci_devices);
18
19 static char STD_PCI_DEV[] = "Standard PCI Device";
20 static char PCI2PCI[] = "PCI-to-PCI Bridge";
21 static char PCI2CARDBUS[] = "PCI-Cardbus Bridge";
22
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)
27 {
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);
32         uint32_t retval;
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;
36         retval = ~retval + 1;
37         pcidev_write32(pcidev, bar_off, old_val);
38         return retval;
39 }
40
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)
46 {
47         /* only handling standards for now */
48         uint32_t bar_val;
49         int max_bars = pcidev->header_type == STD_PCI_DEV ? MAX_PCI_BAR : 0;
50         /* TODO: consider aborting for classes 00, 05 (memory ctlr), 06 (bridge) */
51         for (int i = 0; i < max_bars; i++) {
52                 bar_val = pci_getbar(pcidev, i);
53                 pcidev->bar[i].raw_bar = bar_val;
54                 if (!bar_val)   /* (0 denotes no valid data) */
55                         continue;
56                 if (pci_is_iobar(bar_val)) {
57                         pcidev->bar[i].pio_base = pci_getiobar32(bar_val);
58                 } else {
59                         if (pci_is_membar32(bar_val)) {
60                                 pcidev->bar[i].mmio_base32 = bar_val & PCI_BAR_MEM_MASK;
61                                 pcidev->bar[i].mmio_sz = pci_membar_get_sz(pcidev, i);
62                         } else if (pci_is_membar64(bar_val)) {
63                                 /* 64 bit, the lower 32 are in this bar, the upper
64                                  * are in the next bar */
65                                 pcidev->bar[i].mmio_base64 = bar_val & PCI_BAR_MEM_MASK;
66                                 assert(i < max_bars - 1);
67                                 bar_val = pci_getbar(pcidev, i + 1);    /* read next bar */
68                                 /* note we don't check for IO or memsize.  the entire next bar
69                                  * is supposed to be for the upper 32 bits. */
70                                 pcidev->bar[i].mmio_base64 |= (uint64_t)bar_val << 32;
71                                 pcidev->bar[i].mmio_sz = pci_membar_get_sz(pcidev, i);
72                                 i++;
73                         }
74                 }
75                 /* this will track the maximum bar we've had.  it'll include the 64 bit
76                  * uppers, as well as devices that have only higher numbered bars. */
77                 pcidev->nr_bars = i + 1;
78         }
79 }
80
81 /* Scans the PCI bus.  Won't actually work for anything other than bus 0, til we
82  * sort out how to handle bridge devices. */
83 void pci_init(void) {
84         uint32_t result = 0;
85         uint16_t dev_id, ven_id;
86         struct pci_device *pcidev;
87         int max_nr_func;
88         for (int i = 0; i < PCI_MAX_BUS - 1; i++) {     /* phantoms at 0xff */
89                 for (int j = 0; j < PCI_MAX_DEV; j++) {
90                         max_nr_func = 1;
91                         for (int k = 0; k < max_nr_func; k++) {
92                                 result = pci_read32(i, j, k, PCI_DEV_VEND_REG);
93                                 dev_id = result >> 16;
94                                 ven_id = result & 0xffff;
95                                 /* Skip invalid IDs (not a device) */
96                                 if (ven_id == INVALID_VENDOR_ID) 
97                                         break;  /* skip functions too, they won't exist */
98                                 pcidev = kzmalloc(sizeof(struct pci_device), 0);
99                                 pcidev->bus = i;
100                                 pcidev->dev = j;
101                                 pcidev->func = k;
102                                 pcidev->dev_id = dev_id;
103                                 pcidev->ven_id = ven_id;
104                                 /* Get the Class/subclass */
105                                 pcidev->class = pcidev_read8(pcidev, PCI_CLASS_REG);
106                                 pcidev->subclass = pcidev_read8(pcidev, PCI_SUBCLASS_REG);
107                                 pcidev->progif = pcidev_read8(pcidev, PCI_PROGIF_REG);
108                                 /* All device types (0, 1, 2) have the IRQ in the same place */
109                                 /* This is the PIC IRQ the device is wired to */
110                                 pcidev->irqline = pcidev_read8(pcidev, PCI_IRQLINE_STD);
111                                 /* This is the interrupt pin the device uses (INTA# - INTD#) */
112                                 pcidev->irqpin = pcidev_read8(pcidev, PCI_IRQPIN_STD);
113                                 if (pcidev->irqpin != PCI_NOINT) {
114                                         /* TODO: use a list (check for collisions for now) (massive
115                                          * collisions on a desktop with bridge IRQs. */
116                                         //assert(!irq_pci_map[pcidev->irqline]);
117                                         irq_pci_map[pcidev->irqline] = pcidev;
118                                 }
119                                 /* bottom 7 bits are header type */
120                                 switch (pcidev_read8(pcidev, PCI_HEADER_REG) & 0x7c) {
121                                         case 0x00:
122                                                 pcidev->header_type = STD_PCI_DEV;
123                                                 break;
124                                         case 0x01:
125                                                 pcidev->header_type = PCI2PCI;
126                                                 break;
127                                         case 0x02:
128                                                 pcidev->header_type = PCI2CARDBUS;
129                                                 break;
130                                         default:
131                                                 pcidev->header_type = "Unknown Header Type";
132                                 }
133                                 pci_handle_bars(pcidev);
134                                 STAILQ_INSERT_TAIL(&pci_devices, pcidev, all_dev);
135                                 #ifdef CONFIG_PCI_VERBOSE
136                                 pcidev_print_info(pcidev, 4);
137                                 #else
138                                 pcidev_print_info(pcidev, 0);
139                                 #endif /* CONFIG_PCI_VERBOSE */
140                                 /* Top bit determines if we have multiple functions on this
141                                  * device.  We can't just check for more functions, since
142                                  * non-multifunction devices exist that respond to different
143                                  * functions with the same underlying device (same bars etc).
144                                  * Note that this style allows for devices that only report
145                                  * multifunction in the first function's header. */
146                                 if (pcidev_read8(pcidev, PCI_HEADER_REG) & 0x80)
147                                         max_nr_func = PCI_MAX_FUNC;
148                         }
149                 }
150         }
151 }
152
153 uint32_t pci_config_addr(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg)
154 {
155         return (uint32_t)(((uint32_t)bus << 16) |
156                           ((uint32_t)dev << 11) |
157                           ((uint32_t)func << 8) |
158                           (reg & 0xfc) | 0x80000000);
159 }
160
161 /* Helper to read 32 bits from the config space of B:D:F.  'Offset' is how far
162  * into the config space we offset before reading, aka: where we are reading. */
163 uint32_t pci_read32(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset)
164 {
165         /* Send type 1 requests for everything beyond bus 0.  Note this does nothing
166          * until we configure the PCI bridges (which we don't do yet). */
167         if (bus !=  0)
168                 offset |= 0x1;
169         outl(PCI_CONFIG_ADDR, pci_config_addr(bus, dev, func, offset));
170         return inl(PCI_CONFIG_DATA);
171 }
172
173 /* Same, but writes (doing 32bit at a time).  Never actually tested (not sure if
174  * PCI lets you write back). */
175 void pci_write32(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset,
176                  uint32_t value)
177 {
178         outl(PCI_CONFIG_ADDR, pci_config_addr(bus, dev, func, offset));
179         outl(PCI_CONFIG_DATA, value);
180 }
181
182 /* Helper to read from a specific device's config space. */
183 uint32_t pcidev_read32(struct pci_device *pcidev, uint8_t offset)
184 {
185         return pci_read32(pcidev->bus, pcidev->dev, pcidev->func, offset);
186 }
187
188 /* Helper to write to a specific device */
189 void pcidev_write32(struct pci_device *pcidev, uint8_t offset, uint32_t value)
190 {
191         pci_write32(pcidev->bus, pcidev->dev, pcidev->func, offset, value);
192 }
193
194 /* For the 16 and 8 functions, we need to access on 32 bit alignments, then
195  * figure out which byte/word we need to read/write.  & 0xfc will give us the 4
196  * byte aligned offset to access in PCI space.  & 0x3 will give the offset
197  * within the 32 bits (number of bytes).  When writing, we also need to x-out
198  * any existing values (and not just |=). */
199
200 /* Returns the 32-bit addr/offset needed to access 'offset'. */
201 static inline uint8_t __pci_off32(uint8_t offset)
202 {
203         return offset & 0xfc;
204 }
205
206 /* Returns the number of bits needed to shift to get the offset's spot in a 32
207  * bit config register. */
208 static inline uint8_t __pci_shift_for(uint8_t offset)
209 {
210         return (offset & 0x3) * 8;
211 }
212
213 uint16_t pcidev_read16(struct pci_device *pcidev, uint8_t offset)
214 {
215         uint32_t retval = pcidev_read32(pcidev, __pci_off32(offset));
216         /* 0x2 would work here, since offset & 0x3 should be 0 or 2 */
217         retval >>= __pci_shift_for(offset);
218         return (uint16_t)(retval & 0xffff);
219 }
220
221 void pcidev_write16(struct pci_device *pcidev, uint8_t offset, uint16_t value)
222 {
223         uint32_t readval = pcidev_read32(pcidev, __pci_off32(offset));
224         uint32_t writeval = (uint32_t)value << __pci_shift_for(offset);
225         readval &= ~(0xffff << __pci_shift_for(offset));
226         pcidev_write32(pcidev, __pci_off32(offset), readval | writeval);
227 }
228
229 uint8_t pcidev_read8(struct pci_device *pcidev, uint8_t offset)
230 {
231         uint32_t retval = pcidev_read32(pcidev, __pci_off32(offset));
232         retval >>= __pci_shift_for(offset);
233         return (uint8_t)(retval & 0xff);
234 }
235
236 void pcidev_write8(struct pci_device *pcidev, uint8_t offset, uint8_t value)
237 {
238         uint32_t readval = pcidev_read32(pcidev, __pci_off32(offset));
239         uint32_t writeval = (uint32_t)value << __pci_shift_for(offset);
240         readval &= ~(0xff << __pci_shift_for(offset));
241         pcidev_write32(pcidev, __pci_off32(offset), readval | writeval);
242 }
243
244 /* Gets any old raw bar, with some catches based on type. */
245 uint32_t pci_getbar(struct pci_device *pcidev, unsigned int bar)
246 {
247         uint32_t type;
248         if (bar >= MAX_PCI_BAR)
249                 panic("Nonexistant bar requested!");
250         type = pcidev_read8(pcidev, PCI_HEADER_REG);
251         /* Only types 0 and 1 have BARS */
252         if ((type != 0x00) && (type != 0x01))
253                 return 0;
254         /* Only type 0 has BAR2 - BAR5 */
255         if ((bar > 1) && (type != 0x00))
256                 return 0;
257         return pcidev_read32(pcidev, PCI_BAR0_STD + bar * PCI_BAR_OFF);
258 }
259
260 /* Determines if a given bar is IO (o/w, it's mem) */
261 bool pci_is_iobar(uint32_t bar)
262 {
263         return bar & PCI_BAR_IO;
264 }
265
266 bool pci_is_membar32(uint32_t bar)
267 {
268         if (pci_is_iobar(bar))
269                 return FALSE;
270         return (bar & PCI_MEMBAR_TYPE) == PCI_MEMBAR_32BIT;
271 }
272
273 bool pci_is_membar64(uint32_t bar)
274 {
275         if (pci_is_iobar(bar))
276                 return FALSE;
277         return (bar & PCI_MEMBAR_TYPE) == PCI_MEMBAR_64BIT;
278 }
279
280 /* Helper to get the address from a membar.  Check the type beforehand */
281 uint32_t pci_getmembar32(uint32_t bar)
282 {
283         uint8_t type = bar & PCI_MEMBAR_TYPE;
284         if (type != PCI_MEMBAR_32BIT) {
285                 warn("Unhandled PCI membar type: %02p\n", type >> 1);
286                 return 0;
287         }
288         return bar & 0xfffffff0;
289 }
290
291 /* Helper to get the address from an IObar.  Check the type beforehand */
292 uint32_t pci_getiobar32(uint32_t bar)
293 {
294         return bar & 0xfffffffc;
295 }
296
297 /* Helper to get the class description strings.  Adapted from
298  * http://www.pcidatabase.com/reports.php?type=c-header */
299 static void pcidev_get_cldesc(struct pci_device *pcidev, char **class,
300                               char **subclass, char **progif)
301 {
302         int     i ;
303         *class = *subclass = *progif = "";
304
305         for (i = 0; i < PCI_CLASSCODETABLE_LEN; i++) {
306                 if (PciClassCodeTable[i].BaseClass == pcidev->class) {
307                         if (!(**class))
308                                 *class = PciClassCodeTable[i].BaseDesc;
309                         if (PciClassCodeTable[i].SubClass == pcidev->subclass) {
310                                 if (!(**subclass))
311                                         *subclass = PciClassCodeTable[i].SubDesc;
312                                 if (PciClassCodeTable[i].ProgIf == pcidev->progif) {
313                                         *progif = PciClassCodeTable[i].ProgDesc;
314                                         break ;
315                                 }
316                         }
317                 }
318         }
319 }
320
321 /* Helper to get the vendor and device description strings */
322 static void pcidev_get_devdesc(struct pci_device *pcidev, char **vend_short,
323                                char **vend_full, char **chip, char **chip_desc)
324 {
325         int     i ;
326         *vend_short = *vend_full = *chip = *chip_desc = "";
327
328         for (i = 0; i < PCI_VENTABLE_LEN; i++) {
329                 if (PciVenTable[i].VenId == pcidev->ven_id) {
330                         *vend_short = PciVenTable[i].VenShort;
331                         *vend_full = PciVenTable[i].VenFull;
332                         break ;
333                 }
334         }
335         for (i = 0; i < PCI_DEVTABLE_LEN; i++) {
336                 if ((PciDevTable[i].VenId == pcidev->ven_id) &&
337                    (PciDevTable[i].DevId == pcidev->dev_id)) {
338                         *chip = PciDevTable[i].Chip;
339                         *chip_desc = PciDevTable[i].ChipDesc;
340                         break ;
341                 }
342         }
343 }
344
345 /* Prints info (like lspci) for a device */
346 void pcidev_print_info(struct pci_device *pcidev, int verbosity)
347 {
348         char *ven_sht, *ven_fl, *chip, *chip_txt, *class, *subcl, *progif;
349         pcidev_get_cldesc(pcidev, &class, &subcl, &progif);
350         pcidev_get_devdesc(pcidev, &ven_sht, &ven_fl, &chip, &chip_txt);
351
352         printk("%02x:%02x.%x %s: %s %s %s: %s\n",
353                pcidev->bus,
354                pcidev->dev,
355                pcidev->func,
356                subcl,
357                ven_sht,
358                chip,
359                chip_txt,
360                    pcidev->header_type);
361         if (verbosity < 1)      /* whatever */
362                 return;
363         printk("\tIRQ: %02d IRQ pin: 0x%02x\n",
364                pcidev->irqline,
365                pcidev->irqpin);
366         printk("\tVendor Id: 0x%04x Device Id: 0x%04x\n",
367                pcidev->ven_id,
368                pcidev->dev_id);
369         printk("\t%s %s %s\n",
370                class,
371                progif,
372                ven_fl);
373         for (int i = 0; i < pcidev->nr_bars; i++) {
374                 if (pcidev->bar[i].raw_bar == 0)
375                         continue;
376                 printk("\tBAR %d: ", i);
377                 if (pci_is_iobar(pcidev->bar[i].raw_bar)) {
378                         assert(pcidev->bar[i].pio_base);
379                         printk("IO port 0x%04x\n", pcidev->bar[i].pio_base);
380                 } else {
381                         bool bar_is_64 = pci_is_membar64(pcidev->bar[i].raw_bar);
382                         printk("MMIO Base %p, MMIO Size %p\n",
383                                bar_is_64 ? pcidev->bar[i].mmio_base64 :
384                                            pcidev->bar[i].mmio_base32,
385                                pcidev->bar[i].mmio_sz);
386                         /* Takes up two bars */
387                         if (bar_is_64) {
388                                 assert(!pcidev->bar[i].mmio_base32);    /* double-check */
389                                 i++;
390                         }
391                 }
392         }
393 }
394
395 void pci_set_bus_master(struct pci_device *pcidev)
396 {
397         pcidev_write16(pcidev, PCI_CMD_REG, pcidev_read16(pcidev, PCI_CMD_REG) |
398                                             PCI_CMD_BUS_MAS);
399 }