diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2011-05-30 19:09:47 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2011-05-30 19:09:47 +0000 |
commit | af1a5338237281a95fe158aeabc08c87f8528487 (patch) | |
tree | ab6561b97fa594b2dffed40b397412d1b467ebaa /sys | |
parent | 7a7439ed5fb6b4f404a29437dddda79c9b8b6efe (diff) |
Enable MSI for HyperTransport devices that have MSI remapping enabled.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pci/pci.c | 60 | ||||
-rw-r--r-- | sys/dev/pci/pcireg.h | 23 | ||||
-rw-r--r-- | sys/dev/pci/pcivar.h | 8 |
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; |