blob: 6668b99025c844b61e3b0580ce27ddf3b95838bf [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/************************************************************************
2 * s2io.c: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC
3 * Copyright(c) 2002-2005 Neterion Inc.
4
5 * This software may be used and distributed according to the terms of
6 * the GNU General Public License (GPL), incorporated herein by reference.
7 * Drivers based on or derived from this code fall under the GPL and must
8 * retain the authorship, copyright and license notice. This file is not
9 * a complete program and may only be used when the entire operating
10 * system is licensed under the GPL.
11 * See the file COPYING in this distribution for more information.
12 *
13 * Credits:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070014 * Jeff Garzik : For pointing out the improper error condition
15 * check in the s2io_xmit routine and also some
16 * issues in the Tx watch dog function. Also for
17 * patiently answering all those innumerable
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 * questions regaring the 2.6 porting issues.
19 * Stephen Hemminger : Providing proper 2.6 porting mechanism for some
20 * macros available only in 2.6 Kernel.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070021 * Francois Romieu : For pointing out all code part that were
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 * deprecated and also styling related comments.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070023 * Grant Grundler : For helping me get rid of some Architecture
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 * dependent code.
25 * Christopher Hellwig : Some more 2.6 specific issues in the driver.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070026 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 * The module loadable parameters that are supported by the driver and a brief
28 * explaination of all the variables.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070029 * rx_ring_num : This can be used to program the number of receive rings used
30 * in the driver.
31 * rx_ring_len: This defines the number of descriptors each ring can have. This
Linus Torvalds1da177e2005-04-16 15:20:36 -070032 * is also an array of size 8.
33 * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070034 * tx_fifo_len: This too is an array of 8. Each element defines the number of
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 * Tx descriptors that can be associated with each corresponding FIFO.
Linus Torvalds1da177e2005-04-16 15:20:36 -070036 ************************************************************************/
37
38#include <linux/config.h>
39#include <linux/module.h>
40#include <linux/types.h>
41#include <linux/errno.h>
42#include <linux/ioport.h>
43#include <linux/pci.h>
Domen Puncer1e7f0bd2005-06-26 18:22:14 -040044#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <linux/kernel.h>
46#include <linux/netdevice.h>
47#include <linux/etherdevice.h>
48#include <linux/skbuff.h>
49#include <linux/init.h>
50#include <linux/delay.h>
51#include <linux/stddef.h>
52#include <linux/ioctl.h>
53#include <linux/timex.h>
54#include <linux/sched.h>
55#include <linux/ethtool.h>
56#include <linux/version.h>
57#include <linux/workqueue.h>
58
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <asm/system.h>
60#include <asm/uaccess.h>
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070061#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63/* local include */
64#include "s2io.h"
65#include "s2io-regs.h"
66
67/* S2io Driver name & version. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070068static char s2io_driver_name[] = "Neterion";
69static char s2io_driver_version[] = "Version 1.7.7";
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -070071static inline int RXD_IS_UP2DT(RxD_t *rxdp)
72{
73 int ret;
74
75 ret = ((!(rxdp->Control_1 & RXD_OWN_XENA)) &&
76 (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK));
77
78 return ret;
79}
80
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070081/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 * Cards with following subsystem_id have a link state indication
83 * problem, 600B, 600C, 600D, 640B, 640C and 640D.
84 * macro below identifies these cards given the subsystem_id.
85 */
86#define CARDS_WITH_FAULTY_LINK_INDICATORS(subid) \
87 (((subid >= 0x600B) && (subid <= 0x600D)) || \
88 ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0
89
90#define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \
91 ADAPTER_STATUS_RMAC_LOCAL_FAULT)))
92#define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status))
93#define PANIC 1
94#define LOW 2
95static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring)
96{
97 int level = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070098 mac_info_t *mac_control;
99
100 mac_control = &sp->mac_control;
101 if ((mac_control->rings[ring].pkt_cnt - rxb_size) > 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 level = LOW;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700103 if ((mac_control->rings[ring].pkt_cnt - rxb_size) <
104 MAX_RXDS_PER_BLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 level = PANIC;
106 }
107 }
108
109 return level;
110}
111
112/* Ethtool related variables and Macros. */
113static char s2io_gstrings[][ETH_GSTRING_LEN] = {
114 "Register test\t(offline)",
115 "Eeprom test\t(offline)",
116 "Link test\t(online)",
117 "RLDRAM test\t(offline)",
118 "BIST Test\t(offline)"
119};
120
121static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
122 {"tmac_frms"},
123 {"tmac_data_octets"},
124 {"tmac_drop_frms"},
125 {"tmac_mcst_frms"},
126 {"tmac_bcst_frms"},
127 {"tmac_pause_ctrl_frms"},
128 {"tmac_any_err_frms"},
129 {"tmac_vld_ip_octets"},
130 {"tmac_vld_ip"},
131 {"tmac_drop_ip"},
132 {"tmac_icmp"},
133 {"tmac_rst_tcp"},
134 {"tmac_tcp"},
135 {"tmac_udp"},
136 {"rmac_vld_frms"},
137 {"rmac_data_octets"},
138 {"rmac_fcs_err_frms"},
139 {"rmac_drop_frms"},
140 {"rmac_vld_mcst_frms"},
141 {"rmac_vld_bcst_frms"},
142 {"rmac_in_rng_len_err_frms"},
143 {"rmac_long_frms"},
144 {"rmac_pause_ctrl_frms"},
145 {"rmac_discarded_frms"},
146 {"rmac_usized_frms"},
147 {"rmac_osized_frms"},
148 {"rmac_frag_frms"},
149 {"rmac_jabber_frms"},
150 {"rmac_ip"},
151 {"rmac_ip_octets"},
152 {"rmac_hdr_err_ip"},
153 {"rmac_drop_ip"},
154 {"rmac_icmp"},
155 {"rmac_tcp"},
156 {"rmac_udp"},
157 {"rmac_err_drp_udp"},
158 {"rmac_pause_cnt"},
159 {"rmac_accepted_ip"},
160 {"rmac_err_tcp"},
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -0700161 {"\n DRIVER STATISTICS"},
162 {"single_bit_ecc_errs"},
163 {"double_bit_ecc_errs"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164};
165
166#define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN
167#define S2IO_STAT_STRINGS_LEN S2IO_STAT_LEN * ETH_GSTRING_LEN
168
169#define S2IO_TEST_LEN sizeof(s2io_gstrings) / ETH_GSTRING_LEN
170#define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN
171
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700172/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 * Constants to be programmed into the Xena's registers, to configure
174 * the XAUI.
175 */
176
177#define SWITCH_SIGN 0xA5A5A5A5A5A5A5A5ULL
178#define END_SIGN 0x0
179
180static u64 default_mdio_cfg[] = {
181 /* Reset PMA PLL */
182 0xC001010000000000ULL, 0xC0010100000000E0ULL,
183 0xC0010100008000E4ULL,
184 /* Remove Reset from PMA PLL */
185 0xC001010000000000ULL, 0xC0010100000000E0ULL,
186 0xC0010100000000E4ULL,
187 END_SIGN
188};
189
190static u64 default_dtx_cfg[] = {
191 0x8000051500000000ULL, 0x80000515000000E0ULL,
192 0x80000515D93500E4ULL, 0x8001051500000000ULL,
193 0x80010515000000E0ULL, 0x80010515001E00E4ULL,
194 0x8002051500000000ULL, 0x80020515000000E0ULL,
195 0x80020515F21000E4ULL,
196 /* Set PADLOOPBACKN */
197 0x8002051500000000ULL, 0x80020515000000E0ULL,
198 0x80020515B20000E4ULL, 0x8003051500000000ULL,
199 0x80030515000000E0ULL, 0x80030515B20000E4ULL,
200 0x8004051500000000ULL, 0x80040515000000E0ULL,
201 0x80040515B20000E4ULL, 0x8005051500000000ULL,
202 0x80050515000000E0ULL, 0x80050515B20000E4ULL,
203 SWITCH_SIGN,
204 /* Remove PADLOOPBACKN */
205 0x8002051500000000ULL, 0x80020515000000E0ULL,
206 0x80020515F20000E4ULL, 0x8003051500000000ULL,
207 0x80030515000000E0ULL, 0x80030515F20000E4ULL,
208 0x8004051500000000ULL, 0x80040515000000E0ULL,
209 0x80040515F20000E4ULL, 0x8005051500000000ULL,
210 0x80050515000000E0ULL, 0x80050515F20000E4ULL,
211 END_SIGN
212};
213
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700214/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 * Constants for Fixing the MacAddress problem seen mostly on
216 * Alpha machines.
217 */
218static u64 fix_mac[] = {
219 0x0060000000000000ULL, 0x0060600000000000ULL,
220 0x0040600000000000ULL, 0x0000600000000000ULL,
221 0x0020600000000000ULL, 0x0060600000000000ULL,
222 0x0020600000000000ULL, 0x0060600000000000ULL,
223 0x0020600000000000ULL, 0x0060600000000000ULL,
224 0x0020600000000000ULL, 0x0060600000000000ULL,
225 0x0020600000000000ULL, 0x0060600000000000ULL,
226 0x0020600000000000ULL, 0x0060600000000000ULL,
227 0x0020600000000000ULL, 0x0060600000000000ULL,
228 0x0020600000000000ULL, 0x0060600000000000ULL,
229 0x0020600000000000ULL, 0x0060600000000000ULL,
230 0x0020600000000000ULL, 0x0060600000000000ULL,
231 0x0020600000000000ULL, 0x0000600000000000ULL,
232 0x0040600000000000ULL, 0x0060600000000000ULL,
233 END_SIGN
234};
235
236/* Module Loadable parameters. */
237static unsigned int tx_fifo_num = 1;
238static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
239 {[0 ...(MAX_TX_FIFOS - 1)] = 0 };
240static unsigned int rx_ring_num = 1;
241static unsigned int rx_ring_sz[MAX_RX_RINGS] =
242 {[0 ...(MAX_RX_RINGS - 1)] = 0 };
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700243static unsigned int rts_frm_len[MAX_RX_RINGS] =
244 {[0 ...(MAX_RX_RINGS - 1)] = 0 };
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700245static unsigned int use_continuous_tx_intrs = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246static unsigned int rmac_pause_time = 65535;
247static unsigned int mc_pause_threshold_q0q3 = 187;
248static unsigned int mc_pause_threshold_q4q7 = 187;
249static unsigned int shared_splits;
250static unsigned int tmac_util_period = 5;
251static unsigned int rmac_util_period = 5;
252#ifndef CONFIG_S2IO_NAPI
253static unsigned int indicate_max_pkts;
254#endif
255
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700256/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 * S2IO device table.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700258 * This table lists all the devices that this driver supports.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 */
260static struct pci_device_id s2io_tbl[] __devinitdata = {
261 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN,
262 PCI_ANY_ID, PCI_ANY_ID},
263 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI,
264 PCI_ANY_ID, PCI_ANY_ID},
265 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700266 PCI_ANY_ID, PCI_ANY_ID},
267 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI,
268 PCI_ANY_ID, PCI_ANY_ID},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 {0,}
270};
271
272MODULE_DEVICE_TABLE(pci, s2io_tbl);
273
274static struct pci_driver s2io_driver = {
275 .name = "S2IO",
276 .id_table = s2io_tbl,
277 .probe = s2io_init_nic,
278 .remove = __devexit_p(s2io_rem_nic),
279};
280
281/* A simplifier macro used both by init and free shared_mem Fns(). */
282#define TXD_MEM_PAGE_CNT(len, per_each) ((len+per_each - 1) / per_each)
283
284/**
285 * init_shared_mem - Allocation and Initialization of Memory
286 * @nic: Device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700287 * Description: The function allocates all the memory areas shared
288 * between the NIC and the driver. This includes Tx descriptors,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 * Rx descriptors and the statistics block.
290 */
291
292static int init_shared_mem(struct s2io_nic *nic)
293{
294 u32 size;
295 void *tmp_v_addr, *tmp_v_addr_next;
296 dma_addr_t tmp_p_addr, tmp_p_addr_next;
297 RxD_block_t *pre_rxd_blk = NULL;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700298 int i, j, blk_cnt, rx_sz, tx_sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 int lst_size, lst_per_page;
300 struct net_device *dev = nic->dev;
301#ifdef CONFIG_2BUFF_MODE
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700302 u64 tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 buffAdd_t *ba;
304#endif
305
306 mac_info_t *mac_control;
307 struct config_param *config;
308
309 mac_control = &nic->mac_control;
310 config = &nic->config;
311
312
313 /* Allocation and initialization of TXDLs in FIOFs */
314 size = 0;
315 for (i = 0; i < config->tx_fifo_num; i++) {
316 size += config->tx_cfg[i].fifo_len;
317 }
318 if (size > MAX_AVAILABLE_TXDS) {
319 DBG_PRINT(ERR_DBG, "%s: Total number of Tx FIFOs ",
320 dev->name);
321 DBG_PRINT(ERR_DBG, "exceeds the maximum value ");
322 DBG_PRINT(ERR_DBG, "that can be used\n");
323 return FAILURE;
324 }
325
326 lst_size = (sizeof(TxD_t) * config->max_txds);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700327 tx_sz = lst_size * size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 lst_per_page = PAGE_SIZE / lst_size;
329
330 for (i = 0; i < config->tx_fifo_num; i++) {
331 int fifo_len = config->tx_cfg[i].fifo_len;
332 int list_holder_size = fifo_len * sizeof(list_info_hold_t);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700333 mac_control->fifos[i].list_info = kmalloc(list_holder_size,
334 GFP_KERNEL);
335 if (!mac_control->fifos[i].list_info) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 DBG_PRINT(ERR_DBG,
337 "Malloc failed for list_info\n");
338 return -ENOMEM;
339 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700340 memset(mac_control->fifos[i].list_info, 0, list_holder_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 }
342 for (i = 0; i < config->tx_fifo_num; i++) {
343 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
344 lst_per_page);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700345 mac_control->fifos[i].tx_curr_put_info.offset = 0;
346 mac_control->fifos[i].tx_curr_put_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700348 mac_control->fifos[i].tx_curr_get_info.offset = 0;
349 mac_control->fifos[i].tx_curr_get_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700351 mac_control->fifos[i].fifo_no = i;
352 mac_control->fifos[i].nic = nic;
353 mac_control->fifos[i].max_txds = MAX_SKB_FRAGS;
354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 for (j = 0; j < page_num; j++) {
356 int k = 0;
357 dma_addr_t tmp_p;
358 void *tmp_v;
359 tmp_v = pci_alloc_consistent(nic->pdev,
360 PAGE_SIZE, &tmp_p);
361 if (!tmp_v) {
362 DBG_PRINT(ERR_DBG,
363 "pci_alloc_consistent ");
364 DBG_PRINT(ERR_DBG, "failed for TxDL\n");
365 return -ENOMEM;
366 }
367 while (k < lst_per_page) {
368 int l = (j * lst_per_page) + k;
369 if (l == config->tx_cfg[i].fifo_len)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700370 break;
371 mac_control->fifos[i].list_info[l].list_virt_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 tmp_v + (k * lst_size);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700373 mac_control->fifos[i].list_info[l].list_phy_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 tmp_p + (k * lst_size);
375 k++;
376 }
377 }
378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 /* Allocation and initialization of RXDs in Rings */
381 size = 0;
382 for (i = 0; i < config->rx_ring_num; i++) {
383 if (config->rx_cfg[i].num_rxd % (MAX_RXDS_PER_BLOCK + 1)) {
384 DBG_PRINT(ERR_DBG, "%s: RxD count of ", dev->name);
385 DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ",
386 i);
387 DBG_PRINT(ERR_DBG, "RxDs per Block");
388 return FAILURE;
389 }
390 size += config->rx_cfg[i].num_rxd;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700391 mac_control->rings[i].block_count =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700393 mac_control->rings[i].pkt_cnt =
394 config->rx_cfg[i].num_rxd - mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700396 size = (size * (sizeof(RxD_t)));
397 rx_sz = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
399 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700400 mac_control->rings[i].rx_curr_get_info.block_index = 0;
401 mac_control->rings[i].rx_curr_get_info.offset = 0;
402 mac_control->rings[i].rx_curr_get_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700404 mac_control->rings[i].rx_curr_put_info.block_index = 0;
405 mac_control->rings[i].rx_curr_put_info.offset = 0;
406 mac_control->rings[i].rx_curr_put_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700408 mac_control->rings[i].nic = nic;
409 mac_control->rings[i].ring_no = i;
410
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 blk_cnt =
412 config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1);
413 /* Allocating all the Rx blocks */
414 for (j = 0; j < blk_cnt; j++) {
415#ifndef CONFIG_2BUFF_MODE
416 size = (MAX_RXDS_PER_BLOCK + 1) * (sizeof(RxD_t));
417#else
418 size = SIZE_OF_BLOCK;
419#endif
420 tmp_v_addr = pci_alloc_consistent(nic->pdev, size,
421 &tmp_p_addr);
422 if (tmp_v_addr == NULL) {
423 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700424 * In case of failure, free_shared_mem()
425 * is called, which should free any
426 * memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 * failure happened.
428 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700429 mac_control->rings[i].rx_blocks[j].block_virt_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 tmp_v_addr;
431 return -ENOMEM;
432 }
433 memset(tmp_v_addr, 0, size);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700434 mac_control->rings[i].rx_blocks[j].block_virt_addr =
435 tmp_v_addr;
436 mac_control->rings[i].rx_blocks[j].block_dma_addr =
437 tmp_p_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 }
439 /* Interlinking all Rx Blocks */
440 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700441 tmp_v_addr =
442 mac_control->rings[i].rx_blocks[j].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 tmp_v_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700444 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 blk_cnt].block_virt_addr;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700446 tmp_p_addr =
447 mac_control->rings[i].rx_blocks[j].block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 tmp_p_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700449 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 blk_cnt].block_dma_addr;
451
452 pre_rxd_blk = (RxD_block_t *) tmp_v_addr;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700453 pre_rxd_blk->reserved_1 = END_OF_BLOCK; /* last RxD
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 * marker.
455 */
456#ifndef CONFIG_2BUFF_MODE
457 pre_rxd_blk->reserved_2_pNext_RxD_block =
458 (unsigned long) tmp_v_addr_next;
459#endif
460 pre_rxd_blk->pNext_RxD_Blk_physical =
461 (u64) tmp_p_addr_next;
462 }
463 }
464
465#ifdef CONFIG_2BUFF_MODE
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700466 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 * Allocation of Storages for buffer addresses in 2BUFF mode
468 * and the buffers as well.
469 */
470 for (i = 0; i < config->rx_ring_num; i++) {
471 blk_cnt =
472 config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700473 mac_control->rings[i].ba = kmalloc((sizeof(buffAdd_t *) * blk_cnt),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 GFP_KERNEL);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700475 if (!mac_control->rings[i].ba)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 return -ENOMEM;
477 for (j = 0; j < blk_cnt; j++) {
478 int k = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700479 mac_control->rings[i].ba[j] = kmalloc((sizeof(buffAdd_t) *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 (MAX_RXDS_PER_BLOCK + 1)),
481 GFP_KERNEL);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700482 if (!mac_control->rings[i].ba[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 return -ENOMEM;
484 while (k != MAX_RXDS_PER_BLOCK) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700485 ba = &mac_control->rings[i].ba[j][k];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700487 ba->ba_0_org = (void *) kmalloc
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
489 if (!ba->ba_0_org)
490 return -ENOMEM;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700491 tmp = (u64) ba->ba_0_org;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 tmp += ALIGN_SIZE;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700493 tmp &= ~((u64) ALIGN_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 ba->ba_0 = (void *) tmp;
495
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700496 ba->ba_1_org = (void *) kmalloc
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
498 if (!ba->ba_1_org)
499 return -ENOMEM;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700500 tmp = (u64) ba->ba_1_org;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 tmp += ALIGN_SIZE;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700502 tmp &= ~((u64) ALIGN_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 ba->ba_1 = (void *) tmp;
504 k++;
505 }
506 }
507 }
508#endif
509
510 /* Allocation and initialization of Statistics block */
511 size = sizeof(StatInfo_t);
512 mac_control->stats_mem = pci_alloc_consistent
513 (nic->pdev, size, &mac_control->stats_mem_phy);
514
515 if (!mac_control->stats_mem) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700516 /*
517 * In case of failure, free_shared_mem() is called, which
518 * should free any memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 * failure happened.
520 */
521 return -ENOMEM;
522 }
523 mac_control->stats_mem_sz = size;
524
525 tmp_v_addr = mac_control->stats_mem;
526 mac_control->stats_info = (StatInfo_t *) tmp_v_addr;
527 memset(tmp_v_addr, 0, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name,
529 (unsigned long long) tmp_p_addr);
530
531 return SUCCESS;
532}
533
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700534/**
535 * free_shared_mem - Free the allocated Memory
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 * @nic: Device private variable.
537 * Description: This function is to free all memory locations allocated by
538 * the init_shared_mem() function and return it to the kernel.
539 */
540
541static void free_shared_mem(struct s2io_nic *nic)
542{
543 int i, j, blk_cnt, size;
544 void *tmp_v_addr;
545 dma_addr_t tmp_p_addr;
546 mac_info_t *mac_control;
547 struct config_param *config;
548 int lst_size, lst_per_page;
549
550
551 if (!nic)
552 return;
553
554 mac_control = &nic->mac_control;
555 config = &nic->config;
556
557 lst_size = (sizeof(TxD_t) * config->max_txds);
558 lst_per_page = PAGE_SIZE / lst_size;
559
560 for (i = 0; i < config->tx_fifo_num; i++) {
561 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
562 lst_per_page);
563 for (j = 0; j < page_num; j++) {
564 int mem_blks = (j * lst_per_page);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700565 if (!mac_control->fifos[i].list_info[mem_blks].
566 list_virt_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 break;
568 pci_free_consistent(nic->pdev, PAGE_SIZE,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700569 mac_control->fifos[i].
570 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 list_virt_addr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700572 mac_control->fifos[i].
573 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 list_phy_addr);
575 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700576 kfree(mac_control->fifos[i].list_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 }
578
579#ifndef CONFIG_2BUFF_MODE
580 size = (MAX_RXDS_PER_BLOCK + 1) * (sizeof(RxD_t));
581#else
582 size = SIZE_OF_BLOCK;
583#endif
584 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700585 blk_cnt = mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700587 tmp_v_addr = mac_control->rings[i].rx_blocks[j].
588 block_virt_addr;
589 tmp_p_addr = mac_control->rings[i].rx_blocks[j].
590 block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 if (tmp_v_addr == NULL)
592 break;
593 pci_free_consistent(nic->pdev, size,
594 tmp_v_addr, tmp_p_addr);
595 }
596 }
597
598#ifdef CONFIG_2BUFF_MODE
599 /* Freeing buffer storage addresses in 2BUFF mode. */
600 for (i = 0; i < config->rx_ring_num; i++) {
601 blk_cnt =
602 config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 for (j = 0; j < blk_cnt; j++) {
604 int k = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700605 if (!mac_control->rings[i].ba[j])
606 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 while (k != MAX_RXDS_PER_BLOCK) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700608 buffAdd_t *ba = &mac_control->rings[i].ba[j][k];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 kfree(ba->ba_0_org);
610 kfree(ba->ba_1_org);
611 k++;
612 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700613 kfree(mac_control->rings[i].ba[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700615 if (mac_control->rings[i].ba)
616 kfree(mac_control->rings[i].ba);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618#endif
619
620 if (mac_control->stats_mem) {
621 pci_free_consistent(nic->pdev,
622 mac_control->stats_mem_sz,
623 mac_control->stats_mem,
624 mac_control->stats_mem_phy);
625 }
626}
627
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700628/**
629 * init_nic - Initialization of hardware
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 * @nic: device peivate variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700631 * Description: The function sequentially configures every block
632 * of the H/W from their reset values.
633 * Return Value: SUCCESS on success and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 * '-1' on failure (endian settings incorrect).
635 */
636
637static int init_nic(struct s2io_nic *nic)
638{
639 XENA_dev_config_t __iomem *bar0 = nic->bar0;
640 struct net_device *dev = nic->dev;
641 register u64 val64 = 0;
642 void __iomem *add;
643 u32 time;
644 int i, j;
645 mac_info_t *mac_control;
646 struct config_param *config;
647 int mdio_cnt = 0, dtx_cnt = 0;
648 unsigned long long mem_share;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700649 int mem_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651 mac_control = &nic->mac_control;
652 config = &nic->config;
653
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700654 /* to set the swapper controle on the card */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700655 if(s2io_set_swapper(nic)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n");
657 return -1;
658 }
659
660 /* Remove XGXS from reset state */
661 val64 = 0;
662 writeq(val64, &bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 msleep(500);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700664 val64 = readq(&bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
666 /* Enable Receiving broadcasts */
667 add = &bar0->mac_cfg;
668 val64 = readq(&bar0->mac_cfg);
669 val64 |= MAC_RMAC_BCAST_ENABLE;
670 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
671 writel((u32) val64, add);
672 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
673 writel((u32) (val64 >> 32), (add + 4));
674
675 /* Read registers in all blocks */
676 val64 = readq(&bar0->mac_int_mask);
677 val64 = readq(&bar0->mc_int_mask);
678 val64 = readq(&bar0->xgxs_int_mask);
679
680 /* Set MTU */
681 val64 = dev->mtu;
682 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
683
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700684 /*
685 * Configuring the XAUI Interface of Xena.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 * ***************************************
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700687 * To Configure the Xena's XAUI, one has to write a series
688 * of 64 bit values into two registers in a particular
689 * sequence. Hence a macro 'SWITCH_SIGN' has been defined
690 * which will be defined in the array of configuration values
691 * (default_dtx_cfg & default_mdio_cfg) at appropriate places
692 * to switch writing from one regsiter to another. We continue
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 * writing these values until we encounter the 'END_SIGN' macro.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700694 * For example, After making a series of 21 writes into
695 * dtx_control register the 'SWITCH_SIGN' appears and hence we
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 * start writing into mdio_control until we encounter END_SIGN.
697 */
698 while (1) {
699 dtx_cfg:
700 while (default_dtx_cfg[dtx_cnt] != END_SIGN) {
701 if (default_dtx_cfg[dtx_cnt] == SWITCH_SIGN) {
702 dtx_cnt++;
703 goto mdio_cfg;
704 }
705 SPECIAL_REG_WRITE(default_dtx_cfg[dtx_cnt],
706 &bar0->dtx_control, UF);
707 val64 = readq(&bar0->dtx_control);
708 dtx_cnt++;
709 }
710 mdio_cfg:
711 while (default_mdio_cfg[mdio_cnt] != END_SIGN) {
712 if (default_mdio_cfg[mdio_cnt] == SWITCH_SIGN) {
713 mdio_cnt++;
714 goto dtx_cfg;
715 }
716 SPECIAL_REG_WRITE(default_mdio_cfg[mdio_cnt],
717 &bar0->mdio_control, UF);
718 val64 = readq(&bar0->mdio_control);
719 mdio_cnt++;
720 }
721 if ((default_dtx_cfg[dtx_cnt] == END_SIGN) &&
722 (default_mdio_cfg[mdio_cnt] == END_SIGN)) {
723 break;
724 } else {
725 goto dtx_cfg;
726 }
727 }
728
729 /* Tx DMA Initialization */
730 val64 = 0;
731 writeq(val64, &bar0->tx_fifo_partition_0);
732 writeq(val64, &bar0->tx_fifo_partition_1);
733 writeq(val64, &bar0->tx_fifo_partition_2);
734 writeq(val64, &bar0->tx_fifo_partition_3);
735
736
737 for (i = 0, j = 0; i < config->tx_fifo_num; i++) {
738 val64 |=
739 vBIT(config->tx_cfg[i].fifo_len - 1, ((i * 32) + 19),
740 13) | vBIT(config->tx_cfg[i].fifo_priority,
741 ((i * 32) + 5), 3);
742
743 if (i == (config->tx_fifo_num - 1)) {
744 if (i % 2 == 0)
745 i++;
746 }
747
748 switch (i) {
749 case 1:
750 writeq(val64, &bar0->tx_fifo_partition_0);
751 val64 = 0;
752 break;
753 case 3:
754 writeq(val64, &bar0->tx_fifo_partition_1);
755 val64 = 0;
756 break;
757 case 5:
758 writeq(val64, &bar0->tx_fifo_partition_2);
759 val64 = 0;
760 break;
761 case 7:
762 writeq(val64, &bar0->tx_fifo_partition_3);
763 break;
764 }
765 }
766
767 /* Enable Tx FIFO partition 0. */
768 val64 = readq(&bar0->tx_fifo_partition_0);
769 val64 |= BIT(0); /* To enable the FIFO partition. */
770 writeq(val64, &bar0->tx_fifo_partition_0);
771
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700772 /*
773 * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug
774 * SXE-008 TRANSMIT DMA ARBITRATION ISSUE.
775 */
776 if (get_xena_rev_id(nic->pdev) < 4)
777 writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable);
778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 val64 = readq(&bar0->tx_fifo_partition_0);
780 DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n",
781 &bar0->tx_fifo_partition_0, (unsigned long long) val64);
782
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700783 /*
784 * Initialization of Tx_PA_CONFIG register to ignore packet
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 * integrity checking.
786 */
787 val64 = readq(&bar0->tx_pa_cfg);
788 val64 |= TX_PA_CFG_IGNORE_FRM_ERR | TX_PA_CFG_IGNORE_SNAP_OUI |
789 TX_PA_CFG_IGNORE_LLC_CTRL | TX_PA_CFG_IGNORE_L2_ERR;
790 writeq(val64, &bar0->tx_pa_cfg);
791
792 /* Rx DMA intialization. */
793 val64 = 0;
794 for (i = 0; i < config->rx_ring_num; i++) {
795 val64 |=
796 vBIT(config->rx_cfg[i].ring_priority, (5 + (i * 8)),
797 3);
798 }
799 writeq(val64, &bar0->rx_queue_priority);
800
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700801 /*
802 * Allocating equal share of memory to all the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 * configured Rings.
804 */
805 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700806 mem_size = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 for (i = 0; i < config->rx_ring_num; i++) {
808 switch (i) {
809 case 0:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700810 mem_share = (mem_size / config->rx_ring_num +
811 mem_size % config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 val64 |= RX_QUEUE_CFG_Q0_SZ(mem_share);
813 continue;
814 case 1:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700815 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 val64 |= RX_QUEUE_CFG_Q1_SZ(mem_share);
817 continue;
818 case 2:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700819 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 val64 |= RX_QUEUE_CFG_Q2_SZ(mem_share);
821 continue;
822 case 3:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700823 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 val64 |= RX_QUEUE_CFG_Q3_SZ(mem_share);
825 continue;
826 case 4:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700827 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 val64 |= RX_QUEUE_CFG_Q4_SZ(mem_share);
829 continue;
830 case 5:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700831 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 val64 |= RX_QUEUE_CFG_Q5_SZ(mem_share);
833 continue;
834 case 6:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700835 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 val64 |= RX_QUEUE_CFG_Q6_SZ(mem_share);
837 continue;
838 case 7:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700839 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 val64 |= RX_QUEUE_CFG_Q7_SZ(mem_share);
841 continue;
842 }
843 }
844 writeq(val64, &bar0->rx_queue_cfg);
845
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700846 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700847 * Filling Tx round robin registers
848 * as per the number of FIFOs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 */
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700850 switch (config->tx_fifo_num) {
851 case 1:
852 val64 = 0x0000000000000000ULL;
853 writeq(val64, &bar0->tx_w_round_robin_0);
854 writeq(val64, &bar0->tx_w_round_robin_1);
855 writeq(val64, &bar0->tx_w_round_robin_2);
856 writeq(val64, &bar0->tx_w_round_robin_3);
857 writeq(val64, &bar0->tx_w_round_robin_4);
858 break;
859 case 2:
860 val64 = 0x0000010000010000ULL;
861 writeq(val64, &bar0->tx_w_round_robin_0);
862 val64 = 0x0100000100000100ULL;
863 writeq(val64, &bar0->tx_w_round_robin_1);
864 val64 = 0x0001000001000001ULL;
865 writeq(val64, &bar0->tx_w_round_robin_2);
866 val64 = 0x0000010000010000ULL;
867 writeq(val64, &bar0->tx_w_round_robin_3);
868 val64 = 0x0100000000000000ULL;
869 writeq(val64, &bar0->tx_w_round_robin_4);
870 break;
871 case 3:
872 val64 = 0x0001000102000001ULL;
873 writeq(val64, &bar0->tx_w_round_robin_0);
874 val64 = 0x0001020000010001ULL;
875 writeq(val64, &bar0->tx_w_round_robin_1);
876 val64 = 0x0200000100010200ULL;
877 writeq(val64, &bar0->tx_w_round_robin_2);
878 val64 = 0x0001000102000001ULL;
879 writeq(val64, &bar0->tx_w_round_robin_3);
880 val64 = 0x0001020000000000ULL;
881 writeq(val64, &bar0->tx_w_round_robin_4);
882 break;
883 case 4:
884 val64 = 0x0001020300010200ULL;
885 writeq(val64, &bar0->tx_w_round_robin_0);
886 val64 = 0x0100000102030001ULL;
887 writeq(val64, &bar0->tx_w_round_robin_1);
888 val64 = 0x0200010000010203ULL;
889 writeq(val64, &bar0->tx_w_round_robin_2);
890 val64 = 0x0001020001000001ULL;
891 writeq(val64, &bar0->tx_w_round_robin_3);
892 val64 = 0x0203000100000000ULL;
893 writeq(val64, &bar0->tx_w_round_robin_4);
894 break;
895 case 5:
896 val64 = 0x0001000203000102ULL;
897 writeq(val64, &bar0->tx_w_round_robin_0);
898 val64 = 0x0001020001030004ULL;
899 writeq(val64, &bar0->tx_w_round_robin_1);
900 val64 = 0x0001000203000102ULL;
901 writeq(val64, &bar0->tx_w_round_robin_2);
902 val64 = 0x0001020001030004ULL;
903 writeq(val64, &bar0->tx_w_round_robin_3);
904 val64 = 0x0001000000000000ULL;
905 writeq(val64, &bar0->tx_w_round_robin_4);
906 break;
907 case 6:
908 val64 = 0x0001020304000102ULL;
909 writeq(val64, &bar0->tx_w_round_robin_0);
910 val64 = 0x0304050001020001ULL;
911 writeq(val64, &bar0->tx_w_round_robin_1);
912 val64 = 0x0203000100000102ULL;
913 writeq(val64, &bar0->tx_w_round_robin_2);
914 val64 = 0x0304000102030405ULL;
915 writeq(val64, &bar0->tx_w_round_robin_3);
916 val64 = 0x0001000200000000ULL;
917 writeq(val64, &bar0->tx_w_round_robin_4);
918 break;
919 case 7:
920 val64 = 0x0001020001020300ULL;
921 writeq(val64, &bar0->tx_w_round_robin_0);
922 val64 = 0x0102030400010203ULL;
923 writeq(val64, &bar0->tx_w_round_robin_1);
924 val64 = 0x0405060001020001ULL;
925 writeq(val64, &bar0->tx_w_round_robin_2);
926 val64 = 0x0304050000010200ULL;
927 writeq(val64, &bar0->tx_w_round_robin_3);
928 val64 = 0x0102030000000000ULL;
929 writeq(val64, &bar0->tx_w_round_robin_4);
930 break;
931 case 8:
932 val64 = 0x0001020300040105ULL;
933 writeq(val64, &bar0->tx_w_round_robin_0);
934 val64 = 0x0200030106000204ULL;
935 writeq(val64, &bar0->tx_w_round_robin_1);
936 val64 = 0x0103000502010007ULL;
937 writeq(val64, &bar0->tx_w_round_robin_2);
938 val64 = 0x0304010002060500ULL;
939 writeq(val64, &bar0->tx_w_round_robin_3);
940 val64 = 0x0103020400000000ULL;
941 writeq(val64, &bar0->tx_w_round_robin_4);
942 break;
943 }
944
945 /* Filling the Rx round robin registers as per the
946 * number of Rings and steering based on QoS.
947 */
948 switch (config->rx_ring_num) {
949 case 1:
950 val64 = 0x8080808080808080ULL;
951 writeq(val64, &bar0->rts_qos_steering);
952 break;
953 case 2:
954 val64 = 0x0000010000010000ULL;
955 writeq(val64, &bar0->rx_w_round_robin_0);
956 val64 = 0x0100000100000100ULL;
957 writeq(val64, &bar0->rx_w_round_robin_1);
958 val64 = 0x0001000001000001ULL;
959 writeq(val64, &bar0->rx_w_round_robin_2);
960 val64 = 0x0000010000010000ULL;
961 writeq(val64, &bar0->rx_w_round_robin_3);
962 val64 = 0x0100000000000000ULL;
963 writeq(val64, &bar0->rx_w_round_robin_4);
964
965 val64 = 0x8080808040404040ULL;
966 writeq(val64, &bar0->rts_qos_steering);
967 break;
968 case 3:
969 val64 = 0x0001000102000001ULL;
970 writeq(val64, &bar0->rx_w_round_robin_0);
971 val64 = 0x0001020000010001ULL;
972 writeq(val64, &bar0->rx_w_round_robin_1);
973 val64 = 0x0200000100010200ULL;
974 writeq(val64, &bar0->rx_w_round_robin_2);
975 val64 = 0x0001000102000001ULL;
976 writeq(val64, &bar0->rx_w_round_robin_3);
977 val64 = 0x0001020000000000ULL;
978 writeq(val64, &bar0->rx_w_round_robin_4);
979
980 val64 = 0x8080804040402020ULL;
981 writeq(val64, &bar0->rts_qos_steering);
982 break;
983 case 4:
984 val64 = 0x0001020300010200ULL;
985 writeq(val64, &bar0->rx_w_round_robin_0);
986 val64 = 0x0100000102030001ULL;
987 writeq(val64, &bar0->rx_w_round_robin_1);
988 val64 = 0x0200010000010203ULL;
989 writeq(val64, &bar0->rx_w_round_robin_2);
990 val64 = 0x0001020001000001ULL;
991 writeq(val64, &bar0->rx_w_round_robin_3);
992 val64 = 0x0203000100000000ULL;
993 writeq(val64, &bar0->rx_w_round_robin_4);
994
995 val64 = 0x8080404020201010ULL;
996 writeq(val64, &bar0->rts_qos_steering);
997 break;
998 case 5:
999 val64 = 0x0001000203000102ULL;
1000 writeq(val64, &bar0->rx_w_round_robin_0);
1001 val64 = 0x0001020001030004ULL;
1002 writeq(val64, &bar0->rx_w_round_robin_1);
1003 val64 = 0x0001000203000102ULL;
1004 writeq(val64, &bar0->rx_w_round_robin_2);
1005 val64 = 0x0001020001030004ULL;
1006 writeq(val64, &bar0->rx_w_round_robin_3);
1007 val64 = 0x0001000000000000ULL;
1008 writeq(val64, &bar0->rx_w_round_robin_4);
1009
1010 val64 = 0x8080404020201008ULL;
1011 writeq(val64, &bar0->rts_qos_steering);
1012 break;
1013 case 6:
1014 val64 = 0x0001020304000102ULL;
1015 writeq(val64, &bar0->rx_w_round_robin_0);
1016 val64 = 0x0304050001020001ULL;
1017 writeq(val64, &bar0->rx_w_round_robin_1);
1018 val64 = 0x0203000100000102ULL;
1019 writeq(val64, &bar0->rx_w_round_robin_2);
1020 val64 = 0x0304000102030405ULL;
1021 writeq(val64, &bar0->rx_w_round_robin_3);
1022 val64 = 0x0001000200000000ULL;
1023 writeq(val64, &bar0->rx_w_round_robin_4);
1024
1025 val64 = 0x8080404020100804ULL;
1026 writeq(val64, &bar0->rts_qos_steering);
1027 break;
1028 case 7:
1029 val64 = 0x0001020001020300ULL;
1030 writeq(val64, &bar0->rx_w_round_robin_0);
1031 val64 = 0x0102030400010203ULL;
1032 writeq(val64, &bar0->rx_w_round_robin_1);
1033 val64 = 0x0405060001020001ULL;
1034 writeq(val64, &bar0->rx_w_round_robin_2);
1035 val64 = 0x0304050000010200ULL;
1036 writeq(val64, &bar0->rx_w_round_robin_3);
1037 val64 = 0x0102030000000000ULL;
1038 writeq(val64, &bar0->rx_w_round_robin_4);
1039
1040 val64 = 0x8080402010080402ULL;
1041 writeq(val64, &bar0->rts_qos_steering);
1042 break;
1043 case 8:
1044 val64 = 0x0001020300040105ULL;
1045 writeq(val64, &bar0->rx_w_round_robin_0);
1046 val64 = 0x0200030106000204ULL;
1047 writeq(val64, &bar0->rx_w_round_robin_1);
1048 val64 = 0x0103000502010007ULL;
1049 writeq(val64, &bar0->rx_w_round_robin_2);
1050 val64 = 0x0304010002060500ULL;
1051 writeq(val64, &bar0->rx_w_round_robin_3);
1052 val64 = 0x0103020400000000ULL;
1053 writeq(val64, &bar0->rx_w_round_robin_4);
1054
1055 val64 = 0x8040201008040201ULL;
1056 writeq(val64, &bar0->rts_qos_steering);
1057 break;
1058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060 /* UDP Fix */
1061 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001062 for (i = 0; i < 8; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 writeq(val64, &bar0->rts_frm_len_n[i]);
1064
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001065 /* Set the default rts frame length for the rings configured */
1066 val64 = MAC_RTS_FRM_LEN_SET(dev->mtu+22);
1067 for (i = 0 ; i < config->rx_ring_num ; i++)
1068 writeq(val64, &bar0->rts_frm_len_n[i]);
1069
1070 /* Set the frame length for the configured rings
1071 * desired by the user
1072 */
1073 for (i = 0; i < config->rx_ring_num; i++) {
1074 /* If rts_frm_len[i] == 0 then it is assumed that user not
1075 * specified frame length steering.
1076 * If the user provides the frame length then program
1077 * the rts_frm_len register for those values or else
1078 * leave it as it is.
1079 */
1080 if (rts_frm_len[i] != 0) {
1081 writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]),
1082 &bar0->rts_frm_len_n[i]);
1083 }
1084 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001086 /* Program statistics memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 writeq(mac_control->stats_mem_phy, &bar0->stat_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001089 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 * Initializing the sampling rate for the device to calculate the
1091 * bandwidth utilization.
1092 */
1093 val64 = MAC_TX_LINK_UTIL_VAL(tmac_util_period) |
1094 MAC_RX_LINK_UTIL_VAL(rmac_util_period);
1095 writeq(val64, &bar0->mac_link_util);
1096
1097
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001098 /*
1099 * Initializing the Transmit and Receive Traffic Interrupt
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 * Scheme.
1101 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001102 /*
1103 * TTI Initialization. Default Tx timer gets us about
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 * 250 interrupts per sec. Continuous interrupts are enabled
1105 * by default.
1106 */
1107 val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078) |
1108 TTI_DATA1_MEM_TX_URNG_A(0xA) |
1109 TTI_DATA1_MEM_TX_URNG_B(0x10) |
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001110 TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN;
1111 if (use_continuous_tx_intrs)
1112 val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 writeq(val64, &bar0->tti_data1_mem);
1114
1115 val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
1116 TTI_DATA2_MEM_TX_UFC_B(0x20) |
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001117 TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 writeq(val64, &bar0->tti_data2_mem);
1119
1120 val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
1121 writeq(val64, &bar0->tti_command_mem);
1122
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001123 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 * Once the operation completes, the Strobe bit of the command
1125 * register will be reset. We poll for this particular condition
1126 * We wait for a maximum of 500ms for the operation to complete,
1127 * if it's not complete by then we return error.
1128 */
1129 time = 0;
1130 while (TRUE) {
1131 val64 = readq(&bar0->tti_command_mem);
1132 if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
1133 break;
1134 }
1135 if (time > 10) {
1136 DBG_PRINT(ERR_DBG, "%s: TTI init Failed\n",
1137 dev->name);
1138 return -1;
1139 }
1140 msleep(50);
1141 time++;
1142 }
1143
1144 /* RTI Initialization */
1145 val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF) |
1146 RTI_DATA1_MEM_RX_URNG_A(0xA) |
1147 RTI_DATA1_MEM_RX_URNG_B(0x10) |
1148 RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
1149
1150 writeq(val64, &bar0->rti_data1_mem);
1151
1152 val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
1153 RTI_DATA2_MEM_RX_UFC_B(0x2) |
1154 RTI_DATA2_MEM_RX_UFC_C(0x40) | RTI_DATA2_MEM_RX_UFC_D(0x80);
1155 writeq(val64, &bar0->rti_data2_mem);
1156
1157 val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD;
1158 writeq(val64, &bar0->rti_command_mem);
1159
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001160 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001161 * Once the operation completes, the Strobe bit of the
1162 * command register will be reset. We poll for this
1163 * particular condition. We wait for a maximum of 500ms
1164 * for the operation to complete, if it's not complete
1165 * by then we return error.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 */
1167 time = 0;
1168 while (TRUE) {
1169 val64 = readq(&bar0->rti_command_mem);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001170 if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 break;
1172 }
1173 if (time > 10) {
1174 DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
1175 dev->name);
1176 return -1;
1177 }
1178 time++;
1179 msleep(50);
1180 }
1181
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001182 /*
1183 * Initializing proper values as Pause threshold into all
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 * the 8 Queues on Rx side.
1185 */
1186 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q0q3);
1187 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7);
1188
1189 /* Disable RMAC PAD STRIPPING */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001190 add = (void *) &bar0->mac_cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 val64 = readq(&bar0->mac_cfg);
1192 val64 &= ~(MAC_CFG_RMAC_STRIP_PAD);
1193 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1194 writel((u32) (val64), add);
1195 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1196 writel((u32) (val64 >> 32), (add + 4));
1197 val64 = readq(&bar0->mac_cfg);
1198
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001199 /*
1200 * Set the time value to be inserted in the pause frame
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 * generated by xena.
1202 */
1203 val64 = readq(&bar0->rmac_pause_cfg);
1204 val64 &= ~(RMAC_PAUSE_HG_PTIME(0xffff));
1205 val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time);
1206 writeq(val64, &bar0->rmac_pause_cfg);
1207
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001208 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 * Set the Threshold Limit for Generating the pause frame
1210 * If the amount of data in any Queue exceeds ratio of
1211 * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256
1212 * pause frame is generated
1213 */
1214 val64 = 0;
1215 for (i = 0; i < 4; i++) {
1216 val64 |=
1217 (((u64) 0xFF00 | nic->mac_control.
1218 mc_pause_threshold_q0q3)
1219 << (i * 2 * 8));
1220 }
1221 writeq(val64, &bar0->mc_pause_thresh_q0q3);
1222
1223 val64 = 0;
1224 for (i = 0; i < 4; i++) {
1225 val64 |=
1226 (((u64) 0xFF00 | nic->mac_control.
1227 mc_pause_threshold_q4q7)
1228 << (i * 2 * 8));
1229 }
1230 writeq(val64, &bar0->mc_pause_thresh_q4q7);
1231
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001232 /*
1233 * TxDMA will stop Read request if the number of read split has
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 * exceeded the limit pointed by shared_splits
1235 */
1236 val64 = readq(&bar0->pic_control);
1237 val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits);
1238 writeq(val64, &bar0->pic_control);
1239
1240 return SUCCESS;
1241}
1242
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001243/**
1244 * en_dis_able_nic_intrs - Enable or Disable the interrupts
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 * @nic: device private variable,
1246 * @mask: A mask indicating which Intr block must be modified and,
1247 * @flag: A flag indicating whether to enable or disable the Intrs.
1248 * Description: This function will either disable or enable the interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001249 * depending on the flag argument. The mask argument can be used to
1250 * enable/disable any Intr block.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 * Return Value: NONE.
1252 */
1253
1254static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
1255{
1256 XENA_dev_config_t __iomem *bar0 = nic->bar0;
1257 register u64 val64 = 0, temp64 = 0;
1258
1259 /* Top level interrupt classification */
1260 /* PIC Interrupts */
1261 if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
1262 /* Enable PIC Intrs in the general intr mask register */
1263 val64 = TXPIC_INT_M | PIC_RX_INT_M;
1264 if (flag == ENABLE_INTRS) {
1265 temp64 = readq(&bar0->general_int_mask);
1266 temp64 &= ~((u64) val64);
1267 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001268 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 * Disabled all PCIX, Flash, MDIO, IIC and GPIO
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001270 * interrupts for now.
1271 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 */
1273 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001274 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 * No MSI Support is available presently, so TTI and
1276 * RTI interrupts are also disabled.
1277 */
1278 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001279 /*
1280 * Disable PIC Intrs in the general
1281 * intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 */
1283 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
1284 temp64 = readq(&bar0->general_int_mask);
1285 val64 |= temp64;
1286 writeq(val64, &bar0->general_int_mask);
1287 }
1288 }
1289
1290 /* DMA Interrupts */
1291 /* Enabling/Disabling Tx DMA interrupts */
1292 if (mask & TX_DMA_INTR) {
1293 /* Enable TxDMA Intrs in the general intr mask register */
1294 val64 = TXDMA_INT_M;
1295 if (flag == ENABLE_INTRS) {
1296 temp64 = readq(&bar0->general_int_mask);
1297 temp64 &= ~((u64) val64);
1298 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001299 /*
1300 * Keep all interrupts other than PFC interrupt
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 * and PCC interrupt disabled in DMA level.
1302 */
1303 val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M |
1304 TXDMA_PCC_INT_M);
1305 writeq(val64, &bar0->txdma_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001306 /*
1307 * Enable only the MISC error 1 interrupt in PFC block
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 */
1309 val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1);
1310 writeq(val64, &bar0->pfc_err_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001311 /*
1312 * Enable only the FB_ECC error interrupt in PCC block
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 */
1314 val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR);
1315 writeq(val64, &bar0->pcc_err_mask);
1316 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001317 /*
1318 * Disable TxDMA Intrs in the general intr mask
1319 * register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 */
1321 writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask);
1322 writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask);
1323 temp64 = readq(&bar0->general_int_mask);
1324 val64 |= temp64;
1325 writeq(val64, &bar0->general_int_mask);
1326 }
1327 }
1328
1329 /* Enabling/Disabling Rx DMA interrupts */
1330 if (mask & RX_DMA_INTR) {
1331 /* Enable RxDMA Intrs in the general intr mask register */
1332 val64 = RXDMA_INT_M;
1333 if (flag == ENABLE_INTRS) {
1334 temp64 = readq(&bar0->general_int_mask);
1335 temp64 &= ~((u64) val64);
1336 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001337 /*
1338 * All RxDMA block interrupts are disabled for now
1339 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 */
1341 writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
1342 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001343 /*
1344 * Disable RxDMA Intrs in the general intr mask
1345 * register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 */
1347 writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
1348 temp64 = readq(&bar0->general_int_mask);
1349 val64 |= temp64;
1350 writeq(val64, &bar0->general_int_mask);
1351 }
1352 }
1353
1354 /* MAC Interrupts */
1355 /* Enabling/Disabling MAC interrupts */
1356 if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
1357 val64 = TXMAC_INT_M | RXMAC_INT_M;
1358 if (flag == ENABLE_INTRS) {
1359 temp64 = readq(&bar0->general_int_mask);
1360 temp64 &= ~((u64) val64);
1361 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001362 /*
1363 * All MAC block error interrupts are disabled for now
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 * except the link status change interrupt.
1365 * TODO
1366 */
1367 val64 = MAC_INT_STATUS_RMAC_INT;
1368 temp64 = readq(&bar0->mac_int_mask);
1369 temp64 &= ~((u64) val64);
1370 writeq(temp64, &bar0->mac_int_mask);
1371
1372 val64 = readq(&bar0->mac_rmac_err_mask);
1373 val64 &= ~((u64) RMAC_LINK_STATE_CHANGE_INT);
1374 writeq(val64, &bar0->mac_rmac_err_mask);
1375 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001376 /*
1377 * Disable MAC Intrs in the general intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 */
1379 writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask);
1380 writeq(DISABLE_ALL_INTRS,
1381 &bar0->mac_rmac_err_mask);
1382
1383 temp64 = readq(&bar0->general_int_mask);
1384 val64 |= temp64;
1385 writeq(val64, &bar0->general_int_mask);
1386 }
1387 }
1388
1389 /* XGXS Interrupts */
1390 if (mask & (TX_XGXS_INTR | RX_XGXS_INTR)) {
1391 val64 = TXXGXS_INT_M | RXXGXS_INT_M;
1392 if (flag == ENABLE_INTRS) {
1393 temp64 = readq(&bar0->general_int_mask);
1394 temp64 &= ~((u64) val64);
1395 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001396 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 * All XGXS block error interrupts are disabled for now
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001398 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 */
1400 writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
1401 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001402 /*
1403 * Disable MC Intrs in the general intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 */
1405 writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
1406 temp64 = readq(&bar0->general_int_mask);
1407 val64 |= temp64;
1408 writeq(val64, &bar0->general_int_mask);
1409 }
1410 }
1411
1412 /* Memory Controller(MC) interrupts */
1413 if (mask & MC_INTR) {
1414 val64 = MC_INT_M;
1415 if (flag == ENABLE_INTRS) {
1416 temp64 = readq(&bar0->general_int_mask);
1417 temp64 &= ~((u64) val64);
1418 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001419 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001420 * Enable all MC Intrs.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 */
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001422 writeq(0x0, &bar0->mc_int_mask);
1423 writeq(0x0, &bar0->mc_err_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 } else if (flag == DISABLE_INTRS) {
1425 /*
1426 * Disable MC Intrs in the general intr mask register
1427 */
1428 writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask);
1429 temp64 = readq(&bar0->general_int_mask);
1430 val64 |= temp64;
1431 writeq(val64, &bar0->general_int_mask);
1432 }
1433 }
1434
1435
1436 /* Tx traffic interrupts */
1437 if (mask & TX_TRAFFIC_INTR) {
1438 val64 = TXTRAFFIC_INT_M;
1439 if (flag == ENABLE_INTRS) {
1440 temp64 = readq(&bar0->general_int_mask);
1441 temp64 &= ~((u64) val64);
1442 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001443 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 * Enable all the Tx side interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001445 * writing 0 Enables all 64 TX interrupt levels
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 */
1447 writeq(0x0, &bar0->tx_traffic_mask);
1448 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001449 /*
1450 * Disable Tx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 * register.
1452 */
1453 writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask);
1454 temp64 = readq(&bar0->general_int_mask);
1455 val64 |= temp64;
1456 writeq(val64, &bar0->general_int_mask);
1457 }
1458 }
1459
1460 /* Rx traffic interrupts */
1461 if (mask & RX_TRAFFIC_INTR) {
1462 val64 = RXTRAFFIC_INT_M;
1463 if (flag == ENABLE_INTRS) {
1464 temp64 = readq(&bar0->general_int_mask);
1465 temp64 &= ~((u64) val64);
1466 writeq(temp64, &bar0->general_int_mask);
1467 /* writing 0 Enables all 8 RX interrupt levels */
1468 writeq(0x0, &bar0->rx_traffic_mask);
1469 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001470 /*
1471 * Disable Rx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 * register.
1473 */
1474 writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask);
1475 temp64 = readq(&bar0->general_int_mask);
1476 val64 |= temp64;
1477 writeq(val64, &bar0->general_int_mask);
1478 }
1479 }
1480}
1481
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001482static int check_prc_pcc_state(u64 val64, int flag, int rev_id)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001483{
1484 int ret = 0;
1485
1486 if (flag == FALSE) {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001487 if (rev_id >= 4) {
1488 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) &&
1489 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1490 ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
1491 ret = 1;
1492 }
1493 } else {
1494 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
1495 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1496 ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
1497 ret = 1;
1498 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001499 }
1500 } else {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001501 if (rev_id >= 4) {
1502 if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
1503 ADAPTER_STATUS_RMAC_PCC_IDLE) &&
1504 (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
1505 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1506 ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
1507 ret = 1;
1508 }
1509 } else {
1510 if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
1511 ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
1512 (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
1513 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1514 ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
1515 ret = 1;
1516 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001517 }
1518 }
1519
1520 return ret;
1521}
1522/**
1523 * verify_xena_quiescence - Checks whether the H/W is ready
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 * @val64 : Value read from adapter status register.
1525 * @flag : indicates if the adapter enable bit was ever written once
1526 * before.
1527 * Description: Returns whether the H/W is ready to go or not. Depending
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001528 * on whether adapter enable bit was written or not the comparison
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 * differs and the calling function passes the input argument flag to
1530 * indicate this.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001531 * Return: 1 If xena is quiescence
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 * 0 If Xena is not quiescence
1533 */
1534
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001535static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536{
1537 int ret = 0;
1538 u64 tmp64 = ~((u64) val64);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001539 int rev_id = get_xena_rev_id(sp->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
1541 if (!
1542 (tmp64 &
1543 (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY |
1544 ADAPTER_STATUS_PFC_READY | ADAPTER_STATUS_TMAC_BUF_EMPTY |
1545 ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY |
1546 ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK |
1547 ADAPTER_STATUS_P_PLL_LOCK))) {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001548 ret = check_prc_pcc_state(val64, flag, rev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 }
1550
1551 return ret;
1552}
1553
1554/**
1555 * fix_mac_address - Fix for Mac addr problem on Alpha platforms
1556 * @sp: Pointer to device specifc structure
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001557 * Description :
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 * New procedure to clear mac address reading problems on Alpha platforms
1559 *
1560 */
1561
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001562void fix_mac_address(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563{
1564 XENA_dev_config_t __iomem *bar0 = sp->bar0;
1565 u64 val64;
1566 int i = 0;
1567
1568 while (fix_mac[i] != END_SIGN) {
1569 writeq(fix_mac[i++], &bar0->gpio_control);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001570 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 val64 = readq(&bar0->gpio_control);
1572 }
1573}
1574
1575/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001576 * start_nic - Turns the device on
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001578 * Description:
1579 * This function actually turns the device on. Before this function is
1580 * called,all Registers are configured from their reset states
1581 * and shared memory is allocated but the NIC is still quiescent. On
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 * calling this function, the device interrupts are cleared and the NIC is
1583 * literally switched on by writing into the adapter control register.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001584 * Return Value:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 * SUCCESS on success and -1 on failure.
1586 */
1587
1588static int start_nic(struct s2io_nic *nic)
1589{
1590 XENA_dev_config_t __iomem *bar0 = nic->bar0;
1591 struct net_device *dev = nic->dev;
1592 register u64 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001593 u16 interruptible;
1594 u16 subid, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 mac_info_t *mac_control;
1596 struct config_param *config;
1597
1598 mac_control = &nic->mac_control;
1599 config = &nic->config;
1600
1601 /* PRC Initialization and configuration */
1602 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001603 writeq((u64) mac_control->rings[i].rx_blocks[0].block_dma_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 &bar0->prc_rxd0_n[i]);
1605
1606 val64 = readq(&bar0->prc_ctrl_n[i]);
1607#ifndef CONFIG_2BUFF_MODE
1608 val64 |= PRC_CTRL_RC_ENABLED;
1609#else
1610 val64 |= PRC_CTRL_RC_ENABLED | PRC_CTRL_RING_MODE_3;
1611#endif
1612 writeq(val64, &bar0->prc_ctrl_n[i]);
1613 }
1614
1615#ifdef CONFIG_2BUFF_MODE
1616 /* Enabling 2 buffer mode by writing into Rx_pa_cfg reg. */
1617 val64 = readq(&bar0->rx_pa_cfg);
1618 val64 |= RX_PA_CFG_IGNORE_L2_ERR;
1619 writeq(val64, &bar0->rx_pa_cfg);
1620#endif
1621
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001622 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 * Enabling MC-RLDRAM. After enabling the device, we timeout
1624 * for around 100ms, which is approximately the time required
1625 * for the device to be ready for operation.
1626 */
1627 val64 = readq(&bar0->mc_rldram_mrs);
1628 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE | MC_RLDRAM_MRS_ENABLE;
1629 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
1630 val64 = readq(&bar0->mc_rldram_mrs);
1631
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001632 msleep(100); /* Delay by around 100 ms. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
1634 /* Enabling ECC Protection. */
1635 val64 = readq(&bar0->adapter_control);
1636 val64 &= ~ADAPTER_ECC_EN;
1637 writeq(val64, &bar0->adapter_control);
1638
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001639 /*
1640 * Clearing any possible Link state change interrupts that
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 * could have popped up just before Enabling the card.
1642 */
1643 val64 = readq(&bar0->mac_rmac_err_reg);
1644 if (val64)
1645 writeq(val64, &bar0->mac_rmac_err_reg);
1646
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001647 /*
1648 * Verify if the device is ready to be enabled, if so enable
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 * it.
1650 */
1651 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001652 if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name);
1654 DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n",
1655 (unsigned long long) val64);
1656 return FAILURE;
1657 }
1658
1659 /* Enable select interrupts */
1660 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR | TX_MAC_INTR |
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001661 RX_MAC_INTR | MC_INTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS);
1663
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001664 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 * With some switches, link might be already up at this point.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001666 * Because of this weird behavior, when we enable laser,
1667 * we may not get link. We need to handle this. We cannot
1668 * figure out which switch is misbehaving. So we are forced to
1669 * make a global change.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 */
1671
1672 /* Enabling Laser. */
1673 val64 = readq(&bar0->adapter_control);
1674 val64 |= ADAPTER_EOI_TX_ON;
1675 writeq(val64, &bar0->adapter_control);
1676
1677 /* SXE-002: Initialize link and activity LED */
1678 subid = nic->pdev->subsystem_device;
1679 if ((subid & 0xFF) >= 0x07) {
1680 val64 = readq(&bar0->gpio_control);
1681 val64 |= 0x0000800000000000ULL;
1682 writeq(val64, &bar0->gpio_control);
1683 val64 = 0x0411040400000000ULL;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001684 writeq(val64, (void __iomem *) ((u8 *) bar0 + 0x2700));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 }
1686
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001687 /*
1688 * Don't see link state interrupts on certain switches, so
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 * directly scheduling a link state task from here.
1690 */
1691 schedule_work(&nic->set_link_task);
1692
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 return SUCCESS;
1694}
1695
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001696/**
1697 * free_tx_buffers - Free all queued Tx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001699 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 * Free all queued Tx buffers.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001701 * Return Value: void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702*/
1703
1704static void free_tx_buffers(struct s2io_nic *nic)
1705{
1706 struct net_device *dev = nic->dev;
1707 struct sk_buff *skb;
1708 TxD_t *txdp;
1709 int i, j;
1710 mac_info_t *mac_control;
1711 struct config_param *config;
raghavendra.koushik@neterion.com1ddc50d2005-08-03 12:30:43 -07001712 int cnt = 0, frg_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
1714 mac_control = &nic->mac_control;
1715 config = &nic->config;
1716
1717 for (i = 0; i < config->tx_fifo_num; i++) {
1718 for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001719 txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 list_virt_addr;
1721 skb =
1722 (struct sk_buff *) ((unsigned long) txdp->
1723 Host_Control);
1724 if (skb == NULL) {
raghavendra.koushik@neterion.com1ddc50d2005-08-03 12:30:43 -07001725 memset(txdp, 0, sizeof(TxD_t) *
1726 config->max_txds);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 continue;
1728 }
raghavendra.koushik@neterion.com1ddc50d2005-08-03 12:30:43 -07001729 frg_cnt = skb_shinfo(skb)->nr_frags;
1730 pci_unmap_single(nic->pdev, (dma_addr_t)
1731 txdp->Buffer_Pointer,
1732 skb->len - skb->data_len,
1733 PCI_DMA_TODEVICE);
1734 if (frg_cnt) {
1735 TxD_t *temp;
1736 temp = txdp;
1737 txdp++;
1738 for (j = 0; j < frg_cnt; j++, txdp++) {
1739 skb_frag_t *frag =
1740 &skb_shinfo(skb)->frags[j];
1741 pci_unmap_page(nic->pdev,
1742 (dma_addr_t)
1743 txdp->
1744 Buffer_Pointer,
1745 frag->size,
1746 PCI_DMA_TODEVICE);
1747 }
1748 txdp = temp;
1749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 dev_kfree_skb(skb);
raghavendra.koushik@neterion.com1ddc50d2005-08-03 12:30:43 -07001751 memset(txdp, 0, sizeof(TxD_t) * config->max_txds);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 cnt++;
1753 }
1754 DBG_PRINT(INTR_DBG,
1755 "%s:forcibly freeing %d skbs on FIFO%d\n",
1756 dev->name, cnt, i);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001757 mac_control->fifos[i].tx_curr_get_info.offset = 0;
1758 mac_control->fifos[i].tx_curr_put_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 }
1760}
1761
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001762/**
1763 * stop_nic - To stop the nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 * @nic ; device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001765 * Description:
1766 * This function does exactly the opposite of what the start_nic()
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 * function does. This function is called to stop the device.
1768 * Return Value:
1769 * void.
1770 */
1771
1772static void stop_nic(struct s2io_nic *nic)
1773{
1774 XENA_dev_config_t __iomem *bar0 = nic->bar0;
1775 register u64 val64 = 0;
1776 u16 interruptible, i;
1777 mac_info_t *mac_control;
1778 struct config_param *config;
1779
1780 mac_control = &nic->mac_control;
1781 config = &nic->config;
1782
1783 /* Disable all interrupts */
1784 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR | TX_MAC_INTR |
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001785 RX_MAC_INTR | MC_INTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
1787
1788 /* Disable PRCs */
1789 for (i = 0; i < config->rx_ring_num; i++) {
1790 val64 = readq(&bar0->prc_ctrl_n[i]);
1791 val64 &= ~((u64) PRC_CTRL_RC_ENABLED);
1792 writeq(val64, &bar0->prc_ctrl_n[i]);
1793 }
1794}
1795
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001796/**
1797 * fill_rx_buffers - Allocates the Rx side skbs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001799 * @ring_no: ring number
1800 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 * The function allocates Rx side skbs and puts the physical
1802 * address of these buffers into the RxD buffer pointers, so that the NIC
1803 * can DMA the received frame into these locations.
1804 * The NIC supports 3 receive modes, viz
1805 * 1. single buffer,
1806 * 2. three buffer and
1807 * 3. Five buffer modes.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001808 * Each mode defines how many fragments the received frame will be split
1809 * up into by the NIC. The frame is split into L3 header, L4 Header,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 * L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself
1811 * is split into 3 fragments. As of now only single buffer mode is
1812 * supported.
1813 * Return Value:
1814 * SUCCESS on success or an appropriate -ve value on failure.
1815 */
1816
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001817int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818{
1819 struct net_device *dev = nic->dev;
1820 struct sk_buff *skb;
1821 RxD_t *rxdp;
1822 int off, off1, size, block_no, block_no1;
1823 int offset, offset1;
1824 u32 alloc_tab = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001825 u32 alloc_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 mac_info_t *mac_control;
1827 struct config_param *config;
1828#ifdef CONFIG_2BUFF_MODE
1829 RxD_t *rxdpnext;
1830 int nextblk;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001831 u64 tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 buffAdd_t *ba;
1833 dma_addr_t rxdpphys;
1834#endif
1835#ifndef CONFIG_S2IO_NAPI
1836 unsigned long flags;
1837#endif
1838
1839 mac_control = &nic->mac_control;
1840 config = &nic->config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001841 alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
1842 atomic_read(&nic->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
1844 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
1845
1846 while (alloc_tab < alloc_cnt) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001847 block_no = mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 block_index;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001849 block_no1 = mac_control->rings[ring_no].rx_curr_get_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 block_index;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001851 off = mac_control->rings[ring_no].rx_curr_put_info.offset;
1852 off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853#ifndef CONFIG_2BUFF_MODE
1854 offset = block_no * (MAX_RXDS_PER_BLOCK + 1) + off;
1855 offset1 = block_no1 * (MAX_RXDS_PER_BLOCK + 1) + off1;
1856#else
1857 offset = block_no * (MAX_RXDS_PER_BLOCK) + off;
1858 offset1 = block_no1 * (MAX_RXDS_PER_BLOCK) + off1;
1859#endif
1860
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001861 rxdp = mac_control->rings[ring_no].rx_blocks[block_no].
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 block_virt_addr + off;
1863 if ((offset == offset1) && (rxdp->Host_Control)) {
1864 DBG_PRINT(INTR_DBG, "%s: Get and Put", dev->name);
1865 DBG_PRINT(INTR_DBG, " info equated\n");
1866 goto end;
1867 }
1868#ifndef CONFIG_2BUFF_MODE
1869 if (rxdp->Control_1 == END_OF_BLOCK) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001870 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 block_index++;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001872 mac_control->rings[ring_no].rx_curr_put_info.
1873 block_index %= mac_control->rings[ring_no].block_count;
1874 block_no = mac_control->rings[ring_no].rx_curr_put_info.
1875 block_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 off++;
1877 off %= (MAX_RXDS_PER_BLOCK + 1);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001878 mac_control->rings[ring_no].rx_curr_put_info.offset =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 off;
1880 rxdp = (RxD_t *) ((unsigned long) rxdp->Control_2);
1881 DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
1882 dev->name, rxdp);
1883 }
1884#ifndef CONFIG_S2IO_NAPI
1885 spin_lock_irqsave(&nic->put_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001886 mac_control->rings[ring_no].put_pos =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 (block_no * (MAX_RXDS_PER_BLOCK + 1)) + off;
1888 spin_unlock_irqrestore(&nic->put_lock, flags);
1889#endif
1890#else
1891 if (rxdp->Host_Control == END_OF_BLOCK) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001892 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 block_index++;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001894 mac_control->rings[ring_no].rx_curr_put_info.block_index
1895 %= mac_control->rings[ring_no].block_count;
1896 block_no = mac_control->rings[ring_no].rx_curr_put_info
1897 .block_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 off = 0;
1899 DBG_PRINT(INTR_DBG, "%s: block%d at: 0x%llx\n",
1900 dev->name, block_no,
1901 (unsigned long long) rxdp->Control_1);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001902 mac_control->rings[ring_no].rx_curr_put_info.offset =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 off;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001904 rxdp = mac_control->rings[ring_no].rx_blocks[block_no].
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 block_virt_addr;
1906 }
1907#ifndef CONFIG_S2IO_NAPI
1908 spin_lock_irqsave(&nic->put_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001909 mac_control->rings[ring_no].put_pos = (block_no *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 (MAX_RXDS_PER_BLOCK + 1)) + off;
1911 spin_unlock_irqrestore(&nic->put_lock, flags);
1912#endif
1913#endif
1914
1915#ifndef CONFIG_2BUFF_MODE
1916 if (rxdp->Control_1 & RXD_OWN_XENA)
1917#else
1918 if (rxdp->Control_2 & BIT(0))
1919#endif
1920 {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001921 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 offset = off;
1923 goto end;
1924 }
1925#ifdef CONFIG_2BUFF_MODE
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001926 /*
1927 * RxDs Spanning cache lines will be replenished only
1928 * if the succeeding RxD is also owned by Host. It
1929 * will always be the ((8*i)+3) and ((8*i)+6)
1930 * descriptors for the 48 byte descriptor. The offending
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 * decsriptor is of-course the 3rd descriptor.
1932 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001933 rxdpphys = mac_control->rings[ring_no].rx_blocks[block_no].
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 block_dma_addr + (off * sizeof(RxD_t));
1935 if (((u64) (rxdpphys)) % 128 > 80) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001936 rxdpnext = mac_control->rings[ring_no].rx_blocks[block_no].
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 block_virt_addr + (off + 1);
1938 if (rxdpnext->Host_Control == END_OF_BLOCK) {
1939 nextblk = (block_no + 1) %
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001940 (mac_control->rings[ring_no].block_count);
1941 rxdpnext = mac_control->rings[ring_no].rx_blocks
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 [nextblk].block_virt_addr;
1943 }
1944 if (rxdpnext->Control_2 & BIT(0))
1945 goto end;
1946 }
1947#endif
1948
1949#ifndef CONFIG_2BUFF_MODE
1950 skb = dev_alloc_skb(size + NET_IP_ALIGN);
1951#else
1952 skb = dev_alloc_skb(dev->mtu + ALIGN_SIZE + BUF0_LEN + 4);
1953#endif
1954 if (!skb) {
1955 DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
1956 DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
1957 return -ENOMEM;
1958 }
1959#ifndef CONFIG_2BUFF_MODE
1960 skb_reserve(skb, NET_IP_ALIGN);
1961 memset(rxdp, 0, sizeof(RxD_t));
1962 rxdp->Buffer0_ptr = pci_map_single
1963 (nic->pdev, skb->data, size, PCI_DMA_FROMDEVICE);
1964 rxdp->Control_2 &= (~MASK_BUFFER0_SIZE);
1965 rxdp->Control_2 |= SET_BUFFER0_SIZE(size);
1966 rxdp->Host_Control = (unsigned long) (skb);
1967 rxdp->Control_1 |= RXD_OWN_XENA;
1968 off++;
1969 off %= (MAX_RXDS_PER_BLOCK + 1);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001970 mac_control->rings[ring_no].rx_curr_put_info.offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001972 ba = &mac_control->rings[ring_no].ba[block_no][off];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 skb_reserve(skb, BUF0_LEN);
David S. Miller689be432005-06-28 15:25:31 -07001974 tmp = ((unsigned long) skb->data & ALIGN_SIZE);
1975 if (tmp)
1976 skb_reserve(skb, (ALIGN_SIZE + 1) - tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977
1978 memset(rxdp, 0, sizeof(RxD_t));
1979 rxdp->Buffer2_ptr = pci_map_single
1980 (nic->pdev, skb->data, dev->mtu + BUF0_LEN + 4,
1981 PCI_DMA_FROMDEVICE);
1982 rxdp->Buffer0_ptr =
1983 pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
1984 PCI_DMA_FROMDEVICE);
1985 rxdp->Buffer1_ptr =
1986 pci_map_single(nic->pdev, ba->ba_1, BUF1_LEN,
1987 PCI_DMA_FROMDEVICE);
1988
1989 rxdp->Control_2 = SET_BUFFER2_SIZE(dev->mtu + 4);
1990 rxdp->Control_2 |= SET_BUFFER0_SIZE(BUF0_LEN);
1991 rxdp->Control_2 |= SET_BUFFER1_SIZE(1); /* dummy. */
1992 rxdp->Control_2 |= BIT(0); /* Set Buffer_Empty bit. */
1993 rxdp->Host_Control = (u64) ((unsigned long) (skb));
1994 rxdp->Control_1 |= RXD_OWN_XENA;
1995 off++;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001996 mac_control->rings[ring_no].rx_curr_put_info.offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997#endif
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001998 rxdp->Control_2 |= SET_RXD_MARKER;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001999
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 atomic_inc(&nic->rx_bufs_left[ring_no]);
2001 alloc_tab++;
2002 }
2003
2004 end:
2005 return SUCCESS;
2006}
2007
2008/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002009 * free_rx_buffers - Frees all Rx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 * @sp: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002011 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 * This function will free all Rx buffers allocated by host.
2013 * Return Value:
2014 * NONE.
2015 */
2016
2017static void free_rx_buffers(struct s2io_nic *sp)
2018{
2019 struct net_device *dev = sp->dev;
2020 int i, j, blk = 0, off, buf_cnt = 0;
2021 RxD_t *rxdp;
2022 struct sk_buff *skb;
2023 mac_info_t *mac_control;
2024 struct config_param *config;
2025#ifdef CONFIG_2BUFF_MODE
2026 buffAdd_t *ba;
2027#endif
2028
2029 mac_control = &sp->mac_control;
2030 config = &sp->config;
2031
2032 for (i = 0; i < config->rx_ring_num; i++) {
2033 for (j = 0, blk = 0; j < config->rx_cfg[i].num_rxd; j++) {
2034 off = j % (MAX_RXDS_PER_BLOCK + 1);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002035 rxdp = mac_control->rings[i].rx_blocks[blk].
2036 block_virt_addr + off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037
2038#ifndef CONFIG_2BUFF_MODE
2039 if (rxdp->Control_1 == END_OF_BLOCK) {
2040 rxdp =
2041 (RxD_t *) ((unsigned long) rxdp->
2042 Control_2);
2043 j++;
2044 blk++;
2045 }
2046#else
2047 if (rxdp->Host_Control == END_OF_BLOCK) {
2048 blk++;
2049 continue;
2050 }
2051#endif
2052
2053 if (!(rxdp->Control_1 & RXD_OWN_XENA)) {
2054 memset(rxdp, 0, sizeof(RxD_t));
2055 continue;
2056 }
2057
2058 skb =
2059 (struct sk_buff *) ((unsigned long) rxdp->
2060 Host_Control);
2061 if (skb) {
2062#ifndef CONFIG_2BUFF_MODE
2063 pci_unmap_single(sp->pdev, (dma_addr_t)
2064 rxdp->Buffer0_ptr,
2065 dev->mtu +
2066 HEADER_ETHERNET_II_802_3_SIZE
2067 + HEADER_802_2_SIZE +
2068 HEADER_SNAP_SIZE,
2069 PCI_DMA_FROMDEVICE);
2070#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002071 ba = &mac_control->rings[i].ba[blk][off];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 pci_unmap_single(sp->pdev, (dma_addr_t)
2073 rxdp->Buffer0_ptr,
2074 BUF0_LEN,
2075 PCI_DMA_FROMDEVICE);
2076 pci_unmap_single(sp->pdev, (dma_addr_t)
2077 rxdp->Buffer1_ptr,
2078 BUF1_LEN,
2079 PCI_DMA_FROMDEVICE);
2080 pci_unmap_single(sp->pdev, (dma_addr_t)
2081 rxdp->Buffer2_ptr,
2082 dev->mtu + BUF0_LEN + 4,
2083 PCI_DMA_FROMDEVICE);
2084#endif
2085 dev_kfree_skb(skb);
2086 atomic_dec(&sp->rx_bufs_left[i]);
2087 buf_cnt++;
2088 }
2089 memset(rxdp, 0, sizeof(RxD_t));
2090 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002091 mac_control->rings[i].rx_curr_put_info.block_index = 0;
2092 mac_control->rings[i].rx_curr_get_info.block_index = 0;
2093 mac_control->rings[i].rx_curr_put_info.offset = 0;
2094 mac_control->rings[i].rx_curr_get_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 atomic_set(&sp->rx_bufs_left[i], 0);
2096 DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
2097 dev->name, buf_cnt, i);
2098 }
2099}
2100
2101/**
2102 * s2io_poll - Rx interrupt handler for NAPI support
2103 * @dev : pointer to the device structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002104 * @budget : The number of packets that were budgeted to be processed
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 * during one pass through the 'Poll" function.
2106 * Description:
2107 * Comes into picture only if NAPI support has been incorporated. It does
2108 * the same thing that rx_intr_handler does, but not in a interrupt context
2109 * also It will process only a given number of packets.
2110 * Return value:
2111 * 0 on success and 1 if there are No Rx packets to be processed.
2112 */
2113
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002114#if defined(CONFIG_S2IO_NAPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115static int s2io_poll(struct net_device *dev, int *budget)
2116{
2117 nic_t *nic = dev->priv;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002118 int pkt_cnt = 0, org_pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 mac_info_t *mac_control;
2120 struct config_param *config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002121 XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
2122 u64 val64;
2123 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002125 atomic_inc(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 mac_control = &nic->mac_control;
2127 config = &nic->config;
2128
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002129 nic->pkts_to_process = *budget;
2130 if (nic->pkts_to_process > dev->quota)
2131 nic->pkts_to_process = dev->quota;
2132 org_pkts_to_process = nic->pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133
2134 val64 = readq(&bar0->rx_traffic_int);
2135 writeq(val64, &bar0->rx_traffic_int);
2136
2137 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002138 rx_intr_handler(&mac_control->rings[i]);
2139 pkt_cnt = org_pkts_to_process - nic->pkts_to_process;
2140 if (!nic->pkts_to_process) {
2141 /* Quota for the current iteration has been met */
2142 goto no_rx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 }
2145 if (!pkt_cnt)
2146 pkt_cnt = 1;
2147
2148 dev->quota -= pkt_cnt;
2149 *budget -= pkt_cnt;
2150 netif_rx_complete(dev);
2151
2152 for (i = 0; i < config->rx_ring_num; i++) {
2153 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2154 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2155 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2156 break;
2157 }
2158 }
2159 /* Re enable the Rx interrupts. */
2160 en_dis_able_nic_intrs(nic, RX_TRAFFIC_INTR, ENABLE_INTRS);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002161 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 return 0;
2163
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002164no_rx:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 dev->quota -= pkt_cnt;
2166 *budget -= pkt_cnt;
2167
2168 for (i = 0; i < config->rx_ring_num; i++) {
2169 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2170 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2171 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2172 break;
2173 }
2174 }
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002175 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 return 1;
2177}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002178#endif
2179
2180/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 * rx_intr_handler - Rx interrupt handler
2182 * @nic: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002183 * Description:
2184 * If the interrupt is because of a received frame or if the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 * receive ring contains fresh as yet un-processed frames,this function is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002186 * called. It picks out the RxD at which place the last Rx processing had
2187 * stopped and sends the skb to the OSM's Rx handler and then increments
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 * the offset.
2189 * Return Value:
2190 * NONE.
2191 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002192static void rx_intr_handler(ring_info_t *ring_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002194 nic_t *nic = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 struct net_device *dev = (struct net_device *) nic->dev;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002196 XENA_dev_config_t __iomem *bar0 = nic->bar0;
2197 int get_block, get_offset, put_block, put_offset, ring_bufs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 rx_curr_get_info_t get_info, put_info;
2199 RxD_t *rxdp;
2200 struct sk_buff *skb;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002201#ifndef CONFIG_S2IO_NAPI
2202 int pkt_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203#endif
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002204 register u64 val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002206 spin_lock(&nic->rx_lock);
2207 if (atomic_read(&nic->card_state) == CARD_DOWN) {
2208 DBG_PRINT(ERR_DBG, "%s: %s going down for reset\n",
2209 __FUNCTION__, dev->name);
2210 spin_unlock(&nic->rx_lock);
2211 }
2212
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002213 /*
2214 * rx_traffic_int reg is an R1 register, hence we read and write
2215 * back the same value in the register to clear it
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002217 val64 = readq(&bar0->tx_traffic_int);
2218 writeq(val64, &bar0->tx_traffic_int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002220 get_info = ring_data->rx_curr_get_info;
2221 get_block = get_info.block_index;
2222 put_info = ring_data->rx_curr_put_info;
2223 put_block = put_info.block_index;
2224 ring_bufs = get_info.ring_len+1;
2225 rxdp = ring_data->rx_blocks[get_block].block_virt_addr +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 get_info.offset;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002227 get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
2228 get_info.offset;
2229#ifndef CONFIG_S2IO_NAPI
2230 spin_lock(&nic->put_lock);
2231 put_offset = ring_data->put_pos;
2232 spin_unlock(&nic->put_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002234 put_offset = (put_block * (MAX_RXDS_PER_BLOCK + 1)) +
2235 put_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236#endif
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002237 while (RXD_IS_UP2DT(rxdp) &&
2238 (((get_offset + 1) % ring_bufs) != put_offset)) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002239 skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
2240 if (skb == NULL) {
2241 DBG_PRINT(ERR_DBG, "%s: The skb is ",
2242 dev->name);
2243 DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002244 spin_unlock(&nic->rx_lock);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002245 return;
2246 }
2247#ifndef CONFIG_2BUFF_MODE
2248 pci_unmap_single(nic->pdev, (dma_addr_t)
2249 rxdp->Buffer0_ptr,
2250 dev->mtu +
2251 HEADER_ETHERNET_II_802_3_SIZE +
2252 HEADER_802_2_SIZE +
2253 HEADER_SNAP_SIZE,
2254 PCI_DMA_FROMDEVICE);
2255#else
2256 pci_unmap_single(nic->pdev, (dma_addr_t)
2257 rxdp->Buffer0_ptr,
2258 BUF0_LEN, PCI_DMA_FROMDEVICE);
2259 pci_unmap_single(nic->pdev, (dma_addr_t)
2260 rxdp->Buffer1_ptr,
2261 BUF1_LEN, PCI_DMA_FROMDEVICE);
2262 pci_unmap_single(nic->pdev, (dma_addr_t)
2263 rxdp->Buffer2_ptr,
2264 dev->mtu + BUF0_LEN + 4,
2265 PCI_DMA_FROMDEVICE);
2266#endif
2267 rx_osm_handler(ring_data, rxdp);
2268 get_info.offset++;
2269 ring_data->rx_curr_get_info.offset =
2270 get_info.offset;
2271 rxdp = ring_data->rx_blocks[get_block].block_virt_addr +
2272 get_info.offset;
2273 if (get_info.offset &&
2274 (!(get_info.offset % MAX_RXDS_PER_BLOCK))) {
2275 get_info.offset = 0;
2276 ring_data->rx_curr_get_info.offset
2277 = get_info.offset;
2278 get_block++;
2279 get_block %= ring_data->block_count;
2280 ring_data->rx_curr_get_info.block_index
2281 = get_block;
2282 rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
2283 }
2284
2285 get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
2286 get_info.offset;
2287#ifdef CONFIG_S2IO_NAPI
2288 nic->pkts_to_process -= 1;
2289 if (!nic->pkts_to_process)
2290 break;
2291#else
2292 pkt_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
2294 break;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002295#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 }
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002297 spin_unlock(&nic->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002299
2300/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 * tx_intr_handler - Transmit interrupt handler
2302 * @nic : device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002303 * Description:
2304 * If an interrupt was raised to indicate DMA complete of the
2305 * Tx packet, this function is called. It identifies the last TxD
2306 * whose buffer was freed and frees all skbs whose data have already
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 * DMA'ed into the NICs internal memory.
2308 * Return Value:
2309 * NONE
2310 */
2311
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002312static void tx_intr_handler(fifo_info_t *fifo_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002314 nic_t *nic = fifo_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 XENA_dev_config_t __iomem *bar0 = nic->bar0;
2316 struct net_device *dev = (struct net_device *) nic->dev;
2317 tx_curr_get_info_t get_info, put_info;
2318 struct sk_buff *skb;
2319 TxD_t *txdlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 u16 j, frg_cnt;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002321 register u64 val64 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002323 /*
2324 * tx_traffic_int reg is an R1 register, hence we read and write
2325 * back the same value in the register to clear it
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 */
2327 val64 = readq(&bar0->tx_traffic_int);
2328 writeq(val64, &bar0->tx_traffic_int);
2329
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002330 get_info = fifo_data->tx_curr_get_info;
2331 put_info = fifo_data->tx_curr_put_info;
2332 txdlp = (TxD_t *) fifo_data->list_info[get_info.offset].
2333 list_virt_addr;
2334 while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
2335 (get_info.offset != put_info.offset) &&
2336 (txdlp->Host_Control)) {
2337 /* Check for TxD errors */
2338 if (txdlp->Control_1 & TXD_T_CODE) {
2339 unsigned long long err;
2340 err = txdlp->Control_1 & TXD_T_CODE;
2341 DBG_PRINT(ERR_DBG, "***TxD error %llx\n",
2342 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002344
2345 skb = (struct sk_buff *) ((unsigned long)
2346 txdlp->Host_Control);
2347 if (skb == NULL) {
2348 DBG_PRINT(ERR_DBG, "%s: Null skb ",
2349 __FUNCTION__);
2350 DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
2351 return;
2352 }
2353
2354 frg_cnt = skb_shinfo(skb)->nr_frags;
2355 nic->tx_pkt_count++;
2356
2357 pci_unmap_single(nic->pdev, (dma_addr_t)
2358 txdlp->Buffer_Pointer,
2359 skb->len - skb->data_len,
2360 PCI_DMA_TODEVICE);
2361 if (frg_cnt) {
2362 TxD_t *temp;
2363 temp = txdlp;
2364 txdlp++;
2365 for (j = 0; j < frg_cnt; j++, txdlp++) {
2366 skb_frag_t *frag =
2367 &skb_shinfo(skb)->frags[j];
2368 pci_unmap_page(nic->pdev,
2369 (dma_addr_t)
2370 txdlp->
2371 Buffer_Pointer,
2372 frag->size,
2373 PCI_DMA_TODEVICE);
2374 }
2375 txdlp = temp;
2376 }
2377 memset(txdlp, 0,
2378 (sizeof(TxD_t) * fifo_data->max_txds));
2379
2380 /* Updating the statistics block */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002381 nic->stats.tx_bytes += skb->len;
2382 dev_kfree_skb_irq(skb);
2383
2384 get_info.offset++;
2385 get_info.offset %= get_info.fifo_len + 1;
2386 txdlp = (TxD_t *) fifo_data->list_info
2387 [get_info.offset].list_virt_addr;
2388 fifo_data->tx_curr_get_info.offset =
2389 get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 }
2391
2392 spin_lock(&nic->tx_lock);
2393 if (netif_queue_stopped(dev))
2394 netif_wake_queue(dev);
2395 spin_unlock(&nic->tx_lock);
2396}
2397
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002398/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 * alarm_intr_handler - Alarm Interrrupt handler
2400 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002401 * Description: If the interrupt was neither because of Rx packet or Tx
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 * complete, this function is called. If the interrupt was to indicate
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002403 * a loss of link, the OSM link status handler is invoked for any other
2404 * alarm interrupt the block that raised the interrupt is displayed
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 * and a H/W reset is issued.
2406 * Return Value:
2407 * NONE
2408*/
2409
2410static void alarm_intr_handler(struct s2io_nic *nic)
2411{
2412 struct net_device *dev = (struct net_device *) nic->dev;
2413 XENA_dev_config_t __iomem *bar0 = nic->bar0;
2414 register u64 val64 = 0, err_reg = 0;
2415
2416 /* Handling link status change error Intr */
2417 err_reg = readq(&bar0->mac_rmac_err_reg);
2418 writeq(err_reg, &bar0->mac_rmac_err_reg);
2419 if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
2420 schedule_work(&nic->set_link_task);
2421 }
2422
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002423 /* Handling Ecc errors */
2424 val64 = readq(&bar0->mc_err_reg);
2425 writeq(val64, &bar0->mc_err_reg);
2426 if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
2427 if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002428 nic->mac_control.stats_info->sw_stat.
2429 double_ecc_errs++;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002430 DBG_PRINT(ERR_DBG, "%s: Device indicates ",
2431 dev->name);
2432 DBG_PRINT(ERR_DBG, "double ECC error!!\n");
2433 netif_stop_queue(dev);
2434 schedule_work(&nic->rst_timer_task);
2435 } else {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002436 nic->mac_control.stats_info->sw_stat.
2437 single_ecc_errs++;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002438 }
2439 }
2440
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 /* In case of a serious error, the device will be Reset. */
2442 val64 = readq(&bar0->serr_source);
2443 if (val64 & SERR_SOURCE_ANY) {
2444 DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
2445 DBG_PRINT(ERR_DBG, "serious error!!\n");
2446 netif_stop_queue(dev);
2447 schedule_work(&nic->rst_timer_task);
2448 }
2449
2450 /*
2451 * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
2452 * Error occurs, the adapter will be recycled by disabling the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002453 * adapter enable bit and enabling it again after the device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 * becomes Quiescent.
2455 */
2456 val64 = readq(&bar0->pcc_err_reg);
2457 writeq(val64, &bar0->pcc_err_reg);
2458 if (val64 & PCC_FB_ECC_DB_ERR) {
2459 u64 ac = readq(&bar0->adapter_control);
2460 ac &= ~(ADAPTER_CNTL_EN);
2461 writeq(ac, &bar0->adapter_control);
2462 ac = readq(&bar0->adapter_control);
2463 schedule_work(&nic->set_link_task);
2464 }
2465
2466 /* Other type of interrupts are not being handled now, TODO */
2467}
2468
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002469/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 * wait_for_cmd_complete - waits for a command to complete.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002471 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002473 * Description: Function that waits for a command to Write into RMAC
2474 * ADDR DATA registers to be completed and returns either success or
2475 * error depending on whether the command was complete or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 * Return value:
2477 * SUCCESS on success and FAILURE on failure.
2478 */
2479
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002480int wait_for_cmd_complete(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481{
2482 XENA_dev_config_t __iomem *bar0 = sp->bar0;
2483 int ret = FAILURE, cnt = 0;
2484 u64 val64;
2485
2486 while (TRUE) {
2487 val64 = readq(&bar0->rmac_addr_cmd_mem);
2488 if (!(val64 & RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
2489 ret = SUCCESS;
2490 break;
2491 }
2492 msleep(50);
2493 if (cnt++ > 10)
2494 break;
2495 }
2496
2497 return ret;
2498}
2499
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002500/**
2501 * s2io_reset - Resets the card.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 * @sp : private member of the device structure.
2503 * Description: Function to Reset the card. This function then also
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002504 * restores the previously saved PCI configuration space registers as
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 * the card reset also resets the configuration space.
2506 * Return value:
2507 * void.
2508 */
2509
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002510void s2io_reset(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511{
2512 XENA_dev_config_t __iomem *bar0 = sp->bar0;
2513 u64 val64;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002514 u16 subid, pci_cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516 val64 = SW_RESET_ALL;
2517 writeq(val64, &bar0->sw_reset);
2518
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002519 /*
2520 * At this stage, if the PCI write is indeed completed, the
2521 * card is reset and so is the PCI Config space of the device.
2522 * So a read cannot be issued at this stage on any of the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 * registers to ensure the write into "sw_reset" register
2524 * has gone through.
2525 * Question: Is there any system call that will explicitly force
2526 * all the write commands still pending on the bus to be pushed
2527 * through?
2528 * As of now I'am just giving a 250ms delay and hoping that the
2529 * PCI write to sw_reset register is done by this time.
2530 */
2531 msleep(250);
2532
2533 /* Restore the PCI state saved during initializarion. */
2534 pci_restore_state(sp->pdev);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002535
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 s2io_init_pci(sp);
2537
2538 msleep(250);
2539
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002540 /* Set swapper to enable I/O register access */
2541 s2io_set_swapper(sp);
2542
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002543 /* Clear certain PCI/PCI-X fields after reset */
2544 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
2545 pci_cmd &= 0x7FFF; /* Clear parity err detect bit */
2546 pci_write_config_word(sp->pdev, PCI_COMMAND, pci_cmd);
2547
2548 val64 = readq(&bar0->txpic_int_reg);
2549 val64 &= ~BIT(62); /* Clearing PCI_STATUS error reflected here */
2550 writeq(val64, &bar0->txpic_int_reg);
2551
2552 /* Clearing PCIX Ecc status register */
2553 pci_write_config_dword(sp->pdev, 0x68, 0);
2554
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002555 /* Reset device statistics maintained by OS */
2556 memset(&sp->stats, 0, sizeof (struct net_device_stats));
2557
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 /* SXE-002: Configure link and activity LED to turn it off */
2559 subid = sp->pdev->subsystem_device;
2560 if ((subid & 0xFF) >= 0x07) {
2561 val64 = readq(&bar0->gpio_control);
2562 val64 |= 0x0000800000000000ULL;
2563 writeq(val64, &bar0->gpio_control);
2564 val64 = 0x0411040400000000ULL;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002565 writeq(val64, (void __iomem *) ((u8 *) bar0 + 0x2700));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 }
2567
2568 sp->device_enabled_once = FALSE;
2569}
2570
2571/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002572 * s2io_set_swapper - to set the swapper controle on the card
2573 * @sp : private member of the device structure,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 * pointer to the s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002575 * Description: Function to set the swapper control on the card
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 * correctly depending on the 'endianness' of the system.
2577 * Return value:
2578 * SUCCESS on success and FAILURE on failure.
2579 */
2580
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002581int s2io_set_swapper(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582{
2583 struct net_device *dev = sp->dev;
2584 XENA_dev_config_t __iomem *bar0 = sp->bar0;
2585 u64 val64, valt, valr;
2586
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002587 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 * Set proper endian settings and verify the same by reading
2589 * the PIF Feed-back register.
2590 */
2591
2592 val64 = readq(&bar0->pif_rd_swapper_fb);
2593 if (val64 != 0x0123456789ABCDEFULL) {
2594 int i = 0;
2595 u64 value[] = { 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */
2596 0x8100008181000081ULL, /* FE=1, SE=0 */
2597 0x4200004242000042ULL, /* FE=0, SE=1 */
2598 0}; /* FE=0, SE=0 */
2599
2600 while(i<4) {
2601 writeq(value[i], &bar0->swapper_ctrl);
2602 val64 = readq(&bar0->pif_rd_swapper_fb);
2603 if (val64 == 0x0123456789ABCDEFULL)
2604 break;
2605 i++;
2606 }
2607 if (i == 4) {
2608 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
2609 dev->name);
2610 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
2611 (unsigned long long) val64);
2612 return FAILURE;
2613 }
2614 valr = value[i];
2615 } else {
2616 valr = readq(&bar0->swapper_ctrl);
2617 }
2618
2619 valt = 0x0123456789ABCDEFULL;
2620 writeq(valt, &bar0->xmsi_address);
2621 val64 = readq(&bar0->xmsi_address);
2622
2623 if(val64 != valt) {
2624 int i = 0;
2625 u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */
2626 0x0081810000818100ULL, /* FE=1, SE=0 */
2627 0x0042420000424200ULL, /* FE=0, SE=1 */
2628 0}; /* FE=0, SE=0 */
2629
2630 while(i<4) {
2631 writeq((value[i] | valr), &bar0->swapper_ctrl);
2632 writeq(valt, &bar0->xmsi_address);
2633 val64 = readq(&bar0->xmsi_address);
2634 if(val64 == valt)
2635 break;
2636 i++;
2637 }
2638 if(i == 4) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002639 unsigned long long x = val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr ");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002641 DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 return FAILURE;
2643 }
2644 }
2645 val64 = readq(&bar0->swapper_ctrl);
2646 val64 &= 0xFFFF000000000000ULL;
2647
2648#ifdef __BIG_ENDIAN
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002649 /*
2650 * The device by default set to a big endian format, so a
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 * big endian driver need not set anything.
2652 */
2653 val64 |= (SWAPPER_CTRL_TXP_FE |
2654 SWAPPER_CTRL_TXP_SE |
2655 SWAPPER_CTRL_TXD_R_FE |
2656 SWAPPER_CTRL_TXD_W_FE |
2657 SWAPPER_CTRL_TXF_R_FE |
2658 SWAPPER_CTRL_RXD_R_FE |
2659 SWAPPER_CTRL_RXD_W_FE |
2660 SWAPPER_CTRL_RXF_W_FE |
2661 SWAPPER_CTRL_XMSI_FE |
2662 SWAPPER_CTRL_XMSI_SE |
2663 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
2664 writeq(val64, &bar0->swapper_ctrl);
2665#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002666 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 * Initially we enable all bits to make it accessible by the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002668 * driver, then we selectively enable only those bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 * we want to set.
2670 */
2671 val64 |= (SWAPPER_CTRL_TXP_FE |
2672 SWAPPER_CTRL_TXP_SE |
2673 SWAPPER_CTRL_TXD_R_FE |
2674 SWAPPER_CTRL_TXD_R_SE |
2675 SWAPPER_CTRL_TXD_W_FE |
2676 SWAPPER_CTRL_TXD_W_SE |
2677 SWAPPER_CTRL_TXF_R_FE |
2678 SWAPPER_CTRL_RXD_R_FE |
2679 SWAPPER_CTRL_RXD_R_SE |
2680 SWAPPER_CTRL_RXD_W_FE |
2681 SWAPPER_CTRL_RXD_W_SE |
2682 SWAPPER_CTRL_RXF_W_FE |
2683 SWAPPER_CTRL_XMSI_FE |
2684 SWAPPER_CTRL_XMSI_SE |
2685 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
2686 writeq(val64, &bar0->swapper_ctrl);
2687#endif
2688 val64 = readq(&bar0->swapper_ctrl);
2689
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002690 /*
2691 * Verifying if endian settings are accurate by reading a
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 * feedback register.
2693 */
2694 val64 = readq(&bar0->pif_rd_swapper_fb);
2695 if (val64 != 0x0123456789ABCDEFULL) {
2696 /* Endian settings are incorrect, calls for another dekko. */
2697 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
2698 dev->name);
2699 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
2700 (unsigned long long) val64);
2701 return FAILURE;
2702 }
2703
2704 return SUCCESS;
2705}
2706
2707/* ********************************************************* *
2708 * Functions defined below concern the OS part of the driver *
2709 * ********************************************************* */
2710
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002711/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 * s2io_open - open entry point of the driver
2713 * @dev : pointer to the device structure.
2714 * Description:
2715 * This function is the open entry point of the driver. It mainly calls a
2716 * function to allocate Rx buffers and inserts them into the buffer
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002717 * descriptors and then enables the Rx part of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 * Return value:
2719 * 0 on success and an appropriate (-)ve integer as defined in errno.h
2720 * file on failure.
2721 */
2722
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002723int s2io_open(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724{
2725 nic_t *sp = dev->priv;
2726 int err = 0;
2727
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002728 /*
2729 * Make sure you have link off by default every time
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 * Nic is initialized
2731 */
2732 netif_carrier_off(dev);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002733 sp->last_link_state = 0; /* Unkown link state */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734
2735 /* Initialize H/W and enable interrupts */
2736 if (s2io_card_up(sp)) {
2737 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
2738 dev->name);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002739 err = -ENODEV;
2740 goto hw_init_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 }
2742
2743 /* After proper initialization of H/W, register ISR */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002744 err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 sp->name, dev);
2746 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
2748 dev->name);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002749 goto isr_registration_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 }
2751
2752 if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
2753 DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002754 err = -ENODEV;
2755 goto setting_mac_address_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 }
2757
2758 netif_start_queue(dev);
2759 return 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002760
2761setting_mac_address_failed:
2762 free_irq(sp->pdev->irq, dev);
2763isr_registration_failed:
2764 s2io_reset(sp);
2765hw_init_failed:
2766 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767}
2768
2769/**
2770 * s2io_close -close entry point of the driver
2771 * @dev : device pointer.
2772 * Description:
2773 * This is the stop entry point of the driver. It needs to undo exactly
2774 * whatever was done by the open entry point,thus it's usually referred to
2775 * as the close function.Among other things this function mainly stops the
2776 * Rx side of the NIC and frees all the Rx buffers in the Rx rings.
2777 * Return value:
2778 * 0 on success and an appropriate (-)ve integer as defined in errno.h
2779 * file on failure.
2780 */
2781
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002782int s2io_close(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783{
2784 nic_t *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 flush_scheduled_work();
2786 netif_stop_queue(dev);
2787 /* Reset card, kill tasklet and free Tx and Rx buffers. */
2788 s2io_card_down(sp);
2789
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002790 free_irq(sp->pdev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 sp->device_close_flag = TRUE; /* Device is shut down. */
2792 return 0;
2793}
2794
2795/**
2796 * s2io_xmit - Tx entry point of te driver
2797 * @skb : the socket buffer containing the Tx data.
2798 * @dev : device pointer.
2799 * Description :
2800 * This function is the Tx entry point of the driver. S2IO NIC supports
2801 * certain protocol assist features on Tx side, namely CSO, S/G, LSO.
2802 * NOTE: when device cant queue the pkt,just the trans_start variable will
2803 * not be upadted.
2804 * Return value:
2805 * 0 on success & 1 on failure.
2806 */
2807
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002808int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809{
2810 nic_t *sp = dev->priv;
2811 u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
2812 register u64 val64;
2813 TxD_t *txdp;
2814 TxFIFO_element_t __iomem *tx_fifo;
2815 unsigned long flags;
2816#ifdef NETIF_F_TSO
2817 int mss;
2818#endif
2819 mac_info_t *mac_control;
2820 struct config_param *config;
2821 XENA_dev_config_t __iomem *bar0 = sp->bar0;
2822
2823 mac_control = &sp->mac_control;
2824 config = &sp->config;
2825
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002826 DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 spin_lock_irqsave(&sp->tx_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 if (atomic_read(&sp->card_state) == CARD_DOWN) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002829 DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 dev->name);
2831 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002832 dev_kfree_skb(skb);
2833 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 }
2835
2836 queue = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002838 put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
2839 get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
2840 txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off].
2841 list_virt_addr;
2842
2843 queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 /* Avoid "put" pointer going beyond "get" pointer */
2845 if (txdp->Host_Control || (((put_off + 1) % queue_len) == get_off)) {
2846 DBG_PRINT(ERR_DBG, "Error in xmit, No free TXDs.\n");
2847 netif_stop_queue(dev);
2848 dev_kfree_skb(skb);
2849 spin_unlock_irqrestore(&sp->tx_lock, flags);
2850 return 0;
2851 }
2852#ifdef NETIF_F_TSO
2853 mss = skb_shinfo(skb)->tso_size;
2854 if (mss) {
2855 txdp->Control_1 |= TXD_TCP_LSO_EN;
2856 txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
2857 }
2858#endif
2859
2860 frg_cnt = skb_shinfo(skb)->nr_frags;
2861 frg_len = skb->len - skb->data_len;
2862
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 txdp->Buffer_Pointer = pci_map_single
2864 (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002865 txdp->Host_Control = (unsigned long) skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 if (skb->ip_summed == CHECKSUM_HW) {
2867 txdp->Control_2 |=
2868 (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
2869 TXD_TX_CKO_UDP_EN);
2870 }
2871
2872 txdp->Control_2 |= config->tx_intr_type;
2873
2874 txdp->Control_1 |= (TXD_BUFFER0_SIZE(frg_len) |
2875 TXD_GATHER_CODE_FIRST);
2876 txdp->Control_1 |= TXD_LIST_OWN_XENA;
2877
2878 /* For fragmented SKB. */
2879 for (i = 0; i < frg_cnt; i++) {
2880 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
2881 txdp++;
2882 txdp->Buffer_Pointer = (u64) pci_map_page
2883 (sp->pdev, frag->page, frag->page_offset,
2884 frag->size, PCI_DMA_TODEVICE);
2885 txdp->Control_1 |= TXD_BUFFER0_SIZE(frag->size);
2886 }
2887 txdp->Control_1 |= TXD_GATHER_CODE_LAST;
2888
2889 tx_fifo = mac_control->tx_FIFO_start[queue];
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002890 val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 writeq(val64, &tx_fifo->TxDL_Pointer);
2892
2893 val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
2894 TX_FIFO_LAST_LIST);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002895
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896#ifdef NETIF_F_TSO
2897 if (mss)
2898 val64 |= TX_FIFO_SPECIAL_FUNC;
2899#endif
2900 writeq(val64, &tx_fifo->List_Control);
2901
2902 /* Perform a PCI read to flush previous writes */
2903 val64 = readq(&bar0->general_int_status);
2904
2905 put_off++;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002906 put_off %= mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
2907 mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
2909 /* Avoid "put" pointer going beyond "get" pointer */
2910 if (((put_off + 1) % queue_len) == get_off) {
2911 DBG_PRINT(TX_DBG,
2912 "No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
2913 put_off, get_off);
2914 netif_stop_queue(dev);
2915 }
2916
2917 dev->trans_start = jiffies;
2918 spin_unlock_irqrestore(&sp->tx_lock, flags);
2919
2920 return 0;
2921}
2922
2923/**
2924 * s2io_isr - ISR handler of the device .
2925 * @irq: the irq of the device.
2926 * @dev_id: a void pointer to the dev structure of the NIC.
2927 * @pt_regs: pointer to the registers pushed on the stack.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002928 * Description: This function is the ISR handler of the device. It
2929 * identifies the reason for the interrupt and calls the relevant
2930 * service routines. As a contongency measure, this ISR allocates the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 * recv buffers, if their numbers are below the panic value which is
2932 * presently set to 25% of the original number of rcv buffers allocated.
2933 * Return value:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002934 * IRQ_HANDLED: will be returned if IRQ was handled by this routine
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 * IRQ_NONE: will be returned if interrupt is not from our device
2936 */
2937static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
2938{
2939 struct net_device *dev = (struct net_device *) dev_id;
2940 nic_t *sp = dev->priv;
2941 XENA_dev_config_t __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002942 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 u64 reason = 0;
2944 mac_info_t *mac_control;
2945 struct config_param *config;
2946
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002947 atomic_inc(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 mac_control = &sp->mac_control;
2949 config = &sp->config;
2950
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002951 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 * Identify the cause for interrupt and call the appropriate
2953 * interrupt handler. Causes for the interrupt could be;
2954 * 1. Rx of packet.
2955 * 2. Tx complete.
2956 * 3. Link down.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002957 * 4. Error in any functional blocks of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 */
2959 reason = readq(&bar0->general_int_status);
2960
2961 if (!reason) {
2962 /* The interrupt was not raised by Xena. */
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002963 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 return IRQ_NONE;
2965 }
2966
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 if (reason & (GEN_ERROR_INTR))
2968 alarm_intr_handler(sp);
2969
2970#ifdef CONFIG_S2IO_NAPI
2971 if (reason & GEN_INTR_RXTRAFFIC) {
2972 if (netif_rx_schedule_prep(dev)) {
2973 en_dis_able_nic_intrs(sp, RX_TRAFFIC_INTR,
2974 DISABLE_INTRS);
2975 __netif_rx_schedule(dev);
2976 }
2977 }
2978#else
2979 /* If Intr is because of Rx Traffic */
2980 if (reason & GEN_INTR_RXTRAFFIC) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002981 for (i = 0; i < config->rx_ring_num; i++) {
2982 rx_intr_handler(&mac_control->rings[i]);
2983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 }
2985#endif
2986
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002987 /* If Intr is because of Tx Traffic */
2988 if (reason & GEN_INTR_TXTRAFFIC) {
2989 for (i = 0; i < config->tx_fifo_num; i++)
2990 tx_intr_handler(&mac_control->fifos[i]);
2991 }
2992
2993 /*
2994 * If the Rx buffer count is below the panic threshold then
2995 * reallocate the buffers from the interrupt handler itself,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 * else schedule a tasklet to reallocate the buffers.
2997 */
2998#ifndef CONFIG_S2IO_NAPI
2999 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003000 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
3002 int level = rx_buffer_level(sp, rxb_size, i);
3003
3004 if ((level == PANIC) && (!TASKLET_IN_USE)) {
3005 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name);
3006 DBG_PRINT(INTR_DBG, "PANIC levels\n");
3007 if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
3008 DBG_PRINT(ERR_DBG, "%s:Out of memory",
3009 dev->name);
3010 DBG_PRINT(ERR_DBG, " in ISR!!\n");
3011 clear_bit(0, (&sp->tasklet_status));
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003012 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 return IRQ_HANDLED;
3014 }
3015 clear_bit(0, (&sp->tasklet_status));
3016 } else if (level == LOW) {
3017 tasklet_schedule(&sp->task);
3018 }
3019 }
3020#endif
3021
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003022 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 return IRQ_HANDLED;
3024}
3025
3026/**
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003027 * s2io_updt_stats -
3028 */
3029static void s2io_updt_stats(nic_t *sp)
3030{
3031 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3032 u64 val64;
3033 int cnt = 0;
3034
3035 if (atomic_read(&sp->card_state) == CARD_UP) {
3036 /* Apprx 30us on a 133 MHz bus */
3037 val64 = SET_UPDT_CLICKS(10) |
3038 STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
3039 writeq(val64, &bar0->stat_cfg);
3040 do {
3041 udelay(100);
3042 val64 = readq(&bar0->stat_cfg);
3043 if (!(val64 & BIT(0)))
3044 break;
3045 cnt++;
3046 if (cnt == 5)
3047 break; /* Updt failed */
3048 } while(1);
3049 }
3050}
3051
3052/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003053 * s2io_get_stats - Updates the device statistics structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 * @dev : pointer to the device structure.
3055 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003056 * This function updates the device statistics structure in the s2io_nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 * structure and returns a pointer to the same.
3058 * Return value:
3059 * pointer to the updated net_device_stats structure.
3060 */
3061
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003062struct net_device_stats *s2io_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063{
3064 nic_t *sp = dev->priv;
3065 mac_info_t *mac_control;
3066 struct config_param *config;
3067
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003068
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 mac_control = &sp->mac_control;
3070 config = &sp->config;
3071
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003072 /* Configure Stats for immediate updt */
3073 s2io_updt_stats(sp);
3074
3075 sp->stats.tx_packets =
3076 le32_to_cpu(mac_control->stats_info->tmac_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003077 sp->stats.tx_errors =
3078 le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
3079 sp->stats.rx_errors =
3080 le32_to_cpu(mac_control->stats_info->rmac_drop_frms);
3081 sp->stats.multicast =
3082 le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 sp->stats.rx_length_errors =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003084 le32_to_cpu(mac_control->stats_info->rmac_long_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085
3086 return (&sp->stats);
3087}
3088
3089/**
3090 * s2io_set_multicast - entry point for multicast address enable/disable.
3091 * @dev : pointer to the device structure
3092 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003093 * This function is a driver entry point which gets called by the kernel
3094 * whenever multicast addresses must be enabled/disabled. This also gets
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 * called to set/reset promiscuous mode. Depending on the deivce flag, we
3096 * determine, if multicast address must be enabled or if promiscuous mode
3097 * is to be disabled etc.
3098 * Return value:
3099 * void.
3100 */
3101
3102static void s2io_set_multicast(struct net_device *dev)
3103{
3104 int i, j, prev_cnt;
3105 struct dev_mc_list *mclist;
3106 nic_t *sp = dev->priv;
3107 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3108 u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
3109 0xfeffffffffffULL;
3110 u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
3111 void __iomem *add;
3112
3113 if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) {
3114 /* Enable all Multicast addresses */
3115 writeq(RMAC_ADDR_DATA0_MEM_ADDR(multi_mac),
3116 &bar0->rmac_addr_data0_mem);
3117 writeq(RMAC_ADDR_DATA1_MEM_MASK(mask),
3118 &bar0->rmac_addr_data1_mem);
3119 val64 = RMAC_ADDR_CMD_MEM_WE |
3120 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
3121 RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
3122 writeq(val64, &bar0->rmac_addr_cmd_mem);
3123 /* Wait till command completes */
3124 wait_for_cmd_complete(sp);
3125
3126 sp->m_cast_flg = 1;
3127 sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
3128 } else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) {
3129 /* Disable all Multicast addresses */
3130 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
3131 &bar0->rmac_addr_data0_mem);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003132 writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0),
3133 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 val64 = RMAC_ADDR_CMD_MEM_WE |
3135 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
3136 RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos);
3137 writeq(val64, &bar0->rmac_addr_cmd_mem);
3138 /* Wait till command completes */
3139 wait_for_cmd_complete(sp);
3140
3141 sp->m_cast_flg = 0;
3142 sp->all_multi_pos = 0;
3143 }
3144
3145 if ((dev->flags & IFF_PROMISC) && (!sp->promisc_flg)) {
3146 /* Put the NIC into promiscuous mode */
3147 add = &bar0->mac_cfg;
3148 val64 = readq(&bar0->mac_cfg);
3149 val64 |= MAC_CFG_RMAC_PROM_ENABLE;
3150
3151 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
3152 writel((u32) val64, add);
3153 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
3154 writel((u32) (val64 >> 32), (add + 4));
3155
3156 val64 = readq(&bar0->mac_cfg);
3157 sp->promisc_flg = 1;
3158 DBG_PRINT(ERR_DBG, "%s: entered promiscuous mode\n",
3159 dev->name);
3160 } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) {
3161 /* Remove the NIC from promiscuous mode */
3162 add = &bar0->mac_cfg;
3163 val64 = readq(&bar0->mac_cfg);
3164 val64 &= ~MAC_CFG_RMAC_PROM_ENABLE;
3165
3166 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
3167 writel((u32) val64, add);
3168 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
3169 writel((u32) (val64 >> 32), (add + 4));
3170
3171 val64 = readq(&bar0->mac_cfg);
3172 sp->promisc_flg = 0;
3173 DBG_PRINT(ERR_DBG, "%s: left promiscuous mode\n",
3174 dev->name);
3175 }
3176
3177 /* Update individual M_CAST address list */
3178 if ((!sp->m_cast_flg) && dev->mc_count) {
3179 if (dev->mc_count >
3180 (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) {
3181 DBG_PRINT(ERR_DBG, "%s: No more Rx filters ",
3182 dev->name);
3183 DBG_PRINT(ERR_DBG, "can be added, please enable ");
3184 DBG_PRINT(ERR_DBG, "ALL_MULTI instead\n");
3185 return;
3186 }
3187
3188 prev_cnt = sp->mc_addr_count;
3189 sp->mc_addr_count = dev->mc_count;
3190
3191 /* Clear out the previous list of Mc in the H/W. */
3192 for (i = 0; i < prev_cnt; i++) {
3193 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
3194 &bar0->rmac_addr_data0_mem);
3195 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003196 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 val64 = RMAC_ADDR_CMD_MEM_WE |
3198 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
3199 RMAC_ADDR_CMD_MEM_OFFSET
3200 (MAC_MC_ADDR_START_OFFSET + i);
3201 writeq(val64, &bar0->rmac_addr_cmd_mem);
3202
3203 /* Wait for command completes */
3204 if (wait_for_cmd_complete(sp)) {
3205 DBG_PRINT(ERR_DBG, "%s: Adding ",
3206 dev->name);
3207 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
3208 return;
3209 }
3210 }
3211
3212 /* Create the new Rx filter list and update the same in H/W. */
3213 for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
3214 i++, mclist = mclist->next) {
3215 memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr,
3216 ETH_ALEN);
3217 for (j = 0; j < ETH_ALEN; j++) {
3218 mac_addr |= mclist->dmi_addr[j];
3219 mac_addr <<= 8;
3220 }
3221 mac_addr >>= 8;
3222 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
3223 &bar0->rmac_addr_data0_mem);
3224 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003225 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 val64 = RMAC_ADDR_CMD_MEM_WE |
3227 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
3228 RMAC_ADDR_CMD_MEM_OFFSET
3229 (i + MAC_MC_ADDR_START_OFFSET);
3230 writeq(val64, &bar0->rmac_addr_cmd_mem);
3231
3232 /* Wait for command completes */
3233 if (wait_for_cmd_complete(sp)) {
3234 DBG_PRINT(ERR_DBG, "%s: Adding ",
3235 dev->name);
3236 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
3237 return;
3238 }
3239 }
3240 }
3241}
3242
3243/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003244 * s2io_set_mac_addr - Programs the Xframe mac address
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 * @dev : pointer to the device structure.
3246 * @addr: a uchar pointer to the new mac address which is to be set.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003247 * Description : This procedure will program the Xframe to receive
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 * frames with new Mac Address
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003249 * Return value: SUCCESS on success and an appropriate (-)ve integer
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 * as defined in errno.h file on failure.
3251 */
3252
3253int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
3254{
3255 nic_t *sp = dev->priv;
3256 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3257 register u64 val64, mac_addr = 0;
3258 int i;
3259
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003260 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 * Set the new MAC address as the new unicast filter and reflect this
3262 * change on the device address registered with the OS. It will be
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003263 * at offset 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 */
3265 for (i = 0; i < ETH_ALEN; i++) {
3266 mac_addr <<= 8;
3267 mac_addr |= addr[i];
3268 }
3269
3270 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
3271 &bar0->rmac_addr_data0_mem);
3272
3273 val64 =
3274 RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
3275 RMAC_ADDR_CMD_MEM_OFFSET(0);
3276 writeq(val64, &bar0->rmac_addr_cmd_mem);
3277 /* Wait till command completes */
3278 if (wait_for_cmd_complete(sp)) {
3279 DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
3280 return FAILURE;
3281 }
3282
3283 return SUCCESS;
3284}
3285
3286/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003287 * s2io_ethtool_sset - Sets different link parameters.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure.
3289 * @info: pointer to the structure with parameters given by ethtool to set
3290 * link information.
3291 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003292 * The function sets different link parameters provided by the user onto
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 * the NIC.
3294 * Return value:
3295 * 0 on success.
3296*/
3297
3298static int s2io_ethtool_sset(struct net_device *dev,
3299 struct ethtool_cmd *info)
3300{
3301 nic_t *sp = dev->priv;
3302 if ((info->autoneg == AUTONEG_ENABLE) ||
3303 (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
3304 return -EINVAL;
3305 else {
3306 s2io_close(sp->dev);
3307 s2io_open(sp->dev);
3308 }
3309
3310 return 0;
3311}
3312
3313/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003314 * s2io_ethtol_gset - Return link specific information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 * @sp : private member of the device structure, pointer to the
3316 * s2io_nic structure.
3317 * @info : pointer to the structure with parameters given by ethtool
3318 * to return link information.
3319 * Description:
3320 * Returns link specific information like speed, duplex etc.. to ethtool.
3321 * Return value :
3322 * return 0 on success.
3323 */
3324
3325static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
3326{
3327 nic_t *sp = dev->priv;
3328 info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
3329 info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
3330 info->port = PORT_FIBRE;
3331 /* info->transceiver?? TODO */
3332
3333 if (netif_carrier_ok(sp->dev)) {
3334 info->speed = 10000;
3335 info->duplex = DUPLEX_FULL;
3336 } else {
3337 info->speed = -1;
3338 info->duplex = -1;
3339 }
3340
3341 info->autoneg = AUTONEG_DISABLE;
3342 return 0;
3343}
3344
3345/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003346 * s2io_ethtool_gdrvinfo - Returns driver specific information.
3347 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 * s2io_nic structure.
3349 * @info : pointer to the structure with parameters given by ethtool to
3350 * return driver information.
3351 * Description:
3352 * Returns driver specefic information like name, version etc.. to ethtool.
3353 * Return value:
3354 * void
3355 */
3356
3357static void s2io_ethtool_gdrvinfo(struct net_device *dev,
3358 struct ethtool_drvinfo *info)
3359{
3360 nic_t *sp = dev->priv;
3361
3362 strncpy(info->driver, s2io_driver_name, sizeof(s2io_driver_name));
3363 strncpy(info->version, s2io_driver_version,
3364 sizeof(s2io_driver_version));
3365 strncpy(info->fw_version, "", 32);
3366 strncpy(info->bus_info, pci_name(sp->pdev), 32);
3367 info->regdump_len = XENA_REG_SPACE;
3368 info->eedump_len = XENA_EEPROM_SPACE;
3369 info->testinfo_len = S2IO_TEST_LEN;
3370 info->n_stats = S2IO_STAT_LEN;
3371}
3372
3373/**
3374 * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003375 * @sp: private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003377 * @regs : pointer to the structure with parameters given by ethtool for
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 * dumping the registers.
3379 * @reg_space: The input argumnet into which all the registers are dumped.
3380 * Description:
3381 * Dumps the entire register space of xFrame NIC into the user given
3382 * buffer area.
3383 * Return value :
3384 * void .
3385*/
3386
3387static void s2io_ethtool_gregs(struct net_device *dev,
3388 struct ethtool_regs *regs, void *space)
3389{
3390 int i;
3391 u64 reg;
3392 u8 *reg_space = (u8 *) space;
3393 nic_t *sp = dev->priv;
3394
3395 regs->len = XENA_REG_SPACE;
3396 regs->version = sp->pdev->subsystem_device;
3397
3398 for (i = 0; i < regs->len; i += 8) {
3399 reg = readq(sp->bar0 + i);
3400 memcpy((reg_space + i), &reg, 8);
3401 }
3402}
3403
3404/**
3405 * s2io_phy_id - timer function that alternates adapter LED.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003406 * @data : address of the private member of the device structure, which
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 * is a pointer to the s2io_nic structure, provided as an u32.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003408 * Description: This is actually the timer function that alternates the
3409 * adapter LED bit of the adapter control bit to set/reset every time on
3410 * invocation. The timer is set for 1/2 a second, hence tha NIC blinks
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 * once every second.
3412*/
3413static void s2io_phy_id(unsigned long data)
3414{
3415 nic_t *sp = (nic_t *) data;
3416 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3417 u64 val64 = 0;
3418 u16 subid;
3419
3420 subid = sp->pdev->subsystem_device;
3421 if ((subid & 0xFF) >= 0x07) {
3422 val64 = readq(&bar0->gpio_control);
3423 val64 ^= GPIO_CTRL_GPIO_0;
3424 writeq(val64, &bar0->gpio_control);
3425 } else {
3426 val64 = readq(&bar0->adapter_control);
3427 val64 ^= ADAPTER_LED_ON;
3428 writeq(val64, &bar0->adapter_control);
3429 }
3430
3431 mod_timer(&sp->id_timer, jiffies + HZ / 2);
3432}
3433
3434/**
3435 * s2io_ethtool_idnic - To physically identify the nic on the system.
3436 * @sp : private member of the device structure, which is a pointer to the
3437 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003438 * @id : pointer to the structure with identification parameters given by
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 * ethtool.
3440 * Description: Used to physically identify the NIC on the system.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003441 * The Link LED will blink for a time specified by the user for
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 * identification.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003443 * NOTE: The Link has to be Up to be able to blink the LED. Hence
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 * identification is possible only if it's link is up.
3445 * Return value:
3446 * int , returns 0 on success
3447 */
3448
3449static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
3450{
3451 u64 val64 = 0, last_gpio_ctrl_val;
3452 nic_t *sp = dev->priv;
3453 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3454 u16 subid;
3455
3456 subid = sp->pdev->subsystem_device;
3457 last_gpio_ctrl_val = readq(&bar0->gpio_control);
3458 if ((subid & 0xFF) < 0x07) {
3459 val64 = readq(&bar0->adapter_control);
3460 if (!(val64 & ADAPTER_CNTL_EN)) {
3461 printk(KERN_ERR
3462 "Adapter Link down, cannot blink LED\n");
3463 return -EFAULT;
3464 }
3465 }
3466 if (sp->id_timer.function == NULL) {
3467 init_timer(&sp->id_timer);
3468 sp->id_timer.function = s2io_phy_id;
3469 sp->id_timer.data = (unsigned long) sp;
3470 }
3471 mod_timer(&sp->id_timer, jiffies);
3472 if (data)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003473 msleep_interruptible(data * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003475 msleep_interruptible(MAX_FLICKER_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 del_timer_sync(&sp->id_timer);
3477
3478 if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) {
3479 writeq(last_gpio_ctrl_val, &bar0->gpio_control);
3480 last_gpio_ctrl_val = readq(&bar0->gpio_control);
3481 }
3482
3483 return 0;
3484}
3485
3486/**
3487 * s2io_ethtool_getpause_data -Pause frame frame generation and reception.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003488 * @sp : private member of the device structure, which is a pointer to the
3489 * s2io_nic structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 * @ep : pointer to the structure with pause parameters given by ethtool.
3491 * Description:
3492 * Returns the Pause frame generation and reception capability of the NIC.
3493 * Return value:
3494 * void
3495 */
3496static void s2io_ethtool_getpause_data(struct net_device *dev,
3497 struct ethtool_pauseparam *ep)
3498{
3499 u64 val64;
3500 nic_t *sp = dev->priv;
3501 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3502
3503 val64 = readq(&bar0->rmac_pause_cfg);
3504 if (val64 & RMAC_PAUSE_GEN_ENABLE)
3505 ep->tx_pause = TRUE;
3506 if (val64 & RMAC_PAUSE_RX_ENABLE)
3507 ep->rx_pause = TRUE;
3508 ep->autoneg = FALSE;
3509}
3510
3511/**
3512 * s2io_ethtool_setpause_data - set/reset pause frame generation.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003513 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 * s2io_nic structure.
3515 * @ep : pointer to the structure with pause parameters given by ethtool.
3516 * Description:
3517 * It can be used to set or reset Pause frame generation or reception
3518 * support of the NIC.
3519 * Return value:
3520 * int, returns 0 on Success
3521 */
3522
3523static int s2io_ethtool_setpause_data(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003524 struct ethtool_pauseparam *ep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525{
3526 u64 val64;
3527 nic_t *sp = dev->priv;
3528 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3529
3530 val64 = readq(&bar0->rmac_pause_cfg);
3531 if (ep->tx_pause)
3532 val64 |= RMAC_PAUSE_GEN_ENABLE;
3533 else
3534 val64 &= ~RMAC_PAUSE_GEN_ENABLE;
3535 if (ep->rx_pause)
3536 val64 |= RMAC_PAUSE_RX_ENABLE;
3537 else
3538 val64 &= ~RMAC_PAUSE_RX_ENABLE;
3539 writeq(val64, &bar0->rmac_pause_cfg);
3540 return 0;
3541}
3542
3543/**
3544 * read_eeprom - reads 4 bytes of data from user given offset.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003545 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 * s2io_nic structure.
3547 * @off : offset at which the data must be written
3548 * @data : Its an output parameter where the data read at the given
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003549 * offset is stored.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003551 * Will read 4 bytes of data from the user given offset and return the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 * read data.
3553 * NOTE: Will allow to read only part of the EEPROM visible through the
3554 * I2C bus.
3555 * Return value:
3556 * -1 on failure and 0 on success.
3557 */
3558
3559#define S2IO_DEV_ID 5
3560static int read_eeprom(nic_t * sp, int off, u32 * data)
3561{
3562 int ret = -1;
3563 u32 exit_cnt = 0;
3564 u64 val64;
3565 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3566
3567 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
3568 I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ |
3569 I2C_CONTROL_CNTL_START;
3570 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
3571
3572 while (exit_cnt < 5) {
3573 val64 = readq(&bar0->i2c_control);
3574 if (I2C_CONTROL_CNTL_END(val64)) {
3575 *data = I2C_CONTROL_GET_DATA(val64);
3576 ret = 0;
3577 break;
3578 }
3579 msleep(50);
3580 exit_cnt++;
3581 }
3582
3583 return ret;
3584}
3585
3586/**
3587 * write_eeprom - actually writes the relevant part of the data value.
3588 * @sp : private member of the device structure, which is a pointer to the
3589 * s2io_nic structure.
3590 * @off : offset at which the data must be written
3591 * @data : The data that is to be written
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003592 * @cnt : Number of bytes of the data that are actually to be written into
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 * the Eeprom. (max of 3)
3594 * Description:
3595 * Actually writes the relevant part of the data value into the Eeprom
3596 * through the I2C bus.
3597 * Return value:
3598 * 0 on success, -1 on failure.
3599 */
3600
3601static int write_eeprom(nic_t * sp, int off, u32 data, int cnt)
3602{
3603 int exit_cnt = 0, ret = -1;
3604 u64 val64;
3605 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3606
3607 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
3608 I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA(data) |
3609 I2C_CONTROL_CNTL_START;
3610 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
3611
3612 while (exit_cnt < 5) {
3613 val64 = readq(&bar0->i2c_control);
3614 if (I2C_CONTROL_CNTL_END(val64)) {
3615 if (!(val64 & I2C_CONTROL_NACK))
3616 ret = 0;
3617 break;
3618 }
3619 msleep(50);
3620 exit_cnt++;
3621 }
3622
3623 return ret;
3624}
3625
3626/**
3627 * s2io_ethtool_geeprom - reads the value stored in the Eeprom.
3628 * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003629 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 * containing all relevant information.
3631 * @data_buf : user defined value to be written into Eeprom.
3632 * Description: Reads the values stored in the Eeprom at given offset
3633 * for a given length. Stores these values int the input argument data
3634 * buffer 'data_buf' and returns these to the caller (ethtool.)
3635 * Return value:
3636 * int 0 on success
3637 */
3638
3639static int s2io_ethtool_geeprom(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003640 struct ethtool_eeprom *eeprom, u8 * data_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641{
3642 u32 data, i, valid;
3643 nic_t *sp = dev->priv;
3644
3645 eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
3646
3647 if ((eeprom->offset + eeprom->len) > (XENA_EEPROM_SPACE))
3648 eeprom->len = XENA_EEPROM_SPACE - eeprom->offset;
3649
3650 for (i = 0; i < eeprom->len; i += 4) {
3651 if (read_eeprom(sp, (eeprom->offset + i), &data)) {
3652 DBG_PRINT(ERR_DBG, "Read of EEPROM failed\n");
3653 return -EFAULT;
3654 }
3655 valid = INV(data);
3656 memcpy((data_buf + i), &valid, 4);
3657 }
3658 return 0;
3659}
3660
3661/**
3662 * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom
3663 * @sp : private member of the device structure, which is a pointer to the
3664 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003665 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 * containing all relevant information.
3667 * @data_buf ; user defined value to be written into Eeprom.
3668 * Description:
3669 * Tries to write the user provided value in the Eeprom, at the offset
3670 * given by the user.
3671 * Return value:
3672 * 0 on success, -EFAULT on failure.
3673 */
3674
3675static int s2io_ethtool_seeprom(struct net_device *dev,
3676 struct ethtool_eeprom *eeprom,
3677 u8 * data_buf)
3678{
3679 int len = eeprom->len, cnt = 0;
3680 u32 valid = 0, data;
3681 nic_t *sp = dev->priv;
3682
3683 if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
3684 DBG_PRINT(ERR_DBG,
3685 "ETHTOOL_WRITE_EEPROM Err: Magic value ");
3686 DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n",
3687 eeprom->magic);
3688 return -EFAULT;
3689 }
3690
3691 while (len) {
3692 data = (u32) data_buf[cnt] & 0x000000FF;
3693 if (data) {
3694 valid = (u32) (data << 24);
3695 } else
3696 valid = data;
3697
3698 if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) {
3699 DBG_PRINT(ERR_DBG,
3700 "ETHTOOL_WRITE_EEPROM Err: Cannot ");
3701 DBG_PRINT(ERR_DBG,
3702 "write into the specified offset\n");
3703 return -EFAULT;
3704 }
3705 cnt++;
3706 len--;
3707 }
3708
3709 return 0;
3710}
3711
3712/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003713 * s2io_register_test - reads and writes into all clock domains.
3714 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 * s2io_nic structure.
3716 * @data : variable that returns the result of each of the test conducted b
3717 * by the driver.
3718 * Description:
3719 * Read and write into all clock domains. The NIC has 3 clock domains,
3720 * see that registers in all the three regions are accessible.
3721 * Return value:
3722 * 0 on success.
3723 */
3724
3725static int s2io_register_test(nic_t * sp, uint64_t * data)
3726{
3727 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3728 u64 val64 = 0;
3729 int fail = 0;
3730
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003731 val64 = readq(&bar0->pif_rd_swapper_fb);
3732 if (val64 != 0x123456789abcdefULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 fail = 1;
3734 DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n");
3735 }
3736
3737 val64 = readq(&bar0->rmac_pause_cfg);
3738 if (val64 != 0xc000ffff00000000ULL) {
3739 fail = 1;
3740 DBG_PRINT(INFO_DBG, "Read Test level 2 fails\n");
3741 }
3742
3743 val64 = readq(&bar0->rx_queue_cfg);
3744 if (val64 != 0x0808080808080808ULL) {
3745 fail = 1;
3746 DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n");
3747 }
3748
3749 val64 = readq(&bar0->xgxs_efifo_cfg);
3750 if (val64 != 0x000000001923141EULL) {
3751 fail = 1;
3752 DBG_PRINT(INFO_DBG, "Read Test level 4 fails\n");
3753 }
3754
3755 val64 = 0x5A5A5A5A5A5A5A5AULL;
3756 writeq(val64, &bar0->xmsi_data);
3757 val64 = readq(&bar0->xmsi_data);
3758 if (val64 != 0x5A5A5A5A5A5A5A5AULL) {
3759 fail = 1;
3760 DBG_PRINT(ERR_DBG, "Write Test level 1 fails\n");
3761 }
3762
3763 val64 = 0xA5A5A5A5A5A5A5A5ULL;
3764 writeq(val64, &bar0->xmsi_data);
3765 val64 = readq(&bar0->xmsi_data);
3766 if (val64 != 0xA5A5A5A5A5A5A5A5ULL) {
3767 fail = 1;
3768 DBG_PRINT(ERR_DBG, "Write Test level 2 fails\n");
3769 }
3770
3771 *data = fail;
3772 return 0;
3773}
3774
3775/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003776 * s2io_eeprom_test - to verify that EEprom in the xena can be programmed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 * @sp : private member of the device structure, which is a pointer to the
3778 * s2io_nic structure.
3779 * @data:variable that returns the result of each of the test conducted by
3780 * the driver.
3781 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003782 * Verify that EEPROM in the xena can be programmed using I2C_CONTROL
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 * register.
3784 * Return value:
3785 * 0 on success.
3786 */
3787
3788static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
3789{
3790 int fail = 0;
3791 u32 ret_data;
3792
3793 /* Test Write Error at offset 0 */
3794 if (!write_eeprom(sp, 0, 0, 3))
3795 fail = 1;
3796
3797 /* Test Write at offset 4f0 */
3798 if (write_eeprom(sp, 0x4F0, 0x01234567, 3))
3799 fail = 1;
3800 if (read_eeprom(sp, 0x4F0, &ret_data))
3801 fail = 1;
3802
3803 if (ret_data != 0x01234567)
3804 fail = 1;
3805
3806 /* Reset the EEPROM data go FFFF */
3807 write_eeprom(sp, 0x4F0, 0xFFFFFFFF, 3);
3808
3809 /* Test Write Request Error at offset 0x7c */
3810 if (!write_eeprom(sp, 0x07C, 0, 3))
3811 fail = 1;
3812
3813 /* Test Write Request at offset 0x7fc */
3814 if (write_eeprom(sp, 0x7FC, 0x01234567, 3))
3815 fail = 1;
3816 if (read_eeprom(sp, 0x7FC, &ret_data))
3817 fail = 1;
3818
3819 if (ret_data != 0x01234567)
3820 fail = 1;
3821
3822 /* Reset the EEPROM data go FFFF */
3823 write_eeprom(sp, 0x7FC, 0xFFFFFFFF, 3);
3824
3825 /* Test Write Error at offset 0x80 */
3826 if (!write_eeprom(sp, 0x080, 0, 3))
3827 fail = 1;
3828
3829 /* Test Write Error at offset 0xfc */
3830 if (!write_eeprom(sp, 0x0FC, 0, 3))
3831 fail = 1;
3832
3833 /* Test Write Error at offset 0x100 */
3834 if (!write_eeprom(sp, 0x100, 0, 3))
3835 fail = 1;
3836
3837 /* Test Write Error at offset 4ec */
3838 if (!write_eeprom(sp, 0x4EC, 0, 3))
3839 fail = 1;
3840
3841 *data = fail;
3842 return 0;
3843}
3844
3845/**
3846 * s2io_bist_test - invokes the MemBist test of the card .
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003847 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003849 * @data:variable that returns the result of each of the test conducted by
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 * the driver.
3851 * Description:
3852 * This invokes the MemBist test of the card. We give around
3853 * 2 secs time for the Test to complete. If it's still not complete
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003854 * within this peiod, we consider that the test failed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 * Return value:
3856 * 0 on success and -1 on failure.
3857 */
3858
3859static int s2io_bist_test(nic_t * sp, uint64_t * data)
3860{
3861 u8 bist = 0;
3862 int cnt = 0, ret = -1;
3863
3864 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
3865 bist |= PCI_BIST_START;
3866 pci_write_config_word(sp->pdev, PCI_BIST, bist);
3867
3868 while (cnt < 20) {
3869 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
3870 if (!(bist & PCI_BIST_START)) {
3871 *data = (bist & PCI_BIST_CODE_MASK);
3872 ret = 0;
3873 break;
3874 }
3875 msleep(100);
3876 cnt++;
3877 }
3878
3879 return ret;
3880}
3881
3882/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003883 * s2io-link_test - verifies the link state of the nic
3884 * @sp ; private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 * s2io_nic structure.
3886 * @data: variable that returns the result of each of the test conducted by
3887 * the driver.
3888 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003889 * The function verifies the link state of the NIC and updates the input
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 * argument 'data' appropriately.
3891 * Return value:
3892 * 0 on success.
3893 */
3894
3895static int s2io_link_test(nic_t * sp, uint64_t * data)
3896{
3897 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3898 u64 val64;
3899
3900 val64 = readq(&bar0->adapter_status);
3901 if (val64 & ADAPTER_STATUS_RMAC_LOCAL_FAULT)
3902 *data = 1;
3903
3904 return 0;
3905}
3906
3907/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003908 * s2io_rldram_test - offline test for access to the RldRam chip on the NIC
3909 * @sp - private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003911 * @data - variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 * conducted by the driver.
3913 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003914 * This is one of the offline test that tests the read and write
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 * access to the RldRam chip on the NIC.
3916 * Return value:
3917 * 0 on success.
3918 */
3919
3920static int s2io_rldram_test(nic_t * sp, uint64_t * data)
3921{
3922 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3923 u64 val64;
3924 int cnt, iteration = 0, test_pass = 0;
3925
3926 val64 = readq(&bar0->adapter_control);
3927 val64 &= ~ADAPTER_ECC_EN;
3928 writeq(val64, &bar0->adapter_control);
3929
3930 val64 = readq(&bar0->mc_rldram_test_ctrl);
3931 val64 |= MC_RLDRAM_TEST_MODE;
3932 writeq(val64, &bar0->mc_rldram_test_ctrl);
3933
3934 val64 = readq(&bar0->mc_rldram_mrs);
3935 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE;
3936 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
3937
3938 val64 |= MC_RLDRAM_MRS_ENABLE;
3939 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
3940
3941 while (iteration < 2) {
3942 val64 = 0x55555555aaaa0000ULL;
3943 if (iteration == 1) {
3944 val64 ^= 0xFFFFFFFFFFFF0000ULL;
3945 }
3946 writeq(val64, &bar0->mc_rldram_test_d0);
3947
3948 val64 = 0xaaaa5a5555550000ULL;
3949 if (iteration == 1) {
3950 val64 ^= 0xFFFFFFFFFFFF0000ULL;
3951 }
3952 writeq(val64, &bar0->mc_rldram_test_d1);
3953
3954 val64 = 0x55aaaaaaaa5a0000ULL;
3955 if (iteration == 1) {
3956 val64 ^= 0xFFFFFFFFFFFF0000ULL;
3957 }
3958 writeq(val64, &bar0->mc_rldram_test_d2);
3959
3960 val64 = (u64) (0x0000003fffff0000ULL);
3961 writeq(val64, &bar0->mc_rldram_test_add);
3962
3963
3964 val64 = MC_RLDRAM_TEST_MODE;
3965 writeq(val64, &bar0->mc_rldram_test_ctrl);
3966
3967 val64 |=
3968 MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE |
3969 MC_RLDRAM_TEST_GO;
3970 writeq(val64, &bar0->mc_rldram_test_ctrl);
3971
3972 for (cnt = 0; cnt < 5; cnt++) {
3973 val64 = readq(&bar0->mc_rldram_test_ctrl);
3974 if (val64 & MC_RLDRAM_TEST_DONE)
3975 break;
3976 msleep(200);
3977 }
3978
3979 if (cnt == 5)
3980 break;
3981
3982 val64 = MC_RLDRAM_TEST_MODE;
3983 writeq(val64, &bar0->mc_rldram_test_ctrl);
3984
3985 val64 |= MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO;
3986 writeq(val64, &bar0->mc_rldram_test_ctrl);
3987
3988 for (cnt = 0; cnt < 5; cnt++) {
3989 val64 = readq(&bar0->mc_rldram_test_ctrl);
3990 if (val64 & MC_RLDRAM_TEST_DONE)
3991 break;
3992 msleep(500);
3993 }
3994
3995 if (cnt == 5)
3996 break;
3997
3998 val64 = readq(&bar0->mc_rldram_test_ctrl);
3999 if (val64 & MC_RLDRAM_TEST_PASS)
4000 test_pass = 1;
4001
4002 iteration++;
4003 }
4004
4005 if (!test_pass)
4006 *data = 1;
4007 else
4008 *data = 0;
4009
4010 return 0;
4011}
4012
4013/**
4014 * s2io_ethtool_test - conducts 6 tsets to determine the health of card.
4015 * @sp : private member of the device structure, which is a pointer to the
4016 * s2io_nic structure.
4017 * @ethtest : pointer to a ethtool command specific structure that will be
4018 * returned to the user.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004019 * @data : variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 * conducted by the driver.
4021 * Description:
4022 * This function conducts 6 tests ( 4 offline and 2 online) to determine
4023 * the health of the card.
4024 * Return value:
4025 * void
4026 */
4027
4028static void s2io_ethtool_test(struct net_device *dev,
4029 struct ethtool_test *ethtest,
4030 uint64_t * data)
4031{
4032 nic_t *sp = dev->priv;
4033 int orig_state = netif_running(sp->dev);
4034
4035 if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
4036 /* Offline Tests. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004037 if (orig_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 s2io_close(sp->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039
4040 if (s2io_register_test(sp, &data[0]))
4041 ethtest->flags |= ETH_TEST_FL_FAILED;
4042
4043 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044
4045 if (s2io_rldram_test(sp, &data[3]))
4046 ethtest->flags |= ETH_TEST_FL_FAILED;
4047
4048 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049
4050 if (s2io_eeprom_test(sp, &data[1]))
4051 ethtest->flags |= ETH_TEST_FL_FAILED;
4052
4053 if (s2io_bist_test(sp, &data[4]))
4054 ethtest->flags |= ETH_TEST_FL_FAILED;
4055
4056 if (orig_state)
4057 s2io_open(sp->dev);
4058
4059 data[2] = 0;
4060 } else {
4061 /* Online Tests. */
4062 if (!orig_state) {
4063 DBG_PRINT(ERR_DBG,
4064 "%s: is not up, cannot run test\n",
4065 dev->name);
4066 data[0] = -1;
4067 data[1] = -1;
4068 data[2] = -1;
4069 data[3] = -1;
4070 data[4] = -1;
4071 }
4072
4073 if (s2io_link_test(sp, &data[2]))
4074 ethtest->flags |= ETH_TEST_FL_FAILED;
4075
4076 data[0] = 0;
4077 data[1] = 0;
4078 data[3] = 0;
4079 data[4] = 0;
4080 }
4081}
4082
4083static void s2io_get_ethtool_stats(struct net_device *dev,
4084 struct ethtool_stats *estats,
4085 u64 * tmp_stats)
4086{
4087 int i = 0;
4088 nic_t *sp = dev->priv;
4089 StatInfo_t *stat_info = sp->mac_control.stats_info;
4090
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004091 s2io_updt_stats(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092 tmp_stats[i++] = le32_to_cpu(stat_info->tmac_frms);
4093 tmp_stats[i++] = le32_to_cpu(stat_info->tmac_data_octets);
4094 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms);
4095 tmp_stats[i++] = le32_to_cpu(stat_info->tmac_mcst_frms);
4096 tmp_stats[i++] = le32_to_cpu(stat_info->tmac_bcst_frms);
4097 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms);
4098 tmp_stats[i++] = le32_to_cpu(stat_info->tmac_any_err_frms);
4099 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets);
4100 tmp_stats[i++] = le32_to_cpu(stat_info->tmac_vld_ip);
4101 tmp_stats[i++] = le32_to_cpu(stat_info->tmac_drop_ip);
4102 tmp_stats[i++] = le32_to_cpu(stat_info->tmac_icmp);
4103 tmp_stats[i++] = le32_to_cpu(stat_info->tmac_rst_tcp);
4104 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp);
4105 tmp_stats[i++] = le32_to_cpu(stat_info->tmac_udp);
4106 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_frms);
4107 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_data_octets);
4108 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms);
4109 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms);
4110 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_mcst_frms);
4111 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_bcst_frms);
4112 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms);
4113 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms);
4114 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms);
4115 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_discarded_frms);
4116 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_usized_frms);
4117 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_osized_frms);
4118 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_frag_frms);
4119 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_jabber_frms);
4120 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ip);
4121 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets);
4122 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip);
4123 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_drop_ip);
4124 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_icmp);
4125 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp);
4126 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_udp);
4127 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_drp_udp);
4128 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pause_cnt);
4129 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_accepted_ip);
4130 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004131 tmp_stats[i++] = 0;
4132 tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
4133 tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134}
4135
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004136int s2io_ethtool_get_regs_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137{
4138 return (XENA_REG_SPACE);
4139}
4140
4141
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004142u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143{
4144 nic_t *sp = dev->priv;
4145
4146 return (sp->rx_csum);
4147}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004148int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149{
4150 nic_t *sp = dev->priv;
4151
4152 if (data)
4153 sp->rx_csum = 1;
4154 else
4155 sp->rx_csum = 0;
4156
4157 return 0;
4158}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004159int s2io_get_eeprom_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160{
4161 return (XENA_EEPROM_SPACE);
4162}
4163
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004164int s2io_ethtool_self_test_count(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165{
4166 return (S2IO_TEST_LEN);
4167}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004168void s2io_ethtool_get_strings(struct net_device *dev,
4169 u32 stringset, u8 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170{
4171 switch (stringset) {
4172 case ETH_SS_TEST:
4173 memcpy(data, s2io_gstrings, S2IO_STRINGS_LEN);
4174 break;
4175 case ETH_SS_STATS:
4176 memcpy(data, &ethtool_stats_keys,
4177 sizeof(ethtool_stats_keys));
4178 }
4179}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180static int s2io_ethtool_get_stats_count(struct net_device *dev)
4181{
4182 return (S2IO_STAT_LEN);
4183}
4184
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004185int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186{
4187 if (data)
4188 dev->features |= NETIF_F_IP_CSUM;
4189 else
4190 dev->features &= ~NETIF_F_IP_CSUM;
4191
4192 return 0;
4193}
4194
4195
4196static struct ethtool_ops netdev_ethtool_ops = {
4197 .get_settings = s2io_ethtool_gset,
4198 .set_settings = s2io_ethtool_sset,
4199 .get_drvinfo = s2io_ethtool_gdrvinfo,
4200 .get_regs_len = s2io_ethtool_get_regs_len,
4201 .get_regs = s2io_ethtool_gregs,
4202 .get_link = ethtool_op_get_link,
4203 .get_eeprom_len = s2io_get_eeprom_len,
4204 .get_eeprom = s2io_ethtool_geeprom,
4205 .set_eeprom = s2io_ethtool_seeprom,
4206 .get_pauseparam = s2io_ethtool_getpause_data,
4207 .set_pauseparam = s2io_ethtool_setpause_data,
4208 .get_rx_csum = s2io_ethtool_get_rx_csum,
4209 .set_rx_csum = s2io_ethtool_set_rx_csum,
4210 .get_tx_csum = ethtool_op_get_tx_csum,
4211 .set_tx_csum = s2io_ethtool_op_set_tx_csum,
4212 .get_sg = ethtool_op_get_sg,
4213 .set_sg = ethtool_op_set_sg,
4214#ifdef NETIF_F_TSO
4215 .get_tso = ethtool_op_get_tso,
4216 .set_tso = ethtool_op_set_tso,
4217#endif
4218 .self_test_count = s2io_ethtool_self_test_count,
4219 .self_test = s2io_ethtool_test,
4220 .get_strings = s2io_ethtool_get_strings,
4221 .phys_id = s2io_ethtool_idnic,
4222 .get_stats_count = s2io_ethtool_get_stats_count,
4223 .get_ethtool_stats = s2io_get_ethtool_stats
4224};
4225
4226/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004227 * s2io_ioctl - Entry point for the Ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 * @dev : Device pointer.
4229 * @ifr : An IOCTL specefic structure, that can contain a pointer to
4230 * a proprietary structure used to pass information to the driver.
4231 * @cmd : This is used to distinguish between the different commands that
4232 * can be passed to the IOCTL functions.
4233 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004234 * Currently there are no special functionality supported in IOCTL, hence
4235 * function always return EOPNOTSUPPORTED
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 */
4237
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004238int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239{
4240 return -EOPNOTSUPP;
4241}
4242
4243/**
4244 * s2io_change_mtu - entry point to change MTU size for the device.
4245 * @dev : device pointer.
4246 * @new_mtu : the new MTU size for the device.
4247 * Description: A driver entry point to change MTU size for the device.
4248 * Before changing the MTU the device must be stopped.
4249 * Return value:
4250 * 0 on success and an appropriate (-)ve integer as defined in errno.h
4251 * file on failure.
4252 */
4253
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004254int s2io_change_mtu(struct net_device *dev, int new_mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255{
4256 nic_t *sp = dev->priv;
4257 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4258 register u64 val64;
4259
4260 if (netif_running(dev)) {
4261 DBG_PRINT(ERR_DBG, "%s: Must be stopped to ", dev->name);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004262 DBG_PRINT(ERR_DBG, "change its MTU\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 return -EBUSY;
4264 }
4265
4266 if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
4267 DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
4268 dev->name);
4269 return -EPERM;
4270 }
4271
4272 /* Set the new MTU into the PYLD register of the NIC */
4273 val64 = new_mtu;
4274 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
4275
4276 dev->mtu = new_mtu;
4277
4278 return 0;
4279}
4280
4281/**
4282 * s2io_tasklet - Bottom half of the ISR.
4283 * @dev_adr : address of the device structure in dma_addr_t format.
4284 * Description:
4285 * This is the tasklet or the bottom half of the ISR. This is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004286 * an extension of the ISR which is scheduled by the scheduler to be run
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 * when the load on the CPU is low. All low priority tasks of the ISR can
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004288 * be pushed into the tasklet. For now the tasklet is used only to
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 * replenish the Rx buffers in the Rx buffer descriptors.
4290 * Return value:
4291 * void.
4292 */
4293
4294static void s2io_tasklet(unsigned long dev_addr)
4295{
4296 struct net_device *dev = (struct net_device *) dev_addr;
4297 nic_t *sp = dev->priv;
4298 int i, ret;
4299 mac_info_t *mac_control;
4300 struct config_param *config;
4301
4302 mac_control = &sp->mac_control;
4303 config = &sp->config;
4304
4305 if (!TASKLET_IN_USE) {
4306 for (i = 0; i < config->rx_ring_num; i++) {
4307 ret = fill_rx_buffers(sp, i);
4308 if (ret == -ENOMEM) {
4309 DBG_PRINT(ERR_DBG, "%s: Out of ",
4310 dev->name);
4311 DBG_PRINT(ERR_DBG, "memory in tasklet\n");
4312 break;
4313 } else if (ret == -EFILL) {
4314 DBG_PRINT(ERR_DBG,
4315 "%s: Rx Ring %d is full\n",
4316 dev->name, i);
4317 break;
4318 }
4319 }
4320 clear_bit(0, (&sp->tasklet_status));
4321 }
4322}
4323
4324/**
4325 * s2io_set_link - Set the LInk status
4326 * @data: long pointer to device private structue
4327 * Description: Sets the link status for the adapter
4328 */
4329
4330static void s2io_set_link(unsigned long data)
4331{
4332 nic_t *nic = (nic_t *) data;
4333 struct net_device *dev = nic->dev;
4334 XENA_dev_config_t __iomem *bar0 = nic->bar0;
4335 register u64 val64;
4336 u16 subid;
4337
4338 if (test_and_set_bit(0, &(nic->link_state))) {
4339 /* The card is being reset, no point doing anything */
4340 return;
4341 }
4342
4343 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004344 /*
4345 * Allow a small delay for the NICs self initiated
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 * cleanup to complete.
4347 */
4348 msleep(100);
4349
4350 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004351 if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 if (LINK_IS_UP(val64)) {
4353 val64 = readq(&bar0->adapter_control);
4354 val64 |= ADAPTER_CNTL_EN;
4355 writeq(val64, &bar0->adapter_control);
4356 if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) {
4357 val64 = readq(&bar0->gpio_control);
4358 val64 |= GPIO_CTRL_GPIO_0;
4359 writeq(val64, &bar0->gpio_control);
4360 val64 = readq(&bar0->gpio_control);
4361 } else {
4362 val64 |= ADAPTER_LED_ON;
4363 writeq(val64, &bar0->adapter_control);
4364 }
4365 val64 = readq(&bar0->adapter_status);
4366 if (!LINK_IS_UP(val64)) {
4367 DBG_PRINT(ERR_DBG, "%s:", dev->name);
4368 DBG_PRINT(ERR_DBG, " Link down");
4369 DBG_PRINT(ERR_DBG, "after ");
4370 DBG_PRINT(ERR_DBG, "enabling ");
4371 DBG_PRINT(ERR_DBG, "device \n");
4372 }
4373 if (nic->device_enabled_once == FALSE) {
4374 nic->device_enabled_once = TRUE;
4375 }
4376 s2io_link(nic, LINK_UP);
4377 } else {
4378 if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) {
4379 val64 = readq(&bar0->gpio_control);
4380 val64 &= ~GPIO_CTRL_GPIO_0;
4381 writeq(val64, &bar0->gpio_control);
4382 val64 = readq(&bar0->gpio_control);
4383 }
4384 s2io_link(nic, LINK_DOWN);
4385 }
4386 } else { /* NIC is not Quiescent. */
4387 DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
4388 DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
4389 netif_stop_queue(dev);
4390 }
4391 clear_bit(0, &(nic->link_state));
4392}
4393
4394static void s2io_card_down(nic_t * sp)
4395{
4396 int cnt = 0;
4397 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4398 unsigned long flags;
4399 register u64 val64 = 0;
4400
4401 /* If s2io_set_link task is executing, wait till it completes. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004402 while (test_and_set_bit(0, &(sp->link_state))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 msleep(50);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 atomic_set(&sp->card_state, CARD_DOWN);
4406
4407 /* disable Tx and Rx traffic on the NIC */
4408 stop_nic(sp);
4409
4410 /* Kill tasklet. */
4411 tasklet_kill(&sp->task);
4412
4413 /* Check if the device is Quiescent and then Reset the NIC */
4414 do {
4415 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004416 if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 break;
4418 }
4419
4420 msleep(50);
4421 cnt++;
4422 if (cnt == 10) {
4423 DBG_PRINT(ERR_DBG,
4424 "s2io_close:Device not Quiescent ");
4425 DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n",
4426 (unsigned long long) val64);
4427 break;
4428 }
4429 } while (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 s2io_reset(sp);
4431
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004432 /* Waiting till all Interrupt handlers are complete */
4433 cnt = 0;
4434 do {
4435 msleep(10);
4436 if (!atomic_read(&sp->isr_cnt))
4437 break;
4438 cnt++;
4439 } while(cnt < 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004441 spin_lock_irqsave(&sp->tx_lock, flags);
4442 /* Free all Tx buffers */
4443 free_tx_buffers(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004445
4446 /* Free all Rx buffers */
4447 spin_lock_irqsave(&sp->rx_lock, flags);
4448 free_rx_buffers(sp);
4449 spin_unlock_irqrestore(&sp->rx_lock, flags);
4450
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 clear_bit(0, &(sp->link_state));
4452}
4453
4454static int s2io_card_up(nic_t * sp)
4455{
4456 int i, ret;
4457 mac_info_t *mac_control;
4458 struct config_param *config;
4459 struct net_device *dev = (struct net_device *) sp->dev;
4460
4461 /* Initialize the H/W I/O registers */
4462 if (init_nic(sp) != 0) {
4463 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
4464 dev->name);
4465 return -ENODEV;
4466 }
4467
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004468 /*
4469 * Initializing the Rx buffers. For now we are considering only 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 * Rx ring and initializing buffers into 30 Rx blocks
4471 */
4472 mac_control = &sp->mac_control;
4473 config = &sp->config;
4474
4475 for (i = 0; i < config->rx_ring_num; i++) {
4476 if ((ret = fill_rx_buffers(sp, i))) {
4477 DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
4478 dev->name);
4479 s2io_reset(sp);
4480 free_rx_buffers(sp);
4481 return -ENOMEM;
4482 }
4483 DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
4484 atomic_read(&sp->rx_bufs_left[i]));
4485 }
4486
4487 /* Setting its receive mode */
4488 s2io_set_multicast(dev);
4489
4490 /* Enable tasklet for the device */
4491 tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
4492
4493 /* Enable Rx Traffic and interrupts on the NIC */
4494 if (start_nic(sp)) {
4495 DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
4496 tasklet_kill(&sp->task);
4497 s2io_reset(sp);
4498 free_irq(dev->irq, dev);
4499 free_rx_buffers(sp);
4500 return -ENODEV;
4501 }
4502
4503 atomic_set(&sp->card_state, CARD_UP);
4504 return 0;
4505}
4506
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004507/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 * s2io_restart_nic - Resets the NIC.
4509 * @data : long pointer to the device private structure
4510 * Description:
4511 * This function is scheduled to be run by the s2io_tx_watchdog
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004512 * function after 0.5 secs to reset the NIC. The idea is to reduce
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 * the run time of the watch dog routine which is run holding a
4514 * spin lock.
4515 */
4516
4517static void s2io_restart_nic(unsigned long data)
4518{
4519 struct net_device *dev = (struct net_device *) data;
4520 nic_t *sp = dev->priv;
4521
4522 s2io_card_down(sp);
4523 if (s2io_card_up(sp)) {
4524 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
4525 dev->name);
4526 }
4527 netif_wake_queue(dev);
4528 DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
4529 dev->name);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004530
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531}
4532
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004533/**
4534 * s2io_tx_watchdog - Watchdog for transmit side.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 * @dev : Pointer to net device structure
4536 * Description:
4537 * This function is triggered if the Tx Queue is stopped
4538 * for a pre-defined amount of time when the Interface is still up.
4539 * If the Interface is jammed in such a situation, the hardware is
4540 * reset (by s2io_close) and restarted again (by s2io_open) to
4541 * overcome any problem that might have been caused in the hardware.
4542 * Return value:
4543 * void
4544 */
4545
4546static void s2io_tx_watchdog(struct net_device *dev)
4547{
4548 nic_t *sp = dev->priv;
4549
4550 if (netif_carrier_ok(dev)) {
4551 schedule_work(&sp->rst_timer_task);
4552 }
4553}
4554
4555/**
4556 * rx_osm_handler - To perform some OS related operations on SKB.
4557 * @sp: private member of the device structure,pointer to s2io_nic structure.
4558 * @skb : the socket buffer pointer.
4559 * @len : length of the packet
4560 * @cksum : FCS checksum of the frame.
4561 * @ring_no : the ring from which this RxD was extracted.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004562 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 * This function is called by the Tx interrupt serivce routine to perform
4564 * some OS related operations on the SKB before passing it to the upper
4565 * layers. It mainly checks if the checksum is OK, if so adds it to the
4566 * SKBs cksum variable, increments the Rx packet count and passes the SKB
4567 * to the upper layer. If the checksum is wrong, it increments the Rx
4568 * packet error count, frees the SKB and returns error.
4569 * Return value:
4570 * SUCCESS on success and -1 on failure.
4571 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004572static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004574 nic_t *sp = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 struct net_device *dev = (struct net_device *) sp->dev;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004576 struct sk_buff *skb = (struct sk_buff *)
4577 ((unsigned long) rxdp->Host_Control);
4578 int ring_no = ring_data->ring_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 u16 l3_csum, l4_csum;
4580#ifdef CONFIG_2BUFF_MODE
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004581 int buf0_len = RXD_GET_BUFFER0_SIZE(rxdp->Control_2);
4582 int buf2_len = RXD_GET_BUFFER2_SIZE(rxdp->Control_2);
4583 int get_block = ring_data->rx_curr_get_info.block_index;
4584 int get_off = ring_data->rx_curr_get_info.offset;
4585 buffAdd_t *ba = &ring_data->ba[get_block][get_off];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 unsigned char *buff;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004587#else
4588 u16 len = (u16) ((RXD_GET_BUFFER0_SIZE(rxdp->Control_2)) >> 48);;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589#endif
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004590 skb->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 if (rxdp->Control_1 & RXD_T_CODE) {
4592 unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
4593 DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
4594 dev->name, err);
raghavendra.koushik@neterion.com1ddc50d2005-08-03 12:30:43 -07004595 dev_kfree_skb(skb);
4596 sp->stats.rx_crc_errors++;
4597 atomic_dec(&sp->rx_bufs_left[ring_no]);
4598 rxdp->Host_Control = 0;
4599 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004602 /* Updating statistics */
4603 rxdp->Host_Control = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604 sp->rx_pkt_count++;
4605 sp->stats.rx_packets++;
4606#ifndef CONFIG_2BUFF_MODE
4607 sp->stats.rx_bytes += len;
4608#else
4609 sp->stats.rx_bytes += buf0_len + buf2_len;
4610#endif
4611
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004612#ifndef CONFIG_2BUFF_MODE
4613 skb_put(skb, len);
4614#else
4615 buff = skb_push(skb, buf0_len);
4616 memcpy(buff, ba->ba_0, buf0_len);
4617 skb_put(skb, buf2_len);
4618#endif
4619
4620 if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) &&
4621 (sp->rx_csum)) {
4622 l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
4623 l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
4624 if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) {
4625 /*
4626 * NIC verifies if the Checksum of the received
4627 * frame is Ok or not and accordingly returns
4628 * a flag in the RxD.
4629 */
4630 skb->ip_summed = CHECKSUM_UNNECESSARY;
4631 } else {
4632 /*
4633 * Packet with erroneous checksum, let the
4634 * upper layers deal with it.
4635 */
4636 skb->ip_summed = CHECKSUM_NONE;
4637 }
4638 } else {
4639 skb->ip_summed = CHECKSUM_NONE;
4640 }
4641
4642 skb->protocol = eth_type_trans(skb, dev);
4643#ifdef CONFIG_S2IO_NAPI
4644 netif_receive_skb(skb);
4645#else
4646 netif_rx(skb);
4647#endif
4648 dev->last_rx = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 atomic_dec(&sp->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 return SUCCESS;
4651}
4652
4653/**
4654 * s2io_link - stops/starts the Tx queue.
4655 * @sp : private member of the device structure, which is a pointer to the
4656 * s2io_nic structure.
4657 * @link : inidicates whether link is UP/DOWN.
4658 * Description:
4659 * This function stops/starts the Tx queue depending on whether the link
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004660 * status of the NIC is is down or up. This is called by the Alarm
4661 * interrupt handler whenever a link change interrupt comes up.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 * Return value:
4663 * void.
4664 */
4665
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004666void s2io_link(nic_t * sp, int link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667{
4668 struct net_device *dev = (struct net_device *) sp->dev;
4669
4670 if (link != sp->last_link_state) {
4671 if (link == LINK_DOWN) {
4672 DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
4673 netif_carrier_off(dev);
4674 } else {
4675 DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
4676 netif_carrier_on(dev);
4677 }
4678 }
4679 sp->last_link_state = link;
4680}
4681
4682/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004683 * get_xena_rev_id - to identify revision ID of xena.
4684 * @pdev : PCI Dev structure
4685 * Description:
4686 * Function to identify the Revision ID of xena.
4687 * Return value:
4688 * returns the revision ID of the device.
4689 */
4690
4691int get_xena_rev_id(struct pci_dev *pdev)
4692{
4693 u8 id = 0;
4694 int ret;
4695 ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id);
4696 return id;
4697}
4698
4699/**
4700 * s2io_init_pci -Initialization of PCI and PCI-X configuration registers .
4701 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 * s2io_nic structure.
4703 * Description:
4704 * This function initializes a few of the PCI and PCI-X configuration registers
4705 * with recommended values.
4706 * Return value:
4707 * void
4708 */
4709
4710static void s2io_init_pci(nic_t * sp)
4711{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004712 u16 pci_cmd = 0, pcix_cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713
4714 /* Enable Data Parity Error Recovery in PCI-X command register. */
4715 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004716 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004718 (pcix_cmd | 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004720 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721
4722 /* Set the PErr Response bit in PCI command register. */
4723 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
4724 pci_write_config_word(sp->pdev, PCI_COMMAND,
4725 (pci_cmd | PCI_COMMAND_PARITY));
4726 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
4727
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728 /* Forcibly disabling relaxed ordering capability of the card. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004729 pcix_cmd &= 0xfffd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004731 pcix_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004733 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734}
4735
4736MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
4737MODULE_LICENSE("GPL");
4738module_param(tx_fifo_num, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739module_param(rx_ring_num, int, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004740module_param_array(tx_fifo_len, uint, NULL, 0);
4741module_param_array(rx_ring_sz, uint, NULL, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004742module_param_array(rts_frm_len, uint, NULL, 0);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07004743module_param(use_continuous_tx_intrs, int, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744module_param(rmac_pause_time, int, 0);
4745module_param(mc_pause_threshold_q0q3, int, 0);
4746module_param(mc_pause_threshold_q4q7, int, 0);
4747module_param(shared_splits, int, 0);
4748module_param(tmac_util_period, int, 0);
4749module_param(rmac_util_period, int, 0);
4750#ifndef CONFIG_S2IO_NAPI
4751module_param(indicate_max_pkts, int, 0);
4752#endif
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004753
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004755 * s2io_init_nic - Initialization of the adapter .
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 * @pdev : structure containing the PCI related information of the device.
4757 * @pre: List of PCI devices supported by the driver listed in s2io_tbl.
4758 * Description:
4759 * The function initializes an adapter identified by the pci_dec structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004760 * All OS related initialization including memory and device structure and
4761 * initlaization of the device private variable is done. Also the swapper
4762 * control register is initialized to enable read and write into the I/O
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 * registers of the device.
4764 * Return value:
4765 * returns 0 on success and negative on failure.
4766 */
4767
4768static int __devinit
4769s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
4770{
4771 nic_t *sp;
4772 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 int i, j, ret;
4774 int dma_flag = FALSE;
4775 u32 mac_up, mac_down;
4776 u64 val64 = 0, tmp64 = 0;
4777 XENA_dev_config_t __iomem *bar0 = NULL;
4778 u16 subid;
4779 mac_info_t *mac_control;
4780 struct config_param *config;
4781
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004782#ifdef CONFIG_S2IO_NAPI
4783 DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n");
4784#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785
4786 if ((ret = pci_enable_device(pdev))) {
4787 DBG_PRINT(ERR_DBG,
4788 "s2io_init_nic: pci_enable_device failed\n");
4789 return ret;
4790 }
4791
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04004792 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
4794 dma_flag = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 if (pci_set_consistent_dma_mask
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04004796 (pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 DBG_PRINT(ERR_DBG,
4798 "Unable to obtain 64bit DMA for \
4799 consistent allocations\n");
4800 pci_disable_device(pdev);
4801 return -ENOMEM;
4802 }
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04004803 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n");
4805 } else {
4806 pci_disable_device(pdev);
4807 return -ENOMEM;
4808 }
4809
4810 if (pci_request_regions(pdev, s2io_driver_name)) {
4811 DBG_PRINT(ERR_DBG, "Request Regions failed\n"),
4812 pci_disable_device(pdev);
4813 return -ENODEV;
4814 }
4815
4816 dev = alloc_etherdev(sizeof(nic_t));
4817 if (dev == NULL) {
4818 DBG_PRINT(ERR_DBG, "Device allocation failed\n");
4819 pci_disable_device(pdev);
4820 pci_release_regions(pdev);
4821 return -ENODEV;
4822 }
4823
4824 pci_set_master(pdev);
4825 pci_set_drvdata(pdev, dev);
4826 SET_MODULE_OWNER(dev);
4827 SET_NETDEV_DEV(dev, &pdev->dev);
4828
4829 /* Private member variable initialized to s2io NIC structure */
4830 sp = dev->priv;
4831 memset(sp, 0, sizeof(nic_t));
4832 sp->dev = dev;
4833 sp->pdev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 sp->high_dma_flag = dma_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 sp->device_enabled_once = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836
4837 /* Initialize some PCI/PCI-X fields of the NIC. */
4838 s2io_init_pci(sp);
4839
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004840 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 * Setting the device configuration parameters.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004842 * Most of these parameters can be specified by the user during
4843 * module insertion as they are module loadable parameters. If
4844 * these parameters are not not specified during load time, they
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 * are initialized with default values.
4846 */
4847 mac_control = &sp->mac_control;
4848 config = &sp->config;
4849
4850 /* Tx side parameters. */
4851 tx_fifo_len[0] = DEFAULT_FIFO_LEN; /* Default value. */
4852 config->tx_fifo_num = tx_fifo_num;
4853 for (i = 0; i < MAX_TX_FIFOS; i++) {
4854 config->tx_cfg[i].fifo_len = tx_fifo_len[i];
4855 config->tx_cfg[i].fifo_priority = i;
4856 }
4857
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004858 /* mapping the QoS priority to the configured fifos */
4859 for (i = 0; i < MAX_TX_FIFOS; i++)
4860 config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i];
4861
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 config->tx_intr_type = TXD_INT_TYPE_UTILZ;
4863 for (i = 0; i < config->tx_fifo_num; i++) {
4864 config->tx_cfg[i].f_no_snoop =
4865 (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER);
4866 if (config->tx_cfg[i].fifo_len < 65) {
4867 config->tx_intr_type = TXD_INT_TYPE_PER_LIST;
4868 break;
4869 }
4870 }
4871 config->max_txds = MAX_SKB_FRAGS;
4872
4873 /* Rx side parameters. */
4874 rx_ring_sz[0] = SMALL_BLK_CNT; /* Default value. */
4875 config->rx_ring_num = rx_ring_num;
4876 for (i = 0; i < MAX_RX_RINGS; i++) {
4877 config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
4878 (MAX_RXDS_PER_BLOCK + 1);
4879 config->rx_cfg[i].ring_priority = i;
4880 }
4881
4882 for (i = 0; i < rx_ring_num; i++) {
4883 config->rx_cfg[i].ring_org = RING_ORG_BUFF1;
4884 config->rx_cfg[i].f_no_snoop =
4885 (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER);
4886 }
4887
4888 /* Setting Mac Control parameters */
4889 mac_control->rmac_pause_time = rmac_pause_time;
4890 mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3;
4891 mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
4892
4893
4894 /* Initialize Ring buffer parameters. */
4895 for (i = 0; i < config->rx_ring_num; i++)
4896 atomic_set(&sp->rx_bufs_left[i], 0);
4897
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004898 /* Initialize the number of ISRs currently running */
4899 atomic_set(&sp->isr_cnt, 0);
4900
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 /* initialize the shared memory used by the NIC and the host */
4902 if (init_shared_mem(sp)) {
4903 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
4904 dev->name);
4905 ret = -ENOMEM;
4906 goto mem_alloc_failed;
4907 }
4908
4909 sp->bar0 = ioremap(pci_resource_start(pdev, 0),
4910 pci_resource_len(pdev, 0));
4911 if (!sp->bar0) {
4912 DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem1\n",
4913 dev->name);
4914 ret = -ENOMEM;
4915 goto bar0_remap_failed;
4916 }
4917
4918 sp->bar1 = ioremap(pci_resource_start(pdev, 2),
4919 pci_resource_len(pdev, 2));
4920 if (!sp->bar1) {
4921 DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem2\n",
4922 dev->name);
4923 ret = -ENOMEM;
4924 goto bar1_remap_failed;
4925 }
4926
4927 dev->irq = pdev->irq;
4928 dev->base_addr = (unsigned long) sp->bar0;
4929
4930 /* Initializing the BAR1 address as the start of the FIFO pointer. */
4931 for (j = 0; j < MAX_TX_FIFOS; j++) {
4932 mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *)
4933 (sp->bar1 + (j * 0x00020000));
4934 }
4935
4936 /* Driver entry points */
4937 dev->open = &s2io_open;
4938 dev->stop = &s2io_close;
4939 dev->hard_start_xmit = &s2io_xmit;
4940 dev->get_stats = &s2io_get_stats;
4941 dev->set_multicast_list = &s2io_set_multicast;
4942 dev->do_ioctl = &s2io_ioctl;
4943 dev->change_mtu = &s2io_change_mtu;
4944 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004945
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 /*
4947 * will use eth_mac_addr() for dev->set_mac_address
4948 * mac address will be set every time dev->open() is called
4949 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004950#if defined(CONFIG_S2IO_NAPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951 dev->poll = s2io_poll;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004952 dev->weight = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953#endif
4954
4955 dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
4956 if (sp->high_dma_flag == TRUE)
4957 dev->features |= NETIF_F_HIGHDMA;
4958#ifdef NETIF_F_TSO
4959 dev->features |= NETIF_F_TSO;
4960#endif
4961
4962 dev->tx_timeout = &s2io_tx_watchdog;
4963 dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
4964 INIT_WORK(&sp->rst_timer_task,
4965 (void (*)(void *)) s2io_restart_nic, dev);
4966 INIT_WORK(&sp->set_link_task,
4967 (void (*)(void *)) s2io_set_link, sp);
4968
4969 pci_save_state(sp->pdev);
4970
4971 /* Setting swapper control on the NIC, for proper reset operation */
4972 if (s2io_set_swapper(sp)) {
4973 DBG_PRINT(ERR_DBG, "%s:swapper settings are wrong\n",
4974 dev->name);
4975 ret = -EAGAIN;
4976 goto set_swap_failed;
4977 }
4978
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004979 /*
4980 * Fix for all "FFs" MAC address problems observed on
4981 * Alpha platforms
4982 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983 fix_mac_address(sp);
4984 s2io_reset(sp);
4985
4986 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 * MAC address initialization.
4988 * For now only one mac address will be read and used.
4989 */
4990 bar0 = sp->bar0;
4991 val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4992 RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
4993 writeq(val64, &bar0->rmac_addr_cmd_mem);
4994 wait_for_cmd_complete(sp);
4995
4996 tmp64 = readq(&bar0->rmac_addr_data0_mem);
4997 mac_down = (u32) tmp64;
4998 mac_up = (u32) (tmp64 >> 32);
4999
5000 memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
5001
5002 sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up);
5003 sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8);
5004 sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16);
5005 sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_up >> 24);
5006 sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16);
5007 sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24);
5008
5009 DBG_PRINT(INIT_DBG,
5010 "DEFAULT MAC ADDR:0x%02x-%02x-%02x-%02x-%02x-%02x\n",
5011 sp->def_mac_addr[0].mac_addr[0],
5012 sp->def_mac_addr[0].mac_addr[1],
5013 sp->def_mac_addr[0].mac_addr[2],
5014 sp->def_mac_addr[0].mac_addr[3],
5015 sp->def_mac_addr[0].mac_addr[4],
5016 sp->def_mac_addr[0].mac_addr[5]);
5017
5018 /* Set the factory defined MAC address initially */
5019 dev->addr_len = ETH_ALEN;
5020 memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
5021
5022 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005023 * Initialize the tasklet status and link state flags
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024 * and the card statte parameter
5025 */
5026 atomic_set(&(sp->card_state), 0);
5027 sp->tasklet_status = 0;
5028 sp->link_state = 0;
5029
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030 /* Initialize spinlocks */
5031 spin_lock_init(&sp->tx_lock);
5032#ifndef CONFIG_S2IO_NAPI
5033 spin_lock_init(&sp->put_lock);
5034#endif
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005035 spin_lock_init(&sp->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005037 /*
5038 * SXE-002: Configure link and activity LED to init state
5039 * on driver load.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040 */
5041 subid = sp->pdev->subsystem_device;
5042 if ((subid & 0xFF) >= 0x07) {
5043 val64 = readq(&bar0->gpio_control);
5044 val64 |= 0x0000800000000000ULL;
5045 writeq(val64, &bar0->gpio_control);
5046 val64 = 0x0411040400000000ULL;
5047 writeq(val64, (void __iomem *) bar0 + 0x2700);
5048 val64 = readq(&bar0->gpio_control);
5049 }
5050
5051 sp->rx_csum = 1; /* Rx chksum verify enabled by default */
5052
5053 if (register_netdev(dev)) {
5054 DBG_PRINT(ERR_DBG, "Device registration failed\n");
5055 ret = -ENODEV;
5056 goto register_failed;
5057 }
5058
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005059 /* Initialize device name */
5060 strcpy(sp->name, dev->name);
5061 strcat(sp->name, ": Neterion Xframe I 10GbE adapter");
5062
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005063 /*
5064 * Make Link state as off at this point, when the Link change
5065 * interrupt comes the state will be automatically changed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 * the right state.
5067 */
5068 netif_carrier_off(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069
5070 return 0;
5071
5072 register_failed:
5073 set_swap_failed:
5074 iounmap(sp->bar1);
5075 bar1_remap_failed:
5076 iounmap(sp->bar0);
5077 bar0_remap_failed:
5078 mem_alloc_failed:
5079 free_shared_mem(sp);
5080 pci_disable_device(pdev);
5081 pci_release_regions(pdev);
5082 pci_set_drvdata(pdev, NULL);
5083 free_netdev(dev);
5084
5085 return ret;
5086}
5087
5088/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005089 * s2io_rem_nic - Free the PCI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 * @pdev: structure containing the PCI related information of the device.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005091 * Description: This function is called by the Pci subsystem to release a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092 * PCI device and free up all resource held up by the device. This could
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005093 * be in response to a Hot plug event or when the driver is to be removed
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 * from memory.
5095 */
5096
5097static void __devexit s2io_rem_nic(struct pci_dev *pdev)
5098{
5099 struct net_device *dev =
5100 (struct net_device *) pci_get_drvdata(pdev);
5101 nic_t *sp;
5102
5103 if (dev == NULL) {
5104 DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
5105 return;
5106 }
5107
5108 sp = dev->priv;
5109 unregister_netdev(dev);
5110
5111 free_shared_mem(sp);
5112 iounmap(sp->bar0);
5113 iounmap(sp->bar1);
5114 pci_disable_device(pdev);
5115 pci_release_regions(pdev);
5116 pci_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 free_netdev(dev);
5118}
5119
5120/**
5121 * s2io_starter - Entry point for the driver
5122 * Description: This function is the entry point for the driver. It verifies
5123 * the module loadable parameters and initializes PCI configuration space.
5124 */
5125
5126int __init s2io_starter(void)
5127{
5128 return pci_module_init(&s2io_driver);
5129}
5130
5131/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005132 * s2io_closer - Cleanup routine for the driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
5134 */
5135
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005136void s2io_closer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137{
5138 pci_unregister_driver(&s2io_driver);
5139 DBG_PRINT(INIT_DBG, "cleanup done\n");
5140}
5141
5142module_init(s2io_starter);
5143module_exit(s2io_closer);