History

Merge tag 'stable/for-linus-3.17-b-rc4-arm-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull Xen ARM bugfix from Stefano Stabellini: "The patches fix the "xen_add_mach_to_phys_entry: cannot add" bug that has been affecting xen on arm and arm64 guests since 3.16. They require a few hypervisor side changes that just went in xen-unstable. A couple of days ago David sent out a pull request with a few other Xen fixes (it is already in master). Sorry we didn't synchronized better among us" * tag 'stable/for-linus-3.17-b-rc4-arm-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: xen/arm: remove mach_to_phys rbtree xen/arm: reimplement xen_dma_unmap_page & friends xen/arm: introduce XENFEAT_grant_map_identity

Linus Torvalds committed 12 years ago

Commit fc486b02 parents 471cff7 d50582e7 files · +220 −93Browse files

Unified · Split

7 files
  1. arch/arm/include/asm/xen/page-coherent.h +7 −18
  2. arch/arm/include/asm/xen/page.h +0 −9
  3. arch/arm/xen/Makefile +1 −1
  4. arch/arm/xen/enlighten.c +6 −0
  5. arch/arm/xen/mm32.c +202 −0
  6. arch/arm/xen/p2m.c +1 −65
  7. include/xen/interface/features.h +3 −0
arch/arm/include/asm/xen/page-coherent.h+7−18
@@ -26,25 +26,14 @@ static inline void xen_dma_map_page(struct device *hwdev, struct page *page, · 25 unmodified lines
2626 __generic_dma_ops(hwdev)->map_page(hwdev, page, offset, size, dir, attrs);
2727 }
2828
29−static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
29+void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
3030 size_t size, enum dma_data_direction dir,
31− struct dma_attrs *attrs)
32−{
33− if (__generic_dma_ops(hwdev)->unmap_page)
34− __generic_dma_ops(hwdev)->unmap_page(hwdev, handle, size, dir, attrs);
35−}
31+ struct dma_attrs *attrs);
3632
37−static inline void xen_dma_sync_single_for_cpu(struct device *hwdev,
38− dma_addr_t handle, size_t size, enum dma_data_direction dir)
39−{
40− if (__generic_dma_ops(hwdev)->sync_single_for_cpu)
41− __generic_dma_ops(hwdev)->sync_single_for_cpu(hwdev, handle, size, dir);
42−}
33+void xen_dma_sync_single_for_cpu(struct device *hwdev,
34+ dma_addr_t handle, size_t size, enum dma_data_direction dir);
35+
36+void xen_dma_sync_single_for_device(struct device *hwdev,
37+ dma_addr_t handle, size_t size, enum dma_data_direction dir);
4338
44−static inline void xen_dma_sync_single_for_device(struct device *hwdev,
45− dma_addr_t handle, size_t size, enum dma_data_direction dir)
46−{
47− if (__generic_dma_ops(hwdev)->sync_single_for_device)
48− __generic_dma_ops(hwdev)->sync_single_for_device(hwdev, handle, size, dir);
49−}
5039 #endif /* _ASM_ARM_XEN_PAGE_COHERENT_H */
arch/arm/include/asm/xen/page.h+0−9
@@ -33,7 +33,6 @@ typedef struct xpaddr { · 32 unmodified lines
3333 #define INVALID_P2M_ENTRY (~0UL)
3434
3535 unsigned long __pfn_to_mfn(unsigned long pfn);
36−unsigned long __mfn_to_pfn(unsigned long mfn);
3736 extern struct rb_root phys_to_mach;
3837
3938 static inline unsigned long pfn_to_mfn(unsigned long pfn)
@@ -51,14 +50,6 @@ static inline unsigned long pfn_to_mfn(unsigned long pfn) · 11 unmodified lines
5150
5251 static inline unsigned long mfn_to_pfn(unsigned long mfn)
5352 {
54− unsigned long pfn;
55−
56− if (phys_to_mach.rb_node != NULL) {
57− pfn = __mfn_to_pfn(mfn);
58− if (pfn != INVALID_P2M_ENTRY)
59− return pfn;
60− }
61−
6253 return mfn;
6354 }
6455
arch/arm/xen/Makefile+1−1
@@ -1 +1 @@
1−obj-y := enlighten.o hypercall.o grant-table.o p2m.o mm.o
1+obj-y := enlighten.o hypercall.o grant-table.o p2m.o mm.o mm32.o
arch/arm/xen/enlighten.c+6−0
@@ -260,6 +260,12 @@ static int __init xen_guest_init(void) · 259 unmodified lines
260260 xen_domain_type = XEN_HVM_DOMAIN;
261261
262262 xen_setup_features();
263+
264+ if (!xen_feature(XENFEAT_grant_map_identity)) {
265+ pr_warn("Please upgrade your Xen.\n"
266+ "If your platform has any non-coherent DMA devices, they won't work properly.\n");
267+ }
268+
263269 if (xen_feature(XENFEAT_dom0))
264270 xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
265271 else
arch/arm/xen/mm32.c+202−0
@@ -0,0 +1,202 @@
1+#include <linux/cpu.h>
2+#include <linux/dma-mapping.h>
3+#include <linux/gfp.h>
4+#include <linux/highmem.h>
5+
6+#include <xen/features.h>
7+
8+static DEFINE_PER_CPU(unsigned long, xen_mm32_scratch_virt);
9+static DEFINE_PER_CPU(pte_t *, xen_mm32_scratch_ptep);
10+
11+static int alloc_xen_mm32_scratch_page(int cpu)
12+{
13+ struct page *page;
14+ unsigned long virt;
15+ pmd_t *pmdp;
16+ pte_t *ptep;
17+
18+ if (per_cpu(xen_mm32_scratch_ptep, cpu) != NULL)
19+ return 0;
20+
21+ page = alloc_page(GFP_KERNEL);
22+ if (page == NULL) {
23+ pr_warn("Failed to allocate xen_mm32_scratch_page for cpu %d\n", cpu);
24+ return -ENOMEM;
25+ }
26+
27+ virt = (unsigned long)__va(page_to_phys(page));
28+ pmdp = pmd_offset(pud_offset(pgd_offset_k(virt), virt), virt);
29+ ptep = pte_offset_kernel(pmdp, virt);
30+
31+ per_cpu(xen_mm32_scratch_virt, cpu) = virt;
32+ per_cpu(xen_mm32_scratch_ptep, cpu) = ptep;
33+
34+ return 0;
35+}
36+
37+static int xen_mm32_cpu_notify(struct notifier_block *self,
38+ unsigned long action, void *hcpu)
39+{
40+ int cpu = (long)hcpu;
41+ switch (action) {
42+ case CPU_UP_PREPARE:
43+ if (alloc_xen_mm32_scratch_page(cpu))
44+ return NOTIFY_BAD;
45+ break;
46+ default:
47+ break;
48+ }
49+ return NOTIFY_OK;
50+}
51+
52+static struct notifier_block xen_mm32_cpu_notifier = {
53+ .notifier_call = xen_mm32_cpu_notify,
54+};
55+
56+static void* xen_mm32_remap_page(dma_addr_t handle)
57+{
58+ unsigned long virt = get_cpu_var(xen_mm32_scratch_virt);
59+ pte_t *ptep = __get_cpu_var(xen_mm32_scratch_ptep);
60+
61+ *ptep = pfn_pte(handle >> PAGE_SHIFT, PAGE_KERNEL);
62+ local_flush_tlb_kernel_page(virt);
63+
64+ return (void*)virt;
65+}
66+
67+static void xen_mm32_unmap(void *vaddr)
68+{
69+ put_cpu_var(xen_mm32_scratch_virt);
70+}
71+
72+
73+/* functions called by SWIOTLB */
74+
75+static void dma_cache_maint(dma_addr_t handle, unsigned long offset,
76+ size_t size, enum dma_data_direction dir,
77+ void (*op)(const void *, size_t, int))
78+{
79+ unsigned long pfn;
80+ size_t left = size;
81+
82+ pfn = (handle >> PAGE_SHIFT) + offset / PAGE_SIZE;
83+ offset %= PAGE_SIZE;
84+
85+ do {
86+ size_t len = left;
87+ void *vaddr;
88+
89+ if (!pfn_valid(pfn))
90+ {
91+ /* Cannot map the page, we don't know its physical address.
92+ * Return and hope for the best */
93+ if (!xen_feature(XENFEAT_grant_map_identity))
94+ return;
95+ vaddr = xen_mm32_remap_page(handle) + offset;
96+ op(vaddr, len, dir);
97+ xen_mm32_unmap(vaddr - offset);
98+ } else {
99+ struct page *page = pfn_to_page(pfn);
100+
101+ if (PageHighMem(page)) {
102+ if (len + offset > PAGE_SIZE)
103+ len = PAGE_SIZE - offset;
104+
105+ if (cache_is_vipt_nonaliasing()) {
106+ vaddr = kmap_atomic(page);
107+ op(vaddr + offset, len, dir);
108+ kunmap_atomic(vaddr);
109+ } else {
110+ vaddr = kmap_high_get(page);
111+ if (vaddr) {
112+ op(vaddr + offset, len, dir);
113+ kunmap_high(page);
114+ }
115+ }
116+ } else {
117+ vaddr = page_address(page) + offset;
118+ op(vaddr, len, dir);
119+ }
120+ }
121+
122+ offset = 0;
123+ pfn++;
124+ left -= len;
125+ } while (left);
126+}
127+
128+static void __xen_dma_page_dev_to_cpu(struct device *hwdev, dma_addr_t handle,
129+ size_t size, enum dma_data_direction dir)
130+{
131+ /* Cannot use __dma_page_dev_to_cpu because we don't have a
132+ * struct page for handle */
133+
134+ if (dir != DMA_TO_DEVICE)
135+ outer_inv_range(handle, handle + size);
136+
137+ dma_cache_maint(handle & PAGE_MASK, handle & ~PAGE_MASK, size, dir, dmac_unmap_area);
138+}
139+
140+static void __xen_dma_page_cpu_to_dev(struct device *hwdev, dma_addr_t handle,
141+ size_t size, enum dma_data_direction dir)
142+{
143+
144+ dma_cache_maint(handle & PAGE_MASK, handle & ~PAGE_MASK, size, dir, dmac_map_area);
145+
146+ if (dir == DMA_FROM_DEVICE) {
147+ outer_inv_range(handle, handle + size);
148+ } else {
149+ outer_clean_range(handle, handle + size);
150+ }
151+}
152+
153+void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
154+ size_t size, enum dma_data_direction dir,
155+ struct dma_attrs *attrs)
156+
157+{
158+ if (!__generic_dma_ops(hwdev)->unmap_page)
159+ return;
160+ if (dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
161+ return;
162+
163+ __xen_dma_page_dev_to_cpu(hwdev, handle, size, dir);
164+}
165+
166+void xen_dma_sync_single_for_cpu(struct device *hwdev,
167+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
168+{
169+ if (!__generic_dma_ops(hwdev)->sync_single_for_cpu)
170+ return;
171+ __xen_dma_page_dev_to_cpu(hwdev, handle, size, dir);
172+}
173+
174+void xen_dma_sync_single_for_device(struct device *hwdev,
175+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
176+{
177+ if (!__generic_dma_ops(hwdev)->sync_single_for_device)
178+ return;
179+ __xen_dma_page_cpu_to_dev(hwdev, handle, size, dir);
180+}
181+
182+int __init xen_mm32_init(void)
183+{
184+ int cpu;
185+
186+ if (!xen_initial_domain())
187+ return 0;
188+
189+ register_cpu_notifier(&xen_mm32_cpu_notifier);
190+ get_online_cpus();
191+ for_each_online_cpu(cpu) {
192+ if (alloc_xen_mm32_scratch_page(cpu)) {
193+ put_online_cpus();
194+ unregister_cpu_notifier(&xen_mm32_cpu_notifier);
195+ return -ENOMEM;
196+ }
197+ }
198+ put_online_cpus();
199+
200+ return 0;
201+}
202+arch_initcall(xen_mm32_init);
arch/arm/xen/p2m.c+1−65
@@ -21,14 +21,12 @@ struct xen_p2m_entry { · 20 unmodified lines
2121 unsigned long pfn;
2222 unsigned long mfn;
2323 unsigned long nr_pages;
24− struct rb_node rbnode_mach;
2524 struct rb_node rbnode_phys;
2625 };
2726
2827 static rwlock_t p2m_lock;
2928 struct rb_root phys_to_mach = RB_ROOT;
3029 EXPORT_SYMBOL_GPL(phys_to_mach);
31−static struct rb_root mach_to_phys = RB_ROOT;
3230
3331 static int xen_add_phys_to_mach_entry(struct xen_p2m_entry *new)
3432 {
@@ -41,8 +39,6 @@ static int xen_add_phys_to_mach_entry(struct xen_p2m_entry *new) · 6 unmodified lines
4139 parent = *link;
4240 entry = rb_entry(parent, struct xen_p2m_entry, rbnode_phys);
4341
44− if (new->mfn == entry->mfn)
45− goto err_out;
4642 if (new->pfn == entry->pfn)
4743 goto err_out;
4844
@@ -88,64 +84,6 @@ unsigned long __pfn_to_mfn(unsigned long pfn) · 39 unmodified lines
8884 }
8985 EXPORT_SYMBOL_GPL(__pfn_to_mfn);
9086
91−static int xen_add_mach_to_phys_entry(struct xen_p2m_entry *new)
92−{
93− struct rb_node **link = &mach_to_phys.rb_node;
94− struct rb_node *parent = NULL;
95− struct xen_p2m_entry *entry;
96− int rc = 0;
97−
98− while (*link) {
99− parent = *link;
100− entry = rb_entry(parent, struct xen_p2m_entry, rbnode_mach);
101−
102− if (new->mfn == entry->mfn)
103− goto err_out;
104− if (new->pfn == entry->pfn)
105− goto err_out;
106−
107− if (new->mfn < entry->mfn)
108− link = &(*link)->rb_left;
109− else
110− link = &(*link)->rb_right;
111− }
112− rb_link_node(&new->rbnode_mach, parent, link);
113− rb_insert_color(&new->rbnode_mach, &mach_to_phys);
114− goto out;
115−
116−err_out:
117− rc = -EINVAL;
118− pr_warn("%s: cannot add pfn=%pa -> mfn=%pa: pfn=%pa -> mfn=%pa already exists\n",
119− __func__, &new->pfn, &new->mfn, &entry->pfn, &entry->mfn);
120−out:
121− return rc;
122−}
123−
124−unsigned long __mfn_to_pfn(unsigned long mfn)
125−{
126− struct rb_node *n = mach_to_phys.rb_node;
127− struct xen_p2m_entry *entry;
128− unsigned long irqflags;
129−
130− read_lock_irqsave(&p2m_lock, irqflags);
131− while (n) {
132− entry = rb_entry(n, struct xen_p2m_entry, rbnode_mach);
133− if (entry->mfn <= mfn &&
134− entry->mfn + entry->nr_pages > mfn) {
135− read_unlock_irqrestore(&p2m_lock, irqflags);
136− return entry->pfn + (mfn - entry->mfn);
137− }
138− if (mfn < entry->mfn)
139− n = n->rb_left;
140− else
141− n = n->rb_right;
142− }
143− read_unlock_irqrestore(&p2m_lock, irqflags);
144−
145− return INVALID_P2M_ENTRY;
146−}
147−EXPORT_SYMBOL_GPL(__mfn_to_pfn);
148−
14987 int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
15088 struct gnttab_map_grant_ref *kmap_ops,
15189 struct page **pages, unsigned int count)
@@ -192,7 +130,6 @@ bool __set_phys_to_machine_multi(unsigned long pfn, · 40 unmodified lines
192130 p2m_entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys);
193131 if (p2m_entry->pfn <= pfn &&
194132 p2m_entry->pfn + p2m_entry->nr_pages > pfn) {
195− rb_erase(&p2m_entry->rbnode_mach, &mach_to_phys);
196133 rb_erase(&p2m_entry->rbnode_phys, &phys_to_mach);
197134 write_unlock_irqrestore(&p2m_lock, irqflags);
198135 kfree(p2m_entry);
@@ -217,8 +154,7 @@ bool __set_phys_to_machine_multi(unsigned long pfn, · 18 unmodified lines
217154 p2m_entry->mfn = mfn;
218155
219156 write_lock_irqsave(&p2m_lock, irqflags);
220− if ((rc = xen_add_phys_to_mach_entry(p2m_entry) < 0) ||
221− (rc = xen_add_mach_to_phys_entry(p2m_entry) < 0)) {
157+ if ((rc = xen_add_phys_to_mach_entry(p2m_entry)) < 0) {
222158 write_unlock_irqrestore(&p2m_lock, irqflags);
223159 return false;
224160 }
include/xen/interface/features.h+3−0
@@ -53,6 +53,9 @@ · 52 unmodified lines
5353 /* operation as Dom0 is supported */
5454 #define XENFEAT_dom0 11
5555
56+/* Xen also maps grant references at pfn = mfn */
57+#define XENFEAT_grant_map_identity 12
58+
5659 #define XENFEAT_NR_SUBMAPS 1
5760
5861 #endif /* __XEN_PUBLIC_FEATURES_H__ */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t