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) { | |
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 | ||
993fb90c | 71 | static 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 | 77 | |
4790654c | 78 | /* |
3d396eb1 AK |
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 | */ | |
4790654c | 91 | int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, |
13ba9c77 | 92 | __u32 * readval) |
3d396eb1 AK |
93 | { |
94 | long timeout = 0; | |
95 | long result = 0; | |
96 | long restore = 0; | |
3276fbad | 97 | long phy = adapter->physical_port; |
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 | ||
4790654c | 174 | /* |
3d396eb1 AK |
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 | */ | |
4790654c | 187 | int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, |
13ba9c77 | 188 | __u32 val) |
3d396eb1 AK |
189 | { |
190 | long timeout = 0; | |
191 | long result = 0; | |
192 | long restore = 0; | |
3276fbad | 193 | long phy = adapter->physical_port; |
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 != | |
4790654c | 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 | ||
993fb90c | 303 | #if 0 |
13ba9c77 | 304 | int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter) |
3d396eb1 AK |
305 | { |
306 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1); | |
307 | return 0; | |
308 | } | |
993fb90c | 309 | #endif /* 0 */ |
3d396eb1 | 310 | |
993fb90c | 311 | static int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter) |
3d396eb1 AK |
312 | { |
313 | int result = 0; | |
314 | if (0 != | |
4790654c | 315 | netxen_niu_gbe_phy_write(adapter, |
3d396eb1 AK |
316 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, |
317 | -EIO)) | |
318 | result = -EIO; | |
319 | ||
320 | return result; | |
321 | } | |
322 | ||
4790654c | 323 | /* |
3d396eb1 AK |
324 | * netxen_niu_gbe_set_mii_mode- Set 10/100 Mbit Mode for GbE MAC |
325 | * | |
326 | */ | |
993fb90c AB |
327 | static void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, |
328 | int port, long enable) | |
3d396eb1 AK |
329 | { |
330 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2); | |
331 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
332 | 0x80000000); | |
333 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
334 | 0x0000f0025); | |
335 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), | |
336 | 0xf1ff); | |
337 | netxen_crb_writelit_adapter(adapter, | |
338 | NETXEN_NIU_GB0_GMII_MODE + (port << 3), 0); | |
339 | netxen_crb_writelit_adapter(adapter, | |
340 | NETXEN_NIU_GB0_MII_MODE + (port << 3), 1); | |
341 | netxen_crb_writelit_adapter(adapter, | |
342 | (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); | |
343 | netxen_crb_writelit_adapter(adapter, | |
344 | NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); | |
345 | ||
346 | if (enable) { | |
4790654c JG |
347 | /* |
348 | * Do NOT enable flow control until a suitable solution for | |
349 | * shutting down pause frames is found. | |
3d396eb1 AK |
350 | */ |
351 | netxen_crb_writelit_adapter(adapter, | |
352 | NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
353 | 0x5); | |
354 | } | |
355 | ||
13ba9c77 | 356 | if (netxen_niu_gbe_enable_phy_interrupts(adapter)) |
3d396eb1 | 357 | printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); |
13ba9c77 | 358 | if (netxen_niu_gbe_clear_phy_interrupts(adapter)) |
3d396eb1 AK |
359 | printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); |
360 | } | |
361 | ||
4790654c | 362 | /* |
3d396eb1 AK |
363 | * netxen_niu_gbe_set_gmii_mode- Set GbE Mode for GbE MAC |
364 | */ | |
993fb90c AB |
365 | static void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, |
366 | int port, long enable) | |
3d396eb1 AK |
367 | { |
368 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2); | |
369 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
370 | 0x80000000); | |
371 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
372 | 0x0000f0025); | |
373 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), | |
374 | 0xf2ff); | |
375 | netxen_crb_writelit_adapter(adapter, | |
376 | NETXEN_NIU_GB0_MII_MODE + (port << 3), 0); | |
377 | netxen_crb_writelit_adapter(adapter, | |
378 | NETXEN_NIU_GB0_GMII_MODE + (port << 3), 1); | |
379 | netxen_crb_writelit_adapter(adapter, | |
380 | (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); | |
381 | netxen_crb_writelit_adapter(adapter, | |
382 | NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); | |
383 | ||
384 | if (enable) { | |
4790654c JG |
385 | /* |
386 | * Do NOT enable flow control until a suitable solution for | |
387 | * shutting down pause frames is found. | |
3d396eb1 AK |
388 | */ |
389 | netxen_crb_writelit_adapter(adapter, | |
390 | NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
391 | 0x5); | |
392 | } | |
393 | ||
13ba9c77 | 394 | if (netxen_niu_gbe_enable_phy_interrupts(adapter)) |
3d396eb1 | 395 | printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); |
13ba9c77 | 396 | if (netxen_niu_gbe_clear_phy_interrupts(adapter)) |
3d396eb1 AK |
397 | printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); |
398 | } | |
399 | ||
400 | int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) | |
401 | { | |
402 | int result = 0; | |
a608ab9c | 403 | __u32 status; |
80922fbc | 404 | if (adapter->disable_phy_interrupts) |
13ba9c77 | 405 | adapter->disable_phy_interrupts(adapter); |
3d396eb1 AK |
406 | mdelay(2); |
407 | ||
408 | if (0 == | |
13ba9c77 | 409 | netxen_niu_gbe_phy_read(adapter, |
3d396eb1 | 410 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, |
a608ab9c | 411 | &status)) { |
3d396eb1 AK |
412 | if (netxen_get_phy_link(status)) { |
413 | if (netxen_get_phy_speed(status) == 2) { | |
414 | netxen_niu_gbe_set_gmii_mode(adapter, port, 1); | |
415 | } else if ((netxen_get_phy_speed(status) == 1) | |
416 | || (netxen_get_phy_speed(status) == 0)) { | |
417 | netxen_niu_gbe_set_mii_mode(adapter, port, 1); | |
418 | } else { | |
419 | result = -1; | |
420 | } | |
421 | ||
422 | } else { | |
cb8011ad AK |
423 | /* |
424 | * We don't have link. Cable must be unconnected. | |
425 | * Enable phy interrupts so we take action when | |
426 | * plugged in. | |
427 | */ | |
428 | ||
3d396eb1 AK |
429 | netxen_crb_writelit_adapter(adapter, |
430 | NETXEN_NIU_GB_MAC_CONFIG_0 | |
cb8011ad AK |
431 | (port), |
432 | NETXEN_GB_MAC_SOFT_RESET); | |
3d396eb1 AK |
433 | netxen_crb_writelit_adapter(adapter, |
434 | NETXEN_NIU_GB_MAC_CONFIG_0 | |
cb8011ad AK |
435 | (port), |
436 | NETXEN_GB_MAC_RESET_PROT_BLK | |
437 | | NETXEN_GB_MAC_ENABLE_TX_RX | |
438 | | | |
439 | NETXEN_GB_MAC_PAUSED_FRMS); | |
13ba9c77 | 440 | if (netxen_niu_gbe_clear_phy_interrupts(adapter)) |
3d396eb1 AK |
441 | printk(KERN_ERR PFX |
442 | "ERROR clearing PHY interrupts\n"); | |
13ba9c77 | 443 | if (netxen_niu_gbe_enable_phy_interrupts(adapter)) |
3d396eb1 AK |
444 | printk(KERN_ERR PFX |
445 | "ERROR enabling PHY interrupts\n"); | |
13ba9c77 | 446 | if (netxen_niu_gbe_clear_phy_interrupts(adapter)) |
3d396eb1 AK |
447 | printk(KERN_ERR PFX |
448 | "ERROR clearing PHY interrupts\n"); | |
449 | result = -1; | |
450 | } | |
451 | } else { | |
452 | result = -EIO; | |
453 | } | |
454 | return result; | |
455 | } | |
456 | ||
cb8011ad AK |
457 | int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) |
458 | { | |
3276fbad | 459 | u32 portnum = adapter->physical_port; |
6c80b18d MT |
460 | |
461 | netxen_crb_writelit_adapter(adapter, | |
3e2facef | 462 | NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), 0x1447); |
6c80b18d | 463 | netxen_crb_writelit_adapter(adapter, |
3e2facef | 464 | NETXEN_NIU_XGE_CONFIG_0+(0x10000*portnum), 0x5); |
cb8011ad | 465 | |
6c80b18d | 466 | return 0; |
cb8011ad AK |
467 | } |
468 | ||
993fb90c | 469 | #if 0 |
4790654c | 470 | /* |
3d396eb1 AK |
471 | * netxen_niu_gbe_handle_phy_interrupt - Handles GbE PHY interrupts |
472 | * @param enable 0 means don't enable the port | |
cb8011ad | 473 | * 1 means enable (or re-enable) the port |
3d396eb1 AK |
474 | */ |
475 | int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, | |
476 | int port, long enable) | |
477 | { | |
478 | int result = 0; | |
a608ab9c | 479 | __u32 int_src; |
3d396eb1 AK |
480 | |
481 | printk(KERN_INFO PFX "NETXEN: Handling PHY interrupt on port %d" | |
482 | " (device enable = %d)\n", (int)port, (int)enable); | |
483 | ||
cb8011ad AK |
484 | /* |
485 | * The read of the PHY INT status will clear the pending | |
486 | * interrupt status | |
487 | */ | |
13ba9c77 | 488 | if (netxen_niu_gbe_phy_read(adapter, |
3d396eb1 AK |
489 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, |
490 | &int_src) != 0) | |
491 | result = -EINVAL; | |
492 | else { | |
493 | printk(KERN_INFO PFX "PHY Interrupt source = 0x%x \n", int_src); | |
494 | if (netxen_get_phy_int_jabber(int_src)) | |
495 | printk(KERN_INFO PFX "jabber Interrupt "); | |
496 | if (netxen_get_phy_int_polarity_changed(int_src)) | |
497 | printk(KERN_INFO PFX "polarity changed "); | |
498 | if (netxen_get_phy_int_energy_detect(int_src)) | |
499 | printk(KERN_INFO PFX "energy detect \n"); | |
500 | if (netxen_get_phy_int_downshift(int_src)) | |
501 | printk(KERN_INFO PFX "downshift \n"); | |
502 | if (netxen_get_phy_int_mdi_xover_changed(int_src)) | |
503 | printk(KERN_INFO PFX "mdi_xover_changed "); | |
504 | if (netxen_get_phy_int_fifo_over_underflow(int_src)) | |
505 | printk(KERN_INFO PFX "fifo_over_underflow "); | |
506 | if (netxen_get_phy_int_false_carrier(int_src)) | |
507 | printk(KERN_INFO PFX "false_carrier "); | |
508 | if (netxen_get_phy_int_symbol_error(int_src)) | |
509 | printk(KERN_INFO PFX "symbol_error "); | |
510 | if (netxen_get_phy_int_autoneg_completed(int_src)) | |
511 | printk(KERN_INFO PFX "autoneg_completed "); | |
512 | if (netxen_get_phy_int_page_received(int_src)) | |
513 | printk(KERN_INFO PFX "page_received "); | |
514 | if (netxen_get_phy_int_duplex_changed(int_src)) | |
515 | printk(KERN_INFO PFX "duplex_changed "); | |
516 | if (netxen_get_phy_int_autoneg_error(int_src)) | |
517 | printk(KERN_INFO PFX "autoneg_error "); | |
518 | if ((netxen_get_phy_int_speed_changed(int_src)) | |
519 | || (netxen_get_phy_int_link_status_changed(int_src))) { | |
a608ab9c | 520 | __u32 status; |
3d396eb1 AK |
521 | |
522 | printk(KERN_INFO PFX | |
523 | "speed_changed or link status changed"); | |
524 | if (netxen_niu_gbe_phy_read | |
13ba9c77 | 525 | (adapter, |
3d396eb1 AK |
526 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, |
527 | &status) == 0) { | |
528 | if (netxen_get_phy_speed(status) == 2) { | |
529 | printk | |
530 | (KERN_INFO PFX "Link speed changed" | |
531 | " to 1000 Mbps\n"); | |
532 | netxen_niu_gbe_set_gmii_mode(adapter, | |
533 | port, | |
534 | enable); | |
535 | } else if (netxen_get_phy_speed(status) == 1) { | |
536 | printk | |
537 | (KERN_INFO PFX "Link speed changed" | |
538 | " to 100 Mbps\n"); | |
539 | netxen_niu_gbe_set_mii_mode(adapter, | |
540 | port, | |
541 | enable); | |
542 | } else if (netxen_get_phy_speed(status) == 0) { | |
543 | printk | |
544 | (KERN_INFO PFX "Link speed changed" | |
545 | " to 10 Mbps\n"); | |
546 | netxen_niu_gbe_set_mii_mode(adapter, | |
547 | port, | |
548 | enable); | |
549 | } else { | |
5bc51424 JP |
550 | printk(KERN_ERR PFX "ERROR reading " |
551 | "PHY status. Invalid speed.\n"); | |
3d396eb1 AK |
552 | result = -1; |
553 | } | |
554 | } else { | |
555 | printk(KERN_ERR PFX | |
556 | "ERROR reading PHY status.\n"); | |
557 | result = -1; | |
558 | } | |
559 | ||
560 | } | |
561 | printk(KERN_INFO "\n"); | |
562 | } | |
563 | return result; | |
564 | } | |
993fb90c | 565 | #endif /* 0 */ |
3d396eb1 AK |
566 | |
567 | /* | |
568 | * Return the current station MAC address. | |
569 | * Note that the passed-in value must already be in network byte order. | |
570 | */ | |
993fb90c AB |
571 | static int netxen_niu_macaddr_get(struct netxen_adapter *adapter, |
572 | netxen_ethernet_macaddr_t * addr) | |
3d396eb1 | 573 | { |
a608ab9c AV |
574 | u32 stationhigh; |
575 | u32 stationlow; | |
3276fbad | 576 | int phy = adapter->physical_port; |
a608ab9c | 577 | u8 val[8]; |
3d396eb1 AK |
578 | |
579 | if (addr == NULL) | |
580 | return -EINVAL; | |
581 | if ((phy < 0) || (phy > 3)) | |
582 | return -EINVAL; | |
583 | ||
584 | if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), | |
585 | &stationhigh, 4)) | |
586 | return -EIO; | |
587 | if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), | |
588 | &stationlow, 4)) | |
589 | return -EIO; | |
a608ab9c AV |
590 | ((__le32 *)val)[1] = cpu_to_le32(stationhigh); |
591 | ((__le32 *)val)[0] = cpu_to_le32(stationlow); | |
3d396eb1 | 592 | |
a608ab9c | 593 | memcpy(addr, val + 2, 6); |
3d396eb1 AK |
594 | |
595 | return 0; | |
596 | } | |
597 | ||
598 | /* | |
599 | * Set the station MAC address. | |
600 | * Note that the passed-in value must already be in network byte order. | |
601 | */ | |
3176ff3e | 602 | int netxen_niu_macaddr_set(struct netxen_adapter *adapter, |
3d396eb1 AK |
603 | netxen_ethernet_macaddr_t addr) |
604 | { | |
a608ab9c AV |
605 | u8 temp[4]; |
606 | u32 val; | |
3276fbad | 607 | int phy = adapter->physical_port; |
ed25ffa1 | 608 | unsigned char mac_addr[6]; |
cb8011ad | 609 | int i; |
0795af57 | 610 | DECLARE_MAC_BUF(mac); |
cb8011ad AK |
611 | |
612 | for (i = 0; i < 10; i++) { | |
a608ab9c AV |
613 | temp[0] = temp[1] = 0; |
614 | memcpy(temp + 2, addr, 2); | |
615 | val = le32_to_cpu(*(__le32 *)temp); | |
cb8011ad | 616 | if (netxen_nic_hw_write_wx |
a608ab9c | 617 | (adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), &val, 4)) |
cb8011ad | 618 | return -EIO; |
3d396eb1 | 619 | |
a608ab9c AV |
620 | memcpy(temp, ((u8 *) addr) + 2, sizeof(__le32)); |
621 | val = le32_to_cpu(*(__le32 *)temp); | |
cb8011ad | 622 | if (netxen_nic_hw_write_wx |
a608ab9c | 623 | (adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4)) |
cb8011ad | 624 | return -2; |
3d396eb1 | 625 | |
4790654c | 626 | netxen_niu_macaddr_get(adapter, |
cb8011ad | 627 | (netxen_ethernet_macaddr_t *) mac_addr); |
ed25ffa1 | 628 | if (memcmp(mac_addr, addr, 6) == 0) |
cb8011ad AK |
629 | break; |
630 | } | |
3d396eb1 | 631 | |
cb8011ad AK |
632 | if (i == 10) { |
633 | printk(KERN_ERR "%s: cannot set Mac addr for %s\n", | |
3176ff3e | 634 | netxen_nic_driver_name, adapter->netdev->name); |
0795af57 JP |
635 | printk(KERN_ERR "MAC address set: %s.\n", |
636 | print_mac(mac, addr)); | |
637 | printk(KERN_ERR "MAC address get: %s.\n", | |
638 | print_mac(mac, mac_addr)); | |
cb8011ad | 639 | } |
3d396eb1 AK |
640 | return 0; |
641 | } | |
642 | ||
993fb90c | 643 | #if 0 |
3d396eb1 AK |
644 | /* Enable a GbE interface */ |
645 | int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter, | |
646 | int port, netxen_niu_gbe_ifmode_t mode) | |
647 | { | |
a608ab9c AV |
648 | __u32 mac_cfg0; |
649 | __u32 mac_cfg1; | |
650 | __u32 mii_cfg; | |
3d396eb1 AK |
651 | |
652 | if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) | |
653 | return -EINVAL; | |
654 | ||
655 | mac_cfg0 = 0; | |
656 | netxen_gb_soft_reset(mac_cfg0); | |
657 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
658 | &mac_cfg0, 4)) | |
659 | return -EIO; | |
660 | mac_cfg0 = 0; | |
661 | netxen_gb_enable_tx(mac_cfg0); | |
662 | netxen_gb_enable_rx(mac_cfg0); | |
663 | netxen_gb_unset_rx_flowctl(mac_cfg0); | |
664 | netxen_gb_tx_reset_pb(mac_cfg0); | |
665 | netxen_gb_rx_reset_pb(mac_cfg0); | |
666 | netxen_gb_tx_reset_mac(mac_cfg0); | |
667 | netxen_gb_rx_reset_mac(mac_cfg0); | |
668 | ||
669 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
670 | &mac_cfg0, 4)) | |
671 | return -EIO; | |
672 | mac_cfg1 = 0; | |
673 | netxen_gb_set_preamblelen(mac_cfg1, 0xf); | |
674 | netxen_gb_set_duplex(mac_cfg1); | |
675 | netxen_gb_set_crc_enable(mac_cfg1); | |
676 | netxen_gb_set_padshort(mac_cfg1); | |
677 | netxen_gb_set_checklength(mac_cfg1); | |
678 | netxen_gb_set_hugeframes(mac_cfg1); | |
679 | ||
680 | if (mode == NETXEN_NIU_10_100_MB) { | |
681 | netxen_gb_set_intfmode(mac_cfg1, 1); | |
682 | if (netxen_nic_hw_write_wx(adapter, | |
683 | NETXEN_NIU_GB_MAC_CONFIG_1(port), | |
684 | &mac_cfg1, 4)) | |
685 | return -EIO; | |
686 | ||
687 | /* set mii mode */ | |
688 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_GMII_MODE + | |
689 | (port << 3), 0); | |
690 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_MII_MODE + | |
691 | (port << 3), 1); | |
692 | ||
693 | } else if (mode == NETXEN_NIU_1000_MB) { | |
694 | netxen_gb_set_intfmode(mac_cfg1, 2); | |
695 | if (netxen_nic_hw_write_wx(adapter, | |
696 | NETXEN_NIU_GB_MAC_CONFIG_1(port), | |
697 | &mac_cfg1, 4)) | |
698 | return -EIO; | |
699 | /* set gmii mode */ | |
700 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_MII_MODE + | |
701 | (port << 3), 0); | |
702 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_GMII_MODE + | |
703 | (port << 3), 1); | |
704 | } | |
705 | mii_cfg = 0; | |
706 | netxen_gb_set_mii_mgmt_clockselect(mii_cfg, 7); | |
707 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port), | |
708 | &mii_cfg, 4)) | |
709 | return -EIO; | |
710 | mac_cfg0 = 0; | |
711 | netxen_gb_enable_tx(mac_cfg0); | |
712 | netxen_gb_enable_rx(mac_cfg0); | |
713 | netxen_gb_unset_rx_flowctl(mac_cfg0); | |
714 | netxen_gb_unset_tx_flowctl(mac_cfg0); | |
715 | ||
716 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
717 | &mac_cfg0, 4)) | |
718 | return -EIO; | |
719 | return 0; | |
720 | } | |
993fb90c | 721 | #endif /* 0 */ |
3d396eb1 AK |
722 | |
723 | /* Disable a GbE interface */ | |
3176ff3e | 724 | int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter) |
3d396eb1 | 725 | { |
a608ab9c | 726 | __u32 mac_cfg0; |
3276fbad | 727 | u32 port = adapter->physical_port; |
3d396eb1 | 728 | |
287aa83d | 729 | if (port > NETXEN_NIU_MAX_GBE_PORTS) |
6c80b18d | 730 | return -EINVAL; |
3d396eb1 AK |
731 | mac_cfg0 = 0; |
732 | netxen_gb_soft_reset(mac_cfg0); | |
733 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), | |
734 | &mac_cfg0, 4)) | |
735 | return -EIO; | |
736 | return 0; | |
737 | } | |
738 | ||
739 | /* Disable an XG interface */ | |
3176ff3e | 740 | int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) |
3d396eb1 | 741 | { |
a608ab9c | 742 | __u32 mac_cfg; |
3276fbad | 743 | u32 port = adapter->physical_port; |
3d396eb1 | 744 | |
72b0a7a8 | 745 | if (port > NETXEN_NIU_MAX_XG_PORTS) |
6c80b18d | 746 | return -EINVAL; |
72b0a7a8 | 747 | |
3d396eb1 | 748 | mac_cfg = 0; |
72b0a7a8 | 749 | if (netxen_nic_hw_write_wx(adapter, |
750 | NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), &mac_cfg, 4)) | |
3d396eb1 AK |
751 | return -EIO; |
752 | return 0; | |
753 | } | |
754 | ||
755 | /* Set promiscuous mode for a GbE interface */ | |
4790654c | 756 | int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, |
3d396eb1 AK |
757 | netxen_niu_prom_mode_t mode) |
758 | { | |
a608ab9c | 759 | __u32 reg; |
3276fbad | 760 | u32 port = adapter->physical_port; |
3d396eb1 | 761 | |
287aa83d | 762 | if (port > NETXEN_NIU_MAX_GBE_PORTS) |
3d396eb1 AK |
763 | return -EINVAL; |
764 | ||
765 | /* save previous contents */ | |
766 | if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, | |
767 | ®, 4)) | |
768 | return -EIO; | |
769 | if (mode == NETXEN_NIU_PROMISC_MODE) { | |
770 | switch (port) { | |
771 | case 0: | |
772 | netxen_clear_gb_drop_gb0(reg); | |
773 | break; | |
774 | case 1: | |
775 | netxen_clear_gb_drop_gb1(reg); | |
776 | break; | |
777 | case 2: | |
778 | netxen_clear_gb_drop_gb2(reg); | |
779 | break; | |
780 | case 3: | |
781 | netxen_clear_gb_drop_gb3(reg); | |
782 | break; | |
783 | default: | |
784 | return -EIO; | |
785 | } | |
786 | } else { | |
787 | switch (port) { | |
788 | case 0: | |
789 | netxen_set_gb_drop_gb0(reg); | |
790 | break; | |
791 | case 1: | |
792 | netxen_set_gb_drop_gb1(reg); | |
793 | break; | |
794 | case 2: | |
795 | netxen_set_gb_drop_gb2(reg); | |
796 | break; | |
797 | case 3: | |
798 | netxen_set_gb_drop_gb3(reg); | |
799 | break; | |
800 | default: | |
801 | return -EIO; | |
802 | } | |
803 | } | |
804 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, | |
805 | ®, 4)) | |
806 | return -EIO; | |
807 | return 0; | |
808 | } | |
809 | ||
810 | /* | |
811 | * Set the MAC address for an XG port | |
812 | * Note that the passed-in value must already be in network byte order. | |
813 | */ | |
3176ff3e | 814 | int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, |
3d396eb1 AK |
815 | netxen_ethernet_macaddr_t addr) |
816 | { | |
3276fbad | 817 | int phy = adapter->physical_port; |
a608ab9c AV |
818 | u8 temp[4]; |
819 | u32 val; | |
3d396eb1 | 820 | |
6c80b18d MT |
821 | if ((phy < 0) || (phy > NETXEN_NIU_MAX_XG_PORTS)) |
822 | return -EIO; | |
823 | ||
a608ab9c | 824 | temp[0] = temp[1] = 0; |
6c80b18d MT |
825 | switch (phy) { |
826 | case 0: | |
827 | memcpy(temp + 2, addr, 2); | |
828 | val = le32_to_cpu(*(__le32 *)temp); | |
829 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, | |
830 | &val, 4)) | |
3d396eb1 AK |
831 | return -EIO; |
832 | ||
6c80b18d MT |
833 | memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); |
834 | val = le32_to_cpu(*(__le32 *)temp); | |
835 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, | |
836 | &val, 4)) | |
837 | return -EIO; | |
838 | break; | |
839 | ||
840 | case 1: | |
841 | memcpy(temp + 2, addr, 2); | |
842 | val = le32_to_cpu(*(__le32 *)temp); | |
843 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_1, | |
844 | &val, 4)) | |
845 | return -EIO; | |
846 | ||
847 | memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); | |
848 | val = le32_to_cpu(*(__le32 *)temp); | |
849 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_HI, | |
850 | &val, 4)) | |
3d396eb1 | 851 | return -EIO; |
6c80b18d MT |
852 | break; |
853 | ||
854 | default: | |
855 | printk(KERN_ERR "Unknown port %d\n", phy); | |
856 | break; | |
857 | } | |
3d396eb1 AK |
858 | |
859 | return 0; | |
860 | } | |
861 | ||
993fb90c | 862 | #if 0 |
3d396eb1 AK |
863 | /* |
864 | * Return the current station MAC address. | |
865 | * Note that the passed-in value must already be in network byte order. | |
866 | */ | |
13ba9c77 | 867 | int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, |
3d396eb1 AK |
868 | netxen_ethernet_macaddr_t * addr) |
869 | { | |
3276fbad | 870 | int phy = adapter->physical_port; |
a608ab9c AV |
871 | u32 stationhigh; |
872 | u32 stationlow; | |
873 | u8 val[8]; | |
3d396eb1 AK |
874 | |
875 | if (addr == NULL) | |
876 | return -EINVAL; | |
877 | if (phy != 0) | |
878 | return -EINVAL; | |
879 | ||
880 | if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, | |
881 | &stationhigh, 4)) | |
882 | return -EIO; | |
883 | if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, | |
884 | &stationlow, 4)) | |
885 | return -EIO; | |
a608ab9c AV |
886 | ((__le32 *)val)[1] = cpu_to_le32(stationhigh); |
887 | ((__le32 *)val)[0] = cpu_to_le32(stationlow); | |
3d396eb1 | 888 | |
a608ab9c | 889 | memcpy(addr, val + 2, 6); |
3d396eb1 AK |
890 | |
891 | return 0; | |
892 | } | |
993fb90c | 893 | #endif /* 0 */ |
3d396eb1 AK |
894 | |
895 | int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, | |
3176ff3e | 896 | netxen_niu_prom_mode_t mode) |
3d396eb1 | 897 | { |
a608ab9c | 898 | __u32 reg; |
3276fbad | 899 | u32 port = adapter->physical_port; |
3d396eb1 | 900 | |
287aa83d | 901 | if (port > NETXEN_NIU_MAX_XG_PORTS) |
3d396eb1 AK |
902 | return -EINVAL; |
903 | ||
6c80b18d MT |
904 | if (netxen_nic_hw_read_wx(adapter, |
905 | NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), ®, 4)) | |
906 | return -EIO; | |
3d396eb1 AK |
907 | if (mode == NETXEN_NIU_PROMISC_MODE) |
908 | reg = (reg | 0x2000UL); | |
909 | else | |
910 | reg = (reg & ~0x2000UL); | |
911 | ||
6c80b18d MT |
912 | netxen_crb_writelit_adapter(adapter, |
913 | NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); | |
3d396eb1 AK |
914 | |
915 | return 0; | |
916 | } |