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 *);
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 */
{ 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 */
};
*/
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
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
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)
{
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);
}
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.
/* 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
#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
#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 */
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 */
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) */
PCI_IVAR_MINGNT,
PCI_IVAR_MAXLAT,
PCI_IVAR_LATTIMER,
+ PCI_IVAR_PCIXCAP_PTR,
+ PCI_IVAR_PCIECAP_PTR,
+ PCI_IVAR_VPDCAP_PTR
};
/*
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
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:
*
static __inline int
pci_is_pcie(device_t dev)
{
- int reg;
- return (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 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, ®) == 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)
{