x86: interrupt return path checks kmsgs
[akaros.git] / kern / arch / i686 / pci.c
1 /*
2  * Copyright (c) 2009 The Regents of the University of California
3  * See LICENSE for details.
4  */
5
6 #ifdef __SHARC__
7 #pragma nosharc
8 #endif
9 // Not currently sharc complient. 
10
11 /** @file
12  * @brief Basic PCI Driver.
13  *
14  * This file is responsible for the scanning the PCI bus and recording
15  * all the information needed for ouR OS to function. 
16  *
17  * No PCI Specifications (or even consulted) were harmed in the making of this file.
18  *
19  * @author Paul Pearce <pearce@eecs.berkeley.edu>
20  *
21  * @todo Build an entire useful PCI subsystem, not this hack with a few data structures laying around
22  *
23  */
24
25 #include <arch/x86.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <arch/pci.h>
29
30 // A value of INVALID_IRQ (something 256 or larger) means invalid
31 uint16_t pci_irq_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
32
33 pci_dev_entry_t pci_dev_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
34
35 // NOTE: If we care about ALL devices associated with an IRQ, not just the last device, this needs to be some sort of linked structure
36 pci_irq_entry_t irq_pci_map[NUM_IRQS];
37
38 /**
39  * @brief Perform the actual PCI bus parsing
40  *
41  * See file description.
42  * 
43  * This function must be called during bootup, before ioapic_init().
44  */
45 void pci_init() {
46         
47         // Initalize the irq->pci table (pci->irq below)
48         // Setting all 1's forces an invalid entry, as bus = INVALID_BUS = 0xFFFF.
49         memset(irq_pci_map, 0xFF, sizeof(irq_pci_map));
50         
51         uint32_t address;
52         uint32_t bus = 0;
53         uint32_t dev = 0;
54         uint32_t func = 0;
55         uint32_t reg = 0; 
56         uint32_t result  = 0;
57  
58         pci_debug("Scanning PCI Bus....\n");
59
60         for (int i = 0; i < PCI_MAX_BUS; i++)
61                 for (int j = 0; j < PCI_MAX_DEV; j++)
62                         for (int k = 0; k < PCI_MAX_FUNC; k++) {
63
64                                 bus = i;
65                                 dev = j;
66                                 func = k;
67                                 reg = 0; // PCI REGISTER 0
68                                 
69                                 // Set the fields invalid.
70                                 pci_irq_map[i][j][k] = INVALID_IRQ;
71                                 pci_dev_map[i][j][k].dev_id = INVALID_VENDOR_ID;
72
73                                 address = MK_CONFIG_ADDR(bus, dev, func, reg); 
74
75                                 // Probe current bus/dev
76                                 outl(PCI_CONFIG_ADDR, address);
77                                 result = inl(PCI_CONFIG_DATA);
78         
79                                 uint16_t dev_id = result >> PCI_DEVICE_OFFSET;
80                                 uint16_t ven_id = result & PCI_VENDOR_MASK;
81
82                                 // Vender DNE
83                                 if (ven_id == INVALID_VENDOR_ID) 
84                                         continue;
85
86                                 pci_debug("Found device on BUS %x DEV %x FUNC %x: DEV_ID: %x VEN_ID: %x\n", i, j, k, dev_id, ven_id);
87
88                                 // Find the IRQ
89                                 address = MK_CONFIG_ADDR(bus, dev, func, PCI_IRQ_REG);
90                                 outl(PCI_CONFIG_ADDR, address);
91                                 uint16_t irq = inl(PCI_CONFIG_DATA) & PCI_IRQ_MASK;
92                                 pci_debug("-->IRQ: %u\n", irq);
93                                 
94                                 // Find the line (a-d)
95                                 address = MK_CONFIG_ADDR(bus, dev, func, PCI_IRQ_REG);
96                                 outl(PCI_CONFIG_ADDR, address);
97                                 uint8_t line = (inl(PCI_CONFIG_DATA) & PCI_LINE_MASK) >> PCI_LINE_SHFT;
98                                 
99                                 // If intn == 0, no interrupts used.
100                                 if (line != INVALID_LINE) {
101                                         
102                                         // Now shift A to 0, B to 1, etc.
103                                         // This starts off as A 1, B 2 (grr)
104                                         line--;
105                                 
106                                         pci_irq_map[i][j][k] = irq;
107                                         pci_dev_map[i][j][k].dev_id = dev_id;
108                                         pci_dev_map[i][j][k].ven_id = ven_id;
109                                         irq_pci_map[irq].bus = i;
110                                         irq_pci_map[irq].dev = j;
111                                         irq_pci_map[irq].func = k;
112                                         irq_pci_map[irq].line = line;
113                                         
114                                         // @todo We may want to perform some check to make sure we arent overwriting some current irq entry and maintain that info
115                                 }
116                                 
117
118                                 /* Loop over the BARs
119                                  * Right now we don't do anything useful with this data. 
120                                  * This is legacy code in which I pulled data from the BARS during NIC development
121                                  * At some point we will have to use this, so the code is still here.
122                                  */
123                                 
124                                 // Note: These magic numbers are from the PCI spec (according to OSDev).
125                                 #ifdef CHECK_BARS
126                                 for (int k = 0; k <= 5; k++) {
127                                         reg = 4 + k;
128                                         address = MK_CONFIG_ADDR(bus, dev, func, reg << 2);     
129                                 outl(PCI_CONFIG_ADDR, address);
130                                 result = inl(PCI_CONFIG_DATA);
131                                         
132                                         if (result == 0) // (0 denotes no valid data)
133                                                 continue;
134
135                                         // Read the bottom bit of the BAR. 
136                                         if (result & PCI_BAR_IO_MASK) {
137                                                 result = result & PCI_IO_MASK;
138                                                 pci_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
139                                         } else {
140                                                 result = result & PCI_MEM_MASK;
141                                                 pci_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
142                                         }                                       
143                                 }
144                                 #endif
145                                 
146                                 pci_debug("\n");
147                         }               
148 }