Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F111649233
D28803.id92173.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
17 KB
Referenced Files
None
Subscribers
None
D28803.id92173.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D28803: arm/mv: Don't rely on firmware MSI mapping in ICU
Attached
Detach File
Event Timeline
Log In to Comment