1 IB/mlx4: set write-combining flag for userspace blueflame pages
3 Supported on i386 and x86_64 for now.
5 Signed-off-by: Michael S. Tsirkin <mst@dev.mellanox.co.il>
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
12 obj-$(CONFIG_MLX4_INFINIBAND) += mlx4_ib.o
14 mlx4_ib-y := ah.o cq.o doorbell.o mad.o main.o mr.o qp.o srq.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
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)
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);
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 = {
39 static int __init mlx4_ib_init(void)
42 return mlx4_register_interface(&mlx4_ib_interface);
45 static void __exit mlx4_ib_cleanup(void)
47 mlx4_unregister_interface(&mlx4_ib_interface);
51 module_init(mlx4_ib_init);
52 diff --git a/drivers/infiniband/hw/mlx4/wc.c b/drivers/infiniband/hw/mlx4/wc.c
54 index 0000000..3747ab1
56 +++ b/drivers/infiniband/hw/mlx4/wc.c
59 + * Copyright (c) 2006-2007 Mellanox Technologies. All rights reserved.
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:
67 + * Redistribution and use in source and binary forms, with or
68 + * without modification, are permitted provided that the following
69 + * conditions are met:
71 + * - Redistributions of source code must retain the above
72 + * copyright notice, this list of conditions and the following
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.
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
90 +#include <linux/pci.h>
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;
97 +#define MLX4_PAT_MASK (0xFFFFF8FF)
98 +#define MLX4_PAT_MOD (0x00000100)
99 +#define MLX4_WC_FLAGS (_PAGE_PWT)
101 +#if defined(__i386__) || defined(__x86_64__)
103 +#define X86_MSR_PAT_OFFSET 0x277
105 +/* Returns non-zero if we have a chipset write-combining problem */
106 +static int have_wc_errata(void)
108 + struct pci_dev *dev;
111 + if ((dev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) {
113 + * ServerWorks LE chipsets < rev 6 have problems with
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);
120 + printk(KERN_INFO "ib_mlx4: Serverworks LE rev < 6"
121 + " detected. Write-combining disabled.\n");
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");
140 +static void rd_old_pat(void *err)
142 + *(int *)err |= rdmsr_safe(X86_MSR_PAT_OFFSET,
143 + &old_pat_lo[smp_processor_id()],
144 + &old_pat_hi[smp_processor_id()]);
147 +static void wr_new_pat(void *err)
149 + u32 new_pat_lo = (old_pat_lo[smp_processor_id()] & MLX4_PAT_MASK) |
152 + *(int *)err |= wrmsr_safe(X86_MSR_PAT_OFFSET,
154 + old_pat_hi[smp_processor_id()]);
157 +static void wr_old_pat(void *err)
159 + *(int *)err |= wrmsr_safe(X86_MSR_PAT_OFFSET,
160 + old_pat_lo[smp_processor_id()],
161 + old_pat_hi[smp_processor_id()]);
164 +static int read_and_modify_pat(void)
171 + smp_call_function(rd_old_pat, &ret, 1, 1);
179 + smp_call_function(wr_new_pat, &ret, 1, 1);
180 + BUG_ON(ret); /* have inconsistent PAT state */
186 +static int restore_pat(void)
193 + smp_call_function(wr_old_pat, &ret, 1, 1);
194 + BUG_ON(ret); /* have inconsistent PAT state */
201 +int mlx4_enable_wc(void)
203 + struct cpuinfo_x86 *c = &cpu_data(0);
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");
216 + if (have_wc_errata())
219 + if (!(ret = read_and_modify_pat()))
222 + printk(KERN_INFO "ib_mlx4: failed to enable WC\n");
223 + return ret ? -EIO : 0;
226 +void mlx4_disable_wc(void)
229 + if (!restore_pat())
232 + printk(KERN_INFO "ib_mlx4: failed to disable WC\n");
236 +pgprot_t pgprot_wc(pgprot_t _prot)
238 + return wc_enabled ? __pgprot(pgprot_val(_prot) | MLX4_WC_FLAGS) :
239 + pgprot_noncached(_prot);
242 +int mlx4_wc_enabled(void)
247 +#else /* !(defined(__i386__) || defined(__x86_64__)) */
249 +int mlx4_enable_wc(void){ return 0; }
250 +void mlx4_disable_wc(void){}
252 +pgprot_t pgprot_wc(pgprot_t _prot)
254 + return pgprot_noncached(_prot);
257 +int mlx4_wc_enabled(void)
264 diff --git a/drivers/infiniband/hw/mlx4/wc.h b/drivers/infiniband/hw/mlx4/wc.h
266 index 0000000..70b891d
268 +++ b/drivers/infiniband/hw/mlx4/wc.h
271 + * Copyright (c) 2006-2007 Mellanox Technologies. All rights reserved.
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:
279 + * Redistribution and use in source and binary forms, with or
280 + * without modification, are permitted provided that the following
281 + * conditions are met:
283 + * - Redistributions of source code must retain the above
284 + * copyright notice, this list of conditions and the following
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.
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
305 +#include <asm/pgtable.h>
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);