spapr: move the IRQ allocation routines under the machine

Also change the prototype to use a sPAPRMachineState and prefix them
with spapr_irq_. It will let us synchronise the IRQ allocation with
the XIVE interrupt mode when available.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
Cédric Le Goater 2017-12-01 17:06:02 +01:00 committed by David Gibson
parent ed0c37eedf
commit 60c6823b9b
9 changed files with 131 additions and 129 deletions

View File

@ -64,10 +64,6 @@ xics_ics_simple_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq 0x%x]
xics_ics_simple_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq 0x%x [src %d] server 0x%x prio 0x%x"
xics_ics_simple_reject(int nr, int srcno) "reject irq 0x%x [src %d]"
xics_ics_simple_eoi(int nr) "ics_eoi: irq 0x%x"
xics_alloc(int irq) "irq %d"
xics_alloc_block(int first, int num, bool lsi, int align) "first irq %d, %d irqs, lsi=%d, alignnum %d"
xics_ics_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs"
xics_ics_free_warn(int src, int irq) "Source#%d, irq %d is already free"
# hw/intc/s390_flic_kvm.c
flic_create_device(int err) "flic: create device failed %d"

View File

@ -245,120 +245,6 @@ void xics_spapr_init(sPAPRMachineState *spapr)
spapr_register_hypercall(H_IPOLL, h_ipoll);
}
#define ICS_IRQ_FREE(ics, srcno) \
(!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
static int ics_find_free_block(ICSState *ics, int num, int alignnum)
{
int first, i;
for (first = 0; first < ics->nr_irqs; first += alignnum) {
if (num > (ics->nr_irqs - first)) {
return -1;
}
for (i = first; i < first + num; ++i) {
if (!ICS_IRQ_FREE(ics, i)) {
break;
}
}
if (i == (first + num)) {
return first;
}
}
return -1;
}
int spapr_ics_alloc(ICSState *ics, int irq_hint, bool lsi, Error **errp)
{
int irq;
if (!ics) {
return -1;
}
if (irq_hint) {
if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) {
error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint);
return -1;
}
irq = irq_hint;
} else {
irq = ics_find_free_block(ics, 1, 1);
if (irq < 0) {
error_setg(errp, "can't allocate IRQ: no IRQ left");
return -1;
}
irq += ics->offset;
}
ics_set_irq_type(ics, irq - ics->offset, lsi);
trace_xics_alloc(irq);
return irq;
}
/*
* Allocate block of consecutive IRQs, and return the number of the first IRQ in
* the block. If align==true, aligns the first IRQ number to num.
*/
int spapr_ics_alloc_block(ICSState *ics, int num, bool lsi,
bool align, Error **errp)
{
int i, first = -1;
if (!ics) {
return -1;
}
/*
* MSIMesage::data is used for storing VIRQ so
* it has to be aligned to num to support multiple
* MSI vectors. MSI-X is not affected by this.
* The hint is used for the first IRQ, the rest should
* be allocated continuously.
*/
if (align) {
assert((num == 1) || (num == 2) || (num == 4) ||
(num == 8) || (num == 16) || (num == 32));
first = ics_find_free_block(ics, num, num);
} else {
first = ics_find_free_block(ics, num, 1);
}
if (first < 0) {
error_setg(errp, "can't find a free %d-IRQ block", num);
return -1;
}
for (i = first; i < first + num; ++i) {
ics_set_irq_type(ics, i, lsi);
}
first += ics->offset;
trace_xics_alloc_block(first, num, lsi, align);
return first;
}
static void ics_free(ICSState *ics, int srcno, int num)
{
int i;
for (i = srcno; i < srcno + num; ++i) {
if (ICS_IRQ_FREE(ics, i)) {
trace_xics_ics_free_warn(0, i + ics->offset);
}
memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
}
}
void spapr_ics_free(ICSState *ics, int irq, int num)
{
if (ics_valid_irq(ics, irq)) {
trace_xics_ics_free(0, irq, num);
ics_free(ics, irq - ics->offset, num);
}
}
void spapr_dt_xics(int nr_servers, void *fdt, uint32_t phandle)
{
uint32_t interrupt_server_ranges_prop[] = {

View File

@ -3558,6 +3558,120 @@ static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
return cpu ? ICP(cpu->intc) : NULL;
}
#define ICS_IRQ_FREE(ics, srcno) \
(!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
static int ics_find_free_block(ICSState *ics, int num, int alignnum)
{
int first, i;
for (first = 0; first < ics->nr_irqs; first += alignnum) {
if (num > (ics->nr_irqs - first)) {
return -1;
}
for (i = first; i < first + num; ++i) {
if (!ICS_IRQ_FREE(ics, i)) {
break;
}
}
if (i == (first + num)) {
return first;
}
}
return -1;
}
int spapr_irq_alloc(sPAPRMachineState *spapr, int irq_hint, bool lsi,
Error **errp)
{
ICSState *ics = spapr->ics;
int irq;
if (!ics) {
return -1;
}
if (irq_hint) {
if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) {
error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint);
return -1;
}
irq = irq_hint;
} else {
irq = ics_find_free_block(ics, 1, 1);
if (irq < 0) {
error_setg(errp, "can't allocate IRQ: no IRQ left");
return -1;
}
irq += ics->offset;
}
ics_set_irq_type(ics, irq - ics->offset, lsi);
trace_spapr_irq_alloc(irq);
return irq;
}
/*
* Allocate block of consecutive IRQs, and return the number of the first IRQ in
* the block. If align==true, aligns the first IRQ number to num.
*/
int spapr_irq_alloc_block(sPAPRMachineState *spapr, int num, bool lsi,
bool align, Error **errp)
{
ICSState *ics = spapr->ics;
int i, first = -1;
if (!ics) {
return -1;
}
/*
* MSIMesage::data is used for storing VIRQ so
* it has to be aligned to num to support multiple
* MSI vectors. MSI-X is not affected by this.
* The hint is used for the first IRQ, the rest should
* be allocated continuously.
*/
if (align) {
assert((num == 1) || (num == 2) || (num == 4) ||
(num == 8) || (num == 16) || (num == 32));
first = ics_find_free_block(ics, num, num);
} else {
first = ics_find_free_block(ics, num, 1);
}
if (first < 0) {
error_setg(errp, "can't find a free %d-IRQ block", num);
return -1;
}
for (i = first; i < first + num; ++i) {
ics_set_irq_type(ics, i, lsi);
}
first += ics->offset;
trace_spapr_irq_alloc_block(first, num, lsi, align);
return first;
}
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num)
{
ICSState *ics = spapr->ics;
int srcno = irq - ics->offset;
int i;
if (ics_valid_irq(ics, irq)) {
trace_spapr_irq_free(0, irq, num);
for (i = srcno; i < srcno + num; ++i) {
if (ICS_IRQ_FREE(ics, i)) {
trace_spapr_irq_free_warn(0, i + ics->offset);
}
memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
}
}
}
static void spapr_pic_print_info(InterruptStatsProvider *obj,
Monitor *mon)
{

View File

@ -718,7 +718,7 @@ void spapr_events_init(sPAPRMachineState *spapr)
spapr->event_sources = spapr_event_sources_new();
spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_EPOW,
spapr_ics_alloc(spapr->ics, 0, false,
spapr_irq_alloc(spapr, 0, false,
&error_fatal));
/* NOTE: if machine supports modern/dedicated hotplug event source,
@ -731,7 +731,7 @@ void spapr_events_init(sPAPRMachineState *spapr)
*/
if (spapr->use_hotplug_event_source) {
spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_HOT_PLUG,
spapr_ics_alloc(spapr->ics, 0, false,
spapr_irq_alloc(spapr, 0, false,
&error_fatal));
}

View File

@ -314,7 +314,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return;
}
spapr_ics_free(spapr->ics, msi->first_irq, msi->num);
spapr_irq_free(spapr, msi->first_irq, msi->num);
if (msi_present(pdev)) {
spapr_msi_setmsg(pdev, 0, false, 0, 0);
}
@ -352,7 +352,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
}
/* Allocate MSIs */
irq = spapr_ics_alloc_block(spapr->ics, req_num, false,
irq = spapr_irq_alloc_block(spapr, req_num, false,
ret_intr_type == RTAS_TYPE_MSI, &err);
if (err) {
error_reportf_err(err, "Can't allocate MSIs for device %x: ",
@ -363,7 +363,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
/* Release previous MSIs */
if (msi) {
spapr_ics_free(spapr->ics, msi->first_irq, msi->num);
spapr_irq_free(spapr, msi->first_irq, msi->num);
g_hash_table_remove(phb->msi, &config_addr);
}
@ -1675,7 +1675,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
uint32_t irq;
Error *local_err = NULL;
irq = spapr_ics_alloc_block(spapr->ics, 1, true, false, &local_err);
irq = spapr_irq_alloc_block(spapr, 1, true, false, &local_err);
if (local_err) {
error_propagate(errp, local_err);
error_prepend(errp, "can't allocate LSIs: ");

View File

@ -454,7 +454,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
dev->qdev.id = id;
}
dev->irq = spapr_ics_alloc(spapr->ics, dev->irq, false, &local_err);
dev->irq = spapr_irq_alloc(spapr, dev->irq, false, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;

View File

@ -12,6 +12,10 @@ spapr_pci_msi_retry(unsigned config_addr, unsigned req_num, unsigned max_irqs) "
# hw/ppc/spapr.c
spapr_cas_failed(unsigned long n) "DT diff buffer is too small: %ld bytes"
spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes"
spapr_irq_alloc(int irq) "irq %d"
spapr_irq_alloc_block(int first, int num, bool lsi, int align) "first irq %d, %d irqs, lsi=%d, alignnum %d"
spapr_irq_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs"
spapr_irq_free_warn(int src, int irq) "Source#%d, irq %d is already free"
# hw/ppc/spapr_hcall.c
spapr_cas_pvr_try(uint32_t pvr) "0x%x"

View File

@ -707,4 +707,10 @@ void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg);
int spapr_vcpu_id(PowerPCCPU *cpu);
PowerPCCPU *spapr_find_cpu(int vcpu_id);
int spapr_irq_alloc(sPAPRMachineState *spapr, int irq_hint, bool lsi,
Error **errp);
int spapr_irq_alloc_block(sPAPRMachineState *spapr, int num, bool lsi,
bool align, Error **errp);
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num);
#endif /* HW_SPAPR_H */

View File

@ -181,10 +181,6 @@ typedef struct XICSFabricClass {
#define XICS_IRQS_SPAPR 1024
int spapr_ics_alloc(ICSState *ics, int irq_hint, bool lsi, Error **errp);
int spapr_ics_alloc_block(ICSState *ics, int num, bool lsi, bool align,
Error **errp);
void spapr_ics_free(ICSState *ics, int irq, int num);
void spapr_dt_xics(int nr_servers, void *fdt, uint32_t phandle);
qemu_irq xics_get_qirq(XICSFabric *xi, int irq);