1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39#include <linux/pci.h>
40#include <asm/mtrr.h>
41#include <asm/processor.h>
42
43#include "ipath_kernel.h"
44
45
46
47
48
49
50
51
52int ipath_enable_wc(struct ipath_devdata *dd)
53{
54 int ret = 0;
55 u64 pioaddr, piolen;
56 unsigned bits;
57 const unsigned long addr = pci_resource_start(dd->pcidev, 0);
58 const size_t len = pci_resource_len(dd->pcidev, 0);
59
60
61
62
63
64
65
66
67
68
69
70
71 if (dd->ipath_piobcnt2k && dd->ipath_piobcnt4k) {
72 unsigned long pio2kbase, pio4kbase;
73 pio2kbase = dd->ipath_piobufbase & 0xffffffffUL;
74 pio4kbase = (dd->ipath_piobufbase >> 32) & 0xffffffffUL;
75 if (pio2kbase < pio4kbase) {
76 pioaddr = addr + pio2kbase;
77 piolen = pio4kbase - pio2kbase +
78 dd->ipath_piobcnt4k * dd->ipath_4kalign;
79 } else {
80 pioaddr = addr + pio4kbase;
81 piolen = pio2kbase - pio4kbase +
82 dd->ipath_piobcnt2k * dd->ipath_palign;
83 }
84 } else {
85 pioaddr = addr + dd->ipath_piobufbase;
86 piolen = dd->ipath_piobcnt2k * dd->ipath_palign +
87 dd->ipath_piobcnt4k * dd->ipath_4kalign;
88 }
89
90 for (bits = 0; !(piolen & (1ULL << bits)); bits++)
91 ;
92
93 if (piolen != (1ULL << bits)) {
94 piolen >>= bits;
95 while (piolen >>= 1)
96 bits++;
97 piolen = 1ULL << (bits + 1);
98 }
99 if (pioaddr & (piolen - 1)) {
100 u64 atmp;
101 ipath_dbg("pioaddr %llx not on right boundary for size "
102 "%llx, fixing\n",
103 (unsigned long long) pioaddr,
104 (unsigned long long) piolen);
105 atmp = pioaddr & ~(piolen - 1);
106 if (atmp < addr || (atmp + piolen) > (addr + len)) {
107 ipath_dev_err(dd, "No way to align address/size "
108 "(%llx/%llx), no WC mtrr\n",
109 (unsigned long long) atmp,
110 (unsigned long long) piolen << 1);
111 ret = -ENODEV;
112 } else {
113 ipath_dbg("changing WC base from %llx to %llx, "
114 "len from %llx to %llx\n",
115 (unsigned long long) pioaddr,
116 (unsigned long long) atmp,
117 (unsigned long long) piolen,
118 (unsigned long long) piolen << 1);
119 pioaddr = atmp;
120 piolen <<= 1;
121 }
122 }
123
124 if (!ret) {
125 int cookie;
126 ipath_cdbg(VERBOSE, "Setting mtrr for chip to WC "
127 "(addr %llx, len=0x%llx)\n",
128 (unsigned long long) pioaddr,
129 (unsigned long long) piolen);
130 cookie = mtrr_add(pioaddr, piolen, MTRR_TYPE_WRCOMB, 0);
131 if (cookie < 0) {
132 {
133 dev_info(&dd->pcidev->dev,
134 "mtrr_add() WC for PIO bufs "
135 "failed (%d)\n",
136 cookie);
137 ret = -EINVAL;
138 }
139 } else {
140 ipath_cdbg(VERBOSE, "Set mtrr for chip to WC, "
141 "cookie is %d\n", cookie);
142 dd->ipath_wc_cookie = cookie;
143 dd->ipath_wc_base = (unsigned long) pioaddr;
144 dd->ipath_wc_len = (unsigned long) piolen;
145 }
146 }
147
148 return ret;
149}
150
151
152
153
154
155void ipath_disable_wc(struct ipath_devdata *dd)
156{
157 if (dd->ipath_wc_cookie) {
158 int r;
159 ipath_cdbg(VERBOSE, "undoing WCCOMB on pio buffers\n");
160 r = mtrr_del(dd->ipath_wc_cookie, dd->ipath_wc_base,
161 dd->ipath_wc_len);
162 if (r < 0)
163 dev_info(&dd->pcidev->dev,
164 "mtrr_del(%lx, %lx, %lx) failed: %d\n",
165 dd->ipath_wc_cookie, dd->ipath_wc_base,
166 dd->ipath_wc_len, r);
167 dd->ipath_wc_cookie = 0;
168 }
169}
170
171
172
173
174
175
176
177
178
179
180
181int ipath_unordered_wc(void)
182{
183 return boot_cpu_data.x86_vendor != X86_VENDOR_AMD;
184}
185