aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/events.c
diff options
context:
space:
mode:
authorOlaf Hering <olaf@aepfle.de>2011-08-25 12:30:48 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-09-01 11:48:54 -0400
commit62cc5fc7b2e0218144e162afb8191db9b924b5e6 (patch)
tree8d8d301157536fe6d65c8ca3303995a81a5a7d3b /drivers/xen/events.c
parentc4c303c7c5679b4b368e12f41124aee29c325b76 (diff)
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>
Diffstat (limited to 'drivers/xen/events.c')
-rw-r--r--drivers/xen/events.c37
1 files changed, 32 insertions, 5 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 30df85d8fca8..31493e906bbd 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -877,11 +877,32 @@ static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
877 return err ? : bind_evtchn_to_irq(bind_interdomain.local_port); 877 return err ? : bind_evtchn_to_irq(bind_interdomain.local_port);
878} 878}
879 879
880static int find_virq(unsigned int virq, unsigned int cpu)
881{
882 struct evtchn_status status;
883 int port, rc = -ENOENT;
884
885 memset(&status, 0, sizeof(status));
886 for (port = 0; port <= NR_EVENT_CHANNELS; port++) {
887 status.dom = DOMID_SELF;
888 status.port = port;
889 rc = HYPERVISOR_event_channel_op(EVTCHNOP_status, &status);
890 if (rc < 0)
891 continue;
892 if (status.status != EVTCHNSTAT_virq)
893 continue;
894 if (status.u.virq == virq && status.vcpu == cpu) {
895 rc = port;
896 break;
897 }
898 }
899 return rc;
900}
880 901
881int bind_virq_to_irq(unsigned int virq, unsigned int cpu) 902int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
882{ 903{
883 struct evtchn_bind_virq bind_virq; 904 struct evtchn_bind_virq bind_virq;
884 int evtchn, irq; 905 int evtchn, irq, ret;
885 906
886 spin_lock(&irq_mapping_update_lock); 907 spin_lock(&irq_mapping_update_lock);
887 908
@@ -897,10 +918,16 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
897 918
898 bind_virq.virq = virq; 919 bind_virq.virq = virq;
899 bind_virq.vcpu = cpu; 920 bind_virq.vcpu = cpu;
900 if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, 921 ret = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
901 &bind_virq) != 0) 922 &bind_virq);
902 BUG(); 923 if (ret == 0)
903 evtchn = bind_virq.port; 924 evtchn = bind_virq.port;
925 else {
926 if (ret == -EEXIST)
927 ret = find_virq(virq, cpu);
928 BUG_ON(ret < 0);
929 evtchn = ret;
930 }
904 931
905 xen_irq_info_virq_init(cpu, irq, evtchn, virq); 932 xen_irq_info_virq_init(cpu, irq, evtchn, virq);
906 933