Skip to content

Instantly share code, notes, and snippets.

@nonakap
Created February 20, 2015 18:17
Show Gist options
  • Select an option

  • Save nonakap/6d1ff85bd8878dae3b0e to your computer and use it in GitHub Desktop.

Select an option

Save nonakap/6d1ff85bd8878dae3b0e to your computer and use it in GitHub Desktop.
NetBSD/x86: MSI interrupt preliminary support
Index: sys/arch/x86/include/pic.h
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/include/pic.h,v
retrieving revision 1.7
diff -u -r1.7 pic.h
--- sys/arch/x86/include/pic.h 19 Apr 2009 14:11:37 -0000 1.7
+++ sys/arch/x86/include/pic.h 20 Feb 2015 18:12:42 -0000
@@ -30,7 +30,8 @@
#define PIC_I8259 0
#define PIC_IOAPIC 1
#define PIC_LAPIC 2
-#define PIC_SOFT 3
+#define PIC_MSI 3
+#define PIC_SOFT 4
extern struct pic i8259_pic;
extern struct pic local_pic;
Index: sys/arch/x86/pci/pci_intr_machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/pci/pci_intr_machdep.c,v
retrieving revision 1.27
diff -u -r1.27 pci_intr_machdep.c
--- sys/arch/x86/pci/pci_intr_machdep.c 29 Mar 2014 19:28:30 -0000 1.27
+++ sys/arch/x86/pci/pci_intr_machdep.c 20 Feb 2015 18:12:42 -0000
@@ -112,6 +112,14 @@
#define MPSAFE_MASK 0x80000000
+#if NIOAPIC > 0
+#define MSI_MASK 0x20000000
+static void *msi_establish(pci_chipset_tag_t, pci_intr_handle_t, int,
+ int (*)(void *), void *);
+static void msi_disestablish(void *);
+static int msi_count;
+#endif
+
int
pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
{
@@ -122,13 +130,22 @@
int rawpin = pa->pa_rawintrpin;
int bus, dev, func;
#endif
-
for (ipc = pc; ipc != NULL; ipc = ipc->pc_super) {
if ((ipc->pc_present & PCI_OVERRIDE_INTR_MAP) == 0)
continue;
return (*ipc->pc_ov->ov_intr_map)(ipc->pc_ctx, pa, ihp);
}
+#if NIOAPIC > 0
+ if (mp_busses != NULL &&
+ pci_get_capability(pc, pa->pa_tag, PCI_CAP_MSI, NULL, NULL)) {
+ *ihp = pa->pa_tag.mode1 | MSI_MASK; // XXX X-(
+ *ihp &= ~0x80000000U; /*PCI_MODE1_ENABLE*/ // XXX X-(
+ *ihp |= msi_count++ & 0xff; // XXX X-(
+ return 0;
+ }
+#endif
+
if (pin == 0) {
/* No IRQ used. */
goto bad;
@@ -232,6 +249,13 @@
buf, len);
}
+#if NIOAPIC > 0
+ if (ih & MSI_MASK) {
+ snprintf(buf, len, "msi devid %d", ih & 0xff);
+ return buf;
+ }
+#endif
+
return intr_string(ih & ~MPSAFE_MASK, buf, len);
}
@@ -270,6 +294,11 @@
}
}
+struct pci_hdl {
+ struct intrhand *ih;
+ int type;
+};
+
void *
pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih,
int level, int (*func)(void *), void *arg)
@@ -289,6 +318,11 @@
pc, ih, level, func, arg);
}
+#if NIOAPIC > 0
+ if (ih & MSI_MASK)
+ return msi_establish(pc, ih, level, func, arg);
+#endif
+
pic = &i8259_pic;
pin = irq = (ih & ~MPSAFE_MASK);
mpsafe = ((ih & MPSAFE_MASK) != 0);
@@ -309,13 +343,21 @@
}
#endif
- return intr_establish(irq, pic, pin, IST_LEVEL, level, func, arg,
- mpsafe);
+ struct intrhand *ihand = intr_establish(irq, pic, pin, IST_LEVEL, level,
+ func, arg, mpsafe);
+ if (ihand == NULL)
+ return NULL;
+
+ struct pci_hdl *pcih = malloc(sizeof(*pcih), M_DEVBUF, M_WAITOK);
+ pcih->ih = ihand;
+ pcih->type = 0;
+ return pcih;
}
void
pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
{
+ struct pci_hdl *pcih = cookie;
pci_chipset_tag_t ipc;
for (ipc = pc; ipc != NULL; ipc = ipc->pc_super) {
@@ -325,7 +367,15 @@
return;
}
- intr_disestablish(cookie);
+#if NIOAPIC > 0
+ if (pcih->type == MSI_MASK) {
+ msi_disestablish(cookie);
+ return;
+ }
+#endif
+
+ intr_disestablish(pcih->ih);
+ free(pcih, M_DEVBUF);
}
#if NIOAPIC > 0
@@ -336,98 +386,119 @@
* from its kernel support)
*/
-/* dummies, needed by common intr_establish code */
+struct msi_pic {
+ struct pic mp_pic;
+ pci_chipset_tag_t mp_pc;
+ pcitag_t mp_tag;
+ int mp_co;
+};
+
static void
msipic_hwmask(struct pic *pic, int pin)
{
}
+
+static void
+msipic_hwunmask(struct pic *pic, int pin)
+{
+}
+
static void
msipic_addroute(struct pic *pic, struct cpu_info *ci,
int pin, int vec, int type)
{
+ struct msi_pic *msipic = (struct msi_pic *)pic;
+ pci_chipset_tag_t pc = msipic->mp_pc;
+ pcitag_t tag = msipic->mp_tag;
+ int co = msipic->mp_co;
+
+ pcireg_t ctl = pci_conf_read(pc, tag, co + PCI_MSI_CTL);
+ pci_conf_write(pc, tag, co + PCI_MSI_MADDR64_LO,
+ LAPIC_MSIADDR_BASE |
+ __SHIFTIN(ci->ci_cpuid, LAPIC_MSIADDR_DSTID_MASK));
+ int dataoff = PCI_MSI_MDATA;
+ if (ctl & PCI_MSI_CTL_64BIT_ADDR) {
+ dataoff = PCI_MSI_MDATA64;
+ pci_conf_write(pc, tag, co + PCI_MSI_MADDR64_HI, 0);
+ }
+ pci_conf_write(pc, tag, co + dataoff,
+ __SHIFTIN(vec, LAPIC_MSIDATA_VECTOR_MASK) |
+ LAPIC_MSIDATA_TRGMODE_EDGE | LAPIC_MSIDATA_DM_FIXED);
+ ctl |= PCI_MSI_CTL_MSI_ENABLE;
+ pci_conf_write(pc, tag, co + PCI_MSI_CTL, ctl);
+}
+
+static void
+msipic_delroute(struct pic *pic, struct cpu_info *ci,
+ int pin, int vec, int type)
+{
+ struct msi_pic *msipic = (struct msi_pic *)pic;
+ pci_chipset_tag_t pc = msipic->mp_pc;
+ pcitag_t tag = msipic->mp_tag;
+ int co = msipic->mp_co;
+
+ pcireg_t ctl = pci_conf_read(pc, tag, co + PCI_MSI_CTL);
+ ctl &= ~PCI_MSI_CTL_MSI_ENABLE;
+ pci_conf_write(pc, tag, co + PCI_MSI_CTL, ctl);
}
static struct pic msi_pic = {
.pic_name = "msi",
- .pic_type = PIC_SOFT,
+ .pic_type = PIC_MSI,
.pic_vecbase = 0,
.pic_apicid = 0,
.pic_lock = __SIMPLELOCK_UNLOCKED,
.pic_hwmask = msipic_hwmask,
- .pic_hwunmask = msipic_hwmask,
+ .pic_hwunmask = msipic_hwunmask,
.pic_addroute = msipic_addroute,
- .pic_delroute = msipic_addroute,
+ .pic_delroute = msipic_delroute,
.pic_edge_stubs = ioapic_edge_stubs,
};
struct msi_hdl {
- struct intrhand *ih;
- pci_chipset_tag_t pc;
- pcitag_t tag;
- int co;
+ struct pci_hdl pci;
+ struct msi_pic *msipic;
};
-void *
-pci_msi_establish(struct pci_attach_args *pa, int level,
- int (*func)(void *), void *arg)
+static void *
+msi_establish(pci_chipset_tag_t pc, pci_intr_handle_t pih, int level,
+ int (*func)(void *), void *arg)
{
- int co;
- struct intrhand *ih;
- struct msi_hdl *msih;
- struct cpu_info *ci;
- struct intrsource *is;
- pcireg_t reg;
+ pcitag_t tag;
+ tag.mode1 = (pih & ~(MSI_MASK|0xff)) | 0x80000000U; /*PCI_MODE1_ENABLE*/
- if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSI, &co, 0))
+ int co;
+ pcireg_t ctl;
+ if (!pci_get_capability(pc, tag, PCI_CAP_MSI, &co, &ctl))
return NULL;
- ih = intr_establish(-1, &msi_pic, -1, IST_EDGE, level, func, arg, 0);
+ struct msi_pic *msipic = malloc(sizeof(*msipic), M_DEVBUF, M_WAITOK);
+ msipic->mp_pic = msi_pic;
+ msipic->mp_pc = pc;
+ msipic->mp_tag = tag;
+ msipic->mp_co = co;
+
+ struct intrhand *ih = intr_establish(-1, &msipic->mp_pic, pih & 0xff,
+ IST_EDGE, level, func, arg, (pih & MPSAFE_MASK) != 0);
if (ih == NULL)
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 = ih->ih_cpu;
- is = ci->ci_isources[ih->ih_slot];
- reg = pci_conf_read(pa->pa_pc, pa->pa_tag, co + PCI_MSI_CTL);
- pci_conf_write(pa->pa_pc, pa->pa_tag, co + PCI_MSI_MADDR64_LO,
- LAPIC_MSIADDR_BASE |
- __SHIFTIN(ci->ci_cpuid, LAPIC_MSIADDR_DSTID_MASK));
- if (reg & PCI_MSI_CTL_64BIT_ADDR) {
- pci_conf_write(pa->pa_pc, pa->pa_tag, co + PCI_MSI_MADDR64_HI,
- 0);
- /* XXX according to the manual, ASSERT is unnecessary if
- * EDGE
- */
- pci_conf_write(pa->pa_pc, pa->pa_tag, co + PCI_MSI_MDATA64,
- __SHIFTIN(is->is_idtvec, LAPIC_MSIDATA_VECTOR_MASK) |
- LAPIC_MSIDATA_TRGMODE_EDGE | LAPIC_MSIDATA_LEVEL_ASSERT |
- LAPIC_MSIDATA_DM_FIXED);
- } else {
- /* XXX according to the manual, ASSERT is unnecessary if
- * EDGE
- */
- pci_conf_write(pa->pa_pc, pa->pa_tag, co + PCI_MSI_MDATA,
- __SHIFTIN(is->is_idtvec, LAPIC_MSIDATA_VECTOR_MASK) |
- LAPIC_MSIDATA_TRGMODE_EDGE | LAPIC_MSIDATA_LEVEL_ASSERT |
- LAPIC_MSIDATA_DM_FIXED);
- }
- pci_conf_write(pa->pa_pc, pa->pa_tag, co + PCI_MSI_CTL,
- PCI_MSI_CTL_MSI_ENABLE);
+ struct msi_hdl *msih = malloc(sizeof(*msih), M_DEVBUF, M_WAITOK);
+ msih->pci.ih = ih;
+ msih->pci.type = MSI_MASK;
+ msih->msipic = msipic;
return msih;
}
-void
-pci_msi_disestablish(void *ih)
+static void
+msi_disestablish(void *ih)
{
struct msi_hdl *msih = ih;
- pci_conf_write(msih->pc, msih->tag, msih->co + PCI_MSI_CTL, 0);
- intr_disestablish(msih->ih);
+ pci_conf_write(msih->msipic->mp_pc, msih->msipic->mp_tag,
+ msih->msipic->mp_co + PCI_MSI_CTL, 0);
+ intr_disestablish(msih->pci.ih);
+ free(msih->msipic, M_DEVBUF);
free(msih, M_DEVBUF);
}
#endif
Index: sys/arch/x86/x86/intr.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/x86/intr.c,v
retrieving revision 1.77
diff -u -r1.77 intr.c
--- sys/arch/x86/x86/intr.c 20 May 2014 03:24:19 -0000 1.77
+++ sys/arch/x86/x86/intr.c 20 Feb 2015 18:12:42 -0000
@@ -426,13 +426,17 @@
KASSERT(CPU_IS_PRIMARY(ci));
slot = pin;
} else {
+ int start = 0;
slot = -1;
+ if (CPU_IS_PRIMARY(ci) && pic->pic_type == PIC_MSI)
+ start = NUM_LEGACY_IRQS;
+
/*
* intr_allocate_slot has checked for an existing mapping.
* Now look for a free slot.
*/
- for (i = 0; i < MAX_INTR_SOURCES ; i++) {
+ for (i = start; i < MAX_INTR_SOURCES ; i++) {
if (ci->ci_isources[i] == NULL) {
slot = i;
break;
@@ -449,8 +453,13 @@
if (isp == NULL) {
return ENOMEM;
}
- snprintf(isp->is_evname, sizeof (isp->is_evname),
- "pin %d", pin);
+ if (pic->pic_type == PIC_MSI) {
+ snprintf(isp->is_evname, sizeof (isp->is_evname),
+ "devid %d", pin);
+ } else {
+ snprintf(isp->is_evname, sizeof (isp->is_evname),
+ "pin %d", pin);
+ }
evcnt_attach_dynamic(&isp->is_evcnt, EVCNT_TYPE_INTR, NULL,
pic->pic_name, isp->is_evname);
ci->ci_isources[slot] = isp;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment