pci: Put back PCI Express related bits
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sat, 4 Jul 2009 09:02:22 +0000 (17:02 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 8 Jul 2009 10:50:38 +0000 (18:50 +0800)
sys/bus/pci/pci.c
sys/bus/pci/pci_pci.c
sys/bus/pci/pcireg.h
sys/bus/pci/pcivar.h

index 6e3ed0b..414a596 100644 (file)
@@ -113,6 +113,8 @@ static void         pci_unmask_msix(device_t dev, u_int index);
 static int             pci_msi_blacklisted(void);
 static void            pci_resume_msi(device_t dev);
 static void            pci_resume_msix(device_t dev);
+static int             pcie_slotimpl(const pcicfgregs *);
+static void            pci_print_verbose_expr(const pcicfgregs *);
 
 static void            pci_read_cap_pmgt(device_t, int, int, pcicfgregs *);
 static void            pci_read_cap_ht(device_t, int, int, pcicfgregs *);
@@ -122,7 +124,7 @@ static void         pci_read_cap_vpd(device_t, int, int, pcicfgregs *);
 static void            pci_read_cap_subvendor(device_t, int, int,
                            pcicfgregs *);
 static void            pci_read_cap_pcix(device_t, int, int, pcicfgregs *);
-static void            pci_read_cap_pcie(device_t, int, int, pcicfgregs *);
+static void            pci_read_cap_express(device_t, int, int, pcicfgregs *);
 
 static device_method_t pci_methods[] = {
        /* Device interface */
@@ -198,7 +200,7 @@ static const struct pci_read_cap {
        { PCIY_VPD,             pci_read_cap_vpd },
        { PCIY_SUBVENDOR,       pci_read_cap_subvendor },
        { PCIY_PCIX,            pci_read_cap_pcix },
-       { PCIY_EXPRESS,         pci_read_cap_pcie },
+       { PCIY_EXPRESS,         pci_read_cap_express },
        { 0, NULL } /* required last entry */
 };
 
@@ -737,16 +739,73 @@ pci_read_cap_pcix(device_t pcib, int ptr, int nextptr, pcicfgregs *cfg)
         */
        if ((cfg->hdrtype & PCIM_HDRTYPE) == 1)
                pcix_chipset = 1;
+
+       cfg->pcix.pcix_ptr = ptr;
+}
+
+static int
+pcie_slotimpl(const pcicfgregs *cfg)
+{
+       const struct pcicfg_expr *expr = &cfg->expr;
+       uint16_t port_type;
+
+       /*
+        * Only version 1 can be parsed currently 
+        */
+       if ((expr->expr_cap & PCIEM_CAP_VER_MASK) != PCIEM_CAP_VER_1)
+               return 0;
+
+       /*
+        * - Slot implemented bit is meaningful iff current port is
+        *   root port or down stream port.
+        * - Testing for root port or down stream port is meanningful
+        *   iff PCI configure has type 1 header.
+        */
+
+       if (cfg->hdrtype != 1)
+               return 0;
+
+       port_type = expr->expr_cap & PCIEM_CAP_PORT_TYPE;
+       if (port_type != PCIE_ROOT_PORT && port_type != PCIE_DOWN_STREAM_PORT)
+               return 0;
+
+       if (!(expr->expr_cap & PCIEM_CAP_SLOT_IMPL))
+               return 0;
+
+       return 1;
 }
 
 static void
-pci_read_cap_pcie(device_t pcib, int ptr, int nextptr, pcicfgregs *cfg)
+pci_read_cap_express(device_t pcib, int ptr, int nextptr, pcicfgregs *cfg)
 {
+#define REG(n, w)      \
+       PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w)
+
+       struct pcicfg_expr *expr = &cfg->expr;
+
        /*
         * Assume we have a PCI-express chipset if we have
         * at least one PCI-express device.
         */
        pcie_chipset = 1;
+
+       expr->expr_ptr = ptr;
+       expr->expr_cap = REG(ptr + PCIER_CAPABILITY, 2);
+
+       /*
+        * Only version 1 can be parsed currently 
+        */
+       if ((expr->expr_cap & PCIEM_CAP_VER_MASK) != PCIEM_CAP_VER_1)
+               return;
+
+       /*
+        * Read slot capabilities.  Slot capabilities exists iff
+        * current port's slot is implemented
+        */
+       if (pcie_slotimpl(cfg))
+               expr->expr_slotcap = REG(ptr + PCIER_SLOTCAP, 4);
+
+#undef REG
 }
 
 static void
