summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgonzo <gonzo@FreeBSD.org>2016-11-06 18:40:12 +0000
committergonzo <gonzo@FreeBSD.org>2016-11-06 18:40:12 +0000
commitb82022461caea290c7bce683816b76f5bad5d78d (patch)
tree4a04888a8377ec5623ae862e2b374ecdf586d221
parent476fa99d66ff006a890ec0755cee69ff5fb89759 (diff)
downloadFreeBSD-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
-rw-r--r--sys/arm/arm/gic.c4
-rw-r--r--sys/arm/arm/nexus.c6
-rw-r--r--sys/arm64/arm64/nexus.c6
-rw-r--r--sys/kern/subr_intr.c38
-rw-r--r--sys/mips/mips/nexus.c6
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
OpenPOWER on IntegriCloud