forked from Minki/linux
xen/pv-on-hvm kexec: rebind virqs to existing eventchannel ports
During a kexec boot some virqs such as timer and debugirq were already registered by the old kernel. The hypervisor will return -EEXISTS from the new EVTCHNOP_bind_virq request and the BUG in bind_virq_to_irq() triggers. Catch the -EEXISTS error and loop through all possible ports to find what port belongs to the virq/cpu combo. Signed-off-by: Olaf Hering <olaf@aepfle.de> [v2: - use NR_EVENT_CHANNELS instead of private MAX_EVTCHNS] Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
This commit is contained in:
parent
c4c303c7c5
commit
62cc5fc7b2
@ -877,11 +877,32 @@ static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
|
||||
return err ? : bind_evtchn_to_irq(bind_interdomain.local_port);
|
||||
}
|
||||
|
||||
static int find_virq(unsigned int virq, unsigned int cpu)
|
||||
{
|
||||
struct evtchn_status status;
|
||||
int port, rc = -ENOENT;
|
||||
|
||||
memset(&status, 0, sizeof(status));
|
||||
for (port = 0; port <= NR_EVENT_CHANNELS; port++) {
|
||||
status.dom = DOMID_SELF;
|
||||
status.port = port;
|
||||
rc = HYPERVISOR_event_channel_op(EVTCHNOP_status, &status);
|
||||
if (rc < 0)
|
||||
continue;
|
||||
if (status.status != EVTCHNSTAT_virq)
|
||||
continue;
|
||||
if (status.u.virq == virq && status.vcpu == cpu) {
|
||||
rc = port;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
|
||||
{
|
||||
struct evtchn_bind_virq bind_virq;
|
||||
int evtchn, irq;
|
||||
int evtchn, irq, ret;
|
||||
|
||||
spin_lock(&irq_mapping_update_lock);
|
||||
|
||||
@ -897,10 +918,16 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
|
||||
|
||||
bind_virq.virq = virq;
|
||||
bind_virq.vcpu = cpu;
|
||||
if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
|
||||
&bind_virq) != 0)
|
||||
BUG();
|
||||
evtchn = bind_virq.port;
|
||||
ret = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
|
||||
&bind_virq);
|
||||
if (ret == 0)
|
||||
evtchn = bind_virq.port;
|
||||
else {
|
||||
if (ret == -EEXIST)
|
||||
ret = find_virq(virq, cpu);
|
||||
BUG_ON(ret < 0);
|
||||
evtchn = ret;
|
||||
}
|
||||
|
||||
xen_irq_info_virq_init(cpu, irq, evtchn, virq);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user