blob: eff747cf3113b454c503621653ce2728aeaa34e6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/************************************************************************
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002 * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * 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.
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -070031 * rx_ring_sz: 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>
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -070058#include <linux/if_vlan.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#include <asm/system.h>
61#include <asm/uaccess.h>
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070062#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64/* local include */
65#include "s2io.h"
66#include "s2io-regs.h"
67
68/* S2io Driver name & version. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070069static char s2io_driver_name[] = "Neterion";
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -040070static char s2io_driver_version[] = "Version 2.0.9.1";
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -070072static inline int RXD_IS_UP2DT(RxD_t *rxdp)
73{
74 int ret;
75
76 ret = ((!(rxdp->Control_1 & RXD_OWN_XENA)) &&
77 (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK));
78
79 return ret;
80}
81
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070082/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 * Cards with following subsystem_id have a link state indication
84 * problem, 600B, 600C, 600D, 640B, 640C and 640D.
85 * macro below identifies these cards given the subsystem_id.
86 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -070087#define CARDS_WITH_FAULTY_LINK_INDICATORS(dev_type, subid) \
88 (dev_type == XFRAME_I_DEVICE) ? \
89 ((((subid >= 0x600B) && (subid <= 0x600D)) || \
90 ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0) : 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92#define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \
93 ADAPTER_STATUS_RMAC_LOCAL_FAULT)))
94#define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status))
95#define PANIC 1
96#define LOW 2
97static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring)
98{
99 int level = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700100 mac_info_t *mac_control;
101
102 mac_control = &sp->mac_control;
103 if ((mac_control->rings[ring].pkt_cnt - rxb_size) > 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 level = LOW;
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -0700105 if (rxb_size <= MAX_RXDS_PER_BLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 level = PANIC;
107 }
108 }
109
110 return level;
111}
112
113/* Ethtool related variables and Macros. */
114static char s2io_gstrings[][ETH_GSTRING_LEN] = {
115 "Register test\t(offline)",
116 "Eeprom test\t(offline)",
117 "Link test\t(online)",
118 "RLDRAM test\t(offline)",
119 "BIST Test\t(offline)"
120};
121
122static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
123 {"tmac_frms"},
124 {"tmac_data_octets"},
125 {"tmac_drop_frms"},
126 {"tmac_mcst_frms"},
127 {"tmac_bcst_frms"},
128 {"tmac_pause_ctrl_frms"},
129 {"tmac_any_err_frms"},
130 {"tmac_vld_ip_octets"},
131 {"tmac_vld_ip"},
132 {"tmac_drop_ip"},
133 {"tmac_icmp"},
134 {"tmac_rst_tcp"},
135 {"tmac_tcp"},
136 {"tmac_udp"},
137 {"rmac_vld_frms"},
138 {"rmac_data_octets"},
139 {"rmac_fcs_err_frms"},
140 {"rmac_drop_frms"},
141 {"rmac_vld_mcst_frms"},
142 {"rmac_vld_bcst_frms"},
143 {"rmac_in_rng_len_err_frms"},
144 {"rmac_long_frms"},
145 {"rmac_pause_ctrl_frms"},
146 {"rmac_discarded_frms"},
147 {"rmac_usized_frms"},
148 {"rmac_osized_frms"},
149 {"rmac_frag_frms"},
150 {"rmac_jabber_frms"},
151 {"rmac_ip"},
152 {"rmac_ip_octets"},
153 {"rmac_hdr_err_ip"},
154 {"rmac_drop_ip"},
155 {"rmac_icmp"},
156 {"rmac_tcp"},
157 {"rmac_udp"},
158 {"rmac_err_drp_udp"},
159 {"rmac_pause_cnt"},
160 {"rmac_accepted_ip"},
161 {"rmac_err_tcp"},
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -0700162 {"\n DRIVER STATISTICS"},
163 {"single_bit_ecc_errs"},
164 {"double_bit_ecc_errs"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165};
166
167#define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN
168#define S2IO_STAT_STRINGS_LEN S2IO_STAT_LEN * ETH_GSTRING_LEN
169
170#define S2IO_TEST_LEN sizeof(s2io_gstrings) / ETH_GSTRING_LEN
171#define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN
172
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -0700173#define S2IO_TIMER_CONF(timer, handle, arg, exp) \
174 init_timer(&timer); \
175 timer.function = handle; \
176 timer.data = (unsigned long) arg; \
177 mod_timer(&timer, (jiffies + exp)) \
178
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -0700179/* Add the vlan */
180static void s2io_vlan_rx_register(struct net_device *dev,
181 struct vlan_group *grp)
182{
183 nic_t *nic = dev->priv;
184 unsigned long flags;
185
186 spin_lock_irqsave(&nic->tx_lock, flags);
187 nic->vlgrp = grp;
188 spin_unlock_irqrestore(&nic->tx_lock, flags);
189}
190
191/* Unregister the vlan */
192static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
193{
194 nic_t *nic = dev->priv;
195 unsigned long flags;
196
197 spin_lock_irqsave(&nic->tx_lock, flags);
198 if (nic->vlgrp)
199 nic->vlgrp->vlan_devices[vid] = NULL;
200 spin_unlock_irqrestore(&nic->tx_lock, flags);
201}
202
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700203/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 * Constants to be programmed into the Xena's registers, to configure
205 * the XAUI.
206 */
207
208#define SWITCH_SIGN 0xA5A5A5A5A5A5A5A5ULL
209#define END_SIGN 0x0
210
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700211static u64 herc_act_dtx_cfg[] = {
212 /* Set address */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700213 0x8000051536750000ULL, 0x80000515367500E0ULL,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700214 /* Write data */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700215 0x8000051536750004ULL, 0x80000515367500E4ULL,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700216 /* Set address */
217 0x80010515003F0000ULL, 0x80010515003F00E0ULL,
218 /* Write data */
219 0x80010515003F0004ULL, 0x80010515003F00E4ULL,
220 /* Set address */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700221 0x801205150D440000ULL, 0x801205150D4400E0ULL,
222 /* Write data */
223 0x801205150D440004ULL, 0x801205150D4400E4ULL,
224 /* Set address */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700225 0x80020515F2100000ULL, 0x80020515F21000E0ULL,
226 /* Write data */
227 0x80020515F2100004ULL, 0x80020515F21000E4ULL,
228 /* Done */
229 END_SIGN
230};
231
232static u64 xena_mdio_cfg[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 /* Reset PMA PLL */
234 0xC001010000000000ULL, 0xC0010100000000E0ULL,
235 0xC0010100008000E4ULL,
236 /* Remove Reset from PMA PLL */
237 0xC001010000000000ULL, 0xC0010100000000E0ULL,
238 0xC0010100000000E4ULL,
239 END_SIGN
240};
241
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700242static u64 xena_dtx_cfg[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 0x8000051500000000ULL, 0x80000515000000E0ULL,
244 0x80000515D93500E4ULL, 0x8001051500000000ULL,
245 0x80010515000000E0ULL, 0x80010515001E00E4ULL,
246 0x8002051500000000ULL, 0x80020515000000E0ULL,
247 0x80020515F21000E4ULL,
248 /* Set PADLOOPBACKN */
249 0x8002051500000000ULL, 0x80020515000000E0ULL,
250 0x80020515B20000E4ULL, 0x8003051500000000ULL,
251 0x80030515000000E0ULL, 0x80030515B20000E4ULL,
252 0x8004051500000000ULL, 0x80040515000000E0ULL,
253 0x80040515B20000E4ULL, 0x8005051500000000ULL,
254 0x80050515000000E0ULL, 0x80050515B20000E4ULL,
255 SWITCH_SIGN,
256 /* Remove PADLOOPBACKN */
257 0x8002051500000000ULL, 0x80020515000000E0ULL,
258 0x80020515F20000E4ULL, 0x8003051500000000ULL,
259 0x80030515000000E0ULL, 0x80030515F20000E4ULL,
260 0x8004051500000000ULL, 0x80040515000000E0ULL,
261 0x80040515F20000E4ULL, 0x8005051500000000ULL,
262 0x80050515000000E0ULL, 0x80050515F20000E4ULL,
263 END_SIGN
264};
265
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700266/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 * Constants for Fixing the MacAddress problem seen mostly on
268 * Alpha machines.
269 */
270static u64 fix_mac[] = {
271 0x0060000000000000ULL, 0x0060600000000000ULL,
272 0x0040600000000000ULL, 0x0000600000000000ULL,
273 0x0020600000000000ULL, 0x0060600000000000ULL,
274 0x0020600000000000ULL, 0x0060600000000000ULL,
275 0x0020600000000000ULL, 0x0060600000000000ULL,
276 0x0020600000000000ULL, 0x0060600000000000ULL,
277 0x0020600000000000ULL, 0x0060600000000000ULL,
278 0x0020600000000000ULL, 0x0060600000000000ULL,
279 0x0020600000000000ULL, 0x0060600000000000ULL,
280 0x0020600000000000ULL, 0x0060600000000000ULL,
281 0x0020600000000000ULL, 0x0060600000000000ULL,
282 0x0020600000000000ULL, 0x0060600000000000ULL,
283 0x0020600000000000ULL, 0x0000600000000000ULL,
284 0x0040600000000000ULL, 0x0060600000000000ULL,
285 END_SIGN
286};
287
288/* Module Loadable parameters. */
289static unsigned int tx_fifo_num = 1;
290static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
291 {[0 ...(MAX_TX_FIFOS - 1)] = 0 };
292static unsigned int rx_ring_num = 1;
293static unsigned int rx_ring_sz[MAX_RX_RINGS] =
294 {[0 ...(MAX_RX_RINGS - 1)] = 0 };
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700295static unsigned int rts_frm_len[MAX_RX_RINGS] =
296 {[0 ...(MAX_RX_RINGS - 1)] = 0 };
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700297static unsigned int use_continuous_tx_intrs = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298static unsigned int rmac_pause_time = 65535;
299static unsigned int mc_pause_threshold_q0q3 = 187;
300static unsigned int mc_pause_threshold_q4q7 = 187;
301static unsigned int shared_splits;
302static unsigned int tmac_util_period = 5;
303static unsigned int rmac_util_period = 5;
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -0700304static unsigned int bimodal = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305#ifndef CONFIG_S2IO_NAPI
306static unsigned int indicate_max_pkts;
307#endif
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -0700308/* Frequency of Rx desc syncs expressed as power of 2 */
309static unsigned int rxsync_frequency = 3;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -0400310/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */
311static unsigned int intr_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700313/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 * S2IO device table.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700315 * This table lists all the devices that this driver supports.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 */
317static struct pci_device_id s2io_tbl[] __devinitdata = {
318 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN,
319 PCI_ANY_ID, PCI_ANY_ID},
320 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI,
321 PCI_ANY_ID, PCI_ANY_ID},
322 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700323 PCI_ANY_ID, PCI_ANY_ID},
324 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI,
325 PCI_ANY_ID, PCI_ANY_ID},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 {0,}
327};
328
329MODULE_DEVICE_TABLE(pci, s2io_tbl);
330
331static struct pci_driver s2io_driver = {
332 .name = "S2IO",
333 .id_table = s2io_tbl,
334 .probe = s2io_init_nic,
335 .remove = __devexit_p(s2io_rem_nic),
336};
337
338/* A simplifier macro used both by init and free shared_mem Fns(). */
339#define TXD_MEM_PAGE_CNT(len, per_each) ((len+per_each - 1) / per_each)
340
341/**
342 * init_shared_mem - Allocation and Initialization of Memory
343 * @nic: Device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700344 * Description: The function allocates all the memory areas shared
345 * between the NIC and the driver. This includes Tx descriptors,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 * Rx descriptors and the statistics block.
347 */
348
349static int init_shared_mem(struct s2io_nic *nic)
350{
351 u32 size;
352 void *tmp_v_addr, *tmp_v_addr_next;
353 dma_addr_t tmp_p_addr, tmp_p_addr_next;
354 RxD_block_t *pre_rxd_blk = NULL;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700355 int i, j, blk_cnt, rx_sz, tx_sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 int lst_size, lst_per_page;
357 struct net_device *dev = nic->dev;
358#ifdef CONFIG_2BUFF_MODE
viro@zenIV.linux.org.uk8ae418c2005-09-02 20:15:29 +0100359 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 buffAdd_t *ba;
361#endif
362
363 mac_info_t *mac_control;
364 struct config_param *config;
365
366 mac_control = &nic->mac_control;
367 config = &nic->config;
368
369
370 /* Allocation and initialization of TXDLs in FIOFs */
371 size = 0;
372 for (i = 0; i < config->tx_fifo_num; i++) {
373 size += config->tx_cfg[i].fifo_len;
374 }
375 if (size > MAX_AVAILABLE_TXDS) {
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -0700376 DBG_PRINT(ERR_DBG, "%s: Requested TxDs too high, ",
377 __FUNCTION__);
378 DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 return FAILURE;
380 }
381
382 lst_size = (sizeof(TxD_t) * config->max_txds);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700383 tx_sz = lst_size * size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 lst_per_page = PAGE_SIZE / lst_size;
385
386 for (i = 0; i < config->tx_fifo_num; i++) {
387 int fifo_len = config->tx_cfg[i].fifo_len;
388 int list_holder_size = fifo_len * sizeof(list_info_hold_t);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700389 mac_control->fifos[i].list_info = kmalloc(list_holder_size,
390 GFP_KERNEL);
391 if (!mac_control->fifos[i].list_info) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 DBG_PRINT(ERR_DBG,
393 "Malloc failed for list_info\n");
394 return -ENOMEM;
395 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700396 memset(mac_control->fifos[i].list_info, 0, list_holder_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 }
398 for (i = 0; i < config->tx_fifo_num; i++) {
399 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
400 lst_per_page);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700401 mac_control->fifos[i].tx_curr_put_info.offset = 0;
402 mac_control->fifos[i].tx_curr_put_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700404 mac_control->fifos[i].tx_curr_get_info.offset = 0;
405 mac_control->fifos[i].tx_curr_get_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700407 mac_control->fifos[i].fifo_no = i;
408 mac_control->fifos[i].nic = nic;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700409 mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700410
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 for (j = 0; j < page_num; j++) {
412 int k = 0;
413 dma_addr_t tmp_p;
414 void *tmp_v;
415 tmp_v = pci_alloc_consistent(nic->pdev,
416 PAGE_SIZE, &tmp_p);
417 if (!tmp_v) {
418 DBG_PRINT(ERR_DBG,
419 "pci_alloc_consistent ");
420 DBG_PRINT(ERR_DBG, "failed for TxDL\n");
421 return -ENOMEM;
422 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700423 /* If we got a zero DMA address(can happen on
424 * certain platforms like PPC), reallocate.
425 * Store virtual address of page we don't want,
426 * to be freed later.
427 */
428 if (!tmp_p) {
429 mac_control->zerodma_virt_addr = tmp_v;
430 DBG_PRINT(INIT_DBG,
431 "%s: Zero DMA address for TxDL. ", dev->name);
432 DBG_PRINT(INIT_DBG,
Andrew Morton6b4d6172005-09-12 23:21:55 -0700433 "Virtual address %p\n", tmp_v);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700434 tmp_v = pci_alloc_consistent(nic->pdev,
435 PAGE_SIZE, &tmp_p);
436 if (!tmp_v) {
437 DBG_PRINT(ERR_DBG,
438 "pci_alloc_consistent ");
439 DBG_PRINT(ERR_DBG, "failed for TxDL\n");
440 return -ENOMEM;
441 }
442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 while (k < lst_per_page) {
444 int l = (j * lst_per_page) + k;
445 if (l == config->tx_cfg[i].fifo_len)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700446 break;
447 mac_control->fifos[i].list_info[l].list_virt_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 tmp_v + (k * lst_size);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700449 mac_control->fifos[i].list_info[l].list_phy_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 tmp_p + (k * lst_size);
451 k++;
452 }
453 }
454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
456 /* Allocation and initialization of RXDs in Rings */
457 size = 0;
458 for (i = 0; i < config->rx_ring_num; i++) {
459 if (config->rx_cfg[i].num_rxd % (MAX_RXDS_PER_BLOCK + 1)) {
460 DBG_PRINT(ERR_DBG, "%s: RxD count of ", dev->name);
461 DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ",
462 i);
463 DBG_PRINT(ERR_DBG, "RxDs per Block");
464 return FAILURE;
465 }
466 size += config->rx_cfg[i].num_rxd;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700467 mac_control->rings[i].block_count =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700469 mac_control->rings[i].pkt_cnt =
470 config->rx_cfg[i].num_rxd - mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700472 size = (size * (sizeof(RxD_t)));
473 rx_sz = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
475 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700476 mac_control->rings[i].rx_curr_get_info.block_index = 0;
477 mac_control->rings[i].rx_curr_get_info.offset = 0;
478 mac_control->rings[i].rx_curr_get_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700480 mac_control->rings[i].rx_curr_put_info.block_index = 0;
481 mac_control->rings[i].rx_curr_put_info.offset = 0;
482 mac_control->rings[i].rx_curr_put_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700484 mac_control->rings[i].nic = nic;
485 mac_control->rings[i].ring_no = i;
486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 blk_cnt =
488 config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1);
489 /* Allocating all the Rx blocks */
490 for (j = 0; j < blk_cnt; j++) {
491#ifndef CONFIG_2BUFF_MODE
492 size = (MAX_RXDS_PER_BLOCK + 1) * (sizeof(RxD_t));
493#else
494 size = SIZE_OF_BLOCK;
495#endif
496 tmp_v_addr = pci_alloc_consistent(nic->pdev, size,
497 &tmp_p_addr);
498 if (tmp_v_addr == NULL) {
499 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700500 * In case of failure, free_shared_mem()
501 * is called, which should free any
502 * memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 * failure happened.
504 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700505 mac_control->rings[i].rx_blocks[j].block_virt_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 tmp_v_addr;
507 return -ENOMEM;
508 }
509 memset(tmp_v_addr, 0, size);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700510 mac_control->rings[i].rx_blocks[j].block_virt_addr =
511 tmp_v_addr;
512 mac_control->rings[i].rx_blocks[j].block_dma_addr =
513 tmp_p_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 }
515 /* Interlinking all Rx Blocks */
516 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700517 tmp_v_addr =
518 mac_control->rings[i].rx_blocks[j].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 tmp_v_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700520 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 blk_cnt].block_virt_addr;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700522 tmp_p_addr =
523 mac_control->rings[i].rx_blocks[j].block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 tmp_p_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700525 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 blk_cnt].block_dma_addr;
527
528 pre_rxd_blk = (RxD_block_t *) tmp_v_addr;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700529 pre_rxd_blk->reserved_1 = END_OF_BLOCK; /* last RxD
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 * marker.
531 */
532#ifndef CONFIG_2BUFF_MODE
533 pre_rxd_blk->reserved_2_pNext_RxD_block =
534 (unsigned long) tmp_v_addr_next;
535#endif
536 pre_rxd_blk->pNext_RxD_Blk_physical =
537 (u64) tmp_p_addr_next;
538 }
539 }
540
541#ifdef CONFIG_2BUFF_MODE
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700542 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 * Allocation of Storages for buffer addresses in 2BUFF mode
544 * and the buffers as well.
545 */
546 for (i = 0; i < config->rx_ring_num; i++) {
547 blk_cnt =
548 config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700549 mac_control->rings[i].ba = kmalloc((sizeof(buffAdd_t *) * blk_cnt),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 GFP_KERNEL);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700551 if (!mac_control->rings[i].ba)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 return -ENOMEM;
553 for (j = 0; j < blk_cnt; j++) {
554 int k = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700555 mac_control->rings[i].ba[j] = kmalloc((sizeof(buffAdd_t) *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 (MAX_RXDS_PER_BLOCK + 1)),
557 GFP_KERNEL);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700558 if (!mac_control->rings[i].ba[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 return -ENOMEM;
560 while (k != MAX_RXDS_PER_BLOCK) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700561 ba = &mac_control->rings[i].ba[j][k];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700563 ba->ba_0_org = (void *) kmalloc
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
565 if (!ba->ba_0_org)
566 return -ENOMEM;
viro@zenIV.linux.org.uk8ae418c2005-09-02 20:15:29 +0100567 tmp = (unsigned long) ba->ba_0_org;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 tmp += ALIGN_SIZE;
viro@zenIV.linux.org.uk8ae418c2005-09-02 20:15:29 +0100569 tmp &= ~((unsigned long) ALIGN_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 ba->ba_0 = (void *) tmp;
571
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700572 ba->ba_1_org = (void *) kmalloc
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
574 if (!ba->ba_1_org)
575 return -ENOMEM;
viro@zenIV.linux.org.uk8ae418c2005-09-02 20:15:29 +0100576 tmp = (unsigned long) ba->ba_1_org;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 tmp += ALIGN_SIZE;
viro@zenIV.linux.org.uk8ae418c2005-09-02 20:15:29 +0100578 tmp &= ~((unsigned long) ALIGN_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 ba->ba_1 = (void *) tmp;
580 k++;
581 }
582 }
583 }
584#endif
585
586 /* Allocation and initialization of Statistics block */
587 size = sizeof(StatInfo_t);
588 mac_control->stats_mem = pci_alloc_consistent
589 (nic->pdev, size, &mac_control->stats_mem_phy);
590
591 if (!mac_control->stats_mem) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700592 /*
593 * In case of failure, free_shared_mem() is called, which
594 * should free any memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 * failure happened.
596 */
597 return -ENOMEM;
598 }
599 mac_control->stats_mem_sz = size;
600
601 tmp_v_addr = mac_control->stats_mem;
602 mac_control->stats_info = (StatInfo_t *) tmp_v_addr;
603 memset(tmp_v_addr, 0, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name,
605 (unsigned long long) tmp_p_addr);
606
607 return SUCCESS;
608}
609
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700610/**
611 * free_shared_mem - Free the allocated Memory
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 * @nic: Device private variable.
613 * Description: This function is to free all memory locations allocated by
614 * the init_shared_mem() function and return it to the kernel.
615 */
616
617static void free_shared_mem(struct s2io_nic *nic)
618{
619 int i, j, blk_cnt, size;
620 void *tmp_v_addr;
621 dma_addr_t tmp_p_addr;
622 mac_info_t *mac_control;
623 struct config_param *config;
624 int lst_size, lst_per_page;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700625 struct net_device *dev = nic->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
627 if (!nic)
628 return;
629
630 mac_control = &nic->mac_control;
631 config = &nic->config;
632
633 lst_size = (sizeof(TxD_t) * config->max_txds);
634 lst_per_page = PAGE_SIZE / lst_size;
635
636 for (i = 0; i < config->tx_fifo_num; i++) {
637 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
638 lst_per_page);
639 for (j = 0; j < page_num; j++) {
640 int mem_blks = (j * lst_per_page);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700641 if (!mac_control->fifos[i].list_info)
642 return;
643 if (!mac_control->fifos[i].list_info[mem_blks].
644 list_virt_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 break;
646 pci_free_consistent(nic->pdev, PAGE_SIZE,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700647 mac_control->fifos[i].
648 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 list_virt_addr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700650 mac_control->fifos[i].
651 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 list_phy_addr);
653 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700654 /* If we got a zero DMA address during allocation,
655 * free the page now
656 */
657 if (mac_control->zerodma_virt_addr) {
658 pci_free_consistent(nic->pdev, PAGE_SIZE,
659 mac_control->zerodma_virt_addr,
660 (dma_addr_t)0);
661 DBG_PRINT(INIT_DBG,
Andrew Morton6b4d6172005-09-12 23:21:55 -0700662 "%s: Freeing TxDL with zero DMA addr. ",
663 dev->name);
664 DBG_PRINT(INIT_DBG, "Virtual address %p\n",
665 mac_control->zerodma_virt_addr);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700666 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700667 kfree(mac_control->fifos[i].list_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 }
669
670#ifndef CONFIG_2BUFF_MODE
671 size = (MAX_RXDS_PER_BLOCK + 1) * (sizeof(RxD_t));
672#else
673 size = SIZE_OF_BLOCK;
674#endif
675 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700676 blk_cnt = mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700678 tmp_v_addr = mac_control->rings[i].rx_blocks[j].
679 block_virt_addr;
680 tmp_p_addr = mac_control->rings[i].rx_blocks[j].
681 block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 if (tmp_v_addr == NULL)
683 break;
684 pci_free_consistent(nic->pdev, size,
685 tmp_v_addr, tmp_p_addr);
686 }
687 }
688
689#ifdef CONFIG_2BUFF_MODE
690 /* Freeing buffer storage addresses in 2BUFF mode. */
691 for (i = 0; i < config->rx_ring_num; i++) {
692 blk_cnt =
693 config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 for (j = 0; j < blk_cnt; j++) {
695 int k = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700696 if (!mac_control->rings[i].ba[j])
697 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 while (k != MAX_RXDS_PER_BLOCK) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700699 buffAdd_t *ba = &mac_control->rings[i].ba[j][k];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 kfree(ba->ba_0_org);
701 kfree(ba->ba_1_org);
702 k++;
703 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700704 kfree(mac_control->rings[i].ba[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700706 if (mac_control->rings[i].ba)
707 kfree(mac_control->rings[i].ba);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709#endif
710
711 if (mac_control->stats_mem) {
712 pci_free_consistent(nic->pdev,
713 mac_control->stats_mem_sz,
714 mac_control->stats_mem,
715 mac_control->stats_mem_phy);
716 }
717}
718
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700719/**
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700720 * s2io_verify_pci_mode -
721 */
722
723static int s2io_verify_pci_mode(nic_t *nic)
724{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +0100725 XENA_dev_config_t __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700726 register u64 val64 = 0;
727 int mode;
728
729 val64 = readq(&bar0->pci_mode);
730 mode = (u8)GET_PCI_MODE(val64);
731
732 if ( val64 & PCI_MODE_UNKNOWN_MODE)
733 return -1; /* Unknown PCI mode */
734 return mode;
735}
736
737
738/**
739 * s2io_print_pci_mode -
740 */
741static int s2io_print_pci_mode(nic_t *nic)
742{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +0100743 XENA_dev_config_t __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700744 register u64 val64 = 0;
745 int mode;
746 struct config_param *config = &nic->config;
747
748 val64 = readq(&bar0->pci_mode);
749 mode = (u8)GET_PCI_MODE(val64);
750
751 if ( val64 & PCI_MODE_UNKNOWN_MODE)
752 return -1; /* Unknown PCI mode */
753
754 if (val64 & PCI_MODE_32_BITS) {
755 DBG_PRINT(ERR_DBG, "%s: Device is on 32 bit ", nic->dev->name);
756 } else {
757 DBG_PRINT(ERR_DBG, "%s: Device is on 64 bit ", nic->dev->name);
758 }
759
760 switch(mode) {
761 case PCI_MODE_PCI_33:
762 DBG_PRINT(ERR_DBG, "33MHz PCI bus\n");
763 config->bus_speed = 33;
764 break;
765 case PCI_MODE_PCI_66:
766 DBG_PRINT(ERR_DBG, "66MHz PCI bus\n");
767 config->bus_speed = 133;
768 break;
769 case PCI_MODE_PCIX_M1_66:
770 DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n");
771 config->bus_speed = 133; /* Herc doubles the clock rate */
772 break;
773 case PCI_MODE_PCIX_M1_100:
774 DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n");
775 config->bus_speed = 200;
776 break;
777 case PCI_MODE_PCIX_M1_133:
778 DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n");
779 config->bus_speed = 266;
780 break;
781 case PCI_MODE_PCIX_M2_66:
782 DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n");
783 config->bus_speed = 133;
784 break;
785 case PCI_MODE_PCIX_M2_100:
786 DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n");
787 config->bus_speed = 200;
788 break;
789 case PCI_MODE_PCIX_M2_133:
790 DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n");
791 config->bus_speed = 266;
792 break;
793 default:
794 return -1; /* Unsupported bus speed */
795 }
796
797 return mode;
798}
799
800/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700801 * init_nic - Initialization of hardware
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 * @nic: device peivate variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700803 * Description: The function sequentially configures every block
804 * of the H/W from their reset values.
805 * Return Value: SUCCESS on success and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 * '-1' on failure (endian settings incorrect).
807 */
808
809static int init_nic(struct s2io_nic *nic)
810{
811 XENA_dev_config_t __iomem *bar0 = nic->bar0;
812 struct net_device *dev = nic->dev;
813 register u64 val64 = 0;
814 void __iomem *add;
815 u32 time;
816 int i, j;
817 mac_info_t *mac_control;
818 struct config_param *config;
819 int mdio_cnt = 0, dtx_cnt = 0;
820 unsigned long long mem_share;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700821 int mem_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
823 mac_control = &nic->mac_control;
824 config = &nic->config;
825
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700826 /* to set the swapper controle on the card */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700827 if(s2io_set_swapper(nic)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n");
829 return -1;
830 }
831
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700832 /*
833 * Herc requires EOI to be removed from reset before XGXS, so..
834 */
835 if (nic->device_type & XFRAME_II_DEVICE) {
836 val64 = 0xA500000000ULL;
837 writeq(val64, &bar0->sw_reset);
838 msleep(500);
839 val64 = readq(&bar0->sw_reset);
840 }
841
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 /* Remove XGXS from reset state */
843 val64 = 0;
844 writeq(val64, &bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 msleep(500);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700846 val64 = readq(&bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
848 /* Enable Receiving broadcasts */
849 add = &bar0->mac_cfg;
850 val64 = readq(&bar0->mac_cfg);
851 val64 |= MAC_RMAC_BCAST_ENABLE;
852 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
853 writel((u32) val64, add);
854 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
855 writel((u32) (val64 >> 32), (add + 4));
856
857 /* Read registers in all blocks */
858 val64 = readq(&bar0->mac_int_mask);
859 val64 = readq(&bar0->mc_int_mask);
860 val64 = readq(&bar0->xgxs_int_mask);
861
862 /* Set MTU */
863 val64 = dev->mtu;
864 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
865
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700866 /*
867 * Configuring the XAUI Interface of Xena.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 * ***************************************
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700869 * To Configure the Xena's XAUI, one has to write a series
870 * of 64 bit values into two registers in a particular
871 * sequence. Hence a macro 'SWITCH_SIGN' has been defined
872 * which will be defined in the array of configuration values
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700873 * (xena_dtx_cfg & xena_mdio_cfg) at appropriate places
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700874 * to switch writing from one regsiter to another. We continue
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 * writing these values until we encounter the 'END_SIGN' macro.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700876 * For example, After making a series of 21 writes into
877 * dtx_control register the 'SWITCH_SIGN' appears and hence we
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 * start writing into mdio_control until we encounter END_SIGN.
879 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700880 if (nic->device_type & XFRAME_II_DEVICE) {
881 while (herc_act_dtx_cfg[dtx_cnt] != END_SIGN) {
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -0700882 SPECIAL_REG_WRITE(herc_act_dtx_cfg[dtx_cnt],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 &bar0->dtx_control, UF);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700884 if (dtx_cnt & 0x1)
885 msleep(1); /* Necessary!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 dtx_cnt++;
887 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700888 } else {
889 while (1) {
890 dtx_cfg:
891 while (xena_dtx_cfg[dtx_cnt] != END_SIGN) {
892 if (xena_dtx_cfg[dtx_cnt] == SWITCH_SIGN) {
893 dtx_cnt++;
894 goto mdio_cfg;
895 }
896 SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt],
897 &bar0->dtx_control, UF);
898 val64 = readq(&bar0->dtx_control);
899 dtx_cnt++;
900 }
901 mdio_cfg:
902 while (xena_mdio_cfg[mdio_cnt] != END_SIGN) {
903 if (xena_mdio_cfg[mdio_cnt] == SWITCH_SIGN) {
904 mdio_cnt++;
905 goto dtx_cfg;
906 }
907 SPECIAL_REG_WRITE(xena_mdio_cfg[mdio_cnt],
908 &bar0->mdio_control, UF);
909 val64 = readq(&bar0->mdio_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 mdio_cnt++;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700911 }
912 if ((xena_dtx_cfg[dtx_cnt] == END_SIGN) &&
913 (xena_mdio_cfg[mdio_cnt] == END_SIGN)) {
914 break;
915 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 goto dtx_cfg;
917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 }
919 }
920
921 /* Tx DMA Initialization */
922 val64 = 0;
923 writeq(val64, &bar0->tx_fifo_partition_0);
924 writeq(val64, &bar0->tx_fifo_partition_1);
925 writeq(val64, &bar0->tx_fifo_partition_2);
926 writeq(val64, &bar0->tx_fifo_partition_3);
927
928
929 for (i = 0, j = 0; i < config->tx_fifo_num; i++) {
930 val64 |=
931 vBIT(config->tx_cfg[i].fifo_len - 1, ((i * 32) + 19),
932 13) | vBIT(config->tx_cfg[i].fifo_priority,
933 ((i * 32) + 5), 3);
934
935 if (i == (config->tx_fifo_num - 1)) {
936 if (i % 2 == 0)
937 i++;
938 }
939
940 switch (i) {
941 case 1:
942 writeq(val64, &bar0->tx_fifo_partition_0);
943 val64 = 0;
944 break;
945 case 3:
946 writeq(val64, &bar0->tx_fifo_partition_1);
947 val64 = 0;
948 break;
949 case 5:
950 writeq(val64, &bar0->tx_fifo_partition_2);
951 val64 = 0;
952 break;
953 case 7:
954 writeq(val64, &bar0->tx_fifo_partition_3);
955 break;
956 }
957 }
958
959 /* Enable Tx FIFO partition 0. */
960 val64 = readq(&bar0->tx_fifo_partition_0);
961 val64 |= BIT(0); /* To enable the FIFO partition. */
962 writeq(val64, &bar0->tx_fifo_partition_0);
963
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700964 /*
965 * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug
966 * SXE-008 TRANSMIT DMA ARBITRATION ISSUE.
967 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700968 if ((nic->device_type == XFRAME_I_DEVICE) &&
969 (get_xena_rev_id(nic->pdev) < 4))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700970 writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable);
971
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 val64 = readq(&bar0->tx_fifo_partition_0);
973 DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n",
974 &bar0->tx_fifo_partition_0, (unsigned long long) val64);
975
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700976 /*
977 * Initialization of Tx_PA_CONFIG register to ignore packet
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 * integrity checking.
979 */
980 val64 = readq(&bar0->tx_pa_cfg);
981 val64 |= TX_PA_CFG_IGNORE_FRM_ERR | TX_PA_CFG_IGNORE_SNAP_OUI |
982 TX_PA_CFG_IGNORE_LLC_CTRL | TX_PA_CFG_IGNORE_L2_ERR;
983 writeq(val64, &bar0->tx_pa_cfg);
984
985 /* Rx DMA intialization. */
986 val64 = 0;
987 for (i = 0; i < config->rx_ring_num; i++) {
988 val64 |=
989 vBIT(config->rx_cfg[i].ring_priority, (5 + (i * 8)),
990 3);
991 }
992 writeq(val64, &bar0->rx_queue_priority);
993
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700994 /*
995 * Allocating equal share of memory to all the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 * configured Rings.
997 */
998 val64 = 0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700999 if (nic->device_type & XFRAME_II_DEVICE)
1000 mem_size = 32;
1001 else
1002 mem_size = 64;
1003
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 for (i = 0; i < config->rx_ring_num; i++) {
1005 switch (i) {
1006 case 0:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001007 mem_share = (mem_size / config->rx_ring_num +
1008 mem_size % config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 val64 |= RX_QUEUE_CFG_Q0_SZ(mem_share);
1010 continue;
1011 case 1:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001012 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 val64 |= RX_QUEUE_CFG_Q1_SZ(mem_share);
1014 continue;
1015 case 2:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001016 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 val64 |= RX_QUEUE_CFG_Q2_SZ(mem_share);
1018 continue;
1019 case 3:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001020 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 val64 |= RX_QUEUE_CFG_Q3_SZ(mem_share);
1022 continue;
1023 case 4:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001024 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 val64 |= RX_QUEUE_CFG_Q4_SZ(mem_share);
1026 continue;
1027 case 5:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001028 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 val64 |= RX_QUEUE_CFG_Q5_SZ(mem_share);
1030 continue;
1031 case 6:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001032 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 val64 |= RX_QUEUE_CFG_Q6_SZ(mem_share);
1034 continue;
1035 case 7:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001036 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 val64 |= RX_QUEUE_CFG_Q7_SZ(mem_share);
1038 continue;
1039 }
1040 }
1041 writeq(val64, &bar0->rx_queue_cfg);
1042
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001043 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001044 * Filling Tx round robin registers
1045 * as per the number of FIFOs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 */
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001047 switch (config->tx_fifo_num) {
1048 case 1:
1049 val64 = 0x0000000000000000ULL;
1050 writeq(val64, &bar0->tx_w_round_robin_0);
1051 writeq(val64, &bar0->tx_w_round_robin_1);
1052 writeq(val64, &bar0->tx_w_round_robin_2);
1053 writeq(val64, &bar0->tx_w_round_robin_3);
1054 writeq(val64, &bar0->tx_w_round_robin_4);
1055 break;
1056 case 2:
1057 val64 = 0x0000010000010000ULL;
1058 writeq(val64, &bar0->tx_w_round_robin_0);
1059 val64 = 0x0100000100000100ULL;
1060 writeq(val64, &bar0->tx_w_round_robin_1);
1061 val64 = 0x0001000001000001ULL;
1062 writeq(val64, &bar0->tx_w_round_robin_2);
1063 val64 = 0x0000010000010000ULL;
1064 writeq(val64, &bar0->tx_w_round_robin_3);
1065 val64 = 0x0100000000000000ULL;
1066 writeq(val64, &bar0->tx_w_round_robin_4);
1067 break;
1068 case 3:
1069 val64 = 0x0001000102000001ULL;
1070 writeq(val64, &bar0->tx_w_round_robin_0);
1071 val64 = 0x0001020000010001ULL;
1072 writeq(val64, &bar0->tx_w_round_robin_1);
1073 val64 = 0x0200000100010200ULL;
1074 writeq(val64, &bar0->tx_w_round_robin_2);
1075 val64 = 0x0001000102000001ULL;
1076 writeq(val64, &bar0->tx_w_round_robin_3);
1077 val64 = 0x0001020000000000ULL;
1078 writeq(val64, &bar0->tx_w_round_robin_4);
1079 break;
1080 case 4:
1081 val64 = 0x0001020300010200ULL;
1082 writeq(val64, &bar0->tx_w_round_robin_0);
1083 val64 = 0x0100000102030001ULL;
1084 writeq(val64, &bar0->tx_w_round_robin_1);
1085 val64 = 0x0200010000010203ULL;
1086 writeq(val64, &bar0->tx_w_round_robin_2);
1087 val64 = 0x0001020001000001ULL;
1088 writeq(val64, &bar0->tx_w_round_robin_3);
1089 val64 = 0x0203000100000000ULL;
1090 writeq(val64, &bar0->tx_w_round_robin_4);
1091 break;
1092 case 5:
1093 val64 = 0x0001000203000102ULL;
1094 writeq(val64, &bar0->tx_w_round_robin_0);
1095 val64 = 0x0001020001030004ULL;
1096 writeq(val64, &bar0->tx_w_round_robin_1);
1097 val64 = 0x0001000203000102ULL;
1098 writeq(val64, &bar0->tx_w_round_robin_2);
1099 val64 = 0x0001020001030004ULL;
1100 writeq(val64, &bar0->tx_w_round_robin_3);
1101 val64 = 0x0001000000000000ULL;
1102 writeq(val64, &bar0->tx_w_round_robin_4);
1103 break;
1104 case 6:
1105 val64 = 0x0001020304000102ULL;
1106 writeq(val64, &bar0->tx_w_round_robin_0);
1107 val64 = 0x0304050001020001ULL;
1108 writeq(val64, &bar0->tx_w_round_robin_1);
1109 val64 = 0x0203000100000102ULL;
1110 writeq(val64, &bar0->tx_w_round_robin_2);
1111 val64 = 0x0304000102030405ULL;
1112 writeq(val64, &bar0->tx_w_round_robin_3);
1113 val64 = 0x0001000200000000ULL;
1114 writeq(val64, &bar0->tx_w_round_robin_4);
1115 break;
1116 case 7:
1117 val64 = 0x0001020001020300ULL;
1118 writeq(val64, &bar0->tx_w_round_robin_0);
1119 val64 = 0x0102030400010203ULL;
1120 writeq(val64, &bar0->tx_w_round_robin_1);
1121 val64 = 0x0405060001020001ULL;
1122 writeq(val64, &bar0->tx_w_round_robin_2);
1123 val64 = 0x0304050000010200ULL;
1124 writeq(val64, &bar0->tx_w_round_robin_3);
1125 val64 = 0x0102030000000000ULL;
1126 writeq(val64, &bar0->tx_w_round_robin_4);
1127 break;
1128 case 8:
1129 val64 = 0x0001020300040105ULL;
1130 writeq(val64, &bar0->tx_w_round_robin_0);
1131 val64 = 0x0200030106000204ULL;
1132 writeq(val64, &bar0->tx_w_round_robin_1);
1133 val64 = 0x0103000502010007ULL;
1134 writeq(val64, &bar0->tx_w_round_robin_2);
1135 val64 = 0x0304010002060500ULL;
1136 writeq(val64, &bar0->tx_w_round_robin_3);
1137 val64 = 0x0103020400000000ULL;
1138 writeq(val64, &bar0->tx_w_round_robin_4);
1139 break;
1140 }
1141
1142 /* Filling the Rx round robin registers as per the
1143 * number of Rings and steering based on QoS.
1144 */
1145 switch (config->rx_ring_num) {
1146 case 1:
1147 val64 = 0x8080808080808080ULL;
1148 writeq(val64, &bar0->rts_qos_steering);
1149 break;
1150 case 2:
1151 val64 = 0x0000010000010000ULL;
1152 writeq(val64, &bar0->rx_w_round_robin_0);
1153 val64 = 0x0100000100000100ULL;
1154 writeq(val64, &bar0->rx_w_round_robin_1);
1155 val64 = 0x0001000001000001ULL;
1156 writeq(val64, &bar0->rx_w_round_robin_2);
1157 val64 = 0x0000010000010000ULL;
1158 writeq(val64, &bar0->rx_w_round_robin_3);
1159 val64 = 0x0100000000000000ULL;
1160 writeq(val64, &bar0->rx_w_round_robin_4);
1161
1162 val64 = 0x8080808040404040ULL;
1163 writeq(val64, &bar0->rts_qos_steering);
1164 break;
1165 case 3:
1166 val64 = 0x0001000102000001ULL;
1167 writeq(val64, &bar0->rx_w_round_robin_0);
1168 val64 = 0x0001020000010001ULL;
1169 writeq(val64, &bar0->rx_w_round_robin_1);
1170 val64 = 0x0200000100010200ULL;
1171 writeq(val64, &bar0->rx_w_round_robin_2);
1172 val64 = 0x0001000102000001ULL;
1173 writeq(val64, &bar0->rx_w_round_robin_3);
1174 val64 = 0x0001020000000000ULL;
1175 writeq(val64, &bar0->rx_w_round_robin_4);
1176
1177 val64 = 0x8080804040402020ULL;
1178 writeq(val64, &bar0->rts_qos_steering);
1179 break;
1180 case 4:
1181 val64 = 0x0001020300010200ULL;
1182 writeq(val64, &bar0->rx_w_round_robin_0);
1183 val64 = 0x0100000102030001ULL;
1184 writeq(val64, &bar0->rx_w_round_robin_1);
1185 val64 = 0x0200010000010203ULL;
1186 writeq(val64, &bar0->rx_w_round_robin_2);
1187 val64 = 0x0001020001000001ULL;
1188 writeq(val64, &bar0->rx_w_round_robin_3);
1189 val64 = 0x0203000100000000ULL;
1190 writeq(val64, &bar0->rx_w_round_robin_4);
1191
1192 val64 = 0x8080404020201010ULL;
1193 writeq(val64, &bar0->rts_qos_steering);
1194 break;
1195 case 5:
1196 val64 = 0x0001000203000102ULL;
1197 writeq(val64, &bar0->rx_w_round_robin_0);
1198 val64 = 0x0001020001030004ULL;
1199 writeq(val64, &bar0->rx_w_round_robin_1);
1200 val64 = 0x0001000203000102ULL;
1201 writeq(val64, &bar0->rx_w_round_robin_2);
1202 val64 = 0x0001020001030004ULL;
1203 writeq(val64, &bar0->rx_w_round_robin_3);
1204 val64 = 0x0001000000000000ULL;
1205 writeq(val64, &bar0->rx_w_round_robin_4);
1206
1207 val64 = 0x8080404020201008ULL;
1208 writeq(val64, &bar0->rts_qos_steering);
1209 break;
1210 case 6:
1211 val64 = 0x0001020304000102ULL;
1212 writeq(val64, &bar0->rx_w_round_robin_0);
1213 val64 = 0x0304050001020001ULL;
1214 writeq(val64, &bar0->rx_w_round_robin_1);
1215 val64 = 0x0203000100000102ULL;
1216 writeq(val64, &bar0->rx_w_round_robin_2);
1217 val64 = 0x0304000102030405ULL;
1218 writeq(val64, &bar0->rx_w_round_robin_3);
1219 val64 = 0x0001000200000000ULL;
1220 writeq(val64, &bar0->rx_w_round_robin_4);
1221
1222 val64 = 0x8080404020100804ULL;
1223 writeq(val64, &bar0->rts_qos_steering);
1224 break;
1225 case 7:
1226 val64 = 0x0001020001020300ULL;
1227 writeq(val64, &bar0->rx_w_round_robin_0);
1228 val64 = 0x0102030400010203ULL;
1229 writeq(val64, &bar0->rx_w_round_robin_1);
1230 val64 = 0x0405060001020001ULL;
1231 writeq(val64, &bar0->rx_w_round_robin_2);
1232 val64 = 0x0304050000010200ULL;
1233 writeq(val64, &bar0->rx_w_round_robin_3);
1234 val64 = 0x0102030000000000ULL;
1235 writeq(val64, &bar0->rx_w_round_robin_4);
1236
1237 val64 = 0x8080402010080402ULL;
1238 writeq(val64, &bar0->rts_qos_steering);
1239 break;
1240 case 8:
1241 val64 = 0x0001020300040105ULL;
1242 writeq(val64, &bar0->rx_w_round_robin_0);
1243 val64 = 0x0200030106000204ULL;
1244 writeq(val64, &bar0->rx_w_round_robin_1);
1245 val64 = 0x0103000502010007ULL;
1246 writeq(val64, &bar0->rx_w_round_robin_2);
1247 val64 = 0x0304010002060500ULL;
1248 writeq(val64, &bar0->rx_w_round_robin_3);
1249 val64 = 0x0103020400000000ULL;
1250 writeq(val64, &bar0->rx_w_round_robin_4);
1251
1252 val64 = 0x8040201008040201ULL;
1253 writeq(val64, &bar0->rts_qos_steering);
1254 break;
1255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
1257 /* UDP Fix */
1258 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001259 for (i = 0; i < 8; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 writeq(val64, &bar0->rts_frm_len_n[i]);
1261
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001262 /* Set the default rts frame length for the rings configured */
1263 val64 = MAC_RTS_FRM_LEN_SET(dev->mtu+22);
1264 for (i = 0 ; i < config->rx_ring_num ; i++)
1265 writeq(val64, &bar0->rts_frm_len_n[i]);
1266
1267 /* Set the frame length for the configured rings
1268 * desired by the user
1269 */
1270 for (i = 0; i < config->rx_ring_num; i++) {
1271 /* If rts_frm_len[i] == 0 then it is assumed that user not
1272 * specified frame length steering.
1273 * If the user provides the frame length then program
1274 * the rts_frm_len register for those values or else
1275 * leave it as it is.
1276 */
1277 if (rts_frm_len[i] != 0) {
1278 writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]),
1279 &bar0->rts_frm_len_n[i]);
1280 }
1281 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001283 /* Program statistics memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 writeq(mac_control->stats_mem_phy, &bar0->stat_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001286 if (nic->device_type == XFRAME_II_DEVICE) {
1287 val64 = STAT_BC(0x320);
1288 writeq(val64, &bar0->stat_byte_cnt);
1289 }
1290
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001291 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 * Initializing the sampling rate for the device to calculate the
1293 * bandwidth utilization.
1294 */
1295 val64 = MAC_TX_LINK_UTIL_VAL(tmac_util_period) |
1296 MAC_RX_LINK_UTIL_VAL(rmac_util_period);
1297 writeq(val64, &bar0->mac_link_util);
1298
1299
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001300 /*
1301 * Initializing the Transmit and Receive Traffic Interrupt
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 * Scheme.
1303 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001304 /*
1305 * TTI Initialization. Default Tx timer gets us about
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 * 250 interrupts per sec. Continuous interrupts are enabled
1307 * by default.
1308 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001309 if (nic->device_type == XFRAME_II_DEVICE) {
1310 int count = (nic->config.bus_speed * 125)/2;
1311 val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count);
1312 } else {
1313
1314 val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078);
1315 }
1316 val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 TTI_DATA1_MEM_TX_URNG_B(0x10) |
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001318 TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001319 if (use_continuous_tx_intrs)
1320 val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 writeq(val64, &bar0->tti_data1_mem);
1322
1323 val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
1324 TTI_DATA2_MEM_TX_UFC_B(0x20) |
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001325 TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 writeq(val64, &bar0->tti_data2_mem);
1327
1328 val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
1329 writeq(val64, &bar0->tti_command_mem);
1330
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001331 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 * Once the operation completes, the Strobe bit of the command
1333 * register will be reset. We poll for this particular condition
1334 * We wait for a maximum of 500ms for the operation to complete,
1335 * if it's not complete by then we return error.
1336 */
1337 time = 0;
1338 while (TRUE) {
1339 val64 = readq(&bar0->tti_command_mem);
1340 if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
1341 break;
1342 }
1343 if (time > 10) {
1344 DBG_PRINT(ERR_DBG, "%s: TTI init Failed\n",
1345 dev->name);
1346 return -1;
1347 }
1348 msleep(50);
1349 time++;
1350 }
1351
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001352 if (nic->config.bimodal) {
1353 int k = 0;
1354 for (k = 0; k < config->rx_ring_num; k++) {
1355 val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
1356 val64 |= TTI_CMD_MEM_OFFSET(0x38+k);
1357 writeq(val64, &bar0->tti_command_mem);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001358
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001359 /*
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001360 * Once the operation completes, the Strobe bit of the command
1361 * register will be reset. We poll for this particular condition
1362 * We wait for a maximum of 500ms for the operation to complete,
1363 * if it's not complete by then we return error.
1364 */
1365 time = 0;
1366 while (TRUE) {
1367 val64 = readq(&bar0->tti_command_mem);
1368 if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
1369 break;
1370 }
1371 if (time > 10) {
1372 DBG_PRINT(ERR_DBG,
1373 "%s: TTI init Failed\n",
1374 dev->name);
1375 return -1;
1376 }
1377 time++;
1378 msleep(50);
1379 }
1380 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001381 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001383 /* RTI Initialization */
1384 if (nic->device_type == XFRAME_II_DEVICE) {
1385 /*
1386 * Programmed to generate Apprx 500 Intrs per
1387 * second
1388 */
1389 int count = (nic->config.bus_speed * 125)/4;
1390 val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
1391 } else {
1392 val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 }
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001394 val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
1395 RTI_DATA1_MEM_RX_URNG_B(0x10) |
1396 RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
1397
1398 writeq(val64, &bar0->rti_data1_mem);
1399
1400 val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04001401 RTI_DATA2_MEM_RX_UFC_B(0x2) ;
1402 if (nic->intr_type == MSI_X)
1403 val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
1404 RTI_DATA2_MEM_RX_UFC_D(0x40));
1405 else
1406 val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \
1407 RTI_DATA2_MEM_RX_UFC_D(0x80));
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001408 writeq(val64, &bar0->rti_data2_mem);
1409
1410 for (i = 0; i < config->rx_ring_num; i++) {
1411 val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD
1412 | RTI_CMD_MEM_OFFSET(i);
1413 writeq(val64, &bar0->rti_command_mem);
1414
1415 /*
1416 * Once the operation completes, the Strobe bit of the
1417 * command register will be reset. We poll for this
1418 * particular condition. We wait for a maximum of 500ms
1419 * for the operation to complete, if it's not complete
1420 * by then we return error.
1421 */
1422 time = 0;
1423 while (TRUE) {
1424 val64 = readq(&bar0->rti_command_mem);
1425 if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) {
1426 break;
1427 }
1428 if (time > 10) {
1429 DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
1430 dev->name);
1431 return -1;
1432 }
1433 time++;
1434 msleep(50);
1435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 }
1438
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001439 /*
1440 * Initializing proper values as Pause threshold into all
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 * the 8 Queues on Rx side.
1442 */
1443 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q0q3);
1444 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7);
1445
1446 /* Disable RMAC PAD STRIPPING */
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01001447 add = &bar0->mac_cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 val64 = readq(&bar0->mac_cfg);
1449 val64 &= ~(MAC_CFG_RMAC_STRIP_PAD);
1450 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1451 writel((u32) (val64), add);
1452 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1453 writel((u32) (val64 >> 32), (add + 4));
1454 val64 = readq(&bar0->mac_cfg);
1455
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001456 /*
1457 * Set the time value to be inserted in the pause frame
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 * generated by xena.
1459 */
1460 val64 = readq(&bar0->rmac_pause_cfg);
1461 val64 &= ~(RMAC_PAUSE_HG_PTIME(0xffff));
1462 val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time);
1463 writeq(val64, &bar0->rmac_pause_cfg);
1464
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001465 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 * Set the Threshold Limit for Generating the pause frame
1467 * If the amount of data in any Queue exceeds ratio of
1468 * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256
1469 * pause frame is generated
1470 */
1471 val64 = 0;
1472 for (i = 0; i < 4; i++) {
1473 val64 |=
1474 (((u64) 0xFF00 | nic->mac_control.
1475 mc_pause_threshold_q0q3)
1476 << (i * 2 * 8));
1477 }
1478 writeq(val64, &bar0->mc_pause_thresh_q0q3);
1479
1480 val64 = 0;
1481 for (i = 0; i < 4; i++) {
1482 val64 |=
1483 (((u64) 0xFF00 | nic->mac_control.
1484 mc_pause_threshold_q4q7)
1485 << (i * 2 * 8));
1486 }
1487 writeq(val64, &bar0->mc_pause_thresh_q4q7);
1488
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001489 /*
1490 * TxDMA will stop Read request if the number of read split has
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 * exceeded the limit pointed by shared_splits
1492 */
1493 val64 = readq(&bar0->pic_control);
1494 val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits);
1495 writeq(val64, &bar0->pic_control);
1496
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001497 /*
1498 * Programming the Herc to split every write transaction
1499 * that does not start on an ADB to reduce disconnects.
1500 */
1501 if (nic->device_type == XFRAME_II_DEVICE) {
1502 val64 = WREQ_SPLIT_MASK_SET_MASK(255);
1503 writeq(val64, &bar0->wreq_split_mask);
1504 }
1505
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001506 /* Setting Link stability period to 64 ms */
1507 if (nic->device_type == XFRAME_II_DEVICE) {
1508 val64 = MISC_LINK_STABILITY_PRD(3);
1509 writeq(val64, &bar0->misc_control);
1510 }
1511
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 return SUCCESS;
1513}
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001514#define LINK_UP_DOWN_INTERRUPT 1
1515#define MAC_RMAC_ERR_TIMER 2
1516
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001517int s2io_link_fault_indication(nic_t *nic)
1518{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04001519 if (nic->intr_type != INTA)
1520 return MAC_RMAC_ERR_TIMER;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001521 if (nic->device_type == XFRAME_II_DEVICE)
1522 return LINK_UP_DOWN_INTERRUPT;
1523 else
1524 return MAC_RMAC_ERR_TIMER;
1525}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001527/**
1528 * en_dis_able_nic_intrs - Enable or Disable the interrupts
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 * @nic: device private variable,
1530 * @mask: A mask indicating which Intr block must be modified and,
1531 * @flag: A flag indicating whether to enable or disable the Intrs.
1532 * Description: This function will either disable or enable the interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001533 * depending on the flag argument. The mask argument can be used to
1534 * enable/disable any Intr block.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 * Return Value: NONE.
1536 */
1537
1538static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
1539{
1540 XENA_dev_config_t __iomem *bar0 = nic->bar0;
1541 register u64 val64 = 0, temp64 = 0;
1542
1543 /* Top level interrupt classification */
1544 /* PIC Interrupts */
1545 if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
1546 /* Enable PIC Intrs in the general intr mask register */
1547 val64 = TXPIC_INT_M | PIC_RX_INT_M;
1548 if (flag == ENABLE_INTRS) {
1549 temp64 = readq(&bar0->general_int_mask);
1550 temp64 &= ~((u64) val64);
1551 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001552 /*
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001553 * If Hercules adapter enable GPIO otherwise
1554 * disabled all PCIX, Flash, MDIO, IIC and GPIO
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001555 * interrupts for now.
1556 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001558 if (s2io_link_fault_indication(nic) ==
1559 LINK_UP_DOWN_INTERRUPT ) {
1560 temp64 = readq(&bar0->pic_int_mask);
1561 temp64 &= ~((u64) PIC_INT_GPIO);
1562 writeq(temp64, &bar0->pic_int_mask);
1563 temp64 = readq(&bar0->gpio_int_mask);
1564 temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP);
1565 writeq(temp64, &bar0->gpio_int_mask);
1566 } else {
1567 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
1568 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001569 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 * No MSI Support is available presently, so TTI and
1571 * RTI interrupts are also disabled.
1572 */
1573 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001574 /*
1575 * Disable PIC Intrs in the general
1576 * intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 */
1578 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
1579 temp64 = readq(&bar0->general_int_mask);
1580 val64 |= temp64;
1581 writeq(val64, &bar0->general_int_mask);
1582 }
1583 }
1584
1585 /* DMA Interrupts */
1586 /* Enabling/Disabling Tx DMA interrupts */
1587 if (mask & TX_DMA_INTR) {
1588 /* Enable TxDMA Intrs in the general intr mask register */
1589 val64 = TXDMA_INT_M;
1590 if (flag == ENABLE_INTRS) {
1591 temp64 = readq(&bar0->general_int_mask);
1592 temp64 &= ~((u64) val64);
1593 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001594 /*
1595 * Keep all interrupts other than PFC interrupt
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 * and PCC interrupt disabled in DMA level.
1597 */
1598 val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M |
1599 TXDMA_PCC_INT_M);
1600 writeq(val64, &bar0->txdma_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001601 /*
1602 * Enable only the MISC error 1 interrupt in PFC block
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 */
1604 val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1);
1605 writeq(val64, &bar0->pfc_err_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001606 /*
1607 * Enable only the FB_ECC error interrupt in PCC block
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 */
1609 val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR);
1610 writeq(val64, &bar0->pcc_err_mask);
1611 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001612 /*
1613 * Disable TxDMA Intrs in the general intr mask
1614 * register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 */
1616 writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask);
1617 writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask);
1618 temp64 = readq(&bar0->general_int_mask);
1619 val64 |= temp64;
1620 writeq(val64, &bar0->general_int_mask);
1621 }
1622 }
1623
1624 /* Enabling/Disabling Rx DMA interrupts */
1625 if (mask & RX_DMA_INTR) {
1626 /* Enable RxDMA Intrs in the general intr mask register */
1627 val64 = RXDMA_INT_M;
1628 if (flag == ENABLE_INTRS) {
1629 temp64 = readq(&bar0->general_int_mask);
1630 temp64 &= ~((u64) val64);
1631 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001632 /*
1633 * All RxDMA block interrupts are disabled for now
1634 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 */
1636 writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
1637 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001638 /*
1639 * Disable RxDMA Intrs in the general intr mask
1640 * register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 */
1642 writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
1643 temp64 = readq(&bar0->general_int_mask);
1644 val64 |= temp64;
1645 writeq(val64, &bar0->general_int_mask);
1646 }
1647 }
1648
1649 /* MAC Interrupts */
1650 /* Enabling/Disabling MAC interrupts */
1651 if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
1652 val64 = TXMAC_INT_M | RXMAC_INT_M;
1653 if (flag == ENABLE_INTRS) {
1654 temp64 = readq(&bar0->general_int_mask);
1655 temp64 &= ~((u64) val64);
1656 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001657 /*
1658 * All MAC block error interrupts are disabled for now
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 * TODO
1660 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001662 /*
1663 * Disable MAC Intrs in the general intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 */
1665 writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask);
1666 writeq(DISABLE_ALL_INTRS,
1667 &bar0->mac_rmac_err_mask);
1668
1669 temp64 = readq(&bar0->general_int_mask);
1670 val64 |= temp64;
1671 writeq(val64, &bar0->general_int_mask);
1672 }
1673 }
1674
1675 /* XGXS Interrupts */
1676 if (mask & (TX_XGXS_INTR | RX_XGXS_INTR)) {
1677 val64 = TXXGXS_INT_M | RXXGXS_INT_M;
1678 if (flag == ENABLE_INTRS) {
1679 temp64 = readq(&bar0->general_int_mask);
1680 temp64 &= ~((u64) val64);
1681 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001682 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 * All XGXS block error interrupts are disabled for now
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001684 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 */
1686 writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
1687 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001688 /*
1689 * Disable MC Intrs in the general intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 */
1691 writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
1692 temp64 = readq(&bar0->general_int_mask);
1693 val64 |= temp64;
1694 writeq(val64, &bar0->general_int_mask);
1695 }
1696 }
1697
1698 /* Memory Controller(MC) interrupts */
1699 if (mask & MC_INTR) {
1700 val64 = MC_INT_M;
1701 if (flag == ENABLE_INTRS) {
1702 temp64 = readq(&bar0->general_int_mask);
1703 temp64 &= ~((u64) val64);
1704 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001705 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001706 * Enable all MC Intrs.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 */
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001708 writeq(0x0, &bar0->mc_int_mask);
1709 writeq(0x0, &bar0->mc_err_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 } else if (flag == DISABLE_INTRS) {
1711 /*
1712 * Disable MC Intrs in the general intr mask register
1713 */
1714 writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask);
1715 temp64 = readq(&bar0->general_int_mask);
1716 val64 |= temp64;
1717 writeq(val64, &bar0->general_int_mask);
1718 }
1719 }
1720
1721
1722 /* Tx traffic interrupts */
1723 if (mask & TX_TRAFFIC_INTR) {
1724 val64 = TXTRAFFIC_INT_M;
1725 if (flag == ENABLE_INTRS) {
1726 temp64 = readq(&bar0->general_int_mask);
1727 temp64 &= ~((u64) val64);
1728 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001729 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 * Enable all the Tx side interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001731 * writing 0 Enables all 64 TX interrupt levels
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 */
1733 writeq(0x0, &bar0->tx_traffic_mask);
1734 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001735 /*
1736 * Disable Tx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 * register.
1738 */
1739 writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask);
1740 temp64 = readq(&bar0->general_int_mask);
1741 val64 |= temp64;
1742 writeq(val64, &bar0->general_int_mask);
1743 }
1744 }
1745
1746 /* Rx traffic interrupts */
1747 if (mask & RX_TRAFFIC_INTR) {
1748 val64 = RXTRAFFIC_INT_M;
1749 if (flag == ENABLE_INTRS) {
1750 temp64 = readq(&bar0->general_int_mask);
1751 temp64 &= ~((u64) val64);
1752 writeq(temp64, &bar0->general_int_mask);
1753 /* writing 0 Enables all 8 RX interrupt levels */
1754 writeq(0x0, &bar0->rx_traffic_mask);
1755 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001756 /*
1757 * Disable Rx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 * register.
1759 */
1760 writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask);
1761 temp64 = readq(&bar0->general_int_mask);
1762 val64 |= temp64;
1763 writeq(val64, &bar0->general_int_mask);
1764 }
1765 }
1766}
1767
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001768static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001769{
1770 int ret = 0;
1771
1772 if (flag == FALSE) {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001773 if ((!herc && (rev_id >= 4)) || herc) {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001774 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) &&
1775 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1776 ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
1777 ret = 1;
1778 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001779 }else {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001780 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
1781 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1782 ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
1783 ret = 1;
1784 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001785 }
1786 } else {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001787 if ((!herc && (rev_id >= 4)) || herc) {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001788 if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
1789 ADAPTER_STATUS_RMAC_PCC_IDLE) &&
1790 (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
1791 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1792 ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
1793 ret = 1;
1794 }
1795 } else {
1796 if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
1797 ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
1798 (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
1799 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1800 ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
1801 ret = 1;
1802 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001803 }
1804 }
1805
1806 return ret;
1807}
1808/**
1809 * verify_xena_quiescence - Checks whether the H/W is ready
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 * @val64 : Value read from adapter status register.
1811 * @flag : indicates if the adapter enable bit was ever written once
1812 * before.
1813 * Description: Returns whether the H/W is ready to go or not. Depending
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001814 * on whether adapter enable bit was written or not the comparison
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 * differs and the calling function passes the input argument flag to
1816 * indicate this.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001817 * Return: 1 If xena is quiescence
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 * 0 If Xena is not quiescence
1819 */
1820
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001821static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822{
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001823 int ret = 0, herc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 u64 tmp64 = ~((u64) val64);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001825 int rev_id = get_xena_rev_id(sp->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001827 herc = (sp->device_type == XFRAME_II_DEVICE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 if (!
1829 (tmp64 &
1830 (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY |
1831 ADAPTER_STATUS_PFC_READY | ADAPTER_STATUS_TMAC_BUF_EMPTY |
1832 ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY |
1833 ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK |
1834 ADAPTER_STATUS_P_PLL_LOCK))) {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001835 ret = check_prc_pcc_state(val64, flag, rev_id, herc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 }
1837
1838 return ret;
1839}
1840
1841/**
1842 * fix_mac_address - Fix for Mac addr problem on Alpha platforms
1843 * @sp: Pointer to device specifc structure
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001844 * Description :
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 * New procedure to clear mac address reading problems on Alpha platforms
1846 *
1847 */
1848
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001849void fix_mac_address(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850{
1851 XENA_dev_config_t __iomem *bar0 = sp->bar0;
1852 u64 val64;
1853 int i = 0;
1854
1855 while (fix_mac[i] != END_SIGN) {
1856 writeq(fix_mac[i++], &bar0->gpio_control);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001857 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 val64 = readq(&bar0->gpio_control);
1859 }
1860}
1861
1862/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001863 * start_nic - Turns the device on
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001865 * Description:
1866 * This function actually turns the device on. Before this function is
1867 * called,all Registers are configured from their reset states
1868 * and shared memory is allocated but the NIC is still quiescent. On
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 * calling this function, the device interrupts are cleared and the NIC is
1870 * literally switched on by writing into the adapter control register.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001871 * Return Value:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 * SUCCESS on success and -1 on failure.
1873 */
1874
1875static int start_nic(struct s2io_nic *nic)
1876{
1877 XENA_dev_config_t __iomem *bar0 = nic->bar0;
1878 struct net_device *dev = nic->dev;
1879 register u64 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001880 u16 interruptible;
1881 u16 subid, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 mac_info_t *mac_control;
1883 struct config_param *config;
1884
1885 mac_control = &nic->mac_control;
1886 config = &nic->config;
1887
1888 /* PRC Initialization and configuration */
1889 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001890 writeq((u64) mac_control->rings[i].rx_blocks[0].block_dma_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 &bar0->prc_rxd0_n[i]);
1892
1893 val64 = readq(&bar0->prc_ctrl_n[i]);
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001894 if (nic->config.bimodal)
1895 val64 |= PRC_CTRL_BIMODAL_INTERRUPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896#ifndef CONFIG_2BUFF_MODE
1897 val64 |= PRC_CTRL_RC_ENABLED;
1898#else
1899 val64 |= PRC_CTRL_RC_ENABLED | PRC_CTRL_RING_MODE_3;
1900#endif
1901 writeq(val64, &bar0->prc_ctrl_n[i]);
1902 }
1903
1904#ifdef CONFIG_2BUFF_MODE
1905 /* Enabling 2 buffer mode by writing into Rx_pa_cfg reg. */
1906 val64 = readq(&bar0->rx_pa_cfg);
1907 val64 |= RX_PA_CFG_IGNORE_L2_ERR;
1908 writeq(val64, &bar0->rx_pa_cfg);
1909#endif
1910
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001911 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 * Enabling MC-RLDRAM. After enabling the device, we timeout
1913 * for around 100ms, which is approximately the time required
1914 * for the device to be ready for operation.
1915 */
1916 val64 = readq(&bar0->mc_rldram_mrs);
1917 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE | MC_RLDRAM_MRS_ENABLE;
1918 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
1919 val64 = readq(&bar0->mc_rldram_mrs);
1920
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001921 msleep(100); /* Delay by around 100 ms. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
1923 /* Enabling ECC Protection. */
1924 val64 = readq(&bar0->adapter_control);
1925 val64 &= ~ADAPTER_ECC_EN;
1926 writeq(val64, &bar0->adapter_control);
1927
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001928 /*
1929 * Clearing any possible Link state change interrupts that
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 * could have popped up just before Enabling the card.
1931 */
1932 val64 = readq(&bar0->mac_rmac_err_reg);
1933 if (val64)
1934 writeq(val64, &bar0->mac_rmac_err_reg);
1935
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001936 /*
1937 * Verify if the device is ready to be enabled, if so enable
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 * it.
1939 */
1940 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001941 if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name);
1943 DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n",
1944 (unsigned long long) val64);
1945 return FAILURE;
1946 }
1947
1948 /* Enable select interrupts */
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04001949 if (nic->intr_type != INTA)
1950 en_dis_able_nic_intrs(nic, ENA_ALL_INTRS, DISABLE_INTRS);
1951 else {
1952 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
1953 interruptible |= TX_PIC_INTR | RX_PIC_INTR;
1954 interruptible |= TX_MAC_INTR | RX_MAC_INTR;
1955 en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS);
1956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001958 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 * With some switches, link might be already up at this point.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001960 * Because of this weird behavior, when we enable laser,
1961 * we may not get link. We need to handle this. We cannot
1962 * figure out which switch is misbehaving. So we are forced to
1963 * make a global change.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 */
1965
1966 /* Enabling Laser. */
1967 val64 = readq(&bar0->adapter_control);
1968 val64 |= ADAPTER_EOI_TX_ON;
1969 writeq(val64, &bar0->adapter_control);
1970
1971 /* SXE-002: Initialize link and activity LED */
1972 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001973 if (((subid & 0xFF) >= 0x07) &&
1974 (nic->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 val64 = readq(&bar0->gpio_control);
1976 val64 |= 0x0000800000000000ULL;
1977 writeq(val64, &bar0->gpio_control);
1978 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01001979 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 }
1981
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001982 /*
1983 * Don't see link state interrupts on certain switches, so
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 * directly scheduling a link state task from here.
1985 */
1986 schedule_work(&nic->set_link_task);
1987
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 return SUCCESS;
1989}
1990
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001991/**
1992 * free_tx_buffers - Free all queued Tx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001994 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 * Free all queued Tx buffers.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001996 * Return Value: void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997*/
1998
1999static void free_tx_buffers(struct s2io_nic *nic)
2000{
2001 struct net_device *dev = nic->dev;
2002 struct sk_buff *skb;
2003 TxD_t *txdp;
2004 int i, j;
2005 mac_info_t *mac_control;
2006 struct config_param *config;
raghavendra.koushik@neterion.com1ddc50d2005-08-03 12:30:43 -07002007 int cnt = 0, frg_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008
2009 mac_control = &nic->mac_control;
2010 config = &nic->config;
2011
2012 for (i = 0; i < config->tx_fifo_num; i++) {
2013 for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002014 txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 list_virt_addr;
2016 skb =
2017 (struct sk_buff *) ((unsigned long) txdp->
2018 Host_Control);
2019 if (skb == NULL) {
raghavendra.koushik@neterion.com1ddc50d2005-08-03 12:30:43 -07002020 memset(txdp, 0, sizeof(TxD_t) *
2021 config->max_txds);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 continue;
2023 }
raghavendra.koushik@neterion.com1ddc50d2005-08-03 12:30:43 -07002024 frg_cnt = skb_shinfo(skb)->nr_frags;
2025 pci_unmap_single(nic->pdev, (dma_addr_t)
2026 txdp->Buffer_Pointer,
2027 skb->len - skb->data_len,
2028 PCI_DMA_TODEVICE);
2029 if (frg_cnt) {
2030 TxD_t *temp;
2031 temp = txdp;
2032 txdp++;
2033 for (j = 0; j < frg_cnt; j++, txdp++) {
2034 skb_frag_t *frag =
2035 &skb_shinfo(skb)->frags[j];
2036 pci_unmap_page(nic->pdev,
2037 (dma_addr_t)
2038 txdp->
2039 Buffer_Pointer,
2040 frag->size,
2041 PCI_DMA_TODEVICE);
2042 }
2043 txdp = temp;
2044 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 dev_kfree_skb(skb);
raghavendra.koushik@neterion.com1ddc50d2005-08-03 12:30:43 -07002046 memset(txdp, 0, sizeof(TxD_t) * config->max_txds);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 cnt++;
2048 }
2049 DBG_PRINT(INTR_DBG,
2050 "%s:forcibly freeing %d skbs on FIFO%d\n",
2051 dev->name, cnt, i);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002052 mac_control->fifos[i].tx_curr_get_info.offset = 0;
2053 mac_control->fifos[i].tx_curr_put_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 }
2055}
2056
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002057/**
2058 * stop_nic - To stop the nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 * @nic ; device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002060 * Description:
2061 * This function does exactly the opposite of what the start_nic()
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 * function does. This function is called to stop the device.
2063 * Return Value:
2064 * void.
2065 */
2066
2067static void stop_nic(struct s2io_nic *nic)
2068{
2069 XENA_dev_config_t __iomem *bar0 = nic->bar0;
2070 register u64 val64 = 0;
2071 u16 interruptible, i;
2072 mac_info_t *mac_control;
2073 struct config_param *config;
2074
2075 mac_control = &nic->mac_control;
2076 config = &nic->config;
2077
2078 /* Disable all interrupts */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002079 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07002080 interruptible |= TX_PIC_INTR | RX_PIC_INTR;
2081 interruptible |= TX_MAC_INTR | RX_MAC_INTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
2083
2084 /* Disable PRCs */
2085 for (i = 0; i < config->rx_ring_num; i++) {
2086 val64 = readq(&bar0->prc_ctrl_n[i]);
2087 val64 &= ~((u64) PRC_CTRL_RC_ENABLED);
2088 writeq(val64, &bar0->prc_ctrl_n[i]);
2089 }
2090}
2091
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002092/**
2093 * fill_rx_buffers - Allocates the Rx side skbs
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002095 * @ring_no: ring number
2096 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 * The function allocates Rx side skbs and puts the physical
2098 * address of these buffers into the RxD buffer pointers, so that the NIC
2099 * can DMA the received frame into these locations.
2100 * The NIC supports 3 receive modes, viz
2101 * 1. single buffer,
2102 * 2. three buffer and
2103 * 3. Five buffer modes.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002104 * Each mode defines how many fragments the received frame will be split
2105 * up into by the NIC. The frame is split into L3 header, L4 Header,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 * L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself
2107 * is split into 3 fragments. As of now only single buffer mode is
2108 * supported.
2109 * Return Value:
2110 * SUCCESS on success or an appropriate -ve value on failure.
2111 */
2112
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002113int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114{
2115 struct net_device *dev = nic->dev;
2116 struct sk_buff *skb;
2117 RxD_t *rxdp;
2118 int off, off1, size, block_no, block_no1;
2119 int offset, offset1;
2120 u32 alloc_tab = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002121 u32 alloc_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 mac_info_t *mac_control;
2123 struct config_param *config;
2124#ifdef CONFIG_2BUFF_MODE
2125 RxD_t *rxdpnext;
2126 int nextblk;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002127 u64 tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 buffAdd_t *ba;
2129 dma_addr_t rxdpphys;
2130#endif
2131#ifndef CONFIG_S2IO_NAPI
2132 unsigned long flags;
2133#endif
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002134 RxD_t *first_rxdp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
2136 mac_control = &nic->mac_control;
2137 config = &nic->config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002138 alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
2139 atomic_read(&nic->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
2141 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
2142
2143 while (alloc_tab < alloc_cnt) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002144 block_no = mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 block_index;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002146 block_no1 = mac_control->rings[ring_no].rx_curr_get_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 block_index;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002148 off = mac_control->rings[ring_no].rx_curr_put_info.offset;
2149 off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150#ifndef CONFIG_2BUFF_MODE
2151 offset = block_no * (MAX_RXDS_PER_BLOCK + 1) + off;
2152 offset1 = block_no1 * (MAX_RXDS_PER_BLOCK + 1) + off1;
2153#else
2154 offset = block_no * (MAX_RXDS_PER_BLOCK) + off;
2155 offset1 = block_no1 * (MAX_RXDS_PER_BLOCK) + off1;
2156#endif
2157
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002158 rxdp = mac_control->rings[ring_no].rx_blocks[block_no].
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 block_virt_addr + off;
2160 if ((offset == offset1) && (rxdp->Host_Control)) {
2161 DBG_PRINT(INTR_DBG, "%s: Get and Put", dev->name);
2162 DBG_PRINT(INTR_DBG, " info equated\n");
2163 goto end;
2164 }
2165#ifndef CONFIG_2BUFF_MODE
2166 if (rxdp->Control_1 == END_OF_BLOCK) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002167 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 block_index++;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002169 mac_control->rings[ring_no].rx_curr_put_info.
2170 block_index %= mac_control->rings[ring_no].block_count;
2171 block_no = mac_control->rings[ring_no].rx_curr_put_info.
2172 block_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 off++;
2174 off %= (MAX_RXDS_PER_BLOCK + 1);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002175 mac_control->rings[ring_no].rx_curr_put_info.offset =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 off;
2177 rxdp = (RxD_t *) ((unsigned long) rxdp->Control_2);
2178 DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
2179 dev->name, rxdp);
2180 }
2181#ifndef CONFIG_S2IO_NAPI
2182 spin_lock_irqsave(&nic->put_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002183 mac_control->rings[ring_no].put_pos =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 (block_no * (MAX_RXDS_PER_BLOCK + 1)) + off;
2185 spin_unlock_irqrestore(&nic->put_lock, flags);
2186#endif
2187#else
2188 if (rxdp->Host_Control == END_OF_BLOCK) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002189 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 block_index++;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002191 mac_control->rings[ring_no].rx_curr_put_info.block_index
2192 %= mac_control->rings[ring_no].block_count;
2193 block_no = mac_control->rings[ring_no].rx_curr_put_info
2194 .block_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 off = 0;
2196 DBG_PRINT(INTR_DBG, "%s: block%d at: 0x%llx\n",
2197 dev->name, block_no,
2198 (unsigned long long) rxdp->Control_1);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002199 mac_control->rings[ring_no].rx_curr_put_info.offset =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 off;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002201 rxdp = mac_control->rings[ring_no].rx_blocks[block_no].
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 block_virt_addr;
2203 }
2204#ifndef CONFIG_S2IO_NAPI
2205 spin_lock_irqsave(&nic->put_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002206 mac_control->rings[ring_no].put_pos = (block_no *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 (MAX_RXDS_PER_BLOCK + 1)) + off;
2208 spin_unlock_irqrestore(&nic->put_lock, flags);
2209#endif
2210#endif
2211
2212#ifndef CONFIG_2BUFF_MODE
2213 if (rxdp->Control_1 & RXD_OWN_XENA)
2214#else
2215 if (rxdp->Control_2 & BIT(0))
2216#endif
2217 {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002218 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 offset = off;
2220 goto end;
2221 }
2222#ifdef CONFIG_2BUFF_MODE
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002223 /*
2224 * RxDs Spanning cache lines will be replenished only
2225 * if the succeeding RxD is also owned by Host. It
2226 * will always be the ((8*i)+3) and ((8*i)+6)
2227 * descriptors for the 48 byte descriptor. The offending
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 * decsriptor is of-course the 3rd descriptor.
2229 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002230 rxdpphys = mac_control->rings[ring_no].rx_blocks[block_no].
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 block_dma_addr + (off * sizeof(RxD_t));
2232 if (((u64) (rxdpphys)) % 128 > 80) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002233 rxdpnext = mac_control->rings[ring_no].rx_blocks[block_no].
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 block_virt_addr + (off + 1);
2235 if (rxdpnext->Host_Control == END_OF_BLOCK) {
2236 nextblk = (block_no + 1) %
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002237 (mac_control->rings[ring_no].block_count);
2238 rxdpnext = mac_control->rings[ring_no].rx_blocks
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 [nextblk].block_virt_addr;
2240 }
2241 if (rxdpnext->Control_2 & BIT(0))
2242 goto end;
2243 }
2244#endif
2245
2246#ifndef CONFIG_2BUFF_MODE
2247 skb = dev_alloc_skb(size + NET_IP_ALIGN);
2248#else
2249 skb = dev_alloc_skb(dev->mtu + ALIGN_SIZE + BUF0_LEN + 4);
2250#endif
2251 if (!skb) {
2252 DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
2253 DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002254 if (first_rxdp) {
2255 wmb();
2256 first_rxdp->Control_1 |= RXD_OWN_XENA;
2257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 return -ENOMEM;
2259 }
2260#ifndef CONFIG_2BUFF_MODE
2261 skb_reserve(skb, NET_IP_ALIGN);
2262 memset(rxdp, 0, sizeof(RxD_t));
2263 rxdp->Buffer0_ptr = pci_map_single
2264 (nic->pdev, skb->data, size, PCI_DMA_FROMDEVICE);
2265 rxdp->Control_2 &= (~MASK_BUFFER0_SIZE);
2266 rxdp->Control_2 |= SET_BUFFER0_SIZE(size);
2267 rxdp->Host_Control = (unsigned long) (skb);
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002268 if (alloc_tab & ((1 << rxsync_frequency) - 1))
2269 rxdp->Control_1 |= RXD_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 off++;
2271 off %= (MAX_RXDS_PER_BLOCK + 1);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002272 mac_control->rings[ring_no].rx_curr_put_info.offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002274 ba = &mac_control->rings[ring_no].ba[block_no][off];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 skb_reserve(skb, BUF0_LEN);
David S. Miller689be432005-06-28 15:25:31 -07002276 tmp = ((unsigned long) skb->data & ALIGN_SIZE);
2277 if (tmp)
2278 skb_reserve(skb, (ALIGN_SIZE + 1) - tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279
2280 memset(rxdp, 0, sizeof(RxD_t));
2281 rxdp->Buffer2_ptr = pci_map_single
2282 (nic->pdev, skb->data, dev->mtu + BUF0_LEN + 4,
2283 PCI_DMA_FROMDEVICE);
2284 rxdp->Buffer0_ptr =
2285 pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
2286 PCI_DMA_FROMDEVICE);
2287 rxdp->Buffer1_ptr =
2288 pci_map_single(nic->pdev, ba->ba_1, BUF1_LEN,
2289 PCI_DMA_FROMDEVICE);
2290
2291 rxdp->Control_2 = SET_BUFFER2_SIZE(dev->mtu + 4);
2292 rxdp->Control_2 |= SET_BUFFER0_SIZE(BUF0_LEN);
2293 rxdp->Control_2 |= SET_BUFFER1_SIZE(1); /* dummy. */
2294 rxdp->Control_2 |= BIT(0); /* Set Buffer_Empty bit. */
2295 rxdp->Host_Control = (u64) ((unsigned long) (skb));
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002296 if (alloc_tab & ((1 << rxsync_frequency) - 1))
2297 rxdp->Control_1 |= RXD_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 off++;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002299 mac_control->rings[ring_no].rx_curr_put_info.offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300#endif
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002301 rxdp->Control_2 |= SET_RXD_MARKER;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002302
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002303 if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
2304 if (first_rxdp) {
2305 wmb();
2306 first_rxdp->Control_1 |= RXD_OWN_XENA;
2307 }
2308 first_rxdp = rxdp;
2309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 atomic_inc(&nic->rx_bufs_left[ring_no]);
2311 alloc_tab++;
2312 }
2313
2314 end:
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002315 /* Transfer ownership of first descriptor to adapter just before
2316 * exiting. Before that, use memory barrier so that ownership
2317 * and other fields are seen by adapter correctly.
2318 */
2319 if (first_rxdp) {
2320 wmb();
2321 first_rxdp->Control_1 |= RXD_OWN_XENA;
2322 }
2323
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 return SUCCESS;
2325}
2326
2327/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002328 * free_rx_buffers - Frees all Rx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 * @sp: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002330 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 * This function will free all Rx buffers allocated by host.
2332 * Return Value:
2333 * NONE.
2334 */
2335
2336static void free_rx_buffers(struct s2io_nic *sp)
2337{
2338 struct net_device *dev = sp->dev;
2339 int i, j, blk = 0, off, buf_cnt = 0;
2340 RxD_t *rxdp;
2341 struct sk_buff *skb;
2342 mac_info_t *mac_control;
2343 struct config_param *config;
2344#ifdef CONFIG_2BUFF_MODE
2345 buffAdd_t *ba;
2346#endif
2347
2348 mac_control = &sp->mac_control;
2349 config = &sp->config;
2350
2351 for (i = 0; i < config->rx_ring_num; i++) {
2352 for (j = 0, blk = 0; j < config->rx_cfg[i].num_rxd; j++) {
2353 off = j % (MAX_RXDS_PER_BLOCK + 1);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002354 rxdp = mac_control->rings[i].rx_blocks[blk].
2355 block_virt_addr + off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356
2357#ifndef CONFIG_2BUFF_MODE
2358 if (rxdp->Control_1 == END_OF_BLOCK) {
2359 rxdp =
2360 (RxD_t *) ((unsigned long) rxdp->
2361 Control_2);
2362 j++;
2363 blk++;
2364 }
2365#else
2366 if (rxdp->Host_Control == END_OF_BLOCK) {
2367 blk++;
2368 continue;
2369 }
2370#endif
2371
2372 if (!(rxdp->Control_1 & RXD_OWN_XENA)) {
2373 memset(rxdp, 0, sizeof(RxD_t));
2374 continue;
2375 }
2376
2377 skb =
2378 (struct sk_buff *) ((unsigned long) rxdp->
2379 Host_Control);
2380 if (skb) {
2381#ifndef CONFIG_2BUFF_MODE
2382 pci_unmap_single(sp->pdev, (dma_addr_t)
2383 rxdp->Buffer0_ptr,
2384 dev->mtu +
2385 HEADER_ETHERNET_II_802_3_SIZE
2386 + HEADER_802_2_SIZE +
2387 HEADER_SNAP_SIZE,
2388 PCI_DMA_FROMDEVICE);
2389#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002390 ba = &mac_control->rings[i].ba[blk][off];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 pci_unmap_single(sp->pdev, (dma_addr_t)
2392 rxdp->Buffer0_ptr,
2393 BUF0_LEN,
2394 PCI_DMA_FROMDEVICE);
2395 pci_unmap_single(sp->pdev, (dma_addr_t)
2396 rxdp->Buffer1_ptr,
2397 BUF1_LEN,
2398 PCI_DMA_FROMDEVICE);
2399 pci_unmap_single(sp->pdev, (dma_addr_t)
2400 rxdp->Buffer2_ptr,
2401 dev->mtu + BUF0_LEN + 4,
2402 PCI_DMA_FROMDEVICE);
2403#endif
2404 dev_kfree_skb(skb);
2405 atomic_dec(&sp->rx_bufs_left[i]);
2406 buf_cnt++;
2407 }
2408 memset(rxdp, 0, sizeof(RxD_t));
2409 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002410 mac_control->rings[i].rx_curr_put_info.block_index = 0;
2411 mac_control->rings[i].rx_curr_get_info.block_index = 0;
2412 mac_control->rings[i].rx_curr_put_info.offset = 0;
2413 mac_control->rings[i].rx_curr_get_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 atomic_set(&sp->rx_bufs_left[i], 0);
2415 DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
2416 dev->name, buf_cnt, i);
2417 }
2418}
2419
2420/**
2421 * s2io_poll - Rx interrupt handler for NAPI support
2422 * @dev : pointer to the device structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002423 * @budget : The number of packets that were budgeted to be processed
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 * during one pass through the 'Poll" function.
2425 * Description:
2426 * Comes into picture only if NAPI support has been incorporated. It does
2427 * the same thing that rx_intr_handler does, but not in a interrupt context
2428 * also It will process only a given number of packets.
2429 * Return value:
2430 * 0 on success and 1 if there are No Rx packets to be processed.
2431 */
2432
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002433#if defined(CONFIG_S2IO_NAPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434static int s2io_poll(struct net_device *dev, int *budget)
2435{
2436 nic_t *nic = dev->priv;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002437 int pkt_cnt = 0, org_pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 mac_info_t *mac_control;
2439 struct config_param *config;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01002440 XENA_dev_config_t __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002441 u64 val64;
2442 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002444 atomic_inc(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 mac_control = &nic->mac_control;
2446 config = &nic->config;
2447
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002448 nic->pkts_to_process = *budget;
2449 if (nic->pkts_to_process > dev->quota)
2450 nic->pkts_to_process = dev->quota;
2451 org_pkts_to_process = nic->pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452
2453 val64 = readq(&bar0->rx_traffic_int);
2454 writeq(val64, &bar0->rx_traffic_int);
2455
2456 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002457 rx_intr_handler(&mac_control->rings[i]);
2458 pkt_cnt = org_pkts_to_process - nic->pkts_to_process;
2459 if (!nic->pkts_to_process) {
2460 /* Quota for the current iteration has been met */
2461 goto no_rx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 }
2464 if (!pkt_cnt)
2465 pkt_cnt = 1;
2466
2467 dev->quota -= pkt_cnt;
2468 *budget -= pkt_cnt;
2469 netif_rx_complete(dev);
2470
2471 for (i = 0; i < config->rx_ring_num; i++) {
2472 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2473 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2474 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2475 break;
2476 }
2477 }
2478 /* Re enable the Rx interrupts. */
2479 en_dis_able_nic_intrs(nic, RX_TRAFFIC_INTR, ENABLE_INTRS);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002480 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 return 0;
2482
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002483no_rx:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 dev->quota -= pkt_cnt;
2485 *budget -= pkt_cnt;
2486
2487 for (i = 0; i < config->rx_ring_num; i++) {
2488 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2489 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2490 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2491 break;
2492 }
2493 }
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002494 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 return 1;
2496}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002497#endif
2498
2499/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 * rx_intr_handler - Rx interrupt handler
2501 * @nic: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002502 * Description:
2503 * If the interrupt is because of a received frame or if the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 * receive ring contains fresh as yet un-processed frames,this function is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002505 * called. It picks out the RxD at which place the last Rx processing had
2506 * stopped and sends the skb to the OSM's Rx handler and then increments
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 * the offset.
2508 * Return Value:
2509 * NONE.
2510 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002511static void rx_intr_handler(ring_info_t *ring_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002513 nic_t *nic = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 struct net_device *dev = (struct net_device *) nic->dev;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002515 int get_block, get_offset, put_block, put_offset, ring_bufs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 rx_curr_get_info_t get_info, put_info;
2517 RxD_t *rxdp;
2518 struct sk_buff *skb;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002519#ifndef CONFIG_S2IO_NAPI
2520 int pkt_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521#endif
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002522 spin_lock(&nic->rx_lock);
2523 if (atomic_read(&nic->card_state) == CARD_DOWN) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002524 DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002525 __FUNCTION__, dev->name);
2526 spin_unlock(&nic->rx_lock);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002527 return;
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002528 }
2529
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002530 get_info = ring_data->rx_curr_get_info;
2531 get_block = get_info.block_index;
2532 put_info = ring_data->rx_curr_put_info;
2533 put_block = put_info.block_index;
2534 ring_bufs = get_info.ring_len+1;
2535 rxdp = ring_data->rx_blocks[get_block].block_virt_addr +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 get_info.offset;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002537 get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
2538 get_info.offset;
2539#ifndef CONFIG_S2IO_NAPI
2540 spin_lock(&nic->put_lock);
2541 put_offset = ring_data->put_pos;
2542 spin_unlock(&nic->put_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002544 put_offset = (put_block * (MAX_RXDS_PER_BLOCK + 1)) +
2545 put_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546#endif
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002547 while (RXD_IS_UP2DT(rxdp) &&
2548 (((get_offset + 1) % ring_bufs) != put_offset)) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002549 skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
2550 if (skb == NULL) {
2551 DBG_PRINT(ERR_DBG, "%s: The skb is ",
2552 dev->name);
2553 DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002554 spin_unlock(&nic->rx_lock);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002555 return;
2556 }
2557#ifndef CONFIG_2BUFF_MODE
2558 pci_unmap_single(nic->pdev, (dma_addr_t)
2559 rxdp->Buffer0_ptr,
2560 dev->mtu +
2561 HEADER_ETHERNET_II_802_3_SIZE +
2562 HEADER_802_2_SIZE +
2563 HEADER_SNAP_SIZE,
2564 PCI_DMA_FROMDEVICE);
2565#else
2566 pci_unmap_single(nic->pdev, (dma_addr_t)
2567 rxdp->Buffer0_ptr,
2568 BUF0_LEN, PCI_DMA_FROMDEVICE);
2569 pci_unmap_single(nic->pdev, (dma_addr_t)
2570 rxdp->Buffer1_ptr,
2571 BUF1_LEN, PCI_DMA_FROMDEVICE);
2572 pci_unmap_single(nic->pdev, (dma_addr_t)
2573 rxdp->Buffer2_ptr,
2574 dev->mtu + BUF0_LEN + 4,
2575 PCI_DMA_FROMDEVICE);
2576#endif
2577 rx_osm_handler(ring_data, rxdp);
2578 get_info.offset++;
2579 ring_data->rx_curr_get_info.offset =
2580 get_info.offset;
2581 rxdp = ring_data->rx_blocks[get_block].block_virt_addr +
2582 get_info.offset;
2583 if (get_info.offset &&
2584 (!(get_info.offset % MAX_RXDS_PER_BLOCK))) {
2585 get_info.offset = 0;
2586 ring_data->rx_curr_get_info.offset
2587 = get_info.offset;
2588 get_block++;
2589 get_block %= ring_data->block_count;
2590 ring_data->rx_curr_get_info.block_index
2591 = get_block;
2592 rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
2593 }
2594
2595 get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) +
2596 get_info.offset;
2597#ifdef CONFIG_S2IO_NAPI
2598 nic->pkts_to_process -= 1;
2599 if (!nic->pkts_to_process)
2600 break;
2601#else
2602 pkt_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
2604 break;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002605#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 }
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002607 spin_unlock(&nic->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002609
2610/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 * tx_intr_handler - Transmit interrupt handler
2612 * @nic : device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002613 * Description:
2614 * If an interrupt was raised to indicate DMA complete of the
2615 * Tx packet, this function is called. It identifies the last TxD
2616 * whose buffer was freed and frees all skbs whose data have already
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 * DMA'ed into the NICs internal memory.
2618 * Return Value:
2619 * NONE
2620 */
2621
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002622static void tx_intr_handler(fifo_info_t *fifo_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002624 nic_t *nic = fifo_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 struct net_device *dev = (struct net_device *) nic->dev;
2626 tx_curr_get_info_t get_info, put_info;
2627 struct sk_buff *skb;
2628 TxD_t *txdlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 u16 j, frg_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002631 get_info = fifo_data->tx_curr_get_info;
2632 put_info = fifo_data->tx_curr_put_info;
2633 txdlp = (TxD_t *) fifo_data->list_info[get_info.offset].
2634 list_virt_addr;
2635 while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
2636 (get_info.offset != put_info.offset) &&
2637 (txdlp->Host_Control)) {
2638 /* Check for TxD errors */
2639 if (txdlp->Control_1 & TXD_T_CODE) {
2640 unsigned long long err;
2641 err = txdlp->Control_1 & TXD_T_CODE;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002642 if ((err >> 48) == 0xA) {
2643 DBG_PRINT(TX_DBG, "TxD returned due \
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04002644to loss of link\n");
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002645 }
2646 else {
2647 DBG_PRINT(ERR_DBG, "***TxD error \
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04002648%llx\n", err);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002651
2652 skb = (struct sk_buff *) ((unsigned long)
2653 txdlp->Host_Control);
2654 if (skb == NULL) {
2655 DBG_PRINT(ERR_DBG, "%s: Null skb ",
2656 __FUNCTION__);
2657 DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
2658 return;
2659 }
2660
2661 frg_cnt = skb_shinfo(skb)->nr_frags;
2662 nic->tx_pkt_count++;
2663
2664 pci_unmap_single(nic->pdev, (dma_addr_t)
2665 txdlp->Buffer_Pointer,
2666 skb->len - skb->data_len,
2667 PCI_DMA_TODEVICE);
2668 if (frg_cnt) {
2669 TxD_t *temp;
2670 temp = txdlp;
2671 txdlp++;
2672 for (j = 0; j < frg_cnt; j++, txdlp++) {
2673 skb_frag_t *frag =
2674 &skb_shinfo(skb)->frags[j];
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07002675 if (!txdlp->Buffer_Pointer)
2676 break;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002677 pci_unmap_page(nic->pdev,
2678 (dma_addr_t)
2679 txdlp->
2680 Buffer_Pointer,
2681 frag->size,
2682 PCI_DMA_TODEVICE);
2683 }
2684 txdlp = temp;
2685 }
2686 memset(txdlp, 0,
2687 (sizeof(TxD_t) * fifo_data->max_txds));
2688
2689 /* Updating the statistics block */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002690 nic->stats.tx_bytes += skb->len;
2691 dev_kfree_skb_irq(skb);
2692
2693 get_info.offset++;
2694 get_info.offset %= get_info.fifo_len + 1;
2695 txdlp = (TxD_t *) fifo_data->list_info
2696 [get_info.offset].list_virt_addr;
2697 fifo_data->tx_curr_get_info.offset =
2698 get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 }
2700
2701 spin_lock(&nic->tx_lock);
2702 if (netif_queue_stopped(dev))
2703 netif_wake_queue(dev);
2704 spin_unlock(&nic->tx_lock);
2705}
2706
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002707/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 * alarm_intr_handler - Alarm Interrrupt handler
2709 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002710 * Description: If the interrupt was neither because of Rx packet or Tx
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 * complete, this function is called. If the interrupt was to indicate
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002712 * a loss of link, the OSM link status handler is invoked for any other
2713 * alarm interrupt the block that raised the interrupt is displayed
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 * and a H/W reset is issued.
2715 * Return Value:
2716 * NONE
2717*/
2718
2719static void alarm_intr_handler(struct s2io_nic *nic)
2720{
2721 struct net_device *dev = (struct net_device *) nic->dev;
2722 XENA_dev_config_t __iomem *bar0 = nic->bar0;
2723 register u64 val64 = 0, err_reg = 0;
2724
2725 /* Handling link status change error Intr */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07002726 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
2727 err_reg = readq(&bar0->mac_rmac_err_reg);
2728 writeq(err_reg, &bar0->mac_rmac_err_reg);
2729 if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
2730 schedule_work(&nic->set_link_task);
2731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 }
2733
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002734 /* Handling Ecc errors */
2735 val64 = readq(&bar0->mc_err_reg);
2736 writeq(val64, &bar0->mc_err_reg);
2737 if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
2738 if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002739 nic->mac_control.stats_info->sw_stat.
2740 double_ecc_errs++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002741 DBG_PRINT(INIT_DBG, "%s: Device indicates ",
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002742 dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002743 DBG_PRINT(INIT_DBG, "double ECC error!!\n");
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002744 if (nic->device_type != XFRAME_II_DEVICE) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002745 /* Reset XframeI only if critical error */
2746 if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
2747 MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
2748 netif_stop_queue(dev);
2749 schedule_work(&nic->rst_timer_task);
2750 }
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002751 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002752 } else {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002753 nic->mac_control.stats_info->sw_stat.
2754 single_ecc_errs++;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002755 }
2756 }
2757
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 /* In case of a serious error, the device will be Reset. */
2759 val64 = readq(&bar0->serr_source);
2760 if (val64 & SERR_SOURCE_ANY) {
2761 DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002762 DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
2763 (unsigned long long)val64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 netif_stop_queue(dev);
2765 schedule_work(&nic->rst_timer_task);
2766 }
2767
2768 /*
2769 * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
2770 * Error occurs, the adapter will be recycled by disabling the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002771 * adapter enable bit and enabling it again after the device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 * becomes Quiescent.
2773 */
2774 val64 = readq(&bar0->pcc_err_reg);
2775 writeq(val64, &bar0->pcc_err_reg);
2776 if (val64 & PCC_FB_ECC_DB_ERR) {
2777 u64 ac = readq(&bar0->adapter_control);
2778 ac &= ~(ADAPTER_CNTL_EN);
2779 writeq(ac, &bar0->adapter_control);
2780 ac = readq(&bar0->adapter_control);
2781 schedule_work(&nic->set_link_task);
2782 }
2783
2784 /* Other type of interrupts are not being handled now, TODO */
2785}
2786
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002787/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 * wait_for_cmd_complete - waits for a command to complete.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002789 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002791 * Description: Function that waits for a command to Write into RMAC
2792 * ADDR DATA registers to be completed and returns either success or
2793 * error depending on whether the command was complete or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 * Return value:
2795 * SUCCESS on success and FAILURE on failure.
2796 */
2797
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002798int wait_for_cmd_complete(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799{
2800 XENA_dev_config_t __iomem *bar0 = sp->bar0;
2801 int ret = FAILURE, cnt = 0;
2802 u64 val64;
2803
2804 while (TRUE) {
2805 val64 = readq(&bar0->rmac_addr_cmd_mem);
2806 if (!(val64 & RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
2807 ret = SUCCESS;
2808 break;
2809 }
2810 msleep(50);
2811 if (cnt++ > 10)
2812 break;
2813 }
2814
2815 return ret;
2816}
2817
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002818/**
2819 * s2io_reset - Resets the card.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 * @sp : private member of the device structure.
2821 * Description: Function to Reset the card. This function then also
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002822 * restores the previously saved PCI configuration space registers as
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 * the card reset also resets the configuration space.
2824 * Return value:
2825 * void.
2826 */
2827
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002828void s2io_reset(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829{
2830 XENA_dev_config_t __iomem *bar0 = sp->bar0;
2831 u64 val64;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002832 u16 subid, pci_cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07002834 /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002835 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07002836
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 val64 = SW_RESET_ALL;
2838 writeq(val64, &bar0->sw_reset);
2839
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002840 /*
2841 * At this stage, if the PCI write is indeed completed, the
2842 * card is reset and so is the PCI Config space of the device.
2843 * So a read cannot be issued at this stage on any of the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 * registers to ensure the write into "sw_reset" register
2845 * has gone through.
2846 * Question: Is there any system call that will explicitly force
2847 * all the write commands still pending on the bus to be pushed
2848 * through?
2849 * As of now I'am just giving a 250ms delay and hoping that the
2850 * PCI write to sw_reset register is done by this time.
2851 */
2852 msleep(250);
2853
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002854 /* Restore the PCI state saved during initialization. */
2855 pci_restore_state(sp->pdev);
2856 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07002857 pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 s2io_init_pci(sp);
2859
2860 msleep(250);
2861
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002862 /* Set swapper to enable I/O register access */
2863 s2io_set_swapper(sp);
2864
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04002865 /* Restore the MSIX table entries from local variables */
2866 restore_xmsi_data(sp);
2867
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002868 /* Clear certain PCI/PCI-X fields after reset */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002869 if (sp->device_type == XFRAME_II_DEVICE) {
2870 /* Clear parity err detect bit */
2871 pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002872
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002873 /* Clearing PCIX Ecc status register */
2874 pci_write_config_dword(sp->pdev, 0x68, 0x7C);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002875
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002876 /* Clearing PCI_STATUS error reflected here */
2877 writeq(BIT(62), &bar0->txpic_int_reg);
2878 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002879
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002880 /* Reset device statistics maintained by OS */
2881 memset(&sp->stats, 0, sizeof (struct net_device_stats));
2882
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 /* SXE-002: Configure link and activity LED to turn it off */
2884 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07002885 if (((subid & 0xFF) >= 0x07) &&
2886 (sp->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 val64 = readq(&bar0->gpio_control);
2888 val64 |= 0x0000800000000000ULL;
2889 writeq(val64, &bar0->gpio_control);
2890 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01002891 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 }
2893
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07002894 /*
2895 * Clear spurious ECC interrupts that would have occured on
2896 * XFRAME II cards after reset.
2897 */
2898 if (sp->device_type == XFRAME_II_DEVICE) {
2899 val64 = readq(&bar0->pcc_err_reg);
2900 writeq(val64, &bar0->pcc_err_reg);
2901 }
2902
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 sp->device_enabled_once = FALSE;
2904}
2905
2906/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002907 * s2io_set_swapper - to set the swapper controle on the card
2908 * @sp : private member of the device structure,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 * pointer to the s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002910 * Description: Function to set the swapper control on the card
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 * correctly depending on the 'endianness' of the system.
2912 * Return value:
2913 * SUCCESS on success and FAILURE on failure.
2914 */
2915
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002916int s2io_set_swapper(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917{
2918 struct net_device *dev = sp->dev;
2919 XENA_dev_config_t __iomem *bar0 = sp->bar0;
2920 u64 val64, valt, valr;
2921
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002922 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 * Set proper endian settings and verify the same by reading
2924 * the PIF Feed-back register.
2925 */
2926
2927 val64 = readq(&bar0->pif_rd_swapper_fb);
2928 if (val64 != 0x0123456789ABCDEFULL) {
2929 int i = 0;
2930 u64 value[] = { 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */
2931 0x8100008181000081ULL, /* FE=1, SE=0 */
2932 0x4200004242000042ULL, /* FE=0, SE=1 */
2933 0}; /* FE=0, SE=0 */
2934
2935 while(i<4) {
2936 writeq(value[i], &bar0->swapper_ctrl);
2937 val64 = readq(&bar0->pif_rd_swapper_fb);
2938 if (val64 == 0x0123456789ABCDEFULL)
2939 break;
2940 i++;
2941 }
2942 if (i == 4) {
2943 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
2944 dev->name);
2945 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
2946 (unsigned long long) val64);
2947 return FAILURE;
2948 }
2949 valr = value[i];
2950 } else {
2951 valr = readq(&bar0->swapper_ctrl);
2952 }
2953
2954 valt = 0x0123456789ABCDEFULL;
2955 writeq(valt, &bar0->xmsi_address);
2956 val64 = readq(&bar0->xmsi_address);
2957
2958 if(val64 != valt) {
2959 int i = 0;
2960 u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */
2961 0x0081810000818100ULL, /* FE=1, SE=0 */
2962 0x0042420000424200ULL, /* FE=0, SE=1 */
2963 0}; /* FE=0, SE=0 */
2964
2965 while(i<4) {
2966 writeq((value[i] | valr), &bar0->swapper_ctrl);
2967 writeq(valt, &bar0->xmsi_address);
2968 val64 = readq(&bar0->xmsi_address);
2969 if(val64 == valt)
2970 break;
2971 i++;
2972 }
2973 if(i == 4) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002974 unsigned long long x = val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr ");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002976 DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 return FAILURE;
2978 }
2979 }
2980 val64 = readq(&bar0->swapper_ctrl);
2981 val64 &= 0xFFFF000000000000ULL;
2982
2983#ifdef __BIG_ENDIAN
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002984 /*
2985 * The device by default set to a big endian format, so a
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 * big endian driver need not set anything.
2987 */
2988 val64 |= (SWAPPER_CTRL_TXP_FE |
2989 SWAPPER_CTRL_TXP_SE |
2990 SWAPPER_CTRL_TXD_R_FE |
2991 SWAPPER_CTRL_TXD_W_FE |
2992 SWAPPER_CTRL_TXF_R_FE |
2993 SWAPPER_CTRL_RXD_R_FE |
2994 SWAPPER_CTRL_RXD_W_FE |
2995 SWAPPER_CTRL_RXF_W_FE |
2996 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04002998 if (nic->intr_type == INTA)
2999 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 writeq(val64, &bar0->swapper_ctrl);
3001#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003002 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 * Initially we enable all bits to make it accessible by the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003004 * driver, then we selectively enable only those bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 * we want to set.
3006 */
3007 val64 |= (SWAPPER_CTRL_TXP_FE |
3008 SWAPPER_CTRL_TXP_SE |
3009 SWAPPER_CTRL_TXD_R_FE |
3010 SWAPPER_CTRL_TXD_R_SE |
3011 SWAPPER_CTRL_TXD_W_FE |
3012 SWAPPER_CTRL_TXD_W_SE |
3013 SWAPPER_CTRL_TXF_R_FE |
3014 SWAPPER_CTRL_RXD_R_FE |
3015 SWAPPER_CTRL_RXD_R_SE |
3016 SWAPPER_CTRL_RXD_W_FE |
3017 SWAPPER_CTRL_RXD_W_SE |
3018 SWAPPER_CTRL_RXF_W_FE |
3019 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003021 if (sp->intr_type == INTA)
3022 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 writeq(val64, &bar0->swapper_ctrl);
3024#endif
3025 val64 = readq(&bar0->swapper_ctrl);
3026
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003027 /*
3028 * Verifying if endian settings are accurate by reading a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 * feedback register.
3030 */
3031 val64 = readq(&bar0->pif_rd_swapper_fb);
3032 if (val64 != 0x0123456789ABCDEFULL) {
3033 /* Endian settings are incorrect, calls for another dekko. */
3034 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3035 dev->name);
3036 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3037 (unsigned long long) val64);
3038 return FAILURE;
3039 }
3040
3041 return SUCCESS;
3042}
3043
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003044int wait_for_msix_trans(nic_t *nic, int i)
3045{
3046 XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
3047 u64 val64;
3048 int ret = 0, cnt = 0;
3049
3050 do {
3051 val64 = readq(&bar0->xmsi_access);
3052 if (!(val64 & BIT(15)))
3053 break;
3054 mdelay(1);
3055 cnt++;
3056 } while(cnt < 5);
3057 if (cnt == 5) {
3058 DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i);
3059 ret = 1;
3060 }
3061
3062 return ret;
3063}
3064
3065void restore_xmsi_data(nic_t *nic)
3066{
3067 XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
3068 u64 val64;
3069 int i;
3070
3071 for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
3072 writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
3073 writeq(nic->msix_info[i].data, &bar0->xmsi_data);
3074 val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
3075 writeq(val64, &bar0->xmsi_access);
3076 if (wait_for_msix_trans(nic, i)) {
3077 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3078 continue;
3079 }
3080 }
3081}
3082
3083void store_xmsi_data(nic_t *nic)
3084{
3085 XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
3086 u64 val64, addr, data;
3087 int i;
3088
3089 /* Store and display */
3090 for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
3091 val64 = (BIT(15) | vBIT(i, 26, 6));
3092 writeq(val64, &bar0->xmsi_access);
3093 if (wait_for_msix_trans(nic, i)) {
3094 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3095 continue;
3096 }
3097 addr = readq(&bar0->xmsi_address);
3098 data = readq(&bar0->xmsi_data);
3099 if (addr && data) {
3100 nic->msix_info[i].addr = addr;
3101 nic->msix_info[i].data = data;
3102 }
3103 }
3104}
3105
3106int s2io_enable_msi(nic_t *nic)
3107{
3108 XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
3109 u16 msi_ctrl, msg_val;
3110 struct config_param *config = &nic->config;
3111 struct net_device *dev = nic->dev;
3112 u64 val64, tx_mat, rx_mat;
3113 int i, err;
3114
3115 val64 = readq(&bar0->pic_control);
3116 val64 &= ~BIT(1);
3117 writeq(val64, &bar0->pic_control);
3118
3119 err = pci_enable_msi(nic->pdev);
3120 if (err) {
3121 DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n",
3122 nic->dev->name);
3123 return err;
3124 }
3125
3126 /*
3127 * Enable MSI and use MSI-1 in stead of the standard MSI-0
3128 * for interrupt handling.
3129 */
3130 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3131 msg_val ^= 0x1;
3132 pci_write_config_word(nic->pdev, 0x4c, msg_val);
3133 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3134
3135 pci_read_config_word(nic->pdev, 0x42, &msi_ctrl);
3136 msi_ctrl |= 0x10;
3137 pci_write_config_word(nic->pdev, 0x42, msi_ctrl);
3138
3139 /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */
3140 tx_mat = readq(&bar0->tx_mat0_n[0]);
3141 for (i=0; i<config->tx_fifo_num; i++) {
3142 tx_mat |= TX_MAT_SET(i, 1);
3143 }
3144 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3145
3146 rx_mat = readq(&bar0->rx_mat);
3147 for (i=0; i<config->rx_ring_num; i++) {
3148 rx_mat |= RX_MAT_SET(i, 1);
3149 }
3150 writeq(rx_mat, &bar0->rx_mat);
3151
3152 dev->irq = nic->pdev->irq;
3153 return 0;
3154}
3155
3156int s2io_enable_msi_x(nic_t *nic)
3157{
3158 XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
3159 u64 tx_mat, rx_mat;
3160 u16 msi_control; /* Temp variable */
3161 int ret, i, j, msix_indx = 1;
3162
3163 nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
3164 GFP_KERNEL);
3165 if (nic->entries == NULL) {
3166 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3167 return -ENOMEM;
3168 }
3169 memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
3170
3171 nic->s2io_entries =
3172 kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
3173 GFP_KERNEL);
3174 if (nic->s2io_entries == NULL) {
3175 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3176 kfree(nic->entries);
3177 return -ENOMEM;
3178 }
3179 memset(nic->s2io_entries, 0,
3180 MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
3181
3182 for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
3183 nic->entries[i].entry = i;
3184 nic->s2io_entries[i].entry = i;
3185 nic->s2io_entries[i].arg = NULL;
3186 nic->s2io_entries[i].in_use = 0;
3187 }
3188
3189 tx_mat = readq(&bar0->tx_mat0_n[0]);
3190 for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) {
3191 tx_mat |= TX_MAT_SET(i, msix_indx);
3192 nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i];
3193 nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE;
3194 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3195 }
3196 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3197
3198 if (!nic->config.bimodal) {
3199 rx_mat = readq(&bar0->rx_mat);
3200 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3201 rx_mat |= RX_MAT_SET(j, msix_indx);
3202 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3203 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3204 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3205 }
3206 writeq(rx_mat, &bar0->rx_mat);
3207 } else {
3208 tx_mat = readq(&bar0->tx_mat0_n[7]);
3209 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3210 tx_mat |= TX_MAT_SET(i, msix_indx);
3211 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3212 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3213 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3214 }
3215 writeq(tx_mat, &bar0->tx_mat0_n[7]);
3216 }
3217
3218 ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
3219 if (ret) {
3220 DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
3221 kfree(nic->entries);
3222 kfree(nic->s2io_entries);
3223 nic->entries = NULL;
3224 nic->s2io_entries = NULL;
3225 return -ENOMEM;
3226 }
3227
3228 /*
3229 * To enable MSI-X, MSI also needs to be enabled, due to a bug
3230 * in the herc NIC. (Temp change, needs to be removed later)
3231 */
3232 pci_read_config_word(nic->pdev, 0x42, &msi_control);
3233 msi_control |= 0x1; /* Enable MSI */
3234 pci_write_config_word(nic->pdev, 0x42, msi_control);
3235
3236 return 0;
3237}
3238
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239/* ********************************************************* *
3240 * Functions defined below concern the OS part of the driver *
3241 * ********************************************************* */
3242
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003243/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 * s2io_open - open entry point of the driver
3245 * @dev : pointer to the device structure.
3246 * Description:
3247 * This function is the open entry point of the driver. It mainly calls a
3248 * function to allocate Rx buffers and inserts them into the buffer
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003249 * descriptors and then enables the Rx part of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 * Return value:
3251 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3252 * file on failure.
3253 */
3254
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003255int s2io_open(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256{
3257 nic_t *sp = dev->priv;
3258 int err = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003259 int i;
3260 u16 msi_control; /* Temp variable */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003262 /*
3263 * Make sure you have link off by default every time
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 * Nic is initialized
3265 */
3266 netif_carrier_off(dev);
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003267 sp->last_link_state = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268
3269 /* Initialize H/W and enable interrupts */
3270 if (s2io_card_up(sp)) {
3271 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
3272 dev->name);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003273 err = -ENODEV;
3274 goto hw_init_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 }
3276
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003277 /* Store the values of the MSIX table in the nic_t structure */
3278 store_xmsi_data(sp);
3279
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 /* After proper initialization of H/W, register ISR */
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003281 if (sp->intr_type == MSI) {
3282 err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
3283 SA_SHIRQ, sp->name, dev);
3284 if (err) {
3285 DBG_PRINT(ERR_DBG, "%s: MSI registration \
3286failed\n", dev->name);
3287 goto isr_registration_failed;
3288 }
3289 }
3290 if (sp->intr_type == MSI_X) {
3291 for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
3292 if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
3293 sprintf(sp->desc1, "%s:MSI-X-%d-TX",
3294 dev->name, i);
3295 err = request_irq(sp->entries[i].vector,
3296 s2io_msix_fifo_handle, 0, sp->desc1,
3297 sp->s2io_entries[i].arg);
3298 DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1,
3299 sp->msix_info[i].addr);
3300 } else {
3301 sprintf(sp->desc2, "%s:MSI-X-%d-RX",
3302 dev->name, i);
3303 err = request_irq(sp->entries[i].vector,
3304 s2io_msix_ring_handle, 0, sp->desc2,
3305 sp->s2io_entries[i].arg);
3306 DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2,
3307 sp->msix_info[i].addr);
3308 }
3309 if (err) {
3310 DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \
3311failed\n", dev->name, i);
3312 DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
3313 goto isr_registration_failed;
3314 }
3315 sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
3316 }
3317 }
3318 if (sp->intr_type == INTA) {
3319 err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ,
3320 sp->name, dev);
3321 if (err) {
3322 DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
3323 dev->name);
3324 goto isr_registration_failed;
3325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 }
3327
3328 if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
3329 DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003330 err = -ENODEV;
3331 goto setting_mac_address_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 }
3333
3334 netif_start_queue(dev);
3335 return 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003336
3337setting_mac_address_failed:
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003338 if (sp->intr_type != MSI_X)
3339 free_irq(sp->pdev->irq, dev);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003340isr_registration_failed:
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07003341 del_timer_sync(&sp->alarm_timer);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003342 if (sp->intr_type == MSI_X) {
3343 if (sp->device_type == XFRAME_II_DEVICE) {
3344 for (i=1; (sp->s2io_entries[i].in_use ==
3345 MSIX_REGISTERED_SUCCESS); i++) {
3346 int vector = sp->entries[i].vector;
3347 void *arg = sp->s2io_entries[i].arg;
3348
3349 free_irq(vector, arg);
3350 }
3351 pci_disable_msix(sp->pdev);
3352
3353 /* Temp */
3354 pci_read_config_word(sp->pdev, 0x42, &msi_control);
3355 msi_control &= 0xFFFE; /* Disable MSI */
3356 pci_write_config_word(sp->pdev, 0x42, msi_control);
3357 }
3358 }
3359 else if (sp->intr_type == MSI)
3360 pci_disable_msi(sp->pdev);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003361 s2io_reset(sp);
3362hw_init_failed:
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003363 if (sp->intr_type == MSI_X) {
3364 if (sp->entries)
3365 kfree(sp->entries);
3366 if (sp->s2io_entries)
3367 kfree(sp->s2io_entries);
3368 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003369 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370}
3371
3372/**
3373 * s2io_close -close entry point of the driver
3374 * @dev : device pointer.
3375 * Description:
3376 * This is the stop entry point of the driver. It needs to undo exactly
3377 * whatever was done by the open entry point,thus it's usually referred to
3378 * as the close function.Among other things this function mainly stops the
3379 * Rx side of the NIC and frees all the Rx buffers in the Rx rings.
3380 * Return value:
3381 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3382 * file on failure.
3383 */
3384
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003385int s2io_close(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386{
3387 nic_t *sp = dev->priv;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003388 int i;
3389 u16 msi_control;
3390
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 flush_scheduled_work();
3392 netif_stop_queue(dev);
3393 /* Reset card, kill tasklet and free Tx and Rx buffers. */
3394 s2io_card_down(sp);
3395
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003396 if (sp->intr_type == MSI_X) {
3397 if (sp->device_type == XFRAME_II_DEVICE) {
3398 for (i=1; (sp->s2io_entries[i].in_use ==
3399 MSIX_REGISTERED_SUCCESS); i++) {
3400 int vector = sp->entries[i].vector;
3401 void *arg = sp->s2io_entries[i].arg;
3402
3403 free_irq(vector, arg);
3404 }
3405 pci_read_config_word(sp->pdev, 0x42, &msi_control);
3406 msi_control &= 0xFFFE; /* Disable MSI */
3407 pci_write_config_word(sp->pdev, 0x42, msi_control);
3408
3409 pci_disable_msix(sp->pdev);
3410 }
3411 }
3412 else {
3413 free_irq(sp->pdev->irq, dev);
3414 if (sp->intr_type == MSI)
3415 pci_disable_msi(sp->pdev);
3416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 sp->device_close_flag = TRUE; /* Device is shut down. */
3418 return 0;
3419}
3420
3421/**
3422 * s2io_xmit - Tx entry point of te driver
3423 * @skb : the socket buffer containing the Tx data.
3424 * @dev : device pointer.
3425 * Description :
3426 * This function is the Tx entry point of the driver. S2IO NIC supports
3427 * certain protocol assist features on Tx side, namely CSO, S/G, LSO.
3428 * NOTE: when device cant queue the pkt,just the trans_start variable will
3429 * not be upadted.
3430 * Return value:
3431 * 0 on success & 1 on failure.
3432 */
3433
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003434int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435{
3436 nic_t *sp = dev->priv;
3437 u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
3438 register u64 val64;
3439 TxD_t *txdp;
3440 TxFIFO_element_t __iomem *tx_fifo;
3441 unsigned long flags;
3442#ifdef NETIF_F_TSO
3443 int mss;
3444#endif
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003445 u16 vlan_tag = 0;
3446 int vlan_priority = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 mac_info_t *mac_control;
3448 struct config_param *config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449
3450 mac_control = &sp->mac_control;
3451 config = &sp->config;
3452
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003453 DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 spin_lock_irqsave(&sp->tx_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 if (atomic_read(&sp->card_state) == CARD_DOWN) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003456 DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 dev->name);
3458 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003459 dev_kfree_skb(skb);
3460 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 }
3462
3463 queue = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003465 /* Get Fifo number to Transmit based on vlan priority */
3466 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3467 vlan_tag = vlan_tx_tag_get(skb);
3468 vlan_priority = vlan_tag >> 13;
3469 queue = config->fifo_mapping[vlan_priority];
3470 }
3471
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003472 put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
3473 get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
3474 txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off].
3475 list_virt_addr;
3476
3477 queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 /* Avoid "put" pointer going beyond "get" pointer */
3479 if (txdp->Host_Control || (((put_off + 1) % queue_len) == get_off)) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003480 DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 netif_stop_queue(dev);
3482 dev_kfree_skb(skb);
3483 spin_unlock_irqrestore(&sp->tx_lock, flags);
3484 return 0;
3485 }
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003486
3487 /* A buffer with no data will be dropped */
3488 if (!skb->len) {
3489 DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
3490 dev_kfree_skb(skb);
3491 spin_unlock_irqrestore(&sp->tx_lock, flags);
3492 return 0;
3493 }
3494
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495#ifdef NETIF_F_TSO
3496 mss = skb_shinfo(skb)->tso_size;
3497 if (mss) {
3498 txdp->Control_1 |= TXD_TCP_LSO_EN;
3499 txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
3500 }
3501#endif
3502
3503 frg_cnt = skb_shinfo(skb)->nr_frags;
3504 frg_len = skb->len - skb->data_len;
3505
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 txdp->Buffer_Pointer = pci_map_single
3507 (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003508 txdp->Host_Control = (unsigned long) skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 if (skb->ip_summed == CHECKSUM_HW) {
3510 txdp->Control_2 |=
3511 (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
3512 TXD_TX_CKO_UDP_EN);
3513 }
3514
3515 txdp->Control_2 |= config->tx_intr_type;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07003516
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003517 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3518 txdp->Control_2 |= TXD_VLAN_ENABLE;
3519 txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
3520 }
3521
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 txdp->Control_1 |= (TXD_BUFFER0_SIZE(frg_len) |
3523 TXD_GATHER_CODE_FIRST);
3524 txdp->Control_1 |= TXD_LIST_OWN_XENA;
3525
3526 /* For fragmented SKB. */
3527 for (i = 0; i < frg_cnt; i++) {
3528 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003529 /* A '0' length fragment will be ignored */
3530 if (!frag->size)
3531 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 txdp++;
3533 txdp->Buffer_Pointer = (u64) pci_map_page
3534 (sp->pdev, frag->page, frag->page_offset,
3535 frag->size, PCI_DMA_TODEVICE);
3536 txdp->Control_1 |= TXD_BUFFER0_SIZE(frag->size);
3537 }
3538 txdp->Control_1 |= TXD_GATHER_CODE_LAST;
3539
3540 tx_fifo = mac_control->tx_FIFO_start[queue];
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003541 val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 writeq(val64, &tx_fifo->TxDL_Pointer);
3543
3544 val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
3545 TX_FIFO_LAST_LIST);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003546
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547#ifdef NETIF_F_TSO
3548 if (mss)
3549 val64 |= TX_FIFO_SPECIAL_FUNC;
3550#endif
3551 writeq(val64, &tx_fifo->List_Control);
3552
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003553 mmiowb();
3554
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 put_off++;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003556 put_off %= mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
3557 mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
3559 /* Avoid "put" pointer going beyond "get" pointer */
3560 if (((put_off + 1) % queue_len) == get_off) {
3561 DBG_PRINT(TX_DBG,
3562 "No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
3563 put_off, get_off);
3564 netif_stop_queue(dev);
3565 }
3566
3567 dev->trans_start = jiffies;
3568 spin_unlock_irqrestore(&sp->tx_lock, flags);
3569
3570 return 0;
3571}
3572
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07003573static void
3574s2io_alarm_handle(unsigned long data)
3575{
3576 nic_t *sp = (nic_t *)data;
3577
3578 alarm_intr_handler(sp);
3579 mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
3580}
3581
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003582static irqreturn_t
3583s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs)
3584{
3585 struct net_device *dev = (struct net_device *) dev_id;
3586 nic_t *sp = dev->priv;
3587 int i;
3588 int ret;
3589 mac_info_t *mac_control;
3590 struct config_param *config;
3591
3592 atomic_inc(&sp->isr_cnt);
3593 mac_control = &sp->mac_control;
3594 config = &sp->config;
3595 DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__);
3596
3597 /* If Intr is because of Rx Traffic */
3598 for (i = 0; i < config->rx_ring_num; i++)
3599 rx_intr_handler(&mac_control->rings[i]);
3600
3601 /* If Intr is because of Tx Traffic */
3602 for (i = 0; i < config->tx_fifo_num; i++)
3603 tx_intr_handler(&mac_control->fifos[i]);
3604
3605 /*
3606 * If the Rx buffer count is below the panic threshold then
3607 * reallocate the buffers from the interrupt handler itself,
3608 * else schedule a tasklet to reallocate the buffers.
3609 */
3610 for (i = 0; i < config->rx_ring_num; i++) {
3611 int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
3612 int level = rx_buffer_level(sp, rxb_size, i);
3613
3614 if ((level == PANIC) && (!TASKLET_IN_USE)) {
3615 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name);
3616 DBG_PRINT(INTR_DBG, "PANIC levels\n");
3617 if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
3618 DBG_PRINT(ERR_DBG, "%s:Out of memory",
3619 dev->name);
3620 DBG_PRINT(ERR_DBG, " in ISR!!\n");
3621 clear_bit(0, (&sp->tasklet_status));
3622 atomic_dec(&sp->isr_cnt);
3623 return IRQ_HANDLED;
3624 }
3625 clear_bit(0, (&sp->tasklet_status));
3626 } else if (level == LOW) {
3627 tasklet_schedule(&sp->task);
3628 }
3629 }
3630
3631 atomic_dec(&sp->isr_cnt);
3632 return IRQ_HANDLED;
3633}
3634
3635static irqreturn_t
3636s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs)
3637{
3638 ring_info_t *ring = (ring_info_t *)dev_id;
3639 nic_t *sp = ring->nic;
3640 int rxb_size, level, rng_n;
3641
3642 atomic_inc(&sp->isr_cnt);
3643 rx_intr_handler(ring);
3644
3645 rng_n = ring->ring_no;
3646 rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
3647 level = rx_buffer_level(sp, rxb_size, rng_n);
3648
3649 if ((level == PANIC) && (!TASKLET_IN_USE)) {
3650 int ret;
3651 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
3652 DBG_PRINT(INTR_DBG, "PANIC levels\n");
3653 if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
3654 DBG_PRINT(ERR_DBG, "Out of memory in %s",
3655 __FUNCTION__);
3656 clear_bit(0, (&sp->tasklet_status));
3657 return IRQ_HANDLED;
3658 }
3659 clear_bit(0, (&sp->tasklet_status));
3660 } else if (level == LOW) {
3661 tasklet_schedule(&sp->task);
3662 }
3663 atomic_dec(&sp->isr_cnt);
3664
3665 return IRQ_HANDLED;
3666}
3667
3668static irqreturn_t
3669s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs)
3670{
3671 fifo_info_t *fifo = (fifo_info_t *)dev_id;
3672 nic_t *sp = fifo->nic;
3673
3674 atomic_inc(&sp->isr_cnt);
3675 tx_intr_handler(fifo);
3676 atomic_dec(&sp->isr_cnt);
3677 return IRQ_HANDLED;
3678}
3679
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07003680static void s2io_txpic_intr_handle(nic_t *sp)
3681{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01003682 XENA_dev_config_t __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07003683 u64 val64;
3684
3685 val64 = readq(&bar0->pic_int_status);
3686 if (val64 & PIC_INT_GPIO) {
3687 val64 = readq(&bar0->gpio_int_reg);
3688 if ((val64 & GPIO_INT_REG_LINK_DOWN) &&
3689 (val64 & GPIO_INT_REG_LINK_UP)) {
3690 val64 |= GPIO_INT_REG_LINK_DOWN;
3691 val64 |= GPIO_INT_REG_LINK_UP;
3692 writeq(val64, &bar0->gpio_int_reg);
3693 goto masking;
3694 }
3695
3696 if (((sp->last_link_state == LINK_UP) &&
3697 (val64 & GPIO_INT_REG_LINK_DOWN)) ||
3698 ((sp->last_link_state == LINK_DOWN) &&
3699 (val64 & GPIO_INT_REG_LINK_UP))) {
3700 val64 = readq(&bar0->gpio_int_mask);
3701 val64 |= GPIO_INT_MASK_LINK_DOWN;
3702 val64 |= GPIO_INT_MASK_LINK_UP;
3703 writeq(val64, &bar0->gpio_int_mask);
3704 s2io_set_link((unsigned long)sp);
3705 }
3706masking:
3707 if (sp->last_link_state == LINK_UP) {
3708 /*enable down interrupt */
3709 val64 = readq(&bar0->gpio_int_mask);
3710 /* unmasks link down intr */
3711 val64 &= ~GPIO_INT_MASK_LINK_DOWN;
3712 /* masks link up intr */
3713 val64 |= GPIO_INT_MASK_LINK_UP;
3714 writeq(val64, &bar0->gpio_int_mask);
3715 } else {
3716 /*enable UP Interrupt */
3717 val64 = readq(&bar0->gpio_int_mask);
3718 /* unmasks link up interrupt */
3719 val64 &= ~GPIO_INT_MASK_LINK_UP;
3720 /* masks link down interrupt */
3721 val64 |= GPIO_INT_MASK_LINK_DOWN;
3722 writeq(val64, &bar0->gpio_int_mask);
3723 }
3724 }
3725}
3726
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727/**
3728 * s2io_isr - ISR handler of the device .
3729 * @irq: the irq of the device.
3730 * @dev_id: a void pointer to the dev structure of the NIC.
3731 * @pt_regs: pointer to the registers pushed on the stack.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003732 * Description: This function is the ISR handler of the device. It
3733 * identifies the reason for the interrupt and calls the relevant
3734 * service routines. As a contongency measure, this ISR allocates the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 * recv buffers, if their numbers are below the panic value which is
3736 * presently set to 25% of the original number of rcv buffers allocated.
3737 * Return value:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003738 * IRQ_HANDLED: will be returned if IRQ was handled by this routine
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 * IRQ_NONE: will be returned if interrupt is not from our device
3740 */
3741static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
3742{
3743 struct net_device *dev = (struct net_device *) dev_id;
3744 nic_t *sp = dev->priv;
3745 XENA_dev_config_t __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003746 int i;
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -07003747 u64 reason = 0, val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 mac_info_t *mac_control;
3749 struct config_param *config;
3750
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003751 atomic_inc(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 mac_control = &sp->mac_control;
3753 config = &sp->config;
3754
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003755 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 * Identify the cause for interrupt and call the appropriate
3757 * interrupt handler. Causes for the interrupt could be;
3758 * 1. Rx of packet.
3759 * 2. Tx complete.
3760 * 3. Link down.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003761 * 4. Error in any functional blocks of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 */
3763 reason = readq(&bar0->general_int_status);
3764
3765 if (!reason) {
3766 /* The interrupt was not raised by Xena. */
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003767 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 return IRQ_NONE;
3769 }
3770
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771#ifdef CONFIG_S2IO_NAPI
3772 if (reason & GEN_INTR_RXTRAFFIC) {
3773 if (netif_rx_schedule_prep(dev)) {
3774 en_dis_able_nic_intrs(sp, RX_TRAFFIC_INTR,
3775 DISABLE_INTRS);
3776 __netif_rx_schedule(dev);
3777 }
3778 }
3779#else
3780 /* If Intr is because of Rx Traffic */
3781 if (reason & GEN_INTR_RXTRAFFIC) {
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -07003782 /*
3783 * rx_traffic_int reg is an R1 register, writing all 1's
3784 * will ensure that the actual interrupt causing bit get's
3785 * cleared and hence a read can be avoided.
3786 */
3787 val64 = 0xFFFFFFFFFFFFFFFFULL;
3788 writeq(val64, &bar0->rx_traffic_int);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003789 for (i = 0; i < config->rx_ring_num; i++) {
3790 rx_intr_handler(&mac_control->rings[i]);
3791 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 }
3793#endif
3794
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003795 /* If Intr is because of Tx Traffic */
3796 if (reason & GEN_INTR_TXTRAFFIC) {
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -07003797 /*
3798 * tx_traffic_int reg is an R1 register, writing all 1's
3799 * will ensure that the actual interrupt causing bit get's
3800 * cleared and hence a read can be avoided.
3801 */
3802 val64 = 0xFFFFFFFFFFFFFFFFULL;
3803 writeq(val64, &bar0->tx_traffic_int);
3804
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003805 for (i = 0; i < config->tx_fifo_num; i++)
3806 tx_intr_handler(&mac_control->fifos[i]);
3807 }
3808
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07003809 if (reason & GEN_INTR_TXPIC)
3810 s2io_txpic_intr_handle(sp);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003811 /*
3812 * If the Rx buffer count is below the panic threshold then
3813 * reallocate the buffers from the interrupt handler itself,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 * else schedule a tasklet to reallocate the buffers.
3815 */
3816#ifndef CONFIG_S2IO_NAPI
3817 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003818 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
3820 int level = rx_buffer_level(sp, rxb_size, i);
3821
3822 if ((level == PANIC) && (!TASKLET_IN_USE)) {
3823 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name);
3824 DBG_PRINT(INTR_DBG, "PANIC levels\n");
3825 if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
3826 DBG_PRINT(ERR_DBG, "%s:Out of memory",
3827 dev->name);
3828 DBG_PRINT(ERR_DBG, " in ISR!!\n");
3829 clear_bit(0, (&sp->tasklet_status));
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003830 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 return IRQ_HANDLED;
3832 }
3833 clear_bit(0, (&sp->tasklet_status));
3834 } else if (level == LOW) {
3835 tasklet_schedule(&sp->task);
3836 }
3837 }
3838#endif
3839
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003840 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 return IRQ_HANDLED;
3842}
3843
3844/**
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003845 * s2io_updt_stats -
3846 */
3847static void s2io_updt_stats(nic_t *sp)
3848{
3849 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3850 u64 val64;
3851 int cnt = 0;
3852
3853 if (atomic_read(&sp->card_state) == CARD_UP) {
3854 /* Apprx 30us on a 133 MHz bus */
3855 val64 = SET_UPDT_CLICKS(10) |
3856 STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
3857 writeq(val64, &bar0->stat_cfg);
3858 do {
3859 udelay(100);
3860 val64 = readq(&bar0->stat_cfg);
3861 if (!(val64 & BIT(0)))
3862 break;
3863 cnt++;
3864 if (cnt == 5)
3865 break; /* Updt failed */
3866 } while(1);
3867 }
3868}
3869
3870/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003871 * s2io_get_stats - Updates the device statistics structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 * @dev : pointer to the device structure.
3873 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003874 * This function updates the device statistics structure in the s2io_nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 * structure and returns a pointer to the same.
3876 * Return value:
3877 * pointer to the updated net_device_stats structure.
3878 */
3879
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003880struct net_device_stats *s2io_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881{
3882 nic_t *sp = dev->priv;
3883 mac_info_t *mac_control;
3884 struct config_param *config;
3885
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003886
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 mac_control = &sp->mac_control;
3888 config = &sp->config;
3889
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003890 /* Configure Stats for immediate updt */
3891 s2io_updt_stats(sp);
3892
3893 sp->stats.tx_packets =
3894 le32_to_cpu(mac_control->stats_info->tmac_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003895 sp->stats.tx_errors =
3896 le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
3897 sp->stats.rx_errors =
3898 le32_to_cpu(mac_control->stats_info->rmac_drop_frms);
3899 sp->stats.multicast =
3900 le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 sp->stats.rx_length_errors =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003902 le32_to_cpu(mac_control->stats_info->rmac_long_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903
3904 return (&sp->stats);
3905}
3906
3907/**
3908 * s2io_set_multicast - entry point for multicast address enable/disable.
3909 * @dev : pointer to the device structure
3910 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003911 * This function is a driver entry point which gets called by the kernel
3912 * whenever multicast addresses must be enabled/disabled. This also gets
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 * called to set/reset promiscuous mode. Depending on the deivce flag, we
3914 * determine, if multicast address must be enabled or if promiscuous mode
3915 * is to be disabled etc.
3916 * Return value:
3917 * void.
3918 */
3919
3920static void s2io_set_multicast(struct net_device *dev)
3921{
3922 int i, j, prev_cnt;
3923 struct dev_mc_list *mclist;
3924 nic_t *sp = dev->priv;
3925 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3926 u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
3927 0xfeffffffffffULL;
3928 u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
3929 void __iomem *add;
3930
3931 if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) {
3932 /* Enable all Multicast addresses */
3933 writeq(RMAC_ADDR_DATA0_MEM_ADDR(multi_mac),
3934 &bar0->rmac_addr_data0_mem);
3935 writeq(RMAC_ADDR_DATA1_MEM_MASK(mask),
3936 &bar0->rmac_addr_data1_mem);
3937 val64 = RMAC_ADDR_CMD_MEM_WE |
3938 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
3939 RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
3940 writeq(val64, &bar0->rmac_addr_cmd_mem);
3941 /* Wait till command completes */
3942 wait_for_cmd_complete(sp);
3943
3944 sp->m_cast_flg = 1;
3945 sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
3946 } else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) {
3947 /* Disable all Multicast addresses */
3948 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
3949 &bar0->rmac_addr_data0_mem);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003950 writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0),
3951 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 val64 = RMAC_ADDR_CMD_MEM_WE |
3953 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
3954 RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos);
3955 writeq(val64, &bar0->rmac_addr_cmd_mem);
3956 /* Wait till command completes */
3957 wait_for_cmd_complete(sp);
3958
3959 sp->m_cast_flg = 0;
3960 sp->all_multi_pos = 0;
3961 }
3962
3963 if ((dev->flags & IFF_PROMISC) && (!sp->promisc_flg)) {
3964 /* Put the NIC into promiscuous mode */
3965 add = &bar0->mac_cfg;
3966 val64 = readq(&bar0->mac_cfg);
3967 val64 |= MAC_CFG_RMAC_PROM_ENABLE;
3968
3969 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
3970 writel((u32) val64, add);
3971 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
3972 writel((u32) (val64 >> 32), (add + 4));
3973
3974 val64 = readq(&bar0->mac_cfg);
3975 sp->promisc_flg = 1;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003976 DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 dev->name);
3978 } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) {
3979 /* Remove the NIC from promiscuous mode */
3980 add = &bar0->mac_cfg;
3981 val64 = readq(&bar0->mac_cfg);
3982 val64 &= ~MAC_CFG_RMAC_PROM_ENABLE;
3983
3984 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
3985 writel((u32) val64, add);
3986 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
3987 writel((u32) (val64 >> 32), (add + 4));
3988
3989 val64 = readq(&bar0->mac_cfg);
3990 sp->promisc_flg = 0;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003991 DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 dev->name);
3993 }
3994
3995 /* Update individual M_CAST address list */
3996 if ((!sp->m_cast_flg) && dev->mc_count) {
3997 if (dev->mc_count >
3998 (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) {
3999 DBG_PRINT(ERR_DBG, "%s: No more Rx filters ",
4000 dev->name);
4001 DBG_PRINT(ERR_DBG, "can be added, please enable ");
4002 DBG_PRINT(ERR_DBG, "ALL_MULTI instead\n");
4003 return;
4004 }
4005
4006 prev_cnt = sp->mc_addr_count;
4007 sp->mc_addr_count = dev->mc_count;
4008
4009 /* Clear out the previous list of Mc in the H/W. */
4010 for (i = 0; i < prev_cnt; i++) {
4011 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4012 &bar0->rmac_addr_data0_mem);
4013 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004014 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 val64 = RMAC_ADDR_CMD_MEM_WE |
4016 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4017 RMAC_ADDR_CMD_MEM_OFFSET
4018 (MAC_MC_ADDR_START_OFFSET + i);
4019 writeq(val64, &bar0->rmac_addr_cmd_mem);
4020
4021 /* Wait for command completes */
4022 if (wait_for_cmd_complete(sp)) {
4023 DBG_PRINT(ERR_DBG, "%s: Adding ",
4024 dev->name);
4025 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4026 return;
4027 }
4028 }
4029
4030 /* Create the new Rx filter list and update the same in H/W. */
4031 for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
4032 i++, mclist = mclist->next) {
4033 memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr,
4034 ETH_ALEN);
4035 for (j = 0; j < ETH_ALEN; j++) {
4036 mac_addr |= mclist->dmi_addr[j];
4037 mac_addr <<= 8;
4038 }
4039 mac_addr >>= 8;
4040 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4041 &bar0->rmac_addr_data0_mem);
4042 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004043 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 val64 = RMAC_ADDR_CMD_MEM_WE |
4045 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4046 RMAC_ADDR_CMD_MEM_OFFSET
4047 (i + MAC_MC_ADDR_START_OFFSET);
4048 writeq(val64, &bar0->rmac_addr_cmd_mem);
4049
4050 /* Wait for command completes */
4051 if (wait_for_cmd_complete(sp)) {
4052 DBG_PRINT(ERR_DBG, "%s: Adding ",
4053 dev->name);
4054 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4055 return;
4056 }
4057 }
4058 }
4059}
4060
4061/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004062 * s2io_set_mac_addr - Programs the Xframe mac address
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 * @dev : pointer to the device structure.
4064 * @addr: a uchar pointer to the new mac address which is to be set.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004065 * Description : This procedure will program the Xframe to receive
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 * frames with new Mac Address
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004067 * Return value: SUCCESS on success and an appropriate (-)ve integer
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 * as defined in errno.h file on failure.
4069 */
4070
4071int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
4072{
4073 nic_t *sp = dev->priv;
4074 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4075 register u64 val64, mac_addr = 0;
4076 int i;
4077
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004078 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 * Set the new MAC address as the new unicast filter and reflect this
4080 * change on the device address registered with the OS. It will be
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004081 * at offset 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082 */
4083 for (i = 0; i < ETH_ALEN; i++) {
4084 mac_addr <<= 8;
4085 mac_addr |= addr[i];
4086 }
4087
4088 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4089 &bar0->rmac_addr_data0_mem);
4090
4091 val64 =
4092 RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4093 RMAC_ADDR_CMD_MEM_OFFSET(0);
4094 writeq(val64, &bar0->rmac_addr_cmd_mem);
4095 /* Wait till command completes */
4096 if (wait_for_cmd_complete(sp)) {
4097 DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
4098 return FAILURE;
4099 }
4100
4101 return SUCCESS;
4102}
4103
4104/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004105 * s2io_ethtool_sset - Sets different link parameters.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure.
4107 * @info: pointer to the structure with parameters given by ethtool to set
4108 * link information.
4109 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004110 * The function sets different link parameters provided by the user onto
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 * the NIC.
4112 * Return value:
4113 * 0 on success.
4114*/
4115
4116static int s2io_ethtool_sset(struct net_device *dev,
4117 struct ethtool_cmd *info)
4118{
4119 nic_t *sp = dev->priv;
4120 if ((info->autoneg == AUTONEG_ENABLE) ||
4121 (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
4122 return -EINVAL;
4123 else {
4124 s2io_close(sp->dev);
4125 s2io_open(sp->dev);
4126 }
4127
4128 return 0;
4129}
4130
4131/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004132 * s2io_ethtol_gset - Return link specific information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 * @sp : private member of the device structure, pointer to the
4134 * s2io_nic structure.
4135 * @info : pointer to the structure with parameters given by ethtool
4136 * to return link information.
4137 * Description:
4138 * Returns link specific information like speed, duplex etc.. to ethtool.
4139 * Return value :
4140 * return 0 on success.
4141 */
4142
4143static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
4144{
4145 nic_t *sp = dev->priv;
4146 info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4147 info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4148 info->port = PORT_FIBRE;
4149 /* info->transceiver?? TODO */
4150
4151 if (netif_carrier_ok(sp->dev)) {
4152 info->speed = 10000;
4153 info->duplex = DUPLEX_FULL;
4154 } else {
4155 info->speed = -1;
4156 info->duplex = -1;
4157 }
4158
4159 info->autoneg = AUTONEG_DISABLE;
4160 return 0;
4161}
4162
4163/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004164 * s2io_ethtool_gdrvinfo - Returns driver specific information.
4165 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166 * s2io_nic structure.
4167 * @info : pointer to the structure with parameters given by ethtool to
4168 * return driver information.
4169 * Description:
4170 * Returns driver specefic information like name, version etc.. to ethtool.
4171 * Return value:
4172 * void
4173 */
4174
4175static void s2io_ethtool_gdrvinfo(struct net_device *dev,
4176 struct ethtool_drvinfo *info)
4177{
4178 nic_t *sp = dev->priv;
4179
John W. Linvilledbc23092005-09-28 17:50:51 -04004180 strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
4181 strncpy(info->version, s2io_driver_version, sizeof(info->version));
4182 strncpy(info->fw_version, "", sizeof(info->fw_version));
4183 strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 info->regdump_len = XENA_REG_SPACE;
4185 info->eedump_len = XENA_EEPROM_SPACE;
4186 info->testinfo_len = S2IO_TEST_LEN;
4187 info->n_stats = S2IO_STAT_LEN;
4188}
4189
4190/**
4191 * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004192 * @sp: private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004194 * @regs : pointer to the structure with parameters given by ethtool for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 * dumping the registers.
4196 * @reg_space: The input argumnet into which all the registers are dumped.
4197 * Description:
4198 * Dumps the entire register space of xFrame NIC into the user given
4199 * buffer area.
4200 * Return value :
4201 * void .
4202*/
4203
4204static void s2io_ethtool_gregs(struct net_device *dev,
4205 struct ethtool_regs *regs, void *space)
4206{
4207 int i;
4208 u64 reg;
4209 u8 *reg_space = (u8 *) space;
4210 nic_t *sp = dev->priv;
4211
4212 regs->len = XENA_REG_SPACE;
4213 regs->version = sp->pdev->subsystem_device;
4214
4215 for (i = 0; i < regs->len; i += 8) {
4216 reg = readq(sp->bar0 + i);
4217 memcpy((reg_space + i), &reg, 8);
4218 }
4219}
4220
4221/**
4222 * s2io_phy_id - timer function that alternates adapter LED.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004223 * @data : address of the private member of the device structure, which
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 * is a pointer to the s2io_nic structure, provided as an u32.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004225 * Description: This is actually the timer function that alternates the
4226 * adapter LED bit of the adapter control bit to set/reset every time on
4227 * invocation. The timer is set for 1/2 a second, hence tha NIC blinks
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 * once every second.
4229*/
4230static void s2io_phy_id(unsigned long data)
4231{
4232 nic_t *sp = (nic_t *) data;
4233 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4234 u64 val64 = 0;
4235 u16 subid;
4236
4237 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004238 if ((sp->device_type == XFRAME_II_DEVICE) ||
4239 ((subid & 0xFF) >= 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 val64 = readq(&bar0->gpio_control);
4241 val64 ^= GPIO_CTRL_GPIO_0;
4242 writeq(val64, &bar0->gpio_control);
4243 } else {
4244 val64 = readq(&bar0->adapter_control);
4245 val64 ^= ADAPTER_LED_ON;
4246 writeq(val64, &bar0->adapter_control);
4247 }
4248
4249 mod_timer(&sp->id_timer, jiffies + HZ / 2);
4250}
4251
4252/**
4253 * s2io_ethtool_idnic - To physically identify the nic on the system.
4254 * @sp : private member of the device structure, which is a pointer to the
4255 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004256 * @id : pointer to the structure with identification parameters given by
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257 * ethtool.
4258 * Description: Used to physically identify the NIC on the system.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004259 * The Link LED will blink for a time specified by the user for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 * identification.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004261 * NOTE: The Link has to be Up to be able to blink the LED. Hence
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 * identification is possible only if it's link is up.
4263 * Return value:
4264 * int , returns 0 on success
4265 */
4266
4267static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
4268{
4269 u64 val64 = 0, last_gpio_ctrl_val;
4270 nic_t *sp = dev->priv;
4271 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4272 u16 subid;
4273
4274 subid = sp->pdev->subsystem_device;
4275 last_gpio_ctrl_val = readq(&bar0->gpio_control);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004276 if ((sp->device_type == XFRAME_I_DEVICE) &&
4277 ((subid & 0xFF) < 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 val64 = readq(&bar0->adapter_control);
4279 if (!(val64 & ADAPTER_CNTL_EN)) {
4280 printk(KERN_ERR
4281 "Adapter Link down, cannot blink LED\n");
4282 return -EFAULT;
4283 }
4284 }
4285 if (sp->id_timer.function == NULL) {
4286 init_timer(&sp->id_timer);
4287 sp->id_timer.function = s2io_phy_id;
4288 sp->id_timer.data = (unsigned long) sp;
4289 }
4290 mod_timer(&sp->id_timer, jiffies);
4291 if (data)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004292 msleep_interruptible(data * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004294 msleep_interruptible(MAX_FLICKER_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 del_timer_sync(&sp->id_timer);
4296
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004297 if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 writeq(last_gpio_ctrl_val, &bar0->gpio_control);
4299 last_gpio_ctrl_val = readq(&bar0->gpio_control);
4300 }
4301
4302 return 0;
4303}
4304
4305/**
4306 * s2io_ethtool_getpause_data -Pause frame frame generation and reception.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004307 * @sp : private member of the device structure, which is a pointer to the
4308 * s2io_nic structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 * @ep : pointer to the structure with pause parameters given by ethtool.
4310 * Description:
4311 * Returns the Pause frame generation and reception capability of the NIC.
4312 * Return value:
4313 * void
4314 */
4315static void s2io_ethtool_getpause_data(struct net_device *dev,
4316 struct ethtool_pauseparam *ep)
4317{
4318 u64 val64;
4319 nic_t *sp = dev->priv;
4320 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4321
4322 val64 = readq(&bar0->rmac_pause_cfg);
4323 if (val64 & RMAC_PAUSE_GEN_ENABLE)
4324 ep->tx_pause = TRUE;
4325 if (val64 & RMAC_PAUSE_RX_ENABLE)
4326 ep->rx_pause = TRUE;
4327 ep->autoneg = FALSE;
4328}
4329
4330/**
4331 * s2io_ethtool_setpause_data - set/reset pause frame generation.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004332 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 * s2io_nic structure.
4334 * @ep : pointer to the structure with pause parameters given by ethtool.
4335 * Description:
4336 * It can be used to set or reset Pause frame generation or reception
4337 * support of the NIC.
4338 * Return value:
4339 * int, returns 0 on Success
4340 */
4341
4342static int s2io_ethtool_setpause_data(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004343 struct ethtool_pauseparam *ep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344{
4345 u64 val64;
4346 nic_t *sp = dev->priv;
4347 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4348
4349 val64 = readq(&bar0->rmac_pause_cfg);
4350 if (ep->tx_pause)
4351 val64 |= RMAC_PAUSE_GEN_ENABLE;
4352 else
4353 val64 &= ~RMAC_PAUSE_GEN_ENABLE;
4354 if (ep->rx_pause)
4355 val64 |= RMAC_PAUSE_RX_ENABLE;
4356 else
4357 val64 &= ~RMAC_PAUSE_RX_ENABLE;
4358 writeq(val64, &bar0->rmac_pause_cfg);
4359 return 0;
4360}
4361
4362/**
4363 * read_eeprom - reads 4 bytes of data from user given offset.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004364 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 * s2io_nic structure.
4366 * @off : offset at which the data must be written
4367 * @data : Its an output parameter where the data read at the given
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004368 * offset is stored.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004370 * Will read 4 bytes of data from the user given offset and return the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 * read data.
4372 * NOTE: Will allow to read only part of the EEPROM visible through the
4373 * I2C bus.
4374 * Return value:
4375 * -1 on failure and 0 on success.
4376 */
4377
4378#define S2IO_DEV_ID 5
4379static int read_eeprom(nic_t * sp, int off, u32 * data)
4380{
4381 int ret = -1;
4382 u32 exit_cnt = 0;
4383 u64 val64;
4384 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4385
4386 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4387 I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ |
4388 I2C_CONTROL_CNTL_START;
4389 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
4390
4391 while (exit_cnt < 5) {
4392 val64 = readq(&bar0->i2c_control);
4393 if (I2C_CONTROL_CNTL_END(val64)) {
4394 *data = I2C_CONTROL_GET_DATA(val64);
4395 ret = 0;
4396 break;
4397 }
4398 msleep(50);
4399 exit_cnt++;
4400 }
4401
4402 return ret;
4403}
4404
4405/**
4406 * write_eeprom - actually writes the relevant part of the data value.
4407 * @sp : private member of the device structure, which is a pointer to the
4408 * s2io_nic structure.
4409 * @off : offset at which the data must be written
4410 * @data : The data that is to be written
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004411 * @cnt : Number of bytes of the data that are actually to be written into
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 * the Eeprom. (max of 3)
4413 * Description:
4414 * Actually writes the relevant part of the data value into the Eeprom
4415 * through the I2C bus.
4416 * Return value:
4417 * 0 on success, -1 on failure.
4418 */
4419
4420static int write_eeprom(nic_t * sp, int off, u32 data, int cnt)
4421{
4422 int exit_cnt = 0, ret = -1;
4423 u64 val64;
4424 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4425
4426 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4427 I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA(data) |
4428 I2C_CONTROL_CNTL_START;
4429 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
4430
4431 while (exit_cnt < 5) {
4432 val64 = readq(&bar0->i2c_control);
4433 if (I2C_CONTROL_CNTL_END(val64)) {
4434 if (!(val64 & I2C_CONTROL_NACK))
4435 ret = 0;
4436 break;
4437 }
4438 msleep(50);
4439 exit_cnt++;
4440 }
4441
4442 return ret;
4443}
4444
4445/**
4446 * s2io_ethtool_geeprom - reads the value stored in the Eeprom.
4447 * @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 -07004448 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 * containing all relevant information.
4450 * @data_buf : user defined value to be written into Eeprom.
4451 * Description: Reads the values stored in the Eeprom at given offset
4452 * for a given length. Stores these values int the input argument data
4453 * buffer 'data_buf' and returns these to the caller (ethtool.)
4454 * Return value:
4455 * int 0 on success
4456 */
4457
4458static int s2io_ethtool_geeprom(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004459 struct ethtool_eeprom *eeprom, u8 * data_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460{
4461 u32 data, i, valid;
4462 nic_t *sp = dev->priv;
4463
4464 eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
4465
4466 if ((eeprom->offset + eeprom->len) > (XENA_EEPROM_SPACE))
4467 eeprom->len = XENA_EEPROM_SPACE - eeprom->offset;
4468
4469 for (i = 0; i < eeprom->len; i += 4) {
4470 if (read_eeprom(sp, (eeprom->offset + i), &data)) {
4471 DBG_PRINT(ERR_DBG, "Read of EEPROM failed\n");
4472 return -EFAULT;
4473 }
4474 valid = INV(data);
4475 memcpy((data_buf + i), &valid, 4);
4476 }
4477 return 0;
4478}
4479
4480/**
4481 * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom
4482 * @sp : private member of the device structure, which is a pointer to the
4483 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004484 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 * containing all relevant information.
4486 * @data_buf ; user defined value to be written into Eeprom.
4487 * Description:
4488 * Tries to write the user provided value in the Eeprom, at the offset
4489 * given by the user.
4490 * Return value:
4491 * 0 on success, -EFAULT on failure.
4492 */
4493
4494static int s2io_ethtool_seeprom(struct net_device *dev,
4495 struct ethtool_eeprom *eeprom,
4496 u8 * data_buf)
4497{
4498 int len = eeprom->len, cnt = 0;
4499 u32 valid = 0, data;
4500 nic_t *sp = dev->priv;
4501
4502 if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
4503 DBG_PRINT(ERR_DBG,
4504 "ETHTOOL_WRITE_EEPROM Err: Magic value ");
4505 DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n",
4506 eeprom->magic);
4507 return -EFAULT;
4508 }
4509
4510 while (len) {
4511 data = (u32) data_buf[cnt] & 0x000000FF;
4512 if (data) {
4513 valid = (u32) (data << 24);
4514 } else
4515 valid = data;
4516
4517 if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) {
4518 DBG_PRINT(ERR_DBG,
4519 "ETHTOOL_WRITE_EEPROM Err: Cannot ");
4520 DBG_PRINT(ERR_DBG,
4521 "write into the specified offset\n");
4522 return -EFAULT;
4523 }
4524 cnt++;
4525 len--;
4526 }
4527
4528 return 0;
4529}
4530
4531/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004532 * s2io_register_test - reads and writes into all clock domains.
4533 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534 * s2io_nic structure.
4535 * @data : variable that returns the result of each of the test conducted b
4536 * by the driver.
4537 * Description:
4538 * Read and write into all clock domains. The NIC has 3 clock domains,
4539 * see that registers in all the three regions are accessible.
4540 * Return value:
4541 * 0 on success.
4542 */
4543
4544static int s2io_register_test(nic_t * sp, uint64_t * data)
4545{
4546 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4547 u64 val64 = 0;
4548 int fail = 0;
4549
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004550 val64 = readq(&bar0->pif_rd_swapper_fb);
4551 if (val64 != 0x123456789abcdefULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552 fail = 1;
4553 DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n");
4554 }
4555
4556 val64 = readq(&bar0->rmac_pause_cfg);
4557 if (val64 != 0xc000ffff00000000ULL) {
4558 fail = 1;
4559 DBG_PRINT(INFO_DBG, "Read Test level 2 fails\n");
4560 }
4561
4562 val64 = readq(&bar0->rx_queue_cfg);
4563 if (val64 != 0x0808080808080808ULL) {
4564 fail = 1;
4565 DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n");
4566 }
4567
4568 val64 = readq(&bar0->xgxs_efifo_cfg);
4569 if (val64 != 0x000000001923141EULL) {
4570 fail = 1;
4571 DBG_PRINT(INFO_DBG, "Read Test level 4 fails\n");
4572 }
4573
4574 val64 = 0x5A5A5A5A5A5A5A5AULL;
4575 writeq(val64, &bar0->xmsi_data);
4576 val64 = readq(&bar0->xmsi_data);
4577 if (val64 != 0x5A5A5A5A5A5A5A5AULL) {
4578 fail = 1;
4579 DBG_PRINT(ERR_DBG, "Write Test level 1 fails\n");
4580 }
4581
4582 val64 = 0xA5A5A5A5A5A5A5A5ULL;
4583 writeq(val64, &bar0->xmsi_data);
4584 val64 = readq(&bar0->xmsi_data);
4585 if (val64 != 0xA5A5A5A5A5A5A5A5ULL) {
4586 fail = 1;
4587 DBG_PRINT(ERR_DBG, "Write Test level 2 fails\n");
4588 }
4589
4590 *data = fail;
4591 return 0;
4592}
4593
4594/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004595 * s2io_eeprom_test - to verify that EEprom in the xena can be programmed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 * @sp : private member of the device structure, which is a pointer to the
4597 * s2io_nic structure.
4598 * @data:variable that returns the result of each of the test conducted by
4599 * the driver.
4600 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004601 * Verify that EEPROM in the xena can be programmed using I2C_CONTROL
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 * register.
4603 * Return value:
4604 * 0 on success.
4605 */
4606
4607static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
4608{
4609 int fail = 0;
4610 u32 ret_data;
4611
4612 /* Test Write Error at offset 0 */
4613 if (!write_eeprom(sp, 0, 0, 3))
4614 fail = 1;
4615
4616 /* Test Write at offset 4f0 */
4617 if (write_eeprom(sp, 0x4F0, 0x01234567, 3))
4618 fail = 1;
4619 if (read_eeprom(sp, 0x4F0, &ret_data))
4620 fail = 1;
4621
4622 if (ret_data != 0x01234567)
4623 fail = 1;
4624
4625 /* Reset the EEPROM data go FFFF */
4626 write_eeprom(sp, 0x4F0, 0xFFFFFFFF, 3);
4627
4628 /* Test Write Request Error at offset 0x7c */
4629 if (!write_eeprom(sp, 0x07C, 0, 3))
4630 fail = 1;
4631
4632 /* Test Write Request at offset 0x7fc */
4633 if (write_eeprom(sp, 0x7FC, 0x01234567, 3))
4634 fail = 1;
4635 if (read_eeprom(sp, 0x7FC, &ret_data))
4636 fail = 1;
4637
4638 if (ret_data != 0x01234567)
4639 fail = 1;
4640
4641 /* Reset the EEPROM data go FFFF */
4642 write_eeprom(sp, 0x7FC, 0xFFFFFFFF, 3);
4643
4644 /* Test Write Error at offset 0x80 */
4645 if (!write_eeprom(sp, 0x080, 0, 3))
4646 fail = 1;
4647
4648 /* Test Write Error at offset 0xfc */
4649 if (!write_eeprom(sp, 0x0FC, 0, 3))
4650 fail = 1;
4651
4652 /* Test Write Error at offset 0x100 */
4653 if (!write_eeprom(sp, 0x100, 0, 3))
4654 fail = 1;
4655
4656 /* Test Write Error at offset 4ec */
4657 if (!write_eeprom(sp, 0x4EC, 0, 3))
4658 fail = 1;
4659
4660 *data = fail;
4661 return 0;
4662}
4663
4664/**
4665 * s2io_bist_test - invokes the MemBist test of the card .
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004666 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004668 * @data:variable that returns the result of each of the test conducted by
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 * the driver.
4670 * Description:
4671 * This invokes the MemBist test of the card. We give around
4672 * 2 secs time for the Test to complete. If it's still not complete
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004673 * within this peiod, we consider that the test failed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674 * Return value:
4675 * 0 on success and -1 on failure.
4676 */
4677
4678static int s2io_bist_test(nic_t * sp, uint64_t * data)
4679{
4680 u8 bist = 0;
4681 int cnt = 0, ret = -1;
4682
4683 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
4684 bist |= PCI_BIST_START;
4685 pci_write_config_word(sp->pdev, PCI_BIST, bist);
4686
4687 while (cnt < 20) {
4688 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
4689 if (!(bist & PCI_BIST_START)) {
4690 *data = (bist & PCI_BIST_CODE_MASK);
4691 ret = 0;
4692 break;
4693 }
4694 msleep(100);
4695 cnt++;
4696 }
4697
4698 return ret;
4699}
4700
4701/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004702 * s2io-link_test - verifies the link state of the nic
4703 * @sp ; private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 * s2io_nic structure.
4705 * @data: variable that returns the result of each of the test conducted by
4706 * the driver.
4707 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004708 * The function verifies the link state of the NIC and updates the input
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 * argument 'data' appropriately.
4710 * Return value:
4711 * 0 on success.
4712 */
4713
4714static int s2io_link_test(nic_t * sp, uint64_t * data)
4715{
4716 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4717 u64 val64;
4718
4719 val64 = readq(&bar0->adapter_status);
4720 if (val64 & ADAPTER_STATUS_RMAC_LOCAL_FAULT)
4721 *data = 1;
4722
4723 return 0;
4724}
4725
4726/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004727 * s2io_rldram_test - offline test for access to the RldRam chip on the NIC
4728 * @sp - private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004730 * @data - variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 * conducted by the driver.
4732 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004733 * This is one of the offline test that tests the read and write
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 * access to the RldRam chip on the NIC.
4735 * Return value:
4736 * 0 on success.
4737 */
4738
4739static int s2io_rldram_test(nic_t * sp, uint64_t * data)
4740{
4741 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4742 u64 val64;
4743 int cnt, iteration = 0, test_pass = 0;
4744
4745 val64 = readq(&bar0->adapter_control);
4746 val64 &= ~ADAPTER_ECC_EN;
4747 writeq(val64, &bar0->adapter_control);
4748
4749 val64 = readq(&bar0->mc_rldram_test_ctrl);
4750 val64 |= MC_RLDRAM_TEST_MODE;
4751 writeq(val64, &bar0->mc_rldram_test_ctrl);
4752
4753 val64 = readq(&bar0->mc_rldram_mrs);
4754 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE;
4755 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
4756
4757 val64 |= MC_RLDRAM_MRS_ENABLE;
4758 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
4759
4760 while (iteration < 2) {
4761 val64 = 0x55555555aaaa0000ULL;
4762 if (iteration == 1) {
4763 val64 ^= 0xFFFFFFFFFFFF0000ULL;
4764 }
4765 writeq(val64, &bar0->mc_rldram_test_d0);
4766
4767 val64 = 0xaaaa5a5555550000ULL;
4768 if (iteration == 1) {
4769 val64 ^= 0xFFFFFFFFFFFF0000ULL;
4770 }
4771 writeq(val64, &bar0->mc_rldram_test_d1);
4772
4773 val64 = 0x55aaaaaaaa5a0000ULL;
4774 if (iteration == 1) {
4775 val64 ^= 0xFFFFFFFFFFFF0000ULL;
4776 }
4777 writeq(val64, &bar0->mc_rldram_test_d2);
4778
4779 val64 = (u64) (0x0000003fffff0000ULL);
4780 writeq(val64, &bar0->mc_rldram_test_add);
4781
4782
4783 val64 = MC_RLDRAM_TEST_MODE;
4784 writeq(val64, &bar0->mc_rldram_test_ctrl);
4785
4786 val64 |=
4787 MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE |
4788 MC_RLDRAM_TEST_GO;
4789 writeq(val64, &bar0->mc_rldram_test_ctrl);
4790
4791 for (cnt = 0; cnt < 5; cnt++) {
4792 val64 = readq(&bar0->mc_rldram_test_ctrl);
4793 if (val64 & MC_RLDRAM_TEST_DONE)
4794 break;
4795 msleep(200);
4796 }
4797
4798 if (cnt == 5)
4799 break;
4800
4801 val64 = MC_RLDRAM_TEST_MODE;
4802 writeq(val64, &bar0->mc_rldram_test_ctrl);
4803
4804 val64 |= MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO;
4805 writeq(val64, &bar0->mc_rldram_test_ctrl);
4806
4807 for (cnt = 0; cnt < 5; cnt++) {
4808 val64 = readq(&bar0->mc_rldram_test_ctrl);
4809 if (val64 & MC_RLDRAM_TEST_DONE)
4810 break;
4811 msleep(500);
4812 }
4813
4814 if (cnt == 5)
4815 break;
4816
4817 val64 = readq(&bar0->mc_rldram_test_ctrl);
4818 if (val64 & MC_RLDRAM_TEST_PASS)
4819 test_pass = 1;
4820
4821 iteration++;
4822 }
4823
4824 if (!test_pass)
4825 *data = 1;
4826 else
4827 *data = 0;
4828
4829 return 0;
4830}
4831
4832/**
4833 * s2io_ethtool_test - conducts 6 tsets to determine the health of card.
4834 * @sp : private member of the device structure, which is a pointer to the
4835 * s2io_nic structure.
4836 * @ethtest : pointer to a ethtool command specific structure that will be
4837 * returned to the user.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004838 * @data : variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 * conducted by the driver.
4840 * Description:
4841 * This function conducts 6 tests ( 4 offline and 2 online) to determine
4842 * the health of the card.
4843 * Return value:
4844 * void
4845 */
4846
4847static void s2io_ethtool_test(struct net_device *dev,
4848 struct ethtool_test *ethtest,
4849 uint64_t * data)
4850{
4851 nic_t *sp = dev->priv;
4852 int orig_state = netif_running(sp->dev);
4853
4854 if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
4855 /* Offline Tests. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004856 if (orig_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 s2io_close(sp->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858
4859 if (s2io_register_test(sp, &data[0]))
4860 ethtest->flags |= ETH_TEST_FL_FAILED;
4861
4862 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863
4864 if (s2io_rldram_test(sp, &data[3]))
4865 ethtest->flags |= ETH_TEST_FL_FAILED;
4866
4867 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868
4869 if (s2io_eeprom_test(sp, &data[1]))
4870 ethtest->flags |= ETH_TEST_FL_FAILED;
4871
4872 if (s2io_bist_test(sp, &data[4]))
4873 ethtest->flags |= ETH_TEST_FL_FAILED;
4874
4875 if (orig_state)
4876 s2io_open(sp->dev);
4877
4878 data[2] = 0;
4879 } else {
4880 /* Online Tests. */
4881 if (!orig_state) {
4882 DBG_PRINT(ERR_DBG,
4883 "%s: is not up, cannot run test\n",
4884 dev->name);
4885 data[0] = -1;
4886 data[1] = -1;
4887 data[2] = -1;
4888 data[3] = -1;
4889 data[4] = -1;
4890 }
4891
4892 if (s2io_link_test(sp, &data[2]))
4893 ethtest->flags |= ETH_TEST_FL_FAILED;
4894
4895 data[0] = 0;
4896 data[1] = 0;
4897 data[3] = 0;
4898 data[4] = 0;
4899 }
4900}
4901
4902static void s2io_get_ethtool_stats(struct net_device *dev,
4903 struct ethtool_stats *estats,
4904 u64 * tmp_stats)
4905{
4906 int i = 0;
4907 nic_t *sp = dev->priv;
4908 StatInfo_t *stat_info = sp->mac_control.stats_info;
4909
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004910 s2io_updt_stats(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004911 tmp_stats[i++] =
4912 (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32 |
4913 le32_to_cpu(stat_info->tmac_frms);
4914 tmp_stats[i++] =
4915 (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 |
4916 le32_to_cpu(stat_info->tmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004918 tmp_stats[i++] =
4919 (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 |
4920 le32_to_cpu(stat_info->tmac_mcst_frms);
4921 tmp_stats[i++] =
4922 (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 |
4923 le32_to_cpu(stat_info->tmac_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004925 tmp_stats[i++] =
4926 (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 |
4927 le32_to_cpu(stat_info->tmac_any_err_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004929 tmp_stats[i++] =
4930 (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 |
4931 le32_to_cpu(stat_info->tmac_vld_ip);
4932 tmp_stats[i++] =
4933 (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 |
4934 le32_to_cpu(stat_info->tmac_drop_ip);
4935 tmp_stats[i++] =
4936 (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 |
4937 le32_to_cpu(stat_info->tmac_icmp);
4938 tmp_stats[i++] =
4939 (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 |
4940 le32_to_cpu(stat_info->tmac_rst_tcp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004942 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 |
4943 le32_to_cpu(stat_info->tmac_udp);
4944 tmp_stats[i++] =
4945 (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 |
4946 le32_to_cpu(stat_info->rmac_vld_frms);
4947 tmp_stats[i++] =
4948 (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 |
4949 le32_to_cpu(stat_info->rmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms);
4951 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004952 tmp_stats[i++] =
4953 (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 |
4954 le32_to_cpu(stat_info->rmac_vld_mcst_frms);
4955 tmp_stats[i++] =
4956 (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 |
4957 le32_to_cpu(stat_info->rmac_vld_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004958 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms);
4959 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms);
4960 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004961 tmp_stats[i++] =
4962 (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 |
4963 le32_to_cpu(stat_info->rmac_discarded_frms);
4964 tmp_stats[i++] =
4965 (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 |
4966 le32_to_cpu(stat_info->rmac_usized_frms);
4967 tmp_stats[i++] =
4968 (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 |
4969 le32_to_cpu(stat_info->rmac_osized_frms);
4970 tmp_stats[i++] =
4971 (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 |
4972 le32_to_cpu(stat_info->rmac_frag_frms);
4973 tmp_stats[i++] =
4974 (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 |
4975 le32_to_cpu(stat_info->rmac_jabber_frms);
4976 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 |
4977 le32_to_cpu(stat_info->rmac_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets);
4979 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004980 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 |
4981 le32_to_cpu(stat_info->rmac_drop_ip);
4982 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 |
4983 le32_to_cpu(stat_info->rmac_icmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004985 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 |
4986 le32_to_cpu(stat_info->rmac_udp);
4987 tmp_stats[i++] =
4988 (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 |
4989 le32_to_cpu(stat_info->rmac_err_drp_udp);
4990 tmp_stats[i++] =
4991 (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 |
4992 le32_to_cpu(stat_info->rmac_pause_cnt);
4993 tmp_stats[i++] =
4994 (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 |
4995 le32_to_cpu(stat_info->rmac_accepted_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004997 tmp_stats[i++] = 0;
4998 tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
4999 tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000}
5001
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005002int s2io_ethtool_get_regs_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003{
5004 return (XENA_REG_SPACE);
5005}
5006
5007
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005008u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009{
5010 nic_t *sp = dev->priv;
5011
5012 return (sp->rx_csum);
5013}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005014int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015{
5016 nic_t *sp = dev->priv;
5017
5018 if (data)
5019 sp->rx_csum = 1;
5020 else
5021 sp->rx_csum = 0;
5022
5023 return 0;
5024}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005025int s2io_get_eeprom_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026{
5027 return (XENA_EEPROM_SPACE);
5028}
5029
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005030int s2io_ethtool_self_test_count(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031{
5032 return (S2IO_TEST_LEN);
5033}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005034void s2io_ethtool_get_strings(struct net_device *dev,
5035 u32 stringset, u8 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036{
5037 switch (stringset) {
5038 case ETH_SS_TEST:
5039 memcpy(data, s2io_gstrings, S2IO_STRINGS_LEN);
5040 break;
5041 case ETH_SS_STATS:
5042 memcpy(data, &ethtool_stats_keys,
5043 sizeof(ethtool_stats_keys));
5044 }
5045}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046static int s2io_ethtool_get_stats_count(struct net_device *dev)
5047{
5048 return (S2IO_STAT_LEN);
5049}
5050
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005051int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052{
5053 if (data)
5054 dev->features |= NETIF_F_IP_CSUM;
5055 else
5056 dev->features &= ~NETIF_F_IP_CSUM;
5057
5058 return 0;
5059}
5060
5061
5062static struct ethtool_ops netdev_ethtool_ops = {
5063 .get_settings = s2io_ethtool_gset,
5064 .set_settings = s2io_ethtool_sset,
5065 .get_drvinfo = s2io_ethtool_gdrvinfo,
5066 .get_regs_len = s2io_ethtool_get_regs_len,
5067 .get_regs = s2io_ethtool_gregs,
5068 .get_link = ethtool_op_get_link,
5069 .get_eeprom_len = s2io_get_eeprom_len,
5070 .get_eeprom = s2io_ethtool_geeprom,
5071 .set_eeprom = s2io_ethtool_seeprom,
5072 .get_pauseparam = s2io_ethtool_getpause_data,
5073 .set_pauseparam = s2io_ethtool_setpause_data,
5074 .get_rx_csum = s2io_ethtool_get_rx_csum,
5075 .set_rx_csum = s2io_ethtool_set_rx_csum,
5076 .get_tx_csum = ethtool_op_get_tx_csum,
5077 .set_tx_csum = s2io_ethtool_op_set_tx_csum,
5078 .get_sg = ethtool_op_get_sg,
5079 .set_sg = ethtool_op_set_sg,
5080#ifdef NETIF_F_TSO
5081 .get_tso = ethtool_op_get_tso,
5082 .set_tso = ethtool_op_set_tso,
5083#endif
5084 .self_test_count = s2io_ethtool_self_test_count,
5085 .self_test = s2io_ethtool_test,
5086 .get_strings = s2io_ethtool_get_strings,
5087 .phys_id = s2io_ethtool_idnic,
5088 .get_stats_count = s2io_ethtool_get_stats_count,
5089 .get_ethtool_stats = s2io_get_ethtool_stats
5090};
5091
5092/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005093 * s2io_ioctl - Entry point for the Ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 * @dev : Device pointer.
5095 * @ifr : An IOCTL specefic structure, that can contain a pointer to
5096 * a proprietary structure used to pass information to the driver.
5097 * @cmd : This is used to distinguish between the different commands that
5098 * can be passed to the IOCTL functions.
5099 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005100 * Currently there are no special functionality supported in IOCTL, hence
5101 * function always return EOPNOTSUPPORTED
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 */
5103
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005104int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105{
5106 return -EOPNOTSUPP;
5107}
5108
5109/**
5110 * s2io_change_mtu - entry point to change MTU size for the device.
5111 * @dev : device pointer.
5112 * @new_mtu : the new MTU size for the device.
5113 * Description: A driver entry point to change MTU size for the device.
5114 * Before changing the MTU the device must be stopped.
5115 * Return value:
5116 * 0 on success and an appropriate (-)ve integer as defined in errno.h
5117 * file on failure.
5118 */
5119
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005120int s2io_change_mtu(struct net_device *dev, int new_mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121{
5122 nic_t *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123
5124 if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
5125 DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
5126 dev->name);
5127 return -EPERM;
5128 }
5129
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130 dev->mtu = new_mtu;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005131 if (netif_running(dev)) {
5132 s2io_card_down(sp);
5133 netif_stop_queue(dev);
5134 if (s2io_card_up(sp)) {
5135 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
5136 __FUNCTION__);
5137 }
5138 if (netif_queue_stopped(dev))
5139 netif_wake_queue(dev);
5140 } else { /* Device is down */
5141 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5142 u64 val64 = new_mtu;
5143
5144 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
5145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146
5147 return 0;
5148}
5149
5150/**
5151 * s2io_tasklet - Bottom half of the ISR.
5152 * @dev_adr : address of the device structure in dma_addr_t format.
5153 * Description:
5154 * This is the tasklet or the bottom half of the ISR. This is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005155 * an extension of the ISR which is scheduled by the scheduler to be run
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 * 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 -07005157 * be pushed into the tasklet. For now the tasklet is used only to
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 * replenish the Rx buffers in the Rx buffer descriptors.
5159 * Return value:
5160 * void.
5161 */
5162
5163static void s2io_tasklet(unsigned long dev_addr)
5164{
5165 struct net_device *dev = (struct net_device *) dev_addr;
5166 nic_t *sp = dev->priv;
5167 int i, ret;
5168 mac_info_t *mac_control;
5169 struct config_param *config;
5170
5171 mac_control = &sp->mac_control;
5172 config = &sp->config;
5173
5174 if (!TASKLET_IN_USE) {
5175 for (i = 0; i < config->rx_ring_num; i++) {
5176 ret = fill_rx_buffers(sp, i);
5177 if (ret == -ENOMEM) {
5178 DBG_PRINT(ERR_DBG, "%s: Out of ",
5179 dev->name);
5180 DBG_PRINT(ERR_DBG, "memory in tasklet\n");
5181 break;
5182 } else if (ret == -EFILL) {
5183 DBG_PRINT(ERR_DBG,
5184 "%s: Rx Ring %d is full\n",
5185 dev->name, i);
5186 break;
5187 }
5188 }
5189 clear_bit(0, (&sp->tasklet_status));
5190 }
5191}
5192
5193/**
5194 * s2io_set_link - Set the LInk status
5195 * @data: long pointer to device private structue
5196 * Description: Sets the link status for the adapter
5197 */
5198
5199static void s2io_set_link(unsigned long data)
5200{
5201 nic_t *nic = (nic_t *) data;
5202 struct net_device *dev = nic->dev;
5203 XENA_dev_config_t __iomem *bar0 = nic->bar0;
5204 register u64 val64;
5205 u16 subid;
5206
5207 if (test_and_set_bit(0, &(nic->link_state))) {
5208 /* The card is being reset, no point doing anything */
5209 return;
5210 }
5211
5212 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07005213 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
5214 /*
5215 * Allow a small delay for the NICs self initiated
5216 * cleanup to complete.
5217 */
5218 msleep(100);
5219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220
5221 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005222 if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223 if (LINK_IS_UP(val64)) {
5224 val64 = readq(&bar0->adapter_control);
5225 val64 |= ADAPTER_CNTL_EN;
5226 writeq(val64, &bar0->adapter_control);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005227 if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
5228 subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 val64 = readq(&bar0->gpio_control);
5230 val64 |= GPIO_CTRL_GPIO_0;
5231 writeq(val64, &bar0->gpio_control);
5232 val64 = readq(&bar0->gpio_control);
5233 } else {
5234 val64 |= ADAPTER_LED_ON;
5235 writeq(val64, &bar0->adapter_control);
5236 }
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07005237 if (s2io_link_fault_indication(nic) ==
5238 MAC_RMAC_ERR_TIMER) {
5239 val64 = readq(&bar0->adapter_status);
5240 if (!LINK_IS_UP(val64)) {
5241 DBG_PRINT(ERR_DBG, "%s:", dev->name);
5242 DBG_PRINT(ERR_DBG, " Link down");
5243 DBG_PRINT(ERR_DBG, "after ");
5244 DBG_PRINT(ERR_DBG, "enabling ");
5245 DBG_PRINT(ERR_DBG, "device \n");
5246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 }
5248 if (nic->device_enabled_once == FALSE) {
5249 nic->device_enabled_once = TRUE;
5250 }
5251 s2io_link(nic, LINK_UP);
5252 } else {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005253 if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
5254 subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 val64 = readq(&bar0->gpio_control);
5256 val64 &= ~GPIO_CTRL_GPIO_0;
5257 writeq(val64, &bar0->gpio_control);
5258 val64 = readq(&bar0->gpio_control);
5259 }
5260 s2io_link(nic, LINK_DOWN);
5261 }
5262 } else { /* NIC is not Quiescent. */
5263 DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
5264 DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
5265 netif_stop_queue(dev);
5266 }
5267 clear_bit(0, &(nic->link_state));
5268}
5269
5270static void s2io_card_down(nic_t * sp)
5271{
5272 int cnt = 0;
5273 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5274 unsigned long flags;
5275 register u64 val64 = 0;
5276
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07005277 del_timer_sync(&sp->alarm_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278 /* If s2io_set_link task is executing, wait till it completes. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005279 while (test_and_set_bit(0, &(sp->link_state))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 msleep(50);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005281 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282 atomic_set(&sp->card_state, CARD_DOWN);
5283
5284 /* disable Tx and Rx traffic on the NIC */
5285 stop_nic(sp);
5286
5287 /* Kill tasklet. */
5288 tasklet_kill(&sp->task);
5289
5290 /* Check if the device is Quiescent and then Reset the NIC */
5291 do {
5292 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005293 if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294 break;
5295 }
5296
5297 msleep(50);
5298 cnt++;
5299 if (cnt == 10) {
5300 DBG_PRINT(ERR_DBG,
5301 "s2io_close:Device not Quiescent ");
5302 DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n",
5303 (unsigned long long) val64);
5304 break;
5305 }
5306 } while (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 s2io_reset(sp);
5308
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005309 /* Waiting till all Interrupt handlers are complete */
5310 cnt = 0;
5311 do {
5312 msleep(10);
5313 if (!atomic_read(&sp->isr_cnt))
5314 break;
5315 cnt++;
5316 } while(cnt < 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005318 spin_lock_irqsave(&sp->tx_lock, flags);
5319 /* Free all Tx buffers */
5320 free_tx_buffers(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005322
5323 /* Free all Rx buffers */
5324 spin_lock_irqsave(&sp->rx_lock, flags);
5325 free_rx_buffers(sp);
5326 spin_unlock_irqrestore(&sp->rx_lock, flags);
5327
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328 clear_bit(0, &(sp->link_state));
5329}
5330
5331static int s2io_card_up(nic_t * sp)
5332{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04005333 int i, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334 mac_info_t *mac_control;
5335 struct config_param *config;
5336 struct net_device *dev = (struct net_device *) sp->dev;
5337
5338 /* Initialize the H/W I/O registers */
5339 if (init_nic(sp) != 0) {
5340 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
5341 dev->name);
5342 return -ENODEV;
5343 }
5344
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04005345 if (sp->intr_type == MSI)
5346 ret = s2io_enable_msi(sp);
5347 else if (sp->intr_type == MSI_X)
5348 ret = s2io_enable_msi_x(sp);
5349 if (ret) {
5350 DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
5351 sp->intr_type = INTA;
5352 }
5353
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005354 /*
5355 * Initializing the Rx buffers. For now we are considering only 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 * Rx ring and initializing buffers into 30 Rx blocks
5357 */
5358 mac_control = &sp->mac_control;
5359 config = &sp->config;
5360
5361 for (i = 0; i < config->rx_ring_num; i++) {
5362 if ((ret = fill_rx_buffers(sp, i))) {
5363 DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
5364 dev->name);
5365 s2io_reset(sp);
5366 free_rx_buffers(sp);
5367 return -ENOMEM;
5368 }
5369 DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
5370 atomic_read(&sp->rx_bufs_left[i]));
5371 }
5372
5373 /* Setting its receive mode */
5374 s2io_set_multicast(dev);
5375
5376 /* Enable tasklet for the device */
5377 tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
5378
5379 /* Enable Rx Traffic and interrupts on the NIC */
5380 if (start_nic(sp)) {
5381 DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
5382 tasklet_kill(&sp->task);
5383 s2io_reset(sp);
5384 free_irq(dev->irq, dev);
5385 free_rx_buffers(sp);
5386 return -ENODEV;
5387 }
5388
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07005389 S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
5390
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 atomic_set(&sp->card_state, CARD_UP);
5392 return 0;
5393}
5394
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005395/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 * s2io_restart_nic - Resets the NIC.
5397 * @data : long pointer to the device private structure
5398 * Description:
5399 * This function is scheduled to be run by the s2io_tx_watchdog
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005400 * function after 0.5 secs to reset the NIC. The idea is to reduce
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 * the run time of the watch dog routine which is run holding a
5402 * spin lock.
5403 */
5404
5405static void s2io_restart_nic(unsigned long data)
5406{
5407 struct net_device *dev = (struct net_device *) data;
5408 nic_t *sp = dev->priv;
5409
5410 s2io_card_down(sp);
5411 if (s2io_card_up(sp)) {
5412 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
5413 dev->name);
5414 }
5415 netif_wake_queue(dev);
5416 DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
5417 dev->name);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005418
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419}
5420
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005421/**
5422 * s2io_tx_watchdog - Watchdog for transmit side.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 * @dev : Pointer to net device structure
5424 * Description:
5425 * This function is triggered if the Tx Queue is stopped
5426 * for a pre-defined amount of time when the Interface is still up.
5427 * If the Interface is jammed in such a situation, the hardware is
5428 * reset (by s2io_close) and restarted again (by s2io_open) to
5429 * overcome any problem that might have been caused in the hardware.
5430 * Return value:
5431 * void
5432 */
5433
5434static void s2io_tx_watchdog(struct net_device *dev)
5435{
5436 nic_t *sp = dev->priv;
5437
5438 if (netif_carrier_ok(dev)) {
5439 schedule_work(&sp->rst_timer_task);
5440 }
5441}
5442
5443/**
5444 * rx_osm_handler - To perform some OS related operations on SKB.
5445 * @sp: private member of the device structure,pointer to s2io_nic structure.
5446 * @skb : the socket buffer pointer.
5447 * @len : length of the packet
5448 * @cksum : FCS checksum of the frame.
5449 * @ring_no : the ring from which this RxD was extracted.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005450 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 * This function is called by the Tx interrupt serivce routine to perform
5452 * some OS related operations on the SKB before passing it to the upper
5453 * layers. It mainly checks if the checksum is OK, if so adds it to the
5454 * SKBs cksum variable, increments the Rx packet count and passes the SKB
5455 * to the upper layer. If the checksum is wrong, it increments the Rx
5456 * packet error count, frees the SKB and returns error.
5457 * Return value:
5458 * SUCCESS on success and -1 on failure.
5459 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005460static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005462 nic_t *sp = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463 struct net_device *dev = (struct net_device *) sp->dev;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005464 struct sk_buff *skb = (struct sk_buff *)
5465 ((unsigned long) rxdp->Host_Control);
5466 int ring_no = ring_data->ring_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 u16 l3_csum, l4_csum;
5468#ifdef CONFIG_2BUFF_MODE
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005469 int buf0_len = RXD_GET_BUFFER0_SIZE(rxdp->Control_2);
5470 int buf2_len = RXD_GET_BUFFER2_SIZE(rxdp->Control_2);
5471 int get_block = ring_data->rx_curr_get_info.block_index;
5472 int get_off = ring_data->rx_curr_get_info.offset;
5473 buffAdd_t *ba = &ring_data->ba[get_block][get_off];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 unsigned char *buff;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005475#else
5476 u16 len = (u16) ((RXD_GET_BUFFER0_SIZE(rxdp->Control_2)) >> 48);;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477#endif
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005478 skb->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 if (rxdp->Control_1 & RXD_T_CODE) {
5480 unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
5481 DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
5482 dev->name, err);
raghavendra.koushik@neterion.com1ddc50d2005-08-03 12:30:43 -07005483 dev_kfree_skb(skb);
5484 sp->stats.rx_crc_errors++;
5485 atomic_dec(&sp->rx_bufs_left[ring_no]);
5486 rxdp->Host_Control = 0;
5487 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005490 /* Updating statistics */
5491 rxdp->Host_Control = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 sp->rx_pkt_count++;
5493 sp->stats.rx_packets++;
5494#ifndef CONFIG_2BUFF_MODE
5495 sp->stats.rx_bytes += len;
5496#else
5497 sp->stats.rx_bytes += buf0_len + buf2_len;
5498#endif
5499
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005500#ifndef CONFIG_2BUFF_MODE
5501 skb_put(skb, len);
5502#else
5503 buff = skb_push(skb, buf0_len);
5504 memcpy(buff, ba->ba_0, buf0_len);
5505 skb_put(skb, buf2_len);
5506#endif
5507
5508 if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) &&
5509 (sp->rx_csum)) {
5510 l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
5511 l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
5512 if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) {
5513 /*
5514 * NIC verifies if the Checksum of the received
5515 * frame is Ok or not and accordingly returns
5516 * a flag in the RxD.
5517 */
5518 skb->ip_summed = CHECKSUM_UNNECESSARY;
5519 } else {
5520 /*
5521 * Packet with erroneous checksum, let the
5522 * upper layers deal with it.
5523 */
5524 skb->ip_summed = CHECKSUM_NONE;
5525 }
5526 } else {
5527 skb->ip_summed = CHECKSUM_NONE;
5528 }
5529
5530 skb->protocol = eth_type_trans(skb, dev);
5531#ifdef CONFIG_S2IO_NAPI
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07005532 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
5533 /* Queueing the vlan frame to the upper layer */
5534 vlan_hwaccel_receive_skb(skb, sp->vlgrp,
5535 RXD_GET_VLAN_TAG(rxdp->Control_2));
5536 } else {
5537 netif_receive_skb(skb);
5538 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005539#else
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07005540 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
5541 /* Queueing the vlan frame to the upper layer */
5542 vlan_hwaccel_rx(skb, sp->vlgrp,
5543 RXD_GET_VLAN_TAG(rxdp->Control_2));
5544 } else {
5545 netif_rx(skb);
5546 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005547#endif
5548 dev->last_rx = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 atomic_dec(&sp->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 return SUCCESS;
5551}
5552
5553/**
5554 * s2io_link - stops/starts the Tx queue.
5555 * @sp : private member of the device structure, which is a pointer to the
5556 * s2io_nic structure.
5557 * @link : inidicates whether link is UP/DOWN.
5558 * Description:
5559 * This function stops/starts the Tx queue depending on whether the link
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005560 * status of the NIC is is down or up. This is called by the Alarm
5561 * interrupt handler whenever a link change interrupt comes up.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 * Return value:
5563 * void.
5564 */
5565
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005566void s2io_link(nic_t * sp, int link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567{
5568 struct net_device *dev = (struct net_device *) sp->dev;
5569
5570 if (link != sp->last_link_state) {
5571 if (link == LINK_DOWN) {
5572 DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
5573 netif_carrier_off(dev);
5574 } else {
5575 DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
5576 netif_carrier_on(dev);
5577 }
5578 }
5579 sp->last_link_state = link;
5580}
5581
5582/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005583 * get_xena_rev_id - to identify revision ID of xena.
5584 * @pdev : PCI Dev structure
5585 * Description:
5586 * Function to identify the Revision ID of xena.
5587 * Return value:
5588 * returns the revision ID of the device.
5589 */
5590
5591int get_xena_rev_id(struct pci_dev *pdev)
5592{
5593 u8 id = 0;
5594 int ret;
5595 ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id);
5596 return id;
5597}
5598
5599/**
5600 * s2io_init_pci -Initialization of PCI and PCI-X configuration registers .
5601 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602 * s2io_nic structure.
5603 * Description:
5604 * This function initializes a few of the PCI and PCI-X configuration registers
5605 * with recommended values.
5606 * Return value:
5607 * void
5608 */
5609
5610static void s2io_init_pci(nic_t * sp)
5611{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005612 u16 pci_cmd = 0, pcix_cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613
5614 /* Enable Data Parity Error Recovery in PCI-X command register. */
5615 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005616 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005618 (pcix_cmd | 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005620 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621
5622 /* Set the PErr Response bit in PCI command register. */
5623 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
5624 pci_write_config_word(sp->pdev, PCI_COMMAND,
5625 (pci_cmd | PCI_COMMAND_PARITY));
5626 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
5627
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 /* Forcibly disabling relaxed ordering capability of the card. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005629 pcix_cmd &= 0xfffd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005631 pcix_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005633 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634}
5635
5636MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
5637MODULE_LICENSE("GPL");
5638module_param(tx_fifo_num, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639module_param(rx_ring_num, int, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005640module_param_array(tx_fifo_len, uint, NULL, 0);
5641module_param_array(rx_ring_sz, uint, NULL, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005642module_param_array(rts_frm_len, uint, NULL, 0);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07005643module_param(use_continuous_tx_intrs, int, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644module_param(rmac_pause_time, int, 0);
5645module_param(mc_pause_threshold_q0q3, int, 0);
5646module_param(mc_pause_threshold_q4q7, int, 0);
5647module_param(shared_splits, int, 0);
5648module_param(tmac_util_period, int, 0);
5649module_param(rmac_util_period, int, 0);
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07005650module_param(bimodal, bool, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651#ifndef CONFIG_S2IO_NAPI
5652module_param(indicate_max_pkts, int, 0);
5653#endif
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07005654module_param(rxsync_frequency, int, 0);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04005655module_param(intr_type, int, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005656
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005658 * s2io_init_nic - Initialization of the adapter .
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659 * @pdev : structure containing the PCI related information of the device.
5660 * @pre: List of PCI devices supported by the driver listed in s2io_tbl.
5661 * Description:
5662 * The function initializes an adapter identified by the pci_dec structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005663 * All OS related initialization including memory and device structure and
5664 * initlaization of the device private variable is done. Also the swapper
5665 * control register is initialized to enable read and write into the I/O
Linus Torvalds1da177e2005-04-16 15:20:36 -07005666 * registers of the device.
5667 * Return value:
5668 * returns 0 on success and negative on failure.
5669 */
5670
5671static int __devinit
5672s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
5673{
5674 nic_t *sp;
5675 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 int i, j, ret;
5677 int dma_flag = FALSE;
5678 u32 mac_up, mac_down;
5679 u64 val64 = 0, tmp64 = 0;
5680 XENA_dev_config_t __iomem *bar0 = NULL;
5681 u16 subid;
5682 mac_info_t *mac_control;
5683 struct config_param *config;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005684 int mode;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04005685 u8 dev_intr_type = intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005687#ifdef CONFIG_S2IO_NAPI
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04005688 if (dev_intr_type != INTA) {
5689 DBG_PRINT(ERR_DBG, "NAPI cannot be enabled when MSI/MSI-X \
5690is enabled. Defaulting to INTA\n");
5691 dev_intr_type = INTA;
5692 }
5693 else
5694 DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005695#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696
5697 if ((ret = pci_enable_device(pdev))) {
5698 DBG_PRINT(ERR_DBG,
5699 "s2io_init_nic: pci_enable_device failed\n");
5700 return ret;
5701 }
5702
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04005703 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
5705 dma_flag = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 if (pci_set_consistent_dma_mask
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04005707 (pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708 DBG_PRINT(ERR_DBG,
5709 "Unable to obtain 64bit DMA for \
5710 consistent allocations\n");
5711 pci_disable_device(pdev);
5712 return -ENOMEM;
5713 }
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04005714 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n");
5716 } else {
5717 pci_disable_device(pdev);
5718 return -ENOMEM;
5719 }
5720
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04005721 if ((dev_intr_type == MSI_X) &&
5722 ((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
5723 (pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
5724 DBG_PRINT(ERR_DBG, "Xframe I does not support MSI_X. \
5725Defaulting to INTA\n");
5726 dev_intr_type = INTA;
5727 }
5728 if (dev_intr_type != MSI_X) {
5729 if (pci_request_regions(pdev, s2io_driver_name)) {
5730 DBG_PRINT(ERR_DBG, "Request Regions failed\n"),
5731 pci_disable_device(pdev);
5732 return -ENODEV;
5733 }
5734 }
5735 else {
5736 if (!(request_mem_region(pci_resource_start(pdev, 0),
5737 pci_resource_len(pdev, 0), s2io_driver_name))) {
5738 DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n");
5739 pci_disable_device(pdev);
5740 return -ENODEV;
5741 }
5742 if (!(request_mem_region(pci_resource_start(pdev, 2),
5743 pci_resource_len(pdev, 2), s2io_driver_name))) {
5744 DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n");
5745 release_mem_region(pci_resource_start(pdev, 0),
5746 pci_resource_len(pdev, 0));
5747 pci_disable_device(pdev);
5748 return -ENODEV;
5749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 }
5751
5752 dev = alloc_etherdev(sizeof(nic_t));
5753 if (dev == NULL) {
5754 DBG_PRINT(ERR_DBG, "Device allocation failed\n");
5755 pci_disable_device(pdev);
5756 pci_release_regions(pdev);
5757 return -ENODEV;
5758 }
5759
5760 pci_set_master(pdev);
5761 pci_set_drvdata(pdev, dev);
5762 SET_MODULE_OWNER(dev);
5763 SET_NETDEV_DEV(dev, &pdev->dev);
5764
5765 /* Private member variable initialized to s2io NIC structure */
5766 sp = dev->priv;
5767 memset(sp, 0, sizeof(nic_t));
5768 sp->dev = dev;
5769 sp->pdev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770 sp->high_dma_flag = dma_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771 sp->device_enabled_once = FALSE;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04005772 sp->intr_type = dev_intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005774 if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
5775 (pdev->device == PCI_DEVICE_ID_HERC_UNI))
5776 sp->device_type = XFRAME_II_DEVICE;
5777 else
5778 sp->device_type = XFRAME_I_DEVICE;
5779
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04005780
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781 /* Initialize some PCI/PCI-X fields of the NIC. */
5782 s2io_init_pci(sp);
5783
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005784 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785 * Setting the device configuration parameters.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005786 * Most of these parameters can be specified by the user during
5787 * module insertion as they are module loadable parameters. If
5788 * these parameters are not not specified during load time, they
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789 * are initialized with default values.
5790 */
5791 mac_control = &sp->mac_control;
5792 config = &sp->config;
5793
5794 /* Tx side parameters. */
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07005795 if (tx_fifo_len[0] == 0)
5796 tx_fifo_len[0] = DEFAULT_FIFO_LEN; /* Default value. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797 config->tx_fifo_num = tx_fifo_num;
5798 for (i = 0; i < MAX_TX_FIFOS; i++) {
5799 config->tx_cfg[i].fifo_len = tx_fifo_len[i];
5800 config->tx_cfg[i].fifo_priority = i;
5801 }
5802
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005803 /* mapping the QoS priority to the configured fifos */
5804 for (i = 0; i < MAX_TX_FIFOS; i++)
5805 config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i];
5806
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807 config->tx_intr_type = TXD_INT_TYPE_UTILZ;
5808 for (i = 0; i < config->tx_fifo_num; i++) {
5809 config->tx_cfg[i].f_no_snoop =
5810 (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER);
5811 if (config->tx_cfg[i].fifo_len < 65) {
5812 config->tx_intr_type = TXD_INT_TYPE_PER_LIST;
5813 break;
5814 }
5815 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07005816 config->max_txds = MAX_SKB_FRAGS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817
5818 /* Rx side parameters. */
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07005819 if (rx_ring_sz[0] == 0)
5820 rx_ring_sz[0] = SMALL_BLK_CNT; /* Default value. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821 config->rx_ring_num = rx_ring_num;
5822 for (i = 0; i < MAX_RX_RINGS; i++) {
5823 config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
5824 (MAX_RXDS_PER_BLOCK + 1);
5825 config->rx_cfg[i].ring_priority = i;
5826 }
5827
5828 for (i = 0; i < rx_ring_num; i++) {
5829 config->rx_cfg[i].ring_org = RING_ORG_BUFF1;
5830 config->rx_cfg[i].f_no_snoop =
5831 (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER);
5832 }
5833
5834 /* Setting Mac Control parameters */
5835 mac_control->rmac_pause_time = rmac_pause_time;
5836 mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3;
5837 mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
5838
5839
5840 /* Initialize Ring buffer parameters. */
5841 for (i = 0; i < config->rx_ring_num; i++)
5842 atomic_set(&sp->rx_bufs_left[i], 0);
5843
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005844 /* Initialize the number of ISRs currently running */
5845 atomic_set(&sp->isr_cnt, 0);
5846
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847 /* initialize the shared memory used by the NIC and the host */
5848 if (init_shared_mem(sp)) {
5849 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07005850 __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851 ret = -ENOMEM;
5852 goto mem_alloc_failed;
5853 }
5854
5855 sp->bar0 = ioremap(pci_resource_start(pdev, 0),
5856 pci_resource_len(pdev, 0));
5857 if (!sp->bar0) {
5858 DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem1\n",
5859 dev->name);
5860 ret = -ENOMEM;
5861 goto bar0_remap_failed;
5862 }
5863
5864 sp->bar1 = ioremap(pci_resource_start(pdev, 2),
5865 pci_resource_len(pdev, 2));
5866 if (!sp->bar1) {
5867 DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem2\n",
5868 dev->name);
5869 ret = -ENOMEM;
5870 goto bar1_remap_failed;
5871 }
5872
5873 dev->irq = pdev->irq;
5874 dev->base_addr = (unsigned long) sp->bar0;
5875
5876 /* Initializing the BAR1 address as the start of the FIFO pointer. */
5877 for (j = 0; j < MAX_TX_FIFOS; j++) {
5878 mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *)
5879 (sp->bar1 + (j * 0x00020000));
5880 }
5881
5882 /* Driver entry points */
5883 dev->open = &s2io_open;
5884 dev->stop = &s2io_close;
5885 dev->hard_start_xmit = &s2io_xmit;
5886 dev->get_stats = &s2io_get_stats;
5887 dev->set_multicast_list = &s2io_set_multicast;
5888 dev->do_ioctl = &s2io_ioctl;
5889 dev->change_mtu = &s2io_change_mtu;
5890 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07005891 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
5892 dev->vlan_rx_register = s2io_vlan_rx_register;
5893 dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005894
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895 /*
5896 * will use eth_mac_addr() for dev->set_mac_address
5897 * mac address will be set every time dev->open() is called
5898 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005899#if defined(CONFIG_S2IO_NAPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900 dev->poll = s2io_poll;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005901 dev->weight = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902#endif
5903
5904 dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
5905 if (sp->high_dma_flag == TRUE)
5906 dev->features |= NETIF_F_HIGHDMA;
5907#ifdef NETIF_F_TSO
5908 dev->features |= NETIF_F_TSO;
5909#endif
5910
5911 dev->tx_timeout = &s2io_tx_watchdog;
5912 dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
5913 INIT_WORK(&sp->rst_timer_task,
5914 (void (*)(void *)) s2io_restart_nic, dev);
5915 INIT_WORK(&sp->set_link_task,
5916 (void (*)(void *)) s2io_set_link, sp);
5917
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07005918 pci_save_state(sp->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919
5920 /* Setting swapper control on the NIC, for proper reset operation */
5921 if (s2io_set_swapper(sp)) {
5922 DBG_PRINT(ERR_DBG, "%s:swapper settings are wrong\n",
5923 dev->name);
5924 ret = -EAGAIN;
5925 goto set_swap_failed;
5926 }
5927
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005928 /* Verify if the Herc works on the slot its placed into */
5929 if (sp->device_type & XFRAME_II_DEVICE) {
5930 mode = s2io_verify_pci_mode(sp);
5931 if (mode < 0) {
5932 DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__);
5933 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
5934 ret = -EBADSLT;
5935 goto set_swap_failed;
5936 }
5937 }
5938
5939 /* Not needed for Herc */
5940 if (sp->device_type & XFRAME_I_DEVICE) {
5941 /*
5942 * Fix for all "FFs" MAC address problems observed on
5943 * Alpha platforms
5944 */
5945 fix_mac_address(sp);
5946 s2io_reset(sp);
5947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948
5949 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950 * MAC address initialization.
5951 * For now only one mac address will be read and used.
5952 */
5953 bar0 = sp->bar0;
5954 val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
5955 RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
5956 writeq(val64, &bar0->rmac_addr_cmd_mem);
5957 wait_for_cmd_complete(sp);
5958
5959 tmp64 = readq(&bar0->rmac_addr_data0_mem);
5960 mac_down = (u32) tmp64;
5961 mac_up = (u32) (tmp64 >> 32);
5962
5963 memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
5964
5965 sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up);
5966 sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8);
5967 sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16);
5968 sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_up >> 24);
5969 sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16);
5970 sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24);
5971
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972 /* Set the factory defined MAC address initially */
5973 dev->addr_len = ETH_ALEN;
5974 memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
5975
5976 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005977 * Initialize the tasklet status and link state flags
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005978 * and the card state parameter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979 */
5980 atomic_set(&(sp->card_state), 0);
5981 sp->tasklet_status = 0;
5982 sp->link_state = 0;
5983
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984 /* Initialize spinlocks */
5985 spin_lock_init(&sp->tx_lock);
5986#ifndef CONFIG_S2IO_NAPI
5987 spin_lock_init(&sp->put_lock);
5988#endif
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005989 spin_lock_init(&sp->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005991 /*
5992 * SXE-002: Configure link and activity LED to init state
5993 * on driver load.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994 */
5995 subid = sp->pdev->subsystem_device;
5996 if ((subid & 0xFF) >= 0x07) {
5997 val64 = readq(&bar0->gpio_control);
5998 val64 |= 0x0000800000000000ULL;
5999 writeq(val64, &bar0->gpio_control);
6000 val64 = 0x0411040400000000ULL;
6001 writeq(val64, (void __iomem *) bar0 + 0x2700);
6002 val64 = readq(&bar0->gpio_control);
6003 }
6004
6005 sp->rx_csum = 1; /* Rx chksum verify enabled by default */
6006
6007 if (register_netdev(dev)) {
6008 DBG_PRINT(ERR_DBG, "Device registration failed\n");
6009 ret = -ENODEV;
6010 goto register_failed;
6011 }
6012
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006013 if (sp->device_type & XFRAME_II_DEVICE) {
6014 DBG_PRINT(ERR_DBG, "%s: Neterion Xframe II 10GbE adapter ",
6015 dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07006016 DBG_PRINT(ERR_DBG, "(rev %d), %s",
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006017 get_xena_rev_id(sp->pdev),
6018 s2io_driver_version);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07006019#ifdef CONFIG_2BUFF_MODE
6020 DBG_PRINT(ERR_DBG, ", Buffer mode %d",2);
6021#endif
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006022 switch(sp->intr_type) {
6023 case INTA:
6024 DBG_PRINT(ERR_DBG, ", Intr type INTA");
6025 break;
6026 case MSI:
6027 DBG_PRINT(ERR_DBG, ", Intr type MSI");
6028 break;
6029 case MSI_X:
6030 DBG_PRINT(ERR_DBG, ", Intr type MSI-X");
6031 break;
6032 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07006033
6034 DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006035 DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
6036 sp->def_mac_addr[0].mac_addr[0],
6037 sp->def_mac_addr[0].mac_addr[1],
6038 sp->def_mac_addr[0].mac_addr[2],
6039 sp->def_mac_addr[0].mac_addr[3],
6040 sp->def_mac_addr[0].mac_addr[4],
6041 sp->def_mac_addr[0].mac_addr[5]);
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07006042 mode = s2io_print_pci_mode(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006043 if (mode < 0) {
6044 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode ");
6045 ret = -EBADSLT;
6046 goto set_swap_failed;
6047 }
6048 } else {
6049 DBG_PRINT(ERR_DBG, "%s: Neterion Xframe I 10GbE adapter ",
6050 dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07006051 DBG_PRINT(ERR_DBG, "(rev %d), %s",
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006052 get_xena_rev_id(sp->pdev),
6053 s2io_driver_version);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07006054#ifdef CONFIG_2BUFF_MODE
6055 DBG_PRINT(ERR_DBG, ", Buffer mode %d",2);
6056#endif
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006057 switch(sp->intr_type) {
6058 case INTA:
6059 DBG_PRINT(ERR_DBG, ", Intr type INTA");
6060 break;
6061 case MSI:
6062 DBG_PRINT(ERR_DBG, ", Intr type MSI");
6063 break;
6064 case MSI_X:
6065 DBG_PRINT(ERR_DBG, ", Intr type MSI-X");
6066 break;
6067 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07006068 DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006069 DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
6070 sp->def_mac_addr[0].mac_addr[0],
6071 sp->def_mac_addr[0].mac_addr[1],
6072 sp->def_mac_addr[0].mac_addr[2],
6073 sp->def_mac_addr[0].mac_addr[3],
6074 sp->def_mac_addr[0].mac_addr[4],
6075 sp->def_mac_addr[0].mac_addr[5]);
6076 }
6077
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006078 /* Initialize device name */
6079 strcpy(sp->name, dev->name);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006080 if (sp->device_type & XFRAME_II_DEVICE)
6081 strcat(sp->name, ": Neterion Xframe II 10GbE adapter");
6082 else
6083 strcat(sp->name, ": Neterion Xframe I 10GbE adapter");
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006084
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07006085 /* Initialize bimodal Interrupts */
6086 sp->config.bimodal = bimodal;
6087 if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) {
6088 sp->config.bimodal = 0;
6089 DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n",
6090 dev->name);
6091 }
6092
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006093 /*
6094 * Make Link state as off at this point, when the Link change
6095 * interrupt comes the state will be automatically changed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096 * the right state.
6097 */
6098 netif_carrier_off(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099
6100 return 0;
6101
6102 register_failed:
6103 set_swap_failed:
6104 iounmap(sp->bar1);
6105 bar1_remap_failed:
6106 iounmap(sp->bar0);
6107 bar0_remap_failed:
6108 mem_alloc_failed:
6109 free_shared_mem(sp);
6110 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006111 if (dev_intr_type != MSI_X)
6112 pci_release_regions(pdev);
6113 else {
6114 release_mem_region(pci_resource_start(pdev, 0),
6115 pci_resource_len(pdev, 0));
6116 release_mem_region(pci_resource_start(pdev, 2),
6117 pci_resource_len(pdev, 2));
6118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 pci_set_drvdata(pdev, NULL);
6120 free_netdev(dev);
6121
6122 return ret;
6123}
6124
6125/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006126 * s2io_rem_nic - Free the PCI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127 * @pdev: structure containing the PCI related information of the device.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006128 * Description: This function is called by the Pci subsystem to release a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129 * PCI device and free up all resource held up by the device. This could
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006130 * be in response to a Hot plug event or when the driver is to be removed
Linus Torvalds1da177e2005-04-16 15:20:36 -07006131 * from memory.
6132 */
6133
6134static void __devexit s2io_rem_nic(struct pci_dev *pdev)
6135{
6136 struct net_device *dev =
6137 (struct net_device *) pci_get_drvdata(pdev);
6138 nic_t *sp;
6139
6140 if (dev == NULL) {
6141 DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
6142 return;
6143 }
6144
6145 sp = dev->priv;
6146 unregister_netdev(dev);
6147
6148 free_shared_mem(sp);
6149 iounmap(sp->bar0);
6150 iounmap(sp->bar1);
6151 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006152 if (sp->intr_type != MSI_X)
6153 pci_release_regions(pdev);
6154 else {
6155 release_mem_region(pci_resource_start(pdev, 0),
6156 pci_resource_len(pdev, 0));
6157 release_mem_region(pci_resource_start(pdev, 2),
6158 pci_resource_len(pdev, 2));
6159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006160 pci_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161 free_netdev(dev);
6162}
6163
6164/**
6165 * s2io_starter - Entry point for the driver
6166 * Description: This function is the entry point for the driver. It verifies
6167 * the module loadable parameters and initializes PCI configuration space.
6168 */
6169
6170int __init s2io_starter(void)
6171{
6172 return pci_module_init(&s2io_driver);
6173}
6174
6175/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006176 * s2io_closer - Cleanup routine for the driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07006177 * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
6178 */
6179
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006180void s2io_closer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006181{
6182 pci_unregister_driver(&s2io_driver);
6183 DBG_PRINT(INIT_DBG, "cleanup done\n");
6184}
6185
6186module_init(s2io_starter);
6187module_exit(s2io_closer);