Page MenuHomeFreeBSD

D5231.id13123.diff
No OneTemporary

D5231.id13123.diff

Index: sys/arm64/arm64/gic_v3.c
===================================================================
--- sys/arm64/arm64/gic_v3.c
+++ sys/arm64/arm64/gic_v3.c
@@ -58,6 +58,7 @@
#include "gic_v3_var.h"
/* Device and PIC methods */
+static int gic_v3_bind(device_t, u_int, u_int);
static void gic_v3_dispatch(device_t, struct trapframe *);
static void gic_v3_eoi(device_t, u_int);
static void gic_v3_mask_irq(device_t, u_int);
@@ -72,6 +73,7 @@
DEVMETHOD(device_detach, gic_v3_detach),
/* PIC interface */
+ DEVMETHOD(pic_bind, gic_v3_bind),
DEVMETHOD(pic_dispatch, gic_v3_dispatch),
DEVMETHOD(pic_eoi, gic_v3_eoi),
DEVMETHOD(pic_mask, gic_v3_mask_irq),
@@ -244,6 +246,28 @@
/*
* PIC interface.
*/
+
+static int
+gic_v3_bind(device_t dev, u_int irq, u_int cpuid)
+{
+ uint64_t aff;
+ struct gic_v3_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (irq <= GIC_LAST_PPI) {
+ /* Can't bind PPI to another CPU but it's not an error */
+ return (0);
+ } else if (irq >= GIC_FIRST_SPI && irq <= GIC_LAST_SPI) {
+ aff = CPU_AFFINITY(cpuid);
+ gic_d_write(sc, 4, GICD_IROUTER(irq), aff);
+ return (0);
+ } else if (irq >= GIC_FIRST_LPI)
+ return (lpi_migrate(dev, irq, cpuid));
+
+ return (EINVAL);
+}
+
static void
gic_v3_dispatch(device_t dev, struct trapframe *frame)
{
Index: sys/arm64/arm64/gic_v3_its.c
===================================================================
--- sys/arm64/arm64/gic_v3_its.c
+++ sys/arm64/arm64/gic_v3_its.c
@@ -92,9 +92,13 @@
static void its_init_commandq(struct gic_v3_its_softc *);
static void its_init_cpu_collection(struct gic_v3_its_softc *);
static uint32_t its_get_devid(device_t);
+static struct its_dev * its_device_find_locked(struct gic_v3_its_softc *,
+ device_t, uint32_t);
static int its_cmd_send(struct gic_v3_its_softc *, struct its_cmd_desc *);
+static void its_cmd_movi(struct gic_v3_its_softc *, struct its_dev *, uint32_t,
+ struct its_col *);
static void its_cmd_mapc(struct gic_v3_its_softc *, struct its_col *, uint8_t);
static void its_cmd_mapvi(struct gic_v3_its_softc *, struct its_dev *, uint32_t,
uint32_t);
@@ -953,6 +957,32 @@
(unmask == TRUE) ? "unmask" : "mask", irq);
}
+int
+lpi_migrate(device_t parent, uint32_t irq, u_int cpuid)
+{
+ struct gic_v3_its_softc *sc;
+ struct its_dev *its_dev;
+ struct its_col *col;
+
+ sc = its_sc;
+ mtx_lock_spin(&sc->its_dev_lock);
+ its_dev = its_device_find_locked(sc, NULL, irq);
+ mtx_unlock_spin(&sc->its_dev_lock);
+ if (its_dev == NULL) {
+ /* Cannot migrate not configured LPI */
+ return (ENXIO);
+ }
+
+ /* Find local device's interrupt identifier */
+ irq = irq - its_dev->lpis.lpi_base;
+ /* Move interrupt to another collection */
+ col = sc->its_cols[cpuid];
+ its_dev->col->col_id = cpuid;
+ its_cmd_movi(sc, its_dev, irq, col);
+
+ return (0);
+}
+
void
lpi_unmask_irq(device_t parent, uint32_t irq)
{
@@ -1053,6 +1083,20 @@
}
static void
+its_cmd_movi(struct gic_v3_its_softc *sc, struct its_dev *its_dev,
+ uint32_t id, struct its_col *col)
+{
+ struct its_cmd_desc desc;
+
+ desc.cmd_type = ITS_CMD_MOVI;
+ desc.cmd_desc_movi.its_dev = its_dev;
+ desc.cmd_desc_movi.col = col;
+ desc.cmd_desc_movi.id = id;
+
+ its_cmd_send(sc, &desc);
+}
+
+static void
its_cmd_mapc(struct gic_v3_its_softc *sc, struct its_col *col, uint8_t valid)
{
struct its_cmd_desc desc;
@@ -1216,6 +1260,12 @@
target = ITS_TARGET_NONE;
switch (cmd_type) {
+ case ITS_CMD_MOVI: /* Move interrupt ID to another collection */
+ cmd_format_command(cmd, ITS_CMD_MOVI);
+ cmd_format_id(cmd, desc->cmd_desc_movi.id);
+ cmd_format_col(cmd, desc->cmd_desc_movi.its_dev->col->col_id);
+ cmd_format_devid(cmd, desc->cmd_desc_movi.its_dev->devid);
+ break;
case ITS_CMD_SYNC: /* Wait for previous commands completion */
target = desc->cmd_desc_sync.col->col_target;
cmd_format_command(cmd, ITS_CMD_SYNC);
@@ -1367,16 +1417,28 @@
return (0);
}
+/* Find ITS device descriptor by pci_dev or irq number */
static struct its_dev *
-its_device_find_locked(struct gic_v3_its_softc *sc, device_t pci_dev)
+its_device_find_locked(struct gic_v3_its_softc *sc, device_t pci_dev,
+ uint32_t irq)
{
struct its_dev *its_dev;
+ struct lpi_chunk *lpis;
mtx_assert(&sc->its_dev_lock, MA_OWNED);
+ KASSERT((pci_dev == NULL || irq == 0),
+ ("%s: Can't search by both pci_dev and irq number", __func__));
/* Find existing device if any */
TAILQ_FOREACH(its_dev, &sc->its_dev_list, entry) {
- if (its_dev->pci_dev == pci_dev)
- return (its_dev);
+ if (pci_dev != NULL) {
+ if (its_dev->pci_dev == pci_dev)
+ return (its_dev);
+ } else if (irq != 0) {
+ lpis = &its_dev->lpis;
+ if ((irq >= lpis->lpi_base) &&
+ (irq < (lpis->lpi_base + lpis->lpi_num)))
+ return (its_dev);
+ }
}
return (NULL);
@@ -1395,7 +1457,7 @@
mtx_lock_spin(&sc->its_dev_lock);
/* Find existing device if any */
- newdev = its_device_find_locked(sc, pci_dev);
+ newdev = its_device_find_locked(sc, pci_dev, 0);
mtx_unlock_spin(&sc->its_dev_lock);
if (newdev != NULL)
return (newdev);
Index: sys/arm64/arm64/gic_v3_var.h
===================================================================
--- sys/arm64/arm64/gic_v3_var.h
+++ sys/arm64/arm64/gic_v3_var.h
@@ -133,6 +133,7 @@
};
/* ITS commands encoding */
+#define ITS_CMD_MOVI (0x01)
#define ITS_CMD_SYNC (0x05)
#define ITS_CMD_MAPD (0x08)
#define ITS_CMD_MAPC (0x09)
@@ -172,6 +173,12 @@
union {
struct {
+ struct its_dev *its_dev;
+ struct its_col *col;
+ uint32_t id;
+ } cmd_desc_movi;
+
+ struct {
struct its_col *col;
} cmd_desc_sync;
@@ -257,6 +264,7 @@
int its_init_cpu(struct gic_v3_its_softc *);
+int lpi_migrate(device_t, uint32_t, u_int);
void lpi_unmask_irq(device_t, uint32_t);
void lpi_mask_irq(device_t, uint32_t);
/*

File Metadata

Mime Type
text/plain
Expires
Fri, Aug 21, 9:43 AM (11 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37027467
Default Alt Text
D5231.id13123.diff (5 KB)

Event Timeline