83f4207f967bb32f414d852b7a7eb66364bf95e3
[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 <stdio.h>
10 #include <string.h>
11 #include <assert.h>
12 #include <kmalloc.h>
13 #include <arch/pci_defs.h>
14
15 /* Which pci devices hang off of which irqs */
16 /* TODO: make this an array of SLISTs (pain from ioapic.c, etc...) */
17 struct pci_device *irq_pci_map[NUM_IRQS] = {0};
18
19 /* List of all discovered devices */
20 struct pcidev_stailq pci_devices = STAILQ_HEAD_INITIALIZER(pci_devices);
21
22 static char STD_PCI_DEV[] = "Standard PCI Device";
23 static char PCI2PCI[] = "PCI-to-PCI Bridge";
24 static char PCI2CARDBUS[] = "PCI-Cardbus Bridge";
25
26 /* memory bars have a little dance you go through to detect what the size of the
27  * memory region is.  for 64 bit bars, i'm assuming you only need to do this to
28  * the lower part (no device will need > 4GB, right?). */
29 uint32_t pci_membar_get_sz(struct pci_device *pcidev, int bar)
30 {
31         /* save the old value, write all 1s, invert, add 1, restore.
32          * http://wiki.osdev.org/PCI for details. */
33         uint8_t bar_off = PCI_BAR0_STD + bar * PCI_BAR_OFF;
34         uint32_t old_val = pcidev_read32(pcidev, bar_off);
35         uint32_t retval;
36         pcidev_write32(pcidev, bar_off, 0xffffffff);
37         /* Don't forget to mask the lower 3 bits! */
38         retval = pcidev_read32(pcidev, bar_off) & PCI_BAR_MEM_MASK;
39         retval = ~retval + 1;
40         pcidev_write32(pcidev, bar_off, old_val);
41         return retval;
42 }
43
44 /* process the bars.  these will tell us what address space (PIO or memory) and
45  * where the base is.  fills results into pcidev.  i don't know if you can have
46  * multiple bars with conflicting/different regions (like two separate PIO
47  * ranges).  I'm assuming you don't, and will warn if we see one. */
48 static void pci_handle_bars(struct pci_device *pcidev)
49 {
50         /* only handling standards for now */
51         uint32_t bar_val;
52         int max_bars = pcidev->header_type == STD_PCI_DEV ? MAX_PCI_BAR : 0;
53         for (int i = 0; i < max_bars; i++) {
54                 bar_val = pci_getbar(pcidev, i);
55                 pcidev->bar[i].raw_bar = bar_val;
56                 if (!bar_val)   /* (0 denotes no valid data) */
57                         continue;
58                 if (pci_is_iobar(bar_val)) {
59                         pcidev->bar[i].pio_base = pci_getiobar32(bar_val);
60                 } else {
61                         if (pci_is_membar32(bar_val)) {
62                                 pcidev->bar[i].mmio_base32 = bar_val & PCI_BAR_MEM_MASK;
63                                 pcidev->bar[i].mmio_sz = pci_membar_get_sz(pcidev, i);
64                         } else if (pci_is_membar64(bar_val)) {
65                                 /* 64 bit, the lower 32 are in this bar, the upper
66                                  * are in the next bar */
67                                 pcidev->bar[i].mmio_base64 = bar_val & PCI_BAR_MEM_MASK;
68                                 assert(i < max_bars - 1);
69                                 bar_val = pci_getbar(pcidev, i + 1);    /* read next bar */
70                                 /* note we don't check for IO or memsize.  the entire next bar
71                                  * is supposed to be for the upper 32 bits. */
72                                 pcidev->bar[i].mmio_base64 |= (uint64_t)bar_val << 32;
73                                 pcidev->bar[i].mmio_sz = pci_membar_get_sz(pcidev, i);
74                                 i++;
75                         }
76                 }
77                 /* this will track the maximum bar we've had.  it'll include the 64 bit
78                  * uppers, as well as devices that have only higher numbered bars. */
79                 pcidev->nr_bars = i + 1;
80         }
81 }
82
83 /* Scans the PCI bus.  Won't actually work for anything other than bus 0, til we
84  * sort out how to handle bridge devices. */
85 void pci_init(void) {
86         uint32_t result = 0;
87         uint16_t dev_id, ven_id;
88         struct pci_device *pcidev;
89         for (int i = 0; i < PCI_MAX_BUS - 1; i++)       /* phantoms at 0xff */
90                 for (int j = 0; j < PCI_MAX_DEV; j++)
91                         for (int k = 0; k < PCI_MAX_FUNC; k++) {
92                                 result = pci_read32(i, j, k, PCI_DEV_VEND_REG);
93                                 dev_id = result >> PCI_DEVICE_OFFSET;
94                                 ven_id = result & PCI_VENDOR_MASK;
95                                 /* Skip invalid IDs (not a device) */
96                                 if (ven_id == INVALID_VENDOR_ID) 
97                                         continue;
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                                 result = pcidev_read32(pcidev, PCI_CLASS_REG);
106                                 pcidev->class = result >> 24;
107                                 pcidev->subclass = (result >> 16) & 0xff;
108                                 pcidev->progif = (result >> 8) & 0xff;
109                                 /* All device types (0, 1, 2) have the IRQ in the same place */
110                                 result = pcidev_read32(pcidev, PCI_IRQ_STD);
111                                 /* This is the PIC IRQ the device is wired to */
112                                 pcidev->irqline = result & PCI_IRQLINE_MASK;
113                                 /* This is the interrupt pin the device uses (INTA# - INTD#) */
114                                 pcidev->irqpin = (result & PCI_IRQPIN_MASK) >> PCI_IRQPIN_SHFT;
115                                 if (pcidev->irqpin != PCI_NOINT) {
116                                         /* TODO: use a list (check for collisions for now) (massive
117                                          * collisions on a desktop with bridge IRQs. */
118                                         //assert(!irq_pci_map[pcidev->irqline]);
119                                         irq_pci_map[pcidev->irqline] = pcidev;
120                                 }
121                                 switch ((pcidev_read32(pcidev, PCI_HEADER_REG) >> 16) & 0xff) {
122                                         case 0x00:
123                                                 pcidev->header_type = STD_PCI_DEV;
124                                                 break;
125                                         case 0x01:
126                                                 pcidev->header_type = PCI2PCI;
127                                                 break;
128                                         case 0x02:
129                                                 pcidev->header_type = PCI2CARDBUS;
130                                                 break;
131                                         default:
132                                                 pcidev->header_type = "Unknown Header Type";
133                                 }
134                                 pci_handle_bars(pcidev);
135                                 STAILQ_INSERT_TAIL(&pci_devices, pcidev, all_dev);
136                                 #ifdef CONFIG_PCI_VERBOSE
137                                 pcidev_print_info(pcidev, 4);
138                                 #else
139                                 pcidev_print_info(pcidev, 0);
140                                 #endif /* CONFIG_PCI_VERBOSE */
141                         }
142 }
143
144 /* Helper to read 32 bits from the config space of B:D:F.  'Offset' is how far
145  * into the config space we offset before reading, aka: where we are reading. */
146 uint32_t pci_read32(unsigned short bus, unsigned short dev, unsigned short func,
147                     unsigned short offset)
148 {
149         /* Send type 1 requests for everything beyond bus 0.  Note this does nothing
150          * until we configure the PCI bridges (which we don't do yet). */
151         if (bus !=  0)
152                 offset |= 0x1;
153         outl(PCI_CONFIG_ADDR, MK_CONFIG_ADDR(bus, dev, func, offset));
154         return inl(PCI_CONFIG_DATA);
155 }
156
157 /* Same, but writes (doing 32bit at a time).  Never actually tested (not sure if
158  * PCI lets you write back). */
159 void pci_write32(unsigned short bus, unsigned short dev, unsigned short func,
160                     unsigned short offset, uint32_t value)
161 {
162         outl(PCI_CONFIG_ADDR, MK_CONFIG_ADDR(bus, dev, func, offset));
163         outl(PCI_CONFIG_DATA, value);
164 }
165
166 /* Helper to read from a specific device's config space. */
167 uint32_t pcidev_read32(struct pci_device *pcidev, unsigned short offset)
168 {
169         return pci_read32(pcidev->bus, pcidev->dev, pcidev->func, offset);
170 }
171
172 /* Helper to write to a specific device */
173 void pcidev_write32(struct pci_device *pcidev, unsigned short offset,
174                     uint32_t value)
175 {
176         pci_write32(pcidev->bus, pcidev->dev, pcidev->func, offset, value);
177 }
178
179 /* Gets any old raw bar, with some catches based on type. */
180 uint32_t pci_getbar(struct pci_device *pcidev, unsigned int bar)
181 {
182         uint32_t value, type;
183         if (bar >= MAX_PCI_BAR)
184                 panic("Nonexistant bar requested!");
185         value = pcidev_read32(pcidev, PCI_HEADER_REG);
186         type = (value >> 16) & 0xff;
187         /* Only types 0 and 1 have BARS */
188         if ((type != 0x00) && (type != 0x01))
189                 return 0;
190         /* Only type 0 has BAR2 - BAR5 */
191         if ((bar > 1) && (type != 0x00))
192                 return 0;
193         return pcidev_read32(pcidev, PCI_BAR0_STD + bar * PCI_BAR_OFF);
194 }
195
196 /* Determines if a given bar is IO (o/w, it's mem) */
197 bool pci_is_iobar(uint32_t bar)
198 {
199         return bar & PCI_BAR_IO;
200 }
201
202 bool pci_is_membar32(uint32_t bar)
203 {
204         if (pci_is_iobar(bar))
205                 return FALSE;
206         return (bar & PCI_MEMBAR_TYPE) == PCI_MEMBAR_32BIT;
207 }
208
209 bool pci_is_membar64(uint32_t bar)
210 {
211         if (pci_is_iobar(bar))
212                 return FALSE;
213         return (bar & PCI_MEMBAR_TYPE) == PCI_MEMBAR_64BIT;
214 }
215
216 /* Helper to get the address from a membar.  Check the type beforehand */
217 uint32_t pci_getmembar32(uint32_t bar)
218 {
219         uint8_t type = bar & PCI_MEMBAR_TYPE;
220         if (type != PCI_MEMBAR_32BIT) {
221                 warn("Unhandled PCI membar type: %02p\n", type >> 1);
222                 return 0;
223         }
224         return bar & 0xfffffff0;
225 }
226
227 /* Helper to get the address from an IObar.  Check the type beforehand */
228 uint32_t pci_getiobar32(uint32_t bar)
229 {
230         return bar & 0xfffffffc;
231 }
232
233 /* Helper to get the class description strings.  Adapted from
234  * http://www.pcidatabase.com/reports.php?type=c-header */
235 static void pcidev_get_cldesc(struct pci_device *pcidev, char **class,
236                               char **subclass, char **progif)
237 {
238         int     i ;
239         *class = *subclass = *progif = "";
240
241         for (i = 0; i < PCI_CLASSCODETABLE_LEN; i++) {
242                 if (PciClassCodeTable[i].BaseClass == pcidev->class) {
243                         if (!(**class))
244                                 *class = PciClassCodeTable[i].BaseDesc;
245                         if (PciClassCodeTable[i].SubClass == pcidev->subclass) {
246                                 if (!(**subclass))
247                                         *subclass = PciClassCodeTable[i].SubDesc;
248                                 if (PciClassCodeTable[i].ProgIf == pcidev->progif) {
249                                         *progif = PciClassCodeTable[i].ProgDesc;
250                                         break ;
251                                 }
252                         }
253                 }
254         }
255 }
256
257 /* Helper to get the vendor and device description strings */
258 static void pcidev_get_devdesc(struct pci_device *pcidev, char **vend_short,
259                                char **vend_full, char **chip, char **chip_desc)
260 {
261         int     i ;
262         *vend_short = *vend_full = *chip = *chip_desc = "";
263
264         for (i = 0; i < PCI_VENTABLE_LEN; i++) {
265                 if (PciVenTable[i].VenId == pcidev->ven_id) {
266                         *vend_short = PciVenTable[i].VenShort;
267                         *vend_full = PciVenTable[i].VenFull;
268                         break ;
269                 }
270         }
271         for (i = 0; i < PCI_DEVTABLE_LEN; i++) {
272                 if ((PciDevTable[i].VenId == pcidev->ven_id) &&
273                    (PciDevTable[i].DevId == pcidev->dev_id)) {
274                         *chip = PciDevTable[i].Chip;
275                         *chip_desc = PciDevTable[i].ChipDesc;
276                         break ;
277                 }
278         }
279 }
280
281 /* Prints info (like lspci) for a device */
282 void pcidev_print_info(struct pci_device *pcidev, int verbosity)
283 {
284         char *ven_sht, *ven_fl, *chip, *chip_txt, *class, *subcl, *progif;
285         pcidev_get_cldesc(pcidev, &class, &subcl, &progif);
286         pcidev_get_devdesc(pcidev, &ven_sht, &ven_fl, &chip, &chip_txt);
287
288         printk("%02x:%02x.%x %s: %s %s %s: %s\n",
289                pcidev->bus,
290                pcidev->dev,
291                pcidev->func,
292                subcl,
293                ven_sht,
294                chip,
295                chip_txt,
296                    pcidev->header_type);
297         if (verbosity < 1)      /* whatever */
298                 return;
299         printk("\tIRQ: %02d IRQ pin: 0x%02x\n",
300                pcidev->irqline,
301                pcidev->irqpin);
302         printk("\tVendor Id: 0x%04x Device Id: 0x%04x\n",
303                pcidev->ven_id,
304                pcidev->dev_id);
305         printk("\t%s %s %s\n",
306                class,
307                progif,
308                ven_fl);
309         for (int i = 0; i < pcidev->nr_bars; i++) {
310                 if (pcidev->bar[i].raw_bar == 0)
311                         continue;
312                 printk("\tBAR %d: ", i);
313                 if (pci_is_iobar(pcidev->bar[i].raw_bar)) {
314                         assert(pcidev->bar[i].pio_base);
315                         printk("IO port 0x%04x\n", pcidev->bar[i].pio_base);
316                 } else {
317                         bool bar_is_64 = pci_is_membar64(pcidev->bar[i].raw_bar);
318                         printk("MMIO Base %p, MMIO Size %p\n",
319                                bar_is_64 ? pcidev->bar[i].mmio_base64 :
320                                            pcidev->bar[i].mmio_base32,
321                                pcidev->bar[i].mmio_sz);
322                         /* Takes up two bars */
323                         if (bar_is_64) {
324                                 assert(!pcidev->bar[i].mmio_base32);    /* double-check */
325                                 i++;
326                         }
327                 }
328         }
329 }