1 #include <minix/driver.h> 2 #include <acpi.h> 3 #include <assert.h> 4 #include <minix/acpi.h> 5 6 #include "acpi_globals.h" 7 8 #define PCI_MAX_DEVICES 32 9 #define PCI_MAX_PINS 4 10 11 #define IRQ_TABLE_ENTRIES (PCI_MAX_DEVICES * PCI_MAX_PINS) 12 13 struct pci_bridge { 14 ACPI_HANDLE handle; 15 int irqtable[IRQ_TABLE_ENTRIES]; 16 int primary_bus; 17 int secondary_bus; 18 unsigned device; 19 struct pci_bridge * parent; 20 struct pci_bridge * children[PCI_MAX_DEVICES]; 21 }; 22 23 static struct pci_bridge pci_root_bridge; 24 25 struct irq_resource { 26 struct pci_bridge * bridge; 27 ACPI_PCI_ROUTING_TABLE * tbl; 28 }; 29 30 static struct pci_bridge * find_bridge(struct pci_bridge * root, 31 int pbnr, 32 int dev, 33 int sbnr) 34 { 35 if (!root) 36 return NULL; 37 38 if (sbnr == -1) { 39 if (root->secondary_bus == pbnr) 40 return root->children[dev]; 41 else { 42 /* serach all children */ 43 unsigned d; 44 for (d = 0; d < PCI_MAX_DEVICES; d++) { 45 struct pci_bridge * b; 46 b = find_bridge(root->children[d], 47 pbnr, dev, sbnr); 48 if (b) 49 return b; 50 } 51 } 52 } else { 53 if (root->secondary_bus == sbnr) 54 return root; 55 else { 56 /* check all children */ 57 unsigned d; 58 for (d = 0; d < PCI_MAX_DEVICES; d++) { 59 struct pci_bridge * b; 60 b = find_bridge(root->children[d], 61 pbnr, dev, sbnr); 62 if (b) 63 return b; 64 } 65 } 66 } 67 68 return NULL; 69 } 70 71 void do_map_bridge(message *m) 72 { 73 int err = OK; 74 unsigned dev = ((struct acpi_map_bridge_req *)m)->device; 75 unsigned pbnr = ((struct acpi_map_bridge_req *)m)->primary_bus; 76 unsigned sbnr = ((struct acpi_map_bridge_req *)m)->secondary_bus; 77 78 struct pci_bridge * bridge; 79 80 bridge = find_bridge(&pci_root_bridge, pbnr, dev, -1); 81 82 if (!bridge) { 83 err = ENODEV; 84 goto map_error; 85 } 86 87 bridge->primary_bus = pbnr; 88 bridge->secondary_bus = sbnr; 89 90 map_error: 91 ((struct acpi_map_bridge_resp *)m)->err = err; 92 } 93 94 #if 0 95 static ACPI_STATUS device_get_int(ACPI_HANDLE handle, 96 char * name, 97 ACPI_INTEGER * val) 98 { 99 ACPI_STATUS status; 100 char buff[sizeof(ACPI_OBJECT)]; 101 ACPI_BUFFER abuff; 102 103 abuff.Length = sizeof(buff); 104 abuff.Pointer = buff; 105 106 status = AcpiEvaluateObjectTyped(handle, name, NULL, 107 &abuff, ACPI_TYPE_INTEGER); 108 if (ACPI_SUCCESS(status)) { 109 *val = ((ACPI_OBJECT *)abuff.Pointer)->Integer.Value; 110 } 111 112 return status; 113 } 114 #endif 115 116 void do_get_irq(message *m) 117 { 118 struct pci_bridge * bridge; 119 int irq; 120 121 unsigned bus = ((struct acpi_get_irq_req *)m)->bus; 122 unsigned dev = ((struct acpi_get_irq_req *)m)->dev; 123 unsigned pin = ((struct acpi_get_irq_req *)m)->pin; 124 125 assert(dev < PCI_MAX_DEVICES && pin < PCI_MAX_PINS); 126 127 bridge = find_bridge(&pci_root_bridge, -1, -1, bus); 128 129 if (!bridge) 130 irq = -1; 131 else 132 irq = bridge->irqtable[dev * PCI_MAX_PINS + pin]; 133 134 ((struct acpi_get_irq_resp *)m)->irq = irq; 135 } 136 137 static void add_irq(struct pci_bridge * bridge, 138 unsigned dev, 139 unsigned pin, 140 u8_t irq) 141 { 142 assert(dev < PCI_MAX_DEVICES && pin < PCI_MAX_PINS); 143 144 bridge->irqtable[dev * PCI_MAX_PINS + pin] = irq; 145 } 146 147 static ACPI_STATUS get_irq_resource(ACPI_RESOURCE *res, void *context) 148 { 149 struct irq_resource * ires = (struct irq_resource *) context; 150 151 if (res->Type == ACPI_RESOURCE_TYPE_IRQ) { 152 ACPI_RESOURCE_IRQ *irq; 153 154 irq = &res->Data.Irq; 155 add_irq(ires->bridge, ires->tbl->Address >> 16, ires->tbl->Pin, 156 irq->Interrupts[ires->tbl->SourceIndex]); 157 } else if (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { 158 ACPI_RESOURCE_EXTENDED_IRQ *irq; 159 160 irq = &res->Data.ExtendedIrq; 161 add_irq(ires->bridge, ires->tbl->Address >> 16, ires->tbl->Pin, 162 irq->Interrupts[ires->tbl->SourceIndex]); 163 } 164 165 return AE_OK; 166 } 167 168 static ACPI_STATUS get_pci_irq_routing(struct pci_bridge * bridge) 169 { 170 ACPI_STATUS status; 171 ACPI_BUFFER abuff; 172 char buff[4096]; 173 ACPI_PCI_ROUTING_TABLE *tbl; 174 ACPI_DEVICE_INFO *info; 175 int i; 176 177 abuff.Length = sizeof(buff); 178 abuff.Pointer = buff; 179 180 status = AcpiGetIrqRoutingTable(bridge->handle, &abuff); 181 if (ACPI_FAILURE(status)) { 182 return AE_OK; 183 } 184 185 info = abuff.Pointer; 186 status = AcpiGetObjectInfo(bridge->handle, &info); 187 if (ACPI_FAILURE(status)) 188 return status; 189 /* 190 * Decode the device number (upper half of the address) and attach the 191 * new bridge in the children list of its parent 192 */ 193 bridge->device = info->Address >> 16; 194 if (bridge != &pci_root_bridge) { 195 bridge->parent->children[bridge->device] = bridge; 196 bridge->primary_bus = bridge->secondary_bus = -1; 197 } 198 199 200 for (i = 0; i < PCI_MAX_DEVICES; i++) 201 bridge->children[i] = NULL; 202 203 for (tbl = (ACPI_PCI_ROUTING_TABLE *)abuff.Pointer; tbl->Length; 204 tbl = (ACPI_PCI_ROUTING_TABLE *) 205 ((char *)tbl + tbl->Length)) { 206 ACPI_HANDLE src_handle; 207 struct irq_resource ires; 208 209 if (*(char*)tbl->Source == '\0') { 210 add_irq(bridge, tbl->Address >> 16, 211 tbl->Pin, tbl->SourceIndex); 212 continue; 213 } 214 215 status = AcpiGetHandle(bridge->handle, tbl->Source, &src_handle); 216 if (ACPI_FAILURE(status)) { 217 printf("Failed AcpiGetHandle\n"); 218 continue; 219 } 220 ires.bridge = bridge; 221 ires.tbl = tbl; 222 status = AcpiWalkResources(src_handle, METHOD_NAME__CRS, 223 get_irq_resource, &ires); 224 if (ACPI_FAILURE(status)) { 225 printf("Failed IRQ resource\n"); 226 continue; 227 } 228 } 229 230 return AE_OK; 231 } 232 233 static void bridge_init_irqtable(struct pci_bridge * bridge) 234 { 235 int i; 236 237 for (i = 0; i < IRQ_TABLE_ENTRIES; i++) 238 bridge->irqtable[i] = -1; 239 } 240 241 static ACPI_STATUS add_pci_dev(ACPI_HANDLE handle, 242 UINT32 level, 243 void *context, 244 void **retval) 245 { 246 ACPI_STATUS status; 247 ACPI_BUFFER abuff; 248 char buff[4096]; 249 ACPI_HANDLE parent_handle; 250 struct pci_bridge * bridge; 251 struct pci_bridge * parent_bridge = (struct pci_bridge *) context; 252 253 254 /* skip pci root when we get to it again */ 255 if (handle == pci_root_bridge.handle) 256 return AE_OK; 257 258 status = AcpiGetParent(handle, &parent_handle); 259 if (!ACPI_SUCCESS(status)) 260 return status; 261 /* skip devices that have a different parent */ 262 if (parent_handle != parent_bridge->handle) 263 return AE_OK; 264 265 abuff.Length = sizeof(buff); 266 abuff.Pointer = buff; 267 268 bridge = malloc(sizeof(struct pci_bridge)); 269 if (!bridge) 270 return AE_NO_MEMORY; 271 bridge->handle = handle; 272 bridge->parent = parent_bridge; 273 bridge_init_irqtable(bridge); 274 275 status = get_pci_irq_routing(bridge); 276 if (!(ACPI_SUCCESS(status))) { 277 free(bridge); 278 return status; 279 } 280 281 /* get the pci bridges */ 282 status = AcpiGetDevices(NULL, add_pci_dev, bridge, NULL); 283 return status; 284 } 285 286 static ACPI_STATUS add_pci_root_dev(ACPI_HANDLE handle, 287 UINT32 level, 288 void *context, 289 void **retval) 290 { 291 static unsigned called; 292 ACPI_STATUS status; 293 294 if (++called > 1) { 295 printf("ACPI: Warning! Multi rooted PCI is not supported!\n"); 296 return AE_OK; 297 } 298 299 pci_root_bridge.handle = handle; 300 pci_root_bridge.primary_bus = -1; /* undefined */ 301 pci_root_bridge.secondary_bus = 0; /* root bus is 0 in a single root 302 system */ 303 bridge_init_irqtable(&pci_root_bridge); 304 305 status = get_pci_irq_routing(&pci_root_bridge); 306 if (!ACPI_SUCCESS(status)) 307 return status; 308 309 /* get the pci bridges */ 310 status = AcpiGetDevices(NULL, add_pci_dev, &pci_root_bridge, NULL); 311 return status; 312 } 313 314 void pci_scan_devices(void) 315 { 316 ACPI_STATUS status; 317 318 /* do not scan devices in PIC mode */ 319 if (!machine.apic_enabled) 320 return; 321 322 /* get the root first */ 323 status = AcpiGetDevices("PNP0A03", add_pci_root_dev, NULL, NULL); 324 assert(ACPI_SUCCESS(status)); 325 } 326