@@ -878,31 +937,42 @@ vpd_nextbyte(struct vpd_readstate *vrs, uint8_t *data)
        return (0);
 }
 
+int
+pcie_slot_implemented(device_t dev)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+
+       return pcie_slotimpl(&dinfo->cfg);
+}
+
 void
 pcie_set_max_readrq(device_t dev, uint16_t rqsize)
 {
-        int expr_ptr;
-        uint16_t val;
-        rqsize &= PCIEM_DEVCTL_MAX_READRQ_MASK;
-        if (rqsize > PCIEM_DEVCTL_MAX_READRQ_4096) {
-                panic("%s: invalid max read request size 0x%02x\n",
-                      device_get_nameunit(dev), rqsize);
-        }
-#warning "this code is incorrect, I think"
-       pci_find_extcap_method(device_get_parent(dev), dev, PCIY_EXPRESS, &expr_ptr);
-       if(!expr_ptr)
-               panic("%s: not PCI Express\n", device_get_nameunit(dev));
-        val = pci_read_config(dev, expr_ptr + PCIER_DEVCTRL, 2);
-        if ((val & PCIEM_DEVCTL_MAX_READRQ_MASK) != rqsize) {
-                if (bootverbose)
-                        device_printf(dev, "adjust device control 0x%04x", val);
-                val &= ~PCIEM_DEVCTL_MAX_READRQ_MASK;
-                val |= rqsize;
-                pci_write_config(dev, expr_ptr + PCIER_DEVCTRL, val, 2);
-
-                if (bootverbose)
-                        kprintf(" -> 0x%04x\n", val);
-        }
+       uint8_t expr_ptr;
+       uint16_t val;
+
+       rqsize &= PCIEM_DEVCTL_MAX_READRQ_MASK;
+       if (rqsize > PCIEM_DEVCTL_MAX_READRQ_4096) {
+               panic("%s: invalid max read request size 0x%02x\n",
+                     device_get_nameunit(dev), rqsize);
+       }
+
+       expr_ptr = pci_get_pciecap_ptr(dev);
+       if (!expr_ptr)
+               panic("%s: not PCIe device\n", device_get_nameunit(dev));
+
+       val = pci_read_config(dev, expr_ptr + PCIER_DEVCTRL, 2);
+       if ((val & PCIEM_DEVCTL_MAX_READRQ_MASK) != rqsize) {
+               if (bootverbose)
+                       device_printf(dev, "adjust device control 0x%04x", val);
+
+               val &= ~PCIEM_DEVCTL_MAX_READRQ_MASK;
+               val |= rqsize;
+               pci_write_config(dev, expr_ptr + PCIER_DEVCTRL, val, 2);
+
+               if (bootverbose)
+                       kprintf(" -> 0x%04x\n", val);
+       }
 }
 
 static void
@@ -2450,9 +2520,72 @@ pci_print_verbose(struct pci_devinfo *dinfo)
                                    cfg->msix.msix_table_bar,
                                    cfg->msix.msix_pba_bar);
                }
+               pci_print_verbose_expr(cfg);
        }
 }
 
