summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2011-05-30 19:09:47 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2011-05-30 19:09:47 +0000
commitaf1a5338237281a95fe158aeabc08c87f8528487 (patch)
treeab6561b97fa594b2dffed40b397412d1b467ebaa /sys
parent7a7439ed5fb6b4f404a29437dddda79c9b8b6efe (diff)
Enable MSI for HyperTransport devices that have MSI remapping enabled.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/pci.c60
-rw-r--r--sys/dev/pci/pcireg.h23
-rw-r--r--sys/dev/pci/pcivar.h8
3 files changed, 83 insertions, 8 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 79a85a1d92c..3cb6423ce3d 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci.c,v 1.91 2011/05/19 20:14:55 kettenis Exp $ */
+/* $OpenBSD: pci.c,v 1.92 2011/05/30 19:09:46 kettenis Exp $ */
/* $NetBSD: pci.c,v 1.31 1997/06/06 23:48:04 thorpej Exp $ */
/*
@@ -370,8 +370,10 @@ pci_probe_device(struct pci_softc *sc, pcitag_t tag,
struct pci_attach_args pa;
struct pci_dev *pd;
struct device *dev;
- pcireg_t id, class, intr, bhlcr;
- int ret = 0, pin, bus, device, function;
+ pcireg_t id, class, intr, bhlcr, cap;
+ int pin, bus, device, function;
+ int off, ret = 0;
+ uint64_t addr;
pci_decompose_tag(pc, tag, &bus, &device, &function);
@@ -437,6 +439,29 @@ pci_probe_device(struct pci_softc *sc, pcitag_t tag,
}
pa.pa_intrline = PCI_INTERRUPT_LINE(intr);
+ if (pci_get_ht_capability(pc, tag, PCI_HT_CAP_MSI, &off, &cap)) {
+ /*
+ * XXX Should we enable MSI mapping ourselves on
+ * systems that have it disabled?
+ */
+ if (cap & PCI_HT_MSI_ENABLED) {
+ if ((cap & PCI_HT_MSI_FIXED) == 0) {
+ addr = pci_conf_read(pc, tag,
+ off + PCI_HT_MSI_ADDR);
+ addr |= (uint64_t)pci_conf_read(pc, tag,
+ off + PCI_HT_MSI_ADDR_HI32) << 32;
+ } else
+ addr = PCI_HT_MSI_FIXED_ADDR;
+
+ /*
+ * XXX This will fail to enable MSI on systems
+ * that don't use the canonical address.
+ */
+ if (addr == PCI_HT_MSI_FIXED_ADDR)
+ pa.pa_flags |= PCI_FLAGS_MSI_ENABLED;
+ }
+ }
+
if (match != NULL) {
ret = (*match)(&pa);
if (ret != 0 && pap != NULL)
@@ -558,6 +583,35 @@ pci_get_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid,
}
int
+pci_get_ht_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid,
+ int *offset, pcireg_t *value)
+{
+ pcireg_t reg;
+ unsigned int ofs;
+
+ if (pci_get_capability(pc, tag, PCI_CAP_HT, &ofs, NULL) == 0)
+ return (0);
+
+ while (ofs != 0) {
+#ifdef DIAGNOSTIC
+ if ((ofs & 3) || (ofs < 0x40))
+ panic("pci_get_ht_capability");
+#endif
+ reg = pci_conf_read(pc, tag, ofs);
+ if (PCI_HT_CAP(reg) == capid) {
+ if (offset)
+ *offset = ofs;
+ if (value)
+ *value = reg;
+ return (1);
+ }
+ ofs = PCI_CAPLIST_NEXT(reg);
+ }
+
+ return (0);
+}
+
+int
pci_find_device(struct pci_attach_args *pa,
int (*match)(struct pci_attach_args *))
{
diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h
index d8f299527e3..33a63cf273e 100644
--- a/sys/dev/pci/pcireg.h
+++ b/sys/dev/pci/pcireg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pcireg.h,v 1.40 2011/05/14 09:57:56 kettenis Exp $ */
+/* $OpenBSD: pcireg.h,v 1.41 2011/05/30 19:09:46 kettenis Exp $ */
/* $NetBSD: pcireg.h,v 1.26 2000/05/10 16:58:42 thorpej Exp $ */
/*
@@ -479,7 +479,7 @@ typedef u_int8_t pci_revision_t;
#define PCI_CAP_MSI 0x05
#define PCI_CAP_CPCI_HOTSWAP 0x06
#define PCI_CAP_PCIX 0x07
-#define PCI_CAP_LDT 0x08
+#define PCI_CAP_HT 0x08
#define PCI_CAP_VENDSPEC 0x09
#define PCI_CAP_DEBUGPORT 0x0a
#define PCI_CAP_CPCI_RSRCCTL 0x0b
@@ -523,6 +523,25 @@ typedef u_int8_t pci_revision_t;
#define PCI_PMCSR_STATE_D3 0x03
/*
+ * HyperTransport; access via capability pointer.
+ */
+#define PCI_HT_CAP(cr) ((((cr) >> 27) < 0x08) ? \
+ (((cr) >> 27) & 0x1c) : (((cr) >> 27) & 0x1f))
+
+#define PCI_HT_CAP_SLAVE 0x00
+#define PCI_HT_CAP_HOST 0x04
+#define PCI_HT_CAP_INTERRUPT 0x10
+#define PCI_HT_CAP_MSI 0x15
+
+#define PCI_HT_MSI_ENABLED 0x00010000
+#define PCI_HT_MSI_FIXED 0x00020000
+
+#define PCI_HT_MSI_FIXED_ADDR 0xffe00000UL
+
+#define PCI_HT_MSI_ADDR 0x04
+#define PCI_HT_MSI_ADDR_HI32 0x08
+
+/*
* PCI Express; access via capability pointer.
*/
#define PCI_PCIE_XCAP 0x00
diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h
index 395b6384b21..1f862f8cc0c 100644
--- a/sys/dev/pci/pcivar.h
+++ b/sys/dev/pci/pcivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pcivar.h,v 1.65 2011/05/21 10:34:53 kettenis Exp $ */
+/* $OpenBSD: pcivar.h,v 1.66 2011/05/30 19:09:46 kettenis Exp $ */
/* $NetBSD: pcivar.h,v 1.23 1997/06/06 23:48:05 thorpej Exp $ */
/*
@@ -231,8 +231,10 @@ int pci_io_find(pci_chipset_tag_t, pcitag_t, int, bus_addr_t *,
int pci_mem_find(pci_chipset_tag_t, pcitag_t, int, bus_addr_t *,
bus_size_t *, int *);
-int pci_get_capability(pci_chipset_tag_t, pcitag_t, int,
- int *, pcireg_t *);
+int pci_get_capability(pci_chipset_tag_t, pcitag_t, int,
+ int *, pcireg_t *);
+int pci_get_ht_capability(pci_chipset_tag_t, pcitag_t, int,
+ int *, pcireg_t *);
struct pci_matchid {
pci_vendor_id_t pm_vid;