aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
diff options
context:
space:
mode:
authorBryan O'Sullivan <bos@pathscale.com>2006-03-29 18:23:29 -0500
committerRoland Dreier <rolandd@cisco.com>2006-03-31 16:14:19 -0500
commit108ecf0d90655055d5a7db8d3a7239133b4d52b7 (patch)
tree95e3a20828478e7e66f1aa7e88e3b5cf17b93dfe /drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
parent097709fea03140b567bde8369f3ffafe33dfc1c6 (diff)
IB/ipath: misc driver support code
EEPROM support, interrupt handling, statistics gathering, and write combining management for x86_64. A note regarding i2c: The Atmel EEPROM hardware we use looks like an i2c device electrically, but is not i2c compliant at all from a functional perspective. We tried using the kernel's i2c support to talk to it, but failed. Normal i2c devices have a single 7-bit or 10-bit i2c address that they respond to. Valid 7-bit addresses range from 0x03 to 0x77. Addresses 0x00 to 0x02 and 0x78 to 0x7F are special reserved addresses (e.g. 0x00 is the "general call" address.) The Atmel device, on the other hand, responds to ALL addresses. It's designed to be the only device on a given i2c bus. A given i2c device address corresponds to the memory address within the i2c device itself. At least one reason why the linux core i2c stuff won't work for this is that it prohibits access to reserved addresses like 0x00, which are really valid addresses on the Atmel devices. Signed-off-by: Bryan O'Sullivan <bos@pathscale.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_wc_x86_64.c')
-rw-r--r--drivers/infiniband/hw/ipath/ipath_wc_x86_64.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
new file mode 100644
index 00000000000..adc5322f15c
--- /dev/null
+++ b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
@@ -0,0 +1,157 @@
1/*
2 * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32
33/*
34 * This file is conditionally built on x86_64 only. Otherwise weak symbol
35 * versions of the functions exported from here are used.
36 */
37
38#include <linux/pci.h>
39#include <asm/mtrr.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 */
51int 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 */
66 pioaddr = addr + dd->ipath_piobufbase;
67 piolen = (dd->ipath_piobcnt2k +
68 dd->ipath_piobcnt4k) *
69 ALIGN(dd->ipath_piobcnt2k +
70 dd->ipath_piobcnt4k, dd->ipath_palign);
71
72 for (bits = 0; !(piolen & (1ULL << bits)); bits++)
73 /* do nothing */ ;
74
75 if (piolen != (1ULL << bits)) {
76 piolen >>= bits;
77 while (piolen >>= 1)
78 bits++;
79 piolen = 1ULL << (bits + 1);
80 }
81 if (pioaddr & (piolen - 1)) {
82 u64 atmp;
83 ipath_dbg("pioaddr %llx not on right boundary for size "
84 "%llx, fixing\n",
85 (unsigned long long) pioaddr,
86 (unsigned long long) piolen);
87 atmp = pioaddr & ~(piolen - 1);
88 if (atmp < addr || (atmp + piolen) > (addr + len)) {
89 ipath_dev_err(dd, "No way to align address/size "
90 "(%llx/%llx), no WC mtrr\n",
91 (unsigned long long) atmp,
92 (unsigned long long) piolen << 1);
93 ret = -ENODEV;
94 } else {
95 ipath_dbg("changing WC base from %llx to %llx, "
96 "len from %llx to %llx\n",
97 (unsigned long long) pioaddr,
98 (unsigned long long) atmp,
99 (unsigned long long) piolen,
100 (unsigned long long) piolen << 1);
101 pioaddr = atmp;
102 piolen <<= 1;
103 }
104 }
105
106 if (!ret) {
107 int cookie;
108 ipath_cdbg(VERBOSE, "Setting mtrr for chip to WC "
109 "(addr %llx, len=0x%llx)\n",
110 (unsigned long long) pioaddr,
111 (unsigned long long) piolen);
112 cookie = mtrr_add(pioaddr, piolen, MTRR_TYPE_WRCOMB, 0);
113 if (cookie < 0) {
114 {
115 dev_info(&dd->pcidev->dev,
116 "mtrr_add() WC for PIO bufs "
117 "failed (%d)\n",
118 cookie);
119 ret = -EINVAL;
120 }
121 } else {
122 ipath_cdbg(VERBOSE, "Set mtrr for chip to WC, "
123 "cookie is %d\n", cookie);
124 dd->ipath_wc_cookie = cookie;
125 }
126 }
127
128 return ret;
129}
130
131/**
132 * ipath_disable_wc - disable write combining for MMIO writes to the device
133 * @dd: infinipath device
134 */
135void ipath_disable_wc(struct ipath_devdata *dd)
136{
137 if (dd->ipath_wc_cookie) {
138 ipath_cdbg(VERBOSE, "undoing WCCOMB on pio buffers\n");
139 mtrr_del(dd->ipath_wc_cookie, 0, 0);
140 dd->ipath_wc_cookie = 0;
141 }
142}
143
144/**
145 * ipath_unordered_wc - indicate whether write combining is ordered
146 *
147 * Because our performance depends on our ability to do write combining mmio
148 * writes in the most efficient way, we need to know if we are on an Intel
149 * or AMD x86_64 processor. AMD x86_64 processors flush WC buffers out in
150 * the order completed, and so no special flushing is required to get
151 * correct ordering. Intel processors, however, will flush write buffers
152 * out in "random" orders, and so explicit ordering is needed at times.
153 */
154int ipath_unordered_wc(void)
155{
156 return boot_cpu_data.x86_vendor != X86_VENDOR_AMD;
157}