+static void
+pci_print_verbose_expr(const pcicfgregs *cfg)
+{
+       const struct pcicfg_expr *expr = &cfg->expr;
+       const char *port_name;
+       uint16_t port_type;
+
+       if (!bootverbose)
+               return;
+
+       if (expr->expr_ptr == 0) /* No PCI Express capability */
+               return;
+
+       kprintf("\tPCI Express ver.%d cap=0x%04x",
+               expr->expr_cap & PCIEM_CAP_VER_MASK, expr->expr_cap);
+       if ((expr->expr_cap & PCIEM_CAP_VER_MASK) != PCIEM_CAP_VER_1)
+               goto back;
+
+       port_type = expr->expr_cap & PCIEM_CAP_PORT_TYPE;
+
+       switch (port_type) {
+       case PCIE_END_POINT:
+               port_name = "DEVICE";
+               break;
+       case PCIE_LEG_END_POINT:
+               port_name = "LEGDEV";
+               break;
+       case PCIE_ROOT_PORT:
+               port_name = "ROOT";
+               break;
+       case PCIE_UP_STREAM_PORT:
+               port_name = "UPSTREAM";
+               break;
+       case PCIE_DOWN_STREAM_PORT:
+               port_name = "DOWNSTRM";
+               break;
+       case PCIE_PCIE2PCI_BRIDGE:
+               port_name = "PCIE2PCI";
+               break;
+       case PCIE_PCI2PCIE_BRIDGE:
+               port_name = "PCI2PCIE";
+               break;
+       default:
+               port_name = NULL;
+               break;
+       }
+       if ((port_type == PCIE_ROOT_PORT ||
+            port_type == PCIE_DOWN_STREAM_PORT) &&
+           !(expr->expr_cap & PCIEM_CAP_SLOT_IMPL))
+               port_name = NULL;
+       if (port_name != NULL)
+               kprintf("[%s]", port_name);
+
+       if (pcie_slotimpl(cfg)) {
+               kprintf(", slotcap=0x%08x", expr->expr_slotcap);
+               if (expr->expr_slotcap & PCIEM_SLTCAP_HP_CAP)
+                       kprintf("[HOTPLUG]");
+       }
+back:
+       kprintf("\n");
+}
+
 static int
 pci_porten(device_t pcib, int b, int s, int f)
 {
@@ -3505,6 +3638,15 @@ pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
        case PCI_IVAR_LATTIMER:
                *result = cfg->lattimer;
                break;
+       case PCI_IVAR_PCIXCAP_PTR:
+               *result = cfg->pcix.pcix_ptr;
+               break;
+       case PCI_IVAR_PCIECAP_PTR:
+               *result = cfg->expr.expr_ptr;
+               break;
+       case PCI_IVAR_VPDCAP_PTR:
+               *result = cfg->vpd.vpd_reg;
+               break;
        default:
                return (ENOENT);
        }
index 0532cdd..377249a 100644 (file)
@@ -283,6 +283,30 @@ pcib_attach_common(device_t dev)
            device_printf(dev, "  Subtractively decoded bridge.\n");
     }
 
+    if (pci_is_pcie(dev) && pcie_slot_implemented(dev)) {
+       uint16_t slot_ctrl;
+       uint8_t ptr;
+
+       /*
+        * XXX
+        * Before proper PCI Express hot-plug support is in place,
+        * disable all hot-plug interrupts on the PCI Express root
+        * port or down stream port for now.
+        */
+#define HPINTRS        (PCIEM_SLTCTL_HPINTR_MASK | PCIEM_SLTCTL_HPINTR_EN)
+
+       ptr = pci_get_pciecap_ptr(dev);
+       slot_ctrl = pci_read_config(dev, ptr + PCIER_SLOTCTRL, 2);
+       if (slot_ctrl & HPINTRS) {
+           device_printf(dev, "Disable PCI Express hot-plug "
+                         "interrupts(0x%04x)\n", slot_ctrl & HPINTRS);
+           slot_ctrl &= ~HPINTRS;
+           pci_write_config(dev, ptr + PCIER_SLOTCTRL, slot_ctrl, 2);
+       }
+
+#undef HPINTRS
+    }
+
     /*
      * XXX If the secondary bus number is zero, we should assign a bus number
      *     since the BIOS hasn't, then initialise the bridge.
index 15d4325..3a99d08 100644 (file)
@@ -603,19 +603,6 @@ typedef u_int32_t pcireg_t;             /* ~typical configuration space */
 /* PCI-PCI Bridge Subvendor definitions */
 #define        PCIR_SUBVENDCAP_ID      0x4
 
-/* PCI Express definitions */
-#define        PCIR_EXPRESS_FLAGS      0x2
-#define        PCIM_EXP_FLAGS_VERSION          0x000F
-#define        PCIM_EXP_FLAGS_TYPE             0x00F0
-#define        PCIM_EXP_TYPE_ENDPOINT          0x0000
-#define        PCIM_EXP_TYPE_LEGACY_ENDPOINT   0x0010
-#define        PCIM_EXP_TYPE_ROOT_PORT         0x0040
-#define        PCIM_EXP_TYPE_UPSTREAM_PORT     0x0050
-#define        PCIM_EXP_TYPE_DOWNSTREAM_PORT   0x0060
-#define        PCIM_EXP_TYPE_PCI_BRIDGE        0x0070
-#define        PCIM_EXP_FLAGS_SLOT             0x0100
-#define        PCIM_EXP_FLAGS_IRQ              0x3e00
-#define PCIER_DEVCTRL                   0x08
 /* MSI-X definitions */
 #define        PCIR_MSIX_CTRL          0x2
 #define        PCIM_MSIXCTRL_MSIX_ENABLE       0x8000
@@ -632,13 +619,60 @@ typedef u_int32_t pcireg_t;             /* ~typical configuration space */
 #define        PCIM_MSIX_BIR_BAR_24            5
 #define        PCIM_MSIX_VCTRL_MASK            0x1
 
