[HW] Remove FUNC_PTR64.
[mirror/winof/.git] / hw / mlx4 / kernel_patches / mlx4_0010_add_wc.patch
1 IB/mlx4: set write-combining flag for userspace blueflame pages
2
3 Supported on i386 and x86_64 for now.
4
5 Signed-off-by: Michael S. Tsirkin <mst@dev.mellanox.co.il>
6
7 diff --git a/drivers/infiniband/hw/mlx4/Makefile b/drivers/infiniband/hw/mlx4/Makefile
8 index 70f09c7..ce885a8 100644
9 --- a/drivers/infiniband/hw/mlx4/Makefile
10 +++ b/drivers/infiniband/hw/mlx4/Makefile
11 @@ -1,3 +1,4 @@
12  obj-$(CONFIG_MLX4_INFINIBAND)  += mlx4_ib.o
13  
14  mlx4_ib-y :=   ah.o cq.o doorbell.o mad.o main.o mr.o qp.o srq.o
15 +mlx4_ib-y +=   wc.o
16 diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
17 index 5128d95..f60a3cd 100644
18 --- a/drivers/infiniband/hw/mlx4/main.c
19 +++ b/drivers/infiniband/hw/mlx4/main.c
20 @@ -42,6 +42,7 @@
21  
22  #include "mlx4_ib.h"
23  #include "user.h"
24 +#include "wc.h"
25  
26  #define DRV_NAME       "mlx4_ib"
27  #define DRV_VERSION    "0.01"
28 @@ -375,7 +376,7 @@ static int mlx4_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
29                         return -EAGAIN;
30         } else if (vma->vm_pgoff == 1 && dev->dev->caps.bf_reg_size != 0) {
31                 /* FIXME want pgprot_writecombine() for BlueFlame pages */
32 -               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
33 +               vma->vm_page_prot = pgprot_wc(vma->vm_page_prot);
34  
35                 if (io_remap_pfn_range(vma, vma->vm_start,
36                                        to_mucontext(context)->uar.pfn +
37 @@ -611,12 +612,14 @@ static struct mlx4_interface mlx4_ib_interface = {
38  
39  static int __init mlx4_ib_init(void)
40  {
41 +       mlx4_enable_wc();
42         return mlx4_register_interface(&mlx4_ib_interface);
43  }
44  
45  static void __exit mlx4_ib_cleanup(void)
46  {
47         mlx4_unregister_interface(&mlx4_ib_interface);
48 +       mlx4_disable_wc();
49  }
50  
51  module_init(mlx4_ib_init);
52 diff --git a/drivers/infiniband/hw/mlx4/wc.c b/drivers/infiniband/hw/mlx4/wc.c
53 new file mode 100644
54 index 0000000..3747ab1
55 --- /dev/null
56 +++ b/drivers/infiniband/hw/mlx4/wc.c
57 @@ -0,0 +1,206 @@
58 +/*
59 + * Copyright (c) 2006-2007 Mellanox Technologies. All rights reserved.
60 + *
61 + * This software is available to you under a choice of one of two
62 + * licenses.  You may choose to be licensed under the terms of the GNU
63 + * General Public License (GPL) Version 2, available from the file
64 + * COPYING in the main directory of this source tree, or the
65 + * OpenIB.org BSD license below:
66 + *
67 + *     Redistribution and use in source and binary forms, with or
68 + *     without modification, are permitted provided that the following
69 + *     conditions are met:
70 + *
71 + *      - Redistributions of source code must retain the above
72 + *        copyright notice, this list of conditions and the following
73 + *        disclaimer.
74 + *
75 + *      - Redistributions in binary form must reproduce the above
76 + *        copyright notice, this list of conditions and the following
77 + *        disclaimer in the documentation and/or other materials
78 + *        provided with the distribution.
79 + *
80 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
81 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
82 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
83 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
84 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
85 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
86 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
87 + * SOFTWARE.
88 + */
89 +
90 +#include <linux/pci.h>
91 +#include "wc.h"
92 +
93 +static u32 old_pat_lo[NR_CPUS] = {0};
94 +static u32 old_pat_hi[NR_CPUS] = {0};
95 +static unsigned int wc_enabled = 0;
96 +
97 +#define MLX4_PAT_MASK  (0xFFFFF8FF)
98 +#define MLX4_PAT_MOD   (0x00000100)
99 +#define MLX4_WC_FLAGS  (_PAGE_PWT)
100 +
101 +#if defined(__i386__) || defined(__x86_64__)
102 +
103 +#define X86_MSR_PAT_OFFSET  0x277
104 +
105 +/*  Returns non-zero if we have a chipset write-combining problem */
106 +static int have_wc_errata(void)
107 +{
108 +       struct pci_dev *dev;
109 +       u8 rev;
110 +
111 +       if ((dev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) {
112 +               /*
113 +                * ServerWorks LE chipsets < rev 6 have problems with
114 +                * write-combining.
115 +                */
116 +               if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
117 +                   dev->device == PCI_DEVICE_ID_SERVERWORKS_LE) {
118 +                       pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
119 +                       if (rev <= 5) {
120 +                               printk(KERN_INFO "ib_mlx4: Serverworks LE rev < 6"
121 +                                      " detected. Write-combining disabled.\n");
122 +                               pci_dev_put(dev);
123 +                               return -ENOSYS;
124 +                       }
125 +               }
126 +               /* Intel 450NX errata # 23. Non ascending cacheline evictions
127 +                  to write combining memory may resulting in data corruption */
128 +               if (dev->vendor == PCI_VENDOR_ID_INTEL &&
129 +                   dev->device == PCI_DEVICE_ID_INTEL_82451NX) {
130 +                       printk(KERN_INFO "ib_mlx4: Intel 450NX MMC detected."
131 +                              " Write-combining disabled.\n");
132 +                       pci_dev_put(dev);
133 +                       return -ENOSYS;
134 +               }
135 +               pci_dev_put(dev);
136 +       }
137 +       return 0;
138 +}
139 +
140 +static void rd_old_pat(void *err)
141 +{
142 +       *(int *)err |= rdmsr_safe(X86_MSR_PAT_OFFSET,
143 +                                 &old_pat_lo[smp_processor_id()],
144 +                                 &old_pat_hi[smp_processor_id()]);
145 +}
146 +
147 +static void wr_new_pat(void *err)
148 +{
149 +       u32 new_pat_lo = (old_pat_lo[smp_processor_id()] & MLX4_PAT_MASK) |
150 +                         MLX4_PAT_MOD;
151 +
152 +       *(int *)err |= wrmsr_safe(X86_MSR_PAT_OFFSET,
153 +                                 new_pat_lo,
154 +                                 old_pat_hi[smp_processor_id()]);
155 +}
156 +
157 +static void wr_old_pat(void *err)
158 +{
159 +       *(int *)err |= wrmsr_safe(X86_MSR_PAT_OFFSET,
160 +                                 old_pat_lo[smp_processor_id()],
161 +                                 old_pat_hi[smp_processor_id()]);
162 +}
163 +
164 +static int read_and_modify_pat(void)
165 +{
166 +       int ret = 0;
167 +
168 +       preempt_disable();
169 +       rd_old_pat(&ret);
170 +       if (!ret)
171 +               smp_call_function(rd_old_pat, &ret, 1, 1);
172 +       if (ret)
173 +               goto out;
174 +
175 +       wr_new_pat(&ret);
176 +       if (ret)
177 +               goto out;
178 +
179 +       smp_call_function(wr_new_pat, &ret, 1, 1);
180 +       BUG_ON(ret); /* have inconsistent PAT state */
181 +out:
182 +       preempt_enable();
183 +       return ret;
184 +}
185 +
186 +static int restore_pat(void)
187 +{
188 +       int ret = 0;
189 +
190 +       preempt_disable();
191 +       wr_old_pat(&ret);
192 +       if (!ret) {
193 +               smp_call_function(wr_old_pat, &ret, 1, 1);
194 +               BUG_ON(ret); /* have inconsistent PAT state */
195 +       }
196 +
197 +       preempt_enable();
198 +       return ret;
199 +}
200 +
201 +int mlx4_enable_wc(void)
202 +{
203 +       struct cpuinfo_x86 *c = &cpu_data(0);
204 +       int ret;
205 +
206 +       if (wc_enabled)
207 +               return 0;
208 +
209 +       if (!cpu_has(c, X86_FEATURE_MSR) ||
210 +           !cpu_has(c, X86_FEATURE_PAT)) {
211 +               printk(KERN_INFO "ib_mlx4: WC not available"
212 +                      " on this processor\n");
213 +               return -ENOSYS;
214 +       }
215 +
216 +       if (have_wc_errata())
217 +               return -ENOSYS;
218 +
219 +       if (!(ret = read_and_modify_pat()))
220 +               wc_enabled = 1;
221 +       else
222 +               printk(KERN_INFO "ib_mlx4: failed to enable WC\n");
223 +       return ret ? -EIO  : 0;
224 +}
225 +
226 +void mlx4_disable_wc(void)
227 +{
228 +       if (wc_enabled) {
229 +               if (!restore_pat())
230 +                       wc_enabled = 0;
231 +               else
232 +                       printk(KERN_INFO "ib_mlx4: failed to disable WC\n");
233 +       }
234 +}
235 +
236 +pgprot_t pgprot_wc(pgprot_t _prot)
237 +{
238 +       return wc_enabled ? __pgprot(pgprot_val(_prot) | MLX4_WC_FLAGS) :
239 +                           pgprot_noncached(_prot);
240 +}
241 +
242 +int mlx4_wc_enabled(void)
243 +{
244 +       return wc_enabled;
245 +}
246 +
247 +#else  /* !(defined(__i386__) || defined(__x86_64__)) */
248 +
249 +int mlx4_enable_wc(void){ return 0; }
250 +void mlx4_disable_wc(void){}
251 +
252 +pgprot_t pgprot_wc(pgprot_t _prot)
253 +{
254 +       return pgprot_noncached(_prot);
255 +}
256 +
257 +int mlx4_wc_enabled(void)
258 +{
259 +       return 0;
260 +}
261 +
262 +#endif
263 +
264 diff --git a/drivers/infiniband/hw/mlx4/wc.h b/drivers/infiniband/hw/mlx4/wc.h
265 new file mode 100644
266 index 0000000..70b891d
267 --- /dev/null
268 +++ b/drivers/infiniband/hw/mlx4/wc.h
269 @@ -0,0 +1,43 @@
270 +/*
271 + * Copyright (c) 2006-2007 Mellanox Technologies. All rights reserved.
272 + *
273 + * This software is available to you under a choice of one of two
274 + * licenses.  You may choose to be licensed under the terms of the GNU
275 + * General Public License (GPL) Version 2, available from the file
276 + * COPYING in the main directory of this source tree, or the
277 + * OpenIB.org BSD license below:
278 + *
279 + *     Redistribution and use in source and binary forms, with or
280 + *     without modification, are permitted provided that the following
281 + *     conditions are met:
282 + *
283 + *      - Redistributions of source code must retain the above
284 + *        copyright notice, this list of conditions and the following
285 + *        disclaimer.
286 + *
287 + *      - Redistributions in binary form must reproduce the above
288 + *        copyright notice, this list of conditions and the following
289 + *        disclaimer in the documentation and/or other materials
290 + *        provided with the distribution.
291 + *
292 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
293 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
294 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
295 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
296 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
297 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
298 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
299 + * SOFTWARE.
300 + */
301 +
302 +#ifndef mlx4_WC_H
303 +#define mlx4_WC_H
304 +
305 +#include <asm/pgtable.h>
306 +
307 +int mlx4_enable_wc(void);
308 +void mlx4_disable_wc(void);
309 +int mlx4_wc_enabled(void);
310 +pgprot_t pgprot_wc(pgprot_t _prot);
311 +
312 +#endif