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