aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/interrupts.c105
-rw-r--r--hw/npu.c21
-rw-r--r--hw/p7ioc-phb.c21
-rw-r--r--hw/p7ioc.c13
-rw-r--r--hw/phb3.c37
-rw-r--r--hw/phb4.c10
-rw-r--r--hw/psi.c29
-rw-r--r--include/interrupts.h23
8 files changed, 143 insertions, 116 deletions
diff --git a/core/interrupts.c b/core/interrupts.c
index 7109fae..f93ce7b 100644
--- a/core/interrupts.c
+++ b/core/interrupts.c
@@ -31,32 +31,15 @@
#define ICP_CPPR 0x4 /* 8-bit access */
#define ICP_MFRR 0xc /* 8-bit access */
-struct irq_source {
- uint32_t start;
- uint32_t end;
- const struct irq_source_ops *ops;
- void *data;
- struct list_node link;
-};
-
static LIST_HEAD(irq_sources);
static struct lock irq_lock = LOCK_UNLOCKED;
-void register_irq_source(const struct irq_source_ops *ops, void *data,
- uint32_t start, uint32_t count)
+void __register_irq_source(struct irq_source *is)
{
- struct irq_source *is, *is1;
-
- is = zalloc(sizeof(struct irq_source));
- assert(is);
- is->start = start;
- is->end = start + count;
- is->ops = ops;
- is->data = data;
+ struct irq_source *is1;
- prlog(PR_DEBUG, "IRQ: Registering %04x..%04x ops @%p (data %p) %s\n",
- start, start + count - 1, ops, data,
- ops->interrupt ? "[Internal]" : "[OS]");
+ prlog(PR_DEBUG, "IRQ: Registering %04x..%04x ops @%p (data %p)\n",
+ is->start, is->end - 1, is->ops, is->data);
lock(&irq_lock);
list_for_each(&irq_sources, is1, link) {
@@ -72,6 +55,21 @@ void register_irq_source(const struct irq_source_ops *ops, void *data,
unlock(&irq_lock);
}
+void register_irq_source(const struct irq_source_ops *ops, void *data,
+ uint32_t start, uint32_t count)
+{
+ struct irq_source *is;
+
+ is = zalloc(sizeof(struct irq_source));
+ assert(is);
+ is->start = start;
+ is->end = start + count;
+ is->ops = ops;
+ is->data = data;
+
+ __register_irq_source(is);
+}
+
void unregister_irq_source(uint32_t start, uint32_t count)
{
struct irq_source *is;
@@ -99,6 +97,46 @@ void unregister_irq_source(uint32_t start, uint32_t count)
assert(0);
}
+static struct irq_source *irq_find_source(uint32_t isn)
+{
+ struct irq_source *is;
+
+ lock(&irq_lock);
+ list_for_each(&irq_sources, is, link) {
+ if (isn >= is->start && isn < is->end) {
+ unlock(&irq_lock);
+ return is;
+ }
+ }
+ unlock(&irq_lock);
+
+ return NULL;
+}
+
+void adjust_irq_source(struct irq_source *is, uint32_t new_count)
+{
+ struct irq_source *is1;
+ uint32_t new_end = is->start + new_count;
+
+ prlog(PR_DEBUG, "IRQ: Adjusting %04x..%04x to %04x..%04x\n",
+ is->start, is->end - 1, is->start, new_end - 1);
+
+ lock(&irq_lock);
+ list_for_each(&irq_sources, is1, link) {
+ if (is1 == is)
+ continue;
+ if (new_end > is1->start && is->start < is1->end) {
+ prerror("adjust IRQ source overlap !\n");
+ prerror(" new: %x..%x old: %x..%x\n",
+ is->start, new_end - 1,
+ is1->start, is1->end - 1);
+ assert(0);
+ }
+ }
+ is->end = new_end;
+ unlock(&irq_lock);
+}
+
/*
* This takes a 6-bit chip id and returns a 20 bit value representing
* the PSI interrupt. This includes all the fields above, ie, is a
@@ -341,22 +379,6 @@ uint32_t p8_irq_to_phb(uint32_t irq)
return p8_irq_to_block(irq) - P8_IRQ_BLOCK_PHB_BASE;
}
-static struct irq_source *irq_find_source(uint32_t isn)
-{
- struct irq_source *is;
-
- lock(&irq_lock);
- list_for_each(&irq_sources, is, link) {
- if (isn >= is->start && isn < is->end) {
- unlock(&irq_lock);
- return is;
- }
- }
- unlock(&irq_lock);
-
- return NULL;
-}
-
bool irq_source_eoi(uint32_t isn)
{
struct irq_source *is = irq_find_source(isn);
@@ -364,7 +386,7 @@ bool irq_source_eoi(uint32_t isn)
if (!is || !is->ops->eoi)
return false;
- is->ops->eoi(is->data, isn);
+ is->ops->eoi(is, isn);
return true;
}
@@ -375,7 +397,7 @@ static int64_t opal_set_xive(uint32_t isn, uint16_t server, uint8_t priority)
if (!is || !is->ops->set_xive)
return OPAL_PARAMETER;
- return is->ops->set_xive(is->data, isn, server, priority);
+ return is->ops->set_xive(is, isn, server, priority);
}
opal_call(OPAL_SET_XIVE, opal_set_xive, 3);
@@ -386,7 +408,7 @@ static int64_t opal_get_xive(uint32_t isn, uint16_t *server, uint8_t *priority)
if (!is || !is->ops->get_xive)
return OPAL_PARAMETER;
- return is->ops->get_xive(is->data, isn, server, priority);
+ return is->ops->get_xive(is, isn, server, priority);
}
opal_call(OPAL_GET_XIVE, opal_get_xive, 3);
@@ -402,7 +424,7 @@ static int64_t opal_handle_interrupt(uint32_t isn, __be64 *outstanding_event_mas
}
/* Run it */
- is->ops->interrupt(is->data, isn);
+ is->ops->interrupt(is, isn);
/* Check timers if SLW timer isn't working */
if (!slw_timer_ok())
@@ -440,3 +462,4 @@ void init_interrupts(void)
}
}
+
diff --git a/hw/npu.c b/hw/npu.c
index 43ec46c..a0da887 100644
--- a/hw/npu.c
+++ b/hw/npu.c
@@ -700,12 +700,10 @@ static int npu_isn_valid(struct npu *p, uint32_t isn)
return true;
}
-static int64_t npu_lsi_get_xive(void *data,
- uint32_t isn,
- uint16_t *server,
- uint8_t *prio)
+static int64_t npu_lsi_get_xive(struct irq_source *is, uint32_t isn,
+ uint16_t *server, uint8_t *prio)
{
- struct npu *p = data;
+ struct npu *p = is->data;
uint32_t irq = NPU_IRQ_NUM(isn);
uint64_t lxive;
@@ -724,12 +722,10 @@ static int64_t npu_lsi_get_xive(void *data,
return OPAL_SUCCESS;
}
-static int64_t npu_lsi_set_xive(void *data,
- uint32_t isn,
- uint16_t server,
- uint8_t prio)
+static int64_t npu_lsi_set_xive(struct irq_source *is, uint32_t isn,
+ uint16_t server, uint8_t prio)
{
- struct npu *p = data;
+ struct npu *p = is->data;
uint32_t irq = NPU_IRQ_NUM(isn);
uint64_t lxive;
@@ -754,9 +750,9 @@ static int64_t npu_lsi_set_xive(void *data,
return OPAL_SUCCESS;
}
-static void npu_err_interrupt(void *data, uint32_t isn)
+static void npu_err_interrupt(struct irq_source *is, uint32_t isn)
{
- struct npu *p = data;
+ struct npu *p = is->data;
uint32_t irq = NPU_IRQ_NUM(isn);
if (!npu_isn_valid(p, isn))
@@ -1888,3 +1884,4 @@ void probe_npu(void)
dt_for_each_compatible(dt_root, np, "ibm,power8-npu-pciex")
npu_create_phb(np);
}
+
diff --git a/hw/p7ioc-phb.c b/hw/p7ioc-phb.c
index 6f5a6ab..52ff952 100644
--- a/hw/p7ioc-phb.c
+++ b/hw/p7ioc-phb.c
@@ -2362,10 +2362,10 @@ static const struct phb_ops p7ioc_phb_ops = {
};
/* p7ioc_phb_get_xive - Interrupt control from OPAL */
-static int64_t p7ioc_msi_get_xive(void *data, uint32_t isn,
+static int64_t p7ioc_msi_get_xive(struct irq_source *is, uint32_t isn,
uint16_t *server, uint8_t *prio)
{
- struct p7ioc_phb *p = data;
+ struct p7ioc_phb *p = is->data;
uint32_t irq, fbuid = P7_IRQ_FBUID(isn);
uint64_t xive;
@@ -2382,10 +2382,10 @@ static int64_t p7ioc_msi_get_xive(void *data, uint32_t isn,
}
/* p7ioc_phb_set_xive - Interrupt control from OPAL */
-static int64_t p7ioc_msi_set_xive(void *data, uint32_t isn,
+static int64_t p7ioc_msi_set_xive(struct irq_source *is, uint32_t isn,
uint16_t server, uint8_t prio)
{
- struct p7ioc_phb *p = data;
+ struct p7ioc_phb *p = is->data;
uint32_t irq, fbuid = P7_IRQ_FBUID(isn);
uint64_t xive, m_server, m_prio;
@@ -2422,10 +2422,10 @@ static int64_t p7ioc_msi_set_xive(void *data, uint32_t isn,
}
/* p7ioc_phb_get_xive - Interrupt control from OPAL */
-static int64_t p7ioc_lsi_get_xive(void *data, uint32_t isn,
+static int64_t p7ioc_lsi_get_xive(struct irq_source *is, uint32_t isn,
uint16_t *server, uint8_t *prio)
{
- struct p7ioc_phb *p = data;
+ struct p7ioc_phb *p = is->data;
uint32_t irq = (isn & 0x7);
uint32_t fbuid = P7_IRQ_FBUID(isn);
uint64_t xive;
@@ -2441,10 +2441,10 @@ static int64_t p7ioc_lsi_get_xive(void *data, uint32_t isn,
}
/* p7ioc_phb_set_xive - Interrupt control from OPAL */
-static int64_t p7ioc_lsi_set_xive(void *data, uint32_t isn,
+static int64_t p7ioc_lsi_set_xive(struct irq_source *is, uint32_t isn,
uint16_t server, uint8_t prio)
{
- struct p7ioc_phb *p = data;
+ struct p7ioc_phb *p = is->data;
uint32_t irq = (isn & 0x7);
uint32_t fbuid = P7_IRQ_FBUID(isn);
uint64_t xive, m_server, m_prio;
@@ -2481,9 +2481,9 @@ static int64_t p7ioc_lsi_set_xive(void *data, uint32_t isn,
return OPAL_SUCCESS;
}
-static void p7ioc_phb_err_interrupt(void *data, uint32_t isn)
+static void p7ioc_phb_err_interrupt(struct irq_source *is, uint32_t isn)
{
- struct p7ioc_phb *p = data;
+ struct p7ioc_phb *p = is->data;
uint64_t peev0, peev1;
PHBDBG(p, "Got interrupt 0x%04x\n", isn);
@@ -3264,3 +3264,4 @@ void p7ioc_phb_reset(struct phb *phb)
out_be64(ioc->regs + P7IOC_CIn_LEM_ERR_MASK_AND(ci_idx), 0);
}
+
diff --git a/hw/p7ioc.c b/hw/p7ioc.c
index 4480b8e..6c0732c 100644
--- a/hw/p7ioc.c
+++ b/hw/p7ioc.c
@@ -190,10 +190,10 @@ static const struct io_hub_ops p7ioc_hub_ops = {
.reset = p7ioc_reset,
};
-static int64_t p7ioc_rgc_get_xive(void *data, uint32_t isn,
+static int64_t p7ioc_rgc_get_xive(struct irq_source *is, uint32_t isn,
uint16_t *server, uint8_t *prio)
{
- struct p7ioc *ioc = data;
+ struct p7ioc *ioc = is->data;
uint32_t irq = (isn & 0xf);
uint32_t fbuid = P7_IRQ_FBUID(isn);
uint64_t xive;
@@ -208,10 +208,10 @@ static int64_t p7ioc_rgc_get_xive(void *data, uint32_t isn,
return OPAL_SUCCESS;
}
-static int64_t p7ioc_rgc_set_xive(void *data, uint32_t isn,
+static int64_t p7ioc_rgc_set_xive(struct irq_source *is, uint32_t isn,
uint16_t server, uint8_t prio)
{
- struct p7ioc *ioc = data;
+ struct p7ioc *ioc = is->data;
uint32_t irq = (isn & 0xf);
uint32_t fbuid = P7_IRQ_FBUID(isn);
uint64_t xive;
@@ -566,9 +566,9 @@ static bool p7ioc_check_GEM(struct p7ioc *ioc)
return false;
}
-static void p7ioc_rgc_interrupt(void *data, uint32_t isn)
+static void p7ioc_rgc_interrupt(struct irq_source *is, uint32_t isn)
{
- struct p7ioc *ioc = data;
+ struct p7ioc *ioc = is->data;
printf("Got RGC interrupt 0x%04x\n", isn);
@@ -679,3 +679,4 @@ void probe_p7ioc(void)
p7ioc_create_hub(np);
}
+
diff --git a/hw/phb3.c b/hw/phb3.c
index d3aae27..b97e150 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -1602,12 +1602,10 @@ static void phb3_read_phb_status(struct phb3 *p,
}
}
-static int64_t phb3_msi_get_xive(void *data,
- uint32_t isn,
- uint16_t *server,
- uint8_t *prio)
+static int64_t phb3_msi_get_xive(struct irq_source *is, uint32_t isn,
+ uint16_t *server, uint8_t *prio)
{
- struct phb3 *p = data;
+ struct phb3 *p = is->data;
uint32_t chip, index, irq;
uint64_t ive;
@@ -1631,12 +1629,10 @@ static int64_t phb3_msi_get_xive(void *data,
return OPAL_SUCCESS;
}
-static int64_t phb3_msi_set_xive(void *data,
- uint32_t isn,
- uint16_t server,
- uint8_t prio)
+static int64_t phb3_msi_set_xive(struct irq_source *is, uint32_t isn,
+ uint16_t server, uint8_t prio)
{
- struct phb3 *p = data;
+ struct phb3 *p = is->data;
uint32_t chip, index;
uint64_t *cache, ive_num, data64, m_server, m_prio, ivc;
uint32_t *ive;
@@ -1716,12 +1712,10 @@ static int64_t phb3_msi_set_xive(void *data,
return OPAL_SUCCESS;
}
-static int64_t phb3_lsi_get_xive(void *data,
- uint32_t isn,
- uint16_t *server,
- uint8_t *prio)
+static int64_t phb3_lsi_get_xive(struct irq_source *is, uint32_t isn,
+ uint16_t *server, uint8_t *prio)
{
- struct phb3 *p = data;
+ struct phb3 *p = is->data;
uint32_t chip, index, irq;
uint64_t lxive;
@@ -1742,12 +1736,10 @@ static int64_t phb3_lsi_get_xive(void *data,
return OPAL_SUCCESS;
}
-static int64_t phb3_lsi_set_xive(void *data,
- uint32_t isn,
- uint16_t server,
- uint8_t prio)
+static int64_t phb3_lsi_set_xive(struct irq_source *is, uint32_t isn,
+ uint16_t server, uint8_t prio)
{
- struct phb3 *p = data;
+ struct phb3 *p = is->data;
uint32_t chip, index, irq, entry;
uint64_t lxive;
@@ -1785,9 +1777,9 @@ static int64_t phb3_lsi_set_xive(void *data,
return OPAL_SUCCESS;
}
-static void phb3_err_interrupt(void *data, uint32_t isn)
+static void phb3_err_interrupt(struct irq_source *is, uint32_t isn)
{
- struct phb3 *p = data;
+ struct phb3 *p = is->data;
PHBDBG(p, "Got interrupt 0x%08x\n", isn);
@@ -4733,3 +4725,4 @@ void probe_phb3(void)
dt_for_each_compatible(dt_root, np, "ibm,power8-pciex")
phb3_create(np);
}
+
diff --git a/hw/phb4.c b/hw/phb4.c
index 0e92cc2..734146c 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -2991,7 +2991,7 @@ static bool phb4_calculate_windows(struct phb4 *p)
}
-static int64_t phb4_get_xive(void *data __unused, uint32_t isn,
+static int64_t phb4_get_xive(struct irq_source *is __unused, uint32_t isn,
uint16_t *server, uint8_t *prio)
{
uint32_t target_id;
@@ -3003,10 +3003,10 @@ static int64_t phb4_get_xive(void *data __unused, uint32_t isn,
return OPAL_PARAMETER;
}
-static int64_t phb4_set_xive(void *data, uint32_t isn,
+static int64_t phb4_set_xive(struct irq_source *is, uint32_t isn,
uint16_t server, uint8_t prio)
{
- struct phb4 *p = data;
+ struct phb4 *p = is->data;
uint32_t idx = isn - p->base_msi;
void *mmio_base;
@@ -3027,9 +3027,9 @@ static int64_t phb4_set_xive(void *data, uint32_t isn,
return OPAL_SUCCESS;
}
-static void phb4_eoi(void *data, uint32_t isn)
+static void phb4_eoi(struct irq_source *is, uint32_t isn)
{
- struct phb4 *p = data;
+ struct phb4 *p = is->data;
uint32_t idx = isn - p->base_msi;
void *mmio_base;
uint8_t eoi_val;
diff --git a/hw/psi.c b/hw/psi.c
index 46e059a..3efc177 100644
--- a/hw/psi.c
+++ b/hw/psi.c
@@ -343,9 +343,9 @@ bool psi_poll_fsp_interrupt(struct psi *psi)
return !!(in_be64(psi->regs + PSIHB_CR) & PSIHB_CR_FSP_IRQ);
}
-static void psi_interrupt(void *data, uint32_t isn __unused)
+static void psi_interrupt(struct irq_source *is, uint32_t isn __unused)
{
- struct psi *psi = data;
+ struct psi *psi = is->data;
u64 val;
val = in_be64(psi->regs + PSIHB_CR);
@@ -395,10 +395,10 @@ static void psi_interrupt(void *data, uint32_t isn __unused)
fsp_console_poll(NULL);
}
-static int64_t psi_p7_set_xive(void *data, uint32_t isn __unused,
- uint16_t server, uint8_t priority)
+static int64_t psi_p7_set_xive(struct irq_source *is, uint32_t isn __unused,
+ uint16_t server, uint8_t priority)
{
- struct psi *psi = data;
+ struct psi *psi = is->data;
uint64_t xivr;
if (!psi->working)
@@ -414,10 +414,10 @@ static int64_t psi_p7_set_xive(void *data, uint32_t isn __unused,
return OPAL_SUCCESS;
}
-static int64_t psi_p7_get_xive(void *data, uint32_t isn __unused,
- uint16_t *server, uint8_t *priority)
+static int64_t psi_p7_get_xive(struct irq_source *is, uint32_t isn __unused,
+ uint16_t *server, uint8_t *priority)
{
- struct psi *psi = data;
+ struct psi *psi = is->data;
uint64_t xivr;
if (!psi->working)
@@ -432,10 +432,10 @@ static int64_t psi_p7_get_xive(void *data, uint32_t isn __unused,
return OPAL_SUCCESS;
}
-static int64_t psi_p8_set_xive(void *data, uint32_t isn,
- uint16_t server, uint8_t priority)
+static int64_t psi_p8_set_xive(struct irq_source *is, uint32_t isn,
+ uint16_t server, uint8_t priority)
{
- struct psi *psi = data;
+ struct psi *psi = is->data;
uint64_t xivr_p, xivr;
switch(isn & 7) {
@@ -471,10 +471,10 @@ static int64_t psi_p8_set_xive(void *data, uint32_t isn,
return OPAL_SUCCESS;
}
-static int64_t psi_p8_get_xive(void *data, uint32_t isn __unused,
- uint16_t *server, uint8_t *priority)
+static int64_t psi_p8_get_xive(struct irq_source *is, uint32_t isn __unused,
+ uint16_t *server, uint8_t *priority)
{
- struct psi *psi = data;
+ struct psi *psi = is->data;
uint64_t xivr_p, xivr;
switch(isn & 7) {
@@ -919,3 +919,4 @@ void psi_init(void)
dt_for_each_compatible(dt_root, np, "ibm,psihb-x")
psi_init_psihb(np);
}
+
diff --git a/include/interrupts.h b/include/interrupts.h
index daa9747..3fba9d9 100644
--- a/include/interrupts.h
+++ b/include/interrupts.h
@@ -256,6 +256,8 @@ uint32_t p8_irq_to_phb(uint32_t irq);
* functions in this file (or the corresponding core/interrupts.c).
*/
+struct irq_source;
+
/*
* IRQ sources register themselves here. If an "interrupts" callback
* is provided, then all interrupts in that source will appear in
@@ -266,18 +268,27 @@ uint32_t p8_irq_to_phb(uint32_t irq);
* be used for XIVE interrupts coming from PHBs.
*/
struct irq_source_ops {
- int64_t (*set_xive)(void *data, uint32_t isn, uint16_t server,
- uint8_t priority);
- int64_t (*get_xive)(void *data, uint32_t isn, uint16_t *server,
- uint8_t *priority);
- void (*interrupt)(void *data, uint32_t isn);
+ int64_t (*set_xive)(struct irq_source *is, uint32_t isn,
+ uint16_t server, uint8_t priority);
+ int64_t (*get_xive)(struct irq_source *is, uint32_t isn,
+ uint16_t *server, uint8_t *priority);
+ void (*interrupt)(struct irq_source *is, uint32_t isn);
+ void (*eoi)(struct irq_source *is, uint32_t isn);
+};
- void (*eoi)(void *data, uint32_t isn);
+struct irq_source {
+ uint32_t start;
+ uint32_t end;
+ const struct irq_source_ops *ops;
+ void *data;
+ struct list_node link;
};
+extern void __register_irq_source(struct irq_source *is);
extern void register_irq_source(const struct irq_source_ops *ops, void *data,
uint32_t start, uint32_t count);
extern void unregister_irq_source(uint32_t start, uint32_t count);
+extern void adjust_irq_source(struct irq_source *is, uint32_t new_count);
extern uint32_t get_psi_interrupt(uint32_t chip_id);