diff options
31 files changed, 1246 insertions, 694 deletions
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index 263a2044c65b..224081ccc92f 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c | |||
@@ -53,105 +53,33 @@ EXPORT_SYMBOL_GPL(xen_platform_pci_unplug); | |||
53 | 53 | ||
54 | static __read_mostly int xen_events_irq = -1; | 54 | static __read_mostly int xen_events_irq = -1; |
55 | 55 | ||
56 | /* map fgmfn of domid to lpfn in the current domain */ | 56 | int xen_remap_domain_mfn_array(struct vm_area_struct *vma, |
57 | static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn, | 57 | unsigned long addr, |
58 | unsigned int domid) | 58 | xen_pfn_t *mfn, int nr, |
59 | int *err_ptr, pgprot_t prot, | ||
60 | unsigned domid, | ||
61 | struct page **pages) | ||
59 | { | 62 | { |
60 | int rc; | 63 | return xen_xlate_remap_gfn_array(vma, addr, mfn, nr, err_ptr, |
61 | struct xen_add_to_physmap_range xatp = { | 64 | prot, domid, pages); |
62 | .domid = DOMID_SELF, | ||
63 | .foreign_domid = domid, | ||
64 | .size = 1, | ||
65 | .space = XENMAPSPACE_gmfn_foreign, | ||
66 | }; | ||
67 | xen_ulong_t idx = fgmfn; | ||
68 | xen_pfn_t gpfn = lpfn; | ||
69 | int err = 0; | ||
70 | |||
71 | set_xen_guest_handle(xatp.idxs, &idx); | ||
72 | set_xen_guest_handle(xatp.gpfns, &gpfn); | ||
73 | set_xen_guest_handle(xatp.errs, &err); | ||
74 | |||
75 | rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp); | ||
76 | if (rc || err) { | ||
77 | pr_warn("Failed to map pfn to mfn rc:%d:%d pfn:%lx mfn:%lx\n", | ||
78 | rc, err, lpfn, fgmfn); | ||
79 | return 1; | ||
80 | } | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | struct remap_data { | ||
85 | xen_pfn_t fgmfn; /* foreign domain's gmfn */ | ||
86 | pgprot_t prot; | ||
87 | domid_t domid; | ||
88 | struct vm_area_struct *vma; | ||
89 | int index; | ||
90 | struct page **pages; | ||
91 | struct xen_remap_mfn_info *info; | ||
92 | }; | ||
93 | |||
94 | static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, | ||
95 | void *data) | ||
96 | { | ||
97 | struct remap_data *info = data; | ||
98 | struct page *page = info->pages[info->index++]; | ||
99 | unsigned long pfn = page_to_pfn(page); | ||
100 | pte_t pte = pte_mkspecial(pfn_pte(pfn, info->prot)); | ||
101 | |||
102 | if (map_foreign_page(pfn, info->fgmfn, info->domid)) | ||
103 | return -EFAULT; | ||
104 | set_pte_at(info->vma->vm_mm, addr, ptep, pte); | ||
105 | |||
106 | return 0; | ||
107 | } | 65 | } |
66 | EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_array); | ||
108 | 67 | ||
68 | /* Not used by XENFEAT_auto_translated guests. */ | ||
109 | int xen_remap_domain_mfn_range(struct vm_area_struct *vma, | 69 | int xen_remap_domain_mfn_range(struct vm_area_struct *vma, |
110 | unsigned long addr, | 70 | unsigned long addr, |
111 | xen_pfn_t mfn, int nr, | 71 | xen_pfn_t mfn, int nr, |
112 | pgprot_t prot, unsigned domid, | 72 | pgprot_t prot, unsigned domid, |
113 | struct page **pages) | 73 | struct page **pages) |
114 | { | 74 | { |
115 | int err; | 75 | return -ENOSYS; |
116 | struct remap_data data; | ||
117 | |||
118 | /* TBD: Batching, current sole caller only does page at a time */ | ||
119 | if (nr > 1) | ||
120 | return -EINVAL; | ||
121 | |||
122 | data.fgmfn = mfn; | ||
123 | data.prot = prot; | ||
124 | data.domid = domid; | ||
125 | data.vma = vma; | ||
126 | data.index = 0; | ||
127 | data.pages = pages; | ||
128 | err = apply_to_page_range(vma->vm_mm, addr, nr << PAGE_SHIFT, | ||
129 | remap_pte_fn, &data); | ||
130 | return err; | ||
131 | } | 76 | } |
132 | EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); | 77 | EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); |
133 | 78 | ||
134 | int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, | 79 | int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, |
135 | int nr, struct page **pages) | 80 | int nr, struct page **pages) |
136 | { | 81 | { |
137 | int i; | 82 | return xen_xlate_unmap_gfn_range(vma, nr, pages); |
138 | |||
139 | for (i = 0; i < nr; i++) { | ||
140 | struct xen_remove_from_physmap xrp; | ||
141 | unsigned long rc, pfn; | ||
142 | |||
143 | pfn = page_to_pfn(pages[i]); | ||
144 | |||
145 | xrp.domid = DOMID_SELF; | ||
146 | xrp.gpfn = pfn; | ||
147 | rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp); | ||
148 | if (rc) { | ||
149 | pr_warn("Failed to unmap pfn:%lx rc:%ld\n", | ||
150 | pfn, rc); | ||
151 | return rc; | ||
152 | } | ||
153 | } | ||
154 | return 0; | ||
155 | } | 83 | } |
156 | EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range); | 84 | EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range); |
157 | 85 | ||
diff --git a/arch/x86/syscalls/Makefile b/arch/x86/syscalls/Makefile index 3323c2745248..a55abb9f6c5e 100644 --- a/arch/x86/syscalls/Makefile +++ b/arch/x86/syscalls/Makefile | |||
@@ -19,6 +19,9 @@ quiet_cmd_syshdr = SYSHDR $@ | |||
19 | quiet_cmd_systbl = SYSTBL $@ | 19 | quiet_cmd_systbl = SYSTBL $@ |
20 | cmd_systbl = $(CONFIG_SHELL) '$(systbl)' $< $@ | 20 | cmd_systbl = $(CONFIG_SHELL) '$(systbl)' $< $@ |
21 | 21 | ||
22 | quiet_cmd_hypercalls = HYPERCALLS $@ | ||
23 | cmd_hypercalls = $(CONFIG_SHELL) '$<' $@ $(filter-out $<,$^) | ||
24 | |||
22 | syshdr_abi_unistd_32 := i386 | 25 | syshdr_abi_unistd_32 := i386 |
23 | $(uapi)/unistd_32.h: $(syscall32) $(syshdr) | 26 | $(uapi)/unistd_32.h: $(syscall32) $(syshdr) |
24 | $(call if_changed,syshdr) | 27 | $(call if_changed,syshdr) |
@@ -47,10 +50,16 @@ $(out)/syscalls_32.h: $(syscall32) $(systbl) | |||
47 | $(out)/syscalls_64.h: $(syscall64) $(systbl) | 50 | $(out)/syscalls_64.h: $(syscall64) $(systbl) |
48 | $(call if_changed,systbl) | 51 | $(call if_changed,systbl) |
49 | 52 | ||
53 | $(out)/xen-hypercalls.h: $(srctree)/scripts/xen-hypercalls.sh | ||
54 | $(call if_changed,hypercalls) | ||
55 | |||
56 | $(out)/xen-hypercalls.h: $(srctree)/include/xen/interface/xen*.h | ||
57 | |||
50 | uapisyshdr-y += unistd_32.h unistd_64.h unistd_x32.h | 58 | uapisyshdr-y += unistd_32.h unistd_64.h unistd_x32.h |
51 | syshdr-y += syscalls_32.h | 59 | syshdr-y += syscalls_32.h |
52 | syshdr-$(CONFIG_X86_64) += unistd_32_ia32.h unistd_64_x32.h | 60 | syshdr-$(CONFIG_X86_64) += unistd_32_ia32.h unistd_64_x32.h |
53 | syshdr-$(CONFIG_X86_64) += syscalls_64.h | 61 | syshdr-$(CONFIG_X86_64) += syscalls_64.h |
62 | syshdr-$(CONFIG_XEN) += xen-hypercalls.h | ||
54 | 63 | ||
55 | targets += $(uapisyshdr-y) $(syshdr-y) | 64 | targets += $(uapisyshdr-y) $(syshdr-y) |
56 | 65 | ||
diff --git a/arch/x86/xen/apic.c b/arch/x86/xen/apic.c index 7005ced5d1ad..70e060ad879a 100644 --- a/arch/x86/xen/apic.c +++ b/arch/x86/xen/apic.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <xen/xen.h> | 7 | #include <xen/xen.h> |
8 | #include <xen/interface/physdev.h> | 8 | #include <xen/interface/physdev.h> |
9 | #include "xen-ops.h" | 9 | #include "xen-ops.h" |
10 | #include "smp.h" | ||
10 | 11 | ||
11 | static unsigned int xen_io_apic_read(unsigned apic, unsigned reg) | 12 | static unsigned int xen_io_apic_read(unsigned apic, unsigned reg) |
12 | { | 13 | { |
@@ -28,7 +29,186 @@ static unsigned int xen_io_apic_read(unsigned apic, unsigned reg) | |||
28 | return 0xfd; | 29 | return 0xfd; |
29 | } | 30 | } |
30 | 31 | ||
32 | static unsigned long xen_set_apic_id(unsigned int x) | ||
33 | { | ||
34 | WARN_ON(1); | ||
35 | return x; | ||
36 | } | ||
37 | |||
38 | static unsigned int xen_get_apic_id(unsigned long x) | ||
39 | { | ||
40 | return ((x)>>24) & 0xFFu; | ||
41 | } | ||
42 | |||
43 | static u32 xen_apic_read(u32 reg) | ||
44 | { | ||
45 | struct xen_platform_op op = { | ||
46 | .cmd = XENPF_get_cpuinfo, | ||
47 | .interface_version = XENPF_INTERFACE_VERSION, | ||
48 | .u.pcpu_info.xen_cpuid = 0, | ||
49 | }; | ||
50 | int ret = 0; | ||
51 | |||
52 | /* Shouldn't need this as APIC is turned off for PV, and we only | ||
53 | * get called on the bootup processor. But just in case. */ | ||
54 | if (!xen_initial_domain() || smp_processor_id()) | ||
55 | return 0; | ||
56 | |||
57 | if (reg == APIC_LVR) | ||
58 | return 0x10; | ||
59 | #ifdef CONFIG_X86_32 | ||
60 | if (reg == APIC_LDR) | ||
61 | return SET_APIC_LOGICAL_ID(1UL << smp_processor_id()); | ||
62 | #endif | ||
63 | if (reg != APIC_ID) | ||
64 | return 0; | ||
65 | |||
66 | ret = HYPERVISOR_dom0_op(&op); | ||
67 | if (ret) | ||
68 | return 0; | ||
69 | |||
70 | return op.u.pcpu_info.apic_id << 24; | ||
71 | } | ||
72 | |||
73 | static void xen_apic_write(u32 reg, u32 val) | ||
74 | { | ||
75 | /* Warn to see if there's any stray references */ | ||
76 | WARN(1,"register: %x, value: %x\n", reg, val); | ||
77 | } | ||
78 | |||
79 | static u64 xen_apic_icr_read(void) | ||
80 | { | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static void xen_apic_icr_write(u32 low, u32 id) | ||
85 | { | ||
86 | /* Warn to see if there's any stray references */ | ||
87 | WARN_ON(1); | ||
88 | } | ||
89 | |||
90 | static u32 xen_safe_apic_wait_icr_idle(void) | ||
91 | { | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int xen_apic_probe_pv(void) | ||
96 | { | ||
97 | if (xen_pv_domain()) | ||
98 | return 1; | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static int xen_madt_oem_check(char *oem_id, char *oem_table_id) | ||
104 | { | ||
105 | return xen_pv_domain(); | ||
106 | } | ||
107 | |||
108 | static int xen_id_always_valid(int apicid) | ||
109 | { | ||
110 | return 1; | ||
111 | } | ||
112 | |||
113 | static int xen_id_always_registered(void) | ||
114 | { | ||
115 | return 1; | ||
116 | } | ||
117 | |||
118 | static int xen_phys_pkg_id(int initial_apic_id, int index_msb) | ||
119 | { | ||
120 | return initial_apic_id >> index_msb; | ||
121 | } | ||
122 | |||
123 | #ifdef CONFIG_X86_32 | ||
124 | static int xen_x86_32_early_logical_apicid(int cpu) | ||
125 | { | ||
126 | /* Match with APIC_LDR read. Otherwise setup_local_APIC complains. */ | ||
127 | return 1 << cpu; | ||
128 | } | ||
129 | #endif | ||
130 | |||
131 | static void xen_noop(void) | ||
132 | { | ||
133 | } | ||
134 | |||
135 | static void xen_silent_inquire(int apicid) | ||
136 | { | ||
137 | } | ||
138 | |||
139 | static struct apic xen_pv_apic = { | ||
140 | .name = "Xen PV", | ||
141 | .probe = xen_apic_probe_pv, | ||
142 | .acpi_madt_oem_check = xen_madt_oem_check, | ||
143 | .apic_id_valid = xen_id_always_valid, | ||
144 | .apic_id_registered = xen_id_always_registered, | ||
145 | |||
146 | /* .irq_delivery_mode - used in native_compose_msi_msg only */ | ||
147 | /* .irq_dest_mode - used in native_compose_msi_msg only */ | ||
148 | |||
149 | .target_cpus = default_target_cpus, | ||
150 | .disable_esr = 0, | ||
151 | /* .dest_logical - default_send_IPI_ use it but we use our own. */ | ||
152 | .check_apicid_used = default_check_apicid_used, /* Used on 32-bit */ | ||
153 | |||
154 | .vector_allocation_domain = flat_vector_allocation_domain, | ||
155 | .init_apic_ldr = xen_noop, /* setup_local_APIC calls it */ | ||
156 | |||
157 | .ioapic_phys_id_map = default_ioapic_phys_id_map, /* Used on 32-bit */ | ||
158 | .setup_apic_routing = NULL, | ||
159 | .cpu_present_to_apicid = default_cpu_present_to_apicid, | ||
160 | .apicid_to_cpu_present = physid_set_mask_of_physid, /* Used on 32-bit */ | ||
161 | .check_phys_apicid_present = default_check_phys_apicid_present, /* smp_sanity_check needs it */ | ||
162 | .phys_pkg_id = xen_phys_pkg_id, /* detect_ht */ | ||
163 | |||
164 | .get_apic_id = xen_get_apic_id, | ||
165 | .set_apic_id = xen_set_apic_id, /* Can be NULL on 32-bit. */ | ||
166 | .apic_id_mask = 0xFF << 24, /* Used by verify_local_APIC. Match with what xen_get_apic_id does. */ | ||
167 | |||
168 | .cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and, | ||
169 | |||
170 | #ifdef CONFIG_SMP | ||
171 | .send_IPI_mask = xen_send_IPI_mask, | ||
172 | .send_IPI_mask_allbutself = xen_send_IPI_mask_allbutself, | ||
173 | .send_IPI_allbutself = xen_send_IPI_allbutself, | ||
174 | .send_IPI_all = xen_send_IPI_all, | ||
175 | .send_IPI_self = xen_send_IPI_self, | ||
176 | #endif | ||
177 | /* .wait_for_init_deassert- used by AP bootup - smp_callin which we don't use */ | ||
178 | .inquire_remote_apic = xen_silent_inquire, | ||
179 | |||
180 | .read = xen_apic_read, | ||
181 | .write = xen_apic_write, | ||
182 | .eoi_write = xen_apic_write, | ||
183 | |||
184 | .icr_read = xen_apic_icr_read, | ||
185 | .icr_write = xen_apic_icr_write, | ||
186 | .wait_icr_idle = xen_noop, | ||
187 | .safe_wait_icr_idle = xen_safe_apic_wait_icr_idle, | ||
188 | |||
189 | #ifdef CONFIG_X86_32 | ||
190 | /* generic_processor_info and setup_local_APIC. */ | ||
191 | .x86_32_early_logical_apicid = xen_x86_32_early_logical_apicid, | ||
192 | #endif | ||
193 | }; | ||
194 | |||
195 | static void __init xen_apic_check(void) | ||
196 | { | ||
197 | if (apic == &xen_pv_apic) | ||
198 | return; | ||
199 | |||
200 | pr_info("Switched APIC routing from %s to %s.\n", apic->name, | ||
201 | xen_pv_apic.name); | ||
202 | apic = &xen_pv_apic; | ||
203 | } | ||
31 | void __init xen_init_apic(void) | 204 | void __init xen_init_apic(void) |
32 | { | 205 | { |
33 | x86_io_apic_ops.read = xen_io_apic_read; | 206 | x86_io_apic_ops.read = xen_io_apic_read; |
207 | /* On PV guests the APIC CPUID bit is disabled so none of the | ||
208 | * routines end up executing. */ | ||
209 | if (!xen_initial_domain()) | ||
210 | apic = &xen_pv_apic; | ||
211 | |||
212 | x86_platform.apic_post_init = xen_apic_check; | ||
34 | } | 213 | } |
214 | apic_driver(xen_pv_apic); | ||
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 81665c9f2132..94578efd3067 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -928,92 +928,6 @@ static void xen_io_delay(void) | |||
928 | { | 928 | { |
929 | } | 929 | } |
930 | 930 | ||
931 | #ifdef CONFIG_X86_LOCAL_APIC | ||
932 | static unsigned long xen_set_apic_id(unsigned int x) | ||
933 | { | ||
934 | WARN_ON(1); | ||
935 | return x; | ||
936 | } | ||
937 | static unsigned int xen_get_apic_id(unsigned long x) | ||
938 | { | ||
939 | return ((x)>>24) & 0xFFu; | ||
940 | } | ||
941 | static u32 xen_apic_read(u32 reg) | ||
942 | { | ||
943 | struct xen_platform_op op = { | ||
944 | .cmd = XENPF_get_cpuinfo, | ||
945 | .interface_version = XENPF_INTERFACE_VERSION, | ||
946 | .u.pcpu_info.xen_cpuid = 0, | ||
947 | }; | ||
948 | int ret = 0; | ||
949 | |||
950 | /* Shouldn't need this as APIC is turned off for PV, and we only | ||
951 | * get called on the bootup processor. But just in case. */ | ||
952 | if (!xen_initial_domain() || smp_processor_id()) | ||
953 | return 0; | ||
954 | |||
955 | if (reg == APIC_LVR) | ||
956 | return 0x10; | ||
957 | |||
958 | if (reg != APIC_ID) | ||
959 | return 0; | ||
960 | |||
961 | ret = HYPERVISOR_dom0_op(&op); | ||
962 | if (ret) | ||
963 | return 0; | ||
964 | |||
965 | return op.u.pcpu_info.apic_id << 24; | ||
966 | } | ||
967 | |||
968 | static void xen_apic_write(u32 reg, u32 val) | ||
969 | { | ||
970 | /* Warn to see if there's any stray references */ | ||
971 | WARN_ON(1); | ||
972 | } | ||
973 | |||
974 | static u64 xen_apic_icr_read(void) | ||
975 | { | ||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | static void xen_apic_icr_write(u32 low, u32 id) | ||
980 | { | ||
981 | /* Warn to see if there's any stray references */ | ||
982 | WARN_ON(1); | ||
983 | } | ||
984 | |||
985 | static void xen_apic_wait_icr_idle(void) | ||
986 | { | ||
987 | return; | ||
988 | } | ||
989 | |||
990 | static u32 xen_safe_apic_wait_icr_idle(void) | ||
991 | { | ||
992 | return 0; | ||
993 | } | ||
994 | |||
995 | static void set_xen_basic_apic_ops(void) | ||
996 | { | ||
997 | apic->read = xen_apic_read; | ||
998 | apic->write = xen_apic_write; | ||
999 | apic->icr_read = xen_apic_icr_read; | ||
1000 | apic->icr_write = xen_apic_icr_write; | ||
1001 | apic->wait_icr_idle = xen_apic_wait_icr_idle; | ||
1002 | apic->safe_wait_icr_idle = xen_safe_apic_wait_icr_idle; | ||
1003 | apic->set_apic_id = xen_set_apic_id; | ||
1004 | apic->get_apic_id = xen_get_apic_id; | ||
1005 | |||
1006 | #ifdef CONFIG_SMP | ||
1007 | apic->send_IPI_allbutself = xen_send_IPI_allbutself; | ||
1008 | apic->send_IPI_mask_allbutself = xen_send_IPI_mask_allbutself; | ||
1009 | apic->send_IPI_mask = xen_send_IPI_mask; | ||
1010 | apic->send_IPI_all = xen_send_IPI_all; | ||
1011 | apic->send_IPI_self = xen_send_IPI_self; | ||
1012 | #endif | ||
1013 | } | ||
1014 | |||
1015 | #endif | ||
1016 | |||
1017 | static void xen_clts(void) | 931 | static void xen_clts(void) |
1018 | { | 932 | { |
1019 | struct multicall_space mcs; | 933 | struct multicall_space mcs; |
@@ -1619,7 +1533,7 @@ asmlinkage __visible void __init xen_start_kernel(void) | |||
1619 | /* | 1533 | /* |
1620 | * set up the basic apic ops. | 1534 | * set up the basic apic ops. |
1621 | */ | 1535 | */ |
1622 | set_xen_basic_apic_ops(); | 1536 | xen_init_apic(); |
1623 | #endif | 1537 | #endif |
1624 | 1538 | ||
1625 | if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) { | 1539 | if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) { |
@@ -1732,8 +1646,6 @@ asmlinkage __visible void __init xen_start_kernel(void) | |||
1732 | if (HYPERVISOR_dom0_op(&op) == 0) | 1646 | if (HYPERVISOR_dom0_op(&op) == 0) |
1733 | boot_params.kbd_status = op.u.firmware_info.u.kbd_shift_flags; | 1647 | boot_params.kbd_status = op.u.firmware_info.u.kbd_shift_flags; |
1734 | 1648 | ||
1735 | xen_init_apic(); | ||
1736 | |||
1737 | /* Make sure ACS will be enabled */ | 1649 | /* Make sure ACS will be enabled */ |
1738 | pci_request_acs(); | 1650 | pci_request_acs(); |
1739 | 1651 | ||
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 65083ad63b6f..dd151b2045b0 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -2436,99 +2436,11 @@ void __init xen_hvm_init_mmu_ops(void) | |||
2436 | } | 2436 | } |
2437 | #endif | 2437 | #endif |
2438 | 2438 | ||
2439 | #ifdef CONFIG_XEN_PVH | ||
2440 | /* | ||
2441 | * Map foreign gfn (fgfn), to local pfn (lpfn). This for the user | ||
2442 | * space creating new guest on pvh dom0 and needing to map domU pages. | ||
2443 | */ | ||
2444 | static int xlate_add_to_p2m(unsigned long lpfn, unsigned long fgfn, | ||
2445 | unsigned int domid) | ||
2446 | { | ||
2447 | int rc, err = 0; | ||
2448 | xen_pfn_t gpfn = lpfn; | ||
2449 | xen_ulong_t idx = fgfn; | ||
2450 | |||
2451 | struct xen_add_to_physmap_range xatp = { | ||
2452 | .domid = DOMID_SELF, | ||
2453 | .foreign_domid = domid, | ||
2454 | .size = 1, | ||
2455 | .space = XENMAPSPACE_gmfn_foreign, | ||
2456 | }; | ||
2457 | set_xen_guest_handle(xatp.idxs, &idx); | ||
2458 | set_xen_guest_handle(xatp.gpfns, &gpfn); | ||
2459 | set_xen_guest_handle(xatp.errs, &err); | ||
2460 | |||
2461 | rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp); | ||
2462 | if (rc < 0) | ||
2463 | return rc; | ||
2464 | return err; | ||
2465 | } | ||
2466 | |||
2467 | static int xlate_remove_from_p2m(unsigned long spfn, int count) | ||
2468 | { | ||
2469 | struct xen_remove_from_physmap xrp; | ||
2470 | int i, rc; | ||
2471 | |||
2472 | for (i = 0; i < count; i++) { | ||
2473 | xrp.domid = DOMID_SELF; | ||
2474 | xrp.gpfn = spfn+i; | ||
2475 | rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp); | ||
2476 | if (rc) | ||
2477 | break; | ||
2478 | } | ||
2479 | return rc; | ||
2480 | } | ||
2481 | |||
2482 | struct xlate_remap_data { | ||
2483 | unsigned long fgfn; /* foreign domain's gfn */ | ||
2484 | pgprot_t prot; | ||
2485 | domid_t domid; | ||
2486 | int index; | ||
2487 | struct page **pages; | ||
2488 | }; | ||
2489 | |||
2490 | static int xlate_map_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, | ||
2491 | void *data) | ||
2492 | { | ||
2493 | int rc; | ||
2494 | struct xlate_remap_data *remap = data; | ||
2495 | unsigned long pfn = page_to_pfn(remap->pages[remap->index++]); | ||
2496 | pte_t pteval = pte_mkspecial(pfn_pte(pfn, remap->prot)); | ||
2497 | |||
2498 | rc = xlate_add_to_p2m(pfn, remap->fgfn, remap->domid); | ||
2499 | if (rc) | ||
2500 | return rc; | ||
2501 | native_set_pte(ptep, pteval); | ||
2502 | |||
2503 | return 0; | ||
2504 | } | ||
2505 | |||
2506 | static int xlate_remap_gfn_range(struct vm_area_struct *vma, | ||
2507 | unsigned long addr, unsigned long mfn, | ||
2508 | int nr, pgprot_t prot, unsigned domid, | ||
2509 | struct page **pages) | ||
2510 | { | ||
2511 | int err; | ||
2512 | struct xlate_remap_data pvhdata; | ||
2513 | |||
2514 | BUG_ON(!pages); | ||
2515 | |||
2516 | pvhdata.fgfn = mfn; | ||
2517 | pvhdata.prot = prot; | ||
2518 | pvhdata.domid = domid; | ||
2519 | pvhdata.index = 0; | ||
2520 | pvhdata.pages = pages; | ||
2521 | err = apply_to_page_range(vma->vm_mm, addr, nr << PAGE_SHIFT, | ||
2522 | xlate_map_pte_fn, &pvhdata); | ||
2523 | flush_tlb_all(); | ||
2524 | return err; | ||
2525 | } | ||
2526 | #endif | ||
2527 | |||
2528 | #define REMAP_BATCH_SIZE 16 | 2439 | #define REMAP_BATCH_SIZE 16 |
2529 | 2440 | ||
2530 | struct remap_data { | 2441 | struct remap_data { |
2531 | unsigned long mfn; | 2442 | xen_pfn_t *mfn; |
2443 | bool contiguous; | ||
2532 | pgprot_t prot; | 2444 | pgprot_t prot; |
2533 | struct mmu_update *mmu_update; | 2445 | struct mmu_update *mmu_update; |
2534 | }; | 2446 | }; |
@@ -2537,7 +2449,14 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token, | |||
2537 | unsigned long addr, void *data) | 2449 | unsigned long addr, void *data) |
2538 | { | 2450 | { |
2539 | struct remap_data *rmd = data; | 2451 | struct remap_data *rmd = data; |
2540 | pte_t pte = pte_mkspecial(mfn_pte(rmd->mfn++, rmd->prot)); | 2452 | pte_t pte = pte_mkspecial(mfn_pte(*rmd->mfn, rmd->prot)); |
2453 | |||
2454 | /* If we have a contigious range, just update the mfn itself, | ||
2455 | else update pointer to be "next mfn". */ | ||
2456 | if (rmd->contiguous) | ||
2457 | (*rmd->mfn)++; | ||
2458 | else | ||
2459 | rmd->mfn++; | ||
2541 | 2460 | ||
2542 | rmd->mmu_update->ptr = virt_to_machine(ptep).maddr; | 2461 | rmd->mmu_update->ptr = virt_to_machine(ptep).maddr; |
2543 | rmd->mmu_update->val = pte_val_ma(pte); | 2462 | rmd->mmu_update->val = pte_val_ma(pte); |
@@ -2546,26 +2465,26 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token, | |||
2546 | return 0; | 2465 | return 0; |
2547 | } | 2466 | } |
2548 | 2467 | ||
2549 | int xen_remap_domain_mfn_range(struct vm_area_struct *vma, | 2468 | static int do_remap_mfn(struct vm_area_struct *vma, |
2550 | unsigned long addr, | 2469 | unsigned long addr, |
2551 | xen_pfn_t mfn, int nr, | 2470 | xen_pfn_t *mfn, int nr, |
2552 | pgprot_t prot, unsigned domid, | 2471 | int *err_ptr, pgprot_t prot, |
2553 | struct page **pages) | 2472 | unsigned domid, |
2554 | 2473 | struct page **pages) | |
2555 | { | 2474 | { |
2475 | int err = 0; | ||
2556 | struct remap_data rmd; | 2476 | struct remap_data rmd; |
2557 | struct mmu_update mmu_update[REMAP_BATCH_SIZE]; | 2477 | struct mmu_update mmu_update[REMAP_BATCH_SIZE]; |
2558 | int batch; | ||
2559 | unsigned long range; | 2478 | unsigned long range; |
2560 | int err = 0; | 2479 | int mapped = 0; |
2561 | 2480 | ||
2562 | BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); | 2481 | BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); |
2563 | 2482 | ||
2564 | if (xen_feature(XENFEAT_auto_translated_physmap)) { | 2483 | if (xen_feature(XENFEAT_auto_translated_physmap)) { |
2565 | #ifdef CONFIG_XEN_PVH | 2484 | #ifdef CONFIG_XEN_PVH |
2566 | /* We need to update the local page tables and the xen HAP */ | 2485 | /* We need to update the local page tables and the xen HAP */ |
2567 | return xlate_remap_gfn_range(vma, addr, mfn, nr, prot, | 2486 | return xen_xlate_remap_gfn_array(vma, addr, mfn, nr, err_ptr, |
2568 | domid, pages); | 2487 | prot, domid, pages); |
2569 | #else | 2488 | #else |
2570 | return -EINVAL; | 2489 | return -EINVAL; |
2571 | #endif | 2490 | #endif |
@@ -2573,9 +2492,15 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma, | |||
2573 | 2492 | ||
2574 | rmd.mfn = mfn; | 2493 | rmd.mfn = mfn; |
2575 | rmd.prot = prot; | 2494 | rmd.prot = prot; |
2495 | /* We use the err_ptr to indicate if there we are doing a contigious | ||
2496 | * mapping or a discontigious mapping. */ | ||
2497 | rmd.contiguous = !err_ptr; | ||
2576 | 2498 | ||
2577 | while (nr) { | 2499 | while (nr) { |
2578 | batch = min(REMAP_BATCH_SIZE, nr); | 2500 | int index = 0; |
2501 | int done = 0; | ||
2502 | int batch = min(REMAP_BATCH_SIZE, nr); | ||
2503 | int batch_left = batch; | ||
2579 | range = (unsigned long)batch << PAGE_SHIFT; | 2504 | range = (unsigned long)batch << PAGE_SHIFT; |
2580 | 2505 | ||
2581 | rmd.mmu_update = mmu_update; | 2506 | rmd.mmu_update = mmu_update; |
@@ -2584,23 +2509,72 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma, | |||
2584 | if (err) | 2509 | if (err) |
2585 | goto out; | 2510 | goto out; |
2586 | 2511 | ||
2587 | err = HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid); | 2512 | /* We record the error for each page that gives an error, but |
2588 | if (err < 0) | 2513 | * continue mapping until the whole set is done */ |
2589 | goto out; | 2514 | do { |
2515 | int i; | ||
2516 | |||
2517 | err = HYPERVISOR_mmu_update(&mmu_update[index], | ||
2518 | batch_left, &done, domid); | ||
2519 | |||
2520 | /* | ||
2521 | * @err_ptr may be the same buffer as @mfn, so | ||
2522 | * only clear it after each chunk of @mfn is | ||
2523 | * used. | ||
2524 | */ | ||
2525 | if (err_ptr) { | ||
2526 | for (i = index; i < index + done; i++) | ||
2527 | err_ptr[i] = 0; | ||
2528 | } | ||
2529 | if (err < 0) { | ||
2530 | if (!err_ptr) | ||
2531 | goto out; | ||
2532 | err_ptr[i] = err; | ||
2533 | done++; /* Skip failed frame. */ | ||
2534 | } else | ||
2535 | mapped += done; | ||
2536 | batch_left -= done; | ||
2537 | index += done; | ||
2538 | } while (batch_left); | ||
2590 | 2539 | ||
2591 | nr -= batch; | 2540 | nr -= batch; |
2592 | addr += range; | 2541 | addr += range; |
2542 | if (err_ptr) | ||
2543 | err_ptr += batch; | ||
2593 | } | 2544 | } |
2594 | |||
2595 | err = 0; | ||
2596 | out: | 2545 | out: |
2597 | 2546 | ||
2598 | xen_flush_tlb_all(); | 2547 | xen_flush_tlb_all(); |
2599 | 2548 | ||
2600 | return err; | 2549 | return err < 0 ? err : mapped; |
2550 | } | ||
2551 | |||
2552 | int xen_remap_domain_mfn_range(struct vm_area_struct *vma, | ||
2553 | unsigned long addr, | ||
2554 | xen_pfn_t mfn, int nr, | ||
2555 | pgprot_t prot, unsigned domid, | ||
2556 | struct page **pages) | ||
2557 | { | ||
2558 | return do_remap_mfn(vma, addr, &mfn, nr, NULL, prot, domid, pages); | ||
2601 | } | 2559 | } |
2602 | EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); | 2560 | EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); |
2603 | 2561 | ||
2562 | int xen_remap_domain_mfn_array(struct vm_area_struct *vma, | ||
2563 | unsigned long addr, | ||
2564 | xen_pfn_t *mfn, int nr, | ||
2565 | int *err_ptr, pgprot_t prot, | ||
2566 | unsigned domid, struct page **pages) | ||
2567 | { | ||
2568 | /* We BUG_ON because it's a programmer error to pass a NULL err_ptr, | ||
2569 | * and the consequences later is quite hard to detect what the actual | ||
2570 | * cause of "wrong memory was mapped in". | ||
2571 | */ | ||
2572 | BUG_ON(err_ptr == NULL); | ||
2573 | return do_remap_mfn(vma, addr, mfn, nr, err_ptr, prot, domid, pages); | ||
2574 | } | ||
2575 | EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_array); | ||
2576 | |||
2577 | |||
2604 | /* Returns: 0 success */ | 2578 | /* Returns: 0 success */ |
2605 | int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, | 2579 | int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, |
2606 | int numpgs, struct page **pages) | 2580 | int numpgs, struct page **pages) |
@@ -2609,22 +2583,7 @@ int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, | |||
2609 | return 0; | 2583 | return 0; |
2610 | 2584 | ||
2611 | #ifdef CONFIG_XEN_PVH | 2585 | #ifdef CONFIG_XEN_PVH |
2612 | while (numpgs--) { | 2586 | return xen_xlate_unmap_gfn_range(vma, numpgs, pages); |
2613 | /* | ||
2614 | * The mmu has already cleaned up the process mmu | ||
2615 | * resources at this point (lookup_address will return | ||
2616 | * NULL). | ||
2617 | */ | ||
2618 | unsigned long pfn = page_to_pfn(pages[numpgs]); | ||
2619 | |||
2620 | xlate_remove_from_p2m(pfn, 1); | ||
2621 | } | ||
2622 | /* | ||
2623 | * We don't need to flush tlbs because as part of | ||
2624 | * xlate_remove_from_p2m, the hypervisor will do tlb flushes | ||
2625 | * after removing the p2m entries from the EPT/NPT | ||
2626 | */ | ||
2627 | return 0; | ||
2628 | #else | 2587 | #else |
2629 | return -EINVAL; | 2588 | return -EINVAL; |
2630 | #endif | 2589 | #endif |
diff --git a/arch/x86/xen/trace.c b/arch/x86/xen/trace.c index 520022d1a181..a702ec2f5931 100644 --- a/arch/x86/xen/trace.c +++ b/arch/x86/xen/trace.c | |||
@@ -1,54 +1,12 @@ | |||
1 | #include <linux/ftrace.h> | 1 | #include <linux/ftrace.h> |
2 | #include <xen/interface/xen.h> | 2 | #include <xen/interface/xen.h> |
3 | #include <xen/interface/xen-mca.h> | ||
3 | 4 | ||
4 | #define N(x) [__HYPERVISOR_##x] = "("#x")" | 5 | #define HYPERCALL(x) [__HYPERVISOR_##x] = "("#x")", |
5 | static const char *xen_hypercall_names[] = { | 6 | static const char *xen_hypercall_names[] = { |
6 | N(set_trap_table), | 7 | #include <asm/xen-hypercalls.h> |
7 | N(mmu_update), | ||
8 | N(set_gdt), | ||
9 | N(stack_switch), | ||
10 | N(set_callbacks), | ||
11 | N(fpu_taskswitch), | ||
12 | N(sched_op_compat), | ||
13 | N(dom0_op), | ||
14 | N(set_debugreg), | ||
15 | N(get_debugreg), | ||
16 | N(update_descriptor), | ||
17 | N(memory_op), | ||
18 | N(multicall), | ||
19 | N(update_va_mapping), | ||
20 | N(set_timer_op), | ||
21 | N(event_channel_op_compat), | ||
22 | N(xen_version), | ||
23 | N(console_io), | ||
24 | N(physdev_op_compat), | ||
25 | N(grant_table_op), | ||
26 | N(vm_assist), | ||
27 | N(update_va_mapping_otherdomain), | ||
28 | N(iret), | ||
29 | N(vcpu_op), | ||
30 | N(set_segment_base), | ||
31 | N(mmuext_op), | ||
32 | N(acm_op), | ||
33 | N(nmi_op), | ||
34 | N(sched_op), | ||
35 | N(callback_op), | ||
36 | N(xenoprof_op), | ||
37 | N(event_channel_op), | ||
38 | N(physdev_op), | ||
39 | N(hvm_op), | ||
40 | |||
41 | /* Architecture-specific hypercall definitions. */ | ||
42 | N(arch_0), | ||
43 | N(arch_1), | ||
44 | N(arch_2), | ||
45 | N(arch_3), | ||
46 | N(arch_4), | ||
47 | N(arch_5), | ||
48 | N(arch_6), | ||
49 | N(arch_7), | ||
50 | }; | 8 | }; |
51 | #undef N | 9 | #undef HYPERCALL |
52 | 10 | ||
53 | static const char *xen_hypercall_name(unsigned op) | 11 | static const char *xen_hypercall_name(unsigned op) |
54 | { | 12 | { |
diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S index 674b222544b7..8afdfccf6086 100644 --- a/arch/x86/xen/xen-head.S +++ b/arch/x86/xen/xen-head.S | |||
@@ -12,6 +12,8 @@ | |||
12 | 12 | ||
13 | #include <xen/interface/elfnote.h> | 13 | #include <xen/interface/elfnote.h> |
14 | #include <xen/interface/features.h> | 14 | #include <xen/interface/features.h> |
15 | #include <xen/interface/xen.h> | ||
16 | #include <xen/interface/xen-mca.h> | ||
15 | #include <asm/xen/interface.h> | 17 | #include <asm/xen/interface.h> |
16 | 18 | ||
17 | #ifdef CONFIG_XEN_PVH | 19 | #ifdef CONFIG_XEN_PVH |
@@ -85,59 +87,14 @@ ENTRY(xen_pvh_early_cpu_init) | |||
85 | .pushsection .text | 87 | .pushsection .text |
86 | .balign PAGE_SIZE | 88 | .balign PAGE_SIZE |
87 | ENTRY(hypercall_page) | 89 | ENTRY(hypercall_page) |
88 | #define NEXT_HYPERCALL(x) \ | 90 | .skip PAGE_SIZE |
89 | ENTRY(xen_hypercall_##x) \ | 91 | |
90 | .skip 32 | 92 | #define HYPERCALL(n) \ |
91 | 93 | .equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \ | |
92 | NEXT_HYPERCALL(set_trap_table) | 94 | .type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32 |
93 | NEXT_HYPERCALL(mmu_update) | 95 | #include <asm/xen-hypercalls.h> |
94 | NEXT_HYPERCALL(set_gdt) | 96 | #undef HYPERCALL |
95 | NEXT_HYPERCALL(stack_switch) | 97 | |
96 | NEXT_HYPERCALL(set_callbacks) | ||
97 | NEXT_HYPERCALL(fpu_taskswitch) | ||
98 | NEXT_HYPERCALL(sched_op_compat) | ||
99 | NEXT_HYPERCALL(platform_op) | ||
100 | NEXT_HYPERCALL(set_debugreg) | ||
101 | NEXT_HYPERCALL(get_debugreg) | ||
102 | NEXT_HYPERCALL(update_descriptor) | ||
103 | NEXT_HYPERCALL(ni) | ||
104 | NEXT_HYPERCALL(memory_op) | ||
105 | NEXT_HYPERCALL(multicall) | ||
106 | NEXT_HYPERCALL(update_va_mapping) | ||
107 | NEXT_HYPERCALL(set_timer_op) | ||
108 | NEXT_HYPERCALL(event_channel_op_compat) | ||
109 | NEXT_HYPERCALL(xen_version) | ||
110 | NEXT_HYPERCALL(console_io) | ||
111 | NEXT_HYPERCALL(physdev_op_compat) | ||
112 | NEXT_HYPERCALL(grant_table_op) | ||
113 | NEXT_HYPERCALL(vm_assist) | ||
114 | NEXT_HYPERCALL(update_va_mapping_otherdomain) | ||
115 | NEXT_HYPERCALL(iret) | ||
116 | NEXT_HYPERCALL(vcpu_op) | ||
117 | NEXT_HYPERCALL(set_segment_base) | ||
118 | NEXT_HYPERCALL(mmuext_op) | ||
119 | NEXT_HYPERCALL(xsm_op) | ||
120 | NEXT_HYPERCALL(nmi_op) | ||
121 | NEXT_HYPERCALL(sched_op) | ||
122 | NEXT_HYPERCALL(callback_op) | ||
123 | NEXT_HYPERCALL(xenoprof_op) | ||
124 | NEXT_HYPERCALL(event_channel_op) | ||
125 | NEXT_HYPERCALL(physdev_op) | ||
126 | NEXT_HYPERCALL(hvm_op) | ||
127 | NEXT_HYPERCALL(sysctl) | ||
128 | NEXT_HYPERCALL(domctl) | ||
129 | NEXT_HYPERCALL(kexec_op) | ||
130 | NEXT_HYPERCALL(tmem_op) /* 38 */ | ||
131 | ENTRY(xen_hypercall_rsvr) | ||
132 | .skip 320 | ||
133 | NEXT_HYPERCALL(mca) /* 48 */ | ||
134 | NEXT_HYPERCALL(arch_1) | ||
135 | NEXT_HYPERCALL(arch_2) | ||
136 | NEXT_HYPERCALL(arch_3) | ||
137 | NEXT_HYPERCALL(arch_4) | ||
138 | NEXT_HYPERCALL(arch_5) | ||
139 | NEXT_HYPERCALL(arch_6) | ||
140 | .balign PAGE_SIZE | ||
141 | .popsection | 98 | .popsection |
142 | 99 | ||
143 | ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux") | 100 | ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux") |
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index e3afe97280b1..ff3025922c14 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c | |||
@@ -193,7 +193,7 @@ fail: | |||
193 | return ERR_PTR(-ENOMEM); | 193 | return ERR_PTR(-ENOMEM); |
194 | } | 194 | } |
195 | 195 | ||
196 | static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page, | 196 | static int xen_blkif_map(struct xen_blkif *blkif, grant_ref_t gref, |
197 | unsigned int evtchn) | 197 | unsigned int evtchn) |
198 | { | 198 | { |
199 | int err; | 199 | int err; |
@@ -202,7 +202,8 @@ static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page, | |||
202 | if (blkif->irq) | 202 | if (blkif->irq) |
203 | return 0; | 203 | return 0; |
204 | 204 | ||
205 | err = xenbus_map_ring_valloc(blkif->be->dev, shared_page, &blkif->blk_ring); | 205 | err = xenbus_map_ring_valloc(blkif->be->dev, &gref, 1, |
206 | &blkif->blk_ring); | ||
206 | if (err < 0) | 207 | if (err < 0) |
207 | return err; | 208 | return err; |
208 | 209 | ||
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 37779e4c4585..2c61cf8c6f61 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c | |||
@@ -1245,6 +1245,7 @@ static int setup_blkring(struct xenbus_device *dev, | |||
1245 | struct blkfront_info *info) | 1245 | struct blkfront_info *info) |
1246 | { | 1246 | { |
1247 | struct blkif_sring *sring; | 1247 | struct blkif_sring *sring; |
1248 | grant_ref_t gref; | ||
1248 | int err; | 1249 | int err; |
1249 | 1250 | ||
1250 | info->ring_ref = GRANT_INVALID_REF; | 1251 | info->ring_ref = GRANT_INVALID_REF; |
@@ -1257,13 +1258,13 @@ static int setup_blkring(struct xenbus_device *dev, | |||
1257 | SHARED_RING_INIT(sring); | 1258 | SHARED_RING_INIT(sring); |
1258 | FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); | 1259 | FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); |
1259 | 1260 | ||
1260 | err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring)); | 1261 | err = xenbus_grant_ring(dev, info->ring.sring, 1, &gref); |
1261 | if (err < 0) { | 1262 | if (err < 0) { |
1262 | free_page((unsigned long)sring); | 1263 | free_page((unsigned long)sring); |
1263 | info->ring.sring = NULL; | 1264 | info->ring.sring = NULL; |
1264 | goto fail; | 1265 | goto fail; |
1265 | } | 1266 | } |
1266 | info->ring_ref = err; | 1267 | info->ring_ref = gref; |
1267 | 1268 | ||
1268 | err = xenbus_alloc_evtchn(dev, &info->evtchn); | 1269 | err = xenbus_alloc_evtchn(dev, &info->evtchn); |
1269 | if (err) | 1270 | if (err) |
diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index c3b4f5a5ac10..3111f2778079 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c | |||
@@ -193,6 +193,7 @@ static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv) | |||
193 | struct xenbus_transaction xbt; | 193 | struct xenbus_transaction xbt; |
194 | const char *message = NULL; | 194 | const char *message = NULL; |
195 | int rv; | 195 | int rv; |
196 | grant_ref_t gref; | ||
196 | 197 | ||
197 | priv->shr = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO); | 198 | priv->shr = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO); |
198 | if (!priv->shr) { | 199 | if (!priv->shr) { |
@@ -200,11 +201,11 @@ static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv) | |||
200 | return -ENOMEM; | 201 | return -ENOMEM; |
201 | } | 202 | } |
202 | 203 | ||
203 | rv = xenbus_grant_ring(dev, virt_to_mfn(priv->shr)); | 204 | rv = xenbus_grant_ring(dev, &priv->shr, 1, &gref); |
204 | if (rv < 0) | 205 | if (rv < 0) |
205 | return rv; | 206 | return rv; |
206 | 207 | ||
207 | priv->ring_ref = rv; | 208 | priv->ring_ref = gref; |
208 | 209 | ||
209 | rv = xenbus_alloc_evtchn(dev, &priv->evtchn); | 210 | rv = xenbus_alloc_evtchn(dev, &priv->evtchn); |
210 | if (rv) | 211 | if (rv) |
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index b8c471813f4c..4de46aa61d95 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c | |||
@@ -1780,7 +1780,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue, | |||
1780 | int err = -ENOMEM; | 1780 | int err = -ENOMEM; |
1781 | 1781 | ||
1782 | err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), | 1782 | err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), |
1783 | tx_ring_ref, &addr); | 1783 | &tx_ring_ref, 1, &addr); |
1784 | if (err) | 1784 | if (err) |
1785 | goto err; | 1785 | goto err; |
1786 | 1786 | ||
@@ -1788,7 +1788,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue, | |||
1788 | BACK_RING_INIT(&queue->tx, txs, PAGE_SIZE); | 1788 | BACK_RING_INIT(&queue->tx, txs, PAGE_SIZE); |
1789 | 1789 | ||
1790 | err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), | 1790 | err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), |
1791 | rx_ring_ref, &addr); | 1791 | &rx_ring_ref, 1, &addr); |
1792 | if (err) | 1792 | if (err) |
1793 | goto err; | 1793 | goto err; |
1794 | 1794 | ||
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 720aaf6313d2..4c08f98f4484 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c | |||
@@ -1483,6 +1483,7 @@ static int setup_netfront(struct xenbus_device *dev, | |||
1483 | { | 1483 | { |
1484 | struct xen_netif_tx_sring *txs; | 1484 | struct xen_netif_tx_sring *txs; |
1485 | struct xen_netif_rx_sring *rxs; | 1485 | struct xen_netif_rx_sring *rxs; |
1486 | grant_ref_t gref; | ||
1486 | int err; | 1487 | int err; |
1487 | 1488 | ||
1488 | queue->tx_ring_ref = GRANT_INVALID_REF; | 1489 | queue->tx_ring_ref = GRANT_INVALID_REF; |
@@ -1499,10 +1500,10 @@ static int setup_netfront(struct xenbus_device *dev, | |||
1499 | SHARED_RING_INIT(txs); | 1500 | SHARED_RING_INIT(txs); |
1500 | FRONT_RING_INIT(&queue->tx, txs, PAGE_SIZE); | 1501 | FRONT_RING_INIT(&queue->tx, txs, PAGE_SIZE); |
1501 | 1502 | ||
1502 | err = xenbus_grant_ring(dev, virt_to_mfn(txs)); | 1503 | err = xenbus_grant_ring(dev, txs, 1, &gref); |
1503 | if (err < 0) | 1504 | if (err < 0) |
1504 | goto grant_tx_ring_fail; | 1505 | goto grant_tx_ring_fail; |
1505 | queue->tx_ring_ref = err; | 1506 | queue->tx_ring_ref = gref; |
1506 | 1507 | ||
1507 | rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH); | 1508 | rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH); |
1508 | if (!rxs) { | 1509 | if (!rxs) { |
@@ -1513,10 +1514,10 @@ static int setup_netfront(struct xenbus_device *dev, | |||
1513 | SHARED_RING_INIT(rxs); | 1514 | SHARED_RING_INIT(rxs); |
1514 | FRONT_RING_INIT(&queue->rx, rxs, PAGE_SIZE); | 1515 | FRONT_RING_INIT(&queue->rx, rxs, PAGE_SIZE); |
1515 | 1516 | ||
1516 | err = xenbus_grant_ring(dev, virt_to_mfn(rxs)); | 1517 | err = xenbus_grant_ring(dev, rxs, 1, &gref); |
1517 | if (err < 0) | 1518 | if (err < 0) |
1518 | goto grant_rx_ring_fail; | 1519 | goto grant_rx_ring_fail; |
1519 | queue->rx_ring_ref = err; | 1520 | queue->rx_ring_ref = gref; |
1520 | 1521 | ||
1521 | if (feature_split_evtchn) | 1522 | if (feature_split_evtchn) |
1522 | err = setup_netfront_split(queue); | 1523 | err = setup_netfront_split(queue); |
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index b1ffebec9b9e..7cfd2db02deb 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c | |||
@@ -777,12 +777,13 @@ static int pcifront_publish_info(struct pcifront_device *pdev) | |||
777 | { | 777 | { |
778 | int err = 0; | 778 | int err = 0; |
779 | struct xenbus_transaction trans; | 779 | struct xenbus_transaction trans; |
780 | grant_ref_t gref; | ||
780 | 781 | ||
781 | err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info)); | 782 | err = xenbus_grant_ring(pdev->xdev, pdev->sh_info, 1, &gref); |
782 | if (err < 0) | 783 | if (err < 0) |
783 | goto out; | 784 | goto out; |
784 | 785 | ||
785 | pdev->gnt_ref = err; | 786 | pdev->gnt_ref = gref; |
786 | 787 | ||
787 | err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn); | 788 | err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn); |
788 | if (err) | 789 | if (err) |
diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c index 34199d206ba6..fad22caf0eff 100644 --- a/drivers/scsi/xen-scsifront.c +++ b/drivers/scsi/xen-scsifront.c | |||
@@ -63,6 +63,7 @@ | |||
63 | 63 | ||
64 | #define VSCSIFRONT_OP_ADD_LUN 1 | 64 | #define VSCSIFRONT_OP_ADD_LUN 1 |
65 | #define VSCSIFRONT_OP_DEL_LUN 2 | 65 | #define VSCSIFRONT_OP_DEL_LUN 2 |
66 | #define VSCSIFRONT_OP_READD_LUN 3 | ||
66 | 67 | ||
67 | /* Tuning point. */ | 68 | /* Tuning point. */ |
68 | #define VSCSIIF_DEFAULT_CMD_PER_LUN 10 | 69 | #define VSCSIIF_DEFAULT_CMD_PER_LUN 10 |
@@ -113,8 +114,13 @@ struct vscsifrnt_info { | |||
113 | DECLARE_BITMAP(shadow_free_bitmap, VSCSIIF_MAX_REQS); | 114 | DECLARE_BITMAP(shadow_free_bitmap, VSCSIIF_MAX_REQS); |
114 | struct vscsifrnt_shadow *shadow[VSCSIIF_MAX_REQS]; | 115 | struct vscsifrnt_shadow *shadow[VSCSIIF_MAX_REQS]; |
115 | 116 | ||
117 | /* Following items are protected by the host lock. */ | ||
116 | wait_queue_head_t wq_sync; | 118 | wait_queue_head_t wq_sync; |
119 | wait_queue_head_t wq_pause; | ||
117 | unsigned int wait_ring_available:1; | 120 | unsigned int wait_ring_available:1; |
121 | unsigned int waiting_pause:1; | ||
122 | unsigned int pause:1; | ||
123 | unsigned callers; | ||
118 | 124 | ||
119 | char dev_state_path[64]; | 125 | char dev_state_path[64]; |
120 | struct task_struct *curr; | 126 | struct task_struct *curr; |
@@ -274,31 +280,31 @@ static void scsifront_sync_cmd_done(struct vscsifrnt_info *info, | |||
274 | wake_up(&shadow->wq_reset); | 280 | wake_up(&shadow->wq_reset); |
275 | } | 281 | } |
276 | 282 | ||
277 | static int scsifront_cmd_done(struct vscsifrnt_info *info) | 283 | static void scsifront_do_response(struct vscsifrnt_info *info, |
284 | struct vscsiif_response *ring_rsp) | ||
285 | { | ||
286 | if (WARN(ring_rsp->rqid >= VSCSIIF_MAX_REQS || | ||
287 | test_bit(ring_rsp->rqid, info->shadow_free_bitmap), | ||
288 | "illegal rqid %u returned by backend!\n", ring_rsp->rqid)) | ||
289 | return; | ||
290 | |||
291 | if (info->shadow[ring_rsp->rqid]->act == VSCSIIF_ACT_SCSI_CDB) | ||
292 | scsifront_cdb_cmd_done(info, ring_rsp); | ||
293 | else | ||
294 | scsifront_sync_cmd_done(info, ring_rsp); | ||
295 | } | ||
296 | |||
297 | static int scsifront_ring_drain(struct vscsifrnt_info *info) | ||
278 | { | 298 | { |
279 | struct vscsiif_response *ring_rsp; | 299 | struct vscsiif_response *ring_rsp; |
280 | RING_IDX i, rp; | 300 | RING_IDX i, rp; |
281 | int more_to_do = 0; | 301 | int more_to_do = 0; |
282 | unsigned long flags; | ||
283 | |||
284 | spin_lock_irqsave(info->host->host_lock, flags); | ||
285 | 302 | ||
286 | rp = info->ring.sring->rsp_prod; | 303 | rp = info->ring.sring->rsp_prod; |
287 | rmb(); /* ordering required respective to dom0 */ | 304 | rmb(); /* ordering required respective to dom0 */ |
288 | for (i = info->ring.rsp_cons; i != rp; i++) { | 305 | for (i = info->ring.rsp_cons; i != rp; i++) { |
289 | |||
290 | ring_rsp = RING_GET_RESPONSE(&info->ring, i); | 306 | ring_rsp = RING_GET_RESPONSE(&info->ring, i); |
291 | 307 | scsifront_do_response(info, ring_rsp); | |
292 | if (WARN(ring_rsp->rqid >= VSCSIIF_MAX_REQS || | ||
293 | test_bit(ring_rsp->rqid, info->shadow_free_bitmap), | ||
294 | "illegal rqid %u returned by backend!\n", | ||
295 | ring_rsp->rqid)) | ||
296 | continue; | ||
297 | |||
298 | if (info->shadow[ring_rsp->rqid]->act == VSCSIIF_ACT_SCSI_CDB) | ||
299 | scsifront_cdb_cmd_done(info, ring_rsp); | ||
300 | else | ||
301 | scsifront_sync_cmd_done(info, ring_rsp); | ||
302 | } | 308 | } |
303 | 309 | ||
304 | info->ring.rsp_cons = i; | 310 | info->ring.rsp_cons = i; |
@@ -308,6 +314,18 @@ static int scsifront_cmd_done(struct vscsifrnt_info *info) | |||
308 | else | 314 | else |
309 | info->ring.sring->rsp_event = i + 1; | 315 | info->ring.sring->rsp_event = i + 1; |
310 | 316 | ||
317 | return more_to_do; | ||
318 | } | ||
319 | |||
320 | static int scsifront_cmd_done(struct vscsifrnt_info *info) | ||
321 | { | ||
322 | int more_to_do; | ||
323 | unsigned long flags; | ||
324 | |||
325 | spin_lock_irqsave(info->host->host_lock, flags); | ||
326 | |||
327 | more_to_do = scsifront_ring_drain(info); | ||
328 | |||
311 | info->wait_ring_available = 0; | 329 | info->wait_ring_available = 0; |
312 | 330 | ||
313 | spin_unlock_irqrestore(info->host->host_lock, flags); | 331 | spin_unlock_irqrestore(info->host->host_lock, flags); |
@@ -328,6 +346,24 @@ static irqreturn_t scsifront_irq_fn(int irq, void *dev_id) | |||
328 | return IRQ_HANDLED; | 346 | return IRQ_HANDLED; |
329 | } | 347 | } |
330 | 348 | ||
349 | static void scsifront_finish_all(struct vscsifrnt_info *info) | ||
350 | { | ||
351 | unsigned i; | ||
352 | struct vscsiif_response resp; | ||
353 | |||
354 | scsifront_ring_drain(info); | ||
355 | |||
356 | for (i = 0; i < VSCSIIF_MAX_REQS; i++) { | ||
357 | if (test_bit(i, info->shadow_free_bitmap)) | ||
358 | continue; | ||
359 | resp.rqid = i; | ||
360 | resp.sense_len = 0; | ||
361 | resp.rslt = DID_RESET << 16; | ||
362 | resp.residual_len = 0; | ||
363 | scsifront_do_response(info, &resp); | ||
364 | } | ||
365 | } | ||
366 | |||
331 | static int map_data_for_request(struct vscsifrnt_info *info, | 367 | static int map_data_for_request(struct vscsifrnt_info *info, |
332 | struct scsi_cmnd *sc, | 368 | struct scsi_cmnd *sc, |
333 | struct vscsiif_request *ring_req, | 369 | struct vscsiif_request *ring_req, |
@@ -475,6 +511,27 @@ static struct vscsiif_request *scsifront_command2ring( | |||
475 | return ring_req; | 511 | return ring_req; |
476 | } | 512 | } |
477 | 513 | ||
514 | static int scsifront_enter(struct vscsifrnt_info *info) | ||
515 | { | ||
516 | if (info->pause) | ||
517 | return 1; | ||
518 | info->callers++; | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static void scsifront_return(struct vscsifrnt_info *info) | ||
523 | { | ||
524 | info->callers--; | ||
525 | if (info->callers) | ||
526 | return; | ||
527 | |||
528 | if (!info->waiting_pause) | ||
529 | return; | ||
530 | |||
531 | info->waiting_pause = 0; | ||
532 | wake_up(&info->wq_pause); | ||
533 | } | ||
534 | |||
478 | static int scsifront_queuecommand(struct Scsi_Host *shost, | 535 | static int scsifront_queuecommand(struct Scsi_Host *shost, |
479 | struct scsi_cmnd *sc) | 536 | struct scsi_cmnd *sc) |
480 | { | 537 | { |
@@ -486,6 +543,10 @@ static int scsifront_queuecommand(struct Scsi_Host *shost, | |||
486 | uint16_t rqid; | 543 | uint16_t rqid; |
487 | 544 | ||
488 | spin_lock_irqsave(shost->host_lock, flags); | 545 | spin_lock_irqsave(shost->host_lock, flags); |
546 | if (scsifront_enter(info)) { | ||
547 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
548 | return SCSI_MLQUEUE_HOST_BUSY; | ||
549 | } | ||
489 | if (RING_FULL(&info->ring)) | 550 | if (RING_FULL(&info->ring)) |
490 | goto busy; | 551 | goto busy; |
491 | 552 | ||
@@ -505,6 +566,7 @@ static int scsifront_queuecommand(struct Scsi_Host *shost, | |||
505 | if (err < 0) { | 566 | if (err < 0) { |
506 | pr_debug("%s: err %d\n", __func__, err); | 567 | pr_debug("%s: err %d\n", __func__, err); |
507 | scsifront_put_rqid(info, rqid); | 568 | scsifront_put_rqid(info, rqid); |
569 | scsifront_return(info); | ||
508 | spin_unlock_irqrestore(shost->host_lock, flags); | 570 | spin_unlock_irqrestore(shost->host_lock, flags); |
509 | if (err == -ENOMEM) | 571 | if (err == -ENOMEM) |
510 | return SCSI_MLQUEUE_HOST_BUSY; | 572 | return SCSI_MLQUEUE_HOST_BUSY; |
@@ -514,11 +576,13 @@ static int scsifront_queuecommand(struct Scsi_Host *shost, | |||
514 | } | 576 | } |
515 | 577 | ||
516 | scsifront_do_request(info); | 578 | scsifront_do_request(info); |
579 | scsifront_return(info); | ||
517 | spin_unlock_irqrestore(shost->host_lock, flags); | 580 | spin_unlock_irqrestore(shost->host_lock, flags); |
518 | 581 | ||
519 | return 0; | 582 | return 0; |
520 | 583 | ||
521 | busy: | 584 | busy: |
585 | scsifront_return(info); | ||
522 | spin_unlock_irqrestore(shost->host_lock, flags); | 586 | spin_unlock_irqrestore(shost->host_lock, flags); |
523 | pr_debug("%s: busy\n", __func__); | 587 | pr_debug("%s: busy\n", __func__); |
524 | return SCSI_MLQUEUE_HOST_BUSY; | 588 | return SCSI_MLQUEUE_HOST_BUSY; |
@@ -549,7 +613,7 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act) | |||
549 | if (ring_req) | 613 | if (ring_req) |
550 | break; | 614 | break; |
551 | } | 615 | } |
552 | if (err) { | 616 | if (err || info->pause) { |
553 | spin_unlock_irq(host->host_lock); | 617 | spin_unlock_irq(host->host_lock); |
554 | kfree(shadow); | 618 | kfree(shadow); |
555 | return FAILED; | 619 | return FAILED; |
@@ -561,6 +625,11 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act) | |||
561 | spin_lock_irq(host->host_lock); | 625 | spin_lock_irq(host->host_lock); |
562 | } | 626 | } |
563 | 627 | ||
628 | if (scsifront_enter(info)) { | ||
629 | spin_unlock_irq(host->host_lock); | ||
630 | return FAILED; | ||
631 | } | ||
632 | |||
564 | ring_req->act = act; | 633 | ring_req->act = act; |
565 | ring_req->ref_rqid = s->rqid; | 634 | ring_req->ref_rqid = s->rqid; |
566 | 635 | ||
@@ -587,6 +656,7 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act) | |||
587 | err = FAILED; | 656 | err = FAILED; |
588 | } | 657 | } |
589 | 658 | ||
659 | scsifront_return(info); | ||
590 | spin_unlock_irq(host->host_lock); | 660 | spin_unlock_irq(host->host_lock); |
591 | return err; | 661 | return err; |
592 | } | 662 | } |
@@ -644,6 +714,7 @@ static int scsifront_alloc_ring(struct vscsifrnt_info *info) | |||
644 | { | 714 | { |
645 | struct xenbus_device *dev = info->dev; | 715 | struct xenbus_device *dev = info->dev; |
646 | struct vscsiif_sring *sring; | 716 | struct vscsiif_sring *sring; |
717 | grant_ref_t gref; | ||
647 | int err = -ENOMEM; | 718 | int err = -ENOMEM; |
648 | 719 | ||
649 | /***** Frontend to Backend ring start *****/ | 720 | /***** Frontend to Backend ring start *****/ |
@@ -656,14 +727,14 @@ static int scsifront_alloc_ring(struct vscsifrnt_info *info) | |||
656 | SHARED_RING_INIT(sring); | 727 | SHARED_RING_INIT(sring); |
657 | FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); | 728 | FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); |
658 | 729 | ||
659 | err = xenbus_grant_ring(dev, virt_to_mfn(sring)); | 730 | err = xenbus_grant_ring(dev, sring, 1, &gref); |
660 | if (err < 0) { | 731 | if (err < 0) { |
661 | free_page((unsigned long)sring); | 732 | free_page((unsigned long)sring); |
662 | xenbus_dev_fatal(dev, err, | 733 | xenbus_dev_fatal(dev, err, |
663 | "fail to grant shared ring (Front to Back)"); | 734 | "fail to grant shared ring (Front to Back)"); |
664 | return err; | 735 | return err; |
665 | } | 736 | } |
666 | info->ring_ref = err; | 737 | info->ring_ref = gref; |
667 | 738 | ||
668 | err = xenbus_alloc_evtchn(dev, &info->evtchn); | 739 | err = xenbus_alloc_evtchn(dev, &info->evtchn); |
669 | if (err) { | 740 | if (err) { |
@@ -698,6 +769,13 @@ free_gnttab: | |||
698 | return err; | 769 | return err; |
699 | } | 770 | } |
700 | 771 | ||
772 | static void scsifront_free_ring(struct vscsifrnt_info *info) | ||
773 | { | ||
774 | unbind_from_irqhandler(info->irq, info); | ||
775 | gnttab_end_foreign_access(info->ring_ref, 0, | ||
776 | (unsigned long)info->ring.sring); | ||
777 | } | ||
778 | |||
701 | static int scsifront_init_ring(struct vscsifrnt_info *info) | 779 | static int scsifront_init_ring(struct vscsifrnt_info *info) |
702 | { | 780 | { |
703 | struct xenbus_device *dev = info->dev; | 781 | struct xenbus_device *dev = info->dev; |
@@ -744,9 +822,7 @@ again: | |||
744 | fail: | 822 | fail: |
745 | xenbus_transaction_end(xbt, 1); | 823 | xenbus_transaction_end(xbt, 1); |
746 | free_sring: | 824 | free_sring: |
747 | unbind_from_irqhandler(info->irq, info); | 825 | scsifront_free_ring(info); |
748 | gnttab_end_foreign_access(info->ring_ref, 0, | ||
749 | (unsigned long)info->ring.sring); | ||
750 | 826 | ||
751 | return err; | 827 | return err; |
752 | } | 828 | } |
@@ -779,6 +855,7 @@ static int scsifront_probe(struct xenbus_device *dev, | |||
779 | } | 855 | } |
780 | 856 | ||
781 | init_waitqueue_head(&info->wq_sync); | 857 | init_waitqueue_head(&info->wq_sync); |
858 | init_waitqueue_head(&info->wq_pause); | ||
782 | spin_lock_init(&info->shadow_lock); | 859 | spin_lock_init(&info->shadow_lock); |
783 | 860 | ||
784 | snprintf(name, TASK_COMM_LEN, "vscsiif.%d", host->host_no); | 861 | snprintf(name, TASK_COMM_LEN, "vscsiif.%d", host->host_no); |
@@ -802,13 +879,60 @@ static int scsifront_probe(struct xenbus_device *dev, | |||
802 | return 0; | 879 | return 0; |
803 | 880 | ||
804 | free_sring: | 881 | free_sring: |
805 | unbind_from_irqhandler(info->irq, info); | 882 | scsifront_free_ring(info); |
806 | gnttab_end_foreign_access(info->ring_ref, 0, | ||
807 | (unsigned long)info->ring.sring); | ||
808 | scsi_host_put(host); | 883 | scsi_host_put(host); |
809 | return err; | 884 | return err; |
810 | } | 885 | } |
811 | 886 | ||
887 | static int scsifront_resume(struct xenbus_device *dev) | ||
888 | { | ||
889 | struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev); | ||
890 | struct Scsi_Host *host = info->host; | ||
891 | int err; | ||
892 | |||
893 | spin_lock_irq(host->host_lock); | ||
894 | |||
895 | /* Finish all still pending commands. */ | ||
896 | scsifront_finish_all(info); | ||
897 | |||
898 | spin_unlock_irq(host->host_lock); | ||
899 | |||
900 | /* Reconnect to dom0. */ | ||
901 | scsifront_free_ring(info); | ||
902 | err = scsifront_init_ring(info); | ||
903 | if (err) { | ||
904 | dev_err(&dev->dev, "fail to resume %d\n", err); | ||
905 | scsi_host_put(host); | ||
906 | return err; | ||
907 | } | ||
908 | |||
909 | xenbus_switch_state(dev, XenbusStateInitialised); | ||
910 | |||
911 | return 0; | ||
912 | } | ||
913 | |||
914 | static int scsifront_suspend(struct xenbus_device *dev) | ||
915 | { | ||
916 | struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev); | ||
917 | struct Scsi_Host *host = info->host; | ||
918 | int err = 0; | ||
919 | |||
920 | /* No new commands for the backend. */ | ||
921 | spin_lock_irq(host->host_lock); | ||
922 | info->pause = 1; | ||
923 | while (info->callers && !err) { | ||
924 | info->waiting_pause = 1; | ||
925 | info->wait_ring_available = 0; | ||
926 | spin_unlock_irq(host->host_lock); | ||
927 | wake_up(&info->wq_sync); | ||
928 | err = wait_event_interruptible(info->wq_pause, | ||
929 | !info->waiting_pause); | ||
930 | spin_lock_irq(host->host_lock); | ||
931 | } | ||
932 | spin_unlock_irq(host->host_lock); | ||
933 | return err; | ||
934 | } | ||
935 | |||
812 | static int scsifront_remove(struct xenbus_device *dev) | 936 | static int scsifront_remove(struct xenbus_device *dev) |
813 | { | 937 | { |
814 | struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev); | 938 | struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev); |
@@ -823,10 +947,7 @@ static int scsifront_remove(struct xenbus_device *dev) | |||
823 | } | 947 | } |
824 | mutex_unlock(&scsifront_mutex); | 948 | mutex_unlock(&scsifront_mutex); |
825 | 949 | ||
826 | gnttab_end_foreign_access(info->ring_ref, 0, | 950 | scsifront_free_ring(info); |
827 | (unsigned long)info->ring.sring); | ||
828 | unbind_from_irqhandler(info->irq, info); | ||
829 | |||
830 | scsi_host_put(info->host); | 951 | scsi_host_put(info->host); |
831 | 952 | ||
832 | return 0; | 953 | return 0; |
@@ -919,6 +1040,12 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op) | |||
919 | scsi_device_put(sdev); | 1040 | scsi_device_put(sdev); |
920 | } | 1041 | } |
921 | break; | 1042 | break; |
1043 | case VSCSIFRONT_OP_READD_LUN: | ||
1044 | if (device_state == XenbusStateConnected) | ||
1045 | xenbus_printf(XBT_NIL, dev->nodename, | ||
1046 | info->dev_state_path, | ||
1047 | "%d", XenbusStateConnected); | ||
1048 | break; | ||
922 | default: | 1049 | default: |
923 | break; | 1050 | break; |
924 | } | 1051 | } |
@@ -932,21 +1059,29 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op) | |||
932 | static void scsifront_read_backend_params(struct xenbus_device *dev, | 1059 | static void scsifront_read_backend_params(struct xenbus_device *dev, |
933 | struct vscsifrnt_info *info) | 1060 | struct vscsifrnt_info *info) |
934 | { | 1061 | { |
935 | unsigned int sg_grant; | 1062 | unsigned int sg_grant, nr_segs; |
936 | int ret; | 1063 | int ret; |
937 | struct Scsi_Host *host = info->host; | 1064 | struct Scsi_Host *host = info->host; |
938 | 1065 | ||
939 | ret = xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg-grant", "%u", | 1066 | ret = xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg-grant", "%u", |
940 | &sg_grant); | 1067 | &sg_grant); |
941 | if (ret == 1 && sg_grant) { | 1068 | if (ret != 1) |
942 | sg_grant = min_t(unsigned int, sg_grant, SG_ALL); | 1069 | sg_grant = 0; |
943 | sg_grant = max_t(unsigned int, sg_grant, VSCSIIF_SG_TABLESIZE); | 1070 | nr_segs = min_t(unsigned int, sg_grant, SG_ALL); |
944 | host->sg_tablesize = min_t(unsigned int, sg_grant, | 1071 | nr_segs = max_t(unsigned int, nr_segs, VSCSIIF_SG_TABLESIZE); |
1072 | nr_segs = min_t(unsigned int, nr_segs, | ||
945 | VSCSIIF_SG_TABLESIZE * PAGE_SIZE / | 1073 | VSCSIIF_SG_TABLESIZE * PAGE_SIZE / |
946 | sizeof(struct scsiif_request_segment)); | 1074 | sizeof(struct scsiif_request_segment)); |
947 | host->max_sectors = (host->sg_tablesize - 1) * PAGE_SIZE / 512; | 1075 | |
948 | } | 1076 | if (!info->pause && sg_grant) |
949 | dev_info(&dev->dev, "using up to %d SG entries\n", host->sg_tablesize); | 1077 | dev_info(&dev->dev, "using up to %d SG entries\n", nr_segs); |
1078 | else if (info->pause && nr_segs < host->sg_tablesize) | ||
1079 | dev_warn(&dev->dev, | ||
1080 | "SG entries decreased from %d to %u - device may not work properly anymore\n", | ||
1081 | host->sg_tablesize, nr_segs); | ||
1082 | |||
1083 | host->sg_tablesize = nr_segs; | ||
1084 | host->max_sectors = (nr_segs - 1) * PAGE_SIZE / 512; | ||
950 | } | 1085 | } |
951 | 1086 | ||
952 | static void scsifront_backend_changed(struct xenbus_device *dev, | 1087 | static void scsifront_backend_changed(struct xenbus_device *dev, |
@@ -965,6 +1100,14 @@ static void scsifront_backend_changed(struct xenbus_device *dev, | |||
965 | 1100 | ||
966 | case XenbusStateConnected: | 1101 | case XenbusStateConnected: |
967 | scsifront_read_backend_params(dev, info); | 1102 | scsifront_read_backend_params(dev, info); |
1103 | |||
1104 | if (info->pause) { | ||
1105 | scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_READD_LUN); | ||
1106 | xenbus_switch_state(dev, XenbusStateConnected); | ||
1107 | info->pause = 0; | ||
1108 | return; | ||
1109 | } | ||
1110 | |||
968 | if (xenbus_read_driver_state(dev->nodename) == | 1111 | if (xenbus_read_driver_state(dev->nodename) == |
969 | XenbusStateInitialised) | 1112 | XenbusStateInitialised) |
970 | scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN); | 1113 | scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN); |
@@ -1002,6 +1145,8 @@ static struct xenbus_driver scsifront_driver = { | |||
1002 | .ids = scsifront_ids, | 1145 | .ids = scsifront_ids, |
1003 | .probe = scsifront_probe, | 1146 | .probe = scsifront_probe, |
1004 | .remove = scsifront_remove, | 1147 | .remove = scsifront_remove, |
1148 | .resume = scsifront_resume, | ||
1149 | .suspend = scsifront_suspend, | ||
1005 | .otherend_changed = scsifront_backend_changed, | 1150 | .otherend_changed = scsifront_backend_changed, |
1006 | }; | 1151 | }; |
1007 | 1152 | ||
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 94d96809e686..a270004c9605 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig | |||
@@ -270,4 +270,10 @@ config XEN_EFI | |||
270 | def_bool y | 270 | def_bool y |
271 | depends on X86_64 && EFI | 271 | depends on X86_64 && EFI |
272 | 272 | ||
273 | config XEN_AUTO_XLATE | ||
274 | def_bool y | ||
275 | depends on ARM || ARM64 || XEN_PVHVM | ||
276 | help | ||
277 | Support for auto-translated physmap guests. | ||
278 | |||
273 | endmenu | 279 | endmenu |
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 2ccd3592d41f..40edd1cbb60d 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile | |||
@@ -37,6 +37,7 @@ obj-$(CONFIG_XEN_ACPI_HOTPLUG_CPU) += xen-acpi-cpuhotplug.o | |||
37 | obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o | 37 | obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o |
38 | obj-$(CONFIG_XEN_EFI) += efi.o | 38 | obj-$(CONFIG_XEN_EFI) += efi.o |
39 | obj-$(CONFIG_XEN_SCSI_BACKEND) += xen-scsiback.o | 39 | obj-$(CONFIG_XEN_SCSI_BACKEND) += xen-scsiback.o |
40 | obj-$(CONFIG_XEN_AUTO_XLATE) += xlate_mmu.o | ||
40 | xen-evtchn-y := evtchn.o | 41 | xen-evtchn-y := evtchn.o |
41 | xen-gntdev-y := gntdev.o | 42 | xen-gntdev-y := gntdev.o |
42 | xen-gntalloc-y := gntalloc.o | 43 | xen-gntalloc-y := gntalloc.o |
diff --git a/drivers/xen/mcelog.c b/drivers/xen/mcelog.c index 6ab6a79c38a5..a493c7315e94 100644 --- a/drivers/xen/mcelog.c +++ b/drivers/xen/mcelog.c | |||
@@ -393,14 +393,25 @@ static int bind_virq_for_mce(void) | |||
393 | 393 | ||
394 | static int __init xen_late_init_mcelog(void) | 394 | static int __init xen_late_init_mcelog(void) |
395 | { | 395 | { |
396 | int ret; | ||
397 | |||
396 | /* Only DOM0 is responsible for MCE logging */ | 398 | /* Only DOM0 is responsible for MCE logging */ |
397 | if (xen_initial_domain()) { | 399 | if (!xen_initial_domain()) |
398 | /* register character device /dev/mcelog for xen mcelog */ | 400 | return -ENODEV; |
399 | if (misc_register(&xen_mce_chrdev_device)) | 401 | |
400 | return -ENODEV; | 402 | /* register character device /dev/mcelog for xen mcelog */ |
401 | return bind_virq_for_mce(); | 403 | ret = misc_register(&xen_mce_chrdev_device); |
402 | } | 404 | if (ret) |
405 | return ret; | ||
406 | |||
407 | ret = bind_virq_for_mce(); | ||
408 | if (ret) | ||
409 | goto deregister; | ||
403 | 410 | ||
404 | return -ENODEV; | 411 | return 0; |
412 | |||
413 | deregister: | ||
414 | misc_deregister(&xen_mce_chrdev_device); | ||
415 | return ret; | ||
405 | } | 416 | } |
406 | device_initcall(xen_late_init_mcelog); | 417 | device_initcall(xen_late_init_mcelog); |
diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c index 95ee4302ffb8..7494dbeb4409 100644 --- a/drivers/xen/pci.c +++ b/drivers/xen/pci.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/pci.h> | 20 | #include <linux/pci.h> |
21 | #include <linux/acpi.h> | 21 | #include <linux/acpi.h> |
22 | #include <linux/pci-acpi.h> | ||
22 | #include <xen/xen.h> | 23 | #include <xen/xen.h> |
23 | #include <xen/interface/physdev.h> | 24 | #include <xen/interface/physdev.h> |
24 | #include <xen/interface/xen.h> | 25 | #include <xen/interface/xen.h> |
@@ -67,12 +68,22 @@ static int xen_add_device(struct device *dev) | |||
67 | 68 | ||
68 | #ifdef CONFIG_ACPI | 69 | #ifdef CONFIG_ACPI |
69 | handle = ACPI_HANDLE(&pci_dev->dev); | 70 | handle = ACPI_HANDLE(&pci_dev->dev); |
70 | if (!handle && pci_dev->bus->bridge) | ||
71 | handle = ACPI_HANDLE(pci_dev->bus->bridge); | ||
72 | #ifdef CONFIG_PCI_IOV | 71 | #ifdef CONFIG_PCI_IOV |
73 | if (!handle && pci_dev->is_virtfn) | 72 | if (!handle && pci_dev->is_virtfn) |
74 | handle = ACPI_HANDLE(physfn->bus->bridge); | 73 | handle = ACPI_HANDLE(physfn->bus->bridge); |
75 | #endif | 74 | #endif |
75 | if (!handle) { | ||
76 | /* | ||
77 | * This device was not listed in the ACPI name space at | ||
78 | * all. Try to get acpi handle of parent pci bus. | ||
79 | */ | ||
80 | struct pci_bus *pbus; | ||
81 | for (pbus = pci_dev->bus; pbus; pbus = pbus->parent) { | ||
82 | handle = acpi_pci_get_bridge_handle(pbus); | ||
83 | if (handle) | ||
84 | break; | ||
85 | } | ||
86 | } | ||
76 | if (handle) { | 87 | if (handle) { |
77 | acpi_status status; | 88 | acpi_status status; |
78 | 89 | ||
diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c index 0aac403d53fd..49e88f2ce7a1 100644 --- a/drivers/xen/pcpu.c +++ b/drivers/xen/pcpu.c | |||
@@ -132,6 +132,33 @@ static ssize_t __ref store_online(struct device *dev, | |||
132 | } | 132 | } |
133 | static DEVICE_ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online); | 133 | static DEVICE_ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online); |
134 | 134 | ||
135 | static struct attribute *pcpu_dev_attrs[] = { | ||
136 | &dev_attr_online.attr, | ||
137 | NULL | ||
138 | }; | ||
139 | |||
140 | static umode_t pcpu_dev_is_visible(struct kobject *kobj, | ||
141 | struct attribute *attr, int idx) | ||
142 | { | ||
143 | struct device *dev = kobj_to_dev(kobj); | ||
144 | /* | ||
145 | * Xen never offline cpu0 due to several restrictions | ||
146 | * and assumptions. This basically doesn't add a sys control | ||
147 | * to user, one cannot attempt to offline BSP. | ||
148 | */ | ||
149 | return dev->id ? attr->mode : 0; | ||
150 | } | ||
151 | |||
152 | static const struct attribute_group pcpu_dev_group = { | ||
153 | .attrs = pcpu_dev_attrs, | ||
154 | .is_visible = pcpu_dev_is_visible, | ||
155 | }; | ||
156 | |||
157 | static const struct attribute_group *pcpu_dev_groups[] = { | ||
158 | &pcpu_dev_group, | ||
159 | NULL | ||
160 | }; | ||
161 | |||
135 | static bool xen_pcpu_online(uint32_t flags) | 162 | static bool xen_pcpu_online(uint32_t flags) |
136 | { | 163 | { |
137 | return !!(flags & XEN_PCPU_FLAGS_ONLINE); | 164 | return !!(flags & XEN_PCPU_FLAGS_ONLINE); |
@@ -181,9 +208,6 @@ static void unregister_and_remove_pcpu(struct pcpu *pcpu) | |||
181 | return; | 208 | return; |
182 | 209 | ||
183 | dev = &pcpu->dev; | 210 | dev = &pcpu->dev; |
184 | if (dev->id) | ||
185 | device_remove_file(dev, &dev_attr_online); | ||
186 | |||
187 | /* pcpu remove would be implicitly done */ | 211 | /* pcpu remove would be implicitly done */ |
188 | device_unregister(dev); | 212 | device_unregister(dev); |
189 | } | 213 | } |
@@ -200,6 +224,7 @@ static int register_pcpu(struct pcpu *pcpu) | |||
200 | dev->bus = &xen_pcpu_subsys; | 224 | dev->bus = &xen_pcpu_subsys; |
201 | dev->id = pcpu->cpu_id; | 225 | dev->id = pcpu->cpu_id; |
202 | dev->release = pcpu_release; | 226 | dev->release = pcpu_release; |
227 | dev->groups = pcpu_dev_groups; | ||
203 | 228 | ||
204 | err = device_register(dev); | 229 | err = device_register(dev); |
205 | if (err) { | 230 | if (err) { |
@@ -207,19 +232,6 @@ static int register_pcpu(struct pcpu *pcpu) | |||
207 | return err; | 232 | return err; |
208 | } | 233 | } |
209 | 234 | ||
210 | /* | ||
211 | * Xen never offline cpu0 due to several restrictions | ||
212 | * and assumptions. This basically doesn't add a sys control | ||
213 | * to user, one cannot attempt to offline BSP. | ||
214 | */ | ||
215 | if (dev->id) { | ||
216 | err = device_create_file(dev, &dev_attr_online); | ||
217 | if (err) { | ||
218 | device_unregister(dev); | ||
219 | return err; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | return 0; | 235 | return 0; |
224 | } | 236 | } |
225 | 237 | ||
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 59ac71c4a043..5a296161d843 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c | |||
@@ -159,6 +159,40 @@ static int traverse_pages(unsigned nelem, size_t size, | |||
159 | return ret; | 159 | return ret; |
160 | } | 160 | } |
161 | 161 | ||
162 | /* | ||
163 | * Similar to traverse_pages, but use each page as a "block" of | ||
164 | * data to be processed as one unit. | ||
165 | */ | ||
166 | static int traverse_pages_block(unsigned nelem, size_t size, | ||
167 | struct list_head *pos, | ||
168 | int (*fn)(void *data, int nr, void *state), | ||
169 | void *state) | ||
170 | { | ||
171 | void *pagedata; | ||
172 | unsigned pageidx; | ||
173 | int ret = 0; | ||
174 | |||
175 | BUG_ON(size > PAGE_SIZE); | ||
176 | |||
177 | pageidx = PAGE_SIZE; | ||
178 | |||
179 | while (nelem) { | ||
180 | int nr = (PAGE_SIZE/size); | ||
181 | struct page *page; | ||
182 | if (nr > nelem) | ||
183 | nr = nelem; | ||
184 | pos = pos->next; | ||
185 | page = list_entry(pos, struct page, lru); | ||
186 | pagedata = page_address(page); | ||
187 | ret = (*fn)(pagedata, nr, state); | ||
188 | if (ret) | ||
189 | break; | ||
190 | nelem -= nr; | ||
191 | } | ||
192 | |||
193 | return ret; | ||
194 | } | ||
195 | |||
162 | struct mmap_mfn_state { | 196 | struct mmap_mfn_state { |
163 | unsigned long va; | 197 | unsigned long va; |
164 | struct vm_area_struct *vma; | 198 | struct vm_area_struct *vma; |
@@ -274,39 +308,25 @@ struct mmap_batch_state { | |||
274 | /* auto translated dom0 note: if domU being created is PV, then mfn is | 308 | /* auto translated dom0 note: if domU being created is PV, then mfn is |
275 | * mfn(addr on bus). If it's auto xlated, then mfn is pfn (input to HAP). | 309 | * mfn(addr on bus). If it's auto xlated, then mfn is pfn (input to HAP). |
276 | */ | 310 | */ |
277 | static int mmap_batch_fn(void *data, void *state) | 311 | static int mmap_batch_fn(void *data, int nr, void *state) |
278 | { | 312 | { |
279 | xen_pfn_t *mfnp = data; | 313 | xen_pfn_t *mfnp = data; |
280 | struct mmap_batch_state *st = state; | 314 | struct mmap_batch_state *st = state; |
281 | struct vm_area_struct *vma = st->vma; | 315 | struct vm_area_struct *vma = st->vma; |
282 | struct page **pages = vma->vm_private_data; | 316 | struct page **pages = vma->vm_private_data; |
283 | struct page *cur_page = NULL; | 317 | struct page **cur_pages = NULL; |
284 | int ret; | 318 | int ret; |
285 | 319 | ||
286 | if (xen_feature(XENFEAT_auto_translated_physmap)) | 320 | if (xen_feature(XENFEAT_auto_translated_physmap)) |
287 | cur_page = pages[st->index++]; | 321 | cur_pages = &pages[st->index]; |
288 | 322 | ||
289 | ret = xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1, | 323 | BUG_ON(nr < 0); |
290 | st->vma->vm_page_prot, st->domain, | 324 | ret = xen_remap_domain_mfn_array(st->vma, st->va & PAGE_MASK, mfnp, nr, |
291 | &cur_page); | 325 | (int *)mfnp, st->vma->vm_page_prot, |
326 | st->domain, cur_pages); | ||
292 | 327 | ||
293 | /* Store error code for second pass. */ | 328 | /* Adjust the global_error? */ |
294 | if (st->version == 1) { | 329 | if (ret != nr) { |
295 | if (ret < 0) { | ||
296 | /* | ||
297 | * V1 encodes the error codes in the 32bit top nibble of the | ||
298 | * mfn (with its known limitations vis-a-vis 64 bit callers). | ||
299 | */ | ||
300 | *mfnp |= (ret == -ENOENT) ? | ||
301 | PRIVCMD_MMAPBATCH_PAGED_ERROR : | ||
302 | PRIVCMD_MMAPBATCH_MFN_ERROR; | ||
303 | } | ||
304 | } else { /* st->version == 2 */ | ||
305 | *((int *) mfnp) = ret; | ||
306 | } | ||
307 | |||
308 | /* And see if it affects the global_error. */ | ||
309 | if (ret < 0) { | ||
310 | if (ret == -ENOENT) | 330 | if (ret == -ENOENT) |
311 | st->global_error = -ENOENT; | 331 | st->global_error = -ENOENT; |
312 | else { | 332 | else { |
@@ -315,23 +335,35 @@ static int mmap_batch_fn(void *data, void *state) | |||
315 | st->global_error = 1; | 335 | st->global_error = 1; |
316 | } | 336 | } |
317 | } | 337 | } |
318 | st->va += PAGE_SIZE; | 338 | st->va += PAGE_SIZE * nr; |
339 | st->index += nr; | ||
319 | 340 | ||
320 | return 0; | 341 | return 0; |
321 | } | 342 | } |
322 | 343 | ||
323 | static int mmap_return_errors(void *data, void *state) | 344 | static int mmap_return_error(int err, struct mmap_batch_state *st) |
324 | { | 345 | { |
325 | struct mmap_batch_state *st = state; | 346 | int ret; |
326 | 347 | ||
327 | if (st->version == 1) { | 348 | if (st->version == 1) { |
328 | xen_pfn_t mfnp = *((xen_pfn_t *) data); | 349 | if (err) { |
329 | if (mfnp & PRIVCMD_MMAPBATCH_MFN_ERROR) | 350 | xen_pfn_t mfn; |
330 | return __put_user(mfnp, st->user_mfn++); | 351 | |
331 | else | 352 | ret = get_user(mfn, st->user_mfn); |
353 | if (ret < 0) | ||
354 | return ret; | ||
355 | /* | ||
356 | * V1 encodes the error codes in the 32bit top | ||
357 | * nibble of the mfn (with its known | ||
358 | * limitations vis-a-vis 64 bit callers). | ||
359 | */ | ||
360 | mfn |= (err == -ENOENT) ? | ||
361 | PRIVCMD_MMAPBATCH_PAGED_ERROR : | ||
362 | PRIVCMD_MMAPBATCH_MFN_ERROR; | ||
363 | return __put_user(mfn, st->user_mfn++); | ||
364 | } else | ||
332 | st->user_mfn++; | 365 | st->user_mfn++; |
333 | } else { /* st->version == 2 */ | 366 | } else { /* st->version == 2 */ |
334 | int err = *((int *) data); | ||
335 | if (err) | 367 | if (err) |
336 | return __put_user(err, st->user_err++); | 368 | return __put_user(err, st->user_err++); |
337 | else | 369 | else |
@@ -341,6 +373,21 @@ static int mmap_return_errors(void *data, void *state) | |||
341 | return 0; | 373 | return 0; |
342 | } | 374 | } |
343 | 375 | ||
376 | static int mmap_return_errors(void *data, int nr, void *state) | ||
377 | { | ||
378 | struct mmap_batch_state *st = state; | ||
379 | int *errs = data; | ||
380 | int i; | ||
381 | int ret; | ||
382 | |||
383 | for (i = 0; i < nr; i++) { | ||
384 | ret = mmap_return_error(errs[i], st); | ||
385 | if (ret < 0) | ||
386 | return ret; | ||
387 | } | ||
388 | return 0; | ||
389 | } | ||
390 | |||
344 | /* Allocate pfns that are then mapped with gmfns from foreign domid. Update | 391 | /* Allocate pfns that are then mapped with gmfns from foreign domid. Update |
345 | * the vma with the page info to use later. | 392 | * the vma with the page info to use later. |
346 | * Returns: 0 if success, otherwise -errno | 393 | * Returns: 0 if success, otherwise -errno |
@@ -472,8 +519,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) | |||
472 | state.version = version; | 519 | state.version = version; |
473 | 520 | ||
474 | /* mmap_batch_fn guarantees ret == 0 */ | 521 | /* mmap_batch_fn guarantees ret == 0 */ |
475 | BUG_ON(traverse_pages(m.num, sizeof(xen_pfn_t), | 522 | BUG_ON(traverse_pages_block(m.num, sizeof(xen_pfn_t), |
476 | &pagelist, mmap_batch_fn, &state)); | 523 | &pagelist, mmap_batch_fn, &state)); |
477 | 524 | ||
478 | up_write(&mm->mmap_sem); | 525 | up_write(&mm->mmap_sem); |
479 | 526 | ||
@@ -481,8 +528,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) | |||
481 | /* Write back errors in second pass. */ | 528 | /* Write back errors in second pass. */ |
482 | state.user_mfn = (xen_pfn_t *)m.arr; | 529 | state.user_mfn = (xen_pfn_t *)m.arr; |
483 | state.user_err = m.err; | 530 | state.user_err = m.err; |
484 | ret = traverse_pages(m.num, sizeof(xen_pfn_t), | 531 | ret = traverse_pages_block(m.num, sizeof(xen_pfn_t), |
485 | &pagelist, mmap_return_errors, &state); | 532 | &pagelist, mmap_return_errors, &state); |
486 | } else | 533 | } else |
487 | ret = 0; | 534 | ret = 0; |
488 | 535 | ||
diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c index e555845d61fa..39e7ef8d3957 100644 --- a/drivers/xen/xen-balloon.c +++ b/drivers/xen/xen-balloon.c | |||
@@ -193,13 +193,18 @@ static DEVICE_ATTR(target, S_IRUGO | S_IWUSR, | |||
193 | show_target, store_target); | 193 | show_target, store_target); |
194 | 194 | ||
195 | 195 | ||
196 | static struct device_attribute *balloon_attrs[] = { | 196 | static struct attribute *balloon_attrs[] = { |
197 | &dev_attr_target_kb, | 197 | &dev_attr_target_kb.attr, |
198 | &dev_attr_target, | 198 | &dev_attr_target.attr, |
199 | &dev_attr_schedule_delay.attr, | 199 | &dev_attr_schedule_delay.attr.attr, |
200 | &dev_attr_max_schedule_delay.attr, | 200 | &dev_attr_max_schedule_delay.attr.attr, |
201 | &dev_attr_retry_count.attr, | 201 | &dev_attr_retry_count.attr.attr, |
202 | &dev_attr_max_retry_count.attr | 202 | &dev_attr_max_retry_count.attr.attr, |
203 | NULL | ||
204 | }; | ||
205 | |||
206 | static const struct attribute_group balloon_group = { | ||
207 | .attrs = balloon_attrs | ||
203 | }; | 208 | }; |
204 | 209 | ||
205 | static struct attribute *balloon_info_attrs[] = { | 210 | static struct attribute *balloon_info_attrs[] = { |
@@ -214,6 +219,12 @@ static const struct attribute_group balloon_info_group = { | |||
214 | .attrs = balloon_info_attrs | 219 | .attrs = balloon_info_attrs |
215 | }; | 220 | }; |
216 | 221 | ||
222 | static const struct attribute_group *balloon_groups[] = { | ||
223 | &balloon_group, | ||
224 | &balloon_info_group, | ||
225 | NULL | ||
226 | }; | ||
227 | |||
217 | static struct bus_type balloon_subsys = { | 228 | static struct bus_type balloon_subsys = { |
218 | .name = BALLOON_CLASS_NAME, | 229 | .name = BALLOON_CLASS_NAME, |
219 | .dev_name = BALLOON_CLASS_NAME, | 230 | .dev_name = BALLOON_CLASS_NAME, |
@@ -221,7 +232,7 @@ static struct bus_type balloon_subsys = { | |||
221 | 232 | ||
222 | static int register_balloon(struct device *dev) | 233 | static int register_balloon(struct device *dev) |
223 | { | 234 | { |
224 | int i, error; | 235 | int error; |
225 | 236 | ||
226 | error = subsys_system_register(&balloon_subsys, NULL); | 237 | error = subsys_system_register(&balloon_subsys, NULL); |
227 | if (error) | 238 | if (error) |
@@ -229,6 +240,7 @@ static int register_balloon(struct device *dev) | |||
229 | 240 | ||
230 | dev->id = 0; | 241 | dev->id = 0; |
231 | dev->bus = &balloon_subsys; | 242 | dev->bus = &balloon_subsys; |
243 | dev->groups = balloon_groups; | ||
232 | 244 | ||
233 | error = device_register(dev); | 245 | error = device_register(dev); |
234 | if (error) { | 246 | if (error) { |
@@ -236,24 +248,7 @@ static int register_balloon(struct device *dev) | |||
236 | return error; | 248 | return error; |
237 | } | 249 | } |
238 | 250 | ||
239 | for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) { | ||
240 | error = device_create_file(dev, balloon_attrs[i]); | ||
241 | if (error) | ||
242 | goto fail; | ||
243 | } | ||
244 | |||
245 | error = sysfs_create_group(&dev->kobj, &balloon_info_group); | ||
246 | if (error) | ||
247 | goto fail; | ||
248 | |||
249 | return 0; | 251 | return 0; |
250 | |||
251 | fail: | ||
252 | while (--i >= 0) | ||
253 | device_remove_file(dev, balloon_attrs[i]); | ||
254 | device_unregister(dev); | ||
255 | bus_unregister(&balloon_subsys); | ||
256 | return error; | ||
257 | } | 252 | } |
258 | 253 | ||
259 | MODULE_LICENSE("GPL"); | 254 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/xen/xen-pciback/conf_space_header.c b/drivers/xen/xen-pciback/conf_space_header.c index 2d7369391472..c2260a0456c9 100644 --- a/drivers/xen/xen-pciback/conf_space_header.c +++ b/drivers/xen/xen-pciback/conf_space_header.c | |||
@@ -88,9 +88,15 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) | |||
88 | printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n", | 88 | printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n", |
89 | pci_name(dev)); | 89 | pci_name(dev)); |
90 | pci_set_master(dev); | 90 | pci_set_master(dev); |
91 | } else if (dev->is_busmaster && !is_master_cmd(value)) { | ||
92 | if (unlikely(verbose_request)) | ||
93 | printk(KERN_DEBUG DRV_NAME ": %s: clear bus master\n", | ||
94 | pci_name(dev)); | ||
95 | pci_clear_master(dev); | ||
91 | } | 96 | } |
92 | 97 | ||
93 | if (value & PCI_COMMAND_INVALIDATE) { | 98 | if (!(cmd->val & PCI_COMMAND_INVALIDATE) && |
99 | (value & PCI_COMMAND_INVALIDATE)) { | ||
94 | if (unlikely(verbose_request)) | 100 | if (unlikely(verbose_request)) |
95 | printk(KERN_DEBUG | 101 | printk(KERN_DEBUG |
96 | DRV_NAME ": %s: enable memory-write-invalidate\n", | 102 | DRV_NAME ": %s: enable memory-write-invalidate\n", |
@@ -101,6 +107,13 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) | |||
101 | pci_name(dev), err); | 107 | pci_name(dev), err); |
102 | value &= ~PCI_COMMAND_INVALIDATE; | 108 | value &= ~PCI_COMMAND_INVALIDATE; |
103 | } | 109 | } |
110 | } else if ((cmd->val & PCI_COMMAND_INVALIDATE) && | ||
111 | !(value & PCI_COMMAND_INVALIDATE)) { | ||
112 | if (unlikely(verbose_request)) | ||
113 | printk(KERN_DEBUG | ||
114 | DRV_NAME ": %s: disable memory-write-invalidate\n", | ||
115 | pci_name(dev)); | ||
116 | pci_clear_mwi(dev); | ||
104 | } | 117 | } |
105 | 118 | ||
106 | cmd->val = value; | 119 | cmd->val = value; |
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index cc3cbb4435f8..258b7c325649 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c | |||
@@ -118,7 +118,7 @@ static void pcistub_device_release(struct kref *kref) | |||
118 | int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix, | 118 | int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix, |
119 | &ppdev); | 119 | &ppdev); |
120 | 120 | ||
121 | if (err) | 121 | if (err && err != -ENOSYS) |
122 | dev_warn(&dev->dev, "MSI-X release failed (%d)\n", | 122 | dev_warn(&dev->dev, "MSI-X release failed (%d)\n", |
123 | err); | 123 | err); |
124 | } | 124 | } |
@@ -402,7 +402,7 @@ static int pcistub_init_device(struct pci_dev *dev) | |||
402 | }; | 402 | }; |
403 | 403 | ||
404 | err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev); | 404 | err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev); |
405 | if (err) | 405 | if (err && err != -ENOSYS) |
406 | dev_err(&dev->dev, "MSI-X preparation failed (%d)\n", | 406 | dev_err(&dev->dev, "MSI-X preparation failed (%d)\n", |
407 | err); | 407 | err); |
408 | } | 408 | } |
diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c index fe17c80ff4b7..98bc345f296e 100644 --- a/drivers/xen/xen-pciback/xenbus.c +++ b/drivers/xen/xen-pciback/xenbus.c | |||
@@ -113,7 +113,7 @@ static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref, | |||
113 | "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n", | 113 | "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n", |
114 | gnt_ref, remote_evtchn); | 114 | gnt_ref, remote_evtchn); |
115 | 115 | ||
116 | err = xenbus_map_ring_valloc(pdev->xdev, gnt_ref, &vaddr); | 116 | err = xenbus_map_ring_valloc(pdev->xdev, &gnt_ref, 1, &vaddr); |
117 | if (err < 0) { | 117 | if (err < 0) { |
118 | xenbus_dev_fatal(pdev->xdev, err, | 118 | xenbus_dev_fatal(pdev->xdev, err, |
119 | "Error mapping other domain page in ours."); | 119 | "Error mapping other domain page in ours."); |
diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 42bd55a6c237..07ef38325223 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c | |||
@@ -31,6 +31,8 @@ | |||
31 | * IN THE SOFTWARE. | 31 | * IN THE SOFTWARE. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #define pr_fmt(fmt) "xen-pvscsi: " fmt | ||
35 | |||
34 | #include <stdarg.h> | 36 | #include <stdarg.h> |
35 | 37 | ||
36 | #include <linux/module.h> | 38 | #include <linux/module.h> |
@@ -69,9 +71,6 @@ | |||
69 | #include <xen/interface/grant_table.h> | 71 | #include <xen/interface/grant_table.h> |
70 | #include <xen/interface/io/vscsiif.h> | 72 | #include <xen/interface/io/vscsiif.h> |
71 | 73 | ||
72 | #define DPRINTK(_f, _a...) \ | ||
73 | pr_debug("(file=%s, line=%d) " _f, __FILE__ , __LINE__ , ## _a) | ||
74 | |||
75 | #define VSCSI_VERSION "v0.1" | 74 | #define VSCSI_VERSION "v0.1" |
76 | #define VSCSI_NAMELEN 32 | 75 | #define VSCSI_NAMELEN 32 |
77 | 76 | ||
@@ -271,7 +270,7 @@ static void scsiback_print_status(char *sense_buffer, int errors, | |||
271 | { | 270 | { |
272 | struct scsiback_tpg *tpg = pending_req->v2p->tpg; | 271 | struct scsiback_tpg *tpg = pending_req->v2p->tpg; |
273 | 272 | ||
274 | pr_err("xen-pvscsi[%s:%d] cmnd[0]=%02x -> st=%02x msg=%02x host=%02x drv=%02x\n", | 273 | pr_err("[%s:%d] cmnd[0]=%02x -> st=%02x msg=%02x host=%02x drv=%02x\n", |
275 | tpg->tport->tport_name, pending_req->v2p->lun, | 274 | tpg->tport->tport_name, pending_req->v2p->lun, |
276 | pending_req->cmnd[0], status_byte(errors), msg_byte(errors), | 275 | pending_req->cmnd[0], status_byte(errors), msg_byte(errors), |
277 | host_byte(errors), driver_byte(errors)); | 276 | host_byte(errors), driver_byte(errors)); |
@@ -427,7 +426,7 @@ static int scsiback_gnttab_data_map_batch(struct gnttab_map_grant_ref *map, | |||
427 | BUG_ON(err); | 426 | BUG_ON(err); |
428 | for (i = 0; i < cnt; i++) { | 427 | for (i = 0; i < cnt; i++) { |
429 | if (unlikely(map[i].status != GNTST_okay)) { | 428 | if (unlikely(map[i].status != GNTST_okay)) { |
430 | pr_err("xen-pvscsi: invalid buffer -- could not remap it\n"); | 429 | pr_err("invalid buffer -- could not remap it\n"); |
431 | map[i].handle = SCSIBACK_INVALID_HANDLE; | 430 | map[i].handle = SCSIBACK_INVALID_HANDLE; |
432 | err = -ENOMEM; | 431 | err = -ENOMEM; |
433 | } else { | 432 | } else { |
@@ -449,7 +448,7 @@ static int scsiback_gnttab_data_map_list(struct vscsibk_pend *pending_req, | |||
449 | for (i = 0; i < cnt; i++) { | 448 | for (i = 0; i < cnt; i++) { |
450 | if (get_free_page(pg + mapcount)) { | 449 | if (get_free_page(pg + mapcount)) { |
451 | put_free_pages(pg, mapcount); | 450 | put_free_pages(pg, mapcount); |
452 | pr_err("xen-pvscsi: no grant page\n"); | 451 | pr_err("no grant page\n"); |
453 | return -ENOMEM; | 452 | return -ENOMEM; |
454 | } | 453 | } |
455 | gnttab_set_map_op(&map[mapcount], vaddr_page(pg[mapcount]), | 454 | gnttab_set_map_op(&map[mapcount], vaddr_page(pg[mapcount]), |
@@ -492,7 +491,7 @@ static int scsiback_gnttab_data_map(struct vscsiif_request *ring_req, | |||
492 | return 0; | 491 | return 0; |
493 | 492 | ||
494 | if (nr_segments > VSCSIIF_SG_TABLESIZE) { | 493 | if (nr_segments > VSCSIIF_SG_TABLESIZE) { |
495 | DPRINTK("xen-pvscsi: invalid parameter nr_seg = %d\n", | 494 | pr_debug("invalid parameter nr_seg = %d\n", |
496 | ring_req->nr_segments); | 495 | ring_req->nr_segments); |
497 | return -EINVAL; | 496 | return -EINVAL; |
498 | } | 497 | } |
@@ -516,13 +515,12 @@ static int scsiback_gnttab_data_map(struct vscsiif_request *ring_req, | |||
516 | nr_segments += n_segs; | 515 | nr_segments += n_segs; |
517 | } | 516 | } |
518 | if (nr_segments > SG_ALL) { | 517 | if (nr_segments > SG_ALL) { |
519 | DPRINTK("xen-pvscsi: invalid nr_seg = %d\n", | 518 | pr_debug("invalid nr_seg = %d\n", nr_segments); |
520 | nr_segments); | ||
521 | return -EINVAL; | 519 | return -EINVAL; |
522 | } | 520 | } |
523 | } | 521 | } |
524 | 522 | ||
525 | /* free of (sgl) in fast_flush_area()*/ | 523 | /* free of (sgl) in fast_flush_area() */ |
526 | pending_req->sgl = kmalloc_array(nr_segments, | 524 | pending_req->sgl = kmalloc_array(nr_segments, |
527 | sizeof(struct scatterlist), GFP_KERNEL); | 525 | sizeof(struct scatterlist), GFP_KERNEL); |
528 | if (!pending_req->sgl) | 526 | if (!pending_req->sgl) |
@@ -679,7 +677,8 @@ static int prepare_pending_reqs(struct vscsibk_info *info, | |||
679 | v2p = scsiback_do_translation(info, &vir); | 677 | v2p = scsiback_do_translation(info, &vir); |
680 | if (!v2p) { | 678 | if (!v2p) { |
681 | pending_req->v2p = NULL; | 679 | pending_req->v2p = NULL; |
682 | DPRINTK("xen-pvscsi: doesn't exist.\n"); | 680 | pr_debug("the v2p of (chn:%d, tgt:%d, lun:%d) doesn't exist.\n", |
681 | vir.chn, vir.tgt, vir.lun); | ||
683 | return -ENODEV; | 682 | return -ENODEV; |
684 | } | 683 | } |
685 | pending_req->v2p = v2p; | 684 | pending_req->v2p = v2p; |
@@ -690,14 +689,14 @@ static int prepare_pending_reqs(struct vscsibk_info *info, | |||
690 | (pending_req->sc_data_direction != DMA_TO_DEVICE) && | 689 | (pending_req->sc_data_direction != DMA_TO_DEVICE) && |
691 | (pending_req->sc_data_direction != DMA_FROM_DEVICE) && | 690 | (pending_req->sc_data_direction != DMA_FROM_DEVICE) && |
692 | (pending_req->sc_data_direction != DMA_NONE)) { | 691 | (pending_req->sc_data_direction != DMA_NONE)) { |
693 | DPRINTK("xen-pvscsi: invalid parameter data_dir = %d\n", | 692 | pr_debug("invalid parameter data_dir = %d\n", |
694 | pending_req->sc_data_direction); | 693 | pending_req->sc_data_direction); |
695 | return -EINVAL; | 694 | return -EINVAL; |
696 | } | 695 | } |
697 | 696 | ||
698 | pending_req->cmd_len = ring_req->cmd_len; | 697 | pending_req->cmd_len = ring_req->cmd_len; |
699 | if (pending_req->cmd_len > VSCSIIF_MAX_COMMAND_SIZE) { | 698 | if (pending_req->cmd_len > VSCSIIF_MAX_COMMAND_SIZE) { |
700 | DPRINTK("xen-pvscsi: invalid parameter cmd_len = %d\n", | 699 | pr_debug("invalid parameter cmd_len = %d\n", |
701 | pending_req->cmd_len); | 700 | pending_req->cmd_len); |
702 | return -EINVAL; | 701 | return -EINVAL; |
703 | } | 702 | } |
@@ -721,7 +720,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info) | |||
721 | 720 | ||
722 | if (RING_REQUEST_PROD_OVERFLOW(ring, rp)) { | 721 | if (RING_REQUEST_PROD_OVERFLOW(ring, rp)) { |
723 | rc = ring->rsp_prod_pvt; | 722 | rc = ring->rsp_prod_pvt; |
724 | pr_warn("xen-pvscsi: Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n", | 723 | pr_warn("Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n", |
725 | info->domid, rp, rc, rp - rc); | 724 | info->domid, rp, rc, rp - rc); |
726 | info->ring_error = 1; | 725 | info->ring_error = 1; |
727 | return 0; | 726 | return 0; |
@@ -772,7 +771,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info) | |||
772 | scsiback_device_action(pending_req, TMR_LUN_RESET, 0); | 771 | scsiback_device_action(pending_req, TMR_LUN_RESET, 0); |
773 | break; | 772 | break; |
774 | default: | 773 | default: |
775 | pr_err_ratelimited("xen-pvscsi: invalid request\n"); | 774 | pr_err_ratelimited("invalid request\n"); |
776 | scsiback_do_resp_with_sense(NULL, DRIVER_ERROR << 24, | 775 | scsiback_do_resp_with_sense(NULL, DRIVER_ERROR << 24, |
777 | 0, pending_req); | 776 | 0, pending_req); |
778 | kmem_cache_free(scsiback_cachep, pending_req); | 777 | kmem_cache_free(scsiback_cachep, pending_req); |
@@ -810,7 +809,7 @@ static int scsiback_init_sring(struct vscsibk_info *info, grant_ref_t ring_ref, | |||
810 | if (info->irq) | 809 | if (info->irq) |
811 | return -1; | 810 | return -1; |
812 | 811 | ||
813 | err = xenbus_map_ring_valloc(info->dev, ring_ref, &area); | 812 | err = xenbus_map_ring_valloc(info->dev, &ring_ref, 1, &area); |
814 | if (err) | 813 | if (err) |
815 | return err; | 814 | return err; |
816 | 815 | ||
@@ -874,14 +873,13 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, | |||
874 | 873 | ||
875 | lunp = strrchr(phy, ':'); | 874 | lunp = strrchr(phy, ':'); |
876 | if (!lunp) { | 875 | if (!lunp) { |
877 | pr_err("xen-pvscsi: illegal format of physical device %s\n", | 876 | pr_err("illegal format of physical device %s\n", phy); |
878 | phy); | ||
879 | return -EINVAL; | 877 | return -EINVAL; |
880 | } | 878 | } |
881 | *lunp = 0; | 879 | *lunp = 0; |
882 | lunp++; | 880 | lunp++; |
883 | if (kstrtouint(lunp, 10, &lun) || lun >= TRANSPORT_MAX_LUNS_PER_TPG) { | 881 | if (kstrtouint(lunp, 10, &lun) || lun >= TRANSPORT_MAX_LUNS_PER_TPG) { |
884 | pr_err("xen-pvscsi: lun number not valid: %s\n", lunp); | 882 | pr_err("lun number not valid: %s\n", lunp); |
885 | return -EINVAL; | 883 | return -EINVAL; |
886 | } | 884 | } |
887 | 885 | ||
@@ -909,7 +907,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, | |||
909 | mutex_unlock(&scsiback_mutex); | 907 | mutex_unlock(&scsiback_mutex); |
910 | 908 | ||
911 | if (!tpg) { | 909 | if (!tpg) { |
912 | pr_err("xen-pvscsi: %s:%d %s\n", phy, lun, error); | 910 | pr_err("%s:%d %s\n", phy, lun, error); |
913 | return -ENODEV; | 911 | return -ENODEV; |
914 | } | 912 | } |
915 | 913 | ||
@@ -926,7 +924,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, | |||
926 | if ((entry->v.chn == v->chn) && | 924 | if ((entry->v.chn == v->chn) && |
927 | (entry->v.tgt == v->tgt) && | 925 | (entry->v.tgt == v->tgt) && |
928 | (entry->v.lun == v->lun)) { | 926 | (entry->v.lun == v->lun)) { |
929 | pr_warn("xen-pvscsi: Virtual ID is already used. Assignment was not performed.\n"); | 927 | pr_warn("Virtual ID is already used. Assignment was not performed.\n"); |
930 | err = -EEXIST; | 928 | err = -EEXIST; |
931 | goto out; | 929 | goto out; |
932 | } | 930 | } |
@@ -992,15 +990,15 @@ found: | |||
992 | } | 990 | } |
993 | 991 | ||
994 | static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state, | 992 | static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state, |
995 | char *phy, struct ids_tuple *vir) | 993 | char *phy, struct ids_tuple *vir, int try) |
996 | { | 994 | { |
997 | if (!scsiback_add_translation_entry(info, phy, vir)) { | 995 | if (!scsiback_add_translation_entry(info, phy, vir)) { |
998 | if (xenbus_printf(XBT_NIL, info->dev->nodename, state, | 996 | if (xenbus_printf(XBT_NIL, info->dev->nodename, state, |
999 | "%d", XenbusStateInitialised)) { | 997 | "%d", XenbusStateInitialised)) { |
1000 | pr_err("xen-pvscsi: xenbus_printf error %s\n", state); | 998 | pr_err("xenbus_printf error %s\n", state); |
1001 | scsiback_del_translation_entry(info, vir); | 999 | scsiback_del_translation_entry(info, vir); |
1002 | } | 1000 | } |
1003 | } else { | 1001 | } else if (!try) { |
1004 | xenbus_printf(XBT_NIL, info->dev->nodename, state, | 1002 | xenbus_printf(XBT_NIL, info->dev->nodename, state, |
1005 | "%d", XenbusStateClosed); | 1003 | "%d", XenbusStateClosed); |
1006 | } | 1004 | } |
@@ -1012,7 +1010,7 @@ static void scsiback_do_del_lun(struct vscsibk_info *info, const char *state, | |||
1012 | if (!scsiback_del_translation_entry(info, vir)) { | 1010 | if (!scsiback_del_translation_entry(info, vir)) { |
1013 | if (xenbus_printf(XBT_NIL, info->dev->nodename, state, | 1011 | if (xenbus_printf(XBT_NIL, info->dev->nodename, state, |
1014 | "%d", XenbusStateClosed)) | 1012 | "%d", XenbusStateClosed)) |
1015 | pr_err("xen-pvscsi: xenbus_printf error %s\n", state); | 1013 | pr_err("xenbus_printf error %s\n", state); |
1016 | } | 1014 | } |
1017 | } | 1015 | } |
1018 | 1016 | ||
@@ -1060,10 +1058,19 @@ static void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op, | |||
1060 | 1058 | ||
1061 | switch (op) { | 1059 | switch (op) { |
1062 | case VSCSIBACK_OP_ADD_OR_DEL_LUN: | 1060 | case VSCSIBACK_OP_ADD_OR_DEL_LUN: |
1063 | if (device_state == XenbusStateInitialising) | 1061 | switch (device_state) { |
1064 | scsiback_do_add_lun(info, state, phy, &vir); | 1062 | case XenbusStateInitialising: |
1065 | if (device_state == XenbusStateClosing) | 1063 | scsiback_do_add_lun(info, state, phy, &vir, 0); |
1064 | break; | ||
1065 | case XenbusStateConnected: | ||
1066 | scsiback_do_add_lun(info, state, phy, &vir, 1); | ||
1067 | break; | ||
1068 | case XenbusStateClosing: | ||
1066 | scsiback_do_del_lun(info, state, &vir); | 1069 | scsiback_do_del_lun(info, state, &vir); |
1070 | break; | ||
1071 | default: | ||
1072 | break; | ||
1073 | } | ||
1067 | break; | 1074 | break; |
1068 | 1075 | ||
1069 | case VSCSIBACK_OP_UPDATEDEV_STATE: | 1076 | case VSCSIBACK_OP_UPDATEDEV_STATE: |
@@ -1071,15 +1078,14 @@ static void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op, | |||
1071 | /* modify vscsi-devs/dev-x/state */ | 1078 | /* modify vscsi-devs/dev-x/state */ |
1072 | if (xenbus_printf(XBT_NIL, dev->nodename, state, | 1079 | if (xenbus_printf(XBT_NIL, dev->nodename, state, |
1073 | "%d", XenbusStateConnected)) { | 1080 | "%d", XenbusStateConnected)) { |
1074 | pr_err("xen-pvscsi: xenbus_printf error %s\n", | 1081 | pr_err("xenbus_printf error %s\n", str); |
1075 | str); | ||
1076 | scsiback_del_translation_entry(info, &vir); | 1082 | scsiback_del_translation_entry(info, &vir); |
1077 | xenbus_printf(XBT_NIL, dev->nodename, state, | 1083 | xenbus_printf(XBT_NIL, dev->nodename, state, |
1078 | "%d", XenbusStateClosed); | 1084 | "%d", XenbusStateClosed); |
1079 | } | 1085 | } |
1080 | } | 1086 | } |
1081 | break; | 1087 | break; |
1082 | /*When it is necessary, processing is added here.*/ | 1088 | /* When it is necessary, processing is added here. */ |
1083 | default: | 1089 | default: |
1084 | break; | 1090 | break; |
1085 | } | 1091 | } |
@@ -1196,7 +1202,7 @@ static int scsiback_probe(struct xenbus_device *dev, | |||
1196 | struct vscsibk_info *info = kzalloc(sizeof(struct vscsibk_info), | 1202 | struct vscsibk_info *info = kzalloc(sizeof(struct vscsibk_info), |
1197 | GFP_KERNEL); | 1203 | GFP_KERNEL); |
1198 | 1204 | ||
1199 | DPRINTK("%p %d\n", dev, dev->otherend_id); | 1205 | pr_debug("%s %p %d\n", __func__, dev, dev->otherend_id); |
1200 | 1206 | ||
1201 | if (!info) { | 1207 | if (!info) { |
1202 | xenbus_dev_fatal(dev, -ENOMEM, "allocating backend structure"); | 1208 | xenbus_dev_fatal(dev, -ENOMEM, "allocating backend structure"); |
@@ -1227,7 +1233,7 @@ static int scsiback_probe(struct xenbus_device *dev, | |||
1227 | return 0; | 1233 | return 0; |
1228 | 1234 | ||
1229 | fail: | 1235 | fail: |
1230 | pr_warn("xen-pvscsi: %s failed\n", __func__); | 1236 | pr_warn("%s failed\n", __func__); |
1231 | scsiback_remove(dev); | 1237 | scsiback_remove(dev); |
1232 | 1238 | ||
1233 | return err; | 1239 | return err; |
@@ -1432,7 +1438,7 @@ check_len: | |||
1432 | } | 1438 | } |
1433 | snprintf(&tport->tport_name[0], VSCSI_NAMELEN, "%s", &name[off]); | 1439 | snprintf(&tport->tport_name[0], VSCSI_NAMELEN, "%s", &name[off]); |
1434 | 1440 | ||
1435 | pr_debug("xen-pvscsi: Allocated emulated Target %s Address: %s\n", | 1441 | pr_debug("Allocated emulated Target %s Address: %s\n", |
1436 | scsiback_dump_proto_id(tport), name); | 1442 | scsiback_dump_proto_id(tport), name); |
1437 | 1443 | ||
1438 | return &tport->tport_wwn; | 1444 | return &tport->tport_wwn; |
@@ -1443,7 +1449,7 @@ static void scsiback_drop_tport(struct se_wwn *wwn) | |||
1443 | struct scsiback_tport *tport = container_of(wwn, | 1449 | struct scsiback_tport *tport = container_of(wwn, |
1444 | struct scsiback_tport, tport_wwn); | 1450 | struct scsiback_tport, tport_wwn); |
1445 | 1451 | ||
1446 | pr_debug("xen-pvscsi: Deallocating emulated Target %s Address: %s\n", | 1452 | pr_debug("Deallocating emulated Target %s Address: %s\n", |
1447 | scsiback_dump_proto_id(tport), tport->tport_name); | 1453 | scsiback_dump_proto_id(tport), tport->tport_name); |
1448 | 1454 | ||
1449 | kfree(tport); | 1455 | kfree(tport); |
@@ -1470,8 +1476,8 @@ static u32 scsiback_tpg_get_inst_index(struct se_portal_group *se_tpg) | |||
1470 | static int scsiback_check_stop_free(struct se_cmd *se_cmd) | 1476 | static int scsiback_check_stop_free(struct se_cmd *se_cmd) |
1471 | { | 1477 | { |
1472 | /* | 1478 | /* |
1473 | * Do not release struct se_cmd's containing a valid TMR | 1479 | * Do not release struct se_cmd's containing a valid TMR pointer. |
1474 | * pointer. These will be released directly in scsiback_device_action() | 1480 | * These will be released directly in scsiback_device_action() |
1475 | * with transport_generic_free_cmd(). | 1481 | * with transport_generic_free_cmd(). |
1476 | */ | 1482 | */ |
1477 | if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) | 1483 | if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) |
@@ -1637,7 +1643,7 @@ static int scsiback_make_nexus(struct scsiback_tpg *tpg, | |||
1637 | return -ENOMEM; | 1643 | return -ENOMEM; |
1638 | } | 1644 | } |
1639 | /* | 1645 | /* |
1640 | * Initialize the struct se_session pointer | 1646 | * Initialize the struct se_session pointer |
1641 | */ | 1647 | */ |
1642 | tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL); | 1648 | tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL); |
1643 | if (IS_ERR(tv_nexus->tvn_se_sess)) { | 1649 | if (IS_ERR(tv_nexus->tvn_se_sess)) { |
@@ -1705,7 +1711,7 @@ static int scsiback_drop_nexus(struct scsiback_tpg *tpg) | |||
1705 | return -EBUSY; | 1711 | return -EBUSY; |
1706 | } | 1712 | } |
1707 | 1713 | ||
1708 | pr_debug("xen-pvscsi: Removing I_T Nexus to emulated %s Initiator Port: %s\n", | 1714 | pr_debug("Removing I_T Nexus to emulated %s Initiator Port: %s\n", |
1709 | scsiback_dump_proto_id(tpg->tport), | 1715 | scsiback_dump_proto_id(tpg->tport), |
1710 | tv_nexus->tvn_se_sess->se_node_acl->initiatorname); | 1716 | tv_nexus->tvn_se_sess->se_node_acl->initiatorname); |
1711 | 1717 | ||
@@ -1751,7 +1757,7 @@ static ssize_t scsiback_tpg_store_nexus(struct se_portal_group *se_tpg, | |||
1751 | unsigned char i_port[VSCSI_NAMELEN], *ptr, *port_ptr; | 1757 | unsigned char i_port[VSCSI_NAMELEN], *ptr, *port_ptr; |
1752 | int ret; | 1758 | int ret; |
1753 | /* | 1759 | /* |
1754 | * Shutdown the active I_T nexus if 'NULL' is passed.. | 1760 | * Shutdown the active I_T nexus if 'NULL' is passed. |
1755 | */ | 1761 | */ |
1756 | if (!strncmp(page, "NULL", 4)) { | 1762 | if (!strncmp(page, "NULL", 4)) { |
1757 | ret = scsiback_drop_nexus(tpg); | 1763 | ret = scsiback_drop_nexus(tpg); |
@@ -1922,7 +1928,7 @@ static void scsiback_drop_tpg(struct se_portal_group *se_tpg) | |||
1922 | */ | 1928 | */ |
1923 | scsiback_drop_nexus(tpg); | 1929 | scsiback_drop_nexus(tpg); |
1924 | /* | 1930 | /* |
1925 | * Deregister the se_tpg from TCM.. | 1931 | * Deregister the se_tpg from TCM. |
1926 | */ | 1932 | */ |
1927 | core_tpg_deregister(se_tpg); | 1933 | core_tpg_deregister(se_tpg); |
1928 | kfree(tpg); | 1934 | kfree(tpg); |
@@ -1992,7 +1998,7 @@ static int scsiback_register_configfs(void) | |||
1992 | struct target_fabric_configfs *fabric; | 1998 | struct target_fabric_configfs *fabric; |
1993 | int ret; | 1999 | int ret; |
1994 | 2000 | ||
1995 | pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n", | 2001 | pr_debug("fabric module %s on %s/%s on "UTS_RELEASE"\n", |
1996 | VSCSI_VERSION, utsname()->sysname, utsname()->machine); | 2002 | VSCSI_VERSION, utsname()->sysname, utsname()->machine); |
1997 | /* | 2003 | /* |
1998 | * Register the top level struct config_item_type with TCM core | 2004 | * Register the top level struct config_item_type with TCM core |
@@ -2029,7 +2035,7 @@ static int scsiback_register_configfs(void) | |||
2029 | * Setup our local pointer to *fabric | 2035 | * Setup our local pointer to *fabric |
2030 | */ | 2036 | */ |
2031 | scsiback_fabric_configfs = fabric; | 2037 | scsiback_fabric_configfs = fabric; |
2032 | pr_debug("xen-pvscsi: Set fabric -> scsiback_fabric_configfs\n"); | 2038 | pr_debug("Set fabric -> scsiback_fabric_configfs\n"); |
2033 | return 0; | 2039 | return 0; |
2034 | }; | 2040 | }; |
2035 | 2041 | ||
@@ -2040,7 +2046,7 @@ static void scsiback_deregister_configfs(void) | |||
2040 | 2046 | ||
2041 | target_fabric_configfs_deregister(scsiback_fabric_configfs); | 2047 | target_fabric_configfs_deregister(scsiback_fabric_configfs); |
2042 | scsiback_fabric_configfs = NULL; | 2048 | scsiback_fabric_configfs = NULL; |
2043 | pr_debug("xen-pvscsi: Cleared scsiback_fabric_configfs\n"); | 2049 | pr_debug("Cleared scsiback_fabric_configfs\n"); |
2044 | }; | 2050 | }; |
2045 | 2051 | ||
2046 | static const struct xenbus_device_id scsiback_ids[] = { | 2052 | static const struct xenbus_device_id scsiback_ids[] = { |
@@ -2091,7 +2097,7 @@ out_unregister_xenbus: | |||
2091 | xenbus_unregister_driver(&scsiback_driver); | 2097 | xenbus_unregister_driver(&scsiback_driver); |
2092 | out_cache_destroy: | 2098 | out_cache_destroy: |
2093 | kmem_cache_destroy(scsiback_cachep); | 2099 | kmem_cache_destroy(scsiback_cachep); |
2094 | pr_err("xen-pvscsi: %s: error %d\n", __func__, ret); | 2100 | pr_err("%s: error %d\n", __func__, ret); |
2095 | return ret; | 2101 | return ret; |
2096 | } | 2102 | } |
2097 | 2103 | ||
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index ca744102b666..96b2011d25f3 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c | |||
@@ -52,17 +52,25 @@ | |||
52 | struct xenbus_map_node { | 52 | struct xenbus_map_node { |
53 | struct list_head next; | 53 | struct list_head next; |
54 | union { | 54 | union { |
55 | struct vm_struct *area; /* PV */ | 55 | struct { |
56 | struct page *page; /* HVM */ | 56 | struct vm_struct *area; |
57 | } pv; | ||
58 | struct { | ||
59 | struct page *pages[XENBUS_MAX_RING_PAGES]; | ||
60 | void *addr; | ||
61 | } hvm; | ||
57 | }; | 62 | }; |
58 | grant_handle_t handle; | 63 | grant_handle_t handles[XENBUS_MAX_RING_PAGES]; |
64 | unsigned int nr_handles; | ||
59 | }; | 65 | }; |
60 | 66 | ||
61 | static DEFINE_SPINLOCK(xenbus_valloc_lock); | 67 | static DEFINE_SPINLOCK(xenbus_valloc_lock); |
62 | static LIST_HEAD(xenbus_valloc_pages); | 68 | static LIST_HEAD(xenbus_valloc_pages); |
63 | 69 | ||
64 | struct xenbus_ring_ops { | 70 | struct xenbus_ring_ops { |
65 | int (*map)(struct xenbus_device *dev, int gnt, void **vaddr); | 71 | int (*map)(struct xenbus_device *dev, |
72 | grant_ref_t *gnt_refs, unsigned int nr_grefs, | ||
73 | void **vaddr); | ||
66 | int (*unmap)(struct xenbus_device *dev, void *vaddr); | 74 | int (*unmap)(struct xenbus_device *dev, void *vaddr); |
67 | }; | 75 | }; |
68 | 76 | ||
@@ -355,17 +363,39 @@ static void xenbus_switch_fatal(struct xenbus_device *dev, int depth, int err, | |||
355 | /** | 363 | /** |
356 | * xenbus_grant_ring | 364 | * xenbus_grant_ring |
357 | * @dev: xenbus device | 365 | * @dev: xenbus device |
358 | * @ring_mfn: mfn of ring to grant | 366 | * @vaddr: starting virtual address of the ring |
359 | 367 | * @nr_pages: number of pages to be granted | |
360 | * Grant access to the given @ring_mfn to the peer of the given device. Return | 368 | * @grefs: grant reference array to be filled in |
361 | * a grant reference on success, or -errno on error. On error, the device will | 369 | * |
362 | * switch to XenbusStateClosing, and the error will be saved in the store. | 370 | * Grant access to the given @vaddr to the peer of the given device. |
371 | * Then fill in @grefs with grant references. Return 0 on success, or | ||
372 | * -errno on error. On error, the device will switch to | ||
373 | * XenbusStateClosing, and the error will be saved in the store. | ||
363 | */ | 374 | */ |
364 | int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn) | 375 | int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr, |
376 | unsigned int nr_pages, grant_ref_t *grefs) | ||
365 | { | 377 | { |
366 | int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0); | 378 | int err; |
367 | if (err < 0) | 379 | int i, j; |
368 | xenbus_dev_fatal(dev, err, "granting access to ring page"); | 380 | |
381 | for (i = 0; i < nr_pages; i++) { | ||
382 | unsigned long addr = (unsigned long)vaddr + | ||
383 | (PAGE_SIZE * i); | ||
384 | err = gnttab_grant_foreign_access(dev->otherend_id, | ||
385 | virt_to_mfn(addr), 0); | ||
386 | if (err < 0) { | ||
387 | xenbus_dev_fatal(dev, err, | ||
388 | "granting access to ring page"); | ||
389 | goto fail; | ||
390 | } | ||
391 | grefs[i] = err; | ||
392 | } | ||
393 | |||
394 | return 0; | ||
395 | |||
396 | fail: | ||
397 | for (j = 0; j < i; j++) | ||
398 | gnttab_end_foreign_access_ref(grefs[j], 0); | ||
369 | return err; | 399 | return err; |
370 | } | 400 | } |
371 | EXPORT_SYMBOL_GPL(xenbus_grant_ring); | 401 | EXPORT_SYMBOL_GPL(xenbus_grant_ring); |
@@ -419,62 +449,130 @@ EXPORT_SYMBOL_GPL(xenbus_free_evtchn); | |||
419 | /** | 449 | /** |
420 | * xenbus_map_ring_valloc | 450 | * xenbus_map_ring_valloc |
421 | * @dev: xenbus device | 451 | * @dev: xenbus device |
422 | * @gnt_ref: grant reference | 452 | * @gnt_refs: grant reference array |
453 | * @nr_grefs: number of grant references | ||
423 | * @vaddr: pointer to address to be filled out by mapping | 454 | * @vaddr: pointer to address to be filled out by mapping |
424 | * | 455 | * |
425 | * Based on Rusty Russell's skeleton driver's map_page. | 456 | * Map @nr_grefs pages of memory into this domain from another |
426 | * Map a page of memory into this domain from another domain's grant table. | 457 | * domain's grant table. xenbus_map_ring_valloc allocates @nr_grefs |
427 | * xenbus_map_ring_valloc allocates a page of virtual address space, maps the | 458 | * pages of virtual address space, maps the pages to that address, and |
428 | * page to that address, and sets *vaddr to that address. | 459 | * sets *vaddr to that address. Returns 0 on success, and GNTST_* |
429 | * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) | 460 | * (see xen/include/interface/grant_table.h) or -ENOMEM / -EINVAL on |
430 | * or -ENOMEM on error. If an error is returned, device will switch to | 461 | * error. If an error is returned, device will switch to |
431 | * XenbusStateClosing and the error message will be saved in XenStore. | 462 | * XenbusStateClosing and the error message will be saved in XenStore. |
432 | */ | 463 | */ |
433 | int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) | 464 | int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs, |
465 | unsigned int nr_grefs, void **vaddr) | ||
434 | { | 466 | { |
435 | return ring_ops->map(dev, gnt_ref, vaddr); | 467 | return ring_ops->map(dev, gnt_refs, nr_grefs, vaddr); |
436 | } | 468 | } |
437 | EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); | 469 | EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); |
438 | 470 | ||
471 | /* N.B. sizeof(phys_addr_t) doesn't always equal to sizeof(unsigned | ||
472 | * long), e.g. 32-on-64. Caller is responsible for preparing the | ||
473 | * right array to feed into this function */ | ||
474 | static int __xenbus_map_ring(struct xenbus_device *dev, | ||
475 | grant_ref_t *gnt_refs, | ||
476 | unsigned int nr_grefs, | ||
477 | grant_handle_t *handles, | ||
478 | phys_addr_t *addrs, | ||
479 | unsigned int flags, | ||
480 | bool *leaked) | ||
481 | { | ||
482 | struct gnttab_map_grant_ref map[XENBUS_MAX_RING_PAGES]; | ||
483 | struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_PAGES]; | ||
484 | int i, j; | ||
485 | int err = GNTST_okay; | ||
486 | |||
487 | if (nr_grefs > XENBUS_MAX_RING_PAGES) | ||
488 | return -EINVAL; | ||
489 | |||
490 | for (i = 0; i < nr_grefs; i++) { | ||
491 | memset(&map[i], 0, sizeof(map[i])); | ||
492 | gnttab_set_map_op(&map[i], addrs[i], flags, gnt_refs[i], | ||
493 | dev->otherend_id); | ||
494 | handles[i] = INVALID_GRANT_HANDLE; | ||
495 | } | ||
496 | |||
497 | gnttab_batch_map(map, i); | ||
498 | |||
499 | for (i = 0; i < nr_grefs; i++) { | ||
500 | if (map[i].status != GNTST_okay) { | ||
501 | err = map[i].status; | ||
502 | xenbus_dev_fatal(dev, map[i].status, | ||
503 | "mapping in shared page %d from domain %d", | ||
504 | gnt_refs[i], dev->otherend_id); | ||
505 | goto fail; | ||
506 | } else | ||
507 | handles[i] = map[i].handle; | ||
508 | } | ||
509 | |||
510 | return GNTST_okay; | ||
511 | |||
512 | fail: | ||
513 | for (i = j = 0; i < nr_grefs; i++) { | ||
514 | if (handles[i] != INVALID_GRANT_HANDLE) { | ||
515 | memset(&unmap[j], 0, sizeof(unmap[j])); | ||
516 | gnttab_set_unmap_op(&unmap[j], (phys_addr_t)addrs[i], | ||
517 | GNTMAP_host_map, handles[i]); | ||
518 | j++; | ||
519 | } | ||
520 | } | ||
521 | |||
522 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, j)) | ||
523 | BUG(); | ||
524 | |||
525 | *leaked = false; | ||
526 | for (i = 0; i < j; i++) { | ||
527 | if (unmap[i].status != GNTST_okay) { | ||
528 | *leaked = true; | ||
529 | break; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | return err; | ||
534 | } | ||
535 | |||
439 | static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev, | 536 | static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev, |
440 | int gnt_ref, void **vaddr) | 537 | grant_ref_t *gnt_refs, |
538 | unsigned int nr_grefs, | ||
539 | void **vaddr) | ||
441 | { | 540 | { |
442 | struct gnttab_map_grant_ref op = { | ||
443 | .flags = GNTMAP_host_map | GNTMAP_contains_pte, | ||
444 | .ref = gnt_ref, | ||
445 | .dom = dev->otherend_id, | ||
446 | }; | ||
447 | struct xenbus_map_node *node; | 541 | struct xenbus_map_node *node; |
448 | struct vm_struct *area; | 542 | struct vm_struct *area; |
449 | pte_t *pte; | 543 | pte_t *ptes[XENBUS_MAX_RING_PAGES]; |
544 | phys_addr_t phys_addrs[XENBUS_MAX_RING_PAGES]; | ||
545 | int err = GNTST_okay; | ||
546 | int i; | ||
547 | bool leaked; | ||
450 | 548 | ||
451 | *vaddr = NULL; | 549 | *vaddr = NULL; |
452 | 550 | ||
551 | if (nr_grefs > XENBUS_MAX_RING_PAGES) | ||
552 | return -EINVAL; | ||
553 | |||
453 | node = kzalloc(sizeof(*node), GFP_KERNEL); | 554 | node = kzalloc(sizeof(*node), GFP_KERNEL); |
454 | if (!node) | 555 | if (!node) |
455 | return -ENOMEM; | 556 | return -ENOMEM; |
456 | 557 | ||
457 | area = alloc_vm_area(PAGE_SIZE, &pte); | 558 | area = alloc_vm_area(PAGE_SIZE * nr_grefs, ptes); |
458 | if (!area) { | 559 | if (!area) { |
459 | kfree(node); | 560 | kfree(node); |
460 | return -ENOMEM; | 561 | return -ENOMEM; |
461 | } | 562 | } |
462 | 563 | ||
463 | op.host_addr = arbitrary_virt_to_machine(pte).maddr; | 564 | for (i = 0; i < nr_grefs; i++) |
565 | phys_addrs[i] = arbitrary_virt_to_machine(ptes[i]).maddr; | ||
464 | 566 | ||
465 | gnttab_batch_map(&op, 1); | 567 | err = __xenbus_map_ring(dev, gnt_refs, nr_grefs, node->handles, |
466 | 568 | phys_addrs, | |
467 | if (op.status != GNTST_okay) { | 569 | GNTMAP_host_map | GNTMAP_contains_pte, |
468 | free_vm_area(area); | 570 | &leaked); |
469 | kfree(node); | 571 | if (err) |
470 | xenbus_dev_fatal(dev, op.status, | 572 | goto failed; |
471 | "mapping in shared page %d from domain %d", | ||
472 | gnt_ref, dev->otherend_id); | ||
473 | return op.status; | ||
474 | } | ||
475 | 573 | ||
476 | node->handle = op.handle; | 574 | node->nr_handles = nr_grefs; |
477 | node->area = area; | 575 | node->pv.area = area; |
478 | 576 | ||
479 | spin_lock(&xenbus_valloc_lock); | 577 | spin_lock(&xenbus_valloc_lock); |
480 | list_add(&node->next, &xenbus_valloc_pages); | 578 | list_add(&node->next, &xenbus_valloc_pages); |
@@ -482,14 +580,33 @@ static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev, | |||
482 | 580 | ||
483 | *vaddr = area->addr; | 581 | *vaddr = area->addr; |
484 | return 0; | 582 | return 0; |
583 | |||
584 | failed: | ||
585 | if (!leaked) | ||
586 | free_vm_area(area); | ||
587 | else | ||
588 | pr_alert("leaking VM area %p size %u page(s)", area, nr_grefs); | ||
589 | |||
590 | kfree(node); | ||
591 | return err; | ||
485 | } | 592 | } |
486 | 593 | ||
487 | static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, | 594 | static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, |
488 | int gnt_ref, void **vaddr) | 595 | grant_ref_t *gnt_ref, |
596 | unsigned int nr_grefs, | ||
597 | void **vaddr) | ||
489 | { | 598 | { |
490 | struct xenbus_map_node *node; | 599 | struct xenbus_map_node *node; |
600 | int i; | ||
491 | int err; | 601 | int err; |
492 | void *addr; | 602 | void *addr; |
603 | bool leaked = false; | ||
604 | /* Why do we need two arrays? See comment of __xenbus_map_ring */ | ||
605 | phys_addr_t phys_addrs[XENBUS_MAX_RING_PAGES]; | ||
606 | unsigned long addrs[XENBUS_MAX_RING_PAGES]; | ||
607 | |||
608 | if (nr_grefs > XENBUS_MAX_RING_PAGES) | ||
609 | return -EINVAL; | ||
493 | 610 | ||
494 | *vaddr = NULL; | 611 | *vaddr = NULL; |
495 | 612 | ||
@@ -497,15 +614,32 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, | |||
497 | if (!node) | 614 | if (!node) |
498 | return -ENOMEM; | 615 | return -ENOMEM; |
499 | 616 | ||
500 | err = alloc_xenballooned_pages(1, &node->page, false /* lowmem */); | 617 | err = alloc_xenballooned_pages(nr_grefs, node->hvm.pages, |
618 | false /* lowmem */); | ||
501 | if (err) | 619 | if (err) |
502 | goto out_err; | 620 | goto out_err; |
503 | 621 | ||
504 | addr = pfn_to_kaddr(page_to_pfn(node->page)); | 622 | for (i = 0; i < nr_grefs; i++) { |
623 | unsigned long pfn = page_to_pfn(node->hvm.pages[i]); | ||
624 | phys_addrs[i] = (unsigned long)pfn_to_kaddr(pfn); | ||
625 | addrs[i] = (unsigned long)pfn_to_kaddr(pfn); | ||
626 | } | ||
627 | |||
628 | err = __xenbus_map_ring(dev, gnt_ref, nr_grefs, node->handles, | ||
629 | phys_addrs, GNTMAP_host_map, &leaked); | ||
630 | node->nr_handles = nr_grefs; | ||
505 | 631 | ||
506 | err = xenbus_map_ring(dev, gnt_ref, &node->handle, addr); | ||
507 | if (err) | 632 | if (err) |
508 | goto out_err_free_ballooned_pages; | 633 | goto out_free_ballooned_pages; |
634 | |||
635 | addr = vmap(node->hvm.pages, nr_grefs, VM_MAP | VM_IOREMAP, | ||
636 | PAGE_KERNEL); | ||
637 | if (!addr) { | ||
638 | err = -ENOMEM; | ||
639 | goto out_xenbus_unmap_ring; | ||
640 | } | ||
641 | |||
642 | node->hvm.addr = addr; | ||
509 | 643 | ||
510 | spin_lock(&xenbus_valloc_lock); | 644 | spin_lock(&xenbus_valloc_lock); |
511 | list_add(&node->next, &xenbus_valloc_pages); | 645 | list_add(&node->next, &xenbus_valloc_pages); |
@@ -514,8 +648,16 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, | |||
514 | *vaddr = addr; | 648 | *vaddr = addr; |
515 | return 0; | 649 | return 0; |
516 | 650 | ||
517 | out_err_free_ballooned_pages: | 651 | out_xenbus_unmap_ring: |
518 | free_xenballooned_pages(1, &node->page); | 652 | if (!leaked) |
653 | xenbus_unmap_ring(dev, node->handles, node->nr_handles, | ||
654 | addrs); | ||
655 | else | ||
656 | pr_alert("leaking %p size %u page(s)", | ||
657 | addr, nr_grefs); | ||
658 | out_free_ballooned_pages: | ||
659 | if (!leaked) | ||
660 | free_xenballooned_pages(nr_grefs, node->hvm.pages); | ||
519 | out_err: | 661 | out_err: |
520 | kfree(node); | 662 | kfree(node); |
521 | return err; | 663 | return err; |
@@ -525,35 +667,37 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, | |||
525 | /** | 667 | /** |
526 | * xenbus_map_ring | 668 | * xenbus_map_ring |
527 | * @dev: xenbus device | 669 | * @dev: xenbus device |
528 | * @gnt_ref: grant reference | 670 | * @gnt_refs: grant reference array |
529 | * @handle: pointer to grant handle to be filled | 671 | * @nr_grefs: number of grant reference |
530 | * @vaddr: address to be mapped to | 672 | * @handles: pointer to grant handle to be filled |
673 | * @vaddrs: addresses to be mapped to | ||
674 | * @leaked: fail to clean up a failed map, caller should not free vaddr | ||
531 | * | 675 | * |
532 | * Map a page of memory into this domain from another domain's grant table. | 676 | * Map pages of memory into this domain from another domain's grant table. |
533 | * xenbus_map_ring does not allocate the virtual address space (you must do | 677 | * xenbus_map_ring does not allocate the virtual address space (you must do |
534 | * this yourself!). It only maps in the page to the specified address. | 678 | * this yourself!). It only maps in the pages to the specified address. |
535 | * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) | 679 | * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) |
536 | * or -ENOMEM on error. If an error is returned, device will switch to | 680 | * or -ENOMEM / -EINVAL on error. If an error is returned, device will switch to |
537 | * XenbusStateClosing and the error message will be saved in XenStore. | 681 | * XenbusStateClosing and the first error message will be saved in XenStore. |
682 | * Further more if we fail to map the ring, caller should check @leaked. | ||
683 | * If @leaked is not zero it means xenbus_map_ring fails to clean up, caller | ||
684 | * should not free the address space of @vaddr. | ||
538 | */ | 685 | */ |
539 | int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, | 686 | int xenbus_map_ring(struct xenbus_device *dev, grant_ref_t *gnt_refs, |
540 | grant_handle_t *handle, void *vaddr) | 687 | unsigned int nr_grefs, grant_handle_t *handles, |
688 | unsigned long *vaddrs, bool *leaked) | ||
541 | { | 689 | { |
542 | struct gnttab_map_grant_ref op; | 690 | phys_addr_t phys_addrs[XENBUS_MAX_RING_PAGES]; |
543 | 691 | int i; | |
544 | gnttab_set_map_op(&op, (unsigned long)vaddr, GNTMAP_host_map, gnt_ref, | ||
545 | dev->otherend_id); | ||
546 | 692 | ||
547 | gnttab_batch_map(&op, 1); | 693 | if (nr_grefs > XENBUS_MAX_RING_PAGES) |
694 | return -EINVAL; | ||
548 | 695 | ||
549 | if (op.status != GNTST_okay) { | 696 | for (i = 0; i < nr_grefs; i++) |
550 | xenbus_dev_fatal(dev, op.status, | 697 | phys_addrs[i] = (unsigned long)vaddrs[i]; |
551 | "mapping in shared page %d from domain %d", | ||
552 | gnt_ref, dev->otherend_id); | ||
553 | } else | ||
554 | *handle = op.handle; | ||
555 | 698 | ||
556 | return op.status; | 699 | return __xenbus_map_ring(dev, gnt_refs, nr_grefs, handles, |
700 | phys_addrs, GNTMAP_host_map, leaked); | ||
557 | } | 701 | } |
558 | EXPORT_SYMBOL_GPL(xenbus_map_ring); | 702 | EXPORT_SYMBOL_GPL(xenbus_map_ring); |
559 | 703 | ||
@@ -579,14 +723,15 @@ EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); | |||
579 | static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) | 723 | static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) |
580 | { | 724 | { |
581 | struct xenbus_map_node *node; | 725 | struct xenbus_map_node *node; |
582 | struct gnttab_unmap_grant_ref op = { | 726 | struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_PAGES]; |
583 | .host_addr = (unsigned long)vaddr, | ||
584 | }; | ||
585 | unsigned int level; | 727 | unsigned int level; |
728 | int i; | ||
729 | bool leaked = false; | ||
730 | int err; | ||
586 | 731 | ||
587 | spin_lock(&xenbus_valloc_lock); | 732 | spin_lock(&xenbus_valloc_lock); |
588 | list_for_each_entry(node, &xenbus_valloc_pages, next) { | 733 | list_for_each_entry(node, &xenbus_valloc_pages, next) { |
589 | if (node->area->addr == vaddr) { | 734 | if (node->pv.area->addr == vaddr) { |
590 | list_del(&node->next); | 735 | list_del(&node->next); |
591 | goto found; | 736 | goto found; |
592 | } | 737 | } |
@@ -601,22 +746,41 @@ static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) | |||
601 | return GNTST_bad_virt_addr; | 746 | return GNTST_bad_virt_addr; |
602 | } | 747 | } |
603 | 748 | ||
604 | op.handle = node->handle; | 749 | for (i = 0; i < node->nr_handles; i++) { |
605 | op.host_addr = arbitrary_virt_to_machine( | 750 | unsigned long addr; |
606 | lookup_address((unsigned long)vaddr, &level)).maddr; | 751 | |
752 | memset(&unmap[i], 0, sizeof(unmap[i])); | ||
753 | addr = (unsigned long)vaddr + (PAGE_SIZE * i); | ||
754 | unmap[i].host_addr = arbitrary_virt_to_machine( | ||
755 | lookup_address(addr, &level)).maddr; | ||
756 | unmap[i].dev_bus_addr = 0; | ||
757 | unmap[i].handle = node->handles[i]; | ||
758 | } | ||
607 | 759 | ||
608 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) | 760 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, i)) |
609 | BUG(); | 761 | BUG(); |
610 | 762 | ||
611 | if (op.status == GNTST_okay) | 763 | err = GNTST_okay; |
612 | free_vm_area(node->area); | 764 | leaked = false; |
765 | for (i = 0; i < node->nr_handles; i++) { | ||
766 | if (unmap[i].status != GNTST_okay) { | ||
767 | leaked = true; | ||
768 | xenbus_dev_error(dev, unmap[i].status, | ||
769 | "unmapping page at handle %d error %d", | ||
770 | node->handles[i], unmap[i].status); | ||
771 | err = unmap[i].status; | ||
772 | break; | ||
773 | } | ||
774 | } | ||
775 | |||
776 | if (!leaked) | ||
777 | free_vm_area(node->pv.area); | ||
613 | else | 778 | else |
614 | xenbus_dev_error(dev, op.status, | 779 | pr_alert("leaking VM area %p size %u page(s)", |
615 | "unmapping page at handle %d error %d", | 780 | node->pv.area, node->nr_handles); |
616 | node->handle, op.status); | ||
617 | 781 | ||
618 | kfree(node); | 782 | kfree(node); |
619 | return op.status; | 783 | return err; |
620 | } | 784 | } |
621 | 785 | ||
622 | static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) | 786 | static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) |
@@ -624,10 +788,12 @@ static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) | |||
624 | int rv; | 788 | int rv; |
625 | struct xenbus_map_node *node; | 789 | struct xenbus_map_node *node; |
626 | void *addr; | 790 | void *addr; |
791 | unsigned long addrs[XENBUS_MAX_RING_PAGES]; | ||
792 | int i; | ||
627 | 793 | ||
628 | spin_lock(&xenbus_valloc_lock); | 794 | spin_lock(&xenbus_valloc_lock); |
629 | list_for_each_entry(node, &xenbus_valloc_pages, next) { | 795 | list_for_each_entry(node, &xenbus_valloc_pages, next) { |
630 | addr = pfn_to_kaddr(page_to_pfn(node->page)); | 796 | addr = node->hvm.addr; |
631 | if (addr == vaddr) { | 797 | if (addr == vaddr) { |
632 | list_del(&node->next); | 798 | list_del(&node->next); |
633 | goto found; | 799 | goto found; |
@@ -643,12 +809,16 @@ static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) | |||
643 | return GNTST_bad_virt_addr; | 809 | return GNTST_bad_virt_addr; |
644 | } | 810 | } |
645 | 811 | ||
646 | rv = xenbus_unmap_ring(dev, node->handle, addr); | 812 | for (i = 0; i < node->nr_handles; i++) |
813 | addrs[i] = (unsigned long)pfn_to_kaddr(page_to_pfn(node->hvm.pages[i])); | ||
647 | 814 | ||
815 | rv = xenbus_unmap_ring(dev, node->handles, node->nr_handles, | ||
816 | addrs); | ||
648 | if (!rv) | 817 | if (!rv) |
649 | free_xenballooned_pages(1, &node->page); | 818 | vunmap(vaddr); |
650 | else | 819 | else |
651 | WARN(1, "Leaking %p\n", vaddr); | 820 | WARN(1, "Leaking %p, size %u page(s)\n", vaddr, |
821 | node->nr_handles); | ||
652 | 822 | ||
653 | kfree(node); | 823 | kfree(node); |
654 | return rv; | 824 | return rv; |
@@ -657,29 +827,44 @@ static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) | |||
657 | /** | 827 | /** |
658 | * xenbus_unmap_ring | 828 | * xenbus_unmap_ring |
659 | * @dev: xenbus device | 829 | * @dev: xenbus device |
660 | * @handle: grant handle | 830 | * @handles: grant handle array |
661 | * @vaddr: addr to unmap | 831 | * @nr_handles: number of handles in the array |
832 | * @vaddrs: addresses to unmap | ||
662 | * | 833 | * |
663 | * Unmap a page of memory in this domain that was imported from another domain. | 834 | * Unmap memory in this domain that was imported from another domain. |
664 | * Returns 0 on success and returns GNTST_* on error | 835 | * Returns 0 on success and returns GNTST_* on error |
665 | * (see xen/include/interface/grant_table.h). | 836 | * (see xen/include/interface/grant_table.h). |
666 | */ | 837 | */ |
667 | int xenbus_unmap_ring(struct xenbus_device *dev, | 838 | int xenbus_unmap_ring(struct xenbus_device *dev, |
668 | grant_handle_t handle, void *vaddr) | 839 | grant_handle_t *handles, unsigned int nr_handles, |
840 | unsigned long *vaddrs) | ||
669 | { | 841 | { |
670 | struct gnttab_unmap_grant_ref op; | 842 | struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_PAGES]; |
843 | int i; | ||
844 | int err; | ||
671 | 845 | ||
672 | gnttab_set_unmap_op(&op, (unsigned long)vaddr, GNTMAP_host_map, handle); | 846 | if (nr_handles > XENBUS_MAX_RING_PAGES) |
847 | return -EINVAL; | ||
673 | 848 | ||
674 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) | 849 | for (i = 0; i < nr_handles; i++) |
850 | gnttab_set_unmap_op(&unmap[i], vaddrs[i], | ||
851 | GNTMAP_host_map, handles[i]); | ||
852 | |||
853 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, i)) | ||
675 | BUG(); | 854 | BUG(); |
676 | 855 | ||
677 | if (op.status != GNTST_okay) | 856 | err = GNTST_okay; |
678 | xenbus_dev_error(dev, op.status, | 857 | for (i = 0; i < nr_handles; i++) { |
679 | "unmapping page at handle %d error %d", | 858 | if (unmap[i].status != GNTST_okay) { |
680 | handle, op.status); | 859 | xenbus_dev_error(dev, unmap[i].status, |
860 | "unmapping page at handle %d error %d", | ||
861 | handles[i], unmap[i].status); | ||
862 | err = unmap[i].status; | ||
863 | break; | ||
864 | } | ||
865 | } | ||
681 | 866 | ||
682 | return op.status; | 867 | return err; |
683 | } | 868 | } |
684 | EXPORT_SYMBOL_GPL(xenbus_unmap_ring); | 869 | EXPORT_SYMBOL_GPL(xenbus_unmap_ring); |
685 | 870 | ||
diff --git a/drivers/xen/xlate_mmu.c b/drivers/xen/xlate_mmu.c new file mode 100644 index 000000000000..58a5389aec89 --- /dev/null +++ b/drivers/xen/xlate_mmu.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * MMU operations common to all auto-translated physmap guests. | ||
3 | * | ||
4 | * Copyright (C) 2015 Citrix Systems R&D Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version 2 | ||
8 | * as published by the Free Software Foundation; or, when distributed | ||
9 | * separately from the Linux kernel or incorporated into other | ||
10 | * software packages, subject to the following license: | ||
11 | * | ||
12 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
13 | * of this source file (the "Software"), to deal in the Software without | ||
14 | * restriction, including without limitation the rights to use, copy, modify, | ||
15 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, | ||
16 | * and to permit persons to whom the Software is furnished to do so, subject to | ||
17 | * the following conditions: | ||
18 | * | ||
19 | * The above copyright notice and this permission notice shall be included in | ||
20 | * all copies or substantial portions of the Software. | ||
21 | * | ||
22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
27 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
28 | * IN THE SOFTWARE. | ||
29 | */ | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/mm.h> | ||
32 | |||
33 | #include <asm/xen/hypercall.h> | ||
34 | #include <asm/xen/hypervisor.h> | ||
35 | |||
36 | #include <xen/xen.h> | ||
37 | #include <xen/page.h> | ||
38 | #include <xen/interface/xen.h> | ||
39 | #include <xen/interface/memory.h> | ||
40 | |||
41 | /* map fgmfn of domid to lpfn in the current domain */ | ||
42 | static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn, | ||
43 | unsigned int domid) | ||
44 | { | ||
45 | int rc; | ||
46 | struct xen_add_to_physmap_range xatp = { | ||
47 | .domid = DOMID_SELF, | ||
48 | .foreign_domid = domid, | ||
49 | .size = 1, | ||
50 | .space = XENMAPSPACE_gmfn_foreign, | ||
51 | }; | ||
52 | xen_ulong_t idx = fgmfn; | ||
53 | xen_pfn_t gpfn = lpfn; | ||
54 | int err = 0; | ||
55 | |||
56 | set_xen_guest_handle(xatp.idxs, &idx); | ||
57 | set_xen_guest_handle(xatp.gpfns, &gpfn); | ||
58 | set_xen_guest_handle(xatp.errs, &err); | ||
59 | |||
60 | rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp); | ||
61 | return rc < 0 ? rc : err; | ||
62 | } | ||
63 | |||
64 | struct remap_data { | ||
65 | xen_pfn_t *fgmfn; /* foreign domain's gmfn */ | ||
66 | pgprot_t prot; | ||
67 | domid_t domid; | ||
68 | struct vm_area_struct *vma; | ||
69 | int index; | ||
70 | struct page **pages; | ||
71 | struct xen_remap_mfn_info *info; | ||
72 | int *err_ptr; | ||
73 | int mapped; | ||
74 | }; | ||
75 | |||
76 | static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, | ||
77 | void *data) | ||
78 | { | ||
79 | struct remap_data *info = data; | ||
80 | struct page *page = info->pages[info->index++]; | ||
81 | unsigned long pfn = page_to_pfn(page); | ||
82 | pte_t pte = pte_mkspecial(pfn_pte(pfn, info->prot)); | ||
83 | int rc; | ||
84 | |||
85 | rc = map_foreign_page(pfn, *info->fgmfn, info->domid); | ||
86 | *info->err_ptr++ = rc; | ||
87 | if (!rc) { | ||
88 | set_pte_at(info->vma->vm_mm, addr, ptep, pte); | ||
89 | info->mapped++; | ||
90 | } | ||
91 | info->fgmfn++; | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | int xen_xlate_remap_gfn_array(struct vm_area_struct *vma, | ||
97 | unsigned long addr, | ||
98 | xen_pfn_t *mfn, int nr, | ||
99 | int *err_ptr, pgprot_t prot, | ||
100 | unsigned domid, | ||
101 | struct page **pages) | ||
102 | { | ||
103 | int err; | ||
104 | struct remap_data data; | ||
105 | unsigned long range = nr << PAGE_SHIFT; | ||
106 | |||
107 | /* Kept here for the purpose of making sure code doesn't break | ||
108 | x86 PVOPS */ | ||
109 | BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); | ||
110 | |||
111 | data.fgmfn = mfn; | ||
112 | data.prot = prot; | ||
113 | data.domid = domid; | ||
114 | data.vma = vma; | ||
115 | data.pages = pages; | ||
116 | data.index = 0; | ||
117 | data.err_ptr = err_ptr; | ||
118 | data.mapped = 0; | ||
119 | |||
120 | err = apply_to_page_range(vma->vm_mm, addr, range, | ||
121 | remap_pte_fn, &data); | ||
122 | return err < 0 ? err : data.mapped; | ||
123 | } | ||
124 | EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_array); | ||
125 | |||
126 | int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma, | ||
127 | int nr, struct page **pages) | ||
128 | { | ||
129 | int i; | ||
130 | |||
131 | for (i = 0; i < nr; i++) { | ||
132 | struct xen_remove_from_physmap xrp; | ||
133 | unsigned long pfn; | ||
134 | |||
135 | pfn = page_to_pfn(pages[i]); | ||
136 | |||
137 | xrp.domid = DOMID_SELF; | ||
138 | xrp.gpfn = pfn; | ||
139 | (void)HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp); | ||
140 | } | ||
141 | return 0; | ||
142 | } | ||
143 | EXPORT_SYMBOL_GPL(xen_xlate_unmap_gfn_range); | ||
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h index f68719f405af..a48378958062 100644 --- a/include/xen/interface/xen.h +++ b/include/xen/interface/xen.h | |||
@@ -67,7 +67,7 @@ | |||
67 | #define __HYPERVISOR_vcpu_op 24 | 67 | #define __HYPERVISOR_vcpu_op 24 |
68 | #define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ | 68 | #define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ |
69 | #define __HYPERVISOR_mmuext_op 26 | 69 | #define __HYPERVISOR_mmuext_op 26 |
70 | #define __HYPERVISOR_acm_op 27 | 70 | #define __HYPERVISOR_xsm_op 27 |
71 | #define __HYPERVISOR_nmi_op 28 | 71 | #define __HYPERVISOR_nmi_op 28 |
72 | #define __HYPERVISOR_sched_op 29 | 72 | #define __HYPERVISOR_sched_op 29 |
73 | #define __HYPERVISOR_callback_op 30 | 73 | #define __HYPERVISOR_callback_op 30 |
@@ -75,7 +75,11 @@ | |||
75 | #define __HYPERVISOR_event_channel_op 32 | 75 | #define __HYPERVISOR_event_channel_op 32 |
76 | #define __HYPERVISOR_physdev_op 33 | 76 | #define __HYPERVISOR_physdev_op 33 |
77 | #define __HYPERVISOR_hvm_op 34 | 77 | #define __HYPERVISOR_hvm_op 34 |
78 | #define __HYPERVISOR_sysctl 35 | ||
79 | #define __HYPERVISOR_domctl 36 | ||
80 | #define __HYPERVISOR_kexec_op 37 | ||
78 | #define __HYPERVISOR_tmem_op 38 | 81 | #define __HYPERVISOR_tmem_op 38 |
82 | #define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */ | ||
79 | 83 | ||
80 | /* Architecture-specific hypercall definitions. */ | 84 | /* Architecture-specific hypercall definitions. */ |
81 | #define __HYPERVISOR_arch_0 48 | 85 | #define __HYPERVISOR_arch_0 48 |
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 83338210ee04..c643e6a94c9a 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h | |||
@@ -27,13 +27,58 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order, | |||
27 | void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order); | 27 | void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order); |
28 | 28 | ||
29 | struct vm_area_struct; | 29 | struct vm_area_struct; |
30 | |||
31 | /* | ||
32 | * xen_remap_domain_mfn_array() - map an array of foreign frames | ||
33 | * @vma: VMA to map the pages into | ||
34 | * @addr: Address at which to map the pages | ||
35 | * @gfn: Array of GFNs to map | ||
36 | * @nr: Number entries in the GFN array | ||
37 | * @err_ptr: Returns per-GFN error status. | ||
38 | * @prot: page protection mask | ||
39 | * @domid: Domain owning the pages | ||
40 | * @pages: Array of pages if this domain has an auto-translated physmap | ||
41 | * | ||
42 | * @gfn and @err_ptr may point to the same buffer, the GFNs will be | ||
43 | * overwritten by the error codes after they are mapped. | ||
44 | * | ||
45 | * Returns the number of successfully mapped frames, or a -ve error | ||
46 | * code. | ||
47 | */ | ||
48 | int xen_remap_domain_mfn_array(struct vm_area_struct *vma, | ||
49 | unsigned long addr, | ||
50 | xen_pfn_t *gfn, int nr, | ||
51 | int *err_ptr, pgprot_t prot, | ||
52 | unsigned domid, | ||
53 | struct page **pages); | ||
54 | |||
55 | /* xen_remap_domain_mfn_range() - map a range of foreign frames | ||
56 | * @vma: VMA to map the pages into | ||
57 | * @addr: Address at which to map the pages | ||
58 | * @gfn: First GFN to map. | ||
59 | * @nr: Number frames to map | ||
60 | * @prot: page protection mask | ||
61 | * @domid: Domain owning the pages | ||
62 | * @pages: Array of pages if this domain has an auto-translated physmap | ||
63 | * | ||
64 | * Returns the number of successfully mapped frames, or a -ve error | ||
65 | * code. | ||
66 | */ | ||
30 | int xen_remap_domain_mfn_range(struct vm_area_struct *vma, | 67 | int xen_remap_domain_mfn_range(struct vm_area_struct *vma, |
31 | unsigned long addr, | 68 | unsigned long addr, |
32 | xen_pfn_t mfn, int nr, | 69 | xen_pfn_t gfn, int nr, |
33 | pgprot_t prot, unsigned domid, | 70 | pgprot_t prot, unsigned domid, |
34 | struct page **pages); | 71 | struct page **pages); |
35 | int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, | 72 | int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, |
36 | int numpgs, struct page **pages); | 73 | int numpgs, struct page **pages); |
74 | int xen_xlate_remap_gfn_array(struct vm_area_struct *vma, | ||
75 | unsigned long addr, | ||
76 | xen_pfn_t *gfn, int nr, | ||
77 | int *err_ptr, pgprot_t prot, | ||
78 | unsigned domid, | ||
79 | struct page **pages); | ||
80 | int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma, | ||
81 | int nr, struct page **pages); | ||
37 | 82 | ||
38 | bool xen_running_on_version_or_later(unsigned int major, unsigned int minor); | 83 | bool xen_running_on_version_or_later(unsigned int major, unsigned int minor); |
39 | 84 | ||
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h index b0f1c9e5d687..289c0b5f08fe 100644 --- a/include/xen/xenbus.h +++ b/include/xen/xenbus.h | |||
@@ -46,6 +46,10 @@ | |||
46 | #include <xen/interface/io/xenbus.h> | 46 | #include <xen/interface/io/xenbus.h> |
47 | #include <xen/interface/io/xs_wire.h> | 47 | #include <xen/interface/io/xs_wire.h> |
48 | 48 | ||
49 | #define XENBUS_MAX_RING_PAGE_ORDER 4 | ||
50 | #define XENBUS_MAX_RING_PAGES (1U << XENBUS_MAX_RING_PAGE_ORDER) | ||
51 | #define INVALID_GRANT_HANDLE (~0U) | ||
52 | |||
49 | /* Register callback to watch this node. */ | 53 | /* Register callback to watch this node. */ |
50 | struct xenbus_watch | 54 | struct xenbus_watch |
51 | { | 55 | { |
@@ -199,15 +203,19 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch, | |||
199 | const char *pathfmt, ...); | 203 | const char *pathfmt, ...); |
200 | 204 | ||
201 | int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state); | 205 | int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state); |
202 | int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn); | 206 | int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr, |
203 | int xenbus_map_ring_valloc(struct xenbus_device *dev, | 207 | unsigned int nr_pages, grant_ref_t *grefs); |
204 | int gnt_ref, void **vaddr); | 208 | int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs, |
205 | int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, | 209 | unsigned int nr_grefs, void **vaddr); |
206 | grant_handle_t *handle, void *vaddr); | 210 | int xenbus_map_ring(struct xenbus_device *dev, |
211 | grant_ref_t *gnt_refs, unsigned int nr_grefs, | ||
212 | grant_handle_t *handles, unsigned long *vaddrs, | ||
213 | bool *leaked); | ||
207 | 214 | ||
208 | int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr); | 215 | int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr); |
209 | int xenbus_unmap_ring(struct xenbus_device *dev, | 216 | int xenbus_unmap_ring(struct xenbus_device *dev, |
210 | grant_handle_t handle, void *vaddr); | 217 | grant_handle_t *handles, unsigned int nr_handles, |
218 | unsigned long *vaddrs); | ||
211 | 219 | ||
212 | int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port); | 220 | int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port); |
213 | int xenbus_free_evtchn(struct xenbus_device *dev, int port); | 221 | int xenbus_free_evtchn(struct xenbus_device *dev, int port); |
diff --git a/scripts/xen-hypercalls.sh b/scripts/xen-hypercalls.sh new file mode 100644 index 000000000000..676d9226814f --- /dev/null +++ b/scripts/xen-hypercalls.sh | |||
@@ -0,0 +1,12 @@ | |||
1 | #!/bin/sh | ||
2 | out="$1" | ||
3 | shift | ||
4 | in="$@" | ||
5 | |||
6 | for i in $in; do | ||
7 | eval $CPP $LINUXINCLUDE -dD -imacros "$i" -x c /dev/null | ||
8 | done | \ | ||
9 | awk '$1 == "#define" && $2 ~ /__HYPERVISOR_[a-z][a-z_0-9]*/ { v[$3] = $2 } | ||
10 | END { print "/* auto-generated by scripts/xen-hypercall.sh */" | ||
11 | for (i in v) if (!(v[i] in v)) | ||
12 | print "HYPERCALL("substr(v[i], 14)")"}' | sort -u >$out | ||