Page MenuHomeFreeBSD

D28803.id92173.diff
No OneTemporary

D28803.id92173.diff

Index: sys/arm/mv/mv_ap806_gicp.c
===================================================================
--- sys/arm/mv/mv_ap806_gicp.c
+++ sys/arm/mv/mv_ap806_gicp.c
@@ -34,6 +34,7 @@
#include <sys/systm.h>
#include <sys/bus.h>
+#include <sys/bitset.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/rman.h>
@@ -49,10 +50,18 @@
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include <arm/arm/gic_common.h>
+
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#include "msi_if.h"
#include "pic_if.h"
#define MV_AP806_GICP_MAX_NIRQS 207
+MALLOC_DECLARE(M_GICP);
+MALLOC_DEFINE(M_GICP, "gicp", "Marvell gicp driver");
+
struct mv_ap806_gicp_softc {
device_t dev;
device_t parent;
@@ -61,6 +70,9 @@
ssize_t spi_ranges_cnt;
uint32_t *spi_ranges;
struct intr_map_data_fdt *parent_map_data;
+
+ ssize_t msi_bitmap_size; /* Nr of bits in the bitmap. */
+ BITSET_DEFINE_VAR() *msi_bitmap;
};
static struct ofw_compat_data compat_data[] = {
@@ -71,6 +83,10 @@
#define RD4(sc, reg) bus_read_4((sc)->res, (reg))
#define WR4(sc, reg, val) bus_write_4((sc)->res, (reg), (val))
+static msi_alloc_msi_t mv_ap806_gicp_alloc_msi;
+static msi_release_msi_t mv_ap806_gicp_release_msi;
+static msi_map_msi_t mv_ap806_gicp_map_msi;
+
static int
mv_ap806_gicp_probe(device_t dev)
{
@@ -90,6 +106,7 @@
{
struct mv_ap806_gicp_softc *sc;
phandle_t node, xref, intr_parent;
+ int i, rid;
sc = device_get_softc(dev);
sc->dev = dev;
@@ -107,9 +124,28 @@
return (ENXIO);
}
+ rid = 0;
+ sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (sc->res == NULL) {
+ device_printf(dev, "cannot allocate resources for device\n");
+ return (ENXIO);
+ }
+
sc->spi_ranges_cnt = OF_getencprop_alloc_multi(node, "marvell,spi-ranges",
sizeof(*sc->spi_ranges), (void **)&sc->spi_ranges);
+ sc->msi_bitmap_size = 0;
+ for (i = 0; i < sc->spi_ranges_cnt; i += 2)
+ sc->msi_bitmap_size += sc->spi_ranges[i + 1];
+
+ /*
+ * Create a bitmap of all MSIs that we have.
+ * Each has a correspoding SPI in the GIC.
+ * It will be used to dynamically allocate IRQs when requested.
+ */
+ sc->msi_bitmap = BITSET_ALLOC(sc->msi_bitmap_size, M_GICP, M_WAITOK);
+ BIT_FILL(sc->msi_bitmap_size, sc->msi_bitmap); /* 1 - available, 0 - used. */
+
xref = OF_xref_from_node(node);
if (intr_pic_register(dev, xref) == NULL) {
device_printf(dev, "Cannot register GICP\n");
@@ -131,38 +167,58 @@
return (EBUSY);
}
+static uint32_t
+mv_ap806_gicp_msi_to_spi(struct mv_ap806_gicp_softc *sc, int irq)
+{
+ int i;
+
+ for (i = 0; i < sc->spi_ranges_cnt; i += 2) {
+ if (irq < sc->spi_ranges[i + 1]) {
+ irq += sc->spi_ranges[i];
+ break;
+ }
+ irq -= sc->spi_ranges[i + 1];
+ }
+
+ return (irq - GIC_FIRST_SPI);
+}
+
+static uint32_t
+mv_ap806_gicp_irq_to_msi(struct mv_ap806_gicp_softc *sc, int irq)
+{
+ int i;
+
+ for (i = 0; i < sc->spi_ranges_cnt; i += 2) {
+ if (irq >= sc->spi_ranges[i] &&
+ irq - sc->spi_ranges[i] < sc->spi_ranges[i + 1]) {
+ irq -= sc->spi_ranges[i];
+ break;
+ }
+ }
+
+ return (irq);
+}
+
static struct intr_map_data *
mv_ap806_gicp_convert_map_data(struct mv_ap806_gicp_softc *sc,
struct intr_map_data *data)
{
struct intr_map_data_fdt *daf;
- uint32_t i, irq_num, irq_type;
+ uint32_t irq_num;
daf = (struct intr_map_data_fdt *)data;
if (daf->ncells != 2)
return (NULL);
irq_num = daf->cells[0];
- irq_type = daf->cells[1];
if (irq_num >= MV_AP806_GICP_MAX_NIRQS)
return (NULL);
/* Construct GIC compatible mapping. */
sc->parent_map_data->ncells = 3;
sc->parent_map_data->cells[0] = 0; /* SPI */
- sc->parent_map_data->cells[2] = irq_type;
-
- /* Map the interrupt number to SPI number */
- for (i = 0; i < sc->spi_ranges_cnt; i += 2) {
- if (irq_num < sc->spi_ranges[i + 1]) {
- irq_num += sc->spi_ranges[i];
- break;
- }
-
- irq_num -= sc->spi_ranges[i];
- }
-
- sc->parent_map_data->cells[1] = irq_num - 32;
+ sc->parent_map_data->cells[1] = mv_ap806_gicp_msi_to_spi(sc, irq_num);
+ sc->parent_map_data->cells[2] = IRQ_TYPE_LEVEL_HIGH;
return ((struct intr_map_data *)sc->parent_map_data);
}
@@ -205,21 +261,9 @@
mv_ap806_gicp_map_intr(device_t dev, struct intr_map_data *data,
struct intr_irqsrc **isrcp)
{
- struct mv_ap806_gicp_softc *sc;
- int ret;
-
- sc = device_get_softc(dev);
-
- if (data->type != INTR_MAP_DATA_FDT)
- return (ENOTSUP);
- data = mv_ap806_gicp_convert_map_data(sc, data);
- if (data == NULL)
- return (EINVAL);
-
- ret = PIC_MAP_INTR(sc->parent, data, isrcp);
- (*isrcp)->isrc_dev = sc->dev;
- return(ret);
+ panic("%s: MSI interface has to be used to map an interrupt.\n",
+ __func__);
}
static int
@@ -295,6 +339,83 @@
PIC_POST_FILTER(sc->parent, isrc);
}
+static int
+mv_ap806_gicp_alloc_msi(device_t dev, device_t child, int count, int maxcount,
+ device_t *pic, struct intr_irqsrc **srcs)
+{
+ struct mv_ap806_gicp_softc *sc;
+ int i, ret, vector;
+
+ sc = device_get_softc(dev);
+
+ for (i = 0; i < count; i++) {
+ /*
+ * Find first available vector represented by first set bit
+ * in the bitmap. BIT_FFS starts the count from 1, 0 means
+ * that nothing was found.
+ */
+ vector = BIT_FFS(sc->msi_bitmap_size, sc->msi_bitmap);
+ if (vector == 0) {
+ ret = ENOMEM;
+ i--;
+ goto fail;
+ }
+ vector--;
+ BIT_CLR(sc->msi_bitmap_size, vector, sc->msi_bitmap);
+
+ /* Create GIC compatible SPI interrupt description. */
+ sc->parent_map_data->ncells = 3;
+ sc->parent_map_data->cells[0] = 0; /* SPI */
+ sc->parent_map_data->cells[1] = mv_ap806_gicp_msi_to_spi(sc, vector);
+ sc->parent_map_data->cells[2] = IRQ_TYPE_LEVEL_HIGH;
+
+ ret = PIC_MAP_INTR(sc->parent,
+ (struct intr_map_data *)sc->parent_map_data,
+ &srcs[i]);
+ if (ret != 0)
+ goto fail;
+
+ srcs[i]->isrc_dev = dev;
+ }
+
+ return (0);
+fail:
+ mv_ap806_gicp_release_msi(dev, child, i + 1, srcs);
+ return (ret);
+}
+
+static int
+mv_ap806_gicp_release_msi(device_t dev, device_t child, int count,
+ struct intr_irqsrc **srcs)
+{
+ struct mv_ap806_gicp_softc *sc;
+ int i;
+
+ sc = device_get_softc(dev);
+
+ for (i = 0; i < count; i++) {
+ BIT_SET(sc->msi_bitmap_size,
+ mv_ap806_gicp_irq_to_msi(sc, srcs[i]->isrc_irq),
+ sc->msi_bitmap);
+ }
+
+ return (0);
+}
+
+static int
+mv_ap806_gicp_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc,
+ uint64_t *addr, uint32_t *data)
+{
+ struct mv_ap806_gicp_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ *addr = rman_get_start(sc->res);
+ *data = mv_ap806_gicp_irq_to_msi(sc, isrc->isrc_irq);
+
+ return (0);
+}
+
static device_method_t mv_ap806_gicp_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, mv_ap806_gicp_probe),
@@ -313,6 +434,11 @@
DEVMETHOD(pic_post_ithread, mv_ap806_gicp_post_ithread),
DEVMETHOD(pic_pre_ithread, mv_ap806_gicp_pre_ithread),
+ /* MSI interface */
+ DEVMETHOD(msi_alloc_msi, mv_ap806_gicp_alloc_msi),
+ DEVMETHOD(msi_release_msi, mv_ap806_gicp_release_msi),
+ DEVMETHOD(msi_map_msi, mv_ap806_gicp_map_msi),
+
DEVMETHOD_END
};
Index: sys/arm/mv/mv_ap806_sei.c
===================================================================
--- sys/arm/mv/mv_ap806_sei.c
+++ sys/arm/mv/mv_ap806_sei.c
@@ -32,6 +32,8 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
+
+#include <sys/bitset.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/rman.h>
@@ -48,6 +50,7 @@
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include "msi_if.h"
#include "pic_if.h"
#define MV_AP806_SEI_LOCK(_sc) mtx_lock(&(_sc)->mtx)
@@ -58,7 +61,6 @@
#define MV_AP806_SEI_ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED);
#define MV_AP806_SEI_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED);
-#define MV_AP806_SEI_MAX_NIRQS 64
#define GICP_SECR0 0x00
#define GICP_SECR1 0x04
#define GICP_SECR(i) (0x00 + (((i)/32) * 0x4))
@@ -68,6 +70,16 @@
#define GICP_SEMR(i) (0x20 + (((i)/32) * 0x4))
#define GICP_SEMR_BIT(i) ((i) % 32)
+#define MV_AP806_SEI_AP_FIRST 0
+#define MV_AP806_SEI_AP_SIZE 21
+#define MV_AP806_SEI_CP_FIRST 21
+#define MV_AP806_SEI_CP_SIZE 43
+#define MV_AP806_SEI_MAX_NIRQS (MV_AP806_SEI_AP_SIZE + MV_AP806_SEI_CP_SIZE)
+
+#define MV_AP806_SEI_SETSPI_OFFSET 0x30
+
+BITSET_DEFINE(sei_msi_bitmap, MV_AP806_SEI_CP_SIZE);
+
struct mv_ap806_sei_irqsrc {
struct intr_irqsrc isrc;
u_int irq;
@@ -81,6 +93,8 @@
struct mtx mtx;
struct mv_ap806_sei_irqsrc *isrcs;
+
+ struct sei_msi_bitmap msi_bitmap;
};
static struct ofw_compat_data compat_data[] = {
@@ -91,6 +105,10 @@
#define RD4(sc, reg) bus_read_4((sc)->mem_res, (reg))
#define WR4(sc, reg, val) bus_write_4((sc)->mem_res, (reg), (val))
+static msi_alloc_msi_t mv_ap806_sei_alloc_msi;
+static msi_release_msi_t mv_ap806_sei_release_msi;
+static msi_map_msi_t mv_ap806_sei_map_msi;
+
static inline void
mv_ap806_sei_isrc_mask(struct mv_ap806_sei_softc *sc,
struct mv_ap806_sei_irqsrc *sisrc, uint32_t val)
@@ -152,8 +170,13 @@
return (ENOTSUP);
daf = (struct intr_map_data_fdt *)data;
- if (daf->ncells != 1 || daf->cells[0] >= MV_AP806_SEI_MAX_NIRQS)
+ if (daf->ncells != 1)
return (EINVAL);
+
+ if (daf->cells[0] < MV_AP806_SEI_AP_FIRST ||
+ daf->cells[0] >= MV_AP806_SEI_AP_FIRST + MV_AP806_SEI_AP_SIZE)
+ return (EINVAL);
+
irq = daf->cells[0];
if (irqp != NULL)
*irqp = irq;
@@ -361,6 +384,12 @@
goto fail;
}
+ /*
+ * Bitmap of all IRQs.
+ * 1 - available, 0 - used.
+ */
+ BIT_FILL(MV_AP806_SEI_CP_SIZE, &sc->msi_bitmap);
+
OF_device_register_xref(xref, dev);
return (0);
@@ -382,6 +411,72 @@
return (EBUSY);
}
+static int
+mv_ap806_sei_alloc_msi(device_t dev, device_t child, int count, int maxcount,
+ device_t *pic, struct intr_irqsrc **srcs)
+{
+ struct mv_ap806_sei_softc *sc;
+ int i, ret = 0, vector;
+
+ sc = device_get_softc(dev);
+
+ for (i = 0; i < count; i++) {
+ /*
+ * Find first available MSI vector represented by first set bit
+ * in the bitmap. BIT_FFS starts the count from 1,
+ * 0 means that nothing was found.
+ */
+ vector = BIT_FFS_AT(MV_AP806_SEI_CP_SIZE, &sc->msi_bitmap, 0);
+ if (vector == 0) {
+ ret = ENOMEM;
+ i--;
+ goto fail;
+ }
+
+ vector--;
+ BIT_CLR(MV_AP806_SEI_CP_SIZE, vector, &sc->msi_bitmap);
+ vector += MV_AP806_SEI_CP_FIRST;
+
+ srcs[i] = &sc->isrcs[vector].isrc;
+ }
+
+ return (ret);
+fail:
+ mv_ap806_sei_release_msi(dev, child, i + 1, srcs);
+ return (ret);
+}
+
+static int
+mv_ap806_sei_release_msi(device_t dev, device_t child, int count, struct intr_irqsrc **srcs)
+{
+ struct mv_ap806_sei_softc *sc;
+ int i;
+
+ sc = device_get_softc(dev);
+
+ for (i = 0; i < count; i++) {
+ BIT_SET(MV_AP806_SEI_CP_SIZE,
+ srcs[i]->isrc_irq - MV_AP806_SEI_CP_FIRST,
+ &sc->msi_bitmap);
+ }
+
+ return (0);
+}
+
+static int
+mv_ap806_sei_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc,
+ uint64_t *addr, uint32_t *data)
+{
+ struct mv_ap806_sei_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ *addr = rman_get_start(sc->mem_res) + MV_AP806_SEI_SETSPI_OFFSET;
+ *data = isrc->isrc_irq;
+
+ return (0);
+}
+
static device_method_t mv_ap806_sei_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, mv_ap806_sei_probe),
@@ -398,6 +493,11 @@
DEVMETHOD(pic_post_ithread, mv_ap806_sei_post_ithread),
DEVMETHOD(pic_pre_ithread, mv_ap806_sei_pre_ithread),
+ /* MSI interface */
+ DEVMETHOD(msi_alloc_msi, mv_ap806_sei_alloc_msi),
+ DEVMETHOD(msi_release_msi, mv_ap806_sei_release_msi),
+ DEVMETHOD(msi_map_msi, mv_ap806_sei_map_msi),
+
DEVMETHOD_END
};
Index: sys/arm/mv/mv_cp110_icu.c
===================================================================
--- sys/arm/mv/mv_cp110_icu.c
+++ sys/arm/mv/mv_cp110_icu.c
@@ -50,7 +50,12 @@
#include <dev/ofw/ofw_bus_subr.h>
#include <dt-bindings/interrupt-controller/irq.h>
+
#include "pic_if.h"
+#include "msi_if.h"
+
+#define ICU_TYPE_NSR 1
+#define ICU_TYPE_SEI 2
#define ICU_GRP_NSR 0x0
#define ICU_GRP_SR 0x1
@@ -61,19 +66,28 @@
#define ICU_SETSPI_NSR_AH 0x14
#define ICU_CLRSPI_NSR_AL 0x18
#define ICU_CLRSPI_NSR_AH 0x1c
+#define ICU_SETSPI_SEI_AL 0x50
+#define ICU_SETSPI_SEI_AH 0x54
#define ICU_INT_CFG(x) (0x100 + (x) * 4)
#define ICU_INT_ENABLE (1 << 24)
#define ICU_INT_EDGE (1 << 28)
#define ICU_INT_GROUP_SHIFT 29
#define ICU_INT_MASK 0x3ff
+#define ICU_INT_SATA0 109
+#define ICU_INT_SATA1 107
+
#define MV_CP110_ICU_MAX_NIRQS 207
+#define MV_CP110_ICU_CLRSPI_OFFSET 0x8
+
struct mv_cp110_icu_softc {
device_t dev;
device_t parent;
struct resource *res;
struct intr_map_data_fdt *parent_map_data;
+ bool initialized;
+ int type;
};
static struct resource_spec mv_cp110_icu_res_spec[] = {
@@ -82,8 +96,8 @@
};
static struct ofw_compat_data compat_data[] = {
- {"marvell,cp110-icu-nsr", 1},
- {"marvell,cp110-icu-sei", 2},
+ {"marvell,cp110-icu-nsr", ICU_TYPE_NSR},
+ {"marvell,cp110-icu-sei", ICU_TYPE_SEI},
{NULL, 0}
};
@@ -109,10 +123,14 @@
{
struct mv_cp110_icu_softc *sc;
phandle_t node, msi_parent;
+ uint32_t reg, icu_grp;
+ int i;
sc = device_get_softc(dev);
sc->dev = dev;
node = ofw_bus_get_node(dev);
+ sc->type = (int)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+ sc->initialized = false;
if (OF_getencprop(node, "msi-parent", &msi_parent,
sizeof(phandle_t)) <= 0) {
@@ -134,10 +152,20 @@
goto fail;
}
- /* Allocate GICP compatible mapping entry (2 cells) */
+ /* Allocate GICP/SEI compatible mapping entry (2 cells) */
sc->parent_map_data = (struct intr_map_data_fdt *)intr_alloc_map_data(
INTR_MAP_DATA_FDT, sizeof(struct intr_map_data_fdt) +
+ 3 * sizeof(phandle_t), M_WAITOK | M_ZERO);
+
+ /* Clear any previous mapping done by firmware. */
+ for (i = 0; i < MV_CP110_ICU_MAX_NIRQS; i++) {
+ reg = RD4(sc, ICU_INT_CFG(i));
+ icu_grp = reg >> ICU_INT_GROUP_SHIFT;
+
+ if (icu_grp == ICU_GRP_NSR || icu_grp == ICU_GRP_SEI)
+ WR4(sc, ICU_INT_CFG(i), 0);
+ }
+
return (0);
fail:
@@ -154,15 +182,17 @@
daf = (struct intr_map_data_fdt *)data;
if (daf->ncells != 2)
return (NULL);
+
irq_no = daf->cells[0];
- irq_type = daf->cells[1];
if (irq_no >= MV_CP110_ICU_MAX_NIRQS)
return (NULL);
+
+ irq_type = daf->cells[1];
if (irq_type != IRQ_TYPE_LEVEL_HIGH &&
irq_type != IRQ_TYPE_EDGE_RISING)
return (NULL);
- /* We rely on fact that ICU->GIC mapping is preset by bootstrap. */
+ /* ICU -> GICP/SEI mapping in set in mv_cp110_icu_map_intr. */
reg = RD4(sc, ICU_INT_CFG(irq_no));
/* Construct GICP compatible mapping. */
@@ -212,13 +242,40 @@
PIC_DISABLE_INTR(sc->parent, isrc);
}
+static void
+mv_cp110_icu_init(struct mv_cp110_icu_softc *sc, uint64_t addr)
+{
+
+ if (sc->initialized)
+ return;
+
+ switch (sc->type) {
+ case ICU_TYPE_NSR:
+ WR4(sc, ICU_SETSPI_NSR_AL, addr & UINT32_MAX);
+ WR4(sc, ICU_SETSPI_NSR_AH, (addr >> 32) & UINT32_MAX);
+ addr += MV_CP110_ICU_CLRSPI_OFFSET;
+ WR4(sc, ICU_CLRSPI_NSR_AL, addr & UINT32_MAX);
+ WR4(sc, ICU_CLRSPI_NSR_AH, (addr >> 32) & UINT32_MAX);
+ break;
+ case ICU_TYPE_SEI:
+ WR4(sc, ICU_SETSPI_SEI_AL, addr & UINT32_MAX);
+ WR4(sc, ICU_SETSPI_SEI_AH, (addr >> 32) & UINT32_MAX);
+ break;
+ default:
+ panic("Unkown ICU type.");
+ }
+
+ sc->initialized = true;
+}
+
static int
mv_cp110_icu_map_intr(device_t dev, struct intr_map_data *data,
struct intr_irqsrc **isrcp)
{
struct mv_cp110_icu_softc *sc;
struct intr_map_data_fdt *daf;
- uint32_t reg, irq_no, irq_type;
+ uint32_t vector, irq_no, irq_type;
+ uint64_t addr;
int ret;
sc = device_get_softc(dev);
@@ -230,23 +287,62 @@
daf = (struct intr_map_data_fdt *)data;
if (daf->ncells != 2)
return (EINVAL);
+
irq_no = daf->cells[0];
+ if (irq_no >= MV_CP110_ICU_MAX_NIRQS)
+ return (EINVAL);
+
irq_type = daf->cells[1];
- data = mv_cp110_icu_convert_map_data(sc, data);
- if (data == NULL)
+ if (irq_type != IRQ_TYPE_LEVEL_HIGH &&
+ irq_type != IRQ_TYPE_EDGE_RISING)
return (EINVAL);
- reg = RD4(sc, ICU_INT_CFG(irq_no));
- reg |= ICU_INT_ENABLE;
- if (irq_type == IRQ_TYPE_LEVEL_HIGH)
- reg &= ~ICU_INT_EDGE;
+ /*
+ * Allocate MSI vector.
+ * We don't use intr_alloc_msi wrapper, since it registers a new irq
+ * in the kernel. In our case irq was already added by the ofw code.
+ */
+ ret = MSI_ALLOC_MSI(sc->parent, dev, 1, 1, NULL, isrcp);
+ if (ret != 0)
+ return (ret);
+
+ ret = MSI_MAP_MSI(sc->parent, dev, *isrcp, &addr, &vector);
+ if (ret != 0)
+ goto fail;
+
+ mv_cp110_icu_init(sc, addr);
+ vector |= ICU_INT_ENABLE;
+
+ if (sc->type == ICU_TYPE_NSR)
+ vector |= ICU_GRP_NSR << ICU_INT_GROUP_SHIFT;
else
- reg |= ICU_INT_EDGE;
- WR4(sc, ICU_INT_CFG(irq_no), reg);
+ vector |= ICU_GRP_SEI << ICU_INT_GROUP_SHIFT;
+
+ if (irq_type & IRQ_TYPE_EDGE_BOTH)
+ vector |= ICU_INT_EDGE;
+
+ WR4(sc, ICU_INT_CFG(irq_no), vector);
+
+ /*
+ * SATA controller has two ports, each gets its own interrupt.
+ * The problem is that only one irq is described in dts.
+ * Also ahci_generic driver supports only one irq per controller.
+ * As a workaround map both interrupts when one of them is allocated.
+ * This allows us to use both SATA ports.
+ */
+ if (irq_no == ICU_INT_SATA0)
+ WR4(sc, ICU_INT_CFG(ICU_INT_SATA1), vector);
+ if (irq_no == ICU_INT_SATA1)
+ WR4(sc, ICU_INT_CFG(ICU_INT_SATA0), vector);
- ret = PIC_MAP_INTR(sc->parent, data, isrcp);
(*isrcp)->isrc_dev = sc->dev;
return (ret);
+
+fail:
+ if (*isrcp != NULL)
+ MSI_RELEASE_MSI(sc->parent, dev, 1, isrcp);
+
+ return (ret);
}
static int
@@ -254,13 +350,30 @@
struct resource *res, struct intr_map_data *data)
{
struct mv_cp110_icu_softc *sc;
+ struct intr_map_data_fdt *daf;
+ int irq_no, ret;
+
+ if (data->type != INTR_MAP_DATA_FDT)
+ return (ENOTSUP);
sc = device_get_softc(dev);
+ daf = (struct intr_map_data_fdt *)data;
+ if (daf->ncells != 2)
+ return (EINVAL);
+
+ irq_no = daf->cells[0];
data = mv_cp110_icu_convert_map_data(sc, data);
if (data == NULL)
return (EINVAL);
- return (PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data));
+ /* Clear the mapping. */
+ WR4(sc, ICU_INT_CFG(irq_no), 0);
+
+ ret = PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data);
+ if (ret != 0)
+ return (ret);
+
+ return (MSI_RELEASE_MSI(sc->parent, dev, 1, &isrc));
}
static int

File Metadata

Mime Type
text/plain
Expires
Fri, Mar 7, 12:21 PM (20 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17031960
Default Alt Text
D28803.id92173.diff (17 KB)

Event Timeline