diff options
author | Olaf Hering <olaf@aepfle.de> | 2011-08-25 12:30:48 -0400 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2011-09-01 11:48:54 -0400 |
commit | 62cc5fc7b2e0218144e162afb8191db9b924b5e6 (patch) | |
tree | 8d8d301157536fe6d65c8ca3303995a81a5a7d3b /drivers/xen/events.c | |
parent | c4c303c7c5679b4b368e12f41124aee29c325b76 (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.c | 37 |
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 | ||
880 | static 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 | ||
881 | int bind_virq_to_irq(unsigned int virq, unsigned int cpu) | 902 | int 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 | ||