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