These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / rdma / ipath / ipath_wc_x86_64.c
1 /*
2  * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
3  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
4  *
5  * This software is available to you under a choice of one of two
6  * licenses.  You may choose to be licensed under the terms of the GNU
7  * General Public License (GPL) Version 2, available from the file
8  * COPYING in the main directory of this source tree, or the
9  * OpenIB.org BSD license below:
10  *
11  *     Redistribution and use in source and binary forms, with or
12  *     without modification, are permitted provided that the following
13  *     conditions are met:
14  *
15  *      - Redistributions of source code must retain the above
16  *        copyright notice, this list of conditions and the following
17  *        disclaimer.
18  *
19  *      - Redistributions in binary form must reproduce the above
20  *        copyright notice, this list of conditions and the following
21  *        disclaimer in the documentation and/or other materials
22  *        provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  */
33
34 /*
35  * This file is conditionally built on x86_64 only.  Otherwise weak symbol
36  * versions of the functions exported from here are used.
37  */
38
39 #include <linux/pci.h>
40 #include <asm/processor.h>
41
42 #include "ipath_kernel.h"
43
44 /**
45  * ipath_enable_wc - enable write combining for MMIO writes to the device
46  * @dd: infinipath device
47  *
48  * This routine is x86_64-specific; it twiddles the CPU's MTRRs to enable
49  * write combining.
50  */
51 int ipath_enable_wc(struct ipath_devdata *dd)
52 {
53         int ret = 0;
54         u64 pioaddr, piolen;
55         unsigned bits;
56         const unsigned long addr = pci_resource_start(dd->pcidev, 0);
57         const size_t len = pci_resource_len(dd->pcidev, 0);
58
59         /*
60          * Set the PIO buffers to be WCCOMB, so we get HT bursts to the
61          * chip.  Linux (possibly the hardware) requires it to be on a power
62          * of 2 address matching the length (which has to be a power of 2).
63          * For rev1, that means the base address, for rev2, it will be just
64          * the PIO buffers themselves.
65          * For chips with two sets of buffers, the calculations are
66          * somewhat more complicated; we need to sum, and the piobufbase
67          * register has both offsets, 2K in low 32 bits, 4K in high 32 bits.
68          * The buffers are still packed, so a single range covers both.
69          */
70         if (dd->ipath_piobcnt2k && dd->ipath_piobcnt4k) { /* 2 sizes */
71                 unsigned long pio2kbase, pio4kbase;
72                 pio2kbase = dd->ipath_piobufbase & 0xffffffffUL;
73                 pio4kbase = (dd->ipath_piobufbase >> 32) & 0xffffffffUL;
74                 if (pio2kbase < pio4kbase) { /* all, for now */
75                         pioaddr = addr + pio2kbase;
76                         piolen = pio4kbase - pio2kbase +
77                                 dd->ipath_piobcnt4k * dd->ipath_4kalign;
78                 } else {
79                         pioaddr = addr + pio4kbase;
80                         piolen = pio2kbase - pio4kbase +
81                                 dd->ipath_piobcnt2k * dd->ipath_palign;
82                 }
83         } else {  /* single buffer size (2K, currently) */
84                 pioaddr = addr + dd->ipath_piobufbase;
85                 piolen = dd->ipath_piobcnt2k * dd->ipath_palign +
86                         dd->ipath_piobcnt4k * dd->ipath_4kalign;
87         }
88
89         for (bits = 0; !(piolen & (1ULL << bits)); bits++)
90                 /* do nothing */ ;
91
92         if (piolen != (1ULL << bits)) {
93                 piolen >>= bits;
94                 while (piolen >>= 1)
95                         bits++;
96                 piolen = 1ULL << (bits + 1);
97         }
98         if (pioaddr & (piolen - 1)) {
99                 u64 atmp;
100                 ipath_dbg("pioaddr %llx not on right boundary for size "
101                           "%llx, fixing\n",
102                           (unsigned long long) pioaddr,
103                           (unsigned long long) piolen);
104                 atmp = pioaddr & ~(piolen - 1);
105                 if (atmp < addr || (atmp + piolen) > (addr + len)) {
106                         ipath_dev_err(dd, "No way to align address/size "
107                                       "(%llx/%llx), no WC mtrr\n",
108                                       (unsigned long long) atmp,
109                                       (unsigned long long) piolen << 1);
110                         ret = -ENODEV;
111                 } else {
112                         ipath_dbg("changing WC base from %llx to %llx, "
113                                   "len from %llx to %llx\n",
114                                   (unsigned long long) pioaddr,
115                                   (unsigned long long) atmp,
116                                   (unsigned long long) piolen,
117                                   (unsigned long long) piolen << 1);
118                         pioaddr = atmp;
119                         piolen <<= 1;
120                 }
121         }
122
123         if (!ret) {
124                 dd->wc_cookie = arch_phys_wc_add(pioaddr, piolen);
125                 if (dd->wc_cookie < 0) {
126                         ipath_dev_err(dd, "Seting mtrr failed on PIO buffers\n");
127                         ret = -ENODEV;
128                 } else if (dd->wc_cookie == 0)
129                         ipath_cdbg(VERBOSE, "Set mtrr for chip to WC not needed\n");
130                 else
131                         ipath_cdbg(VERBOSE, "Set mtrr for chip to WC\n");
132         }
133
134         return ret;
135 }
136
137 /**
138  * ipath_disable_wc - disable write combining for MMIO writes to the device
139  * @dd: infinipath device
140  */
141 void ipath_disable_wc(struct ipath_devdata *dd)
142 {
143         arch_phys_wc_del(dd->wc_cookie);
144 }