Commit | Line | Data |
---|---|---|
3d396eb1 AK |
1 | /* |
2 | * Copyright (C) 2003 - 2006 NetXen, Inc. | |
3 | * All rights reserved. | |
80922fbc | 4 | * |
3d396eb1 AK |
5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License | |
7 | * as published by the Free Software Foundation; either version 2 | |
8 | * of the License, or (at your option) any later version. | |
cb8011ad | 9 | * |
3d396eb1 AK |
10 | * This program is distributed in the hope that it will be useful, but |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
cb8011ad | 14 | * |
3d396eb1 AK |
15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |
18 | * MA 02111-1307, USA. | |
80922fbc | 19 | * |
3d396eb1 AK |
20 | * The full GNU General Public License is included in this distribution |
21 | * in the file called LICENSE. | |
80922fbc | 22 | * |
3d396eb1 AK |
23 | * Contact Information: |
24 | * info@netxen.com | |
25 | * NetXen, | |
26 | * 3965 Freedom Circle, Fourth floor, | |
27 | * Santa Clara, CA 95054 | |
28 | * | |
29 | * | |
30 | * Provides access to the Network Interface Unit h/w block. | |
31 | * | |
32 | */ | |
33 | ||
34 | #include "netxen_nic.h" | |
cb8011ad AK |
35 | |
36 | #define NETXEN_GB_MAC_SOFT_RESET 0x80000000 | |
37 | #define NETXEN_GB_MAC_RESET_PROT_BLK 0x000F0000 | |
38 | #define NETXEN_GB_MAC_ENABLE_TX_RX 0x00000005 | |
39 | #define NETXEN_GB_MAC_PAUSED_FRMS 0x00000020 | |
40 | ||
41 | static long phy_lock_timeout = 100000000; | |
42 | ||
993fb90c | 43 | static int phy_lock(struct netxen_adapter *adapter) |
cb8011ad AK |
44 | { |
45 | int i; | |
46 | int done = 0, timeout = 0; | |
47 | ||
48 | while (!done) { | |
3ce06a32 DP |
49 | done = netxen_nic_reg_read(adapter, |
50 | NETXEN_PCIE_REG(PCIE_SEM3_LOCK)); | |
cb8011ad AK |
51 | if (done == 1) |
52 | break; | |
53 | if (timeout >= phy_lock_timeout) { | |
54 | return -1; | |
55 | } | |
56 | timeout++; | |
57 | if (!in_atomic()) | |
58 | schedule(); | |
59 | else { | |
60 | for (i = 0; i < 20; i++) | |
61 | cpu_relax(); | |
62 | } | |
63 | } | |
64 | ||
3ce06a32 DP |
65 | netxen_crb_writelit_adapter(adapter, |
66 | NETXEN_PHY_LOCK_ID, PHY_LOCK_DRIVER); | |
cb8011ad AK |
67 | return 0; |
68 | } | |
69 | ||
993fb90c | 70 | static int phy_unlock(struct netxen_adapter *adapter) |
cb8011ad | 71 | { |
3ce06a32 | 72 | adapter->pci_read_immediate(adapter, NETXEN_PCIE_REG(PCIE_SEM3_UNLOCK)); |
ed25ffa1 | 73 | |
cb8011ad AK |
74 | return 0; |
75 | } | |
3d396eb1 | 76 | |
4790654c | 77 | /* |
3d396eb1 AK |
78 | * netxen_niu_gbe_phy_read - read a register from the GbE PHY via |
79 | * mii management interface. | |
80 | * | |
81 | * Note: The MII management interface goes through port 0. | |
cb8011ad | 82 | * Individual phys are addressed as follows: |
3d396eb1 AK |
83 | * @param phy [15:8] phy id |
84 | * @param reg [7:0] register number | |
85 | * | |
86 | * @returns 0 on success | |
cb8011ad | 87 | * -1 on error |
3d396eb1 AK |
88 | * |
89 | */ | |
4790654c | 90 | int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, |
13ba9c77 | 91 | __u32 * readval) |
3d396eb1 AK |
92 | { |
93 | long timeout = 0; | |
94 | long result = 0; | |
95 | long restore = 0; | |
3276fbad | 96 | long phy = adapter->physical_port; |
a608ab9c AV |
97 | __u32 address; |
98 | __u32 command; | |
99 | __u32 status; | |
100 | __u32 mac_cfg0; | |
3d396eb1 | 101 | |
ed25ffa1 | 102 | if (phy_lock(adapter) != 0) { |
cb8011ad AK |
103 | return -1; |
104 | } | |
105 | ||
106 | /* | |
107 | * MII mgmt all goes through port 0 MAC interface, | |
108 | * so it cannot be in reset | |
109 | */ | |
110 | ||
3ce06a32 | 111 | if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), |
3d396eb1 AK |
112 | &mac_cfg0, 4)) |
113 | return -EIO; | |
114 | if (netxen_gb_get_soft_reset(mac_cfg0)) { | |
a608ab9c | 115 | __u32 temp; |
3d396eb1 AK |
116 | temp = 0; |
117 | netxen_gb_tx_reset_pb(temp); | |
118 | netxen_gb_rx_reset_pb(temp); | |
119 | netxen_gb_tx_reset_mac(temp); | |
120 | netxen_gb_rx_reset_mac(temp); | |
3ce06a32 | 121 | if (adapter->hw_write_wx(adapter, |
3d396eb1 AK |
122 | NETXEN_NIU_GB_MAC_CONFIG_0(0), |
123 | &temp, 4)) | |
124 | return -EIO; | |
125 | restore = 1; | |
126 | } | |
127 | ||
3d396eb1 AK |
128 | address = 0; |
129 | netxen_gb_mii_mgmt_reg_addr(address, reg); | |
130 | netxen_gb_mii_mgmt_phy_addr(address, phy); | |
3ce06a32 | 131 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), |
3d396eb1 AK |
132 | &address, 4)) |
133 | return -EIO; | |
134 | command = 0; /* turn off any prior activity */ | |
3ce06a32 | 135 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), |
3d396eb1 AK |
136 | &command, 4)) |
137 | return -EIO; | |
138 | /* send read command */ | |
139 | netxen_gb_mii_mgmt_set_read_cycle(command); | |
3ce06a32 | 140 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), |
3d396eb1 AK |
141 | &command, 4)) |
142 | return -EIO; | |
143 | ||
144 | status = 0; | |
145 | do { | |
3ce06a32 | 146 | if (adapter->hw_read_wx(adapter, |
3d396eb1 AK |
147 | NETXEN_NIU_GB_MII_MGMT_INDICATE(0), |
148 | &status, 4)) | |
149 | return -EIO; | |
150 | timeout++; | |
151 | } while ((netxen_get_gb_mii_mgmt_busy(status) | |
152 | || netxen_get_gb_mii_mgmt_notvalid(status)) | |
153 | && (timeout++ < NETXEN_NIU_PHY_WAITMAX)); | |
154 | ||
155 | if (timeout < NETXEN_NIU_PHY_WAITMAX) { | |
3ce06a32 | 156 | if (adapter->hw_read_wx(adapter, |
3d396eb1 AK |
157 | NETXEN_NIU_GB_MII_MGMT_STATUS(0), |
158 | readval, 4)) | |
159 | return -EIO; | |
160 | result = 0; | |
161 | } else | |
162 | result = -1; | |
163 | ||
164 | if (restore) | |
3ce06a32 | 165 | if (adapter->hw_write_wx(adapter, |
3d396eb1 AK |
166 | NETXEN_NIU_GB_MAC_CONFIG_0(0), |
167 | &mac_cfg0, 4)) | |
168 | return -EIO; | |
ed25ffa1 | 169 | phy_unlock(adapter); |
3d396eb1 AK |
170 | return result; |
171 | } | |
172 | ||
4790654c | 173 | /* |
3d396eb1 AK |
174 | * netxen_niu_gbe_phy_write - write a register to the GbE PHY via |
175 | * mii management interface. | |
176 | * | |
177 | * Note: The MII management interface goes through port 0. | |
cb8011ad | 178 | * Individual phys are addressed as follows: |
3d396eb1 AK |
179 | * @param phy [15:8] phy id |
180 | * @param reg [7:0] register number | |
181 | * | |
182 | * @returns 0 on success | |
cb8011ad | 183 | * -1 on error |
3d396eb1 AK |
184 | * |
185 | */ | |
4790654c | 186 | int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, |
13ba9c77 | 187 | __u32 val) |
3d396eb1 AK |
188 | { |
189 | long timeout = 0; | |
190 | long result = 0; | |
191 | long restore = 0; | |
3276fbad | 192 | long phy = adapter->physical_port; |
a608ab9c AV |
193 | __u32 address; |
194 | __u32 command; | |
195 | __u32 status; | |
196 | __u32 mac_cfg0; | |
3d396eb1 | 197 | |
cb8011ad AK |
198 | /* |
199 | * MII mgmt all goes through port 0 MAC interface, so it | |
200 | * cannot be in reset | |
201 | */ | |
202 | ||
3ce06a32 | 203 | if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), |
3d396eb1 AK |
204 | &mac_cfg0, 4)) |
205 | return -EIO; | |
206 | if (netxen_gb_get_soft_reset(mac_cfg0)) { | |
a608ab9c | 207 | __u32 temp; |
3d396eb1 AK |
208 | temp = 0; |
209 | netxen_gb_tx_reset_pb(temp); | |
210 | netxen_gb_rx_reset_pb(temp); | |
211 | netxen_gb_tx_reset_mac(temp); | |
212 | netxen_gb_rx_reset_mac(temp); | |
213 | ||
3ce06a32 | 214 | if (adapter->hw_write_wx(adapter, |
3d396eb1 AK |
215 | NETXEN_NIU_GB_MAC_CONFIG_0(0), |
216 | &temp, 4)) | |
217 | return -EIO; | |
218 | restore = 1; | |
219 | } | |
220 | ||
221 | command = 0; /* turn off any prior activity */ | |
3ce06a32 | 222 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), |
3d396eb1 AK |
223 | &command, 4)) |
224 | return -EIO; | |
225 | ||
226 | address = 0; | |
227 | netxen_gb_mii_mgmt_reg_addr(address, reg); | |
228 | netxen_gb_mii_mgmt_phy_addr(address, phy); | |
3ce06a32 | 229 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), |
3d396eb1 AK |
230 | &address, 4)) |
231 | return -EIO; | |
232 | ||
3ce06a32 | 233 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_CTRL(0), |
3d396eb1 AK |
234 | &val, 4)) |
235 | return -EIO; | |
236 | ||
237 | status = 0; | |
238 | do { | |
3ce06a32 | 239 | if (adapter->hw_read_wx(adapter, |
3d396eb1 AK |
240 | NETXEN_NIU_GB_MII_MGMT_INDICATE(0), |
241 | &status, 4)) | |
242 | return -EIO; | |
243 | timeout++; | |
244 | } while ((netxen_get_gb_mii_mgmt_busy(status)) | |
245 | && (timeout++ < NETXEN_NIU_PHY_WAITMAX)); | |
246 | ||
247 | if (timeout < NETXEN_NIU_PHY_WAITMAX) | |
248 | result = 0; | |
249 | else | |
250 | result = -EIO; | |
251 | ||
252 | /* restore the state of port 0 MAC in case we tampered with it */ | |
253 | if (restore) | |
3ce06a32 | 254 | if (adapter->hw_write_wx(adapter, |
3d396eb1 AK |
255 | NETXEN_NIU_GB_MAC_CONFIG_0(0), |
256 | &mac_cfg0, 4)) | |
257 | return -EIO; | |
258 | ||
259 | return result; | |
260 | } | |
261 | ||
13ba9c77 | 262 | int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter) |
3d396eb1 AK |
263 | { |
264 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x3f); | |
265 | return 0; | |
266 | } | |
267 | ||
13ba9c77 | 268 | int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter) |
3d396eb1 AK |
269 | { |
270 | int result = 0; | |
a608ab9c | 271 | __u32 enable = 0; |
3d396eb1 AK |
272 | netxen_set_phy_int_link_status_changed(enable); |
273 | netxen_set_phy_int_autoneg_completed(enable); | |
274 | netxen_set_phy_int_speed_changed(enable); | |
275 | ||
276 | if (0 != | |
4790654c | 277 | netxen_niu_gbe_phy_write(adapter, |
3d396eb1 AK |
278 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, |
279 | enable)) | |
280 | result = -EIO; | |
281 | ||
282 | return result; | |
283 | } | |
284 | ||
13ba9c77 | 285 | int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter) |
3d396eb1 AK |
286 | { |
287 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x7f); | |
288 | return 0; | |
289 | } | |
290 | ||
13ba9c77 | 291 | int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter) |
3d396eb1 AK |
292 | { |
293 | int result = 0; | |
294 | if (0 != | |
13ba9c77 | 295 | netxen_niu_gbe_phy_write(adapter, |
3d396eb1 AK |
296 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, 0)) |
297 | result = -EIO; | |
298 | ||
299 | return result; | |
300 | } | |
301 | ||
993fb90c | 302 | #if 0 |
13ba9c77 | 303 | int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter) |
3d396eb1 AK |
304 | { |
305 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1); | |
306 | return 0; | |
307 | } | |
993fb90c | 308 | #endif /* 0 */ |
3d396eb1 | 309 | |
993fb90c | 310 | static int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter) |
3d396eb1 AK |
311 | { |
312 | int result = 0; | |
313 | if (0 != | |
4790654c | 314 | netxen_niu_gbe_phy_write(adapter, |
3d396eb1 AK |
315 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, |
316 | -EIO)) | |
317 | result = -EIO; | |
318 | ||
319 | return result; | |
320 | } | |
321 | ||
4790654c | 322 | /* |
3d396eb1 AK |
323 | * netxen_niu_gbe_set_mii_mode- Set 10/100 Mbit Mode for GbE MAC |
324 | * | |
325 | */ | |
993fb90c AB |
326 | static void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, |
327 | int port, long enable) | |
3d396eb1 AK |
328 | { |
329 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2); | |
330 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
331 | 0x80000000); | |
332 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
333 | 0x0000f0025); | |
334 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), | |
335 | 0xf1ff); | |
336 | netxen_crb_writelit_adapter(adapter, | |
337 | NETXEN_NIU_GB0_GMII_MODE + (port << 3), 0); | |
338 | netxen_crb_writelit_adapter(adapter, | |
339 | NETXEN_NIU_GB0_MII_MODE + (port << 3), 1); | |
340 | netxen_crb_writelit_adapter(adapter, | |
341 | (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); | |
342 | netxen_crb_writelit_adapter(adapter, | |
343 | NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); | |
344 | ||
345 | if (enable) { | |
4790654c JG |
346 | /* |
347 | * Do NOT enable flow control until a suitable solution for | |
348 | * shutting down pause frames is found. | |
3d396eb1 AK |
349 | */ |
350 | netxen_crb_writelit_adapter(adapter, | |
351 | NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
352 | 0x5); | |
353 | } | |
354 | ||
13ba9c77 | 355 | if (netxen_niu_gbe_enable_phy_interrupts(adapter)) |
3d396eb1 | 356 | printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); |
13ba9c77 | 357 | if (netxen_niu_gbe_clear_phy_interrupts(adapter)) |
3d396eb1 AK |
358 | printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); |
359 | } | |
360 | ||
4790654c | 361 | /* |
3d396eb1 AK |
362 | * netxen_niu_gbe_set_gmii_mode- Set GbE Mode for GbE MAC |
363 | */ | |
993fb90c AB |
364 | static void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, |
365 | int port, long enable) | |
3d396eb1 AK |
366 | { |
367 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2); | |
368 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
369 | 0x80000000); | |
370 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
371 | 0x0000f0025); | |
372 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), | |
373 | 0xf2ff); | |
374 | netxen_crb_writelit_adapter(adapter, | |
375 | NETXEN_NIU_GB0_MII_MODE + (port << 3), 0); | |
376 | netxen_crb_writelit_adapter(adapter, | |
377 | NETXEN_NIU_GB0_GMII_MODE + (port << 3), 1); | |
378 | netxen_crb_writelit_adapter(adapter, | |
379 | (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); | |
380 | netxen_crb_writelit_adapter(adapter, | |
381 | NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); | |
382 | ||
383 | if (enable) { | |
4790654c JG |
384 | /* |
385 | * Do NOT enable flow control until a suitable solution for | |
386 | * shutting down pause frames is found. | |
3d396eb1 AK |
387 | */ |
388 | netxen_crb_writelit_adapter(adapter, | |
389 | NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
390 | 0x5); | |
391 | } | |
392 | ||
13ba9c77 | 393 | if (netxen_niu_gbe_enable_phy_interrupts(adapter)) |
3d396eb1 | 394 | printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); |
13ba9c77 | 395 | if (netxen_niu_gbe_clear_phy_interrupts(adapter)) |
3d396eb1 AK |
396 | printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); |
397 | } | |
398 | ||
399 | int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) | |
400 | { | |
401 | int result = 0; | |
a608ab9c | 402 | __u32 status; |
80922fbc | 403 | if (adapter->disable_phy_interrupts) |
13ba9c77 | 404 | adapter->disable_phy_interrupts(adapter); |
3d396eb1 AK |
405 | mdelay(2); |
406 | ||
407 | if (0 == | |
13ba9c77 | 408 | netxen_niu_gbe_phy_read(adapter, |
3d396eb1 | 409 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, |
a608ab9c | 410 | &status)) { |
3d396eb1 AK |
411 | if (netxen_get_phy_link(status)) { |
412 | if (netxen_get_phy_speed(status) == 2) { | |
413 | netxen_niu_gbe_set_gmii_mode(adapter, port, 1); | |
414 | } else if ((netxen_get_phy_speed(status) == 1) | |
415 | || (netxen_get_phy_speed(status) == 0)) { | |
416 | netxen_niu_gbe_set_mii_mode(adapter, port, 1); | |
417 | } else { | |
418 | result = -1; | |
419 | } | |
420 | ||
421 | } else { | |
cb8011ad AK |
422 | /* |
423 | * We don't have link. Cable must be unconnected. | |
424 | * Enable phy interrupts so we take action when | |
425 | * plugged in. | |
426 | */ | |
427 | ||
3d396eb1 AK |
428 | netxen_crb_writelit_adapter(adapter, |
429 | NETXEN_NIU_GB_MAC_CONFIG_0 | |
cb8011ad AK |
430 | (port), |
431 | NETXEN_GB_MAC_SOFT_RESET); | |
3d396eb1 AK |
432 | netxen_crb_writelit_adapter(adapter, |
433 | NETXEN_NIU_GB_MAC_CONFIG_0 | |
cb8011ad AK |
434 | (port), |
435 | NETXEN_GB_MAC_RESET_PROT_BLK | |
436 | | NETXEN_GB_MAC_ENABLE_TX_RX | |
437 | | | |
438 | NETXEN_GB_MAC_PAUSED_FRMS); | |
13ba9c77 | 439 | if (netxen_niu_gbe_clear_phy_interrupts(adapter)) |
3d396eb1 AK |
440 | printk(KERN_ERR PFX |
441 | "ERROR clearing PHY interrupts\n"); | |
13ba9c77 | 442 | if (netxen_niu_gbe_enable_phy_interrupts(adapter)) |
3d396eb1 AK |
443 | printk(KERN_ERR PFX |
444 | "ERROR enabling PHY interrupts\n"); | |
13ba9c77 | 445 | if (netxen_niu_gbe_clear_phy_interrupts(adapter)) |
3d396eb1 AK |
446 | printk(KERN_ERR PFX |
447 | "ERROR clearing PHY interrupts\n"); | |
448 | result = -1; | |
449 | } | |
450 | } else { | |
451 | result = -EIO; | |
452 | } | |
453 | return result; | |
454 | } | |
455 | ||
cb8011ad AK |
456 | int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) |
457 | { | |
3276fbad | 458 | u32 portnum = adapter->physical_port; |
6c80b18d MT |
459 | |
460 | netxen_crb_writelit_adapter(adapter, | |
3e2facef | 461 | NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), 0x1447); |
6c80b18d | 462 | netxen_crb_writelit_adapter(adapter, |
3e2facef | 463 | NETXEN_NIU_XGE_CONFIG_0+(0x10000*portnum), 0x5); |
cb8011ad | 464 | |
6c80b18d | 465 | return 0; |
cb8011ad AK |
466 | } |
467 | ||
993fb90c | 468 | #if 0 |
4790654c | 469 | /* |
3d396eb1 AK |
470 | * netxen_niu_gbe_handle_phy_interrupt - Handles GbE PHY interrupts |
471 | * @param enable 0 means don't enable the port | |
cb8011ad | 472 | * 1 means enable (or re-enable) the port |
3d396eb1 AK |
473 | */ |
474 | int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, | |
475 | int port, long enable) | |
476 | { | |
477 | int result = 0; | |
a608ab9c | 478 | __u32 int_src; |
3d396eb1 AK |
479 | |
480 | printk(KERN_INFO PFX "NETXEN: Handling PHY interrupt on port %d" | |
481 | " (device enable = %d)\n", (int)port, (int)enable); | |
482 | ||
cb8011ad AK |
483 | /* |
484 | * The read of the PHY INT status will clear the pending | |
485 | * interrupt status | |
486 | */ | |
13ba9c77 | 487 | if (netxen_niu_gbe_phy_read(adapter, |
3d396eb1 AK |
488 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, |
489 | &int_src) != 0) | |
490 | result = -EINVAL; | |
491 | else { | |
492 | printk(KERN_INFO PFX "PHY Interrupt source = 0x%x \n", int_src); | |
493 | if (netxen_get_phy_int_jabber(int_src)) | |
494 | printk(KERN_INFO PFX "jabber Interrupt "); | |
495 | if (netxen_get_phy_int_polarity_changed(int_src)) | |
496 | printk(KERN_INFO PFX "polarity changed "); | |
497 | if (netxen_get_phy_int_energy_detect(int_src)) | |
498 | printk(KERN_INFO PFX "energy detect \n"); | |
499 | if (netxen_get_phy_int_downshift(int_src)) | |
500 | printk(KERN_INFO PFX "downshift \n"); | |
501 | if (netxen_get_phy_int_mdi_xover_changed(int_src)) | |
502 | printk(KERN_INFO PFX "mdi_xover_changed "); | |
503 | if (netxen_get_phy_int_fifo_over_underflow(int_src)) | |
504 | printk(KERN_INFO PFX "fifo_over_underflow "); | |
505 | if (netxen_get_phy_int_false_carrier(int_src)) | |
506 | printk(KERN_INFO PFX "false_carrier "); | |
507 | if (netxen_get_phy_int_symbol_error(int_src)) | |
508 | printk(KERN_INFO PFX "symbol_error "); | |
509 | if (netxen_get_phy_int_autoneg_completed(int_src)) | |
510 | printk(KERN_INFO PFX "autoneg_completed "); | |
511 | if (netxen_get_phy_int_page_received(int_src)) | |
512 | printk(KERN_INFO PFX "page_received "); | |
513 | if (netxen_get_phy_int_duplex_changed(int_src)) | |
514 | printk(KERN_INFO PFX "duplex_changed "); | |
515 | if (netxen_get_phy_int_autoneg_error(int_src)) | |
516 | printk(KERN_INFO PFX "autoneg_error "); | |
517 | if ((netxen_get_phy_int_speed_changed(int_src)) | |
518 | || (netxen_get_phy_int_link_status_changed(int_src))) { | |
a608ab9c | 519 | __u32 status; |
3d396eb1 AK |
520 | |
521 | printk(KERN_INFO PFX | |
522 | "speed_changed or link status changed"); | |
523 | if (netxen_niu_gbe_phy_read | |
13ba9c77 | 524 | (adapter, |
3d396eb1 AK |
525 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, |
526 | &status) == 0) { | |
527 | if (netxen_get_phy_speed(status) == 2) { | |
528 | printk | |
529 | (KERN_INFO PFX "Link speed changed" | |
530 | " to 1000 Mbps\n"); | |
531 | netxen_niu_gbe_set_gmii_mode(adapter, | |
532 | port, | |
533 | enable); | |
534 | } else if (netxen_get_phy_speed(status) == 1) { | |
535 | printk | |
536 | (KERN_INFO PFX "Link speed changed" | |
537 | " to 100 Mbps\n"); | |
538 | netxen_niu_gbe_set_mii_mode(adapter, | |
539 | port, | |
540 | enable); | |
541 | } else if (netxen_get_phy_speed(status) == 0) { | |
542 | printk | |
543 | (KERN_INFO PFX "Link speed changed" | |
544 | " to 10 Mbps\n"); | |
545 | netxen_niu_gbe_set_mii_mode(adapter, | |
546 | port, | |
547 | enable); | |
548 | } else { | |
5bc51424 JP |
549 | printk(KERN_ERR PFX "ERROR reading " |
550 | "PHY status. Invalid speed.\n"); | |
3d396eb1 AK |
551 | result = -1; |
552 | } | |
553 | } else { | |
554 | printk(KERN_ERR PFX | |
555 | "ERROR reading PHY status.\n"); | |
556 | result = -1; | |
557 | } | |
558 | ||
559 | } | |
560 | printk(KERN_INFO "\n"); | |
561 | } | |
562 | return result; | |
563 | } | |
993fb90c | 564 | #endif /* 0 */ |
3d396eb1 AK |
565 | |
566 | /* | |
567 | * Return the current station MAC address. | |
568 | * Note that the passed-in value must already be in network byte order. | |
569 | */ | |
993fb90c AB |
570 | static int netxen_niu_macaddr_get(struct netxen_adapter *adapter, |
571 | netxen_ethernet_macaddr_t * addr) | |
3d396eb1 | 572 | { |
a608ab9c AV |
573 | u32 stationhigh; |
574 | u32 stationlow; | |
3276fbad | 575 | int phy = adapter->physical_port; |
a608ab9c | 576 | u8 val[8]; |
3d396eb1 AK |
577 | |
578 | if (addr == NULL) | |
579 | return -EINVAL; | |
580 | if ((phy < 0) || (phy > 3)) | |
581 | return -EINVAL; | |
582 | ||
3ce06a32 | 583 | if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), |
3d396eb1 AK |
584 | &stationhigh, 4)) |
585 | return -EIO; | |
3ce06a32 | 586 | if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), |
3d396eb1 AK |
587 | &stationlow, 4)) |
588 | return -EIO; | |
a608ab9c AV |
589 | ((__le32 *)val)[1] = cpu_to_le32(stationhigh); |
590 | ((__le32 *)val)[0] = cpu_to_le32(stationlow); | |
3d396eb1 | 591 | |
a608ab9c | 592 | memcpy(addr, val + 2, 6); |
3d396eb1 AK |
593 | |
594 | return 0; | |
595 | } | |
596 | ||
597 | /* | |
598 | * Set the station MAC address. | |
599 | * Note that the passed-in value must already be in network byte order. | |
600 | */ | |
3176ff3e | 601 | int netxen_niu_macaddr_set(struct netxen_adapter *adapter, |
3d396eb1 AK |
602 | netxen_ethernet_macaddr_t addr) |
603 | { | |
a608ab9c AV |
604 | u8 temp[4]; |
605 | u32 val; | |
3276fbad | 606 | int phy = adapter->physical_port; |
ed25ffa1 | 607 | unsigned char mac_addr[6]; |
cb8011ad | 608 | int i; |
0795af57 | 609 | DECLARE_MAC_BUF(mac); |
cb8011ad AK |
610 | |
611 | for (i = 0; i < 10; i++) { | |
a608ab9c AV |
612 | temp[0] = temp[1] = 0; |
613 | memcpy(temp + 2, addr, 2); | |
614 | val = le32_to_cpu(*(__le32 *)temp); | |
3ce06a32 DP |
615 | if (adapter->hw_write_wx(adapter, |
616 | NETXEN_NIU_GB_STATION_ADDR_1(phy), &val, 4)) | |
cb8011ad | 617 | return -EIO; |
3d396eb1 | 618 | |
a608ab9c AV |
619 | memcpy(temp, ((u8 *) addr) + 2, sizeof(__le32)); |
620 | val = le32_to_cpu(*(__le32 *)temp); | |
3ce06a32 DP |
621 | if (adapter->hw_write_wx(adapter, |
622 | NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4)) | |
cb8011ad | 623 | return -2; |
3d396eb1 | 624 | |
4790654c | 625 | netxen_niu_macaddr_get(adapter, |
cb8011ad | 626 | (netxen_ethernet_macaddr_t *) mac_addr); |
ed25ffa1 | 627 | if (memcmp(mac_addr, addr, 6) == 0) |
cb8011ad AK |
628 | break; |
629 | } | |
3d396eb1 | 630 | |
cb8011ad AK |
631 | if (i == 10) { |
632 | printk(KERN_ERR "%s: cannot set Mac addr for %s\n", | |
3176ff3e | 633 | netxen_nic_driver_name, adapter->netdev->name); |
0795af57 JP |
634 | printk(KERN_ERR "MAC address set: %s.\n", |
635 | print_mac(mac, addr)); | |
636 | printk(KERN_ERR "MAC address get: %s.\n", | |
637 | print_mac(mac, mac_addr)); | |
cb8011ad | 638 | } |
3d396eb1 AK |
639 | return 0; |
640 | } | |
641 | ||
993fb90c | 642 | #if 0 |
3d396eb1 AK |
643 | /* Enable a GbE interface */ |
644 | int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter, | |
645 | int port, netxen_niu_gbe_ifmode_t mode) | |
646 | { | |
a608ab9c AV |
647 | __u32 mac_cfg0; |
648 | __u32 mac_cfg1; | |
649 | __u32 mii_cfg; | |
3d396eb1 AK |
650 | |
651 | if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) | |
652 | return -EINVAL; | |
653 | ||
654 | mac_cfg0 = 0; | |
655 | netxen_gb_soft_reset(mac_cfg0); | |
3ce06a32 | 656 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), |
3d396eb1 AK |
657 | &mac_cfg0, 4)) |
658 | return -EIO; | |
659 | mac_cfg0 = 0; | |
660 | netxen_gb_enable_tx(mac_cfg0); | |
661 | netxen_gb_enable_rx(mac_cfg0); | |
662 | netxen_gb_unset_rx_flowctl(mac_cfg0); | |
663 | netxen_gb_tx_reset_pb(mac_cfg0); | |
664 | netxen_gb_rx_reset_pb(mac_cfg0); | |
665 | netxen_gb_tx_reset_mac(mac_cfg0); | |
666 | netxen_gb_rx_reset_mac(mac_cfg0); | |
667 | ||
3ce06a32 | 668 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), |
3d396eb1 AK |
669 | &mac_cfg0, 4)) |
670 | return -EIO; | |
671 | mac_cfg1 = 0; | |
672 | netxen_gb_set_preamblelen(mac_cfg1, 0xf); | |
673 | netxen_gb_set_duplex(mac_cfg1); | |
674 | netxen_gb_set_crc_enable(mac_cfg1); | |
675 | netxen_gb_set_padshort(mac_cfg1); | |
676 | netxen_gb_set_checklength(mac_cfg1); | |
677 | netxen_gb_set_hugeframes(mac_cfg1); | |
678 | ||
679 | if (mode == NETXEN_NIU_10_100_MB) { | |
680 | netxen_gb_set_intfmode(mac_cfg1, 1); | |
3ce06a32 | 681 | if (adapter->hw_write_wx(adapter, |
3d396eb1 AK |
682 | NETXEN_NIU_GB_MAC_CONFIG_1(port), |
683 | &mac_cfg1, 4)) | |
684 | return -EIO; | |
685 | ||
686 | /* set mii mode */ | |
687 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_GMII_MODE + | |
688 | (port << 3), 0); | |
689 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_MII_MODE + | |
690 | (port << 3), 1); | |
691 | ||
692 | } else if (mode == NETXEN_NIU_1000_MB) { | |
693 | netxen_gb_set_intfmode(mac_cfg1, 2); | |
3ce06a32 | 694 | if (adapter->hw_write_wx(adapter, |
3d396eb1 AK |
695 | NETXEN_NIU_GB_MAC_CONFIG_1(port), |
696 | &mac_cfg1, 4)) | |
697 | return -EIO; | |
698 | /* set gmii mode */ | |
699 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_MII_MODE + | |
700 | (port << 3), 0); | |
701 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_GMII_MODE + | |
702 | (port << 3), 1); | |
703 | } | |
704 | mii_cfg = 0; | |
705 | netxen_gb_set_mii_mgmt_clockselect(mii_cfg, 7); | |
3ce06a32 | 706 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port), |
3d396eb1 AK |
707 | &mii_cfg, 4)) |
708 | return -EIO; | |
709 | mac_cfg0 = 0; | |
710 | netxen_gb_enable_tx(mac_cfg0); | |
711 | netxen_gb_enable_rx(mac_cfg0); | |
712 | netxen_gb_unset_rx_flowctl(mac_cfg0); | |
713 | netxen_gb_unset_tx_flowctl(mac_cfg0); | |
714 | ||
3ce06a32 | 715 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), |
3d396eb1 AK |
716 | &mac_cfg0, 4)) |
717 | return -EIO; | |
718 | return 0; | |
719 | } | |
993fb90c | 720 | #endif /* 0 */ |
3d396eb1 AK |
721 | |
722 | /* Disable a GbE interface */ | |
3176ff3e | 723 | int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter) |
3d396eb1 | 724 | { |
a608ab9c | 725 | __u32 mac_cfg0; |
3276fbad | 726 | u32 port = adapter->physical_port; |
3d396eb1 | 727 | |
287aa83d | 728 | if (port > NETXEN_NIU_MAX_GBE_PORTS) |
6c80b18d | 729 | return -EINVAL; |
3d396eb1 AK |
730 | mac_cfg0 = 0; |
731 | netxen_gb_soft_reset(mac_cfg0); | |
3ce06a32 | 732 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), |
3d396eb1 AK |
733 | &mac_cfg0, 4)) |
734 | return -EIO; | |
735 | return 0; | |
736 | } | |
737 | ||
738 | /* Disable an XG interface */ | |
3176ff3e | 739 | int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) |
3d396eb1 | 740 | { |
a608ab9c | 741 | __u32 mac_cfg; |
3276fbad | 742 | u32 port = adapter->physical_port; |
3d396eb1 | 743 | |
72b0a7a8 | 744 | if (port > NETXEN_NIU_MAX_XG_PORTS) |
6c80b18d | 745 | return -EINVAL; |
72b0a7a8 | 746 | |
3d396eb1 | 747 | mac_cfg = 0; |
3ce06a32 | 748 | if (adapter->hw_write_wx(adapter, |
72b0a7a8 | 749 | NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), &mac_cfg, 4)) |
3d396eb1 AK |
750 | return -EIO; |
751 | return 0; | |
752 | } | |
753 | ||
754 | /* Set promiscuous mode for a GbE interface */ | |
4790654c | 755 | int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, |
3d396eb1 AK |
756 | netxen_niu_prom_mode_t mode) |
757 | { | |
a608ab9c | 758 | __u32 reg; |
3276fbad | 759 | u32 port = adapter->physical_port; |
3d396eb1 | 760 | |
287aa83d | 761 | if (port > NETXEN_NIU_MAX_GBE_PORTS) |
3d396eb1 AK |
762 | return -EINVAL; |
763 | ||
764 | /* save previous contents */ | |
3ce06a32 | 765 | if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, |
3d396eb1 AK |
766 | ®, 4)) |
767 | return -EIO; | |
768 | if (mode == NETXEN_NIU_PROMISC_MODE) { | |
769 | switch (port) { | |
770 | case 0: | |
771 | netxen_clear_gb_drop_gb0(reg); | |
772 | break; | |
773 | case 1: | |
774 | netxen_clear_gb_drop_gb1(reg); | |
775 | break; | |
776 | case 2: | |
777 | netxen_clear_gb_drop_gb2(reg); | |
778 | break; | |
779 | case 3: | |
780 | netxen_clear_gb_drop_gb3(reg); | |
781 | break; | |
782 | default: | |
783 | return -EIO; | |
784 | } | |
785 | } else { | |
786 | switch (port) { | |
787 | case 0: | |
788 | netxen_set_gb_drop_gb0(reg); | |
789 | break; | |
790 | case 1: | |
791 | netxen_set_gb_drop_gb1(reg); | |
792 | break; | |
793 | case 2: | |
794 | netxen_set_gb_drop_gb2(reg); | |
795 | break; | |
796 | case 3: | |
797 | netxen_set_gb_drop_gb3(reg); | |
798 | break; | |
799 | default: | |
800 | return -EIO; | |
801 | } | |
802 | } | |
3ce06a32 | 803 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, |
3d396eb1 AK |
804 | ®, 4)) |
805 | return -EIO; | |
806 | return 0; | |
807 | } | |
808 | ||
809 | /* | |
810 | * Set the MAC address for an XG port | |
811 | * Note that the passed-in value must already be in network byte order. | |
812 | */ | |
3176ff3e | 813 | int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, |
3d396eb1 AK |
814 | netxen_ethernet_macaddr_t addr) |
815 | { | |
3276fbad | 816 | int phy = adapter->physical_port; |
a608ab9c AV |
817 | u8 temp[4]; |
818 | u32 val; | |
3d396eb1 | 819 | |
6c80b18d MT |
820 | if ((phy < 0) || (phy > NETXEN_NIU_MAX_XG_PORTS)) |
821 | return -EIO; | |
822 | ||
a608ab9c | 823 | temp[0] = temp[1] = 0; |
6c80b18d MT |
824 | switch (phy) { |
825 | case 0: | |
826 | memcpy(temp + 2, addr, 2); | |
827 | val = le32_to_cpu(*(__le32 *)temp); | |
3ce06a32 | 828 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, |
6c80b18d | 829 | &val, 4)) |
3d396eb1 AK |
830 | return -EIO; |
831 | ||
6c80b18d MT |
832 | memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); |
833 | val = le32_to_cpu(*(__le32 *)temp); | |
3ce06a32 | 834 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, |
6c80b18d MT |
835 | &val, 4)) |
836 | return -EIO; | |
837 | break; | |
838 | ||
839 | case 1: | |
840 | memcpy(temp + 2, addr, 2); | |
841 | val = le32_to_cpu(*(__le32 *)temp); | |
3ce06a32 | 842 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_1, |
6c80b18d MT |
843 | &val, 4)) |
844 | return -EIO; | |
845 | ||
846 | memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); | |
847 | val = le32_to_cpu(*(__le32 *)temp); | |
3ce06a32 | 848 | if (adapter->hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_HI, |
6c80b18d | 849 | &val, 4)) |
3d396eb1 | 850 | return -EIO; |
6c80b18d MT |
851 | break; |
852 | ||
853 | default: | |
854 | printk(KERN_ERR "Unknown port %d\n", phy); | |
855 | break; | |
856 | } | |
3d396eb1 AK |
857 | |
858 | return 0; | |
859 | } | |
860 | ||
993fb90c | 861 | #if 0 |
3d396eb1 AK |
862 | /* |
863 | * Return the current station MAC address. | |
864 | * Note that the passed-in value must already be in network byte order. | |
865 | */ | |
13ba9c77 | 866 | int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, |
3d396eb1 AK |
867 | netxen_ethernet_macaddr_t * addr) |
868 | { | |
3276fbad | 869 | int phy = adapter->physical_port; |
a608ab9c AV |
870 | u32 stationhigh; |
871 | u32 stationlow; | |
872 | u8 val[8]; | |
3d396eb1 AK |
873 | |
874 | if (addr == NULL) | |
875 | return -EINVAL; | |
876 | if (phy != 0) | |
877 | return -EINVAL; | |
878 | ||
3ce06a32 | 879 | if (adapter->hw_read_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, |
3d396eb1 AK |
880 | &stationhigh, 4)) |
881 | return -EIO; | |
3ce06a32 | 882 | if (adapter->hw_read_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, |
3d396eb1 AK |
883 | &stationlow, 4)) |
884 | return -EIO; | |
a608ab9c AV |
885 | ((__le32 *)val)[1] = cpu_to_le32(stationhigh); |
886 | ((__le32 *)val)[0] = cpu_to_le32(stationlow); | |
3d396eb1 | 887 | |
a608ab9c | 888 | memcpy(addr, val + 2, 6); |
3d396eb1 AK |
889 | |
890 | return 0; | |
891 | } | |
993fb90c | 892 | #endif /* 0 */ |
3d396eb1 AK |
893 | |
894 | int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, | |
3176ff3e | 895 | netxen_niu_prom_mode_t mode) |
3d396eb1 | 896 | { |
a608ab9c | 897 | __u32 reg; |
3276fbad | 898 | u32 port = adapter->physical_port; |
3d396eb1 | 899 | |
287aa83d | 900 | if (port > NETXEN_NIU_MAX_XG_PORTS) |
3d396eb1 AK |
901 | return -EINVAL; |
902 | ||
3ce06a32 | 903 | if (adapter->hw_read_wx(adapter, |
6c80b18d MT |
904 | NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), ®, 4)) |
905 | return -EIO; | |
3d396eb1 AK |
906 | if (mode == NETXEN_NIU_PROMISC_MODE) |
907 | reg = (reg | 0x2000UL); | |
908 | else | |
909 | reg = (reg & ~0x2000UL); | |
910 | ||
623621b0 DP |
911 | if (mode == NETXEN_NIU_ALLMULTI_MODE) |
912 | reg = (reg | 0x1000UL); | |
913 | else | |
914 | reg = (reg & ~0x1000UL); | |
915 | ||
6c80b18d MT |
916 | netxen_crb_writelit_adapter(adapter, |
917 | NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); | |
3d396eb1 AK |
918 | |
919 | return 0; | |
920 | } |