diff options
Diffstat (limited to 'drivers/net/netxen/netxen_nic_init.c')
-rw-r--r-- | drivers/net/netxen/netxen_nic_init.c | 1143 |
1 files changed, 1143 insertions, 0 deletions
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c new file mode 100644 index 000000000000..d122e51e43ab --- /dev/null +++ b/drivers/net/netxen/netxen_nic_init.c | |||
@@ -0,0 +1,1143 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2003 - 2006 NetXen, Inc. | ||
3 | * All rights reserved. | ||
4 | * | ||
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. | ||
9 | * | ||
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. | ||
14 | * | ||
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. | ||
19 | * | ||
20 | * The full GNU General Public License is included in this distribution | ||
21 | * in the file called LICENSE. | ||
22 | * | ||
23 | * Contact Information: | ||
24 | * info@netxen.com | ||
25 | * NetXen, | ||
26 | * 3965 Freedom Circle, Fourth floor, | ||
27 | * Santa Clara, CA 95054 | ||
28 | * | ||
29 | * | ||
30 | * Source file for NIC routines to initialize the Phantom Hardware | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #include <linux/netdevice.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include "netxen_nic.h" | ||
37 | #include "netxen_nic_hw.h" | ||
38 | #include "netxen_nic_ioctl.h" | ||
39 | #include "netxen_nic_phan_reg.h" | ||
40 | |||
41 | struct crb_addr_pair { | ||
42 | long addr; | ||
43 | long data; | ||
44 | }; | ||
45 | |||
46 | #define NETXEN_MAX_CRB_XFORM 60 | ||
47 | static unsigned int crb_addr_xform[NETXEN_MAX_CRB_XFORM]; | ||
48 | #define NETXEN_ADDR_ERROR ((unsigned long ) 0xffffffff ) | ||
49 | |||
50 | #define crb_addr_transform(name) \ | ||
51 | crb_addr_xform[NETXEN_HW_PX_MAP_CRB_##name] = \ | ||
52 | NETXEN_HW_CRB_HUB_AGT_ADR_##name << 20 | ||
53 | |||
54 | static inline void | ||
55 | netxen_nic_locked_write_reg(struct netxen_adapter *adapter, | ||
56 | unsigned long off, int *data) | ||
57 | { | ||
58 | void __iomem *addr = (adapter->ahw.pci_base + off); | ||
59 | writel(*data, addr); | ||
60 | } | ||
61 | |||
62 | static void crb_addr_transform_setup(void) | ||
63 | { | ||
64 | crb_addr_transform(XDMA); | ||
65 | crb_addr_transform(TIMR); | ||
66 | crb_addr_transform(SRE); | ||
67 | crb_addr_transform(SQN3); | ||
68 | crb_addr_transform(SQN2); | ||
69 | crb_addr_transform(SQN1); | ||
70 | crb_addr_transform(SQN0); | ||
71 | crb_addr_transform(SQS3); | ||
72 | crb_addr_transform(SQS2); | ||
73 | crb_addr_transform(SQS1); | ||
74 | crb_addr_transform(SQS0); | ||
75 | crb_addr_transform(RPMX7); | ||
76 | crb_addr_transform(RPMX6); | ||
77 | crb_addr_transform(RPMX5); | ||
78 | crb_addr_transform(RPMX4); | ||
79 | crb_addr_transform(RPMX3); | ||
80 | crb_addr_transform(RPMX2); | ||
81 | crb_addr_transform(RPMX1); | ||
82 | crb_addr_transform(RPMX0); | ||
83 | crb_addr_transform(ROMUSB); | ||
84 | crb_addr_transform(SN); | ||
85 | crb_addr_transform(QMN); | ||
86 | crb_addr_transform(QMS); | ||
87 | crb_addr_transform(PGNI); | ||
88 | crb_addr_transform(PGND); | ||
89 | crb_addr_transform(PGN3); | ||
90 | crb_addr_transform(PGN2); | ||
91 | crb_addr_transform(PGN1); | ||
92 | crb_addr_transform(PGN0); | ||
93 | crb_addr_transform(PGSI); | ||
94 | crb_addr_transform(PGSD); | ||
95 | crb_addr_transform(PGS3); | ||
96 | crb_addr_transform(PGS2); | ||
97 | crb_addr_transform(PGS1); | ||
98 | crb_addr_transform(PGS0); | ||
99 | crb_addr_transform(PS); | ||
100 | crb_addr_transform(PH); | ||
101 | crb_addr_transform(NIU); | ||
102 | crb_addr_transform(I2Q); | ||
103 | crb_addr_transform(EG); | ||
104 | crb_addr_transform(MN); | ||
105 | crb_addr_transform(MS); | ||
106 | crb_addr_transform(CAS2); | ||
107 | crb_addr_transform(CAS1); | ||
108 | crb_addr_transform(CAS0); | ||
109 | crb_addr_transform(CAM); | ||
110 | crb_addr_transform(C2C1); | ||
111 | crb_addr_transform(C2C0); | ||
112 | } | ||
113 | |||
114 | int netxen_init_firmware(struct netxen_adapter *adapter) | ||
115 | { | ||
116 | u32 state = 0, loops = 0, err = 0; | ||
117 | |||
118 | /* Window 1 call */ | ||
119 | state = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); | ||
120 | |||
121 | if (state == PHAN_INITIALIZE_ACK) | ||
122 | return 0; | ||
123 | |||
124 | while (state != PHAN_INITIALIZE_COMPLETE && loops < 2000) { | ||
125 | udelay(100); | ||
126 | /* Window 1 call */ | ||
127 | state = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); | ||
128 | |||
129 | loops++; | ||
130 | } | ||
131 | if (loops >= 2000) { | ||
132 | printk(KERN_ERR "Cmd Peg initialization not complete:%x.\n", | ||
133 | state); | ||
134 | err = -EIO; | ||
135 | return err; | ||
136 | } | ||
137 | /* Window 1 call */ | ||
138 | writel(PHAN_INITIALIZE_ACK, | ||
139 | NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); | ||
140 | |||
141 | return err; | ||
142 | } | ||
143 | |||
144 | void netxen_initialize_adapter_sw(struct netxen_adapter *adapter) | ||
145 | { | ||
146 | int ctxid, ring; | ||
147 | u32 i; | ||
148 | u32 num_rx_bufs = 0; | ||
149 | struct netxen_rcv_desc_ctx *rcv_desc; | ||
150 | |||
151 | DPRINTK(INFO, "initializing some queues: %p\n", adapter); | ||
152 | for (ctxid = 0; ctxid < MAX_RCV_CTX; ++ctxid) { | ||
153 | for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { | ||
154 | struct netxen_rx_buffer *rx_buf; | ||
155 | rcv_desc = &adapter->recv_ctx[ctxid].rcv_desc[ring]; | ||
156 | rcv_desc->rcv_free = rcv_desc->max_rx_desc_count; | ||
157 | rcv_desc->begin_alloc = 0; | ||
158 | rx_buf = rcv_desc->rx_buf_arr; | ||
159 | num_rx_bufs = rcv_desc->max_rx_desc_count; | ||
160 | /* | ||
161 | * Now go through all of them, set reference handles | ||
162 | * and put them in the queues. | ||
163 | */ | ||
164 | for (i = 0; i < num_rx_bufs; i++) { | ||
165 | rx_buf->ref_handle = i; | ||
166 | rx_buf->state = NETXEN_BUFFER_FREE; | ||
167 | |||
168 | DPRINTK(INFO, "Rx buf:ctx%d i(%d) rx_buf:" | ||
169 | "%p\n", ctxid, i, rx_buf); | ||
170 | rx_buf++; | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | DPRINTK(INFO, "initialized buffers for %s and %s\n", | ||
175 | "adapter->free_cmd_buf_list", "adapter->free_rxbuf"); | ||
176 | } | ||
177 | |||
178 | void netxen_initialize_adapter_hw(struct netxen_adapter *adapter) | ||
179 | { | ||
180 | if (netxen_nic_get_board_info(adapter) != 0) | ||
181 | printk("%s: Error getting board config info.\n", | ||
182 | netxen_nic_driver_name); | ||
183 | |||
184 | switch (adapter->ahw.board_type) { | ||
185 | case NETXEN_NIC_GBE: | ||
186 | adapter->ahw.max_ports = 4; | ||
187 | break; | ||
188 | |||
189 | case NETXEN_NIC_XGBE: | ||
190 | adapter->ahw.max_ports = 1; | ||
191 | break; | ||
192 | |||
193 | default: | ||
194 | printk(KERN_ERR "%s: Unknown board type\n", | ||
195 | netxen_nic_driver_name); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) | ||
200 | { | ||
201 | struct netxen_drvops *ops = adapter->ops; | ||
202 | switch (adapter->ahw.board_type) { | ||
203 | case NETXEN_NIC_GBE: | ||
204 | ops->enable_phy_interrupts = | ||
205 | netxen_niu_gbe_enable_phy_interrupts; | ||
206 | ops->disable_phy_interrupts = | ||
207 | netxen_niu_gbe_disable_phy_interrupts; | ||
208 | ops->handle_phy_intr = netxen_nic_gbe_handle_phy_intr; | ||
209 | ops->macaddr_set = netxen_niu_macaddr_set; | ||
210 | ops->set_mtu = netxen_nic_set_mtu_gb; | ||
211 | ops->set_promisc = netxen_niu_set_promiscuous_mode; | ||
212 | ops->unset_promisc = netxen_niu_set_promiscuous_mode; | ||
213 | ops->phy_read = netxen_niu_gbe_phy_read; | ||
214 | ops->phy_write = netxen_niu_gbe_phy_write; | ||
215 | ops->init_port = netxen_niu_gbe_init_port; | ||
216 | ops->init_niu = netxen_nic_init_niu_gb; | ||
217 | ops->stop_port = netxen_niu_disable_gbe_port; | ||
218 | break; | ||
219 | |||
220 | case NETXEN_NIC_XGBE: | ||
221 | ops->enable_phy_interrupts = | ||
222 | netxen_niu_xgbe_enable_phy_interrupts; | ||
223 | ops->disable_phy_interrupts = | ||
224 | netxen_niu_xgbe_disable_phy_interrupts; | ||
225 | ops->handle_phy_intr = netxen_nic_xgbe_handle_phy_intr; | ||
226 | ops->macaddr_set = netxen_niu_xg_macaddr_set; | ||
227 | ops->set_mtu = netxen_nic_set_mtu_xgb; | ||
228 | ops->set_promisc = netxen_niu_xg_set_promiscuous_mode; | ||
229 | ops->unset_promisc = netxen_niu_xg_set_promiscuous_mode; | ||
230 | ops->stop_port = netxen_niu_disable_xg_port; | ||
231 | break; | ||
232 | |||
233 | default: | ||
234 | break; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | /* | ||
239 | * netxen_decode_crb_addr(0 - utility to translate from internal Phantom CRB | ||
240 | * address to external PCI CRB address. | ||
241 | */ | ||
242 | unsigned long netxen_decode_crb_addr(unsigned long addr) | ||
243 | { | ||
244 | int i; | ||
245 | unsigned long base_addr, offset, pci_base; | ||
246 | |||
247 | crb_addr_transform_setup(); | ||
248 | |||
249 | pci_base = NETXEN_ADDR_ERROR; | ||
250 | base_addr = addr & 0xfff00000; | ||
251 | offset = addr & 0x000fffff; | ||
252 | |||
253 | for (i = 0; i < NETXEN_MAX_CRB_XFORM; i++) { | ||
254 | if (crb_addr_xform[i] == base_addr) { | ||
255 | pci_base = i << 20; | ||
256 | break; | ||
257 | } | ||
258 | } | ||
259 | if (pci_base == NETXEN_ADDR_ERROR) | ||
260 | return pci_base; | ||
261 | else | ||
262 | return (pci_base + offset); | ||
263 | } | ||
264 | |||
265 | static long rom_max_timeout = 10000; | ||
266 | static long rom_lock_timeout = 1000000; | ||
267 | |||
268 | static inline int rom_lock(struct netxen_adapter *adapter) | ||
269 | { | ||
270 | int iter; | ||
271 | u32 done = 0; | ||
272 | int timeout = 0; | ||
273 | |||
274 | while (!done) { | ||
275 | /* acquire semaphore2 from PCI HW block */ | ||
276 | netxen_nic_read_w0(adapter, NETXEN_PCIE_REG(PCIE_SEM2_LOCK), | ||
277 | &done); | ||
278 | if (done == 1) | ||
279 | break; | ||
280 | if (timeout >= rom_lock_timeout) | ||
281 | return -EIO; | ||
282 | |||
283 | timeout++; | ||
284 | /* | ||
285 | * Yield CPU | ||
286 | */ | ||
287 | if (!in_atomic()) | ||
288 | schedule(); | ||
289 | else { | ||
290 | for (iter = 0; iter < 20; iter++) | ||
291 | cpu_relax(); /*This a nop instr on i386 */ | ||
292 | } | ||
293 | } | ||
294 | netxen_nic_reg_write(adapter, NETXEN_ROM_LOCK_ID, ROM_LOCK_DRIVER); | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static inline void rom_unlock(struct netxen_adapter *adapter) | ||
299 | { | ||
300 | u32 val; | ||
301 | |||
302 | /* release semaphore2 */ | ||
303 | netxen_nic_read_w0(adapter, NETXEN_PCIE_REG(PCIE_SEM2_UNLOCK), &val); | ||
304 | |||
305 | } | ||
306 | |||
307 | int netxen_wait_rom_done(struct netxen_adapter *adapter) | ||
308 | { | ||
309 | long timeout = 0; | ||
310 | long done = 0; | ||
311 | |||
312 | while (done == 0) { | ||
313 | done = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_GLB_STATUS); | ||
314 | done &= 2; | ||
315 | timeout++; | ||
316 | if (timeout >= rom_max_timeout) { | ||
317 | printk("Timeout reached waiting for rom done"); | ||
318 | return -EIO; | ||
319 | } | ||
320 | } | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static inline int | ||
325 | do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) | ||
326 | { | ||
327 | netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr); | ||
328 | netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3); | ||
329 | udelay(100); /* prevent bursting on CRB */ | ||
330 | netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); | ||
331 | netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb); | ||
332 | if (netxen_wait_rom_done(adapter)) { | ||
333 | printk("Error waiting for rom done\n"); | ||
334 | return -EIO; | ||
335 | } | ||
336 | /* reset abyte_cnt and dummy_byte_cnt */ | ||
337 | netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0); | ||
338 | udelay(100); /* prevent bursting on CRB */ | ||
339 | netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); | ||
340 | |||
341 | *valp = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_ROM_RDATA); | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) | ||
346 | { | ||
347 | int ret; | ||
348 | |||
349 | if (rom_lock(adapter) != 0) | ||
350 | return -EIO; | ||
351 | |||
352 | ret = do_rom_fast_read(adapter, addr, valp); | ||
353 | rom_unlock(adapter); | ||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | #define NETXEN_BOARDTYPE 0x4008 | ||
358 | #define NETXEN_BOARDNUM 0x400c | ||
359 | #define NETXEN_CHIPNUM 0x4010 | ||
360 | #define NETXEN_ROMBUS_RESET 0xFFFFFFFF | ||
361 | #define NETXEN_ROM_FIRST_BARRIER 0x800000000ULL | ||
362 | #define NETXEN_ROM_FOUND_INIT 0x400 | ||
363 | |||
364 | int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) | ||
365 | { | ||
366 | int addr, val, status; | ||
367 | int n, i; | ||
368 | int init_delay = 0; | ||
369 | struct crb_addr_pair *buf; | ||
370 | unsigned long off; | ||
371 | |||
372 | /* resetall */ | ||
373 | status = netxen_nic_get_board_info(adapter); | ||
374 | if (status) | ||
375 | printk("%s: pinit_from_rom: Error getting board info\n", | ||
376 | netxen_nic_driver_name); | ||
377 | |||
378 | netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_GLB_SW_RESET, | ||
379 | NETXEN_ROMBUS_RESET); | ||
380 | |||
381 | if (verbose) { | ||
382 | int val; | ||
383 | if (netxen_rom_fast_read(adapter, NETXEN_BOARDTYPE, &val) == 0) | ||
384 | printk("P2 ROM board type: 0x%08x\n", val); | ||
385 | else | ||
386 | printk("Could not read board type\n"); | ||
387 | if (netxen_rom_fast_read(adapter, NETXEN_BOARDNUM, &val) == 0) | ||
388 | printk("P2 ROM board num: 0x%08x\n", val); | ||
389 | else | ||
390 | printk("Could not read board number\n"); | ||
391 | if (netxen_rom_fast_read(adapter, NETXEN_CHIPNUM, &val) == 0) | ||
392 | printk("P2 ROM chip num: 0x%08x\n", val); | ||
393 | else | ||
394 | printk("Could not read chip number\n"); | ||
395 | } | ||
396 | |||
397 | if (netxen_rom_fast_read(adapter, 0, &n) == 0 | ||
398 | && (n & NETXEN_ROM_FIRST_BARRIER)) { | ||
399 | n &= ~NETXEN_ROM_ROUNDUP; | ||
400 | if (n < NETXEN_ROM_FOUND_INIT) { | ||
401 | if (verbose) | ||
402 | printk("%s: %d CRB init values found" | ||
403 | " in ROM.\n", netxen_nic_driver_name, n); | ||
404 | } else { | ||
405 | printk("%s:n=0x%x Error! NetXen card flash not" | ||
406 | " initialized.\n", __FUNCTION__, n); | ||
407 | return -EIO; | ||
408 | } | ||
409 | buf = kcalloc(n, sizeof(struct crb_addr_pair), GFP_KERNEL); | ||
410 | if (buf == NULL) { | ||
411 | printk("%s: pinit_from_rom: Unable to calloc memory.\n", | ||
412 | netxen_nic_driver_name); | ||
413 | return -ENOMEM; | ||
414 | } | ||
415 | for (i = 0; i < n; i++) { | ||
416 | if (netxen_rom_fast_read(adapter, 8 * i + 4, &val) != 0 | ||
417 | || netxen_rom_fast_read(adapter, 8 * i + 8, | ||
418 | &addr) != 0) | ||
419 | return -EIO; | ||
420 | |||
421 | buf[i].addr = addr; | ||
422 | buf[i].data = val; | ||
423 | |||
424 | if (verbose) | ||
425 | printk("%s: PCI: 0x%08x == 0x%08x\n", | ||
426 | netxen_nic_driver_name, (unsigned int) | ||
427 | netxen_decode_crb_addr((unsigned long) | ||
428 | addr), val); | ||
429 | } | ||
430 | for (i = 0; i < n; i++) { | ||
431 | |||
432 | off = | ||
433 | netxen_decode_crb_addr((unsigned long)buf[i].addr) + | ||
434 | NETXEN_PCI_CRBSPACE; | ||
435 | /* skipping cold reboot MAGIC */ | ||
436 | if (off == NETXEN_CAM_RAM(0x1fc)) | ||
437 | continue; | ||
438 | |||
439 | /* After writing this register, HW needs time for CRB */ | ||
440 | /* to quiet down (else crb_window returns 0xffffffff) */ | ||
441 | if (off == NETXEN_ROMUSB_GLB_SW_RESET) { | ||
442 | init_delay = 1; | ||
443 | /* hold xdma in reset also */ | ||
444 | buf[i].data = 0x8000ff; | ||
445 | } | ||
446 | |||
447 | if (ADDR_IN_WINDOW1(off)) { | ||
448 | writel(buf[i].data, | ||
449 | NETXEN_CRB_NORMALIZE(adapter, off)); | ||
450 | } else { | ||
451 | netxen_nic_pci_change_crbwindow(adapter, 0); | ||
452 | writel(buf[i].data, | ||
453 | adapter->ahw.pci_base + off); | ||
454 | |||
455 | netxen_nic_pci_change_crbwindow(adapter, 1); | ||
456 | } | ||
457 | if (init_delay == 1) { | ||
458 | ssleep(1); | ||
459 | init_delay = 0; | ||
460 | } | ||
461 | msleep(1); | ||
462 | } | ||
463 | kfree(buf); | ||
464 | |||
465 | /* disable_peg_cache_all */ | ||
466 | |||
467 | /* unreset_net_cache */ | ||
468 | netxen_nic_hw_read_wx(adapter, NETXEN_ROMUSB_GLB_SW_RESET, &val, | ||
469 | 4); | ||
470 | netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_GLB_SW_RESET, | ||
471 | (val & 0xffffff0f)); | ||
472 | /* p2dn replyCount */ | ||
473 | netxen_crb_writelit_adapter(adapter, | ||
474 | NETXEN_CRB_PEG_NET_D + 0xec, 0x1e); | ||
475 | /* disable_peg_cache 0 */ | ||
476 | netxen_crb_writelit_adapter(adapter, | ||
477 | NETXEN_CRB_PEG_NET_D + 0x4c, 8); | ||
478 | /* disable_peg_cache 1 */ | ||
479 | netxen_crb_writelit_adapter(adapter, | ||
480 | NETXEN_CRB_PEG_NET_I + 0x4c, 8); | ||
481 | |||
482 | /* peg_clr_all */ | ||
483 | |||
484 | /* peg_clr 0 */ | ||
485 | netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_0 + 0x8, | ||
486 | 0); | ||
487 | netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_0 + 0xc, | ||
488 | 0); | ||
489 | /* peg_clr 1 */ | ||
490 | netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_1 + 0x8, | ||
491 | 0); | ||
492 | netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_1 + 0xc, | ||
493 | 0); | ||
494 | /* peg_clr 2 */ | ||
495 | netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_2 + 0x8, | ||
496 | 0); | ||
497 | netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_2 + 0xc, | ||
498 | 0); | ||
499 | /* peg_clr 3 */ | ||
500 | netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_3 + 0x8, | ||
501 | 0); | ||
502 | netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_3 + 0xc, | ||
503 | 0); | ||
504 | } | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | void netxen_phantom_init(struct netxen_adapter *adapter) | ||
509 | { | ||
510 | u32 val = 0; | ||
511 | int loops = 0; | ||
512 | |||
513 | netxen_nic_hw_read_wx(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE, &val, 4); | ||
514 | writel(1, | ||
515 | NETXEN_CRB_NORMALIZE(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE)); | ||
516 | |||
517 | if (0 == val) { | ||
518 | while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) { | ||
519 | udelay(100); | ||
520 | val = | ||
521 | readl(NETXEN_CRB_NORMALIZE | ||
522 | (adapter, CRB_CMDPEG_STATE)); | ||
523 | loops++; | ||
524 | } | ||
525 | if (val != PHAN_INITIALIZE_COMPLETE) | ||
526 | printk("WARNING: Initial boot wait loop failed...\n"); | ||
527 | } | ||
528 | } | ||
529 | |||
530 | int netxen_nic_rx_has_work(struct netxen_adapter *adapter) | ||
531 | { | ||
532 | int ctx; | ||
533 | |||
534 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { | ||
535 | struct netxen_recv_context *recv_ctx = | ||
536 | &(adapter->recv_ctx[ctx]); | ||
537 | u32 consumer; | ||
538 | struct status_desc *desc_head; | ||
539 | struct status_desc *desc; /* used to read status desc here */ | ||
540 | |||
541 | consumer = recv_ctx->status_rx_consumer; | ||
542 | desc_head = recv_ctx->rcv_status_desc_head; | ||
543 | desc = &desc_head[consumer]; | ||
544 | |||
545 | if (((le16_to_cpu(desc->owner)) & STATUS_OWNER_HOST)) | ||
546 | return 1; | ||
547 | } | ||
548 | |||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | void netxen_watchdog_task(unsigned long v) | ||
553 | { | ||
554 | int port_num; | ||
555 | struct netxen_port *port; | ||
556 | struct net_device *netdev; | ||
557 | struct netxen_adapter *adapter = (struct netxen_adapter *)v; | ||
558 | |||
559 | for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) { | ||
560 | port = adapter->port[port_num]; | ||
561 | netdev = port->netdev; | ||
562 | |||
563 | if ((netif_running(netdev)) && !netif_carrier_ok(netdev)) { | ||
564 | printk(KERN_INFO "%s port %d, %s carrier is now ok\n", | ||
565 | netxen_nic_driver_name, port_num, netdev->name); | ||
566 | netif_carrier_on(netdev); | ||
567 | } | ||
568 | |||
569 | if (netif_queue_stopped(netdev)) | ||
570 | netif_wake_queue(netdev); | ||
571 | } | ||
572 | |||
573 | netxen_nic_pci_change_crbwindow(adapter, 1); | ||
574 | |||
575 | if (adapter->ops->handle_phy_intr) | ||
576 | adapter->ops->handle_phy_intr(adapter); | ||
577 | mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); | ||
578 | } | ||
579 | |||
580 | /* | ||
581 | * netxen_process_rcv() send the received packet to the protocol stack. | ||
582 | * and if the number of receives exceeds RX_BUFFERS_REFILL, then we | ||
583 | * invoke the routine to send more rx buffers to the Phantom... | ||
584 | */ | ||
585 | void | ||
586 | netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, | ||
587 | struct status_desc *desc) | ||
588 | { | ||
589 | struct netxen_port *port = adapter->port[STATUS_DESC_PORT(desc)]; | ||
590 | struct pci_dev *pdev = port->pdev; | ||
591 | struct net_device *netdev = port->netdev; | ||
592 | int index = le16_to_cpu(desc->reference_handle); | ||
593 | struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]); | ||
594 | struct netxen_rx_buffer *buffer; | ||
595 | struct sk_buff *skb; | ||
596 | u32 length = le16_to_cpu(desc->total_length); | ||
597 | u32 desc_ctx; | ||
598 | struct netxen_rcv_desc_ctx *rcv_desc; | ||
599 | int ret; | ||
600 | |||
601 | desc_ctx = STATUS_DESC_TYPE(desc); | ||
602 | if (unlikely(desc_ctx >= NUM_RCV_DESC_RINGS)) { | ||
603 | printk("%s: %s Bad Rcv descriptor ring\n", | ||
604 | netxen_nic_driver_name, netdev->name); | ||
605 | return; | ||
606 | } | ||
607 | |||
608 | rcv_desc = &recv_ctx->rcv_desc[desc_ctx]; | ||
609 | buffer = &rcv_desc->rx_buf_arr[index]; | ||
610 | |||
611 | pci_unmap_single(pdev, buffer->dma, rcv_desc->dma_size, | ||
612 | PCI_DMA_FROMDEVICE); | ||
613 | |||
614 | skb = (struct sk_buff *)buffer->skb; | ||
615 | |||
616 | if (likely(STATUS_DESC_STATUS(desc) == STATUS_CKSUM_OK)) { | ||
617 | port->stats.csummed++; | ||
618 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
619 | } else | ||
620 | skb->ip_summed = CHECKSUM_NONE; | ||
621 | skb->dev = netdev; | ||
622 | skb_put(skb, length); | ||
623 | skb->protocol = eth_type_trans(skb, netdev); | ||
624 | |||
625 | ret = netif_receive_skb(skb); | ||
626 | |||
627 | /* | ||
628 | * RH: Do we need these stats on a regular basis. Can we get it from | ||
629 | * Linux stats. | ||
630 | */ | ||
631 | switch (ret) { | ||
632 | case NET_RX_SUCCESS: | ||
633 | port->stats.uphappy++; | ||
634 | break; | ||
635 | |||
636 | case NET_RX_CN_LOW: | ||
637 | port->stats.uplcong++; | ||
638 | break; | ||
639 | |||
640 | case NET_RX_CN_MOD: | ||
641 | port->stats.upmcong++; | ||
642 | break; | ||
643 | |||
644 | case NET_RX_CN_HIGH: | ||
645 | port->stats.uphcong++; | ||
646 | break; | ||
647 | |||
648 | case NET_RX_DROP: | ||
649 | port->stats.updropped++; | ||
650 | break; | ||
651 | |||
652 | default: | ||
653 | port->stats.updunno++; | ||
654 | break; | ||
655 | } | ||
656 | |||
657 | netdev->last_rx = jiffies; | ||
658 | |||
659 | rcv_desc->rcv_free++; | ||
660 | rcv_desc->rcv_pending--; | ||
661 | |||
662 | /* | ||
663 | * We just consumed one buffer so post a buffer. | ||
664 | */ | ||
665 | adapter->stats.post_called++; | ||
666 | buffer->skb = NULL; | ||
667 | buffer->state = NETXEN_BUFFER_FREE; | ||
668 | |||
669 | port->stats.no_rcv++; | ||
670 | port->stats.rxbytes += length; | ||
671 | } | ||
672 | |||
673 | /* Process Receive status ring */ | ||
674 | u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max) | ||
675 | { | ||
676 | struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]); | ||
677 | struct status_desc *desc_head = recv_ctx->rcv_status_desc_head; | ||
678 | struct status_desc *desc; /* used to read status desc here */ | ||
679 | u32 consumer = recv_ctx->status_rx_consumer; | ||
680 | int count = 0, ring; | ||
681 | |||
682 | DPRINTK(INFO, "procesing receive\n"); | ||
683 | /* | ||
684 | * we assume in this case that there is only one port and that is | ||
685 | * port #1...changes need to be done in firmware to indicate port | ||
686 | * number as part of the descriptor. This way we will be able to get | ||
687 | * the netdev which is associated with that device. | ||
688 | */ | ||
689 | while (count < max) { | ||
690 | desc = &desc_head[consumer]; | ||
691 | if (!((le16_to_cpu(desc->owner)) & STATUS_OWNER_HOST)) { | ||
692 | DPRINTK(ERR, "desc %p ownedby %x\n", desc, desc->owner); | ||
693 | break; | ||
694 | } | ||
695 | netxen_process_rcv(adapter, ctxid, desc); | ||
696 | desc->owner = STATUS_OWNER_PHANTOM; | ||
697 | consumer = (consumer + 1) & (adapter->max_rx_desc_count - 1); | ||
698 | count++; | ||
699 | } | ||
700 | if (count) { | ||
701 | for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { | ||
702 | netxen_post_rx_buffers(adapter, ctxid, ring); | ||
703 | } | ||
704 | } | ||
705 | |||
706 | /* update the consumer index in phantom */ | ||
707 | if (count) { | ||
708 | adapter->stats.process_rcv++; | ||
709 | recv_ctx->status_rx_consumer = consumer; | ||
710 | |||
711 | /* Window = 1 */ | ||
712 | writel(consumer, | ||
713 | NETXEN_CRB_NORMALIZE(adapter, | ||
714 | recv_crb_registers[ctxid]. | ||
715 | crb_rcv_status_consumer)); | ||
716 | } | ||
717 | |||
718 | return count; | ||
719 | } | ||
720 | |||
721 | /* Process Command status ring */ | ||
722 | void netxen_process_cmd_ring(unsigned long data) | ||
723 | { | ||
724 | u32 last_consumer; | ||
725 | u32 consumer; | ||
726 | struct netxen_adapter *adapter = (struct netxen_adapter *)data; | ||
727 | int count = 0; | ||
728 | struct netxen_cmd_buffer *buffer; | ||
729 | struct netxen_port *port; /* port #1 */ | ||
730 | struct netxen_port *nport; | ||
731 | struct pci_dev *pdev; | ||
732 | struct netxen_skb_frag *frag; | ||
733 | u32 i; | ||
734 | struct sk_buff *skb = NULL; | ||
735 | int p; | ||
736 | |||
737 | spin_lock(&adapter->tx_lock); | ||
738 | last_consumer = adapter->last_cmd_consumer; | ||
739 | DPRINTK(INFO, "procesing xmit complete\n"); | ||
740 | /* we assume in this case that there is only one port and that is | ||
741 | * port #1...changes need to be done in firmware to indicate port | ||
742 | * number as part of the descriptor. This way we will be able to get | ||
743 | * the netdev which is associated with that device. | ||
744 | */ | ||
745 | /* Window = 1 */ | ||
746 | consumer = | ||
747 | readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_CONSUMER_OFFSET)); | ||
748 | |||
749 | if (last_consumer == consumer) { /* Ring is empty */ | ||
750 | DPRINTK(INFO, "last_consumer %d == consumer %d\n", | ||
751 | last_consumer, consumer); | ||
752 | spin_unlock(&adapter->tx_lock); | ||
753 | return; | ||
754 | } | ||
755 | |||
756 | adapter->proc_cmd_buf_counter++; | ||
757 | adapter->stats.process_xmit++; | ||
758 | /* | ||
759 | * Not needed - does not seem to be used anywhere. | ||
760 | * adapter->cmd_consumer = consumer; | ||
761 | */ | ||
762 | spin_unlock(&adapter->tx_lock); | ||
763 | |||
764 | while ((last_consumer != consumer) && (count < MAX_STATUS_HANDLE)) { | ||
765 | buffer = &adapter->cmd_buf_arr[last_consumer]; | ||
766 | port = adapter->port[buffer->port]; | ||
767 | pdev = port->pdev; | ||
768 | frag = &buffer->frag_array[0]; | ||
769 | skb = buffer->skb; | ||
770 | if (skb && (cmpxchg(&buffer->skb, skb, 0) == skb)) { | ||
771 | pci_unmap_single(pdev, frag->dma, frag->length, | ||
772 | PCI_DMA_TODEVICE); | ||
773 | for (i = 1; i < buffer->frag_count; i++) { | ||
774 | DPRINTK(INFO, "getting fragment no %d\n", i); | ||
775 | frag++; /* Get the next frag */ | ||
776 | pci_unmap_page(pdev, frag->dma, frag->length, | ||
777 | PCI_DMA_TODEVICE); | ||
778 | } | ||
779 | |||
780 | port->stats.skbfreed++; | ||
781 | dev_kfree_skb_any(skb); | ||
782 | skb = NULL; | ||
783 | } else if (adapter->proc_cmd_buf_counter == 1) { | ||
784 | port->stats.txnullskb++; | ||
785 | } | ||
786 | if (unlikely(netif_queue_stopped(port->netdev) | ||
787 | && netif_carrier_ok(port->netdev)) | ||
788 | && ((jiffies - port->netdev->trans_start) > | ||
789 | port->netdev->watchdog_timeo)) { | ||
790 | schedule_work(&port->adapter->tx_timeout_task); | ||
791 | } | ||
792 | |||
793 | last_consumer = get_next_index(last_consumer, | ||
794 | adapter->max_tx_desc_count); | ||
795 | count++; | ||
796 | } | ||
797 | adapter->stats.noxmitdone += count; | ||
798 | |||
799 | count = 0; | ||
800 | spin_lock(&adapter->tx_lock); | ||
801 | if ((--adapter->proc_cmd_buf_counter) == 0) { | ||
802 | adapter->last_cmd_consumer = last_consumer; | ||
803 | while ((adapter->last_cmd_consumer != consumer) | ||
804 | && (count < MAX_STATUS_HANDLE)) { | ||
805 | buffer = | ||
806 | &adapter->cmd_buf_arr[adapter->last_cmd_consumer]; | ||
807 | count++; | ||
808 | if (buffer->skb) | ||
809 | break; | ||
810 | else | ||
811 | adapter->last_cmd_consumer = | ||
812 | get_next_index(adapter->last_cmd_consumer, | ||
813 | adapter->max_tx_desc_count); | ||
814 | } | ||
815 | } | ||
816 | if (count) { | ||
817 | for (p = 0; p < adapter->ahw.max_ports; p++) { | ||
818 | nport = adapter->port[p]; | ||
819 | if (netif_queue_stopped(nport->netdev) | ||
820 | && (nport->flags & NETXEN_NETDEV_STATUS)) { | ||
821 | netif_wake_queue(nport->netdev); | ||
822 | nport->flags &= ~NETXEN_NETDEV_STATUS; | ||
823 | } | ||
824 | } | ||
825 | } | ||
826 | |||
827 | spin_unlock(&adapter->tx_lock); | ||
828 | DPRINTK(INFO, "last consumer is %d in %s\n", last_consumer, | ||
829 | __FUNCTION__); | ||
830 | } | ||
831 | |||
832 | /* | ||
833 | * netxen_post_rx_buffers puts buffer in the Phantom memory | ||
834 | */ | ||
835 | void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) | ||
836 | { | ||
837 | struct pci_dev *pdev = adapter->ahw.pdev; | ||
838 | struct sk_buff *skb; | ||
839 | struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctx]); | ||
840 | struct netxen_rcv_desc_ctx *rcv_desc = NULL; | ||
841 | struct netxen_recv_crb *crbarea = &recv_crb_registers[ctx]; | ||
842 | struct netxen_rcv_desc_crb *rcv_desc_crb = NULL; | ||
843 | u32 producer; | ||
844 | struct rcv_desc *pdesc; | ||
845 | struct netxen_rx_buffer *buffer; | ||
846 | int count = 0; | ||
847 | int index = 0; | ||
848 | |||
849 | adapter->stats.post_called++; | ||
850 | rcv_desc = &recv_ctx->rcv_desc[ringid]; | ||
851 | rcv_desc_crb = &crbarea->rcv_desc_crb[ringid]; | ||
852 | |||
853 | producer = rcv_desc->producer; | ||
854 | index = rcv_desc->begin_alloc; | ||
855 | buffer = &rcv_desc->rx_buf_arr[index]; | ||
856 | /* We can start writing rx descriptors into the phantom memory. */ | ||
857 | while (buffer->state == NETXEN_BUFFER_FREE) { | ||
858 | skb = dev_alloc_skb(rcv_desc->skb_size); | ||
859 | if (unlikely(!skb)) { | ||
860 | /* | ||
861 | * We need to schedule the posting of buffers to the pegs. | ||
862 | */ | ||
863 | rcv_desc->begin_alloc = index; | ||
864 | DPRINTK(ERR, "unm_post_rx_buffers: " | ||
865 | " allocated only %d buffers\n", count); | ||
866 | break; | ||
867 | } | ||
868 | count++; /* now there should be no failure */ | ||
869 | pdesc = &rcv_desc->desc_head[producer]; | ||
870 | skb_reserve(skb, NET_IP_ALIGN); | ||
871 | /* | ||
872 | * This will be setup when we receive the | ||
873 | * buffer after it has been filled | ||
874 | * skb->dev = netdev; | ||
875 | */ | ||
876 | buffer->skb = skb; | ||
877 | buffer->state = NETXEN_BUFFER_BUSY; | ||
878 | buffer->dma = pci_map_single(pdev, skb->data, | ||
879 | rcv_desc->dma_size, | ||
880 | PCI_DMA_FROMDEVICE); | ||
881 | /* make a rcv descriptor */ | ||
882 | pdesc->reference_handle = le16_to_cpu(buffer->ref_handle); | ||
883 | pdesc->buffer_length = le16_to_cpu(rcv_desc->dma_size); | ||
884 | pdesc->addr_buffer = cpu_to_le64(buffer->dma); | ||
885 | DPRINTK(INFO, "done writing descripter\n"); | ||
886 | producer = | ||
887 | get_next_index(producer, rcv_desc->max_rx_desc_count); | ||
888 | index = get_next_index(index, rcv_desc->max_rx_desc_count); | ||
889 | buffer = &rcv_desc->rx_buf_arr[index]; | ||
890 | } | ||
891 | |||
892 | /* if we did allocate buffers, then write the count to Phantom */ | ||
893 | if (count) { | ||
894 | rcv_desc->begin_alloc = index; | ||
895 | rcv_desc->rcv_pending += count; | ||
896 | adapter->stats.lastposted = count; | ||
897 | adapter->stats.posted += count; | ||
898 | rcv_desc->producer = producer; | ||
899 | if (rcv_desc->rcv_free >= 32) { | ||
900 | rcv_desc->rcv_free = 0; | ||
901 | /* Window = 1 */ | ||
902 | writel((producer - 1) & | ||
903 | (rcv_desc->max_rx_desc_count - 1), | ||
904 | NETXEN_CRB_NORMALIZE(adapter, | ||
905 | rcv_desc_crb-> | ||
906 | crb_rcv_producer_offset)); | ||
907 | wmb(); | ||
908 | } | ||
909 | } | ||
910 | } | ||
911 | |||
912 | int netxen_nic_tx_has_work(struct netxen_adapter *adapter) | ||
913 | { | ||
914 | if (find_diff_among(adapter->last_cmd_consumer, | ||
915 | adapter->cmd_producer, | ||
916 | adapter->max_tx_desc_count) > 0) | ||
917 | return 1; | ||
918 | |||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | int | ||
923 | netxen_nic_fill_statistics(struct netxen_adapter *adapter, | ||
924 | struct netxen_port *port, | ||
925 | struct netxen_statistics *netxen_stats) | ||
926 | { | ||
927 | void __iomem *addr; | ||
928 | |||
929 | if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { | ||
930 | netxen_nic_pci_change_crbwindow(adapter, 0); | ||
931 | NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_TX_BYTE_CNT, | ||
932 | &(netxen_stats->tx_bytes)); | ||
933 | NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_TX_FRAME_CNT, | ||
934 | &(netxen_stats->tx_packets)); | ||
935 | NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_RX_BYTE_CNT, | ||
936 | &(netxen_stats->rx_bytes)); | ||
937 | NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_RX_FRAME_CNT, | ||
938 | &(netxen_stats->rx_packets)); | ||
939 | NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_AGGR_ERROR_CNT, | ||
940 | &(netxen_stats->rx_errors)); | ||
941 | NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_CRC_ERROR_CNT, | ||
942 | &(netxen_stats->rx_crc_errors)); | ||
943 | NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_OVERSIZE_FRAME_ERR, | ||
944 | &(netxen_stats-> | ||
945 | rx_long_length_error)); | ||
946 | NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_UNDERSIZE_FRAME_ERR, | ||
947 | &(netxen_stats-> | ||
948 | rx_short_length_error)); | ||
949 | |||
950 | netxen_nic_pci_change_crbwindow(adapter, 1); | ||
951 | } else { | ||
952 | spin_lock_bh(&adapter->tx_lock); | ||
953 | netxen_stats->tx_bytes = port->stats.txbytes; | ||
954 | netxen_stats->tx_packets = port->stats.xmitedframes + | ||
955 | port->stats.xmitfinished; | ||
956 | netxen_stats->rx_bytes = port->stats.rxbytes; | ||
957 | netxen_stats->rx_packets = port->stats.no_rcv; | ||
958 | netxen_stats->rx_errors = port->stats.rcvdbadskb; | ||
959 | netxen_stats->tx_errors = port->stats.nocmddescriptor; | ||
960 | netxen_stats->rx_short_length_error = port->stats.uplcong; | ||
961 | netxen_stats->rx_long_length_error = port->stats.uphcong; | ||
962 | netxen_stats->rx_crc_errors = 0; | ||
963 | netxen_stats->rx_mac_errors = 0; | ||
964 | spin_unlock_bh(&adapter->tx_lock); | ||
965 | } | ||
966 | return 0; | ||
967 | } | ||
968 | |||
969 | void netxen_nic_clear_stats(struct netxen_adapter *adapter) | ||
970 | { | ||
971 | struct netxen_port *port; | ||
972 | int port_num; | ||
973 | |||
974 | memset(&adapter->stats, 0, sizeof(adapter->stats)); | ||
975 | for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) { | ||
976 | port = adapter->port[port_num]; | ||
977 | memset(&port->stats, 0, sizeof(port->stats)); | ||
978 | } | ||
979 | } | ||
980 | |||
981 | int | ||
982 | netxen_nic_clear_statistics(struct netxen_adapter *adapter, | ||
983 | struct netxen_port *port) | ||
984 | { | ||
985 | int data = 0; | ||
986 | |||
987 | netxen_nic_pci_change_crbwindow(adapter, 0); | ||
988 | |||
989 | netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_TX_BYTE_CNT, &data); | ||
990 | netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_TX_FRAME_CNT, | ||
991 | &data); | ||
992 | netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_RX_BYTE_CNT, &data); | ||
993 | netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_RX_FRAME_CNT, | ||
994 | &data); | ||
995 | netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_AGGR_ERROR_CNT, | ||
996 | &data); | ||
997 | netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_CRC_ERROR_CNT, | ||
998 | &data); | ||
999 | netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_OVERSIZE_FRAME_ERR, | ||
1000 | &data); | ||
1001 | netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_UNDERSIZE_FRAME_ERR, | ||
1002 | &data); | ||
1003 | |||
1004 | netxen_nic_pci_change_crbwindow(adapter, 1); | ||
1005 | netxen_nic_clear_stats(adapter); | ||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | int | ||
1010 | netxen_nic_do_ioctl(struct netxen_adapter *adapter, void *u_data, | ||
1011 | struct netxen_port *port) | ||
1012 | { | ||
1013 | struct netxen_nic_ioctl_data data; | ||
1014 | struct netxen_nic_ioctl_data *up_data; | ||
1015 | int retval = 0; | ||
1016 | struct netxen_statistics netxen_stats; | ||
1017 | |||
1018 | up_data = (void *)u_data; | ||
1019 | |||
1020 | DPRINTK(INFO, "doing ioctl for %p\n", adapter); | ||
1021 | if (copy_from_user(&data, (void __user *)up_data, sizeof(data))) { | ||
1022 | /* evil user tried to crash the kernel */ | ||
1023 | DPRINTK(ERR, "bad copy from userland: %d\n", (int)sizeof(data)); | ||
1024 | retval = -EFAULT; | ||
1025 | goto error_out; | ||
1026 | } | ||
1027 | |||
1028 | /* Shouldn't access beyond legal limits of "char u[64];" member */ | ||
1029 | if (!data.ptr && (data.size > sizeof(data.u))) { | ||
1030 | /* evil user tried to crash the kernel */ | ||
1031 | DPRINTK(ERR, "bad size: %d\n", data.size); | ||
1032 | retval = -EFAULT; | ||
1033 | goto error_out; | ||
1034 | } | ||
1035 | |||
1036 | switch (data.cmd) { | ||
1037 | case netxen_nic_cmd_pci_read: | ||
1038 | if ((retval = netxen_nic_hw_read_wx(adapter, data.off, | ||
1039 | &(data.u), data.size))) | ||
1040 | goto error_out; | ||
1041 | if (copy_to_user | ||
1042 | ((void __user *)&(up_data->u), &(data.u), data.size)) { | ||
1043 | DPRINTK(ERR, "bad copy to userland: %d\n", | ||
1044 | (int)sizeof(data)); | ||
1045 | retval = -EFAULT; | ||
1046 | goto error_out; | ||
1047 | } | ||
1048 | data.rv = 0; | ||
1049 | break; | ||
1050 | |||
1051 | case netxen_nic_cmd_pci_write: | ||
1052 | data.rv = netxen_nic_hw_write_wx(adapter, data.off, &(data.u), | ||
1053 | data.size); | ||
1054 | break; | ||
1055 | |||
1056 | case netxen_nic_cmd_pci_config_read: | ||
1057 | switch (data.size) { | ||
1058 | case 1: | ||
1059 | data.rv = pci_read_config_byte(adapter->ahw.pdev, | ||
1060 | data.off, | ||
1061 | (char *)&(data.u)); | ||
1062 | break; | ||
1063 | case 2: | ||
1064 | data.rv = pci_read_config_word(adapter->ahw.pdev, | ||
1065 | data.off, | ||
1066 | (short *)&(data.u)); | ||
1067 | break; | ||
1068 | case 4: | ||
1069 | data.rv = pci_read_config_dword(adapter->ahw.pdev, | ||
1070 | data.off, | ||
1071 | (u32 *) & (data.u)); | ||
1072 | break; | ||
1073 | } | ||
1074 | if (copy_to_user | ||
1075 | ((void __user *)&(up_data->u), &(data.u), data.size)) { | ||
1076 | DPRINTK(ERR, "bad copy to userland: %d\n", | ||
1077 | (int)sizeof(data)); | ||
1078 | retval = -EFAULT; | ||
1079 | goto error_out; | ||
1080 | } | ||
1081 | break; | ||
1082 | |||
1083 | case netxen_nic_cmd_pci_config_write: | ||
1084 | switch (data.size) { | ||
1085 | case 1: | ||
1086 | data.rv = pci_write_config_byte(adapter->ahw.pdev, | ||
1087 | data.off, | ||
1088 | *(char *)&(data.u)); | ||
1089 | break; | ||
1090 | case 2: | ||
1091 | data.rv = pci_write_config_word(adapter->ahw.pdev, | ||
1092 | data.off, | ||
1093 | *(short *)&(data.u)); | ||
1094 | break; | ||
1095 | case 4: | ||
1096 | data.rv = pci_write_config_dword(adapter->ahw.pdev, | ||
1097 | data.off, | ||
1098 | *(u32 *) & (data.u)); | ||
1099 | break; | ||
1100 | } | ||
1101 | break; | ||
1102 | |||
1103 | case netxen_nic_cmd_get_stats: | ||
1104 | data.rv = | ||
1105 | netxen_nic_fill_statistics(adapter, port, &netxen_stats); | ||
1106 | if (copy_to_user | ||
1107 | ((void __user *)(up_data->ptr), (void *)&netxen_stats, | ||
1108 | sizeof(struct netxen_statistics))) { | ||
1109 | DPRINTK(ERR, "bad copy to userland: %d\n", | ||
1110 | (int)sizeof(netxen_stats)); | ||
1111 | retval = -EFAULT; | ||
1112 | goto error_out; | ||
1113 | } | ||
1114 | up_data->rv = data.rv; | ||
1115 | break; | ||
1116 | |||
1117 | case netxen_nic_cmd_clear_stats: | ||
1118 | data.rv = netxen_nic_clear_statistics(adapter, port); | ||
1119 | up_data->rv = data.rv; | ||
1120 | break; | ||
1121 | |||
1122 | case netxen_nic_cmd_get_version: | ||
1123 | if (copy_to_user | ||
1124 | ((void __user *)&(up_data->u), NETXEN_NIC_LINUX_VERSIONID, | ||
1125 | sizeof(NETXEN_NIC_LINUX_VERSIONID))) { | ||
1126 | DPRINTK(ERR, "bad copy to userland: %d\n", | ||
1127 | (int)sizeof(data)); | ||
1128 | retval = -EFAULT; | ||
1129 | goto error_out; | ||
1130 | } | ||
1131 | break; | ||
1132 | |||
1133 | default: | ||
1134 | DPRINTK(INFO, "bad command %d for %p\n", data.cmd, adapter); | ||
1135 | retval = -EOPNOTSUPP; | ||
1136 | goto error_out; | ||
1137 | } | ||
1138 | put_user(data.rv, (u16 __user *) (&(up_data->rv))); | ||
1139 | DPRINTK(INFO, "done ioctl for %p well.\n", adapter); | ||
1140 | |||
1141 | error_out: | ||
1142 | return retval; | ||
1143 | } | ||