-#define PCIEM_DEVCTL_MAX_READRQ_4096   0x5000
-#define PCIEM_DEVCTL_MAX_READRQ_MASK    0x7000  /* Max read request size */
-#define PCIEM_DEVCTL_MAX_READRQ_128     0x0000
-#define PCIEM_DEVCTL_MAX_READRQ_256     0x1000
-#define PCIEM_DEVCTL_MAX_READRQ_512     0x2000
-#define PCIEM_DEVCTL_MAX_READRQ_1024    0x3000
-#define PCIEM_DEVCTL_MAX_READRQ_2048    0x4000
-#define PCIEM_DEVCTL_MAX_READRQ_4096    0x5000
+/*
+ * PCI Express definitions
+ * According to
+ * PCI Express base specification, REV. 1.0a
+ */
+
+/* PCI Express capabilities, 16bits */
+#define PCIER_CAPABILITY       0x2
+#define PCIEM_CAP_VER_MASK     0x000f  /* Version */
+#define PCIEM_CAP_VER_1                0x0001
+#define PCIEM_CAP_PORT_TYPE    0x00f0  /* Port type mask */
+#define PCIEM_CAP_SLOT_IMPL    0x0100  /* Slot implemented,
+                                        * valid only for root port and
+                                        * switch downstream port
+                                        */
+    /* PCI Express port types */
+#define PCIE_END_POINT         0x0000  /* Endpoint device */
+#define PCIE_LEG_END_POINT     0x0010  /* Legacy endpoint device */
+#define PCIE_ROOT_PORT         0x0040  /* Root port */
+#define PCIE_UP_STREAM_PORT    0x0050  /* Switch upstream port */
+#define PCIE_DOWN_STREAM_PORT  0x0060  /* Switch downstream port */
+#define PCIE_PCIE2PCI_BRIDGE   0x0070  /* PCI Express to PCI/PCI-X bridge */
+#define PCIE_PCI2PCIE_BRIDGE   0x0080  /* PCI/PCI-X to PCI Express bridge */
+
+/* PCI Express device control, 16bits */
+#define PCIER_DEVCTRL                  0x08
+#define PCIEM_DEVCTL_MAX_READRQ_MASK   0x7000  /* Max read request size */
+#define PCIEM_DEVCTL_MAX_READRQ_128    0x0000
+#define PCIEM_DEVCTL_MAX_READRQ_256    0x1000
+#define PCIEM_DEVCTL_MAX_READRQ_512    0x2000
+#define PCIEM_DEVCTL_MAX_READRQ_1024   0x3000
+#define PCIEM_DEVCTL_MAX_READRQ_2048   0x4000
+#define PCIEM_DEVCTL_MAX_READRQ_4096   0x5000
+
+/* PCI Express slot capabilities, 32bits */
+#define PCIER_SLOTCAP          0x14
+#define PCIEM_SLTCAP_ATTEN_BTN 0x00000001 /* Attention button present */
+#define PCIEM_SLTCAP_PWR_CTRL  0x00000002 /* Power controller present */
+#define PCIEM_SLTCAP_MRL_SNS   0x00000004 /* MRL sensor present */
+#define PCIEM_SLTCAP_ATTEN_IND 0x00000008 /* Attention indicator present */
+#define PCIEM_SLTCAP_PWR_IND   0x00000010 /* Power indicator present */
+#define PCIEM_SLTCAP_HP_SURP   0x00000020 /* Hot-Plug surprise */
+#define PCIEM_SLTCAP_HP_CAP    0x00000040 /* Hot-Plug capable */
+#define PCIEM_SLTCAP_HP_MASK   0x0000007f /* Hot-Plug related bits */
+
+/* PCI Express slot control, 16bits */
+#define PCIER_SLOTCTRL                 0x18
+#define PCIEM_SLTCTL_HPINTR_MASK       0x001f  /* Hot-plug interrupts mask */
+#define PCIEM_SLTCTL_HPINTR_EN         0x0020  /* Enable hot-plug interrupts */
+    /* PCI Expres hot-plug interrupts */
+#define PCIE_HPINTR_ATTEN_BTN          0x0001  /* Attention button intr */
+#define PCIE_HPINTR_PWR_FAULT          0x0002  /* Power fault intr */
+#define PCIE_HPINTR_MRL_SNS            0x0004  /* MRL sensor changed intr */
+#define PCIE_HPINTR_PRSN_DETECT                0x0008  /* Presence detect intr */
+#define PCIE_HPINTR_CMD_COMPL          0x0010  /* Command completed intr */
 
 #endif
