]> Zhao Yanbai Git Server - minix.git/commitdiff
PCI driver uses ACPI if APIC is used.
authorTomas Hruby <tom@minix3.org>
Thu, 2 Sep 2010 15:44:38 +0000 (15:44 +0000)
committerTomas Hruby <tom@minix3.org>
Thu, 2 Sep 2010 15:44:38 +0000 (15:44 +0000)
-  PCI must query ACPI, if (IO)APIC is in use, for the routing
   information and change the ILR (interrupt line register) of each
   device accordingly so drivers use the right IRQ.

drivers/pci/pci.c

index bfc8fedca5d17d0cbd312892d0018faa1fa47883..c75198972686f26157ace4a6c71e680741e81d74 100644 (file)
@@ -30,6 +30,7 @@ Created:      Jan 2000 by Philip Homburg <philip@cs.vu.nl>
 #include <stdlib.h>
 #include <stdio.h>
 #include <minix/sysutil.h>
+#include <minix/acpi.h>
 
 #define PBT_INTEL_HOST  1
 #define PBT_PCIBRIDGE   2
@@ -150,6 +151,9 @@ FORWARD _PROTOTYPE( void print_capabilities, (int devind)           );
 FORWARD _PROTOTYPE( int visible, (struct rs_pci *aclp, int devind)     );
 FORWARD _PROTOTYPE( void print_hyper_cap, (int devind, u8_t capptr)    );
 
+PRIVATE struct machine machine;
+PRIVATE endpoint_t acpi_ep;
+
 /*===========================================================================*
  *                             sef_cb_init_fresh                            *
  *===========================================================================*/
@@ -164,6 +168,15 @@ PUBLIC int sef_cb_init_fresh(int type, sef_init_info_t *info)
        env_parse("pci_debug", "d", 0, &v, 0, 1);
        debug= v;
 
+       if (sys_getmachine(&machine)) {
+               printf("PCI: no machine\n");
+               return ENODEV;
+       }
+       if (machine.apic_enabled &&
+                       ds_retrieve_label_endpt("acpi", &acpi_ep) != OK) {
+               panic("PCI: Cannot use APIC mode without ACPI!\n");
+       }
+
        /* Only Intel (compatible) PCI controllers are supported at the
         * moment.
         */
@@ -768,9 +781,8 @@ PRIVATE void probe_bus(int busind)
        int devind, busnr;
        char *s, *dstr;
 
-#if DEBUG
-printf("probe_bus(%d)\n", busind);
-#endif
+       if (debug)
+               printf("probe_bus(%d)\n", busind);
        if (nr_pcidev >= NR_PCIDEV)
                panic("too many PCI devices: %d", nr_pcidev);
        devind= nr_pcidev;
@@ -933,6 +945,37 @@ PRIVATE int is_duplicate(u8_t busnr, u8_t dev, u8_t func)
        return 0;
 }
 
+PRIVATE int acpi_get_irq(unsigned dev, unsigned pin)
+{
+       int err;
+       message m;
+
+       ((struct acpi_get_irq_req *)&m)->hdr.request = ACPI_REQ_GET_IRQ;
+       ((struct acpi_get_irq_req *)&m)->dev = dev;
+       ((struct acpi_get_irq_req *)&m)->pin = pin;
+
+       if ((err = sendrec(acpi_ep, &m)) != OK)
+               panic("PCI: error %d while receiveing from ACPI\n", err);
+
+       return ((struct acpi_get_irq_resp *)&m)->irq;
+}
+
+PRIVATE int derive_irq(struct pcidev * dev, int pin)
+{
+       struct pcidev * parent_brige;
+       int slot;
+       
+       parent_brige = &pcidev[pcibus[get_busind(dev->pd_busnr)].pb_devind];
+
+       /*
+        * We don't support PCI-Express, no ARI, decode the slot of the device
+        * and mangle the pin as the device is behind a bridge
+        */
+       slot = ((dev->pd_func) >> 3) & 0x1f;
+
+       return acpi_get_irq(parent_brige->pd_dev, (pin + slot) % 4);
+}
+
 /*===========================================================================*
  *                             record_irq                                   *
  *===========================================================================*/
@@ -943,6 +986,36 @@ int devind;
 
        ilr= pci_attr_r8_u(devind, PCI_ILR);
        ipr= pci_attr_r8_u(devind, PCI_IPR);
+
+       if (ipr && machine.apic_enabled) {
+               int irq;
+
+               irq = acpi_get_irq(pcidev[devind].pd_dev, ipr - 1);
+
+               if (irq < 0)
+                       irq = derive_irq(&pcidev[devind], ipr - 1);
+
+               if (irq >= 0) {
+                       ilr = irq;
+                       pci_attr_w8(devind, PCI_ILR, ilr);
+                       printf("PCI: ACPI IRQ %d for "
+                                       "device %d.%d.%d INT%c\n",
+                                       irq,
+                                       pcidev[devind].pd_busnr,
+                                       pcidev[devind].pd_dev,
+                                       pcidev[devind].pd_func,
+                                       'A' + ipr-1);
+               }
+               else {
+                       printf("PCI: no ACPI IRQ routing for "
+                                       "device %d.%d.%d INT%c\n",
+                                       pcidev[devind].pd_busnr,
+                                       pcidev[devind].pd_dev,
+                                       pcidev[devind].pd_func,
+                                       'A' + ipr-1);
+               }
+       }
+
        if (ilr == 0)
        {
                static int first= 1;
@@ -1778,7 +1851,7 @@ int busind;
        {
 #if 0
                printf("do_pcibridge: trying %u.%u.%u\n",
-                       pcidev[devind].pd_busind, pcidev[devind].pd_dev, 
+                       pcidev[devind].pd_busnr, pcidev[devind].pd_dev, 
                        pcidev[devind].pd_func);
 #endif