diff options
author | gonzo <gonzo@FreeBSD.org> | 2016-11-06 18:40:12 +0000 |
---|---|---|
committer | gonzo <gonzo@FreeBSD.org> | 2016-11-06 18:40:12 +0000 |
commit | b82022461caea290c7bce683816b76f5bad5d78d (patch) | |
tree | 4a04888a8377ec5623ae862e2b374ecdf586d221 /sys | |
parent | 476fa99d66ff006a890ec0755cee69ff5fb89759 (diff) | |
download | FreeBSD-src-b82022461caea290c7bce683816b76f5bad5d78d.zip FreeBSD-src-b82022461caea290c7bce683816b76f5bad5d78d.tar.gz |
MFC r306899, r307059, r307151
r306899:
Fix release MSI method for ARM GIC
r307059:
INTRNG - fix MSI/MSIX release path
Use isrc in attached MSI data structure instead of using map's
isrc directly. map's isrc is set to NULL on IRQ deactivation
which happens prior to pci_release_msi so MSI_RELEASE_MSI
receives array of NULLs
Reviewed by: mmel
Differential Revision: https://reviews.freebsd.org/D8206
r307151:
INTRNG: Propagate IRQ activation error to API consumer
Keep resource state consistent with INTRNG state - if intr_activate_irq
fails - deactivate resource and propagate error to calling function
Reviewed by: mmel
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arm/arm/gic.c | 4 | ||||
-rw-r--r-- | sys/arm/arm/nexus.c | 6 | ||||
-rw-r--r-- | sys/arm64/arm64/nexus.c | 6 | ||||
-rw-r--r-- | sys/kern/subr_intr.c | 38 | ||||
-rw-r--r-- | sys/mips/mips/nexus.c | 6 |
5 files changed, 52 insertions, 8 deletions
diff --git a/sys/arm/arm/gic.c b/sys/arm/arm/gic.c index 133cc7f..ce8c28e 100644 --- a/sys/arm/arm/gic.c +++ b/sys/arm/arm/gic.c @@ -1700,15 +1700,15 @@ arm_gicv2m_release_msi(device_t dev, device_t child, int count, mtx_lock(&sc->sc_mutex); for (i = 0; i < count; i++) { - gi = (struct gic_irqsrc *)isrc; + gi = (struct gic_irqsrc *)isrc[i]; KASSERT((gi->gi_flags & GI_FLAG_MSI_USED) == GI_FLAG_MSI_USED, ("%s: Trying to release an unused MSI-X interrupt", __func__)); gi->gi_flags &= ~GI_FLAG_MSI_USED; - mtx_unlock(&sc->sc_mutex); } + mtx_unlock(&sc->sc_mutex); return (0); } diff --git a/sys/arm/arm/nexus.c b/sys/arm/arm/nexus.c index 9bf1b44..879bc30 100644 --- a/sys/arm/arm/nexus.c +++ b/sys/arm/arm/nexus.c @@ -383,7 +383,11 @@ nexus_activate_resource(device_t bus, device_t child, int type, int rid, return (0); } else if (type == SYS_RES_IRQ) { #ifdef INTRNG - intr_activate_irq(child, r); + err = intr_activate_irq(child, r); + if (err != 0) { + rman_deactivate_resource(r); + return (err); + } #endif } return (0); diff --git a/sys/arm64/arm64/nexus.c b/sys/arm64/arm64/nexus.c index 26e1c6c..3e071cb 100644 --- a/sys/arm64/arm64/nexus.c +++ b/sys/arm64/arm64/nexus.c @@ -346,7 +346,11 @@ nexus_activate_resource(device_t bus, device_t child, int type, int rid, rman_set_virtual(r, (void *)vaddr); rman_set_bushandle(r, vaddr); } else if (type == SYS_RES_IRQ) { - intr_activate_irq(child, r); + err = intr_activate_irq(child, r); + if (err != 0) { + rman_deactivate_resource(r); + return (err); + } } return (0); } diff --git a/sys/kern/subr_intr.c b/sys/kern/subr_intr.c index 873bff9..98e7b47 100644 --- a/sys/kern/subr_intr.c +++ b/sys/kern/subr_intr.c @@ -145,6 +145,7 @@ static u_int intrcnt_index; static struct intr_irqsrc *intr_map_get_isrc(u_int res_id); static void intr_map_set_isrc(u_int res_id, struct intr_irqsrc *isrc); +static struct intr_map_data * intr_map_get_map_data(u_int res_id); static void intr_map_copy_map_data(u_int res_id, device_t *dev, intptr_t *xref, struct intr_map_data **data); @@ -1309,6 +1310,7 @@ intr_release_msi(device_t pci, device_t child, intptr_t xref, int count, { struct intr_irqsrc **isrc; struct intr_pic *pic; + struct intr_map_data_msi *msi; int i, err; pic = pic_lookup(NULL, xref); @@ -1321,8 +1323,14 @@ intr_release_msi(device_t pci, device_t child, intptr_t xref, int count, isrc = malloc(sizeof(*isrc) * count, M_INTRNG, M_WAITOK); - for (i = 0; i < count; i++) - isrc[i] = intr_map_get_isrc(irqs[i]); + for (i = 0; i < count; i++) { + msi = (struct intr_map_data_msi *) + intr_map_get_map_data(irqs[i]); + KASSERT(msi->hdr.type == INTR_MAP_DATA_MSI, + ("%s: irq %d map data is not MSI", __func__, + irqs[i])); + isrc[i] = msi->isrc; + } err = MSI_RELEASE_MSI(pic->pic_dev, child, count, isrc); @@ -1369,6 +1377,7 @@ intr_release_msix(device_t pci, device_t child, intptr_t xref, int irq) { struct intr_irqsrc *isrc; struct intr_pic *pic; + struct intr_map_data_msi *msi; int err; pic = pic_lookup(NULL, xref); @@ -1379,7 +1388,12 @@ intr_release_msix(device_t pci, device_t child, intptr_t xref, int irq) ("%s: Found a non-MSI controller: %s", __func__, device_get_name(pic->pic_dev))); - isrc = intr_map_get_isrc(irq); + msi = (struct intr_map_data_msi *) + intr_map_get_map_data(irq); + KASSERT(msi->hdr.type == INTR_MAP_DATA_MSI, + ("%s: irq %d map data is not MSI", __func__, + irq)); + isrc = msi->isrc; if (isrc == NULL) { intr_unmap_irq(irq); return (EINVAL); @@ -1516,6 +1530,24 @@ intr_map_set_isrc(u_int res_id, struct intr_irqsrc *isrc) /* * Get a copy of intr_map_entry data */ +static struct intr_map_data * +intr_map_get_map_data(u_int res_id) +{ + struct intr_map_data *data; + + data = NULL; + mtx_lock(&irq_map_lock); + if (res_id >= irq_map_count || irq_map[res_id] == NULL) + panic("Attempt to copy invalid resource id: %u\n", res_id); + data = irq_map[res_id]->map_data; + mtx_unlock(&irq_map_lock); + + return (data); +} + +/* + * Get a copy of intr_map_entry data + */ static void intr_map_copy_map_data(u_int res_id, device_t *map_dev, intptr_t *map_xref, struct intr_map_data **data) diff --git a/sys/mips/mips/nexus.c b/sys/mips/mips/nexus.c index c0a25a2..a5bac7f 100644 --- a/sys/mips/mips/nexus.c +++ b/sys/mips/mips/nexus.c @@ -433,7 +433,11 @@ nexus_activate_resource(device_t bus, device_t child, int type, int rid, } else if (type == SYS_RES_IRQ) { #ifdef INTRNG #ifdef FDT - intr_activate_irq(child, r); + err = intr_activate_irq(child, r); + if (err != 0) { + rman_deactivate_resource(r); + return (err); + } #else /* * INTRNG without FDT needs to have the interrupt properly |