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