diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/infiniband/hw/mthca/mthca_reset.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/infiniband/hw/mthca/mthca_reset.c')
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_reset.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/mthca/mthca_reset.c b/drivers/infiniband/hw/mthca/mthca_reset.c new file mode 100644 index 000000000000..ce3fff7d02b7 --- /dev/null +++ b/drivers/infiniband/hw/mthca/mthca_reset.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Communications. 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 | * $Id: mthca_reset.c 1349 2004-12-16 21:09:43Z roland $ | ||
33 | */ | ||
34 | |||
35 | #include <linux/config.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/errno.h> | ||
38 | #include <linux/pci.h> | ||
39 | #include <linux/delay.h> | ||
40 | |||
41 | #include "mthca_dev.h" | ||
42 | #include "mthca_cmd.h" | ||
43 | |||
44 | int mthca_reset(struct mthca_dev *mdev) | ||
45 | { | ||
46 | int i; | ||
47 | int err = 0; | ||
48 | u32 *hca_header = NULL; | ||
49 | u32 *bridge_header = NULL; | ||
50 | struct pci_dev *bridge = NULL; | ||
51 | |||
52 | #define MTHCA_RESET_OFFSET 0xf0010 | ||
53 | #define MTHCA_RESET_VALUE swab32(1) | ||
54 | |||
55 | /* | ||
56 | * Reset the chip. This is somewhat ugly because we have to | ||
57 | * save off the PCI header before reset and then restore it | ||
58 | * after the chip reboots. We skip config space offsets 22 | ||
59 | * and 23 since those have a special meaning. | ||
60 | * | ||
61 | * To make matters worse, for Tavor (PCI-X HCA) we have to | ||
62 | * find the associated bridge device and save off its PCI | ||
63 | * header as well. | ||
64 | */ | ||
65 | |||
66 | if (mdev->hca_type == TAVOR) { | ||
67 | /* Look for the bridge -- its device ID will be 2 more | ||
68 | than HCA's device ID. */ | ||
69 | while ((bridge = pci_get_device(mdev->pdev->vendor, | ||
70 | mdev->pdev->device + 2, | ||
71 | bridge)) != NULL) { | ||
72 | if (bridge->hdr_type == PCI_HEADER_TYPE_BRIDGE && | ||
73 | bridge->subordinate == mdev->pdev->bus) { | ||
74 | mthca_dbg(mdev, "Found bridge: %s (%s)\n", | ||
75 | pci_pretty_name(bridge), pci_name(bridge)); | ||
76 | break; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | if (!bridge) { | ||
81 | /* | ||
82 | * Didn't find a bridge for a Tavor device -- | ||
83 | * assume we're in no-bridge mode and hope for | ||
84 | * the best. | ||
85 | */ | ||
86 | mthca_warn(mdev, "No bridge found for %s (%s)\n", | ||
87 | pci_pretty_name(mdev->pdev), pci_name(mdev->pdev)); | ||
88 | } | ||
89 | |||
90 | } | ||
91 | |||
92 | /* For Arbel do we need to save off the full 4K PCI Express header?? */ | ||
93 | hca_header = kmalloc(256, GFP_KERNEL); | ||
94 | if (!hca_header) { | ||
95 | err = -ENOMEM; | ||
96 | mthca_err(mdev, "Couldn't allocate memory to save HCA " | ||
97 | "PCI header, aborting.\n"); | ||
98 | goto out; | ||
99 | } | ||
100 | |||
101 | for (i = 0; i < 64; ++i) { | ||
102 | if (i == 22 || i == 23) | ||
103 | continue; | ||
104 | if (pci_read_config_dword(mdev->pdev, i * 4, hca_header + i)) { | ||
105 | err = -ENODEV; | ||
106 | mthca_err(mdev, "Couldn't save HCA " | ||
107 | "PCI header, aborting.\n"); | ||
108 | goto out; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | if (bridge) { | ||
113 | bridge_header = kmalloc(256, GFP_KERNEL); | ||
114 | if (!bridge_header) { | ||
115 | err = -ENOMEM; | ||
116 | mthca_err(mdev, "Couldn't allocate memory to save HCA " | ||
117 | "bridge PCI header, aborting.\n"); | ||
118 | goto out; | ||
119 | } | ||
120 | |||
121 | for (i = 0; i < 64; ++i) { | ||
122 | if (i == 22 || i == 23) | ||
123 | continue; | ||
124 | if (pci_read_config_dword(bridge, i * 4, bridge_header + i)) { | ||
125 | err = -ENODEV; | ||
126 | mthca_err(mdev, "Couldn't save HCA bridge " | ||
127 | "PCI header, aborting.\n"); | ||
128 | goto out; | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | /* actually hit reset */ | ||
134 | { | ||
135 | void __iomem *reset = ioremap(pci_resource_start(mdev->pdev, 0) + | ||
136 | MTHCA_RESET_OFFSET, 4); | ||
137 | |||
138 | if (!reset) { | ||
139 | err = -ENOMEM; | ||
140 | mthca_err(mdev, "Couldn't map HCA reset register, " | ||
141 | "aborting.\n"); | ||
142 | goto out; | ||
143 | } | ||
144 | |||
145 | writel(MTHCA_RESET_VALUE, reset); | ||
146 | iounmap(reset); | ||
147 | } | ||
148 | |||
149 | /* Docs say to wait one second before accessing device */ | ||
150 | msleep(1000); | ||
151 | |||
152 | /* Now wait for PCI device to start responding again */ | ||
153 | { | ||
154 | u32 v; | ||
155 | int c = 0; | ||
156 | |||
157 | for (c = 0; c < 100; ++c) { | ||
158 | if (pci_read_config_dword(bridge ? bridge : mdev->pdev, 0, &v)) { | ||
159 | err = -ENODEV; | ||
160 | mthca_err(mdev, "Couldn't access HCA after reset, " | ||
161 | "aborting.\n"); | ||
162 | goto out; | ||
163 | } | ||
164 | |||
165 | if (v != 0xffffffff) | ||
166 | goto good; | ||
167 | |||
168 | msleep(100); | ||
169 | } | ||
170 | |||
171 | err = -ENODEV; | ||
172 | mthca_err(mdev, "PCI device did not come back after reset, " | ||
173 | "aborting.\n"); | ||
174 | goto out; | ||
175 | } | ||
176 | |||
177 | good: | ||
178 | /* Now restore the PCI headers */ | ||
179 | if (bridge) { | ||
180 | /* | ||
181 | * Bridge control register is at 0x3e, so we'll | ||
182 | * naturally restore it last in this loop. | ||
183 | */ | ||
184 | for (i = 0; i < 16; ++i) { | ||
185 | if (i * 4 == PCI_COMMAND) | ||
186 | continue; | ||
187 | |||
188 | if (pci_write_config_dword(bridge, i * 4, bridge_header[i])) { | ||
189 | err = -ENODEV; | ||
190 | mthca_err(mdev, "Couldn't restore HCA bridge reg %x, " | ||
191 | "aborting.\n", i); | ||
192 | goto out; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | if (pci_write_config_dword(bridge, PCI_COMMAND, | ||
197 | bridge_header[PCI_COMMAND / 4])) { | ||
198 | err = -ENODEV; | ||
199 | mthca_err(mdev, "Couldn't restore HCA bridge COMMAND, " | ||
200 | "aborting.\n"); | ||
201 | goto out; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | for (i = 0; i < 16; ++i) { | ||
206 | if (i * 4 == PCI_COMMAND) | ||
207 | continue; | ||
208 | |||
209 | if (pci_write_config_dword(mdev->pdev, i * 4, hca_header[i])) { | ||
210 | err = -ENODEV; | ||
211 | mthca_err(mdev, "Couldn't restore HCA reg %x, " | ||
212 | "aborting.\n", i); | ||
213 | goto out; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | if (pci_write_config_dword(mdev->pdev, PCI_COMMAND, | ||
218 | hca_header[PCI_COMMAND / 4])) { | ||
219 | err = -ENODEV; | ||
220 | mthca_err(mdev, "Couldn't restore HCA COMMAND, " | ||
221 | "aborting.\n"); | ||
222 | goto out; | ||
223 | } | ||
224 | |||
225 | out: | ||
226 | if (bridge) | ||
227 | pci_dev_put(bridge); | ||
228 | kfree(bridge_header); | ||
229 | kfree(hca_header); | ||
230 | |||
231 | return err; | ||
232 | } | ||