index 89192b8..f54e92b 100644 (file)
@@ -34,8 +34,6 @@
 #include <sys/queue.h>
 #endif
 
-#include <bus/pci/pcireg.h>
-
 extern const char *pcib_owner;  /* arbitrate who owns the pci device arch */
 
 /* some PCI bus constants */
@@ -128,6 +126,18 @@ struct pcicfg_ht {
     uint64_t   ht_msiaddr;     /* MSI mapping base address */
 };
 
+/* Interesting values for PCI Express capability */
+struct pcicfg_expr {
+    uint8_t    expr_ptr;       /* capability ptr */
+    uint16_t   expr_cap;       /* capabilities */
+    uint32_t   expr_slotcap;   /* slot capabilities */
+};
+
+/* Interesting values for PCI-X */
+struct pcicfg_pcix {
+    uint8_t    pcix_ptr;
+};
+
 /* config header information common to all header types */
 typedef struct pcicfg {
     struct device *dev;                /* device which owns this */
@@ -170,6 +180,8 @@ typedef struct pcicfg {
     struct pcicfg_msi msi;     /* pci msi */
     struct pcicfg_msix msix;   /* pci msi-x */
     struct pcicfg_ht ht;       /* HyperTransport */
+    struct pcicfg_expr expr;   /* PCI Express */
+    struct pcicfg_pcix pcix;   /* PCI-X */
 } pcicfgregs;
 
 /* additional type 1 device config header information (PCI to PCI bridge) */
@@ -253,6 +265,9 @@ enum pci_device_ivars {
     PCI_IVAR_MINGNT,
     PCI_IVAR_MAXLAT,
     PCI_IVAR_LATTIMER,
+    PCI_IVAR_PCIXCAP_PTR,
+    PCI_IVAR_PCIECAP_PTR,
+    PCI_IVAR_VPDCAP_PTR
 };
 
 /*
@@ -282,6 +297,9 @@ PCI_ACCESSOR(cachelnsz,             CACHELNSZ,      uint8_t)
 PCI_ACCESSOR(mingnt,           MINGNT,         uint8_t)
 PCI_ACCESSOR(maxlat,           MAXLAT,         uint8_t)
 PCI_ACCESSOR(lattimer,         LATTIMER,       uint8_t)
+PCI_ACCESSOR(pcixcap_ptr,      PCIXCAP_PTR,    uint8_t)
+PCI_ACCESSOR(pciecap_ptr,      PCIECAP_PTR,    uint8_t)
+PCI_ACCESSOR(vpdcap_ptr,       VPDCAP_PTR,     uint8_t)
 
 #undef PCI_ACCESSOR
 
@@ -386,7 +404,9 @@ pci_is_vga_memory_range(u_long start, u_long end)
        return ((start >= 0xa0000 && end <= 0xbffff) ? 1 : 0);
 }
 
+int pcie_slot_implemented(device_t);
 void pcie_set_max_readrq(device_t, uint16_t);
+
 /*
  * PCI power states are as defined by ACPI:
  *
@@ -429,44 +449,15 @@ pci_find_extcap(device_t dev, int capability, int *capreg)
 static __inline int
 pci_is_pcie(device_t dev)
 {
-        int reg;
-        return (pci_find_extcap(dev,  PCIY_EXPRESS, &reg) == 0);
+       return (pci_get_pciecap_ptr(dev) != 0);
 }
 
 static __inline int
 pci_is_pcix(device_t dev)
 {
-        int reg;
-        return (pci_find_extcap(dev,  PCIY_PCIX, &reg) == 0);
-}
-
-#warning "this code is probably incorrect"
-static __inline int*
-pci_get_vpdcap_ptr(device_t dev)
-{
-       int *reg;
-       pci_find_extcap(dev, PCIY_VPD, reg);
-       return reg;
+       return (pci_get_pcixcap_ptr(dev) != 0);
 }
 
-static __inline int*
-pci_get_pciecap_ptr(device_t dev)
-{
-       int *reg;
-       pci_find_extcap(dev, PCIY_EXPRESS, reg);
-       return reg;
-}
-
-
-static __inline int*
-pci_get_pcixcap_ptr(device_t dev)
-{
-       int *reg;
-       pci_find_extcap(dev, PCIY_PCIX, reg);
-       return reg;
-}
-
-
 static __inline int
 pci_alloc_msi(device_t dev, int *count)
 {