Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/x86 add an experimental implementation of PCI MSIs ...



details:   https://anonhg.NetBSD.org/src/rev/edab282c2443
branches:  trunk
changeset: 767842:edab282c2443
user:      drochner <drochner%NetBSD.org@localhost>
date:      Mon Aug 01 11:08:03 2011 +0000

description:
add an experimental implementation of PCI MSIs (Message Signaled
Interrupts). Successfully tested with hdaudio and "wpi" wireless
ethernet.
notes:
-There seem to be buggy chips around which announce MSI support
 but don't correctly implement it. Thus the final word whether MSIs
 can be used should be by the driver.
-Only a single vector is supported. For multiple vectors, the IDT
 allocation code would have to be changed. (And we would possibly
 run into problems due to the limited number of vectors supported
 by the current code.)
-The code is "#if NIOAPIC > 0" because it uses the ioapic_edge
 interrupt stubs. These actually don't touch any ioapic, so this
 is somewhat a misnomer.
-MSIs can't be identified by a "pin" but only by a cpu/vector
 pair. Common intr code soesn't deal well with this yet.
-Drivers need to take care of saving/restoring MSI data in the device's
 config space on suspend/resume.

diffstat:

 sys/arch/x86/include/pci_machdep_common.h |   6 +-
 sys/arch/x86/pci/pci_intr_machdep.c       |  95 ++++++++++++++++++++++++++++++-
 2 files changed, 98 insertions(+), 3 deletions(-)

diffs (140 lines):

diff -r 071c6bd21db5 -r edab282c2443 sys/arch/x86/include/pci_machdep_common.h
--- a/sys/arch/x86/include/pci_machdep_common.h Mon Aug 01 10:42:23 2011 +0000
+++ b/sys/arch/x86/include/pci_machdep_common.h Mon Aug 01 11:08:03 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pci_machdep_common.h,v 1.6 2011/04/04 20:37:55 dyoung Exp $    */
+/*     $NetBSD: pci_machdep_common.h,v 1.7 2011/08/01 11:08:03 drochner Exp $  */
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
@@ -110,6 +110,10 @@
                    int, int (*)(void *), void *);
 void           pci_intr_disestablish(pci_chipset_tag_t, void *);
 
+/* experimental MSI support */
+void *pci_msi_establish(struct pci_attach_args *, int, int (*)(void *), void *);
+void pci_msi_disestablish(void *);
+
 /*
  * ALL OF THE FOLLOWING ARE MACHINE-DEPENDENT, AND SHOULD NOT BE USED
  * BY PORTABLE CODE.
diff -r 071c6bd21db5 -r edab282c2443 sys/arch/x86/pci/pci_intr_machdep.c
--- a/sys/arch/x86/pci/pci_intr_machdep.c       Mon Aug 01 10:42:23 2011 +0000
+++ b/sys/arch/x86/pci/pci_intr_machdep.c       Mon Aug 01 11:08:03 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pci_intr_machdep.c,v 1.19 2011/04/04 20:37:55 dyoung Exp $     */
+/*     $NetBSD: pci_intr_machdep.c,v 1.20 2011/08/01 11:08:03 drochner Exp $   */
 
 /*-
  * Copyright (c) 1997, 1998, 2009 The NetBSD Foundation, Inc.
@@ -73,7 +73,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci_intr_machdep.c,v 1.19 2011/04/04 20:37:55 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_intr_machdep.c,v 1.20 2011/08/01 11:08:03 drochner Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -82,6 +82,7 @@
 #include <sys/errno.h>
 #include <sys/device.h>
 #include <sys/intr.h>
+#include <sys/malloc.h>
 
 #include <dev/pci/pcivar.h>
 
@@ -325,3 +326,93 @@
 
        intr_disestablish(cookie);
 }
+
+#if NIOAPIC > 0
+/*
+ * experimental support for MSI, does support a single vector,
+ * no MSI-X, 8-bit APIC IDs
+ * (while it doesn't need the ioapic technically, it borrows
+ * from its kernel support)
+ */
+
+/* dummies, needed by common intr_establish code */
+static void
+msipic_hwmask(struct pic *pic, int pin)
+{
+}
+static void
+msipic_addroute(struct pic *pic, struct cpu_info *ci,
+               int pin, int vec, int type)
+{
+}
+
+static struct pic msi_pic = {
+       .pic_name = "msi",
+       .pic_type = PIC_SOFT,
+       .pic_vecbase = 0,
+       .pic_apicid = 0,
+       .pic_lock = __SIMPLELOCK_UNLOCKED,
+       .pic_hwmask = msipic_hwmask,
+       .pic_hwunmask = msipic_hwmask,
+       .pic_addroute = msipic_addroute,
+       .pic_delroute = msipic_addroute,
+       .pic_edge_stubs = ioapic_edge_stubs,
+};
+
+struct msi_hdl {
+       struct intrhand *ih;
+       pci_chipset_tag_t pc;
+       pcitag_t tag;
+       int co;
+};
+
+void *
+pci_msi_establish(struct pci_attach_args *pa, int level,
+                 int (*func)(void *), void *arg)
+{
+       int co;
+       void *ih;
+       struct msi_hdl *msih;
+       struct cpu_info *ci;
+       struct intrsource *s;
+       u_int32_t cr;
+
+       if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSI, &co, 0))
+               return NULL;
+
+       ih = intr_establish(-1, &msi_pic, -1, IST_EDGE, level,
+                           func, arg, 0);
+       if (!ih)
+               return NULL;
+
+       msih = malloc(sizeof(*msih), M_DEVBUF, M_WAITOK);
+       msih->ih = ih;
+       msih->pc = pa->pa_pc;
+       msih->tag = pa->pa_tag;
+       msih->co = co;
+
+       ci = msih->ih->ih_cpu;
+       s = ci->ci_isources[msih->ih->ih_slot];
+       cr = pci_conf_read(pa->pa_pc, pa->pa_tag, co);
+       pci_conf_write(pa->pa_pc, pa->pa_tag, co + 4,
+                      0xfee00000 | ci->ci_cpuid << 12);
+       if (cr & 0x800000) {
+               pci_conf_write(pa->pa_pc, pa->pa_tag, co + 8, 0);
+               pci_conf_write(pa->pa_pc, pa->pa_tag, co + 12,
+                              s->is_idtvec | 0x4000);
+       } else
+               pci_conf_write(pa->pa_pc, pa->pa_tag, co + 8,
+                              s->is_idtvec | 0x4000);
+       pci_conf_write(pa->pa_pc, pa->pa_tag, co, 0x10000);
+       return ih;
+}
+
+void
+pci_msi_disestablish(void *ih)
+{
+       struct msi_hdl *msih = ih;
+
+       pci_conf_write(msih->pc, msih->tag, msih->co, 0);
+       intr_disestablish(msih->ih);
+}
+#endif



Home | Main Index | Thread Index | Old Index