diff options
author | Paul Mackerras <paulus@samba.org> | 2007-05-10 07:08:37 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-05-10 07:08:37 -0400 |
commit | 2ecf042ef530dd0943e41d84b6344f507941af3e (patch) | |
tree | 73100361dd74e3f80f14c7c81ba4675948983f44 /drivers/net/mlx4/reset.c | |
parent | 32a56ebb24f23da1bbaf24292acf85b6c04526ab (diff) | |
parent | de5603748af8bf7deac403e6ba92887f8d18e812 (diff) |
Merge branch 'linux-2.6'
Diffstat (limited to 'drivers/net/mlx4/reset.c')
-rw-r--r-- | drivers/net/mlx4/reset.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/drivers/net/mlx4/reset.c b/drivers/net/mlx4/reset.c new file mode 100644 index 000000000000..51eef8492e93 --- /dev/null +++ b/drivers/net/mlx4/reset.c | |||
@@ -0,0 +1,181 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006, 2007 Cisco Systems, 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 | #include <linux/init.h> | ||
34 | #include <linux/errno.h> | ||
35 | #include <linux/pci.h> | ||
36 | #include <linux/delay.h> | ||
37 | #include <linux/slab.h> | ||
38 | |||
39 | #include "mlx4.h" | ||
40 | |||
41 | int mlx4_reset(struct mlx4_dev *dev) | ||
42 | { | ||
43 | void __iomem *reset; | ||
44 | u32 *hca_header = NULL; | ||
45 | int pcie_cap; | ||
46 | u16 devctl; | ||
47 | u16 linkctl; | ||
48 | u16 vendor; | ||
49 | unsigned long end; | ||
50 | u32 sem; | ||
51 | int i; | ||
52 | int err = 0; | ||
53 | |||
54 | #define MLX4_RESET_BASE 0xf0000 | ||
55 | #define MLX4_RESET_SIZE 0x400 | ||
56 | #define MLX4_SEM_OFFSET 0x3fc | ||
57 | #define MLX4_RESET_OFFSET 0x10 | ||
58 | #define MLX4_RESET_VALUE swab32(1) | ||
59 | |||
60 | #define MLX4_SEM_TIMEOUT_JIFFIES (10 * HZ) | ||
61 | #define MLX4_RESET_TIMEOUT_JIFFIES (2 * HZ) | ||
62 | |||
63 | /* | ||
64 | * Reset the chip. This is somewhat ugly because we have to | ||
65 | * save off the PCI header before reset and then restore it | ||
66 | * after the chip reboots. We skip config space offsets 22 | ||
67 | * and 23 since those have a special meaning. | ||
68 | */ | ||
69 | |||
70 | /* Do we need to save off the full 4K PCI Express header?? */ | ||
71 | hca_header = kmalloc(256, GFP_KERNEL); | ||
72 | if (!hca_header) { | ||
73 | err = -ENOMEM; | ||
74 | mlx4_err(dev, "Couldn't allocate memory to save HCA " | ||
75 | "PCI header, aborting.\n"); | ||
76 | goto out; | ||
77 | } | ||
78 | |||
79 | pcie_cap = pci_find_capability(dev->pdev, PCI_CAP_ID_EXP); | ||
80 | |||
81 | for (i = 0; i < 64; ++i) { | ||
82 | if (i == 22 || i == 23) | ||
83 | continue; | ||
84 | if (pci_read_config_dword(dev->pdev, i * 4, hca_header + i)) { | ||
85 | err = -ENODEV; | ||
86 | mlx4_err(dev, "Couldn't save HCA " | ||
87 | "PCI header, aborting.\n"); | ||
88 | goto out; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | reset = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_RESET_BASE, | ||
93 | MLX4_RESET_SIZE); | ||
94 | if (!reset) { | ||
95 | err = -ENOMEM; | ||
96 | mlx4_err(dev, "Couldn't map HCA reset register, aborting.\n"); | ||
97 | goto out; | ||
98 | } | ||
99 | |||
100 | /* grab HW semaphore to lock out flash updates */ | ||
101 | end = jiffies + MLX4_SEM_TIMEOUT_JIFFIES; | ||
102 | do { | ||
103 | sem = readl(reset + MLX4_SEM_OFFSET); | ||
104 | if (!sem) | ||
105 | break; | ||
106 | |||
107 | msleep(1); | ||
108 | } while (time_before(jiffies, end)); | ||
109 | |||
110 | if (sem) { | ||
111 | mlx4_err(dev, "Failed to obtain HW semaphore, aborting\n"); | ||
112 | err = -EAGAIN; | ||
113 | iounmap(reset); | ||
114 | goto out; | ||
115 | } | ||
116 | |||
117 | /* actually hit reset */ | ||
118 | writel(MLX4_RESET_VALUE, reset + MLX4_RESET_OFFSET); | ||
119 | iounmap(reset); | ||
120 | |||
121 | end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES; | ||
122 | do { | ||
123 | if (!pci_read_config_word(dev->pdev, PCI_VENDOR_ID, &vendor) && | ||
124 | vendor != 0xffff) | ||
125 | break; | ||
126 | |||
127 | msleep(1); | ||
128 | } while (time_before(jiffies, end)); | ||
129 | |||
130 | if (vendor == 0xffff) { | ||
131 | err = -ENODEV; | ||
132 | mlx4_err(dev, "PCI device did not come back after reset, " | ||
133 | "aborting.\n"); | ||
134 | goto out; | ||
135 | } | ||
136 | |||
137 | /* Now restore the PCI headers */ | ||
138 | if (pcie_cap) { | ||
139 | devctl = hca_header[(pcie_cap + PCI_EXP_DEVCTL) / 4]; | ||
140 | if (pci_write_config_word(dev->pdev, pcie_cap + PCI_EXP_DEVCTL, | ||
141 | devctl)) { | ||
142 | err = -ENODEV; | ||
143 | mlx4_err(dev, "Couldn't restore HCA PCI Express " | ||
144 | "Device Control register, aborting.\n"); | ||
145 | goto out; | ||
146 | } | ||
147 | linkctl = hca_header[(pcie_cap + PCI_EXP_LNKCTL) / 4]; | ||
148 | if (pci_write_config_word(dev->pdev, pcie_cap + PCI_EXP_LNKCTL, | ||
149 | linkctl)) { | ||
150 | err = -ENODEV; | ||
151 | mlx4_err(dev, "Couldn't restore HCA PCI Express " | ||
152 | "Link control register, aborting.\n"); | ||
153 | goto out; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | for (i = 0; i < 16; ++i) { | ||
158 | if (i * 4 == PCI_COMMAND) | ||
159 | continue; | ||
160 | |||
161 | if (pci_write_config_dword(dev->pdev, i * 4, hca_header[i])) { | ||
162 | err = -ENODEV; | ||
163 | mlx4_err(dev, "Couldn't restore HCA reg %x, " | ||
164 | "aborting.\n", i); | ||
165 | goto out; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | if (pci_write_config_dword(dev->pdev, PCI_COMMAND, | ||
170 | hca_header[PCI_COMMAND / 4])) { | ||
171 | err = -ENODEV; | ||
172 | mlx4_err(dev, "Couldn't restore HCA COMMAND, " | ||
173 | "aborting.\n"); | ||
174 | goto out; | ||
175 | } | ||
176 | |||
177 | out: | ||
178 | kfree(hca_header); | ||
179 | |||
180 | return err; | ||
181 | } | ||