blob: 4e392914971e2389654859b6ca78df93ed6b6d63 [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.
Ananda Rajuda6971d2005-10-31 16:55:31 -050033 * rx_ring_mode: This defines the operation mode of all 8 rings. The valid
34 * values are 1, 2 and 3.
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070036 * tx_fifo_len: This too is an array of 8. Each element defines the number of
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 * Tx descriptors that can be associated with each corresponding FIFO.
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 ************************************************************************/
39
40#include <linux/config.h>
41#include <linux/module.h>
42#include <linux/types.h>
43#include <linux/errno.h>
44#include <linux/ioport.h>
45#include <linux/pci.h>
Domen Puncer1e7f0bd2005-06-26 18:22:14 -040046#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/kernel.h>
48#include <linux/netdevice.h>
49#include <linux/etherdevice.h>
50#include <linux/skbuff.h>
51#include <linux/init.h>
52#include <linux/delay.h>
53#include <linux/stddef.h>
54#include <linux/ioctl.h>
55#include <linux/timex.h>
56#include <linux/sched.h>
57#include <linux/ethtool.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <linux/workqueue.h>
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -070059#include <linux/if_vlan.h>
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -050060#include <linux/ip.h>
61#include <linux/tcp.h>
62#include <net/tcp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include <asm/system.h>
65#include <asm/uaccess.h>
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070066#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68/* local include */
69#include "s2io.h"
70#include "s2io-regs.h"
71
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -050072#define DRV_VERSION "2.0.11.2"
John Linville6c1792f2005-10-04 07:51:45 -040073
Linus Torvalds1da177e2005-04-16 15:20:36 -070074/* S2io Driver name & version. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070075static char s2io_driver_name[] = "Neterion";
John Linville6c1792f2005-10-04 07:51:45 -040076static char s2io_driver_version[] = DRV_VERSION;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
Ananda Rajuda6971d2005-10-31 16:55:31 -050078int rxd_size[4] = {32,48,48,64};
79int rxd_count[4] = {127,85,85,63};
80
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -070081static inline int RXD_IS_UP2DT(RxD_t *rxdp)
82{
83 int ret;
84
85 ret = ((!(rxdp->Control_1 & RXD_OWN_XENA)) &&
86 (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK));
87
88 return ret;
89}
90
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070091/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 * Cards with following subsystem_id have a link state indication
93 * problem, 600B, 600C, 600D, 640B, 640C and 640D.
94 * macro below identifies these cards given the subsystem_id.
95 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -070096#define CARDS_WITH_FAULTY_LINK_INDICATORS(dev_type, subid) \
97 (dev_type == XFRAME_I_DEVICE) ? \
98 ((((subid >= 0x600B) && (subid <= 0x600D)) || \
99 ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0) : 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
101#define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \
102 ADAPTER_STATUS_RMAC_LOCAL_FAULT)))
103#define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status))
104#define PANIC 1
105#define LOW 2
106static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring)
107{
108 int level = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700109 mac_info_t *mac_control;
110
111 mac_control = &sp->mac_control;
112 if ((mac_control->rings[ring].pkt_cnt - rxb_size) > 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 level = LOW;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500114 if (rxb_size <= rxd_count[sp->rxd_mode]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 level = PANIC;
116 }
117 }
118
119 return level;
120}
121
122/* Ethtool related variables and Macros. */
123static char s2io_gstrings[][ETH_GSTRING_LEN] = {
124 "Register test\t(offline)",
125 "Eeprom test\t(offline)",
126 "Link test\t(online)",
127 "RLDRAM test\t(offline)",
128 "BIST Test\t(offline)"
129};
130
131static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
132 {"tmac_frms"},
133 {"tmac_data_octets"},
134 {"tmac_drop_frms"},
135 {"tmac_mcst_frms"},
136 {"tmac_bcst_frms"},
137 {"tmac_pause_ctrl_frms"},
138 {"tmac_any_err_frms"},
139 {"tmac_vld_ip_octets"},
140 {"tmac_vld_ip"},
141 {"tmac_drop_ip"},
142 {"tmac_icmp"},
143 {"tmac_rst_tcp"},
144 {"tmac_tcp"},
145 {"tmac_udp"},
146 {"rmac_vld_frms"},
147 {"rmac_data_octets"},
148 {"rmac_fcs_err_frms"},
149 {"rmac_drop_frms"},
150 {"rmac_vld_mcst_frms"},
151 {"rmac_vld_bcst_frms"},
152 {"rmac_in_rng_len_err_frms"},
153 {"rmac_long_frms"},
154 {"rmac_pause_ctrl_frms"},
155 {"rmac_discarded_frms"},
156 {"rmac_usized_frms"},
157 {"rmac_osized_frms"},
158 {"rmac_frag_frms"},
159 {"rmac_jabber_frms"},
160 {"rmac_ip"},
161 {"rmac_ip_octets"},
162 {"rmac_hdr_err_ip"},
163 {"rmac_drop_ip"},
164 {"rmac_icmp"},
165 {"rmac_tcp"},
166 {"rmac_udp"},
167 {"rmac_err_drp_udp"},
168 {"rmac_pause_cnt"},
169 {"rmac_accepted_ip"},
170 {"rmac_err_tcp"},
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -0700171 {"\n DRIVER STATISTICS"},
172 {"single_bit_ecc_errs"},
173 {"double_bit_ecc_errs"},
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -0500174 ("lro_aggregated_pkts"),
175 ("lro_flush_both_count"),
176 ("lro_out_of_sequence_pkts"),
177 ("lro_flush_due_to_max_pkts"),
178 ("lro_avg_aggr_pkts"),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179};
180
181#define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN
182#define S2IO_STAT_STRINGS_LEN S2IO_STAT_LEN * ETH_GSTRING_LEN
183
184#define S2IO_TEST_LEN sizeof(s2io_gstrings) / ETH_GSTRING_LEN
185#define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN
186
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -0700187#define S2IO_TIMER_CONF(timer, handle, arg, exp) \
188 init_timer(&timer); \
189 timer.function = handle; \
190 timer.data = (unsigned long) arg; \
191 mod_timer(&timer, (jiffies + exp)) \
192
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -0700193/* Add the vlan */
194static void s2io_vlan_rx_register(struct net_device *dev,
195 struct vlan_group *grp)
196{
197 nic_t *nic = dev->priv;
198 unsigned long flags;
199
200 spin_lock_irqsave(&nic->tx_lock, flags);
201 nic->vlgrp = grp;
202 spin_unlock_irqrestore(&nic->tx_lock, flags);
203}
204
205/* Unregister the vlan */
206static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
207{
208 nic_t *nic = dev->priv;
209 unsigned long flags;
210
211 spin_lock_irqsave(&nic->tx_lock, flags);
212 if (nic->vlgrp)
213 nic->vlgrp->vlan_devices[vid] = NULL;
214 spin_unlock_irqrestore(&nic->tx_lock, flags);
215}
216
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700217/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 * Constants to be programmed into the Xena's registers, to configure
219 * the XAUI.
220 */
221
222#define SWITCH_SIGN 0xA5A5A5A5A5A5A5A5ULL
223#define END_SIGN 0x0
224
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700225static u64 herc_act_dtx_cfg[] = {
226 /* Set address */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700227 0x8000051536750000ULL, 0x80000515367500E0ULL,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700228 /* Write data */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700229 0x8000051536750004ULL, 0x80000515367500E4ULL,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700230 /* Set address */
231 0x80010515003F0000ULL, 0x80010515003F00E0ULL,
232 /* Write data */
233 0x80010515003F0004ULL, 0x80010515003F00E4ULL,
234 /* Set address */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700235 0x801205150D440000ULL, 0x801205150D4400E0ULL,
236 /* Write data */
237 0x801205150D440004ULL, 0x801205150D4400E4ULL,
238 /* Set address */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700239 0x80020515F2100000ULL, 0x80020515F21000E0ULL,
240 /* Write data */
241 0x80020515F2100004ULL, 0x80020515F21000E4ULL,
242 /* Done */
243 END_SIGN
244};
245
246static u64 xena_mdio_cfg[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 /* Reset PMA PLL */
248 0xC001010000000000ULL, 0xC0010100000000E0ULL,
249 0xC0010100008000E4ULL,
250 /* Remove Reset from PMA PLL */
251 0xC001010000000000ULL, 0xC0010100000000E0ULL,
252 0xC0010100000000E4ULL,
253 END_SIGN
254};
255
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700256static u64 xena_dtx_cfg[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 0x8000051500000000ULL, 0x80000515000000E0ULL,
258 0x80000515D93500E4ULL, 0x8001051500000000ULL,
259 0x80010515000000E0ULL, 0x80010515001E00E4ULL,
260 0x8002051500000000ULL, 0x80020515000000E0ULL,
261 0x80020515F21000E4ULL,
262 /* Set PADLOOPBACKN */
263 0x8002051500000000ULL, 0x80020515000000E0ULL,
264 0x80020515B20000E4ULL, 0x8003051500000000ULL,
265 0x80030515000000E0ULL, 0x80030515B20000E4ULL,
266 0x8004051500000000ULL, 0x80040515000000E0ULL,
267 0x80040515B20000E4ULL, 0x8005051500000000ULL,
268 0x80050515000000E0ULL, 0x80050515B20000E4ULL,
269 SWITCH_SIGN,
270 /* Remove PADLOOPBACKN */
271 0x8002051500000000ULL, 0x80020515000000E0ULL,
272 0x80020515F20000E4ULL, 0x8003051500000000ULL,
273 0x80030515000000E0ULL, 0x80030515F20000E4ULL,
274 0x8004051500000000ULL, 0x80040515000000E0ULL,
275 0x80040515F20000E4ULL, 0x8005051500000000ULL,
276 0x80050515000000E0ULL, 0x80050515F20000E4ULL,
277 END_SIGN
278};
279
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700280/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 * Constants for Fixing the MacAddress problem seen mostly on
282 * Alpha machines.
283 */
284static u64 fix_mac[] = {
285 0x0060000000000000ULL, 0x0060600000000000ULL,
286 0x0040600000000000ULL, 0x0000600000000000ULL,
287 0x0020600000000000ULL, 0x0060600000000000ULL,
288 0x0020600000000000ULL, 0x0060600000000000ULL,
289 0x0020600000000000ULL, 0x0060600000000000ULL,
290 0x0020600000000000ULL, 0x0060600000000000ULL,
291 0x0020600000000000ULL, 0x0060600000000000ULL,
292 0x0020600000000000ULL, 0x0060600000000000ULL,
293 0x0020600000000000ULL, 0x0060600000000000ULL,
294 0x0020600000000000ULL, 0x0060600000000000ULL,
295 0x0020600000000000ULL, 0x0060600000000000ULL,
296 0x0020600000000000ULL, 0x0060600000000000ULL,
297 0x0020600000000000ULL, 0x0000600000000000ULL,
298 0x0040600000000000ULL, 0x0060600000000000ULL,
299 END_SIGN
300};
301
302/* Module Loadable parameters. */
303static unsigned int tx_fifo_num = 1;
304static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
305 {[0 ...(MAX_TX_FIFOS - 1)] = 0 };
306static unsigned int rx_ring_num = 1;
307static unsigned int rx_ring_sz[MAX_RX_RINGS] =
308 {[0 ...(MAX_RX_RINGS - 1)] = 0 };
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700309static unsigned int rts_frm_len[MAX_RX_RINGS] =
310 {[0 ...(MAX_RX_RINGS - 1)] = 0 };
Ananda Rajuda6971d2005-10-31 16:55:31 -0500311static unsigned int rx_ring_mode = 1;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700312static unsigned int use_continuous_tx_intrs = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313static unsigned int rmac_pause_time = 65535;
314static unsigned int mc_pause_threshold_q0q3 = 187;
315static unsigned int mc_pause_threshold_q4q7 = 187;
316static unsigned int shared_splits;
317static unsigned int tmac_util_period = 5;
318static unsigned int rmac_util_period = 5;
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -0700319static unsigned int bimodal = 0;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500320static unsigned int l3l4hdr_size = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321#ifndef CONFIG_S2IO_NAPI
322static unsigned int indicate_max_pkts;
323#endif
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -0700324/* Frequency of Rx desc syncs expressed as power of 2 */
325static unsigned int rxsync_frequency = 3;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -0400326/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */
327static unsigned int intr_type = 0;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -0500328/* Large receive offload feature */
329static unsigned int lro = 0;
330/* Max pkts to be aggregated by LRO at one time. If not specified,
331 * aggregation happens until we hit max IP pkt size(64K)
332 */
333static unsigned int lro_max_pkts = 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700335/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 * S2IO device table.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700337 * This table lists all the devices that this driver supports.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 */
339static struct pci_device_id s2io_tbl[] __devinitdata = {
340 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN,
341 PCI_ANY_ID, PCI_ANY_ID},
342 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI,
343 PCI_ANY_ID, PCI_ANY_ID},
344 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700345 PCI_ANY_ID, PCI_ANY_ID},
346 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI,
347 PCI_ANY_ID, PCI_ANY_ID},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 {0,}
349};
350
351MODULE_DEVICE_TABLE(pci, s2io_tbl);
352
353static struct pci_driver s2io_driver = {
354 .name = "S2IO",
355 .id_table = s2io_tbl,
356 .probe = s2io_init_nic,
357 .remove = __devexit_p(s2io_rem_nic),
358};
359
360/* A simplifier macro used both by init and free shared_mem Fns(). */
361#define TXD_MEM_PAGE_CNT(len, per_each) ((len+per_each - 1) / per_each)
362
363/**
364 * init_shared_mem - Allocation and Initialization of Memory
365 * @nic: Device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700366 * Description: The function allocates all the memory areas shared
367 * between the NIC and the driver. This includes Tx descriptors,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 * Rx descriptors and the statistics block.
369 */
370
371static int init_shared_mem(struct s2io_nic *nic)
372{
373 u32 size;
374 void *tmp_v_addr, *tmp_v_addr_next;
375 dma_addr_t tmp_p_addr, tmp_p_addr_next;
376 RxD_block_t *pre_rxd_blk = NULL;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700377 int i, j, blk_cnt, rx_sz, tx_sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 int lst_size, lst_per_page;
379 struct net_device *dev = nic->dev;
viro@zenIV.linux.org.uk8ae418c2005-09-02 20:15:29 +0100380 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 buffAdd_t *ba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
383 mac_info_t *mac_control;
384 struct config_param *config;
385
386 mac_control = &nic->mac_control;
387 config = &nic->config;
388
389
390 /* Allocation and initialization of TXDLs in FIOFs */
391 size = 0;
392 for (i = 0; i < config->tx_fifo_num; i++) {
393 size += config->tx_cfg[i].fifo_len;
394 }
395 if (size > MAX_AVAILABLE_TXDS) {
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -0700396 DBG_PRINT(ERR_DBG, "%s: Requested TxDs too high, ",
397 __FUNCTION__);
398 DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 return FAILURE;
400 }
401
402 lst_size = (sizeof(TxD_t) * config->max_txds);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700403 tx_sz = lst_size * size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 lst_per_page = PAGE_SIZE / lst_size;
405
406 for (i = 0; i < config->tx_fifo_num; i++) {
407 int fifo_len = config->tx_cfg[i].fifo_len;
408 int list_holder_size = fifo_len * sizeof(list_info_hold_t);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700409 mac_control->fifos[i].list_info = kmalloc(list_holder_size,
410 GFP_KERNEL);
411 if (!mac_control->fifos[i].list_info) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 DBG_PRINT(ERR_DBG,
413 "Malloc failed for list_info\n");
414 return -ENOMEM;
415 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700416 memset(mac_control->fifos[i].list_info, 0, list_holder_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 }
418 for (i = 0; i < config->tx_fifo_num; i++) {
419 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
420 lst_per_page);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700421 mac_control->fifos[i].tx_curr_put_info.offset = 0;
422 mac_control->fifos[i].tx_curr_put_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700424 mac_control->fifos[i].tx_curr_get_info.offset = 0;
425 mac_control->fifos[i].tx_curr_get_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700427 mac_control->fifos[i].fifo_no = i;
428 mac_control->fifos[i].nic = nic;
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500429 mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 2;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700430
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 for (j = 0; j < page_num; j++) {
432 int k = 0;
433 dma_addr_t tmp_p;
434 void *tmp_v;
435 tmp_v = pci_alloc_consistent(nic->pdev,
436 PAGE_SIZE, &tmp_p);
437 if (!tmp_v) {
438 DBG_PRINT(ERR_DBG,
439 "pci_alloc_consistent ");
440 DBG_PRINT(ERR_DBG, "failed for TxDL\n");
441 return -ENOMEM;
442 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700443 /* If we got a zero DMA address(can happen on
444 * certain platforms like PPC), reallocate.
445 * Store virtual address of page we don't want,
446 * to be freed later.
447 */
448 if (!tmp_p) {
449 mac_control->zerodma_virt_addr = tmp_v;
450 DBG_PRINT(INIT_DBG,
451 "%s: Zero DMA address for TxDL. ", dev->name);
452 DBG_PRINT(INIT_DBG,
Andrew Morton6b4d6172005-09-12 23:21:55 -0700453 "Virtual address %p\n", tmp_v);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700454 tmp_v = pci_alloc_consistent(nic->pdev,
455 PAGE_SIZE, &tmp_p);
456 if (!tmp_v) {
457 DBG_PRINT(ERR_DBG,
458 "pci_alloc_consistent ");
459 DBG_PRINT(ERR_DBG, "failed for TxDL\n");
460 return -ENOMEM;
461 }
462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 while (k < lst_per_page) {
464 int l = (j * lst_per_page) + k;
465 if (l == config->tx_cfg[i].fifo_len)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700466 break;
467 mac_control->fifos[i].list_info[l].list_virt_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 tmp_v + (k * lst_size);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700469 mac_control->fifos[i].list_info[l].list_phy_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 tmp_p + (k * lst_size);
471 k++;
472 }
473 }
474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500476 nic->ufo_in_band_v = kmalloc((sizeof(u64) * size), GFP_KERNEL);
477 if (!nic->ufo_in_band_v)
478 return -ENOMEM;
479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 /* Allocation and initialization of RXDs in Rings */
481 size = 0;
482 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -0500483 if (config->rx_cfg[i].num_rxd %
484 (rxd_count[nic->rxd_mode] + 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 DBG_PRINT(ERR_DBG, "%s: RxD count of ", dev->name);
486 DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ",
487 i);
488 DBG_PRINT(ERR_DBG, "RxDs per Block");
489 return FAILURE;
490 }
491 size += config->rx_cfg[i].num_rxd;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700492 mac_control->rings[i].block_count =
Ananda Rajuda6971d2005-10-31 16:55:31 -0500493 config->rx_cfg[i].num_rxd /
494 (rxd_count[nic->rxd_mode] + 1 );
495 mac_control->rings[i].pkt_cnt = config->rx_cfg[i].num_rxd -
496 mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500498 if (nic->rxd_mode == RXD_MODE_1)
499 size = (size * (sizeof(RxD1_t)));
500 else
501 size = (size * (sizeof(RxD3_t)));
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700502 rx_sz = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700505 mac_control->rings[i].rx_curr_get_info.block_index = 0;
506 mac_control->rings[i].rx_curr_get_info.offset = 0;
507 mac_control->rings[i].rx_curr_get_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700509 mac_control->rings[i].rx_curr_put_info.block_index = 0;
510 mac_control->rings[i].rx_curr_put_info.offset = 0;
511 mac_control->rings[i].rx_curr_put_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700513 mac_control->rings[i].nic = nic;
514 mac_control->rings[i].ring_no = i;
515
Ananda Rajuda6971d2005-10-31 16:55:31 -0500516 blk_cnt = config->rx_cfg[i].num_rxd /
517 (rxd_count[nic->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 /* Allocating all the Rx blocks */
519 for (j = 0; j < blk_cnt; j++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -0500520 rx_block_info_t *rx_blocks;
521 int l;
522
523 rx_blocks = &mac_control->rings[i].rx_blocks[j];
524 size = SIZE_OF_BLOCK; //size is always page size
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 tmp_v_addr = pci_alloc_consistent(nic->pdev, size,
526 &tmp_p_addr);
527 if (tmp_v_addr == NULL) {
528 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700529 * In case of failure, free_shared_mem()
530 * is called, which should free any
531 * memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 * failure happened.
533 */
Ananda Rajuda6971d2005-10-31 16:55:31 -0500534 rx_blocks->block_virt_addr = tmp_v_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 return -ENOMEM;
536 }
537 memset(tmp_v_addr, 0, size);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500538 rx_blocks->block_virt_addr = tmp_v_addr;
539 rx_blocks->block_dma_addr = tmp_p_addr;
540 rx_blocks->rxds = kmalloc(sizeof(rxd_info_t)*
541 rxd_count[nic->rxd_mode],
542 GFP_KERNEL);
543 for (l=0; l<rxd_count[nic->rxd_mode];l++) {
544 rx_blocks->rxds[l].virt_addr =
545 rx_blocks->block_virt_addr +
546 (rxd_size[nic->rxd_mode] * l);
547 rx_blocks->rxds[l].dma_addr =
548 rx_blocks->block_dma_addr +
549 (rxd_size[nic->rxd_mode] * l);
550 }
551
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700552 mac_control->rings[i].rx_blocks[j].block_virt_addr =
553 tmp_v_addr;
554 mac_control->rings[i].rx_blocks[j].block_dma_addr =
555 tmp_p_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 }
557 /* Interlinking all Rx Blocks */
558 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700559 tmp_v_addr =
560 mac_control->rings[i].rx_blocks[j].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 tmp_v_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700562 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 blk_cnt].block_virt_addr;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700564 tmp_p_addr =
565 mac_control->rings[i].rx_blocks[j].block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 tmp_p_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700567 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 blk_cnt].block_dma_addr;
569
570 pre_rxd_blk = (RxD_block_t *) tmp_v_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 pre_rxd_blk->reserved_2_pNext_RxD_block =
572 (unsigned long) tmp_v_addr_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 pre_rxd_blk->pNext_RxD_Blk_physical =
574 (u64) tmp_p_addr_next;
575 }
576 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500577 if (nic->rxd_mode >= RXD_MODE_3A) {
578 /*
579 * Allocation of Storages for buffer addresses in 2BUFF mode
580 * and the buffers as well.
581 */
582 for (i = 0; i < config->rx_ring_num; i++) {
583 blk_cnt = config->rx_cfg[i].num_rxd /
584 (rxd_count[nic->rxd_mode]+ 1);
585 mac_control->rings[i].ba =
586 kmalloc((sizeof(buffAdd_t *) * blk_cnt),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 GFP_KERNEL);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500588 if (!mac_control->rings[i].ba)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 return -ENOMEM;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500590 for (j = 0; j < blk_cnt; j++) {
591 int k = 0;
592 mac_control->rings[i].ba[j] =
593 kmalloc((sizeof(buffAdd_t) *
594 (rxd_count[nic->rxd_mode] + 1)),
595 GFP_KERNEL);
596 if (!mac_control->rings[i].ba[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 return -ENOMEM;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500598 while (k != rxd_count[nic->rxd_mode]) {
599 ba = &mac_control->rings[i].ba[j][k];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
Ananda Rajuda6971d2005-10-31 16:55:31 -0500601 ba->ba_0_org = (void *) kmalloc
602 (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
603 if (!ba->ba_0_org)
604 return -ENOMEM;
605 tmp = (unsigned long)ba->ba_0_org;
606 tmp += ALIGN_SIZE;
607 tmp &= ~((unsigned long) ALIGN_SIZE);
608 ba->ba_0 = (void *) tmp;
609
610 ba->ba_1_org = (void *) kmalloc
611 (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
612 if (!ba->ba_1_org)
613 return -ENOMEM;
614 tmp = (unsigned long) ba->ba_1_org;
615 tmp += ALIGN_SIZE;
616 tmp &= ~((unsigned long) ALIGN_SIZE);
617 ba->ba_1 = (void *) tmp;
618 k++;
619 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 }
621 }
622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
624 /* Allocation and initialization of Statistics block */
625 size = sizeof(StatInfo_t);
626 mac_control->stats_mem = pci_alloc_consistent
627 (nic->pdev, size, &mac_control->stats_mem_phy);
628
629 if (!mac_control->stats_mem) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700630 /*
631 * In case of failure, free_shared_mem() is called, which
632 * should free any memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 * failure happened.
634 */
635 return -ENOMEM;
636 }
637 mac_control->stats_mem_sz = size;
638
639 tmp_v_addr = mac_control->stats_mem;
640 mac_control->stats_info = (StatInfo_t *) tmp_v_addr;
641 memset(tmp_v_addr, 0, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name,
643 (unsigned long long) tmp_p_addr);
644
645 return SUCCESS;
646}
647
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700648/**
649 * free_shared_mem - Free the allocated Memory
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 * @nic: Device private variable.
651 * Description: This function is to free all memory locations allocated by
652 * the init_shared_mem() function and return it to the kernel.
653 */
654
655static void free_shared_mem(struct s2io_nic *nic)
656{
657 int i, j, blk_cnt, size;
658 void *tmp_v_addr;
659 dma_addr_t tmp_p_addr;
660 mac_info_t *mac_control;
661 struct config_param *config;
662 int lst_size, lst_per_page;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700663 struct net_device *dev = nic->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
665 if (!nic)
666 return;
667
668 mac_control = &nic->mac_control;
669 config = &nic->config;
670
671 lst_size = (sizeof(TxD_t) * config->max_txds);
672 lst_per_page = PAGE_SIZE / lst_size;
673
674 for (i = 0; i < config->tx_fifo_num; i++) {
675 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
676 lst_per_page);
677 for (j = 0; j < page_num; j++) {
678 int mem_blks = (j * lst_per_page);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700679 if (!mac_control->fifos[i].list_info)
680 return;
681 if (!mac_control->fifos[i].list_info[mem_blks].
682 list_virt_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 break;
684 pci_free_consistent(nic->pdev, PAGE_SIZE,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700685 mac_control->fifos[i].
686 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 list_virt_addr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700688 mac_control->fifos[i].
689 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 list_phy_addr);
691 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700692 /* If we got a zero DMA address during allocation,
693 * free the page now
694 */
695 if (mac_control->zerodma_virt_addr) {
696 pci_free_consistent(nic->pdev, PAGE_SIZE,
697 mac_control->zerodma_virt_addr,
698 (dma_addr_t)0);
699 DBG_PRINT(INIT_DBG,
Andrew Morton6b4d6172005-09-12 23:21:55 -0700700 "%s: Freeing TxDL with zero DMA addr. ",
701 dev->name);
702 DBG_PRINT(INIT_DBG, "Virtual address %p\n",
703 mac_control->zerodma_virt_addr);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700704 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700705 kfree(mac_control->fifos[i].list_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 }
707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 size = SIZE_OF_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700710 blk_cnt = mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700712 tmp_v_addr = mac_control->rings[i].rx_blocks[j].
713 block_virt_addr;
714 tmp_p_addr = mac_control->rings[i].rx_blocks[j].
715 block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 if (tmp_v_addr == NULL)
717 break;
718 pci_free_consistent(nic->pdev, size,
719 tmp_v_addr, tmp_p_addr);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500720 kfree(mac_control->rings[i].rx_blocks[j].rxds);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 }
722 }
723
Ananda Rajuda6971d2005-10-31 16:55:31 -0500724 if (nic->rxd_mode >= RXD_MODE_3A) {
725 /* Freeing buffer storage addresses in 2BUFF mode. */
726 for (i = 0; i < config->rx_ring_num; i++) {
727 blk_cnt = config->rx_cfg[i].num_rxd /
728 (rxd_count[nic->rxd_mode] + 1);
729 for (j = 0; j < blk_cnt; j++) {
730 int k = 0;
731 if (!mac_control->rings[i].ba[j])
732 continue;
733 while (k != rxd_count[nic->rxd_mode]) {
734 buffAdd_t *ba =
735 &mac_control->rings[i].ba[j][k];
736 kfree(ba->ba_0_org);
737 kfree(ba->ba_1_org);
738 k++;
739 }
740 kfree(mac_control->rings[i].ba[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500742 kfree(mac_control->rings[i].ba);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
746 if (mac_control->stats_mem) {
747 pci_free_consistent(nic->pdev,
748 mac_control->stats_mem_sz,
749 mac_control->stats_mem,
750 mac_control->stats_mem_phy);
751 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500752 if (nic->ufo_in_band_v)
753 kfree(nic->ufo_in_band_v);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754}
755
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700756/**
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700757 * s2io_verify_pci_mode -
758 */
759
760static int s2io_verify_pci_mode(nic_t *nic)
761{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +0100762 XENA_dev_config_t __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700763 register u64 val64 = 0;
764 int mode;
765
766 val64 = readq(&bar0->pci_mode);
767 mode = (u8)GET_PCI_MODE(val64);
768
769 if ( val64 & PCI_MODE_UNKNOWN_MODE)
770 return -1; /* Unknown PCI mode */
771 return mode;
772}
773
774
775/**
776 * s2io_print_pci_mode -
777 */
778static int s2io_print_pci_mode(nic_t *nic)
779{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +0100780 XENA_dev_config_t __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700781 register u64 val64 = 0;
782 int mode;
783 struct config_param *config = &nic->config;
784
785 val64 = readq(&bar0->pci_mode);
786 mode = (u8)GET_PCI_MODE(val64);
787
788 if ( val64 & PCI_MODE_UNKNOWN_MODE)
789 return -1; /* Unknown PCI mode */
790
791 if (val64 & PCI_MODE_32_BITS) {
792 DBG_PRINT(ERR_DBG, "%s: Device is on 32 bit ", nic->dev->name);
793 } else {
794 DBG_PRINT(ERR_DBG, "%s: Device is on 64 bit ", nic->dev->name);
795 }
796
797 switch(mode) {
798 case PCI_MODE_PCI_33:
799 DBG_PRINT(ERR_DBG, "33MHz PCI bus\n");
800 config->bus_speed = 33;
801 break;
802 case PCI_MODE_PCI_66:
803 DBG_PRINT(ERR_DBG, "66MHz PCI bus\n");
804 config->bus_speed = 133;
805 break;
806 case PCI_MODE_PCIX_M1_66:
807 DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n");
808 config->bus_speed = 133; /* Herc doubles the clock rate */
809 break;
810 case PCI_MODE_PCIX_M1_100:
811 DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n");
812 config->bus_speed = 200;
813 break;
814 case PCI_MODE_PCIX_M1_133:
815 DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n");
816 config->bus_speed = 266;
817 break;
818 case PCI_MODE_PCIX_M2_66:
819 DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n");
820 config->bus_speed = 133;
821 break;
822 case PCI_MODE_PCIX_M2_100:
823 DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n");
824 config->bus_speed = 200;
825 break;
826 case PCI_MODE_PCIX_M2_133:
827 DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n");
828 config->bus_speed = 266;
829 break;
830 default:
831 return -1; /* Unsupported bus speed */
832 }
833
834 return mode;
835}
836
837/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700838 * init_nic - Initialization of hardware
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 * @nic: device peivate variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700840 * Description: The function sequentially configures every block
841 * of the H/W from their reset values.
842 * Return Value: SUCCESS on success and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 * '-1' on failure (endian settings incorrect).
844 */
845
846static int init_nic(struct s2io_nic *nic)
847{
848 XENA_dev_config_t __iomem *bar0 = nic->bar0;
849 struct net_device *dev = nic->dev;
850 register u64 val64 = 0;
851 void __iomem *add;
852 u32 time;
853 int i, j;
854 mac_info_t *mac_control;
855 struct config_param *config;
856 int mdio_cnt = 0, dtx_cnt = 0;
857 unsigned long long mem_share;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700858 int mem_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
860 mac_control = &nic->mac_control;
861 config = &nic->config;
862
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700863 /* to set the swapper controle on the card */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700864 if(s2io_set_swapper(nic)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n");
866 return -1;
867 }
868
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700869 /*
870 * Herc requires EOI to be removed from reset before XGXS, so..
871 */
872 if (nic->device_type & XFRAME_II_DEVICE) {
873 val64 = 0xA500000000ULL;
874 writeq(val64, &bar0->sw_reset);
875 msleep(500);
876 val64 = readq(&bar0->sw_reset);
877 }
878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 /* Remove XGXS from reset state */
880 val64 = 0;
881 writeq(val64, &bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 msleep(500);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700883 val64 = readq(&bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
885 /* Enable Receiving broadcasts */
886 add = &bar0->mac_cfg;
887 val64 = readq(&bar0->mac_cfg);
888 val64 |= MAC_RMAC_BCAST_ENABLE;
889 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
890 writel((u32) val64, add);
891 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
892 writel((u32) (val64 >> 32), (add + 4));
893
894 /* Read registers in all blocks */
895 val64 = readq(&bar0->mac_int_mask);
896 val64 = readq(&bar0->mc_int_mask);
897 val64 = readq(&bar0->xgxs_int_mask);
898
899 /* Set MTU */
900 val64 = dev->mtu;
901 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
902
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700903 /*
904 * Configuring the XAUI Interface of Xena.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 * ***************************************
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700906 * To Configure the Xena's XAUI, one has to write a series
907 * of 64 bit values into two registers in a particular
908 * sequence. Hence a macro 'SWITCH_SIGN' has been defined
909 * which will be defined in the array of configuration values
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700910 * (xena_dtx_cfg & xena_mdio_cfg) at appropriate places
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700911 * to switch writing from one regsiter to another. We continue
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 * writing these values until we encounter the 'END_SIGN' macro.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700913 * For example, After making a series of 21 writes into
914 * dtx_control register the 'SWITCH_SIGN' appears and hence we
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 * start writing into mdio_control until we encounter END_SIGN.
916 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700917 if (nic->device_type & XFRAME_II_DEVICE) {
918 while (herc_act_dtx_cfg[dtx_cnt] != END_SIGN) {
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -0700919 SPECIAL_REG_WRITE(herc_act_dtx_cfg[dtx_cnt],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 &bar0->dtx_control, UF);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700921 if (dtx_cnt & 0x1)
922 msleep(1); /* Necessary!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 dtx_cnt++;
924 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700925 } else {
926 while (1) {
927 dtx_cfg:
928 while (xena_dtx_cfg[dtx_cnt] != END_SIGN) {
929 if (xena_dtx_cfg[dtx_cnt] == SWITCH_SIGN) {
930 dtx_cnt++;
931 goto mdio_cfg;
932 }
933 SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt],
934 &bar0->dtx_control, UF);
935 val64 = readq(&bar0->dtx_control);
936 dtx_cnt++;
937 }
938 mdio_cfg:
939 while (xena_mdio_cfg[mdio_cnt] != END_SIGN) {
940 if (xena_mdio_cfg[mdio_cnt] == SWITCH_SIGN) {
941 mdio_cnt++;
942 goto dtx_cfg;
943 }
944 SPECIAL_REG_WRITE(xena_mdio_cfg[mdio_cnt],
945 &bar0->mdio_control, UF);
946 val64 = readq(&bar0->mdio_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 mdio_cnt++;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700948 }
949 if ((xena_dtx_cfg[dtx_cnt] == END_SIGN) &&
950 (xena_mdio_cfg[mdio_cnt] == END_SIGN)) {
951 break;
952 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 goto dtx_cfg;
954 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 }
956 }
957
958 /* Tx DMA Initialization */
959 val64 = 0;
960 writeq(val64, &bar0->tx_fifo_partition_0);
961 writeq(val64, &bar0->tx_fifo_partition_1);
962 writeq(val64, &bar0->tx_fifo_partition_2);
963 writeq(val64, &bar0->tx_fifo_partition_3);
964
965
966 for (i = 0, j = 0; i < config->tx_fifo_num; i++) {
967 val64 |=
968 vBIT(config->tx_cfg[i].fifo_len - 1, ((i * 32) + 19),
969 13) | vBIT(config->tx_cfg[i].fifo_priority,
970 ((i * 32) + 5), 3);
971
972 if (i == (config->tx_fifo_num - 1)) {
973 if (i % 2 == 0)
974 i++;
975 }
976
977 switch (i) {
978 case 1:
979 writeq(val64, &bar0->tx_fifo_partition_0);
980 val64 = 0;
981 break;
982 case 3:
983 writeq(val64, &bar0->tx_fifo_partition_1);
984 val64 = 0;
985 break;
986 case 5:
987 writeq(val64, &bar0->tx_fifo_partition_2);
988 val64 = 0;
989 break;
990 case 7:
991 writeq(val64, &bar0->tx_fifo_partition_3);
992 break;
993 }
994 }
995
996 /* Enable Tx FIFO partition 0. */
997 val64 = readq(&bar0->tx_fifo_partition_0);
998 val64 |= BIT(0); /* To enable the FIFO partition. */
999 writeq(val64, &bar0->tx_fifo_partition_0);
1000
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001001 /*
1002 * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug
1003 * SXE-008 TRANSMIT DMA ARBITRATION ISSUE.
1004 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001005 if ((nic->device_type == XFRAME_I_DEVICE) &&
1006 (get_xena_rev_id(nic->pdev) < 4))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001007 writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable);
1008
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 val64 = readq(&bar0->tx_fifo_partition_0);
1010 DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n",
1011 &bar0->tx_fifo_partition_0, (unsigned long long) val64);
1012
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001013 /*
1014 * Initialization of Tx_PA_CONFIG register to ignore packet
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 * integrity checking.
1016 */
1017 val64 = readq(&bar0->tx_pa_cfg);
1018 val64 |= TX_PA_CFG_IGNORE_FRM_ERR | TX_PA_CFG_IGNORE_SNAP_OUI |
1019 TX_PA_CFG_IGNORE_LLC_CTRL | TX_PA_CFG_IGNORE_L2_ERR;
1020 writeq(val64, &bar0->tx_pa_cfg);
1021
1022 /* Rx DMA intialization. */
1023 val64 = 0;
1024 for (i = 0; i < config->rx_ring_num; i++) {
1025 val64 |=
1026 vBIT(config->rx_cfg[i].ring_priority, (5 + (i * 8)),
1027 3);
1028 }
1029 writeq(val64, &bar0->rx_queue_priority);
1030
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001031 /*
1032 * Allocating equal share of memory to all the
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 * configured Rings.
1034 */
1035 val64 = 0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001036 if (nic->device_type & XFRAME_II_DEVICE)
1037 mem_size = 32;
1038 else
1039 mem_size = 64;
1040
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 for (i = 0; i < config->rx_ring_num; i++) {
1042 switch (i) {
1043 case 0:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001044 mem_share = (mem_size / config->rx_ring_num +
1045 mem_size % config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 val64 |= RX_QUEUE_CFG_Q0_SZ(mem_share);
1047 continue;
1048 case 1:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001049 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 val64 |= RX_QUEUE_CFG_Q1_SZ(mem_share);
1051 continue;
1052 case 2:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001053 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 val64 |= RX_QUEUE_CFG_Q2_SZ(mem_share);
1055 continue;
1056 case 3:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001057 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 val64 |= RX_QUEUE_CFG_Q3_SZ(mem_share);
1059 continue;
1060 case 4:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001061 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 val64 |= RX_QUEUE_CFG_Q4_SZ(mem_share);
1063 continue;
1064 case 5:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001065 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 val64 |= RX_QUEUE_CFG_Q5_SZ(mem_share);
1067 continue;
1068 case 6:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001069 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 val64 |= RX_QUEUE_CFG_Q6_SZ(mem_share);
1071 continue;
1072 case 7:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001073 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 val64 |= RX_QUEUE_CFG_Q7_SZ(mem_share);
1075 continue;
1076 }
1077 }
1078 writeq(val64, &bar0->rx_queue_cfg);
1079
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001080 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001081 * Filling Tx round robin registers
1082 * as per the number of FIFOs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 */
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001084 switch (config->tx_fifo_num) {
1085 case 1:
1086 val64 = 0x0000000000000000ULL;
1087 writeq(val64, &bar0->tx_w_round_robin_0);
1088 writeq(val64, &bar0->tx_w_round_robin_1);
1089 writeq(val64, &bar0->tx_w_round_robin_2);
1090 writeq(val64, &bar0->tx_w_round_robin_3);
1091 writeq(val64, &bar0->tx_w_round_robin_4);
1092 break;
1093 case 2:
1094 val64 = 0x0000010000010000ULL;
1095 writeq(val64, &bar0->tx_w_round_robin_0);
1096 val64 = 0x0100000100000100ULL;
1097 writeq(val64, &bar0->tx_w_round_robin_1);
1098 val64 = 0x0001000001000001ULL;
1099 writeq(val64, &bar0->tx_w_round_robin_2);
1100 val64 = 0x0000010000010000ULL;
1101 writeq(val64, &bar0->tx_w_round_robin_3);
1102 val64 = 0x0100000000000000ULL;
1103 writeq(val64, &bar0->tx_w_round_robin_4);
1104 break;
1105 case 3:
1106 val64 = 0x0001000102000001ULL;
1107 writeq(val64, &bar0->tx_w_round_robin_0);
1108 val64 = 0x0001020000010001ULL;
1109 writeq(val64, &bar0->tx_w_round_robin_1);
1110 val64 = 0x0200000100010200ULL;
1111 writeq(val64, &bar0->tx_w_round_robin_2);
1112 val64 = 0x0001000102000001ULL;
1113 writeq(val64, &bar0->tx_w_round_robin_3);
1114 val64 = 0x0001020000000000ULL;
1115 writeq(val64, &bar0->tx_w_round_robin_4);
1116 break;
1117 case 4:
1118 val64 = 0x0001020300010200ULL;
1119 writeq(val64, &bar0->tx_w_round_robin_0);
1120 val64 = 0x0100000102030001ULL;
1121 writeq(val64, &bar0->tx_w_round_robin_1);
1122 val64 = 0x0200010000010203ULL;
1123 writeq(val64, &bar0->tx_w_round_robin_2);
1124 val64 = 0x0001020001000001ULL;
1125 writeq(val64, &bar0->tx_w_round_robin_3);
1126 val64 = 0x0203000100000000ULL;
1127 writeq(val64, &bar0->tx_w_round_robin_4);
1128 break;
1129 case 5:
1130 val64 = 0x0001000203000102ULL;
1131 writeq(val64, &bar0->tx_w_round_robin_0);
1132 val64 = 0x0001020001030004ULL;
1133 writeq(val64, &bar0->tx_w_round_robin_1);
1134 val64 = 0x0001000203000102ULL;
1135 writeq(val64, &bar0->tx_w_round_robin_2);
1136 val64 = 0x0001020001030004ULL;
1137 writeq(val64, &bar0->tx_w_round_robin_3);
1138 val64 = 0x0001000000000000ULL;
1139 writeq(val64, &bar0->tx_w_round_robin_4);
1140 break;
1141 case 6:
1142 val64 = 0x0001020304000102ULL;
1143 writeq(val64, &bar0->tx_w_round_robin_0);
1144 val64 = 0x0304050001020001ULL;
1145 writeq(val64, &bar0->tx_w_round_robin_1);
1146 val64 = 0x0203000100000102ULL;
1147 writeq(val64, &bar0->tx_w_round_robin_2);
1148 val64 = 0x0304000102030405ULL;
1149 writeq(val64, &bar0->tx_w_round_robin_3);
1150 val64 = 0x0001000200000000ULL;
1151 writeq(val64, &bar0->tx_w_round_robin_4);
1152 break;
1153 case 7:
1154 val64 = 0x0001020001020300ULL;
1155 writeq(val64, &bar0->tx_w_round_robin_0);
1156 val64 = 0x0102030400010203ULL;
1157 writeq(val64, &bar0->tx_w_round_robin_1);
1158 val64 = 0x0405060001020001ULL;
1159 writeq(val64, &bar0->tx_w_round_robin_2);
1160 val64 = 0x0304050000010200ULL;
1161 writeq(val64, &bar0->tx_w_round_robin_3);
1162 val64 = 0x0102030000000000ULL;
1163 writeq(val64, &bar0->tx_w_round_robin_4);
1164 break;
1165 case 8:
1166 val64 = 0x0001020300040105ULL;
1167 writeq(val64, &bar0->tx_w_round_robin_0);
1168 val64 = 0x0200030106000204ULL;
1169 writeq(val64, &bar0->tx_w_round_robin_1);
1170 val64 = 0x0103000502010007ULL;
1171 writeq(val64, &bar0->tx_w_round_robin_2);
1172 val64 = 0x0304010002060500ULL;
1173 writeq(val64, &bar0->tx_w_round_robin_3);
1174 val64 = 0x0103020400000000ULL;
1175 writeq(val64, &bar0->tx_w_round_robin_4);
1176 break;
1177 }
1178
1179 /* Filling the Rx round robin registers as per the
1180 * number of Rings and steering based on QoS.
1181 */
1182 switch (config->rx_ring_num) {
1183 case 1:
1184 val64 = 0x8080808080808080ULL;
1185 writeq(val64, &bar0->rts_qos_steering);
1186 break;
1187 case 2:
1188 val64 = 0x0000010000010000ULL;
1189 writeq(val64, &bar0->rx_w_round_robin_0);
1190 val64 = 0x0100000100000100ULL;
1191 writeq(val64, &bar0->rx_w_round_robin_1);
1192 val64 = 0x0001000001000001ULL;
1193 writeq(val64, &bar0->rx_w_round_robin_2);
1194 val64 = 0x0000010000010000ULL;
1195 writeq(val64, &bar0->rx_w_round_robin_3);
1196 val64 = 0x0100000000000000ULL;
1197 writeq(val64, &bar0->rx_w_round_robin_4);
1198
1199 val64 = 0x8080808040404040ULL;
1200 writeq(val64, &bar0->rts_qos_steering);
1201 break;
1202 case 3:
1203 val64 = 0x0001000102000001ULL;
1204 writeq(val64, &bar0->rx_w_round_robin_0);
1205 val64 = 0x0001020000010001ULL;
1206 writeq(val64, &bar0->rx_w_round_robin_1);
1207 val64 = 0x0200000100010200ULL;
1208 writeq(val64, &bar0->rx_w_round_robin_2);
1209 val64 = 0x0001000102000001ULL;
1210 writeq(val64, &bar0->rx_w_round_robin_3);
1211 val64 = 0x0001020000000000ULL;
1212 writeq(val64, &bar0->rx_w_round_robin_4);
1213
1214 val64 = 0x8080804040402020ULL;
1215 writeq(val64, &bar0->rts_qos_steering);
1216 break;
1217 case 4:
1218 val64 = 0x0001020300010200ULL;
1219 writeq(val64, &bar0->rx_w_round_robin_0);
1220 val64 = 0x0100000102030001ULL;
1221 writeq(val64, &bar0->rx_w_round_robin_1);
1222 val64 = 0x0200010000010203ULL;
1223 writeq(val64, &bar0->rx_w_round_robin_2);
1224 val64 = 0x0001020001000001ULL;
1225 writeq(val64, &bar0->rx_w_round_robin_3);
1226 val64 = 0x0203000100000000ULL;
1227 writeq(val64, &bar0->rx_w_round_robin_4);
1228
1229 val64 = 0x8080404020201010ULL;
1230 writeq(val64, &bar0->rts_qos_steering);
1231 break;
1232 case 5:
1233 val64 = 0x0001000203000102ULL;
1234 writeq(val64, &bar0->rx_w_round_robin_0);
1235 val64 = 0x0001020001030004ULL;
1236 writeq(val64, &bar0->rx_w_round_robin_1);
1237 val64 = 0x0001000203000102ULL;
1238 writeq(val64, &bar0->rx_w_round_robin_2);
1239 val64 = 0x0001020001030004ULL;
1240 writeq(val64, &bar0->rx_w_round_robin_3);
1241 val64 = 0x0001000000000000ULL;
1242 writeq(val64, &bar0->rx_w_round_robin_4);
1243
1244 val64 = 0x8080404020201008ULL;
1245 writeq(val64, &bar0->rts_qos_steering);
1246 break;
1247 case 6:
1248 val64 = 0x0001020304000102ULL;
1249 writeq(val64, &bar0->rx_w_round_robin_0);
1250 val64 = 0x0304050001020001ULL;
1251 writeq(val64, &bar0->rx_w_round_robin_1);
1252 val64 = 0x0203000100000102ULL;
1253 writeq(val64, &bar0->rx_w_round_robin_2);
1254 val64 = 0x0304000102030405ULL;
1255 writeq(val64, &bar0->rx_w_round_robin_3);
1256 val64 = 0x0001000200000000ULL;
1257 writeq(val64, &bar0->rx_w_round_robin_4);
1258
1259 val64 = 0x8080404020100804ULL;
1260 writeq(val64, &bar0->rts_qos_steering);
1261 break;
1262 case 7:
1263 val64 = 0x0001020001020300ULL;
1264 writeq(val64, &bar0->rx_w_round_robin_0);
1265 val64 = 0x0102030400010203ULL;
1266 writeq(val64, &bar0->rx_w_round_robin_1);
1267 val64 = 0x0405060001020001ULL;
1268 writeq(val64, &bar0->rx_w_round_robin_2);
1269 val64 = 0x0304050000010200ULL;
1270 writeq(val64, &bar0->rx_w_round_robin_3);
1271 val64 = 0x0102030000000000ULL;
1272 writeq(val64, &bar0->rx_w_round_robin_4);
1273
1274 val64 = 0x8080402010080402ULL;
1275 writeq(val64, &bar0->rts_qos_steering);
1276 break;
1277 case 8:
1278 val64 = 0x0001020300040105ULL;
1279 writeq(val64, &bar0->rx_w_round_robin_0);
1280 val64 = 0x0200030106000204ULL;
1281 writeq(val64, &bar0->rx_w_round_robin_1);
1282 val64 = 0x0103000502010007ULL;
1283 writeq(val64, &bar0->rx_w_round_robin_2);
1284 val64 = 0x0304010002060500ULL;
1285 writeq(val64, &bar0->rx_w_round_robin_3);
1286 val64 = 0x0103020400000000ULL;
1287 writeq(val64, &bar0->rx_w_round_robin_4);
1288
1289 val64 = 0x8040201008040201ULL;
1290 writeq(val64, &bar0->rts_qos_steering);
1291 break;
1292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
1294 /* UDP Fix */
1295 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001296 for (i = 0; i < 8; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 writeq(val64, &bar0->rts_frm_len_n[i]);
1298
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001299 /* Set the default rts frame length for the rings configured */
1300 val64 = MAC_RTS_FRM_LEN_SET(dev->mtu+22);
1301 for (i = 0 ; i < config->rx_ring_num ; i++)
1302 writeq(val64, &bar0->rts_frm_len_n[i]);
1303
1304 /* Set the frame length for the configured rings
1305 * desired by the user
1306 */
1307 for (i = 0; i < config->rx_ring_num; i++) {
1308 /* If rts_frm_len[i] == 0 then it is assumed that user not
1309 * specified frame length steering.
1310 * If the user provides the frame length then program
1311 * the rts_frm_len register for those values or else
1312 * leave it as it is.
1313 */
1314 if (rts_frm_len[i] != 0) {
1315 writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]),
1316 &bar0->rts_frm_len_n[i]);
1317 }
1318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001320 /* Program statistics memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 writeq(mac_control->stats_mem_phy, &bar0->stat_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001323 if (nic->device_type == XFRAME_II_DEVICE) {
1324 val64 = STAT_BC(0x320);
1325 writeq(val64, &bar0->stat_byte_cnt);
1326 }
1327
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001328 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 * Initializing the sampling rate for the device to calculate the
1330 * bandwidth utilization.
1331 */
1332 val64 = MAC_TX_LINK_UTIL_VAL(tmac_util_period) |
1333 MAC_RX_LINK_UTIL_VAL(rmac_util_period);
1334 writeq(val64, &bar0->mac_link_util);
1335
1336
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001337 /*
1338 * Initializing the Transmit and Receive Traffic Interrupt
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 * Scheme.
1340 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001341 /*
1342 * TTI Initialization. Default Tx timer gets us about
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 * 250 interrupts per sec. Continuous interrupts are enabled
1344 * by default.
1345 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001346 if (nic->device_type == XFRAME_II_DEVICE) {
1347 int count = (nic->config.bus_speed * 125)/2;
1348 val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count);
1349 } else {
1350
1351 val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078);
1352 }
1353 val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 TTI_DATA1_MEM_TX_URNG_B(0x10) |
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001355 TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001356 if (use_continuous_tx_intrs)
1357 val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 writeq(val64, &bar0->tti_data1_mem);
1359
1360 val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
1361 TTI_DATA2_MEM_TX_UFC_B(0x20) |
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001362 TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 writeq(val64, &bar0->tti_data2_mem);
1364
1365 val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
1366 writeq(val64, &bar0->tti_command_mem);
1367
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001368 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 * Once the operation completes, the Strobe bit of the command
1370 * register will be reset. We poll for this particular condition
1371 * We wait for a maximum of 500ms for the operation to complete,
1372 * if it's not complete by then we return error.
1373 */
1374 time = 0;
1375 while (TRUE) {
1376 val64 = readq(&bar0->tti_command_mem);
1377 if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
1378 break;
1379 }
1380 if (time > 10) {
1381 DBG_PRINT(ERR_DBG, "%s: TTI init Failed\n",
1382 dev->name);
1383 return -1;
1384 }
1385 msleep(50);
1386 time++;
1387 }
1388
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001389 if (nic->config.bimodal) {
1390 int k = 0;
1391 for (k = 0; k < config->rx_ring_num; k++) {
1392 val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
1393 val64 |= TTI_CMD_MEM_OFFSET(0x38+k);
1394 writeq(val64, &bar0->tti_command_mem);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001395
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001396 /*
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001397 * Once the operation completes, the Strobe bit of the command
1398 * register will be reset. We poll for this particular condition
1399 * We wait for a maximum of 500ms for the operation to complete,
1400 * if it's not complete by then we return error.
1401 */
1402 time = 0;
1403 while (TRUE) {
1404 val64 = readq(&bar0->tti_command_mem);
1405 if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
1406 break;
1407 }
1408 if (time > 10) {
1409 DBG_PRINT(ERR_DBG,
1410 "%s: TTI init Failed\n",
1411 dev->name);
1412 return -1;
1413 }
1414 time++;
1415 msleep(50);
1416 }
1417 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001418 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001420 /* RTI Initialization */
1421 if (nic->device_type == XFRAME_II_DEVICE) {
1422 /*
1423 * Programmed to generate Apprx 500 Intrs per
1424 * second
1425 */
1426 int count = (nic->config.bus_speed * 125)/4;
1427 val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
1428 } else {
1429 val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 }
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001431 val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
1432 RTI_DATA1_MEM_RX_URNG_B(0x10) |
1433 RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
1434
1435 writeq(val64, &bar0->rti_data1_mem);
1436
1437 val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04001438 RTI_DATA2_MEM_RX_UFC_B(0x2) ;
1439 if (nic->intr_type == MSI_X)
1440 val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
1441 RTI_DATA2_MEM_RX_UFC_D(0x40));
1442 else
1443 val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \
1444 RTI_DATA2_MEM_RX_UFC_D(0x80));
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001445 writeq(val64, &bar0->rti_data2_mem);
1446
1447 for (i = 0; i < config->rx_ring_num; i++) {
1448 val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD
1449 | RTI_CMD_MEM_OFFSET(i);
1450 writeq(val64, &bar0->rti_command_mem);
1451
1452 /*
1453 * Once the operation completes, the Strobe bit of the
1454 * command register will be reset. We poll for this
1455 * particular condition. We wait for a maximum of 500ms
1456 * for the operation to complete, if it's not complete
1457 * by then we return error.
1458 */
1459 time = 0;
1460 while (TRUE) {
1461 val64 = readq(&bar0->rti_command_mem);
1462 if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) {
1463 break;
1464 }
1465 if (time > 10) {
1466 DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
1467 dev->name);
1468 return -1;
1469 }
1470 time++;
1471 msleep(50);
1472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 }
1475
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001476 /*
1477 * Initializing proper values as Pause threshold into all
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 * the 8 Queues on Rx side.
1479 */
1480 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q0q3);
1481 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7);
1482
1483 /* Disable RMAC PAD STRIPPING */
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01001484 add = &bar0->mac_cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 val64 = readq(&bar0->mac_cfg);
1486 val64 &= ~(MAC_CFG_RMAC_STRIP_PAD);
1487 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1488 writel((u32) (val64), add);
1489 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1490 writel((u32) (val64 >> 32), (add + 4));
1491 val64 = readq(&bar0->mac_cfg);
1492
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05001493 /* Enable FCS stripping by adapter */
1494 add = &bar0->mac_cfg;
1495 val64 = readq(&bar0->mac_cfg);
1496 val64 |= MAC_CFG_RMAC_STRIP_FCS;
1497 if (nic->device_type == XFRAME_II_DEVICE)
1498 writeq(val64, &bar0->mac_cfg);
1499 else {
1500 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1501 writel((u32) (val64), add);
1502 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1503 writel((u32) (val64 >> 32), (add + 4));
1504 }
1505
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001506 /*
1507 * Set the time value to be inserted in the pause frame
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 * generated by xena.
1509 */
1510 val64 = readq(&bar0->rmac_pause_cfg);
1511 val64 &= ~(RMAC_PAUSE_HG_PTIME(0xffff));
1512 val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time);
1513 writeq(val64, &bar0->rmac_pause_cfg);
1514
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001515 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 * Set the Threshold Limit for Generating the pause frame
1517 * If the amount of data in any Queue exceeds ratio of
1518 * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256
1519 * pause frame is generated
1520 */
1521 val64 = 0;
1522 for (i = 0; i < 4; i++) {
1523 val64 |=
1524 (((u64) 0xFF00 | nic->mac_control.
1525 mc_pause_threshold_q0q3)
1526 << (i * 2 * 8));
1527 }
1528 writeq(val64, &bar0->mc_pause_thresh_q0q3);
1529
1530 val64 = 0;
1531 for (i = 0; i < 4; i++) {
1532 val64 |=
1533 (((u64) 0xFF00 | nic->mac_control.
1534 mc_pause_threshold_q4q7)
1535 << (i * 2 * 8));
1536 }
1537 writeq(val64, &bar0->mc_pause_thresh_q4q7);
1538
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001539 /*
1540 * TxDMA will stop Read request if the number of read split has
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 * exceeded the limit pointed by shared_splits
1542 */
1543 val64 = readq(&bar0->pic_control);
1544 val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits);
1545 writeq(val64, &bar0->pic_control);
1546
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001547 /*
1548 * Programming the Herc to split every write transaction
1549 * that does not start on an ADB to reduce disconnects.
1550 */
1551 if (nic->device_type == XFRAME_II_DEVICE) {
1552 val64 = WREQ_SPLIT_MASK_SET_MASK(255);
1553 writeq(val64, &bar0->wreq_split_mask);
1554 }
1555
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001556 /* Setting Link stability period to 64 ms */
1557 if (nic->device_type == XFRAME_II_DEVICE) {
1558 val64 = MISC_LINK_STABILITY_PRD(3);
1559 writeq(val64, &bar0->misc_control);
1560 }
1561
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 return SUCCESS;
1563}
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001564#define LINK_UP_DOWN_INTERRUPT 1
1565#define MAC_RMAC_ERR_TIMER 2
1566
Adrian Bunkac1f60d2005-11-06 01:46:47 +01001567static int s2io_link_fault_indication(nic_t *nic)
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001568{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04001569 if (nic->intr_type != INTA)
1570 return MAC_RMAC_ERR_TIMER;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001571 if (nic->device_type == XFRAME_II_DEVICE)
1572 return LINK_UP_DOWN_INTERRUPT;
1573 else
1574 return MAC_RMAC_ERR_TIMER;
1575}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001577/**
1578 * en_dis_able_nic_intrs - Enable or Disable the interrupts
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 * @nic: device private variable,
1580 * @mask: A mask indicating which Intr block must be modified and,
1581 * @flag: A flag indicating whether to enable or disable the Intrs.
1582 * Description: This function will either disable or enable the interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001583 * depending on the flag argument. The mask argument can be used to
1584 * enable/disable any Intr block.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 * Return Value: NONE.
1586 */
1587
1588static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
1589{
1590 XENA_dev_config_t __iomem *bar0 = nic->bar0;
1591 register u64 val64 = 0, temp64 = 0;
1592
1593 /* Top level interrupt classification */
1594 /* PIC Interrupts */
1595 if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
1596 /* Enable PIC Intrs in the general intr mask register */
1597 val64 = TXPIC_INT_M | PIC_RX_INT_M;
1598 if (flag == ENABLE_INTRS) {
1599 temp64 = readq(&bar0->general_int_mask);
1600 temp64 &= ~((u64) val64);
1601 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001602 /*
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001603 * If Hercules adapter enable GPIO otherwise
1604 * disabled all PCIX, Flash, MDIO, IIC and GPIO
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001605 * interrupts for now.
1606 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001608 if (s2io_link_fault_indication(nic) ==
1609 LINK_UP_DOWN_INTERRUPT ) {
1610 temp64 = readq(&bar0->pic_int_mask);
1611 temp64 &= ~((u64) PIC_INT_GPIO);
1612 writeq(temp64, &bar0->pic_int_mask);
1613 temp64 = readq(&bar0->gpio_int_mask);
1614 temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP);
1615 writeq(temp64, &bar0->gpio_int_mask);
1616 } else {
1617 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
1618 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001619 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 * No MSI Support is available presently, so TTI and
1621 * RTI interrupts are also disabled.
1622 */
1623 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001624 /*
1625 * Disable PIC Intrs in the general
1626 * intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 */
1628 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
1629 temp64 = readq(&bar0->general_int_mask);
1630 val64 |= temp64;
1631 writeq(val64, &bar0->general_int_mask);
1632 }
1633 }
1634
1635 /* DMA Interrupts */
1636 /* Enabling/Disabling Tx DMA interrupts */
1637 if (mask & TX_DMA_INTR) {
1638 /* Enable TxDMA Intrs in the general intr mask register */
1639 val64 = TXDMA_INT_M;
1640 if (flag == ENABLE_INTRS) {
1641 temp64 = readq(&bar0->general_int_mask);
1642 temp64 &= ~((u64) val64);
1643 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001644 /*
1645 * Keep all interrupts other than PFC interrupt
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 * and PCC interrupt disabled in DMA level.
1647 */
1648 val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M |
1649 TXDMA_PCC_INT_M);
1650 writeq(val64, &bar0->txdma_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001651 /*
1652 * Enable only the MISC error 1 interrupt in PFC block
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 */
1654 val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1);
1655 writeq(val64, &bar0->pfc_err_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001656 /*
1657 * Enable only the FB_ECC error interrupt in PCC block
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 */
1659 val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR);
1660 writeq(val64, &bar0->pcc_err_mask);
1661 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001662 /*
1663 * Disable TxDMA Intrs in the general intr mask
1664 * register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 */
1666 writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask);
1667 writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask);
1668 temp64 = readq(&bar0->general_int_mask);
1669 val64 |= temp64;
1670 writeq(val64, &bar0->general_int_mask);
1671 }
1672 }
1673
1674 /* Enabling/Disabling Rx DMA interrupts */
1675 if (mask & RX_DMA_INTR) {
1676 /* Enable RxDMA Intrs in the general intr mask register */
1677 val64 = RXDMA_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 /*
1683 * All RxDMA block interrupts are disabled for now
1684 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 */
1686 writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
1687 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001688 /*
1689 * Disable RxDMA Intrs in the general intr mask
1690 * register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 */
1692 writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
1693 temp64 = readq(&bar0->general_int_mask);
1694 val64 |= temp64;
1695 writeq(val64, &bar0->general_int_mask);
1696 }
1697 }
1698
1699 /* MAC Interrupts */
1700 /* Enabling/Disabling MAC interrupts */
1701 if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
1702 val64 = TXMAC_INT_M | RXMAC_INT_M;
1703 if (flag == ENABLE_INTRS) {
1704 temp64 = readq(&bar0->general_int_mask);
1705 temp64 &= ~((u64) val64);
1706 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001707 /*
1708 * All MAC block error interrupts are disabled for now
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 * TODO
1710 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001712 /*
1713 * Disable MAC Intrs in the general intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 */
1715 writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask);
1716 writeq(DISABLE_ALL_INTRS,
1717 &bar0->mac_rmac_err_mask);
1718
1719 temp64 = readq(&bar0->general_int_mask);
1720 val64 |= temp64;
1721 writeq(val64, &bar0->general_int_mask);
1722 }
1723 }
1724
1725 /* XGXS Interrupts */
1726 if (mask & (TX_XGXS_INTR | RX_XGXS_INTR)) {
1727 val64 = TXXGXS_INT_M | RXXGXS_INT_M;
1728 if (flag == ENABLE_INTRS) {
1729 temp64 = readq(&bar0->general_int_mask);
1730 temp64 &= ~((u64) val64);
1731 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001732 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 * All XGXS block error interrupts are disabled for now
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001734 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 */
1736 writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
1737 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001738 /*
1739 * Disable MC Intrs in the general intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 */
1741 writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
1742 temp64 = readq(&bar0->general_int_mask);
1743 val64 |= temp64;
1744 writeq(val64, &bar0->general_int_mask);
1745 }
1746 }
1747
1748 /* Memory Controller(MC) interrupts */
1749 if (mask & MC_INTR) {
1750 val64 = MC_INT_M;
1751 if (flag == ENABLE_INTRS) {
1752 temp64 = readq(&bar0->general_int_mask);
1753 temp64 &= ~((u64) val64);
1754 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001755 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001756 * Enable all MC Intrs.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 */
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001758 writeq(0x0, &bar0->mc_int_mask);
1759 writeq(0x0, &bar0->mc_err_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 } else if (flag == DISABLE_INTRS) {
1761 /*
1762 * Disable MC Intrs in the general intr mask register
1763 */
1764 writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask);
1765 temp64 = readq(&bar0->general_int_mask);
1766 val64 |= temp64;
1767 writeq(val64, &bar0->general_int_mask);
1768 }
1769 }
1770
1771
1772 /* Tx traffic interrupts */
1773 if (mask & TX_TRAFFIC_INTR) {
1774 val64 = TXTRAFFIC_INT_M;
1775 if (flag == ENABLE_INTRS) {
1776 temp64 = readq(&bar0->general_int_mask);
1777 temp64 &= ~((u64) val64);
1778 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001779 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 * Enable all the Tx side interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001781 * writing 0 Enables all 64 TX interrupt levels
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 */
1783 writeq(0x0, &bar0->tx_traffic_mask);
1784 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001785 /*
1786 * Disable Tx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 * register.
1788 */
1789 writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask);
1790 temp64 = readq(&bar0->general_int_mask);
1791 val64 |= temp64;
1792 writeq(val64, &bar0->general_int_mask);
1793 }
1794 }
1795
1796 /* Rx traffic interrupts */
1797 if (mask & RX_TRAFFIC_INTR) {
1798 val64 = RXTRAFFIC_INT_M;
1799 if (flag == ENABLE_INTRS) {
1800 temp64 = readq(&bar0->general_int_mask);
1801 temp64 &= ~((u64) val64);
1802 writeq(temp64, &bar0->general_int_mask);
1803 /* writing 0 Enables all 8 RX interrupt levels */
1804 writeq(0x0, &bar0->rx_traffic_mask);
1805 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001806 /*
1807 * Disable Rx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 * register.
1809 */
1810 writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask);
1811 temp64 = readq(&bar0->general_int_mask);
1812 val64 |= temp64;
1813 writeq(val64, &bar0->general_int_mask);
1814 }
1815 }
1816}
1817
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001818static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001819{
1820 int ret = 0;
1821
1822 if (flag == FALSE) {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001823 if ((!herc && (rev_id >= 4)) || herc) {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001824 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) &&
1825 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1826 ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
1827 ret = 1;
1828 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001829 }else {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001830 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
1831 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1832 ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
1833 ret = 1;
1834 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001835 }
1836 } else {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001837 if ((!herc && (rev_id >= 4)) || herc) {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001838 if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
1839 ADAPTER_STATUS_RMAC_PCC_IDLE) &&
1840 (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
1841 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1842 ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
1843 ret = 1;
1844 }
1845 } else {
1846 if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
1847 ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
1848 (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
1849 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1850 ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
1851 ret = 1;
1852 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001853 }
1854 }
1855
1856 return ret;
1857}
1858/**
1859 * verify_xena_quiescence - Checks whether the H/W is ready
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 * @val64 : Value read from adapter status register.
1861 * @flag : indicates if the adapter enable bit was ever written once
1862 * before.
1863 * Description: Returns whether the H/W is ready to go or not. Depending
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001864 * on whether adapter enable bit was written or not the comparison
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 * differs and the calling function passes the input argument flag to
1866 * indicate this.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001867 * Return: 1 If xena is quiescence
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 * 0 If Xena is not quiescence
1869 */
1870
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001871static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872{
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001873 int ret = 0, herc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 u64 tmp64 = ~((u64) val64);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001875 int rev_id = get_xena_rev_id(sp->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001877 herc = (sp->device_type == XFRAME_II_DEVICE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 if (!
1879 (tmp64 &
1880 (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY |
1881 ADAPTER_STATUS_PFC_READY | ADAPTER_STATUS_TMAC_BUF_EMPTY |
1882 ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY |
1883 ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK |
1884 ADAPTER_STATUS_P_PLL_LOCK))) {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001885 ret = check_prc_pcc_state(val64, flag, rev_id, herc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 }
1887
1888 return ret;
1889}
1890
1891/**
1892 * fix_mac_address - Fix for Mac addr problem on Alpha platforms
1893 * @sp: Pointer to device specifc structure
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001894 * Description :
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 * New procedure to clear mac address reading problems on Alpha platforms
1896 *
1897 */
1898
Adrian Bunkac1f60d2005-11-06 01:46:47 +01001899static void fix_mac_address(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900{
1901 XENA_dev_config_t __iomem *bar0 = sp->bar0;
1902 u64 val64;
1903 int i = 0;
1904
1905 while (fix_mac[i] != END_SIGN) {
1906 writeq(fix_mac[i++], &bar0->gpio_control);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001907 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 val64 = readq(&bar0->gpio_control);
1909 }
1910}
1911
1912/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001913 * start_nic - Turns the device on
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001915 * Description:
1916 * This function actually turns the device on. Before this function is
1917 * called,all Registers are configured from their reset states
1918 * and shared memory is allocated but the NIC is still quiescent. On
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 * calling this function, the device interrupts are cleared and the NIC is
1920 * literally switched on by writing into the adapter control register.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001921 * Return Value:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 * SUCCESS on success and -1 on failure.
1923 */
1924
1925static int start_nic(struct s2io_nic *nic)
1926{
1927 XENA_dev_config_t __iomem *bar0 = nic->bar0;
1928 struct net_device *dev = nic->dev;
1929 register u64 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001930 u16 interruptible;
1931 u16 subid, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 mac_info_t *mac_control;
1933 struct config_param *config;
1934
1935 mac_control = &nic->mac_control;
1936 config = &nic->config;
1937
1938 /* PRC Initialization and configuration */
1939 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001940 writeq((u64) mac_control->rings[i].rx_blocks[0].block_dma_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 &bar0->prc_rxd0_n[i]);
1942
1943 val64 = readq(&bar0->prc_ctrl_n[i]);
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001944 if (nic->config.bimodal)
1945 val64 |= PRC_CTRL_BIMODAL_INTERRUPT;
Ananda Rajuda6971d2005-10-31 16:55:31 -05001946 if (nic->rxd_mode == RXD_MODE_1)
1947 val64 |= PRC_CTRL_RC_ENABLED;
1948 else
1949 val64 |= PRC_CTRL_RC_ENABLED | PRC_CTRL_RING_MODE_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 writeq(val64, &bar0->prc_ctrl_n[i]);
1951 }
1952
Ananda Rajuda6971d2005-10-31 16:55:31 -05001953 if (nic->rxd_mode == RXD_MODE_3B) {
1954 /* Enabling 2 buffer mode by writing into Rx_pa_cfg reg. */
1955 val64 = readq(&bar0->rx_pa_cfg);
1956 val64 |= RX_PA_CFG_IGNORE_L2_ERR;
1957 writeq(val64, &bar0->rx_pa_cfg);
1958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001960 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 * Enabling MC-RLDRAM. After enabling the device, we timeout
1962 * for around 100ms, which is approximately the time required
1963 * for the device to be ready for operation.
1964 */
1965 val64 = readq(&bar0->mc_rldram_mrs);
1966 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE | MC_RLDRAM_MRS_ENABLE;
1967 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
1968 val64 = readq(&bar0->mc_rldram_mrs);
1969
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001970 msleep(100); /* Delay by around 100 ms. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971
1972 /* Enabling ECC Protection. */
1973 val64 = readq(&bar0->adapter_control);
1974 val64 &= ~ADAPTER_ECC_EN;
1975 writeq(val64, &bar0->adapter_control);
1976
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001977 /*
1978 * Clearing any possible Link state change interrupts that
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 * could have popped up just before Enabling the card.
1980 */
1981 val64 = readq(&bar0->mac_rmac_err_reg);
1982 if (val64)
1983 writeq(val64, &bar0->mac_rmac_err_reg);
1984
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001985 /*
1986 * Verify if the device is ready to be enabled, if so enable
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 * it.
1988 */
1989 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001990 if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name);
1992 DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n",
1993 (unsigned long long) val64);
1994 return FAILURE;
1995 }
1996
1997 /* Enable select interrupts */
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04001998 if (nic->intr_type != INTA)
1999 en_dis_able_nic_intrs(nic, ENA_ALL_INTRS, DISABLE_INTRS);
2000 else {
2001 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
2002 interruptible |= TX_PIC_INTR | RX_PIC_INTR;
2003 interruptible |= TX_MAC_INTR | RX_MAC_INTR;
2004 en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS);
2005 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002007 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 * With some switches, link might be already up at this point.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002009 * Because of this weird behavior, when we enable laser,
2010 * we may not get link. We need to handle this. We cannot
2011 * figure out which switch is misbehaving. So we are forced to
2012 * make a global change.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 */
2014
2015 /* Enabling Laser. */
2016 val64 = readq(&bar0->adapter_control);
2017 val64 |= ADAPTER_EOI_TX_ON;
2018 writeq(val64, &bar0->adapter_control);
2019
2020 /* SXE-002: Initialize link and activity LED */
2021 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07002022 if (((subid & 0xFF) >= 0x07) &&
2023 (nic->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 val64 = readq(&bar0->gpio_control);
2025 val64 |= 0x0000800000000000ULL;
2026 writeq(val64, &bar0->gpio_control);
2027 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01002028 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 }
2030
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002031 /*
2032 * Don't see link state interrupts on certain switches, so
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 * directly scheduling a link state task from here.
2034 */
2035 schedule_work(&nic->set_link_task);
2036
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 return SUCCESS;
2038}
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002039/**
2040 * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb
2041 */
2042static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, int get_off)
2043{
2044 nic_t *nic = fifo_data->nic;
2045 struct sk_buff *skb;
2046 TxD_t *txds;
2047 u16 j, frg_cnt;
2048
2049 txds = txdlp;
Andrew Morton26b76252005-12-14 19:25:23 -08002050 if (txds->Host_Control == (u64)(long)nic->ufo_in_band_v) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002051 pci_unmap_single(nic->pdev, (dma_addr_t)
2052 txds->Buffer_Pointer, sizeof(u64),
2053 PCI_DMA_TODEVICE);
2054 txds++;
2055 }
2056
2057 skb = (struct sk_buff *) ((unsigned long)
2058 txds->Host_Control);
2059 if (!skb) {
2060 memset(txdlp, 0, (sizeof(TxD_t) * fifo_data->max_txds));
2061 return NULL;
2062 }
2063 pci_unmap_single(nic->pdev, (dma_addr_t)
2064 txds->Buffer_Pointer,
2065 skb->len - skb->data_len,
2066 PCI_DMA_TODEVICE);
2067 frg_cnt = skb_shinfo(skb)->nr_frags;
2068 if (frg_cnt) {
2069 txds++;
2070 for (j = 0; j < frg_cnt; j++, txds++) {
2071 skb_frag_t *frag = &skb_shinfo(skb)->frags[j];
2072 if (!txds->Buffer_Pointer)
2073 break;
2074 pci_unmap_page(nic->pdev, (dma_addr_t)
2075 txds->Buffer_Pointer,
2076 frag->size, PCI_DMA_TODEVICE);
2077 }
2078 }
2079 txdlp->Host_Control = 0;
2080 return(skb);
2081}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002083/**
2084 * free_tx_buffers - Free all queued Tx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002086 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 * Free all queued Tx buffers.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002088 * Return Value: void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089*/
2090
2091static void free_tx_buffers(struct s2io_nic *nic)
2092{
2093 struct net_device *dev = nic->dev;
2094 struct sk_buff *skb;
2095 TxD_t *txdp;
2096 int i, j;
2097 mac_info_t *mac_control;
2098 struct config_param *config;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002099 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100
2101 mac_control = &nic->mac_control;
2102 config = &nic->config;
2103
2104 for (i = 0; i < config->tx_fifo_num; i++) {
2105 for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002106 txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 list_virt_addr;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002108 skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
2109 if (skb) {
2110 dev_kfree_skb(skb);
2111 cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 }
2114 DBG_PRINT(INTR_DBG,
2115 "%s:forcibly freeing %d skbs on FIFO%d\n",
2116 dev->name, cnt, i);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002117 mac_control->fifos[i].tx_curr_get_info.offset = 0;
2118 mac_control->fifos[i].tx_curr_put_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 }
2120}
2121
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002122/**
2123 * stop_nic - To stop the nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 * @nic ; device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002125 * Description:
2126 * This function does exactly the opposite of what the start_nic()
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 * function does. This function is called to stop the device.
2128 * Return Value:
2129 * void.
2130 */
2131
2132static void stop_nic(struct s2io_nic *nic)
2133{
2134 XENA_dev_config_t __iomem *bar0 = nic->bar0;
2135 register u64 val64 = 0;
2136 u16 interruptible, i;
2137 mac_info_t *mac_control;
2138 struct config_param *config;
2139
2140 mac_control = &nic->mac_control;
2141 config = &nic->config;
2142
2143 /* Disable all interrupts */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002144 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07002145 interruptible |= TX_PIC_INTR | RX_PIC_INTR;
2146 interruptible |= TX_MAC_INTR | RX_MAC_INTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
2148
2149 /* Disable PRCs */
2150 for (i = 0; i < config->rx_ring_num; i++) {
2151 val64 = readq(&bar0->prc_ctrl_n[i]);
2152 val64 &= ~((u64) PRC_CTRL_RC_ENABLED);
2153 writeq(val64, &bar0->prc_ctrl_n[i]);
2154 }
2155}
2156
Ananda Rajuda6971d2005-10-31 16:55:31 -05002157int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
2158{
2159 struct net_device *dev = nic->dev;
2160 struct sk_buff *frag_list;
Jeff Garzik50eb8002005-11-05 23:40:46 -05002161 void *tmp;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002162
2163 /* Buffer-1 receives L3/L4 headers */
2164 ((RxD3_t*)rxdp)->Buffer1_ptr = pci_map_single
2165 (nic->pdev, skb->data, l3l4hdr_size + 4,
2166 PCI_DMA_FROMDEVICE);
2167
2168 /* skb_shinfo(skb)->frag_list will have L4 data payload */
2169 skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE);
2170 if (skb_shinfo(skb)->frag_list == NULL) {
2171 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
2172 return -ENOMEM ;
2173 }
2174 frag_list = skb_shinfo(skb)->frag_list;
2175 frag_list->next = NULL;
Jeff Garzik50eb8002005-11-05 23:40:46 -05002176 tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
2177 frag_list->data = tmp;
2178 frag_list->tail = tmp;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002179
2180 /* Buffer-2 receives L4 data payload */
2181 ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
2182 frag_list->data, dev->mtu,
2183 PCI_DMA_FROMDEVICE);
2184 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
2185 rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
2186
2187 return SUCCESS;
2188}
2189
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002190/**
2191 * fill_rx_buffers - Allocates the Rx side skbs
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002193 * @ring_no: ring number
2194 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 * The function allocates Rx side skbs and puts the physical
2196 * address of these buffers into the RxD buffer pointers, so that the NIC
2197 * can DMA the received frame into these locations.
2198 * The NIC supports 3 receive modes, viz
2199 * 1. single buffer,
2200 * 2. three buffer and
2201 * 3. Five buffer modes.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002202 * Each mode defines how many fragments the received frame will be split
2203 * up into by the NIC. The frame is split into L3 header, L4 Header,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 * L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself
2205 * is split into 3 fragments. As of now only single buffer mode is
2206 * supported.
2207 * Return Value:
2208 * SUCCESS on success or an appropriate -ve value on failure.
2209 */
2210
Adrian Bunkac1f60d2005-11-06 01:46:47 +01002211static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212{
2213 struct net_device *dev = nic->dev;
2214 struct sk_buff *skb;
2215 RxD_t *rxdp;
2216 int off, off1, size, block_no, block_no1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 u32 alloc_tab = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002218 u32 alloc_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 mac_info_t *mac_control;
2220 struct config_param *config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002221 u64 tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 buffAdd_t *ba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223#ifndef CONFIG_S2IO_NAPI
2224 unsigned long flags;
2225#endif
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002226 RxD_t *first_rxdp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227
2228 mac_control = &nic->mac_control;
2229 config = &nic->config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002230 alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
2231 atomic_read(&nic->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
2233 while (alloc_tab < alloc_cnt) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002234 block_no = mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 block_index;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002236 block_no1 = mac_control->rings[ring_no].rx_curr_get_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 block_index;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002238 off = mac_control->rings[ring_no].rx_curr_put_info.offset;
2239 off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240
Ananda Rajuda6971d2005-10-31 16:55:31 -05002241 rxdp = mac_control->rings[ring_no].
2242 rx_blocks[block_no].rxds[off].virt_addr;
2243
2244 if ((block_no == block_no1) && (off == off1) &&
2245 (rxdp->Host_Control)) {
2246 DBG_PRINT(INTR_DBG, "%s: Get and Put",
2247 dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 DBG_PRINT(INTR_DBG, " info equated\n");
2249 goto end;
2250 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002251 if (off && (off == rxd_count[nic->rxd_mode])) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002252 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 block_index++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002254 if (mac_control->rings[ring_no].rx_curr_put_info.
2255 block_index == mac_control->rings[ring_no].
2256 block_count)
2257 mac_control->rings[ring_no].rx_curr_put_info.
2258 block_index = 0;
2259 block_no = mac_control->rings[ring_no].
2260 rx_curr_put_info.block_index;
2261 if (off == rxd_count[nic->rxd_mode])
2262 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002263 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002264 offset = off;
2265 rxdp = mac_control->rings[ring_no].
2266 rx_blocks[block_no].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
2268 dev->name, rxdp);
2269 }
2270#ifndef CONFIG_S2IO_NAPI
2271 spin_lock_irqsave(&nic->put_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002272 mac_control->rings[ring_no].put_pos =
Ananda Rajuda6971d2005-10-31 16:55:31 -05002273 (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 spin_unlock_irqrestore(&nic->put_lock, flags);
2275#endif
Ananda Rajuda6971d2005-10-31 16:55:31 -05002276 if ((rxdp->Control_1 & RXD_OWN_XENA) &&
2277 ((nic->rxd_mode >= RXD_MODE_3A) &&
2278 (rxdp->Control_2 & BIT(0)))) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002279 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002280 offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 goto end;
2282 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002283 /* calculate size of skb based on ring mode */
2284 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
2285 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
2286 if (nic->rxd_mode == RXD_MODE_1)
2287 size += NET_IP_ALIGN;
2288 else if (nic->rxd_mode == RXD_MODE_3B)
2289 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
2290 else
2291 size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
Ananda Rajuda6971d2005-10-31 16:55:31 -05002293 /* allocate skb */
2294 skb = dev_alloc_skb(size);
2295 if(!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
2297 DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002298 if (first_rxdp) {
2299 wmb();
2300 first_rxdp->Control_1 |= RXD_OWN_XENA;
2301 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002302 return -ENOMEM ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002304 if (nic->rxd_mode == RXD_MODE_1) {
2305 /* 1 buffer mode - normal operation mode */
2306 memset(rxdp, 0, sizeof(RxD1_t));
2307 skb_reserve(skb, NET_IP_ALIGN);
2308 ((RxD1_t*)rxdp)->Buffer0_ptr = pci_map_single
2309 (nic->pdev, skb->data, size, PCI_DMA_FROMDEVICE);
2310 rxdp->Control_2 &= (~MASK_BUFFER0_SIZE_1);
2311 rxdp->Control_2 |= SET_BUFFER0_SIZE_1(size);
2312
2313 } else if (nic->rxd_mode >= RXD_MODE_3A) {
2314 /*
2315 * 2 or 3 buffer mode -
2316 * Both 2 buffer mode and 3 buffer mode provides 128
2317 * byte aligned receive buffers.
2318 *
2319 * 3 buffer mode provides header separation where in
2320 * skb->data will have L3/L4 headers where as
2321 * skb_shinfo(skb)->frag_list will have the L4 data
2322 * payload
2323 */
2324
2325 memset(rxdp, 0, sizeof(RxD3_t));
2326 ba = &mac_control->rings[ring_no].ba[block_no][off];
2327 skb_reserve(skb, BUF0_LEN);
2328 tmp = (u64)(unsigned long) skb->data;
2329 tmp += ALIGN_SIZE;
2330 tmp &= ~ALIGN_SIZE;
2331 skb->data = (void *) (unsigned long)tmp;
2332 skb->tail = (void *) (unsigned long)tmp;
2333
2334 ((RxD3_t*)rxdp)->Buffer0_ptr =
2335 pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
2336 PCI_DMA_FROMDEVICE);
2337 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
2338 if (nic->rxd_mode == RXD_MODE_3B) {
2339 /* Two buffer mode */
2340
2341 /*
2342 * Buffer2 will have L3/L4 header plus
2343 * L4 payload
2344 */
2345 ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single
2346 (nic->pdev, skb->data, dev->mtu + 4,
2347 PCI_DMA_FROMDEVICE);
2348
2349 /* Buffer-1 will be dummy buffer not used */
2350 ((RxD3_t*)rxdp)->Buffer1_ptr =
2351 pci_map_single(nic->pdev, ba->ba_1, BUF1_LEN,
2352 PCI_DMA_FROMDEVICE);
2353 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
2354 rxdp->Control_2 |= SET_BUFFER2_SIZE_3
2355 (dev->mtu + 4);
2356 } else {
2357 /* 3 buffer mode */
2358 if (fill_rxd_3buf(nic, rxdp, skb) == -ENOMEM) {
2359 dev_kfree_skb_irq(skb);
2360 if (first_rxdp) {
2361 wmb();
2362 first_rxdp->Control_1 |=
2363 RXD_OWN_XENA;
2364 }
2365 return -ENOMEM ;
2366 }
2367 }
2368 rxdp->Control_2 |= BIT(0);
2369 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 rxdp->Host_Control = (unsigned long) (skb);
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002371 if (alloc_tab & ((1 << rxsync_frequency) - 1))
2372 rxdp->Control_1 |= RXD_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 off++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002374 if (off == (rxd_count[nic->rxd_mode] + 1))
2375 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002376 mac_control->rings[ring_no].rx_curr_put_info.offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002378 rxdp->Control_2 |= SET_RXD_MARKER;
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002379 if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
2380 if (first_rxdp) {
2381 wmb();
2382 first_rxdp->Control_1 |= RXD_OWN_XENA;
2383 }
2384 first_rxdp = rxdp;
2385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 atomic_inc(&nic->rx_bufs_left[ring_no]);
2387 alloc_tab++;
2388 }
2389
2390 end:
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002391 /* Transfer ownership of first descriptor to adapter just before
2392 * exiting. Before that, use memory barrier so that ownership
2393 * and other fields are seen by adapter correctly.
2394 */
2395 if (first_rxdp) {
2396 wmb();
2397 first_rxdp->Control_1 |= RXD_OWN_XENA;
2398 }
2399
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 return SUCCESS;
2401}
2402
Ananda Rajuda6971d2005-10-31 16:55:31 -05002403static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
2404{
2405 struct net_device *dev = sp->dev;
2406 int j;
2407 struct sk_buff *skb;
2408 RxD_t *rxdp;
2409 mac_info_t *mac_control;
2410 buffAdd_t *ba;
2411
2412 mac_control = &sp->mac_control;
2413 for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
2414 rxdp = mac_control->rings[ring_no].
2415 rx_blocks[blk].rxds[j].virt_addr;
2416 skb = (struct sk_buff *)
2417 ((unsigned long) rxdp->Host_Control);
2418 if (!skb) {
2419 continue;
2420 }
2421 if (sp->rxd_mode == RXD_MODE_1) {
2422 pci_unmap_single(sp->pdev, (dma_addr_t)
2423 ((RxD1_t*)rxdp)->Buffer0_ptr,
2424 dev->mtu +
2425 HEADER_ETHERNET_II_802_3_SIZE
2426 + HEADER_802_2_SIZE +
2427 HEADER_SNAP_SIZE,
2428 PCI_DMA_FROMDEVICE);
2429 memset(rxdp, 0, sizeof(RxD1_t));
2430 } else if(sp->rxd_mode == RXD_MODE_3B) {
2431 ba = &mac_control->rings[ring_no].
2432 ba[blk][j];
2433 pci_unmap_single(sp->pdev, (dma_addr_t)
2434 ((RxD3_t*)rxdp)->Buffer0_ptr,
2435 BUF0_LEN,
2436 PCI_DMA_FROMDEVICE);
2437 pci_unmap_single(sp->pdev, (dma_addr_t)
2438 ((RxD3_t*)rxdp)->Buffer1_ptr,
2439 BUF1_LEN,
2440 PCI_DMA_FROMDEVICE);
2441 pci_unmap_single(sp->pdev, (dma_addr_t)
2442 ((RxD3_t*)rxdp)->Buffer2_ptr,
2443 dev->mtu + 4,
2444 PCI_DMA_FROMDEVICE);
2445 memset(rxdp, 0, sizeof(RxD3_t));
2446 } else {
2447 pci_unmap_single(sp->pdev, (dma_addr_t)
2448 ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
2449 PCI_DMA_FROMDEVICE);
2450 pci_unmap_single(sp->pdev, (dma_addr_t)
2451 ((RxD3_t*)rxdp)->Buffer1_ptr,
2452 l3l4hdr_size + 4,
2453 PCI_DMA_FROMDEVICE);
2454 pci_unmap_single(sp->pdev, (dma_addr_t)
2455 ((RxD3_t*)rxdp)->Buffer2_ptr, dev->mtu,
2456 PCI_DMA_FROMDEVICE);
2457 memset(rxdp, 0, sizeof(RxD3_t));
2458 }
2459 dev_kfree_skb(skb);
2460 atomic_dec(&sp->rx_bufs_left[ring_no]);
2461 }
2462}
2463
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002465 * free_rx_buffers - Frees all Rx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 * @sp: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002467 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 * This function will free all Rx buffers allocated by host.
2469 * Return Value:
2470 * NONE.
2471 */
2472
2473static void free_rx_buffers(struct s2io_nic *sp)
2474{
2475 struct net_device *dev = sp->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002476 int i, blk = 0, buf_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 mac_info_t *mac_control;
2478 struct config_param *config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
2480 mac_control = &sp->mac_control;
2481 config = &sp->config;
2482
2483 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -05002484 for (blk = 0; blk < rx_ring_sz[i]; blk++)
2485 free_rxd_blk(sp,i,blk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002487 mac_control->rings[i].rx_curr_put_info.block_index = 0;
2488 mac_control->rings[i].rx_curr_get_info.block_index = 0;
2489 mac_control->rings[i].rx_curr_put_info.offset = 0;
2490 mac_control->rings[i].rx_curr_get_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 atomic_set(&sp->rx_bufs_left[i], 0);
2492 DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
2493 dev->name, buf_cnt, i);
2494 }
2495}
2496
2497/**
2498 * s2io_poll - Rx interrupt handler for NAPI support
2499 * @dev : pointer to the device structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002500 * @budget : The number of packets that were budgeted to be processed
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 * during one pass through the 'Poll" function.
2502 * Description:
2503 * Comes into picture only if NAPI support has been incorporated. It does
2504 * the same thing that rx_intr_handler does, but not in a interrupt context
2505 * also It will process only a given number of packets.
2506 * Return value:
2507 * 0 on success and 1 if there are No Rx packets to be processed.
2508 */
2509
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002510#if defined(CONFIG_S2IO_NAPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511static int s2io_poll(struct net_device *dev, int *budget)
2512{
2513 nic_t *nic = dev->priv;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002514 int pkt_cnt = 0, org_pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 mac_info_t *mac_control;
2516 struct config_param *config;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01002517 XENA_dev_config_t __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002518 u64 val64;
2519 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002521 atomic_inc(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 mac_control = &nic->mac_control;
2523 config = &nic->config;
2524
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002525 nic->pkts_to_process = *budget;
2526 if (nic->pkts_to_process > dev->quota)
2527 nic->pkts_to_process = dev->quota;
2528 org_pkts_to_process = nic->pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
2530 val64 = readq(&bar0->rx_traffic_int);
2531 writeq(val64, &bar0->rx_traffic_int);
2532
2533 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002534 rx_intr_handler(&mac_control->rings[i]);
2535 pkt_cnt = org_pkts_to_process - nic->pkts_to_process;
2536 if (!nic->pkts_to_process) {
2537 /* Quota for the current iteration has been met */
2538 goto no_rx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 }
2541 if (!pkt_cnt)
2542 pkt_cnt = 1;
2543
2544 dev->quota -= pkt_cnt;
2545 *budget -= pkt_cnt;
2546 netif_rx_complete(dev);
2547
2548 for (i = 0; i < config->rx_ring_num; i++) {
2549 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2550 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2551 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2552 break;
2553 }
2554 }
2555 /* Re enable the Rx interrupts. */
2556 en_dis_able_nic_intrs(nic, RX_TRAFFIC_INTR, ENABLE_INTRS);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002557 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 return 0;
2559
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002560no_rx:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 dev->quota -= pkt_cnt;
2562 *budget -= pkt_cnt;
2563
2564 for (i = 0; i < config->rx_ring_num; i++) {
2565 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2566 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2567 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2568 break;
2569 }
2570 }
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002571 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 return 1;
2573}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002574#endif
2575
2576/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 * rx_intr_handler - Rx interrupt handler
2578 * @nic: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002579 * Description:
2580 * If the interrupt is because of a received frame or if the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 * receive ring contains fresh as yet un-processed frames,this function is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002582 * called. It picks out the RxD at which place the last Rx processing had
2583 * stopped and sends the skb to the OSM's Rx handler and then increments
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 * the offset.
2585 * Return Value:
2586 * NONE.
2587 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002588static void rx_intr_handler(ring_info_t *ring_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002590 nic_t *nic = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 struct net_device *dev = (struct net_device *) nic->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002592 int get_block, put_block, put_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 rx_curr_get_info_t get_info, put_info;
2594 RxD_t *rxdp;
2595 struct sk_buff *skb;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002596#ifndef CONFIG_S2IO_NAPI
2597 int pkt_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598#endif
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002599 int i;
2600
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002601 spin_lock(&nic->rx_lock);
2602 if (atomic_read(&nic->card_state) == CARD_DOWN) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002603 DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002604 __FUNCTION__, dev->name);
2605 spin_unlock(&nic->rx_lock);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002606 return;
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002607 }
2608
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002609 get_info = ring_data->rx_curr_get_info;
2610 get_block = get_info.block_index;
2611 put_info = ring_data->rx_curr_put_info;
2612 put_block = put_info.block_index;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002613 rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002614#ifndef CONFIG_S2IO_NAPI
2615 spin_lock(&nic->put_lock);
2616 put_offset = ring_data->put_pos;
2617 spin_unlock(&nic->put_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618#else
Ananda Rajuda6971d2005-10-31 16:55:31 -05002619 put_offset = (put_block * (rxd_count[nic->rxd_mode] + 1)) +
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002620 put_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621#endif
Ananda Rajuda6971d2005-10-31 16:55:31 -05002622 while (RXD_IS_UP2DT(rxdp)) {
2623 /* If your are next to put index then it's FIFO full condition */
2624 if ((get_block == put_block) &&
2625 (get_info.offset + 1) == put_info.offset) {
2626 DBG_PRINT(ERR_DBG, "%s: Ring Full\n",dev->name);
2627 break;
2628 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002629 skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
2630 if (skb == NULL) {
2631 DBG_PRINT(ERR_DBG, "%s: The skb is ",
2632 dev->name);
2633 DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002634 spin_unlock(&nic->rx_lock);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002635 return;
2636 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002637 if (nic->rxd_mode == RXD_MODE_1) {
2638 pci_unmap_single(nic->pdev, (dma_addr_t)
2639 ((RxD1_t*)rxdp)->Buffer0_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002640 dev->mtu +
2641 HEADER_ETHERNET_II_802_3_SIZE +
2642 HEADER_802_2_SIZE +
2643 HEADER_SNAP_SIZE,
2644 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002645 } else if (nic->rxd_mode == RXD_MODE_3B) {
2646 pci_unmap_single(nic->pdev, (dma_addr_t)
2647 ((RxD3_t*)rxdp)->Buffer0_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002648 BUF0_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002649 pci_unmap_single(nic->pdev, (dma_addr_t)
2650 ((RxD3_t*)rxdp)->Buffer1_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002651 BUF1_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002652 pci_unmap_single(nic->pdev, (dma_addr_t)
2653 ((RxD3_t*)rxdp)->Buffer2_ptr,
2654 dev->mtu + 4,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002655 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002656 } else {
2657 pci_unmap_single(nic->pdev, (dma_addr_t)
2658 ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
2659 PCI_DMA_FROMDEVICE);
2660 pci_unmap_single(nic->pdev, (dma_addr_t)
2661 ((RxD3_t*)rxdp)->Buffer1_ptr,
2662 l3l4hdr_size + 4,
2663 PCI_DMA_FROMDEVICE);
2664 pci_unmap_single(nic->pdev, (dma_addr_t)
2665 ((RxD3_t*)rxdp)->Buffer2_ptr,
2666 dev->mtu, PCI_DMA_FROMDEVICE);
2667 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002668 rx_osm_handler(ring_data, rxdp);
2669 get_info.offset++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002670 ring_data->rx_curr_get_info.offset = get_info.offset;
2671 rxdp = ring_data->rx_blocks[get_block].
2672 rxds[get_info.offset].virt_addr;
2673 if (get_info.offset == rxd_count[nic->rxd_mode]) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002674 get_info.offset = 0;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002675 ring_data->rx_curr_get_info.offset = get_info.offset;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002676 get_block++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002677 if (get_block == ring_data->block_count)
2678 get_block = 0;
2679 ring_data->rx_curr_get_info.block_index = get_block;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002680 rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
2681 }
2682
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002683#ifdef CONFIG_S2IO_NAPI
2684 nic->pkts_to_process -= 1;
2685 if (!nic->pkts_to_process)
2686 break;
2687#else
2688 pkt_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
2690 break;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002691#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002693 if (nic->lro) {
2694 /* Clear all LRO sessions before exiting */
2695 for (i=0; i<MAX_LRO_SESSIONS; i++) {
2696 lro_t *lro = &nic->lro0_n[i];
2697 if (lro->in_use) {
2698 update_L3L4_header(nic, lro);
2699 queue_rx_frame(lro->parent);
2700 clear_lro_session(lro);
2701 }
2702 }
2703 }
2704
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002705 spin_unlock(&nic->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002707
2708/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 * tx_intr_handler - Transmit interrupt handler
2710 * @nic : device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002711 * Description:
2712 * If an interrupt was raised to indicate DMA complete of the
2713 * Tx packet, this function is called. It identifies the last TxD
2714 * whose buffer was freed and frees all skbs whose data have already
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 * DMA'ed into the NICs internal memory.
2716 * Return Value:
2717 * NONE
2718 */
2719
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002720static void tx_intr_handler(fifo_info_t *fifo_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002722 nic_t *nic = fifo_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 struct net_device *dev = (struct net_device *) nic->dev;
2724 tx_curr_get_info_t get_info, put_info;
2725 struct sk_buff *skb;
2726 TxD_t *txdlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002728 get_info = fifo_data->tx_curr_get_info;
2729 put_info = fifo_data->tx_curr_put_info;
2730 txdlp = (TxD_t *) fifo_data->list_info[get_info.offset].
2731 list_virt_addr;
2732 while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
2733 (get_info.offset != put_info.offset) &&
2734 (txdlp->Host_Control)) {
2735 /* Check for TxD errors */
2736 if (txdlp->Control_1 & TXD_T_CODE) {
2737 unsigned long long err;
2738 err = txdlp->Control_1 & TXD_T_CODE;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002739 if ((err >> 48) == 0xA) {
2740 DBG_PRINT(TX_DBG, "TxD returned due \
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04002741to loss of link\n");
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002742 }
2743 else {
2744 DBG_PRINT(ERR_DBG, "***TxD error \
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04002745%llx\n", err);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002748
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002749 skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002750 if (skb == NULL) {
2751 DBG_PRINT(ERR_DBG, "%s: Null skb ",
2752 __FUNCTION__);
2753 DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
2754 return;
2755 }
2756
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002757 /* Updating the statistics block */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002758 nic->stats.tx_bytes += skb->len;
2759 dev_kfree_skb_irq(skb);
2760
2761 get_info.offset++;
2762 get_info.offset %= get_info.fifo_len + 1;
2763 txdlp = (TxD_t *) fifo_data->list_info
2764 [get_info.offset].list_virt_addr;
2765 fifo_data->tx_curr_get_info.offset =
2766 get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 }
2768
2769 spin_lock(&nic->tx_lock);
2770 if (netif_queue_stopped(dev))
2771 netif_wake_queue(dev);
2772 spin_unlock(&nic->tx_lock);
2773}
2774
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002775/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 * alarm_intr_handler - Alarm Interrrupt handler
2777 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002778 * Description: If the interrupt was neither because of Rx packet or Tx
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 * complete, this function is called. If the interrupt was to indicate
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002780 * a loss of link, the OSM link status handler is invoked for any other
2781 * alarm interrupt the block that raised the interrupt is displayed
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 * and a H/W reset is issued.
2783 * Return Value:
2784 * NONE
2785*/
2786
2787static void alarm_intr_handler(struct s2io_nic *nic)
2788{
2789 struct net_device *dev = (struct net_device *) nic->dev;
2790 XENA_dev_config_t __iomem *bar0 = nic->bar0;
2791 register u64 val64 = 0, err_reg = 0;
2792
2793 /* Handling link status change error Intr */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07002794 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
2795 err_reg = readq(&bar0->mac_rmac_err_reg);
2796 writeq(err_reg, &bar0->mac_rmac_err_reg);
2797 if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
2798 schedule_work(&nic->set_link_task);
2799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 }
2801
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002802 /* Handling Ecc errors */
2803 val64 = readq(&bar0->mc_err_reg);
2804 writeq(val64, &bar0->mc_err_reg);
2805 if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
2806 if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002807 nic->mac_control.stats_info->sw_stat.
2808 double_ecc_errs++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002809 DBG_PRINT(INIT_DBG, "%s: Device indicates ",
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002810 dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002811 DBG_PRINT(INIT_DBG, "double ECC error!!\n");
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002812 if (nic->device_type != XFRAME_II_DEVICE) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002813 /* Reset XframeI only if critical error */
2814 if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
2815 MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
2816 netif_stop_queue(dev);
2817 schedule_work(&nic->rst_timer_task);
2818 }
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002819 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002820 } else {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002821 nic->mac_control.stats_info->sw_stat.
2822 single_ecc_errs++;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002823 }
2824 }
2825
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 /* In case of a serious error, the device will be Reset. */
2827 val64 = readq(&bar0->serr_source);
2828 if (val64 & SERR_SOURCE_ANY) {
2829 DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002830 DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
2831 (unsigned long long)val64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 netif_stop_queue(dev);
2833 schedule_work(&nic->rst_timer_task);
2834 }
2835
2836 /*
2837 * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
2838 * Error occurs, the adapter will be recycled by disabling the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002839 * adapter enable bit and enabling it again after the device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 * becomes Quiescent.
2841 */
2842 val64 = readq(&bar0->pcc_err_reg);
2843 writeq(val64, &bar0->pcc_err_reg);
2844 if (val64 & PCC_FB_ECC_DB_ERR) {
2845 u64 ac = readq(&bar0->adapter_control);
2846 ac &= ~(ADAPTER_CNTL_EN);
2847 writeq(ac, &bar0->adapter_control);
2848 ac = readq(&bar0->adapter_control);
2849 schedule_work(&nic->set_link_task);
2850 }
2851
2852 /* Other type of interrupts are not being handled now, TODO */
2853}
2854
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002855/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 * wait_for_cmd_complete - waits for a command to complete.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002857 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002859 * Description: Function that waits for a command to Write into RMAC
2860 * ADDR DATA registers to be completed and returns either success or
2861 * error depending on whether the command was complete or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 * Return value:
2863 * SUCCESS on success and FAILURE on failure.
2864 */
2865
Adrian Bunkac1f60d2005-11-06 01:46:47 +01002866static int wait_for_cmd_complete(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867{
2868 XENA_dev_config_t __iomem *bar0 = sp->bar0;
2869 int ret = FAILURE, cnt = 0;
2870 u64 val64;
2871
2872 while (TRUE) {
2873 val64 = readq(&bar0->rmac_addr_cmd_mem);
2874 if (!(val64 & RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
2875 ret = SUCCESS;
2876 break;
2877 }
2878 msleep(50);
2879 if (cnt++ > 10)
2880 break;
2881 }
2882
2883 return ret;
2884}
2885
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002886/**
2887 * s2io_reset - Resets the card.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 * @sp : private member of the device structure.
2889 * Description: Function to Reset the card. This function then also
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002890 * restores the previously saved PCI configuration space registers as
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 * the card reset also resets the configuration space.
2892 * Return value:
2893 * void.
2894 */
2895
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002896void s2io_reset(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897{
2898 XENA_dev_config_t __iomem *bar0 = sp->bar0;
2899 u64 val64;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002900 u16 subid, pci_cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07002902 /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002903 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07002904
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 val64 = SW_RESET_ALL;
2906 writeq(val64, &bar0->sw_reset);
2907
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002908 /*
2909 * At this stage, if the PCI write is indeed completed, the
2910 * card is reset and so is the PCI Config space of the device.
2911 * So a read cannot be issued at this stage on any of the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 * registers to ensure the write into "sw_reset" register
2913 * has gone through.
2914 * Question: Is there any system call that will explicitly force
2915 * all the write commands still pending on the bus to be pushed
2916 * through?
2917 * As of now I'am just giving a 250ms delay and hoping that the
2918 * PCI write to sw_reset register is done by this time.
2919 */
2920 msleep(250);
2921
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002922 /* Restore the PCI state saved during initialization. */
2923 pci_restore_state(sp->pdev);
2924 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07002925 pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 s2io_init_pci(sp);
2927
2928 msleep(250);
2929
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002930 /* Set swapper to enable I/O register access */
2931 s2io_set_swapper(sp);
2932
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04002933 /* Restore the MSIX table entries from local variables */
2934 restore_xmsi_data(sp);
2935
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002936 /* Clear certain PCI/PCI-X fields after reset */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002937 if (sp->device_type == XFRAME_II_DEVICE) {
2938 /* Clear parity err detect bit */
2939 pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002940
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002941 /* Clearing PCIX Ecc status register */
2942 pci_write_config_dword(sp->pdev, 0x68, 0x7C);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002943
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002944 /* Clearing PCI_STATUS error reflected here */
2945 writeq(BIT(62), &bar0->txpic_int_reg);
2946 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002947
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002948 /* Reset device statistics maintained by OS */
2949 memset(&sp->stats, 0, sizeof (struct net_device_stats));
2950
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 /* SXE-002: Configure link and activity LED to turn it off */
2952 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07002953 if (((subid & 0xFF) >= 0x07) &&
2954 (sp->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 val64 = readq(&bar0->gpio_control);
2956 val64 |= 0x0000800000000000ULL;
2957 writeq(val64, &bar0->gpio_control);
2958 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01002959 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 }
2961
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07002962 /*
2963 * Clear spurious ECC interrupts that would have occured on
2964 * XFRAME II cards after reset.
2965 */
2966 if (sp->device_type == XFRAME_II_DEVICE) {
2967 val64 = readq(&bar0->pcc_err_reg);
2968 writeq(val64, &bar0->pcc_err_reg);
2969 }
2970
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 sp->device_enabled_once = FALSE;
2972}
2973
2974/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002975 * s2io_set_swapper - to set the swapper controle on the card
2976 * @sp : private member of the device structure,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 * pointer to the s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002978 * Description: Function to set the swapper control on the card
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 * correctly depending on the 'endianness' of the system.
2980 * Return value:
2981 * SUCCESS on success and FAILURE on failure.
2982 */
2983
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002984int s2io_set_swapper(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985{
2986 struct net_device *dev = sp->dev;
2987 XENA_dev_config_t __iomem *bar0 = sp->bar0;
2988 u64 val64, valt, valr;
2989
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002990 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 * Set proper endian settings and verify the same by reading
2992 * the PIF Feed-back register.
2993 */
2994
2995 val64 = readq(&bar0->pif_rd_swapper_fb);
2996 if (val64 != 0x0123456789ABCDEFULL) {
2997 int i = 0;
2998 u64 value[] = { 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */
2999 0x8100008181000081ULL, /* FE=1, SE=0 */
3000 0x4200004242000042ULL, /* FE=0, SE=1 */
3001 0}; /* FE=0, SE=0 */
3002
3003 while(i<4) {
3004 writeq(value[i], &bar0->swapper_ctrl);
3005 val64 = readq(&bar0->pif_rd_swapper_fb);
3006 if (val64 == 0x0123456789ABCDEFULL)
3007 break;
3008 i++;
3009 }
3010 if (i == 4) {
3011 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3012 dev->name);
3013 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3014 (unsigned long long) val64);
3015 return FAILURE;
3016 }
3017 valr = value[i];
3018 } else {
3019 valr = readq(&bar0->swapper_ctrl);
3020 }
3021
3022 valt = 0x0123456789ABCDEFULL;
3023 writeq(valt, &bar0->xmsi_address);
3024 val64 = readq(&bar0->xmsi_address);
3025
3026 if(val64 != valt) {
3027 int i = 0;
3028 u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */
3029 0x0081810000818100ULL, /* FE=1, SE=0 */
3030 0x0042420000424200ULL, /* FE=0, SE=1 */
3031 0}; /* FE=0, SE=0 */
3032
3033 while(i<4) {
3034 writeq((value[i] | valr), &bar0->swapper_ctrl);
3035 writeq(valt, &bar0->xmsi_address);
3036 val64 = readq(&bar0->xmsi_address);
3037 if(val64 == valt)
3038 break;
3039 i++;
3040 }
3041 if(i == 4) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003042 unsigned long long x = val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr ");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003044 DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 return FAILURE;
3046 }
3047 }
3048 val64 = readq(&bar0->swapper_ctrl);
3049 val64 &= 0xFFFF000000000000ULL;
3050
3051#ifdef __BIG_ENDIAN
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003052 /*
3053 * The device by default set to a big endian format, so a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 * big endian driver need not set anything.
3055 */
3056 val64 |= (SWAPPER_CTRL_TXP_FE |
3057 SWAPPER_CTRL_TXP_SE |
3058 SWAPPER_CTRL_TXD_R_FE |
3059 SWAPPER_CTRL_TXD_W_FE |
3060 SWAPPER_CTRL_TXF_R_FE |
3061 SWAPPER_CTRL_RXD_R_FE |
3062 SWAPPER_CTRL_RXD_W_FE |
3063 SWAPPER_CTRL_RXF_W_FE |
3064 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Andrew Morton92383342005-10-16 00:11:29 -07003066 if (sp->intr_type == INTA)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003067 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 writeq(val64, &bar0->swapper_ctrl);
3069#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003070 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 * Initially we enable all bits to make it accessible by the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003072 * driver, then we selectively enable only those bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 * we want to set.
3074 */
3075 val64 |= (SWAPPER_CTRL_TXP_FE |
3076 SWAPPER_CTRL_TXP_SE |
3077 SWAPPER_CTRL_TXD_R_FE |
3078 SWAPPER_CTRL_TXD_R_SE |
3079 SWAPPER_CTRL_TXD_W_FE |
3080 SWAPPER_CTRL_TXD_W_SE |
3081 SWAPPER_CTRL_TXF_R_FE |
3082 SWAPPER_CTRL_RXD_R_FE |
3083 SWAPPER_CTRL_RXD_R_SE |
3084 SWAPPER_CTRL_RXD_W_FE |
3085 SWAPPER_CTRL_RXD_W_SE |
3086 SWAPPER_CTRL_RXF_W_FE |
3087 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003089 if (sp->intr_type == INTA)
3090 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 writeq(val64, &bar0->swapper_ctrl);
3092#endif
3093 val64 = readq(&bar0->swapper_ctrl);
3094
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003095 /*
3096 * Verifying if endian settings are accurate by reading a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 * feedback register.
3098 */
3099 val64 = readq(&bar0->pif_rd_swapper_fb);
3100 if (val64 != 0x0123456789ABCDEFULL) {
3101 /* Endian settings are incorrect, calls for another dekko. */
3102 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3103 dev->name);
3104 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3105 (unsigned long long) val64);
3106 return FAILURE;
3107 }
3108
3109 return SUCCESS;
3110}
3111
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003112static int wait_for_msix_trans(nic_t *nic, int i)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003113{
Al Viro37eb47e2005-12-15 09:17:29 +00003114 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003115 u64 val64;
3116 int ret = 0, cnt = 0;
3117
3118 do {
3119 val64 = readq(&bar0->xmsi_access);
3120 if (!(val64 & BIT(15)))
3121 break;
3122 mdelay(1);
3123 cnt++;
3124 } while(cnt < 5);
3125 if (cnt == 5) {
3126 DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i);
3127 ret = 1;
3128 }
3129
3130 return ret;
3131}
3132
3133void restore_xmsi_data(nic_t *nic)
3134{
Al Viro37eb47e2005-12-15 09:17:29 +00003135 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003136 u64 val64;
3137 int i;
3138
3139 for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
3140 writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
3141 writeq(nic->msix_info[i].data, &bar0->xmsi_data);
3142 val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
3143 writeq(val64, &bar0->xmsi_access);
3144 if (wait_for_msix_trans(nic, i)) {
3145 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3146 continue;
3147 }
3148 }
3149}
3150
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003151static void store_xmsi_data(nic_t *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003152{
Al Viro37eb47e2005-12-15 09:17:29 +00003153 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003154 u64 val64, addr, data;
3155 int i;
3156
3157 /* Store and display */
3158 for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
3159 val64 = (BIT(15) | vBIT(i, 26, 6));
3160 writeq(val64, &bar0->xmsi_access);
3161 if (wait_for_msix_trans(nic, i)) {
3162 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3163 continue;
3164 }
3165 addr = readq(&bar0->xmsi_address);
3166 data = readq(&bar0->xmsi_data);
3167 if (addr && data) {
3168 nic->msix_info[i].addr = addr;
3169 nic->msix_info[i].data = data;
3170 }
3171 }
3172}
3173
3174int s2io_enable_msi(nic_t *nic)
3175{
Al Viro37eb47e2005-12-15 09:17:29 +00003176 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003177 u16 msi_ctrl, msg_val;
3178 struct config_param *config = &nic->config;
3179 struct net_device *dev = nic->dev;
3180 u64 val64, tx_mat, rx_mat;
3181 int i, err;
3182
3183 val64 = readq(&bar0->pic_control);
3184 val64 &= ~BIT(1);
3185 writeq(val64, &bar0->pic_control);
3186
3187 err = pci_enable_msi(nic->pdev);
3188 if (err) {
3189 DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n",
3190 nic->dev->name);
3191 return err;
3192 }
3193
3194 /*
3195 * Enable MSI and use MSI-1 in stead of the standard MSI-0
3196 * for interrupt handling.
3197 */
3198 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3199 msg_val ^= 0x1;
3200 pci_write_config_word(nic->pdev, 0x4c, msg_val);
3201 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3202
3203 pci_read_config_word(nic->pdev, 0x42, &msi_ctrl);
3204 msi_ctrl |= 0x10;
3205 pci_write_config_word(nic->pdev, 0x42, msi_ctrl);
3206
3207 /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */
3208 tx_mat = readq(&bar0->tx_mat0_n[0]);
3209 for (i=0; i<config->tx_fifo_num; i++) {
3210 tx_mat |= TX_MAT_SET(i, 1);
3211 }
3212 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3213
3214 rx_mat = readq(&bar0->rx_mat);
3215 for (i=0; i<config->rx_ring_num; i++) {
3216 rx_mat |= RX_MAT_SET(i, 1);
3217 }
3218 writeq(rx_mat, &bar0->rx_mat);
3219
3220 dev->irq = nic->pdev->irq;
3221 return 0;
3222}
3223
3224int s2io_enable_msi_x(nic_t *nic)
3225{
Al Viro37eb47e2005-12-15 09:17:29 +00003226 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003227 u64 tx_mat, rx_mat;
3228 u16 msi_control; /* Temp variable */
3229 int ret, i, j, msix_indx = 1;
3230
3231 nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
3232 GFP_KERNEL);
3233 if (nic->entries == NULL) {
3234 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3235 return -ENOMEM;
3236 }
3237 memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
3238
3239 nic->s2io_entries =
3240 kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
3241 GFP_KERNEL);
3242 if (nic->s2io_entries == NULL) {
3243 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3244 kfree(nic->entries);
3245 return -ENOMEM;
3246 }
3247 memset(nic->s2io_entries, 0,
3248 MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
3249
3250 for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
3251 nic->entries[i].entry = i;
3252 nic->s2io_entries[i].entry = i;
3253 nic->s2io_entries[i].arg = NULL;
3254 nic->s2io_entries[i].in_use = 0;
3255 }
3256
3257 tx_mat = readq(&bar0->tx_mat0_n[0]);
3258 for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) {
3259 tx_mat |= TX_MAT_SET(i, msix_indx);
3260 nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i];
3261 nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE;
3262 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3263 }
3264 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3265
3266 if (!nic->config.bimodal) {
3267 rx_mat = readq(&bar0->rx_mat);
3268 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3269 rx_mat |= RX_MAT_SET(j, msix_indx);
3270 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3271 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3272 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3273 }
3274 writeq(rx_mat, &bar0->rx_mat);
3275 } else {
3276 tx_mat = readq(&bar0->tx_mat0_n[7]);
3277 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3278 tx_mat |= TX_MAT_SET(i, msix_indx);
3279 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3280 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3281 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3282 }
3283 writeq(tx_mat, &bar0->tx_mat0_n[7]);
3284 }
3285
3286 ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
3287 if (ret) {
3288 DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
3289 kfree(nic->entries);
3290 kfree(nic->s2io_entries);
3291 nic->entries = NULL;
3292 nic->s2io_entries = NULL;
3293 return -ENOMEM;
3294 }
3295
3296 /*
3297 * To enable MSI-X, MSI also needs to be enabled, due to a bug
3298 * in the herc NIC. (Temp change, needs to be removed later)
3299 */
3300 pci_read_config_word(nic->pdev, 0x42, &msi_control);
3301 msi_control |= 0x1; /* Enable MSI */
3302 pci_write_config_word(nic->pdev, 0x42, msi_control);
3303
3304 return 0;
3305}
3306
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307/* ********************************************************* *
3308 * Functions defined below concern the OS part of the driver *
3309 * ********************************************************* */
3310
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003311/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 * s2io_open - open entry point of the driver
3313 * @dev : pointer to the device structure.
3314 * Description:
3315 * This function is the open entry point of the driver. It mainly calls a
3316 * function to allocate Rx buffers and inserts them into the buffer
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003317 * descriptors and then enables the Rx part of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 * Return value:
3319 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3320 * file on failure.
3321 */
3322
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003323static int s2io_open(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324{
3325 nic_t *sp = dev->priv;
3326 int err = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003327 int i;
3328 u16 msi_control; /* Temp variable */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003330 /*
3331 * Make sure you have link off by default every time
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 * Nic is initialized
3333 */
3334 netif_carrier_off(dev);
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003335 sp->last_link_state = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336
3337 /* Initialize H/W and enable interrupts */
3338 if (s2io_card_up(sp)) {
3339 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
3340 dev->name);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003341 err = -ENODEV;
3342 goto hw_init_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 }
3344
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003345 /* Store the values of the MSIX table in the nic_t structure */
3346 store_xmsi_data(sp);
3347
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 /* After proper initialization of H/W, register ISR */
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003349 if (sp->intr_type == MSI) {
3350 err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
3351 SA_SHIRQ, sp->name, dev);
3352 if (err) {
3353 DBG_PRINT(ERR_DBG, "%s: MSI registration \
3354failed\n", dev->name);
3355 goto isr_registration_failed;
3356 }
3357 }
3358 if (sp->intr_type == MSI_X) {
3359 for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
3360 if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
3361 sprintf(sp->desc1, "%s:MSI-X-%d-TX",
3362 dev->name, i);
3363 err = request_irq(sp->entries[i].vector,
3364 s2io_msix_fifo_handle, 0, sp->desc1,
3365 sp->s2io_entries[i].arg);
3366 DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1,
Andrew Morton26b76252005-12-14 19:25:23 -08003367 (unsigned long long)sp->msix_info[i].addr);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003368 } else {
3369 sprintf(sp->desc2, "%s:MSI-X-%d-RX",
3370 dev->name, i);
3371 err = request_irq(sp->entries[i].vector,
3372 s2io_msix_ring_handle, 0, sp->desc2,
3373 sp->s2io_entries[i].arg);
3374 DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2,
Andrew Morton26b76252005-12-14 19:25:23 -08003375 (unsigned long long)sp->msix_info[i].addr);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003376 }
3377 if (err) {
3378 DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \
3379failed\n", dev->name, i);
3380 DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
3381 goto isr_registration_failed;
3382 }
3383 sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
3384 }
3385 }
3386 if (sp->intr_type == INTA) {
3387 err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ,
3388 sp->name, dev);
3389 if (err) {
3390 DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
3391 dev->name);
3392 goto isr_registration_failed;
3393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 }
3395
3396 if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
3397 DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003398 err = -ENODEV;
3399 goto setting_mac_address_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 }
3401
3402 netif_start_queue(dev);
3403 return 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003404
3405setting_mac_address_failed:
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003406 if (sp->intr_type != MSI_X)
3407 free_irq(sp->pdev->irq, dev);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003408isr_registration_failed:
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07003409 del_timer_sync(&sp->alarm_timer);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003410 if (sp->intr_type == MSI_X) {
3411 if (sp->device_type == XFRAME_II_DEVICE) {
3412 for (i=1; (sp->s2io_entries[i].in_use ==
3413 MSIX_REGISTERED_SUCCESS); i++) {
3414 int vector = sp->entries[i].vector;
3415 void *arg = sp->s2io_entries[i].arg;
3416
3417 free_irq(vector, arg);
3418 }
3419 pci_disable_msix(sp->pdev);
3420
3421 /* Temp */
3422 pci_read_config_word(sp->pdev, 0x42, &msi_control);
3423 msi_control &= 0xFFFE; /* Disable MSI */
3424 pci_write_config_word(sp->pdev, 0x42, msi_control);
3425 }
3426 }
3427 else if (sp->intr_type == MSI)
3428 pci_disable_msi(sp->pdev);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003429 s2io_reset(sp);
3430hw_init_failed:
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003431 if (sp->intr_type == MSI_X) {
3432 if (sp->entries)
3433 kfree(sp->entries);
3434 if (sp->s2io_entries)
3435 kfree(sp->s2io_entries);
3436 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003437 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438}
3439
3440/**
3441 * s2io_close -close entry point of the driver
3442 * @dev : device pointer.
3443 * Description:
3444 * This is the stop entry point of the driver. It needs to undo exactly
3445 * whatever was done by the open entry point,thus it's usually referred to
3446 * as the close function.Among other things this function mainly stops the
3447 * Rx side of the NIC and frees all the Rx buffers in the Rx rings.
3448 * Return value:
3449 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3450 * file on failure.
3451 */
3452
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003453static int s2io_close(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454{
3455 nic_t *sp = dev->priv;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003456 int i;
3457 u16 msi_control;
3458
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 flush_scheduled_work();
3460 netif_stop_queue(dev);
3461 /* Reset card, kill tasklet and free Tx and Rx buffers. */
3462 s2io_card_down(sp);
3463
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003464 if (sp->intr_type == MSI_X) {
3465 if (sp->device_type == XFRAME_II_DEVICE) {
3466 for (i=1; (sp->s2io_entries[i].in_use ==
3467 MSIX_REGISTERED_SUCCESS); i++) {
3468 int vector = sp->entries[i].vector;
3469 void *arg = sp->s2io_entries[i].arg;
3470
3471 free_irq(vector, arg);
3472 }
3473 pci_read_config_word(sp->pdev, 0x42, &msi_control);
3474 msi_control &= 0xFFFE; /* Disable MSI */
3475 pci_write_config_word(sp->pdev, 0x42, msi_control);
3476
3477 pci_disable_msix(sp->pdev);
3478 }
3479 }
3480 else {
3481 free_irq(sp->pdev->irq, dev);
3482 if (sp->intr_type == MSI)
3483 pci_disable_msi(sp->pdev);
3484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 sp->device_close_flag = TRUE; /* Device is shut down. */
3486 return 0;
3487}
3488
3489/**
3490 * s2io_xmit - Tx entry point of te driver
3491 * @skb : the socket buffer containing the Tx data.
3492 * @dev : device pointer.
3493 * Description :
3494 * This function is the Tx entry point of the driver. S2IO NIC supports
3495 * certain protocol assist features on Tx side, namely CSO, S/G, LSO.
3496 * NOTE: when device cant queue the pkt,just the trans_start variable will
3497 * not be upadted.
3498 * Return value:
3499 * 0 on success & 1 on failure.
3500 */
3501
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003502static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503{
3504 nic_t *sp = dev->priv;
3505 u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
3506 register u64 val64;
3507 TxD_t *txdp;
3508 TxFIFO_element_t __iomem *tx_fifo;
3509 unsigned long flags;
3510#ifdef NETIF_F_TSO
3511 int mss;
3512#endif
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003513 u16 vlan_tag = 0;
3514 int vlan_priority = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 mac_info_t *mac_control;
3516 struct config_param *config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517
3518 mac_control = &sp->mac_control;
3519 config = &sp->config;
3520
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003521 DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 spin_lock_irqsave(&sp->tx_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 if (atomic_read(&sp->card_state) == CARD_DOWN) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003524 DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 dev->name);
3526 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003527 dev_kfree_skb(skb);
3528 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 }
3530
3531 queue = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003533 /* Get Fifo number to Transmit based on vlan priority */
3534 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3535 vlan_tag = vlan_tx_tag_get(skb);
3536 vlan_priority = vlan_tag >> 13;
3537 queue = config->fifo_mapping[vlan_priority];
3538 }
3539
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003540 put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
3541 get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
3542 txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off].
3543 list_virt_addr;
3544
3545 queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 /* Avoid "put" pointer going beyond "get" pointer */
3547 if (txdp->Host_Control || (((put_off + 1) % queue_len) == get_off)) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003548 DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 netif_stop_queue(dev);
3550 dev_kfree_skb(skb);
3551 spin_unlock_irqrestore(&sp->tx_lock, flags);
3552 return 0;
3553 }
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003554
3555 /* A buffer with no data will be dropped */
3556 if (!skb->len) {
3557 DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
3558 dev_kfree_skb(skb);
3559 spin_unlock_irqrestore(&sp->tx_lock, flags);
3560 return 0;
3561 }
3562
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003563 txdp->Control_1 = 0;
3564 txdp->Control_2 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565#ifdef NETIF_F_TSO
3566 mss = skb_shinfo(skb)->tso_size;
3567 if (mss) {
3568 txdp->Control_1 |= TXD_TCP_LSO_EN;
3569 txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
3570 }
3571#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 if (skb->ip_summed == CHECKSUM_HW) {
3573 txdp->Control_2 |=
3574 (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
3575 TXD_TX_CKO_UDP_EN);
3576 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003577 txdp->Control_1 |= TXD_GATHER_CODE_FIRST;
3578 txdp->Control_1 |= TXD_LIST_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 txdp->Control_2 |= config->tx_intr_type;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07003580
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003581 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3582 txdp->Control_2 |= TXD_VLAN_ENABLE;
3583 txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
3584 }
3585
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003586 frg_len = skb->len - skb->data_len;
3587 if (skb_shinfo(skb)->ufo_size) {
3588 int ufo_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003590 ufo_size = skb_shinfo(skb)->ufo_size;
3591 ufo_size &= ~7;
3592 txdp->Control_1 |= TXD_UFO_EN;
3593 txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
3594 txdp->Control_1 |= TXD_BUFFER0_SIZE(8);
3595#ifdef __BIG_ENDIAN
3596 sp->ufo_in_band_v[put_off] =
3597 (u64)skb_shinfo(skb)->ip6_frag_id;
3598#else
3599 sp->ufo_in_band_v[put_off] =
3600 (u64)skb_shinfo(skb)->ip6_frag_id << 32;
3601#endif
3602 txdp->Host_Control = (unsigned long)sp->ufo_in_band_v;
3603 txdp->Buffer_Pointer = pci_map_single(sp->pdev,
3604 sp->ufo_in_band_v,
3605 sizeof(u64), PCI_DMA_TODEVICE);
3606 txdp++;
3607 txdp->Control_1 = 0;
3608 txdp->Control_2 = 0;
3609 }
3610
3611 txdp->Buffer_Pointer = pci_map_single
3612 (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
3613 txdp->Host_Control = (unsigned long) skb;
3614 txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
3615
3616 if (skb_shinfo(skb)->ufo_size)
3617 txdp->Control_1 |= TXD_UFO_EN;
3618
3619 frg_cnt = skb_shinfo(skb)->nr_frags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 /* For fragmented SKB. */
3621 for (i = 0; i < frg_cnt; i++) {
3622 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003623 /* A '0' length fragment will be ignored */
3624 if (!frag->size)
3625 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 txdp++;
3627 txdp->Buffer_Pointer = (u64) pci_map_page
3628 (sp->pdev, frag->page, frag->page_offset,
3629 frag->size, PCI_DMA_TODEVICE);
Ananda Rajuefd51b52006-01-19 14:11:54 -05003630 txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003631 if (skb_shinfo(skb)->ufo_size)
3632 txdp->Control_1 |= TXD_UFO_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 }
3634 txdp->Control_1 |= TXD_GATHER_CODE_LAST;
3635
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003636 if (skb_shinfo(skb)->ufo_size)
3637 frg_cnt++; /* as Txd0 was used for inband header */
3638
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 tx_fifo = mac_control->tx_FIFO_start[queue];
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003640 val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 writeq(val64, &tx_fifo->TxDL_Pointer);
3642
3643 val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
3644 TX_FIFO_LAST_LIST);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003645
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646#ifdef NETIF_F_TSO
3647 if (mss)
3648 val64 |= TX_FIFO_SPECIAL_FUNC;
3649#endif
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003650 if (skb_shinfo(skb)->ufo_size)
3651 val64 |= TX_FIFO_SPECIAL_FUNC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 writeq(val64, &tx_fifo->List_Control);
3653
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003654 mmiowb();
3655
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 put_off++;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003657 put_off %= mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
3658 mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659
3660 /* Avoid "put" pointer going beyond "get" pointer */
3661 if (((put_off + 1) % queue_len) == get_off) {
3662 DBG_PRINT(TX_DBG,
3663 "No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
3664 put_off, get_off);
3665 netif_stop_queue(dev);
3666 }
3667
3668 dev->trans_start = jiffies;
3669 spin_unlock_irqrestore(&sp->tx_lock, flags);
3670
3671 return 0;
3672}
3673
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07003674static void
3675s2io_alarm_handle(unsigned long data)
3676{
3677 nic_t *sp = (nic_t *)data;
3678
3679 alarm_intr_handler(sp);
3680 mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
3681}
3682
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003683static irqreturn_t
3684s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs)
3685{
3686 struct net_device *dev = (struct net_device *) dev_id;
3687 nic_t *sp = dev->priv;
3688 int i;
3689 int ret;
3690 mac_info_t *mac_control;
3691 struct config_param *config;
3692
3693 atomic_inc(&sp->isr_cnt);
3694 mac_control = &sp->mac_control;
3695 config = &sp->config;
3696 DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__);
3697
3698 /* If Intr is because of Rx Traffic */
3699 for (i = 0; i < config->rx_ring_num; i++)
3700 rx_intr_handler(&mac_control->rings[i]);
3701
3702 /* If Intr is because of Tx Traffic */
3703 for (i = 0; i < config->tx_fifo_num; i++)
3704 tx_intr_handler(&mac_control->fifos[i]);
3705
3706 /*
3707 * If the Rx buffer count is below the panic threshold then
3708 * reallocate the buffers from the interrupt handler itself,
3709 * else schedule a tasklet to reallocate the buffers.
3710 */
3711 for (i = 0; i < config->rx_ring_num; i++) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05003712 if (!sp->lro) {
3713 int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
3714 int level = rx_buffer_level(sp, rxb_size, i);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003715
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05003716 if ((level == PANIC) && (!TASKLET_IN_USE)) {
3717 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ",
3718 dev->name);
3719 DBG_PRINT(INTR_DBG, "PANIC levels\n");
3720 if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
3721 DBG_PRINT(ERR_DBG, "%s:Out of memory",
3722 dev->name);
3723 DBG_PRINT(ERR_DBG, " in ISR!!\n");
3724 clear_bit(0, (&sp->tasklet_status));
3725 atomic_dec(&sp->isr_cnt);
3726 return IRQ_HANDLED;
3727 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003728 clear_bit(0, (&sp->tasklet_status));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05003729 } else if (level == LOW) {
3730 tasklet_schedule(&sp->task);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003731 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05003732 }
3733 else if (fill_rx_buffers(sp, i) == -ENOMEM) {
3734 DBG_PRINT(ERR_DBG, "%s:Out of memory",
3735 dev->name);
3736 DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
3737 break;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003738 }
3739 }
3740
3741 atomic_dec(&sp->isr_cnt);
3742 return IRQ_HANDLED;
3743}
3744
3745static irqreturn_t
3746s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs)
3747{
3748 ring_info_t *ring = (ring_info_t *)dev_id;
3749 nic_t *sp = ring->nic;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05003750 struct net_device *dev = (struct net_device *) dev_id;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003751 int rxb_size, level, rng_n;
3752
3753 atomic_inc(&sp->isr_cnt);
3754 rx_intr_handler(ring);
3755
3756 rng_n = ring->ring_no;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05003757 if (!sp->lro) {
3758 rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
3759 level = rx_buffer_level(sp, rxb_size, rng_n);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003760
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05003761 if ((level == PANIC) && (!TASKLET_IN_USE)) {
3762 int ret;
3763 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
3764 DBG_PRINT(INTR_DBG, "PANIC levels\n");
3765 if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
3766 DBG_PRINT(ERR_DBG, "Out of memory in %s",
3767 __FUNCTION__);
3768 clear_bit(0, (&sp->tasklet_status));
3769 return IRQ_HANDLED;
3770 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003771 clear_bit(0, (&sp->tasklet_status));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05003772 } else if (level == LOW) {
3773 tasklet_schedule(&sp->task);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003774 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003775 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05003776 else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
3777 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
3778 DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
3779 }
3780
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003781 atomic_dec(&sp->isr_cnt);
3782
3783 return IRQ_HANDLED;
3784}
3785
3786static irqreturn_t
3787s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs)
3788{
3789 fifo_info_t *fifo = (fifo_info_t *)dev_id;
3790 nic_t *sp = fifo->nic;
3791
3792 atomic_inc(&sp->isr_cnt);
3793 tx_intr_handler(fifo);
3794 atomic_dec(&sp->isr_cnt);
3795 return IRQ_HANDLED;
3796}
3797
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07003798static void s2io_txpic_intr_handle(nic_t *sp)
3799{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01003800 XENA_dev_config_t __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07003801 u64 val64;
3802
3803 val64 = readq(&bar0->pic_int_status);
3804 if (val64 & PIC_INT_GPIO) {
3805 val64 = readq(&bar0->gpio_int_reg);
3806 if ((val64 & GPIO_INT_REG_LINK_DOWN) &&
3807 (val64 & GPIO_INT_REG_LINK_UP)) {
3808 val64 |= GPIO_INT_REG_LINK_DOWN;
3809 val64 |= GPIO_INT_REG_LINK_UP;
3810 writeq(val64, &bar0->gpio_int_reg);
3811 goto masking;
3812 }
3813
3814 if (((sp->last_link_state == LINK_UP) &&
3815 (val64 & GPIO_INT_REG_LINK_DOWN)) ||
3816 ((sp->last_link_state == LINK_DOWN) &&
3817 (val64 & GPIO_INT_REG_LINK_UP))) {
3818 val64 = readq(&bar0->gpio_int_mask);
3819 val64 |= GPIO_INT_MASK_LINK_DOWN;
3820 val64 |= GPIO_INT_MASK_LINK_UP;
3821 writeq(val64, &bar0->gpio_int_mask);
3822 s2io_set_link((unsigned long)sp);
3823 }
3824masking:
3825 if (sp->last_link_state == LINK_UP) {
3826 /*enable down interrupt */
3827 val64 = readq(&bar0->gpio_int_mask);
3828 /* unmasks link down intr */
3829 val64 &= ~GPIO_INT_MASK_LINK_DOWN;
3830 /* masks link up intr */
3831 val64 |= GPIO_INT_MASK_LINK_UP;
3832 writeq(val64, &bar0->gpio_int_mask);
3833 } else {
3834 /*enable UP Interrupt */
3835 val64 = readq(&bar0->gpio_int_mask);
3836 /* unmasks link up interrupt */
3837 val64 &= ~GPIO_INT_MASK_LINK_UP;
3838 /* masks link down interrupt */
3839 val64 |= GPIO_INT_MASK_LINK_DOWN;
3840 writeq(val64, &bar0->gpio_int_mask);
3841 }
3842 }
3843}
3844
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845/**
3846 * s2io_isr - ISR handler of the device .
3847 * @irq: the irq of the device.
3848 * @dev_id: a void pointer to the dev structure of the NIC.
3849 * @pt_regs: pointer to the registers pushed on the stack.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003850 * Description: This function is the ISR handler of the device. It
3851 * identifies the reason for the interrupt and calls the relevant
3852 * service routines. As a contongency measure, this ISR allocates the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853 * recv buffers, if their numbers are below the panic value which is
3854 * presently set to 25% of the original number of rcv buffers allocated.
3855 * Return value:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003856 * IRQ_HANDLED: will be returned if IRQ was handled by this routine
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 * IRQ_NONE: will be returned if interrupt is not from our device
3858 */
3859static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
3860{
3861 struct net_device *dev = (struct net_device *) dev_id;
3862 nic_t *sp = dev->priv;
3863 XENA_dev_config_t __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003864 int i;
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -07003865 u64 reason = 0, val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 mac_info_t *mac_control;
3867 struct config_param *config;
3868
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003869 atomic_inc(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 mac_control = &sp->mac_control;
3871 config = &sp->config;
3872
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003873 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 * Identify the cause for interrupt and call the appropriate
3875 * interrupt handler. Causes for the interrupt could be;
3876 * 1. Rx of packet.
3877 * 2. Tx complete.
3878 * 3. Link down.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003879 * 4. Error in any functional blocks of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 */
3881 reason = readq(&bar0->general_int_status);
3882
3883 if (!reason) {
3884 /* The interrupt was not raised by Xena. */
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003885 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 return IRQ_NONE;
3887 }
3888
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889#ifdef CONFIG_S2IO_NAPI
3890 if (reason & GEN_INTR_RXTRAFFIC) {
3891 if (netif_rx_schedule_prep(dev)) {
3892 en_dis_able_nic_intrs(sp, RX_TRAFFIC_INTR,
3893 DISABLE_INTRS);
3894 __netif_rx_schedule(dev);
3895 }
3896 }
3897#else
3898 /* If Intr is because of Rx Traffic */
3899 if (reason & GEN_INTR_RXTRAFFIC) {
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -07003900 /*
3901 * rx_traffic_int reg is an R1 register, writing all 1's
3902 * will ensure that the actual interrupt causing bit get's
3903 * cleared and hence a read can be avoided.
3904 */
3905 val64 = 0xFFFFFFFFFFFFFFFFULL;
3906 writeq(val64, &bar0->rx_traffic_int);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003907 for (i = 0; i < config->rx_ring_num; i++) {
3908 rx_intr_handler(&mac_control->rings[i]);
3909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 }
3911#endif
3912
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003913 /* If Intr is because of Tx Traffic */
3914 if (reason & GEN_INTR_TXTRAFFIC) {
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -07003915 /*
3916 * tx_traffic_int reg is an R1 register, writing all 1's
3917 * will ensure that the actual interrupt causing bit get's
3918 * cleared and hence a read can be avoided.
3919 */
3920 val64 = 0xFFFFFFFFFFFFFFFFULL;
3921 writeq(val64, &bar0->tx_traffic_int);
3922
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003923 for (i = 0; i < config->tx_fifo_num; i++)
3924 tx_intr_handler(&mac_control->fifos[i]);
3925 }
3926
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07003927 if (reason & GEN_INTR_TXPIC)
3928 s2io_txpic_intr_handle(sp);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003929 /*
3930 * If the Rx buffer count is below the panic threshold then
3931 * reallocate the buffers from the interrupt handler itself,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 * else schedule a tasklet to reallocate the buffers.
3933 */
3934#ifndef CONFIG_S2IO_NAPI
3935 for (i = 0; i < config->rx_ring_num; i++) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05003936 if (!sp->lro) {
3937 int ret;
3938 int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
3939 int level = rx_buffer_level(sp, rxb_size, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05003941 if ((level == PANIC) && (!TASKLET_IN_USE)) {
3942 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ",
3943 dev->name);
3944 DBG_PRINT(INTR_DBG, "PANIC levels\n");
3945 if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
3946 DBG_PRINT(ERR_DBG, "%s:Out of memory",
3947 dev->name);
3948 DBG_PRINT(ERR_DBG, " in ISR!!\n");
3949 clear_bit(0, (&sp->tasklet_status));
3950 atomic_dec(&sp->isr_cnt);
3951 return IRQ_HANDLED;
3952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 clear_bit(0, (&sp->tasklet_status));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05003954 } else if (level == LOW) {
3955 tasklet_schedule(&sp->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05003957 }
3958 else if (fill_rx_buffers(sp, i) == -ENOMEM) {
3959 DBG_PRINT(ERR_DBG, "%s:Out of memory",
3960 dev->name);
3961 DBG_PRINT(ERR_DBG, " in Rx intr!!\n");
3962 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 }
3964 }
3965#endif
3966
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003967 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 return IRQ_HANDLED;
3969}
3970
3971/**
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003972 * s2io_updt_stats -
3973 */
3974static void s2io_updt_stats(nic_t *sp)
3975{
3976 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3977 u64 val64;
3978 int cnt = 0;
3979
3980 if (atomic_read(&sp->card_state) == CARD_UP) {
3981 /* Apprx 30us on a 133 MHz bus */
3982 val64 = SET_UPDT_CLICKS(10) |
3983 STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
3984 writeq(val64, &bar0->stat_cfg);
3985 do {
3986 udelay(100);
3987 val64 = readq(&bar0->stat_cfg);
3988 if (!(val64 & BIT(0)))
3989 break;
3990 cnt++;
3991 if (cnt == 5)
3992 break; /* Updt failed */
3993 } while(1);
3994 }
3995}
3996
3997/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003998 * s2io_get_stats - Updates the device statistics structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 * @dev : pointer to the device structure.
4000 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004001 * This function updates the device statistics structure in the s2io_nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 * structure and returns a pointer to the same.
4003 * Return value:
4004 * pointer to the updated net_device_stats structure.
4005 */
4006
Adrian Bunkac1f60d2005-11-06 01:46:47 +01004007static struct net_device_stats *s2io_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008{
4009 nic_t *sp = dev->priv;
4010 mac_info_t *mac_control;
4011 struct config_param *config;
4012
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004013
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 mac_control = &sp->mac_control;
4015 config = &sp->config;
4016
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004017 /* Configure Stats for immediate updt */
4018 s2io_updt_stats(sp);
4019
4020 sp->stats.tx_packets =
4021 le32_to_cpu(mac_control->stats_info->tmac_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004022 sp->stats.tx_errors =
4023 le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
4024 sp->stats.rx_errors =
4025 le32_to_cpu(mac_control->stats_info->rmac_drop_frms);
4026 sp->stats.multicast =
4027 le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 sp->stats.rx_length_errors =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004029 le32_to_cpu(mac_control->stats_info->rmac_long_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030
4031 return (&sp->stats);
4032}
4033
4034/**
4035 * s2io_set_multicast - entry point for multicast address enable/disable.
4036 * @dev : pointer to the device structure
4037 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004038 * This function is a driver entry point which gets called by the kernel
4039 * whenever multicast addresses must be enabled/disabled. This also gets
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 * called to set/reset promiscuous mode. Depending on the deivce flag, we
4041 * determine, if multicast address must be enabled or if promiscuous mode
4042 * is to be disabled etc.
4043 * Return value:
4044 * void.
4045 */
4046
4047static void s2io_set_multicast(struct net_device *dev)
4048{
4049 int i, j, prev_cnt;
4050 struct dev_mc_list *mclist;
4051 nic_t *sp = dev->priv;
4052 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4053 u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
4054 0xfeffffffffffULL;
4055 u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
4056 void __iomem *add;
4057
4058 if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) {
4059 /* Enable all Multicast addresses */
4060 writeq(RMAC_ADDR_DATA0_MEM_ADDR(multi_mac),
4061 &bar0->rmac_addr_data0_mem);
4062 writeq(RMAC_ADDR_DATA1_MEM_MASK(mask),
4063 &bar0->rmac_addr_data1_mem);
4064 val64 = RMAC_ADDR_CMD_MEM_WE |
4065 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4066 RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
4067 writeq(val64, &bar0->rmac_addr_cmd_mem);
4068 /* Wait till command completes */
4069 wait_for_cmd_complete(sp);
4070
4071 sp->m_cast_flg = 1;
4072 sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
4073 } else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) {
4074 /* Disable all Multicast addresses */
4075 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4076 &bar0->rmac_addr_data0_mem);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07004077 writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0),
4078 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 val64 = RMAC_ADDR_CMD_MEM_WE |
4080 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4081 RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos);
4082 writeq(val64, &bar0->rmac_addr_cmd_mem);
4083 /* Wait till command completes */
4084 wait_for_cmd_complete(sp);
4085
4086 sp->m_cast_flg = 0;
4087 sp->all_multi_pos = 0;
4088 }
4089
4090 if ((dev->flags & IFF_PROMISC) && (!sp->promisc_flg)) {
4091 /* Put the NIC into promiscuous mode */
4092 add = &bar0->mac_cfg;
4093 val64 = readq(&bar0->mac_cfg);
4094 val64 |= MAC_CFG_RMAC_PROM_ENABLE;
4095
4096 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4097 writel((u32) val64, add);
4098 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4099 writel((u32) (val64 >> 32), (add + 4));
4100
4101 val64 = readq(&bar0->mac_cfg);
4102 sp->promisc_flg = 1;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004103 DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 dev->name);
4105 } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) {
4106 /* Remove the NIC from promiscuous mode */
4107 add = &bar0->mac_cfg;
4108 val64 = readq(&bar0->mac_cfg);
4109 val64 &= ~MAC_CFG_RMAC_PROM_ENABLE;
4110
4111 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4112 writel((u32) val64, add);
4113 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4114 writel((u32) (val64 >> 32), (add + 4));
4115
4116 val64 = readq(&bar0->mac_cfg);
4117 sp->promisc_flg = 0;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004118 DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119 dev->name);
4120 }
4121
4122 /* Update individual M_CAST address list */
4123 if ((!sp->m_cast_flg) && dev->mc_count) {
4124 if (dev->mc_count >
4125 (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) {
4126 DBG_PRINT(ERR_DBG, "%s: No more Rx filters ",
4127 dev->name);
4128 DBG_PRINT(ERR_DBG, "can be added, please enable ");
4129 DBG_PRINT(ERR_DBG, "ALL_MULTI instead\n");
4130 return;
4131 }
4132
4133 prev_cnt = sp->mc_addr_count;
4134 sp->mc_addr_count = dev->mc_count;
4135
4136 /* Clear out the previous list of Mc in the H/W. */
4137 for (i = 0; i < prev_cnt; i++) {
4138 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4139 &bar0->rmac_addr_data0_mem);
4140 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004141 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 val64 = RMAC_ADDR_CMD_MEM_WE |
4143 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4144 RMAC_ADDR_CMD_MEM_OFFSET
4145 (MAC_MC_ADDR_START_OFFSET + i);
4146 writeq(val64, &bar0->rmac_addr_cmd_mem);
4147
4148 /* Wait for command completes */
4149 if (wait_for_cmd_complete(sp)) {
4150 DBG_PRINT(ERR_DBG, "%s: Adding ",
4151 dev->name);
4152 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4153 return;
4154 }
4155 }
4156
4157 /* Create the new Rx filter list and update the same in H/W. */
4158 for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
4159 i++, mclist = mclist->next) {
4160 memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr,
4161 ETH_ALEN);
4162 for (j = 0; j < ETH_ALEN; j++) {
4163 mac_addr |= mclist->dmi_addr[j];
4164 mac_addr <<= 8;
4165 }
4166 mac_addr >>= 8;
4167 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4168 &bar0->rmac_addr_data0_mem);
4169 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004170 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 val64 = RMAC_ADDR_CMD_MEM_WE |
4172 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4173 RMAC_ADDR_CMD_MEM_OFFSET
4174 (i + MAC_MC_ADDR_START_OFFSET);
4175 writeq(val64, &bar0->rmac_addr_cmd_mem);
4176
4177 /* Wait for command completes */
4178 if (wait_for_cmd_complete(sp)) {
4179 DBG_PRINT(ERR_DBG, "%s: Adding ",
4180 dev->name);
4181 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4182 return;
4183 }
4184 }
4185 }
4186}
4187
4188/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004189 * s2io_set_mac_addr - Programs the Xframe mac address
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 * @dev : pointer to the device structure.
4191 * @addr: a uchar pointer to the new mac address which is to be set.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004192 * Description : This procedure will program the Xframe to receive
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 * frames with new Mac Address
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004194 * Return value: SUCCESS on success and an appropriate (-)ve integer
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 * as defined in errno.h file on failure.
4196 */
4197
4198int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
4199{
4200 nic_t *sp = dev->priv;
4201 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4202 register u64 val64, mac_addr = 0;
4203 int i;
4204
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004205 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 * Set the new MAC address as the new unicast filter and reflect this
4207 * change on the device address registered with the OS. It will be
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004208 * at offset 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 */
4210 for (i = 0; i < ETH_ALEN; i++) {
4211 mac_addr <<= 8;
4212 mac_addr |= addr[i];
4213 }
4214
4215 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4216 &bar0->rmac_addr_data0_mem);
4217
4218 val64 =
4219 RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4220 RMAC_ADDR_CMD_MEM_OFFSET(0);
4221 writeq(val64, &bar0->rmac_addr_cmd_mem);
4222 /* Wait till command completes */
4223 if (wait_for_cmd_complete(sp)) {
4224 DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
4225 return FAILURE;
4226 }
4227
4228 return SUCCESS;
4229}
4230
4231/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004232 * s2io_ethtool_sset - Sets different link parameters.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure.
4234 * @info: pointer to the structure with parameters given by ethtool to set
4235 * link information.
4236 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004237 * The function sets different link parameters provided by the user onto
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 * the NIC.
4239 * Return value:
4240 * 0 on success.
4241*/
4242
4243static int s2io_ethtool_sset(struct net_device *dev,
4244 struct ethtool_cmd *info)
4245{
4246 nic_t *sp = dev->priv;
4247 if ((info->autoneg == AUTONEG_ENABLE) ||
4248 (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
4249 return -EINVAL;
4250 else {
4251 s2io_close(sp->dev);
4252 s2io_open(sp->dev);
4253 }
4254
4255 return 0;
4256}
4257
4258/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004259 * s2io_ethtol_gset - Return link specific information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 * @sp : private member of the device structure, pointer to the
4261 * s2io_nic structure.
4262 * @info : pointer to the structure with parameters given by ethtool
4263 * to return link information.
4264 * Description:
4265 * Returns link specific information like speed, duplex etc.. to ethtool.
4266 * Return value :
4267 * return 0 on success.
4268 */
4269
4270static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
4271{
4272 nic_t *sp = dev->priv;
4273 info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4274 info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4275 info->port = PORT_FIBRE;
4276 /* info->transceiver?? TODO */
4277
4278 if (netif_carrier_ok(sp->dev)) {
4279 info->speed = 10000;
4280 info->duplex = DUPLEX_FULL;
4281 } else {
4282 info->speed = -1;
4283 info->duplex = -1;
4284 }
4285
4286 info->autoneg = AUTONEG_DISABLE;
4287 return 0;
4288}
4289
4290/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004291 * s2io_ethtool_gdrvinfo - Returns driver specific information.
4292 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 * s2io_nic structure.
4294 * @info : pointer to the structure with parameters given by ethtool to
4295 * return driver information.
4296 * Description:
4297 * Returns driver specefic information like name, version etc.. to ethtool.
4298 * Return value:
4299 * void
4300 */
4301
4302static void s2io_ethtool_gdrvinfo(struct net_device *dev,
4303 struct ethtool_drvinfo *info)
4304{
4305 nic_t *sp = dev->priv;
4306
John W. Linvilledbc23092005-09-28 17:50:51 -04004307 strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
4308 strncpy(info->version, s2io_driver_version, sizeof(info->version));
4309 strncpy(info->fw_version, "", sizeof(info->fw_version));
4310 strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 info->regdump_len = XENA_REG_SPACE;
4312 info->eedump_len = XENA_EEPROM_SPACE;
4313 info->testinfo_len = S2IO_TEST_LEN;
4314 info->n_stats = S2IO_STAT_LEN;
4315}
4316
4317/**
4318 * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004319 * @sp: private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004321 * @regs : pointer to the structure with parameters given by ethtool for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 * dumping the registers.
4323 * @reg_space: The input argumnet into which all the registers are dumped.
4324 * Description:
4325 * Dumps the entire register space of xFrame NIC into the user given
4326 * buffer area.
4327 * Return value :
4328 * void .
4329*/
4330
4331static void s2io_ethtool_gregs(struct net_device *dev,
4332 struct ethtool_regs *regs, void *space)
4333{
4334 int i;
4335 u64 reg;
4336 u8 *reg_space = (u8 *) space;
4337 nic_t *sp = dev->priv;
4338
4339 regs->len = XENA_REG_SPACE;
4340 regs->version = sp->pdev->subsystem_device;
4341
4342 for (i = 0; i < regs->len; i += 8) {
4343 reg = readq(sp->bar0 + i);
4344 memcpy((reg_space + i), &reg, 8);
4345 }
4346}
4347
4348/**
4349 * s2io_phy_id - timer function that alternates adapter LED.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004350 * @data : address of the private member of the device structure, which
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 * is a pointer to the s2io_nic structure, provided as an u32.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004352 * Description: This is actually the timer function that alternates the
4353 * adapter LED bit of the adapter control bit to set/reset every time on
4354 * invocation. The timer is set for 1/2 a second, hence tha NIC blinks
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 * once every second.
4356*/
4357static void s2io_phy_id(unsigned long data)
4358{
4359 nic_t *sp = (nic_t *) data;
4360 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4361 u64 val64 = 0;
4362 u16 subid;
4363
4364 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004365 if ((sp->device_type == XFRAME_II_DEVICE) ||
4366 ((subid & 0xFF) >= 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 val64 = readq(&bar0->gpio_control);
4368 val64 ^= GPIO_CTRL_GPIO_0;
4369 writeq(val64, &bar0->gpio_control);
4370 } else {
4371 val64 = readq(&bar0->adapter_control);
4372 val64 ^= ADAPTER_LED_ON;
4373 writeq(val64, &bar0->adapter_control);
4374 }
4375
4376 mod_timer(&sp->id_timer, jiffies + HZ / 2);
4377}
4378
4379/**
4380 * s2io_ethtool_idnic - To physically identify the nic on the system.
4381 * @sp : private member of the device structure, which is a pointer to the
4382 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004383 * @id : pointer to the structure with identification parameters given by
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 * ethtool.
4385 * Description: Used to physically identify the NIC on the system.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004386 * The Link LED will blink for a time specified by the user for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 * identification.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004388 * NOTE: The Link has to be Up to be able to blink the LED. Hence
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 * identification is possible only if it's link is up.
4390 * Return value:
4391 * int , returns 0 on success
4392 */
4393
4394static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
4395{
4396 u64 val64 = 0, last_gpio_ctrl_val;
4397 nic_t *sp = dev->priv;
4398 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4399 u16 subid;
4400
4401 subid = sp->pdev->subsystem_device;
4402 last_gpio_ctrl_val = readq(&bar0->gpio_control);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004403 if ((sp->device_type == XFRAME_I_DEVICE) &&
4404 ((subid & 0xFF) < 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 val64 = readq(&bar0->adapter_control);
4406 if (!(val64 & ADAPTER_CNTL_EN)) {
4407 printk(KERN_ERR
4408 "Adapter Link down, cannot blink LED\n");
4409 return -EFAULT;
4410 }
4411 }
4412 if (sp->id_timer.function == NULL) {
4413 init_timer(&sp->id_timer);
4414 sp->id_timer.function = s2io_phy_id;
4415 sp->id_timer.data = (unsigned long) sp;
4416 }
4417 mod_timer(&sp->id_timer, jiffies);
4418 if (data)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004419 msleep_interruptible(data * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004421 msleep_interruptible(MAX_FLICKER_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 del_timer_sync(&sp->id_timer);
4423
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004424 if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 writeq(last_gpio_ctrl_val, &bar0->gpio_control);
4426 last_gpio_ctrl_val = readq(&bar0->gpio_control);
4427 }
4428
4429 return 0;
4430}
4431
4432/**
4433 * s2io_ethtool_getpause_data -Pause frame frame generation and reception.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004434 * @sp : private member of the device structure, which is a pointer to the
4435 * s2io_nic structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 * @ep : pointer to the structure with pause parameters given by ethtool.
4437 * Description:
4438 * Returns the Pause frame generation and reception capability of the NIC.
4439 * Return value:
4440 * void
4441 */
4442static void s2io_ethtool_getpause_data(struct net_device *dev,
4443 struct ethtool_pauseparam *ep)
4444{
4445 u64 val64;
4446 nic_t *sp = dev->priv;
4447 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4448
4449 val64 = readq(&bar0->rmac_pause_cfg);
4450 if (val64 & RMAC_PAUSE_GEN_ENABLE)
4451 ep->tx_pause = TRUE;
4452 if (val64 & RMAC_PAUSE_RX_ENABLE)
4453 ep->rx_pause = TRUE;
4454 ep->autoneg = FALSE;
4455}
4456
4457/**
4458 * s2io_ethtool_setpause_data - set/reset pause frame generation.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004459 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 * s2io_nic structure.
4461 * @ep : pointer to the structure with pause parameters given by ethtool.
4462 * Description:
4463 * It can be used to set or reset Pause frame generation or reception
4464 * support of the NIC.
4465 * Return value:
4466 * int, returns 0 on Success
4467 */
4468
4469static int s2io_ethtool_setpause_data(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004470 struct ethtool_pauseparam *ep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471{
4472 u64 val64;
4473 nic_t *sp = dev->priv;
4474 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4475
4476 val64 = readq(&bar0->rmac_pause_cfg);
4477 if (ep->tx_pause)
4478 val64 |= RMAC_PAUSE_GEN_ENABLE;
4479 else
4480 val64 &= ~RMAC_PAUSE_GEN_ENABLE;
4481 if (ep->rx_pause)
4482 val64 |= RMAC_PAUSE_RX_ENABLE;
4483 else
4484 val64 &= ~RMAC_PAUSE_RX_ENABLE;
4485 writeq(val64, &bar0->rmac_pause_cfg);
4486 return 0;
4487}
4488
4489/**
4490 * read_eeprom - reads 4 bytes of data from user given offset.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004491 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 * s2io_nic structure.
4493 * @off : offset at which the data must be written
4494 * @data : Its an output parameter where the data read at the given
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004495 * offset is stored.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004497 * Will read 4 bytes of data from the user given offset and return the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 * read data.
4499 * NOTE: Will allow to read only part of the EEPROM visible through the
4500 * I2C bus.
4501 * Return value:
4502 * -1 on failure and 0 on success.
4503 */
4504
4505#define S2IO_DEV_ID 5
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004506static int read_eeprom(nic_t * sp, int off, u64 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507{
4508 int ret = -1;
4509 u32 exit_cnt = 0;
4510 u64 val64;
4511 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4512
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004513 if (sp->device_type == XFRAME_I_DEVICE) {
4514 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4515 I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ |
4516 I2C_CONTROL_CNTL_START;
4517 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004519 while (exit_cnt < 5) {
4520 val64 = readq(&bar0->i2c_control);
4521 if (I2C_CONTROL_CNTL_END(val64)) {
4522 *data = I2C_CONTROL_GET_DATA(val64);
4523 ret = 0;
4524 break;
4525 }
4526 msleep(50);
4527 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 }
4530
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004531 if (sp->device_type == XFRAME_II_DEVICE) {
4532 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
4533 SPI_CONTROL_BYTECNT(0x3) |
4534 SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off);
4535 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4536 val64 |= SPI_CONTROL_REQ;
4537 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4538 while (exit_cnt < 5) {
4539 val64 = readq(&bar0->spi_control);
4540 if (val64 & SPI_CONTROL_NACK) {
4541 ret = 1;
4542 break;
4543 } else if (val64 & SPI_CONTROL_DONE) {
4544 *data = readq(&bar0->spi_data);
4545 *data &= 0xffffff;
4546 ret = 0;
4547 break;
4548 }
4549 msleep(50);
4550 exit_cnt++;
4551 }
4552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 return ret;
4554}
4555
4556/**
4557 * write_eeprom - actually writes the relevant part of the data value.
4558 * @sp : private member of the device structure, which is a pointer to the
4559 * s2io_nic structure.
4560 * @off : offset at which the data must be written
4561 * @data : The data that is to be written
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004562 * @cnt : Number of bytes of the data that are actually to be written into
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 * the Eeprom. (max of 3)
4564 * Description:
4565 * Actually writes the relevant part of the data value into the Eeprom
4566 * through the I2C bus.
4567 * Return value:
4568 * 0 on success, -1 on failure.
4569 */
4570
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004571static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572{
4573 int exit_cnt = 0, ret = -1;
4574 u64 val64;
4575 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4576
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004577 if (sp->device_type == XFRAME_I_DEVICE) {
4578 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4579 I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) |
4580 I2C_CONTROL_CNTL_START;
4581 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004583 while (exit_cnt < 5) {
4584 val64 = readq(&bar0->i2c_control);
4585 if (I2C_CONTROL_CNTL_END(val64)) {
4586 if (!(val64 & I2C_CONTROL_NACK))
4587 ret = 0;
4588 break;
4589 }
4590 msleep(50);
4591 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 }
4594
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004595 if (sp->device_type == XFRAME_II_DEVICE) {
4596 int write_cnt = (cnt == 8) ? 0 : cnt;
4597 writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data);
4598
4599 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
4600 SPI_CONTROL_BYTECNT(write_cnt) |
4601 SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off);
4602 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4603 val64 |= SPI_CONTROL_REQ;
4604 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4605 while (exit_cnt < 5) {
4606 val64 = readq(&bar0->spi_control);
4607 if (val64 & SPI_CONTROL_NACK) {
4608 ret = 1;
4609 break;
4610 } else if (val64 & SPI_CONTROL_DONE) {
4611 ret = 0;
4612 break;
4613 }
4614 msleep(50);
4615 exit_cnt++;
4616 }
4617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 return ret;
4619}
4620
4621/**
4622 * s2io_ethtool_geeprom - reads the value stored in the Eeprom.
4623 * @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 -07004624 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 * containing all relevant information.
4626 * @data_buf : user defined value to be written into Eeprom.
4627 * Description: Reads the values stored in the Eeprom at given offset
4628 * for a given length. Stores these values int the input argument data
4629 * buffer 'data_buf' and returns these to the caller (ethtool.)
4630 * Return value:
4631 * int 0 on success
4632 */
4633
4634static int s2io_ethtool_geeprom(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004635 struct ethtool_eeprom *eeprom, u8 * data_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636{
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004637 u32 i, valid;
4638 u64 data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 nic_t *sp = dev->priv;
4640
4641 eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
4642
4643 if ((eeprom->offset + eeprom->len) > (XENA_EEPROM_SPACE))
4644 eeprom->len = XENA_EEPROM_SPACE - eeprom->offset;
4645
4646 for (i = 0; i < eeprom->len; i += 4) {
4647 if (read_eeprom(sp, (eeprom->offset + i), &data)) {
4648 DBG_PRINT(ERR_DBG, "Read of EEPROM failed\n");
4649 return -EFAULT;
4650 }
4651 valid = INV(data);
4652 memcpy((data_buf + i), &valid, 4);
4653 }
4654 return 0;
4655}
4656
4657/**
4658 * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom
4659 * @sp : private member of the device structure, which is a pointer to the
4660 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004661 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 * containing all relevant information.
4663 * @data_buf ; user defined value to be written into Eeprom.
4664 * Description:
4665 * Tries to write the user provided value in the Eeprom, at the offset
4666 * given by the user.
4667 * Return value:
4668 * 0 on success, -EFAULT on failure.
4669 */
4670
4671static int s2io_ethtool_seeprom(struct net_device *dev,
4672 struct ethtool_eeprom *eeprom,
4673 u8 * data_buf)
4674{
4675 int len = eeprom->len, cnt = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004676 u64 valid = 0, data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 nic_t *sp = dev->priv;
4678
4679 if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
4680 DBG_PRINT(ERR_DBG,
4681 "ETHTOOL_WRITE_EEPROM Err: Magic value ");
4682 DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n",
4683 eeprom->magic);
4684 return -EFAULT;
4685 }
4686
4687 while (len) {
4688 data = (u32) data_buf[cnt] & 0x000000FF;
4689 if (data) {
4690 valid = (u32) (data << 24);
4691 } else
4692 valid = data;
4693
4694 if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) {
4695 DBG_PRINT(ERR_DBG,
4696 "ETHTOOL_WRITE_EEPROM Err: Cannot ");
4697 DBG_PRINT(ERR_DBG,
4698 "write into the specified offset\n");
4699 return -EFAULT;
4700 }
4701 cnt++;
4702 len--;
4703 }
4704
4705 return 0;
4706}
4707
4708/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004709 * s2io_register_test - reads and writes into all clock domains.
4710 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 * s2io_nic structure.
4712 * @data : variable that returns the result of each of the test conducted b
4713 * by the driver.
4714 * Description:
4715 * Read and write into all clock domains. The NIC has 3 clock domains,
4716 * see that registers in all the three regions are accessible.
4717 * Return value:
4718 * 0 on success.
4719 */
4720
4721static int s2io_register_test(nic_t * sp, uint64_t * data)
4722{
4723 XENA_dev_config_t __iomem *bar0 = sp->bar0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004724 u64 val64 = 0, exp_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 int fail = 0;
4726
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004727 val64 = readq(&bar0->pif_rd_swapper_fb);
4728 if (val64 != 0x123456789abcdefULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 fail = 1;
4730 DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n");
4731 }
4732
4733 val64 = readq(&bar0->rmac_pause_cfg);
4734 if (val64 != 0xc000ffff00000000ULL) {
4735 fail = 1;
4736 DBG_PRINT(INFO_DBG, "Read Test level 2 fails\n");
4737 }
4738
4739 val64 = readq(&bar0->rx_queue_cfg);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004740 if (sp->device_type == XFRAME_II_DEVICE)
4741 exp_val = 0x0404040404040404ULL;
4742 else
4743 exp_val = 0x0808080808080808ULL;
4744 if (val64 != exp_val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 fail = 1;
4746 DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n");
4747 }
4748
4749 val64 = readq(&bar0->xgxs_efifo_cfg);
4750 if (val64 != 0x000000001923141EULL) {
4751 fail = 1;
4752 DBG_PRINT(INFO_DBG, "Read Test level 4 fails\n");
4753 }
4754
4755 val64 = 0x5A5A5A5A5A5A5A5AULL;
4756 writeq(val64, &bar0->xmsi_data);
4757 val64 = readq(&bar0->xmsi_data);
4758 if (val64 != 0x5A5A5A5A5A5A5A5AULL) {
4759 fail = 1;
4760 DBG_PRINT(ERR_DBG, "Write Test level 1 fails\n");
4761 }
4762
4763 val64 = 0xA5A5A5A5A5A5A5A5ULL;
4764 writeq(val64, &bar0->xmsi_data);
4765 val64 = readq(&bar0->xmsi_data);
4766 if (val64 != 0xA5A5A5A5A5A5A5A5ULL) {
4767 fail = 1;
4768 DBG_PRINT(ERR_DBG, "Write Test level 2 fails\n");
4769 }
4770
4771 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004772 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773}
4774
4775/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004776 * s2io_eeprom_test - to verify that EEprom in the xena can be programmed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777 * @sp : private member of the device structure, which is a pointer to the
4778 * s2io_nic structure.
4779 * @data:variable that returns the result of each of the test conducted by
4780 * the driver.
4781 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004782 * Verify that EEPROM in the xena can be programmed using I2C_CONTROL
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 * register.
4784 * Return value:
4785 * 0 on success.
4786 */
4787
4788static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
4789{
4790 int fail = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004791 u64 ret_data, org_4F0, org_7F0;
4792 u8 saved_4F0 = 0, saved_7F0 = 0;
4793 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794
4795 /* Test Write Error at offset 0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004796 /* Note that SPI interface allows write access to all areas
4797 * of EEPROM. Hence doing all negative testing only for Xframe I.
4798 */
4799 if (sp->device_type == XFRAME_I_DEVICE)
4800 if (!write_eeprom(sp, 0, 0, 3))
4801 fail = 1;
4802
4803 /* Save current values at offsets 0x4F0 and 0x7F0 */
4804 if (!read_eeprom(sp, 0x4F0, &org_4F0))
4805 saved_4F0 = 1;
4806 if (!read_eeprom(sp, 0x7F0, &org_7F0))
4807 saved_7F0 = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808
4809 /* Test Write at offset 4f0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004810 if (write_eeprom(sp, 0x4F0, 0x012345, 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 fail = 1;
4812 if (read_eeprom(sp, 0x4F0, &ret_data))
4813 fail = 1;
4814
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004815 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08004816 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. "
4817 "Data written %llx Data read %llx\n",
4818 dev->name, (unsigned long long)0x12345,
4819 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822
4823 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004824 write_eeprom(sp, 0x4F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825
4826 /* Test Write Request Error at offset 0x7c */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004827 if (sp->device_type == XFRAME_I_DEVICE)
4828 if (!write_eeprom(sp, 0x07C, 0, 3))
4829 fail = 1;
4830
4831 /* Test Write Request at offset 0x7f0 */
4832 if (write_eeprom(sp, 0x7F0, 0x012345, 3))
4833 fail = 1;
4834 if (read_eeprom(sp, 0x7F0, &ret_data))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 fail = 1;
4836
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004837 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08004838 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. "
4839 "Data written %llx Data read %llx\n",
4840 dev->name, (unsigned long long)0x12345,
4841 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004843 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844
4845 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004846 write_eeprom(sp, 0x7F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004848 if (sp->device_type == XFRAME_I_DEVICE) {
4849 /* Test Write Error at offset 0x80 */
4850 if (!write_eeprom(sp, 0x080, 0, 3))
4851 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004853 /* Test Write Error at offset 0xfc */
4854 if (!write_eeprom(sp, 0x0FC, 0, 3))
4855 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004857 /* Test Write Error at offset 0x100 */
4858 if (!write_eeprom(sp, 0x100, 0, 3))
4859 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004861 /* Test Write Error at offset 4ec */
4862 if (!write_eeprom(sp, 0x4EC, 0, 3))
4863 fail = 1;
4864 }
4865
4866 /* Restore values at offsets 0x4F0 and 0x7F0 */
4867 if (saved_4F0)
4868 write_eeprom(sp, 0x4F0, org_4F0, 3);
4869 if (saved_7F0)
4870 write_eeprom(sp, 0x7F0, org_7F0, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871
4872 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004873 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874}
4875
4876/**
4877 * s2io_bist_test - invokes the MemBist test of the card .
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004878 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004880 * @data:variable that returns the result of each of the test conducted by
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 * the driver.
4882 * Description:
4883 * This invokes the MemBist test of the card. We give around
4884 * 2 secs time for the Test to complete. If it's still not complete
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004885 * within this peiod, we consider that the test failed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 * Return value:
4887 * 0 on success and -1 on failure.
4888 */
4889
4890static int s2io_bist_test(nic_t * sp, uint64_t * data)
4891{
4892 u8 bist = 0;
4893 int cnt = 0, ret = -1;
4894
4895 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
4896 bist |= PCI_BIST_START;
4897 pci_write_config_word(sp->pdev, PCI_BIST, bist);
4898
4899 while (cnt < 20) {
4900 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
4901 if (!(bist & PCI_BIST_START)) {
4902 *data = (bist & PCI_BIST_CODE_MASK);
4903 ret = 0;
4904 break;
4905 }
4906 msleep(100);
4907 cnt++;
4908 }
4909
4910 return ret;
4911}
4912
4913/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004914 * s2io-link_test - verifies the link state of the nic
4915 * @sp ; private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 * s2io_nic structure.
4917 * @data: variable that returns the result of each of the test conducted by
4918 * the driver.
4919 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004920 * The function verifies the link state of the NIC and updates the input
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921 * argument 'data' appropriately.
4922 * Return value:
4923 * 0 on success.
4924 */
4925
4926static int s2io_link_test(nic_t * sp, uint64_t * data)
4927{
4928 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4929 u64 val64;
4930
4931 val64 = readq(&bar0->adapter_status);
4932 if (val64 & ADAPTER_STATUS_RMAC_LOCAL_FAULT)
4933 *data = 1;
4934
4935 return 0;
4936}
4937
4938/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004939 * s2io_rldram_test - offline test for access to the RldRam chip on the NIC
4940 * @sp - private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004942 * @data - variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 * conducted by the driver.
4944 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004945 * This is one of the offline test that tests the read and write
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 * access to the RldRam chip on the NIC.
4947 * Return value:
4948 * 0 on success.
4949 */
4950
4951static int s2io_rldram_test(nic_t * sp, uint64_t * data)
4952{
4953 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4954 u64 val64;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004955 int cnt, iteration = 0, test_fail = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956
4957 val64 = readq(&bar0->adapter_control);
4958 val64 &= ~ADAPTER_ECC_EN;
4959 writeq(val64, &bar0->adapter_control);
4960
4961 val64 = readq(&bar0->mc_rldram_test_ctrl);
4962 val64 |= MC_RLDRAM_TEST_MODE;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004963 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964
4965 val64 = readq(&bar0->mc_rldram_mrs);
4966 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE;
4967 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
4968
4969 val64 |= MC_RLDRAM_MRS_ENABLE;
4970 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
4971
4972 while (iteration < 2) {
4973 val64 = 0x55555555aaaa0000ULL;
4974 if (iteration == 1) {
4975 val64 ^= 0xFFFFFFFFFFFF0000ULL;
4976 }
4977 writeq(val64, &bar0->mc_rldram_test_d0);
4978
4979 val64 = 0xaaaa5a5555550000ULL;
4980 if (iteration == 1) {
4981 val64 ^= 0xFFFFFFFFFFFF0000ULL;
4982 }
4983 writeq(val64, &bar0->mc_rldram_test_d1);
4984
4985 val64 = 0x55aaaaaaaa5a0000ULL;
4986 if (iteration == 1) {
4987 val64 ^= 0xFFFFFFFFFFFF0000ULL;
4988 }
4989 writeq(val64, &bar0->mc_rldram_test_d2);
4990
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004991 val64 = (u64) (0x0000003ffffe0100ULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 writeq(val64, &bar0->mc_rldram_test_add);
4993
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004994 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE |
4995 MC_RLDRAM_TEST_GO;
4996 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997
4998 for (cnt = 0; cnt < 5; cnt++) {
4999 val64 = readq(&bar0->mc_rldram_test_ctrl);
5000 if (val64 & MC_RLDRAM_TEST_DONE)
5001 break;
5002 msleep(200);
5003 }
5004
5005 if (cnt == 5)
5006 break;
5007
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005008 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO;
5009 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010
5011 for (cnt = 0; cnt < 5; cnt++) {
5012 val64 = readq(&bar0->mc_rldram_test_ctrl);
5013 if (val64 & MC_RLDRAM_TEST_DONE)
5014 break;
5015 msleep(500);
5016 }
5017
5018 if (cnt == 5)
5019 break;
5020
5021 val64 = readq(&bar0->mc_rldram_test_ctrl);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005022 if (!(val64 & MC_RLDRAM_TEST_PASS))
5023 test_fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024
5025 iteration++;
5026 }
5027
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005028 *data = test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005030 /* Bring the adapter out of test mode */
5031 SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF);
5032
5033 return test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034}
5035
5036/**
5037 * s2io_ethtool_test - conducts 6 tsets to determine the health of card.
5038 * @sp : private member of the device structure, which is a pointer to the
5039 * s2io_nic structure.
5040 * @ethtest : pointer to a ethtool command specific structure that will be
5041 * returned to the user.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005042 * @data : variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 * conducted by the driver.
5044 * Description:
5045 * This function conducts 6 tests ( 4 offline and 2 online) to determine
5046 * the health of the card.
5047 * Return value:
5048 * void
5049 */
5050
5051static void s2io_ethtool_test(struct net_device *dev,
5052 struct ethtool_test *ethtest,
5053 uint64_t * data)
5054{
5055 nic_t *sp = dev->priv;
5056 int orig_state = netif_running(sp->dev);
5057
5058 if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
5059 /* Offline Tests. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005060 if (orig_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061 s2io_close(sp->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062
5063 if (s2io_register_test(sp, &data[0]))
5064 ethtest->flags |= ETH_TEST_FL_FAILED;
5065
5066 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067
5068 if (s2io_rldram_test(sp, &data[3]))
5069 ethtest->flags |= ETH_TEST_FL_FAILED;
5070
5071 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072
5073 if (s2io_eeprom_test(sp, &data[1]))
5074 ethtest->flags |= ETH_TEST_FL_FAILED;
5075
5076 if (s2io_bist_test(sp, &data[4]))
5077 ethtest->flags |= ETH_TEST_FL_FAILED;
5078
5079 if (orig_state)
5080 s2io_open(sp->dev);
5081
5082 data[2] = 0;
5083 } else {
5084 /* Online Tests. */
5085 if (!orig_state) {
5086 DBG_PRINT(ERR_DBG,
5087 "%s: is not up, cannot run test\n",
5088 dev->name);
5089 data[0] = -1;
5090 data[1] = -1;
5091 data[2] = -1;
5092 data[3] = -1;
5093 data[4] = -1;
5094 }
5095
5096 if (s2io_link_test(sp, &data[2]))
5097 ethtest->flags |= ETH_TEST_FL_FAILED;
5098
5099 data[0] = 0;
5100 data[1] = 0;
5101 data[3] = 0;
5102 data[4] = 0;
5103 }
5104}
5105
5106static void s2io_get_ethtool_stats(struct net_device *dev,
5107 struct ethtool_stats *estats,
5108 u64 * tmp_stats)
5109{
5110 int i = 0;
5111 nic_t *sp = dev->priv;
5112 StatInfo_t *stat_info = sp->mac_control.stats_info;
5113
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005114 s2io_updt_stats(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005115 tmp_stats[i++] =
5116 (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32 |
5117 le32_to_cpu(stat_info->tmac_frms);
5118 tmp_stats[i++] =
5119 (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 |
5120 le32_to_cpu(stat_info->tmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005122 tmp_stats[i++] =
5123 (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 |
5124 le32_to_cpu(stat_info->tmac_mcst_frms);
5125 tmp_stats[i++] =
5126 (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 |
5127 le32_to_cpu(stat_info->tmac_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005129 tmp_stats[i++] =
5130 (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 |
5131 le32_to_cpu(stat_info->tmac_any_err_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005133 tmp_stats[i++] =
5134 (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 |
5135 le32_to_cpu(stat_info->tmac_vld_ip);
5136 tmp_stats[i++] =
5137 (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 |
5138 le32_to_cpu(stat_info->tmac_drop_ip);
5139 tmp_stats[i++] =
5140 (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 |
5141 le32_to_cpu(stat_info->tmac_icmp);
5142 tmp_stats[i++] =
5143 (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 |
5144 le32_to_cpu(stat_info->tmac_rst_tcp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005146 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 |
5147 le32_to_cpu(stat_info->tmac_udp);
5148 tmp_stats[i++] =
5149 (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 |
5150 le32_to_cpu(stat_info->rmac_vld_frms);
5151 tmp_stats[i++] =
5152 (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 |
5153 le32_to_cpu(stat_info->rmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms);
5155 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005156 tmp_stats[i++] =
5157 (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 |
5158 le32_to_cpu(stat_info->rmac_vld_mcst_frms);
5159 tmp_stats[i++] =
5160 (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 |
5161 le32_to_cpu(stat_info->rmac_vld_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms);
5163 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms);
5164 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005165 tmp_stats[i++] =
5166 (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 |
5167 le32_to_cpu(stat_info->rmac_discarded_frms);
5168 tmp_stats[i++] =
5169 (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 |
5170 le32_to_cpu(stat_info->rmac_usized_frms);
5171 tmp_stats[i++] =
5172 (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 |
5173 le32_to_cpu(stat_info->rmac_osized_frms);
5174 tmp_stats[i++] =
5175 (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 |
5176 le32_to_cpu(stat_info->rmac_frag_frms);
5177 tmp_stats[i++] =
5178 (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 |
5179 le32_to_cpu(stat_info->rmac_jabber_frms);
5180 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 |
5181 le32_to_cpu(stat_info->rmac_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets);
5183 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005184 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 |
5185 le32_to_cpu(stat_info->rmac_drop_ip);
5186 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 |
5187 le32_to_cpu(stat_info->rmac_icmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005189 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 |
5190 le32_to_cpu(stat_info->rmac_udp);
5191 tmp_stats[i++] =
5192 (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 |
5193 le32_to_cpu(stat_info->rmac_err_drp_udp);
5194 tmp_stats[i++] =
5195 (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 |
5196 le32_to_cpu(stat_info->rmac_pause_cnt);
5197 tmp_stats[i++] =
5198 (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 |
5199 le32_to_cpu(stat_info->rmac_accepted_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005201 tmp_stats[i++] = 0;
5202 tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
5203 tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005204 tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt;
5205 tmp_stats[i++] = stat_info->sw_stat.sending_both;
5206 tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts;
5207 tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts;
5208 if (stat_info->sw_stat.num_aggregations)
5209 tmp_stats[i++] = stat_info->sw_stat.sum_avg_pkts_aggregated /
5210 stat_info->sw_stat.num_aggregations;
5211 else
5212 tmp_stats[i++] = 0;
5213
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214}
5215
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005216static int s2io_ethtool_get_regs_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217{
5218 return (XENA_REG_SPACE);
5219}
5220
5221
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005222static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223{
5224 nic_t *sp = dev->priv;
5225
5226 return (sp->rx_csum);
5227}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005228
5229static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230{
5231 nic_t *sp = dev->priv;
5232
5233 if (data)
5234 sp->rx_csum = 1;
5235 else
5236 sp->rx_csum = 0;
5237
5238 return 0;
5239}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005240
5241static int s2io_get_eeprom_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242{
5243 return (XENA_EEPROM_SPACE);
5244}
5245
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005246static int s2io_ethtool_self_test_count(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247{
5248 return (S2IO_TEST_LEN);
5249}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005250
5251static void s2io_ethtool_get_strings(struct net_device *dev,
5252 u32 stringset, u8 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253{
5254 switch (stringset) {
5255 case ETH_SS_TEST:
5256 memcpy(data, s2io_gstrings, S2IO_STRINGS_LEN);
5257 break;
5258 case ETH_SS_STATS:
5259 memcpy(data, &ethtool_stats_keys,
5260 sizeof(ethtool_stats_keys));
5261 }
5262}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263static int s2io_ethtool_get_stats_count(struct net_device *dev)
5264{
5265 return (S2IO_STAT_LEN);
5266}
5267
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005268static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269{
5270 if (data)
5271 dev->features |= NETIF_F_IP_CSUM;
5272 else
5273 dev->features &= ~NETIF_F_IP_CSUM;
5274
5275 return 0;
5276}
5277
5278
5279static struct ethtool_ops netdev_ethtool_ops = {
5280 .get_settings = s2io_ethtool_gset,
5281 .set_settings = s2io_ethtool_sset,
5282 .get_drvinfo = s2io_ethtool_gdrvinfo,
5283 .get_regs_len = s2io_ethtool_get_regs_len,
5284 .get_regs = s2io_ethtool_gregs,
5285 .get_link = ethtool_op_get_link,
5286 .get_eeprom_len = s2io_get_eeprom_len,
5287 .get_eeprom = s2io_ethtool_geeprom,
5288 .set_eeprom = s2io_ethtool_seeprom,
5289 .get_pauseparam = s2io_ethtool_getpause_data,
5290 .set_pauseparam = s2io_ethtool_setpause_data,
5291 .get_rx_csum = s2io_ethtool_get_rx_csum,
5292 .set_rx_csum = s2io_ethtool_set_rx_csum,
5293 .get_tx_csum = ethtool_op_get_tx_csum,
5294 .set_tx_csum = s2io_ethtool_op_set_tx_csum,
5295 .get_sg = ethtool_op_get_sg,
5296 .set_sg = ethtool_op_set_sg,
5297#ifdef NETIF_F_TSO
5298 .get_tso = ethtool_op_get_tso,
5299 .set_tso = ethtool_op_set_tso,
5300#endif
Ananda Rajufed5ecc2005-11-14 15:25:08 -05005301 .get_ufo = ethtool_op_get_ufo,
5302 .set_ufo = ethtool_op_set_ufo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303 .self_test_count = s2io_ethtool_self_test_count,
5304 .self_test = s2io_ethtool_test,
5305 .get_strings = s2io_ethtool_get_strings,
5306 .phys_id = s2io_ethtool_idnic,
5307 .get_stats_count = s2io_ethtool_get_stats_count,
5308 .get_ethtool_stats = s2io_get_ethtool_stats
5309};
5310
5311/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005312 * s2io_ioctl - Entry point for the Ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 * @dev : Device pointer.
5314 * @ifr : An IOCTL specefic structure, that can contain a pointer to
5315 * a proprietary structure used to pass information to the driver.
5316 * @cmd : This is used to distinguish between the different commands that
5317 * can be passed to the IOCTL functions.
5318 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005319 * Currently there are no special functionality supported in IOCTL, hence
5320 * function always return EOPNOTSUPPORTED
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 */
5322
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005323static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324{
5325 return -EOPNOTSUPP;
5326}
5327
5328/**
5329 * s2io_change_mtu - entry point to change MTU size for the device.
5330 * @dev : device pointer.
5331 * @new_mtu : the new MTU size for the device.
5332 * Description: A driver entry point to change MTU size for the device.
5333 * Before changing the MTU the device must be stopped.
5334 * Return value:
5335 * 0 on success and an appropriate (-)ve integer as defined in errno.h
5336 * file on failure.
5337 */
5338
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005339static int s2io_change_mtu(struct net_device *dev, int new_mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340{
5341 nic_t *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342
5343 if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
5344 DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
5345 dev->name);
5346 return -EPERM;
5347 }
5348
Linus Torvalds1da177e2005-04-16 15:20:36 -07005349 dev->mtu = new_mtu;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005350 if (netif_running(dev)) {
5351 s2io_card_down(sp);
5352 netif_stop_queue(dev);
5353 if (s2io_card_up(sp)) {
5354 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
5355 __FUNCTION__);
5356 }
5357 if (netif_queue_stopped(dev))
5358 netif_wake_queue(dev);
5359 } else { /* Device is down */
5360 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5361 u64 val64 = new_mtu;
5362
5363 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
5364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365
5366 return 0;
5367}
5368
5369/**
5370 * s2io_tasklet - Bottom half of the ISR.
5371 * @dev_adr : address of the device structure in dma_addr_t format.
5372 * Description:
5373 * This is the tasklet or the bottom half of the ISR. This is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005374 * an extension of the ISR which is scheduled by the scheduler to be run
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 * 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 -07005376 * be pushed into the tasklet. For now the tasklet is used only to
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 * replenish the Rx buffers in the Rx buffer descriptors.
5378 * Return value:
5379 * void.
5380 */
5381
5382static void s2io_tasklet(unsigned long dev_addr)
5383{
5384 struct net_device *dev = (struct net_device *) dev_addr;
5385 nic_t *sp = dev->priv;
5386 int i, ret;
5387 mac_info_t *mac_control;
5388 struct config_param *config;
5389
5390 mac_control = &sp->mac_control;
5391 config = &sp->config;
5392
5393 if (!TASKLET_IN_USE) {
5394 for (i = 0; i < config->rx_ring_num; i++) {
5395 ret = fill_rx_buffers(sp, i);
5396 if (ret == -ENOMEM) {
5397 DBG_PRINT(ERR_DBG, "%s: Out of ",
5398 dev->name);
5399 DBG_PRINT(ERR_DBG, "memory in tasklet\n");
5400 break;
5401 } else if (ret == -EFILL) {
5402 DBG_PRINT(ERR_DBG,
5403 "%s: Rx Ring %d is full\n",
5404 dev->name, i);
5405 break;
5406 }
5407 }
5408 clear_bit(0, (&sp->tasklet_status));
5409 }
5410}
5411
5412/**
5413 * s2io_set_link - Set the LInk status
5414 * @data: long pointer to device private structue
5415 * Description: Sets the link status for the adapter
5416 */
5417
5418static void s2io_set_link(unsigned long data)
5419{
5420 nic_t *nic = (nic_t *) data;
5421 struct net_device *dev = nic->dev;
5422 XENA_dev_config_t __iomem *bar0 = nic->bar0;
5423 register u64 val64;
5424 u16 subid;
5425
5426 if (test_and_set_bit(0, &(nic->link_state))) {
5427 /* The card is being reset, no point doing anything */
5428 return;
5429 }
5430
5431 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07005432 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
5433 /*
5434 * Allow a small delay for the NICs self initiated
5435 * cleanup to complete.
5436 */
5437 msleep(100);
5438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439
5440 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005441 if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442 if (LINK_IS_UP(val64)) {
5443 val64 = readq(&bar0->adapter_control);
5444 val64 |= ADAPTER_CNTL_EN;
5445 writeq(val64, &bar0->adapter_control);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005446 if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
5447 subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 val64 = readq(&bar0->gpio_control);
5449 val64 |= GPIO_CTRL_GPIO_0;
5450 writeq(val64, &bar0->gpio_control);
5451 val64 = readq(&bar0->gpio_control);
5452 } else {
5453 val64 |= ADAPTER_LED_ON;
5454 writeq(val64, &bar0->adapter_control);
5455 }
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07005456 if (s2io_link_fault_indication(nic) ==
5457 MAC_RMAC_ERR_TIMER) {
5458 val64 = readq(&bar0->adapter_status);
5459 if (!LINK_IS_UP(val64)) {
5460 DBG_PRINT(ERR_DBG, "%s:", dev->name);
5461 DBG_PRINT(ERR_DBG, " Link down");
5462 DBG_PRINT(ERR_DBG, "after ");
5463 DBG_PRINT(ERR_DBG, "enabling ");
5464 DBG_PRINT(ERR_DBG, "device \n");
5465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466 }
5467 if (nic->device_enabled_once == FALSE) {
5468 nic->device_enabled_once = TRUE;
5469 }
5470 s2io_link(nic, LINK_UP);
5471 } else {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005472 if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
5473 subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 val64 = readq(&bar0->gpio_control);
5475 val64 &= ~GPIO_CTRL_GPIO_0;
5476 writeq(val64, &bar0->gpio_control);
5477 val64 = readq(&bar0->gpio_control);
5478 }
5479 s2io_link(nic, LINK_DOWN);
5480 }
5481 } else { /* NIC is not Quiescent. */
5482 DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
5483 DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
5484 netif_stop_queue(dev);
5485 }
5486 clear_bit(0, &(nic->link_state));
5487}
5488
5489static void s2io_card_down(nic_t * sp)
5490{
5491 int cnt = 0;
5492 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5493 unsigned long flags;
5494 register u64 val64 = 0;
5495
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07005496 del_timer_sync(&sp->alarm_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 /* If s2io_set_link task is executing, wait till it completes. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005498 while (test_and_set_bit(0, &(sp->link_state))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499 msleep(50);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 atomic_set(&sp->card_state, CARD_DOWN);
5502
5503 /* disable Tx and Rx traffic on the NIC */
5504 stop_nic(sp);
5505
5506 /* Kill tasklet. */
5507 tasklet_kill(&sp->task);
5508
5509 /* Check if the device is Quiescent and then Reset the NIC */
5510 do {
5511 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005512 if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 break;
5514 }
5515
5516 msleep(50);
5517 cnt++;
5518 if (cnt == 10) {
5519 DBG_PRINT(ERR_DBG,
5520 "s2io_close:Device not Quiescent ");
5521 DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n",
5522 (unsigned long long) val64);
5523 break;
5524 }
5525 } while (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 s2io_reset(sp);
5527
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005528 /* Waiting till all Interrupt handlers are complete */
5529 cnt = 0;
5530 do {
5531 msleep(10);
5532 if (!atomic_read(&sp->isr_cnt))
5533 break;
5534 cnt++;
5535 } while(cnt < 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005537 spin_lock_irqsave(&sp->tx_lock, flags);
5538 /* Free all Tx buffers */
5539 free_tx_buffers(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005541
5542 /* Free all Rx buffers */
5543 spin_lock_irqsave(&sp->rx_lock, flags);
5544 free_rx_buffers(sp);
5545 spin_unlock_irqrestore(&sp->rx_lock, flags);
5546
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 clear_bit(0, &(sp->link_state));
5548}
5549
5550static int s2io_card_up(nic_t * sp)
5551{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04005552 int i, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 mac_info_t *mac_control;
5554 struct config_param *config;
5555 struct net_device *dev = (struct net_device *) sp->dev;
5556
5557 /* Initialize the H/W I/O registers */
5558 if (init_nic(sp) != 0) {
5559 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
5560 dev->name);
5561 return -ENODEV;
5562 }
5563
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04005564 if (sp->intr_type == MSI)
5565 ret = s2io_enable_msi(sp);
5566 else if (sp->intr_type == MSI_X)
5567 ret = s2io_enable_msi_x(sp);
5568 if (ret) {
5569 DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
5570 sp->intr_type = INTA;
5571 }
5572
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005573 /*
5574 * Initializing the Rx buffers. For now we are considering only 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 * Rx ring and initializing buffers into 30 Rx blocks
5576 */
5577 mac_control = &sp->mac_control;
5578 config = &sp->config;
5579
5580 for (i = 0; i < config->rx_ring_num; i++) {
5581 if ((ret = fill_rx_buffers(sp, i))) {
5582 DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
5583 dev->name);
5584 s2io_reset(sp);
5585 free_rx_buffers(sp);
5586 return -ENOMEM;
5587 }
5588 DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
5589 atomic_read(&sp->rx_bufs_left[i]));
5590 }
5591
5592 /* Setting its receive mode */
5593 s2io_set_multicast(dev);
5594
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005595 if (sp->lro) {
5596 /* Initialize max aggregatable pkts based on MTU */
5597 sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
5598 /* Check if we can use(if specified) user provided value */
5599 if (lro_max_pkts < sp->lro_max_aggr_per_sess)
5600 sp->lro_max_aggr_per_sess = lro_max_pkts;
5601 }
5602
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 /* Enable tasklet for the device */
5604 tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
5605
5606 /* Enable Rx Traffic and interrupts on the NIC */
5607 if (start_nic(sp)) {
5608 DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
5609 tasklet_kill(&sp->task);
5610 s2io_reset(sp);
5611 free_irq(dev->irq, dev);
5612 free_rx_buffers(sp);
5613 return -ENODEV;
5614 }
5615
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07005616 S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
5617
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 atomic_set(&sp->card_state, CARD_UP);
5619 return 0;
5620}
5621
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005622/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 * s2io_restart_nic - Resets the NIC.
5624 * @data : long pointer to the device private structure
5625 * Description:
5626 * This function is scheduled to be run by the s2io_tx_watchdog
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005627 * function after 0.5 secs to reset the NIC. The idea is to reduce
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 * the run time of the watch dog routine which is run holding a
5629 * spin lock.
5630 */
5631
5632static void s2io_restart_nic(unsigned long data)
5633{
5634 struct net_device *dev = (struct net_device *) data;
5635 nic_t *sp = dev->priv;
5636
5637 s2io_card_down(sp);
5638 if (s2io_card_up(sp)) {
5639 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
5640 dev->name);
5641 }
5642 netif_wake_queue(dev);
5643 DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
5644 dev->name);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005645
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646}
5647
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005648/**
5649 * s2io_tx_watchdog - Watchdog for transmit side.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 * @dev : Pointer to net device structure
5651 * Description:
5652 * This function is triggered if the Tx Queue is stopped
5653 * for a pre-defined amount of time when the Interface is still up.
5654 * If the Interface is jammed in such a situation, the hardware is
5655 * reset (by s2io_close) and restarted again (by s2io_open) to
5656 * overcome any problem that might have been caused in the hardware.
5657 * Return value:
5658 * void
5659 */
5660
5661static void s2io_tx_watchdog(struct net_device *dev)
5662{
5663 nic_t *sp = dev->priv;
5664
5665 if (netif_carrier_ok(dev)) {
5666 schedule_work(&sp->rst_timer_task);
5667 }
5668}
5669
5670/**
5671 * rx_osm_handler - To perform some OS related operations on SKB.
5672 * @sp: private member of the device structure,pointer to s2io_nic structure.
5673 * @skb : the socket buffer pointer.
5674 * @len : length of the packet
5675 * @cksum : FCS checksum of the frame.
5676 * @ring_no : the ring from which this RxD was extracted.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005677 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678 * This function is called by the Tx interrupt serivce routine to perform
5679 * some OS related operations on the SKB before passing it to the upper
5680 * layers. It mainly checks if the checksum is OK, if so adds it to the
5681 * SKBs cksum variable, increments the Rx packet count and passes the SKB
5682 * to the upper layer. If the checksum is wrong, it increments the Rx
5683 * packet error count, frees the SKB and returns error.
5684 * Return value:
5685 * SUCCESS on success and -1 on failure.
5686 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005687static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005689 nic_t *sp = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690 struct net_device *dev = (struct net_device *) sp->dev;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005691 struct sk_buff *skb = (struct sk_buff *)
5692 ((unsigned long) rxdp->Host_Control);
5693 int ring_no = ring_data->ring_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694 u16 l3_csum, l4_csum;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005695 lro_t *lro;
Ananda Rajuda6971d2005-10-31 16:55:31 -05005696
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005697 skb->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698 if (rxdp->Control_1 & RXD_T_CODE) {
5699 unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
5700 DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
5701 dev->name, err);
raghavendra.koushik@neterion.com1ddc50d2005-08-03 12:30:43 -07005702 dev_kfree_skb(skb);
5703 sp->stats.rx_crc_errors++;
5704 atomic_dec(&sp->rx_bufs_left[ring_no]);
5705 rxdp->Host_Control = 0;
5706 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005709 /* Updating statistics */
5710 rxdp->Host_Control = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711 sp->rx_pkt_count++;
5712 sp->stats.rx_packets++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05005713 if (sp->rxd_mode == RXD_MODE_1) {
5714 int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715
Ananda Rajuda6971d2005-10-31 16:55:31 -05005716 sp->stats.rx_bytes += len;
5717 skb_put(skb, len);
5718
5719 } else if (sp->rxd_mode >= RXD_MODE_3A) {
5720 int get_block = ring_data->rx_curr_get_info.block_index;
5721 int get_off = ring_data->rx_curr_get_info.offset;
5722 int buf0_len = RXD_GET_BUFFER0_SIZE_3(rxdp->Control_2);
5723 int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
5724 unsigned char *buff = skb_push(skb, buf0_len);
5725
5726 buffAdd_t *ba = &ring_data->ba[get_block][get_off];
5727 sp->stats.rx_bytes += buf0_len + buf2_len;
5728 memcpy(buff, ba->ba_0, buf0_len);
5729
5730 if (sp->rxd_mode == RXD_MODE_3A) {
5731 int buf1_len = RXD_GET_BUFFER1_SIZE_3(rxdp->Control_2);
5732
5733 skb_put(skb, buf1_len);
5734 skb->len += buf2_len;
5735 skb->data_len += buf2_len;
5736 skb->truesize += buf2_len;
5737 skb_put(skb_shinfo(skb)->frag_list, buf2_len);
5738 sp->stats.rx_bytes += buf1_len;
5739
5740 } else
5741 skb_put(skb, buf2_len);
5742 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005743
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005744 if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
5745 (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005746 (sp->rx_csum)) {
5747 l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
5748 l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
5749 if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) {
5750 /*
5751 * NIC verifies if the Checksum of the received
5752 * frame is Ok or not and accordingly returns
5753 * a flag in the RxD.
5754 */
5755 skb->ip_summed = CHECKSUM_UNNECESSARY;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005756 if (sp->lro) {
5757 u32 tcp_len;
5758 u8 *tcp;
5759 int ret = 0;
5760
5761 ret = s2io_club_tcp_session(skb->data, &tcp,
5762 &tcp_len, &lro, rxdp, sp);
5763 switch (ret) {
5764 case 3: /* Begin anew */
5765 lro->parent = skb;
5766 goto aggregate;
5767 case 1: /* Aggregate */
5768 {
5769 lro_append_pkt(sp, lro,
5770 skb, tcp_len);
5771 goto aggregate;
5772 }
5773 case 4: /* Flush session */
5774 {
5775 lro_append_pkt(sp, lro,
5776 skb, tcp_len);
5777 queue_rx_frame(lro->parent);
5778 clear_lro_session(lro);
5779 sp->mac_control.stats_info->
5780 sw_stat.flush_max_pkts++;
5781 goto aggregate;
5782 }
5783 case 2: /* Flush both */
5784 lro->parent->data_len =
5785 lro->frags_len;
5786 sp->mac_control.stats_info->
5787 sw_stat.sending_both++;
5788 queue_rx_frame(lro->parent);
5789 clear_lro_session(lro);
5790 goto send_up;
5791 case 0: /* sessions exceeded */
5792 case 5: /*
5793 * First pkt in session not
5794 * L3/L4 aggregatable
5795 */
5796 break;
5797 default:
5798 DBG_PRINT(ERR_DBG,
5799 "%s: Samadhana!!\n",
5800 __FUNCTION__);
5801 BUG();
5802 }
5803 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005804 } else {
5805 /*
5806 * Packet with erroneous checksum, let the
5807 * upper layers deal with it.
5808 */
5809 skb->ip_summed = CHECKSUM_NONE;
5810 }
5811 } else {
5812 skb->ip_summed = CHECKSUM_NONE;
5813 }
5814
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005815 if (!sp->lro) {
5816 skb->protocol = eth_type_trans(skb, dev);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005817#ifdef CONFIG_S2IO_NAPI
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005818 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
5819 /* Queueing the vlan frame to the upper layer */
5820 vlan_hwaccel_receive_skb(skb, sp->vlgrp,
5821 RXD_GET_VLAN_TAG(rxdp->Control_2));
5822 } else {
5823 netif_receive_skb(skb);
5824 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005825#else
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005826 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
5827 /* Queueing the vlan frame to the upper layer */
5828 vlan_hwaccel_rx(skb, sp->vlgrp,
5829 RXD_GET_VLAN_TAG(rxdp->Control_2));
5830 } else {
5831 netif_rx(skb);
5832 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005833#endif
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005834 } else {
5835send_up:
5836 queue_rx_frame(skb);
5837 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005838 dev->last_rx = jiffies;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005839aggregate:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005840 atomic_dec(&sp->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841 return SUCCESS;
5842}
5843
5844/**
5845 * s2io_link - stops/starts the Tx queue.
5846 * @sp : private member of the device structure, which is a pointer to the
5847 * s2io_nic structure.
5848 * @link : inidicates whether link is UP/DOWN.
5849 * Description:
5850 * This function stops/starts the Tx queue depending on whether the link
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005851 * status of the NIC is is down or up. This is called by the Alarm
5852 * interrupt handler whenever a link change interrupt comes up.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853 * Return value:
5854 * void.
5855 */
5856
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005857void s2io_link(nic_t * sp, int link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858{
5859 struct net_device *dev = (struct net_device *) sp->dev;
5860
5861 if (link != sp->last_link_state) {
5862 if (link == LINK_DOWN) {
5863 DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
5864 netif_carrier_off(dev);
5865 } else {
5866 DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
5867 netif_carrier_on(dev);
5868 }
5869 }
5870 sp->last_link_state = link;
5871}
5872
5873/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005874 * get_xena_rev_id - to identify revision ID of xena.
5875 * @pdev : PCI Dev structure
5876 * Description:
5877 * Function to identify the Revision ID of xena.
5878 * Return value:
5879 * returns the revision ID of the device.
5880 */
5881
5882int get_xena_rev_id(struct pci_dev *pdev)
5883{
5884 u8 id = 0;
5885 int ret;
5886 ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id);
5887 return id;
5888}
5889
5890/**
5891 * s2io_init_pci -Initialization of PCI and PCI-X configuration registers .
5892 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893 * s2io_nic structure.
5894 * Description:
5895 * This function initializes a few of the PCI and PCI-X configuration registers
5896 * with recommended values.
5897 * Return value:
5898 * void
5899 */
5900
5901static void s2io_init_pci(nic_t * sp)
5902{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005903 u16 pci_cmd = 0, pcix_cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904
5905 /* Enable Data Parity Error Recovery in PCI-X command register. */
5906 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005907 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005909 (pcix_cmd | 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005911 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912
5913 /* Set the PErr Response bit in PCI command register. */
5914 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
5915 pci_write_config_word(sp->pdev, PCI_COMMAND,
5916 (pci_cmd | PCI_COMMAND_PARITY));
5917 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
5918
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919 /* Forcibly disabling relaxed ordering capability of the card. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005920 pcix_cmd &= 0xfffd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005922 pcix_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005923 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005924 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925}
5926
5927MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
5928MODULE_LICENSE("GPL");
John Linville6c1792f2005-10-04 07:51:45 -04005929MODULE_VERSION(DRV_VERSION);
5930
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931module_param(tx_fifo_num, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932module_param(rx_ring_num, int, 0);
Ananda Rajuda6971d2005-10-31 16:55:31 -05005933module_param(rx_ring_mode, int, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005934module_param_array(tx_fifo_len, uint, NULL, 0);
5935module_param_array(rx_ring_sz, uint, NULL, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005936module_param_array(rts_frm_len, uint, NULL, 0);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07005937module_param(use_continuous_tx_intrs, int, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938module_param(rmac_pause_time, int, 0);
5939module_param(mc_pause_threshold_q0q3, int, 0);
5940module_param(mc_pause_threshold_q4q7, int, 0);
5941module_param(shared_splits, int, 0);
5942module_param(tmac_util_period, int, 0);
5943module_param(rmac_util_period, int, 0);
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07005944module_param(bimodal, bool, 0);
Ananda Rajuda6971d2005-10-31 16:55:31 -05005945module_param(l3l4hdr_size, int , 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946#ifndef CONFIG_S2IO_NAPI
5947module_param(indicate_max_pkts, int, 0);
5948#endif
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07005949module_param(rxsync_frequency, int, 0);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04005950module_param(intr_type, int, 0);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005951module_param(lro, int, 0);
5952module_param(lro_max_pkts, int, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005953
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005955 * s2io_init_nic - Initialization of the adapter .
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956 * @pdev : structure containing the PCI related information of the device.
5957 * @pre: List of PCI devices supported by the driver listed in s2io_tbl.
5958 * Description:
5959 * The function initializes an adapter identified by the pci_dec structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005960 * All OS related initialization including memory and device structure and
5961 * initlaization of the device private variable is done. Also the swapper
5962 * control register is initialized to enable read and write into the I/O
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963 * registers of the device.
5964 * Return value:
5965 * returns 0 on success and negative on failure.
5966 */
5967
5968static int __devinit
5969s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
5970{
5971 nic_t *sp;
5972 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973 int i, j, ret;
5974 int dma_flag = FALSE;
5975 u32 mac_up, mac_down;
5976 u64 val64 = 0, tmp64 = 0;
5977 XENA_dev_config_t __iomem *bar0 = NULL;
5978 u16 subid;
5979 mac_info_t *mac_control;
5980 struct config_param *config;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005981 int mode;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04005982 u8 dev_intr_type = intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005984#ifdef CONFIG_S2IO_NAPI
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04005985 if (dev_intr_type != INTA) {
5986 DBG_PRINT(ERR_DBG, "NAPI cannot be enabled when MSI/MSI-X \
5987is enabled. Defaulting to INTA\n");
5988 dev_intr_type = INTA;
5989 }
5990 else
5991 DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005992#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993
5994 if ((ret = pci_enable_device(pdev))) {
5995 DBG_PRINT(ERR_DBG,
5996 "s2io_init_nic: pci_enable_device failed\n");
5997 return ret;
5998 }
5999
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006000 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
6002 dma_flag = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003 if (pci_set_consistent_dma_mask
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006004 (pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006005 DBG_PRINT(ERR_DBG,
6006 "Unable to obtain 64bit DMA for \
6007 consistent allocations\n");
6008 pci_disable_device(pdev);
6009 return -ENOMEM;
6010 }
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006011 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n");
6013 } else {
6014 pci_disable_device(pdev);
6015 return -ENOMEM;
6016 }
6017
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006018 if ((dev_intr_type == MSI_X) &&
6019 ((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
6020 (pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
6021 DBG_PRINT(ERR_DBG, "Xframe I does not support MSI_X. \
6022Defaulting to INTA\n");
6023 dev_intr_type = INTA;
6024 }
6025 if (dev_intr_type != MSI_X) {
6026 if (pci_request_regions(pdev, s2io_driver_name)) {
6027 DBG_PRINT(ERR_DBG, "Request Regions failed\n"),
6028 pci_disable_device(pdev);
6029 return -ENODEV;
6030 }
6031 }
6032 else {
6033 if (!(request_mem_region(pci_resource_start(pdev, 0),
6034 pci_resource_len(pdev, 0), s2io_driver_name))) {
6035 DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n");
6036 pci_disable_device(pdev);
6037 return -ENODEV;
6038 }
6039 if (!(request_mem_region(pci_resource_start(pdev, 2),
6040 pci_resource_len(pdev, 2), s2io_driver_name))) {
6041 DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n");
6042 release_mem_region(pci_resource_start(pdev, 0),
6043 pci_resource_len(pdev, 0));
6044 pci_disable_device(pdev);
6045 return -ENODEV;
6046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047 }
6048
6049 dev = alloc_etherdev(sizeof(nic_t));
6050 if (dev == NULL) {
6051 DBG_PRINT(ERR_DBG, "Device allocation failed\n");
6052 pci_disable_device(pdev);
6053 pci_release_regions(pdev);
6054 return -ENODEV;
6055 }
6056
6057 pci_set_master(pdev);
6058 pci_set_drvdata(pdev, dev);
6059 SET_MODULE_OWNER(dev);
6060 SET_NETDEV_DEV(dev, &pdev->dev);
6061
6062 /* Private member variable initialized to s2io NIC structure */
6063 sp = dev->priv;
6064 memset(sp, 0, sizeof(nic_t));
6065 sp->dev = dev;
6066 sp->pdev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067 sp->high_dma_flag = dma_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006068 sp->device_enabled_once = FALSE;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006069 if (rx_ring_mode == 1)
6070 sp->rxd_mode = RXD_MODE_1;
6071 if (rx_ring_mode == 2)
6072 sp->rxd_mode = RXD_MODE_3B;
6073 if (rx_ring_mode == 3)
6074 sp->rxd_mode = RXD_MODE_3A;
6075
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006076 sp->intr_type = dev_intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006078 if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
6079 (pdev->device == PCI_DEVICE_ID_HERC_UNI))
6080 sp->device_type = XFRAME_II_DEVICE;
6081 else
6082 sp->device_type = XFRAME_I_DEVICE;
6083
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006084 sp->lro = lro;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006085
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086 /* Initialize some PCI/PCI-X fields of the NIC. */
6087 s2io_init_pci(sp);
6088
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006089 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090 * Setting the device configuration parameters.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006091 * Most of these parameters can be specified by the user during
6092 * module insertion as they are module loadable parameters. If
6093 * these parameters are not not specified during load time, they
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094 * are initialized with default values.
6095 */
6096 mac_control = &sp->mac_control;
6097 config = &sp->config;
6098
6099 /* Tx side parameters. */
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07006100 if (tx_fifo_len[0] == 0)
6101 tx_fifo_len[0] = DEFAULT_FIFO_LEN; /* Default value. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102 config->tx_fifo_num = tx_fifo_num;
6103 for (i = 0; i < MAX_TX_FIFOS; i++) {
6104 config->tx_cfg[i].fifo_len = tx_fifo_len[i];
6105 config->tx_cfg[i].fifo_priority = i;
6106 }
6107
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006108 /* mapping the QoS priority to the configured fifos */
6109 for (i = 0; i < MAX_TX_FIFOS; i++)
6110 config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i];
6111
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112 config->tx_intr_type = TXD_INT_TYPE_UTILZ;
6113 for (i = 0; i < config->tx_fifo_num; i++) {
6114 config->tx_cfg[i].f_no_snoop =
6115 (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER);
6116 if (config->tx_cfg[i].fifo_len < 65) {
6117 config->tx_intr_type = TXD_INT_TYPE_PER_LIST;
6118 break;
6119 }
6120 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05006121 /* + 2 because one Txd for skb->data and one Txd for UFO */
6122 config->max_txds = MAX_SKB_FRAGS + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123
6124 /* Rx side parameters. */
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07006125 if (rx_ring_sz[0] == 0)
6126 rx_ring_sz[0] = SMALL_BLK_CNT; /* Default value. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127 config->rx_ring_num = rx_ring_num;
6128 for (i = 0; i < MAX_RX_RINGS; i++) {
6129 config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
Ananda Rajuda6971d2005-10-31 16:55:31 -05006130 (rxd_count[sp->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006131 config->rx_cfg[i].ring_priority = i;
6132 }
6133
6134 for (i = 0; i < rx_ring_num; i++) {
6135 config->rx_cfg[i].ring_org = RING_ORG_BUFF1;
6136 config->rx_cfg[i].f_no_snoop =
6137 (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER);
6138 }
6139
6140 /* Setting Mac Control parameters */
6141 mac_control->rmac_pause_time = rmac_pause_time;
6142 mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3;
6143 mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
6144
6145
6146 /* Initialize Ring buffer parameters. */
6147 for (i = 0; i < config->rx_ring_num; i++)
6148 atomic_set(&sp->rx_bufs_left[i], 0);
6149
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006150 /* Initialize the number of ISRs currently running */
6151 atomic_set(&sp->isr_cnt, 0);
6152
Linus Torvalds1da177e2005-04-16 15:20:36 -07006153 /* initialize the shared memory used by the NIC and the host */
6154 if (init_shared_mem(sp)) {
6155 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07006156 __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157 ret = -ENOMEM;
6158 goto mem_alloc_failed;
6159 }
6160
6161 sp->bar0 = ioremap(pci_resource_start(pdev, 0),
6162 pci_resource_len(pdev, 0));
6163 if (!sp->bar0) {
6164 DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem1\n",
6165 dev->name);
6166 ret = -ENOMEM;
6167 goto bar0_remap_failed;
6168 }
6169
6170 sp->bar1 = ioremap(pci_resource_start(pdev, 2),
6171 pci_resource_len(pdev, 2));
6172 if (!sp->bar1) {
6173 DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem2\n",
6174 dev->name);
6175 ret = -ENOMEM;
6176 goto bar1_remap_failed;
6177 }
6178
6179 dev->irq = pdev->irq;
6180 dev->base_addr = (unsigned long) sp->bar0;
6181
6182 /* Initializing the BAR1 address as the start of the FIFO pointer. */
6183 for (j = 0; j < MAX_TX_FIFOS; j++) {
6184 mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *)
6185 (sp->bar1 + (j * 0x00020000));
6186 }
6187
6188 /* Driver entry points */
6189 dev->open = &s2io_open;
6190 dev->stop = &s2io_close;
6191 dev->hard_start_xmit = &s2io_xmit;
6192 dev->get_stats = &s2io_get_stats;
6193 dev->set_multicast_list = &s2io_set_multicast;
6194 dev->do_ioctl = &s2io_ioctl;
6195 dev->change_mtu = &s2io_change_mtu;
6196 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07006197 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6198 dev->vlan_rx_register = s2io_vlan_rx_register;
6199 dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006200
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201 /*
6202 * will use eth_mac_addr() for dev->set_mac_address
6203 * mac address will be set every time dev->open() is called
6204 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006205#if defined(CONFIG_S2IO_NAPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206 dev->poll = s2io_poll;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006207 dev->weight = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208#endif
6209
6210 dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
6211 if (sp->high_dma_flag == TRUE)
6212 dev->features |= NETIF_F_HIGHDMA;
6213#ifdef NETIF_F_TSO
6214 dev->features |= NETIF_F_TSO;
6215#endif
Ananda Rajufed5ecc2005-11-14 15:25:08 -05006216 if (sp->device_type & XFRAME_II_DEVICE) {
6217 dev->features |= NETIF_F_UFO;
6218 dev->features |= NETIF_F_HW_CSUM;
6219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220
6221 dev->tx_timeout = &s2io_tx_watchdog;
6222 dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
6223 INIT_WORK(&sp->rst_timer_task,
6224 (void (*)(void *)) s2io_restart_nic, dev);
6225 INIT_WORK(&sp->set_link_task,
6226 (void (*)(void *)) s2io_set_link, sp);
6227
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07006228 pci_save_state(sp->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229
6230 /* Setting swapper control on the NIC, for proper reset operation */
6231 if (s2io_set_swapper(sp)) {
6232 DBG_PRINT(ERR_DBG, "%s:swapper settings are wrong\n",
6233 dev->name);
6234 ret = -EAGAIN;
6235 goto set_swap_failed;
6236 }
6237
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006238 /* Verify if the Herc works on the slot its placed into */
6239 if (sp->device_type & XFRAME_II_DEVICE) {
6240 mode = s2io_verify_pci_mode(sp);
6241 if (mode < 0) {
6242 DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__);
6243 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
6244 ret = -EBADSLT;
6245 goto set_swap_failed;
6246 }
6247 }
6248
6249 /* Not needed for Herc */
6250 if (sp->device_type & XFRAME_I_DEVICE) {
6251 /*
6252 * Fix for all "FFs" MAC address problems observed on
6253 * Alpha platforms
6254 */
6255 fix_mac_address(sp);
6256 s2io_reset(sp);
6257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258
6259 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260 * MAC address initialization.
6261 * For now only one mac address will be read and used.
6262 */
6263 bar0 = sp->bar0;
6264 val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
6265 RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
6266 writeq(val64, &bar0->rmac_addr_cmd_mem);
6267 wait_for_cmd_complete(sp);
6268
6269 tmp64 = readq(&bar0->rmac_addr_data0_mem);
6270 mac_down = (u32) tmp64;
6271 mac_up = (u32) (tmp64 >> 32);
6272
6273 memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
6274
6275 sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up);
6276 sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8);
6277 sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16);
6278 sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_up >> 24);
6279 sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16);
6280 sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24);
6281
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282 /* Set the factory defined MAC address initially */
6283 dev->addr_len = ETH_ALEN;
6284 memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
6285
6286 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006287 * Initialize the tasklet status and link state flags
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006288 * and the card state parameter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289 */
6290 atomic_set(&(sp->card_state), 0);
6291 sp->tasklet_status = 0;
6292 sp->link_state = 0;
6293
Linus Torvalds1da177e2005-04-16 15:20:36 -07006294 /* Initialize spinlocks */
6295 spin_lock_init(&sp->tx_lock);
6296#ifndef CONFIG_S2IO_NAPI
6297 spin_lock_init(&sp->put_lock);
6298#endif
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006299 spin_lock_init(&sp->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006301 /*
6302 * SXE-002: Configure link and activity LED to init state
6303 * on driver load.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006304 */
6305 subid = sp->pdev->subsystem_device;
6306 if ((subid & 0xFF) >= 0x07) {
6307 val64 = readq(&bar0->gpio_control);
6308 val64 |= 0x0000800000000000ULL;
6309 writeq(val64, &bar0->gpio_control);
6310 val64 = 0x0411040400000000ULL;
6311 writeq(val64, (void __iomem *) bar0 + 0x2700);
6312 val64 = readq(&bar0->gpio_control);
6313 }
6314
6315 sp->rx_csum = 1; /* Rx chksum verify enabled by default */
6316
6317 if (register_netdev(dev)) {
6318 DBG_PRINT(ERR_DBG, "Device registration failed\n");
6319 ret = -ENODEV;
6320 goto register_failed;
6321 }
6322
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006323 if (sp->device_type & XFRAME_II_DEVICE) {
6324 DBG_PRINT(ERR_DBG, "%s: Neterion Xframe II 10GbE adapter ",
6325 dev->name);
John Linville6c1792f2005-10-04 07:51:45 -04006326 DBG_PRINT(ERR_DBG, "(rev %d), Version %s",
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006327 get_xena_rev_id(sp->pdev),
6328 s2io_driver_version);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006329 switch(sp->intr_type) {
6330 case INTA:
6331 DBG_PRINT(ERR_DBG, ", Intr type INTA");
6332 break;
6333 case MSI:
6334 DBG_PRINT(ERR_DBG, ", Intr type MSI");
6335 break;
6336 case MSI_X:
6337 DBG_PRINT(ERR_DBG, ", Intr type MSI-X");
6338 break;
6339 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07006340
6341 DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006342 DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
6343 sp->def_mac_addr[0].mac_addr[0],
6344 sp->def_mac_addr[0].mac_addr[1],
6345 sp->def_mac_addr[0].mac_addr[2],
6346 sp->def_mac_addr[0].mac_addr[3],
6347 sp->def_mac_addr[0].mac_addr[4],
6348 sp->def_mac_addr[0].mac_addr[5]);
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07006349 mode = s2io_print_pci_mode(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006350 if (mode < 0) {
6351 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode ");
6352 ret = -EBADSLT;
6353 goto set_swap_failed;
6354 }
6355 } else {
6356 DBG_PRINT(ERR_DBG, "%s: Neterion Xframe I 10GbE adapter ",
6357 dev->name);
John Linville6c1792f2005-10-04 07:51:45 -04006358 DBG_PRINT(ERR_DBG, "(rev %d), Version %s",
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006359 get_xena_rev_id(sp->pdev),
6360 s2io_driver_version);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006361 switch(sp->intr_type) {
6362 case INTA:
6363 DBG_PRINT(ERR_DBG, ", Intr type INTA");
6364 break;
6365 case MSI:
6366 DBG_PRINT(ERR_DBG, ", Intr type MSI");
6367 break;
6368 case MSI_X:
6369 DBG_PRINT(ERR_DBG, ", Intr type MSI-X");
6370 break;
6371 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07006372 DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006373 DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
6374 sp->def_mac_addr[0].mac_addr[0],
6375 sp->def_mac_addr[0].mac_addr[1],
6376 sp->def_mac_addr[0].mac_addr[2],
6377 sp->def_mac_addr[0].mac_addr[3],
6378 sp->def_mac_addr[0].mac_addr[4],
6379 sp->def_mac_addr[0].mac_addr[5]);
6380 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05006381 if (sp->rxd_mode == RXD_MODE_3B)
6382 DBG_PRINT(ERR_DBG, "%s: 2-Buffer mode support has been "
6383 "enabled\n",dev->name);
6384 if (sp->rxd_mode == RXD_MODE_3A)
6385 DBG_PRINT(ERR_DBG, "%s: 3-Buffer mode support has been "
6386 "enabled\n",dev->name);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006387
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006388 if (sp->lro)
6389 DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
6390 dev->name);
6391
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006392 /* Initialize device name */
6393 strcpy(sp->name, dev->name);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006394 if (sp->device_type & XFRAME_II_DEVICE)
6395 strcat(sp->name, ": Neterion Xframe II 10GbE adapter");
6396 else
6397 strcat(sp->name, ": Neterion Xframe I 10GbE adapter");
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006398
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07006399 /* Initialize bimodal Interrupts */
6400 sp->config.bimodal = bimodal;
6401 if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) {
6402 sp->config.bimodal = 0;
6403 DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n",
6404 dev->name);
6405 }
6406
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006407 /*
6408 * Make Link state as off at this point, when the Link change
6409 * interrupt comes the state will be automatically changed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07006410 * the right state.
6411 */
6412 netif_carrier_off(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413
6414 return 0;
6415
6416 register_failed:
6417 set_swap_failed:
6418 iounmap(sp->bar1);
6419 bar1_remap_failed:
6420 iounmap(sp->bar0);
6421 bar0_remap_failed:
6422 mem_alloc_failed:
6423 free_shared_mem(sp);
6424 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006425 if (dev_intr_type != MSI_X)
6426 pci_release_regions(pdev);
6427 else {
6428 release_mem_region(pci_resource_start(pdev, 0),
6429 pci_resource_len(pdev, 0));
6430 release_mem_region(pci_resource_start(pdev, 2),
6431 pci_resource_len(pdev, 2));
6432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006433 pci_set_drvdata(pdev, NULL);
6434 free_netdev(dev);
6435
6436 return ret;
6437}
6438
6439/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006440 * s2io_rem_nic - Free the PCI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07006441 * @pdev: structure containing the PCI related information of the device.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006442 * Description: This function is called by the Pci subsystem to release a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006443 * PCI device and free up all resource held up by the device. This could
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006444 * be in response to a Hot plug event or when the driver is to be removed
Linus Torvalds1da177e2005-04-16 15:20:36 -07006445 * from memory.
6446 */
6447
6448static void __devexit s2io_rem_nic(struct pci_dev *pdev)
6449{
6450 struct net_device *dev =
6451 (struct net_device *) pci_get_drvdata(pdev);
6452 nic_t *sp;
6453
6454 if (dev == NULL) {
6455 DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
6456 return;
6457 }
6458
6459 sp = dev->priv;
6460 unregister_netdev(dev);
6461
6462 free_shared_mem(sp);
6463 iounmap(sp->bar0);
6464 iounmap(sp->bar1);
6465 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006466 if (sp->intr_type != MSI_X)
6467 pci_release_regions(pdev);
6468 else {
6469 release_mem_region(pci_resource_start(pdev, 0),
6470 pci_resource_len(pdev, 0));
6471 release_mem_region(pci_resource_start(pdev, 2),
6472 pci_resource_len(pdev, 2));
6473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006474 pci_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006475 free_netdev(dev);
6476}
6477
6478/**
6479 * s2io_starter - Entry point for the driver
6480 * Description: This function is the entry point for the driver. It verifies
6481 * the module loadable parameters and initializes PCI configuration space.
6482 */
6483
6484int __init s2io_starter(void)
6485{
6486 return pci_module_init(&s2io_driver);
6487}
6488
6489/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006490 * s2io_closer - Cleanup routine for the driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491 * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
6492 */
6493
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006494void s2io_closer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006495{
6496 pci_unregister_driver(&s2io_driver);
6497 DBG_PRINT(INIT_DBG, "cleanup done\n");
6498}
6499
6500module_init(s2io_starter);
6501module_exit(s2io_closer);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006502
6503static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
6504 struct tcphdr **tcp, RxD_t *rxdp)
6505{
6506 int ip_off;
6507 u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
6508
6509 if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) {
6510 DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n",
6511 __FUNCTION__);
6512 return -1;
6513 }
6514
6515 /* TODO:
6516 * By default the VLAN field in the MAC is stripped by the card, if this
6517 * feature is turned off in rx_pa_cfg register, then the ip_off field
6518 * has to be shifted by a further 2 bytes
6519 */
6520 switch (l2_type) {
6521 case 0: /* DIX type */
6522 case 4: /* DIX type with VLAN */
6523 ip_off = HEADER_ETHERNET_II_802_3_SIZE;
6524 break;
6525 /* LLC, SNAP etc are considered non-mergeable */
6526 default:
6527 return -1;
6528 }
6529
6530 *ip = (struct iphdr *)((u8 *)buffer + ip_off);
6531 ip_len = (u8)((*ip)->ihl);
6532 ip_len <<= 2;
6533 *tcp = (struct tcphdr *)((unsigned long)*ip + ip_len);
6534
6535 return 0;
6536}
6537
6538static int check_for_socket_match(lro_t *lro, struct iphdr *ip,
6539 struct tcphdr *tcp)
6540{
6541 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
6542 if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) ||
6543 (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest))
6544 return -1;
6545 return 0;
6546}
6547
6548static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
6549{
6550 return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
6551}
6552
6553static void initiate_new_session(lro_t *lro, u8 *l2h,
6554 struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
6555{
6556 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
6557 lro->l2h = l2h;
6558 lro->iph = ip;
6559 lro->tcph = tcp;
6560 lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq);
6561 lro->tcp_ack = ntohl(tcp->ack_seq);
6562 lro->sg_num = 1;
6563 lro->total_len = ntohs(ip->tot_len);
6564 lro->frags_len = 0;
6565 /*
6566 * check if we saw TCP timestamp. Other consistency checks have
6567 * already been done.
6568 */
6569 if (tcp->doff == 8) {
6570 u32 *ptr;
6571 ptr = (u32 *)(tcp+1);
6572 lro->saw_ts = 1;
6573 lro->cur_tsval = *(ptr+1);
6574 lro->cur_tsecr = *(ptr+2);
6575 }
6576 lro->in_use = 1;
6577}
6578
6579static void update_L3L4_header(nic_t *sp, lro_t *lro)
6580{
6581 struct iphdr *ip = lro->iph;
6582 struct tcphdr *tcp = lro->tcph;
6583 u16 nchk;
6584 StatInfo_t *statinfo = sp->mac_control.stats_info;
6585 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
6586
6587 /* Update L3 header */
6588 ip->tot_len = htons(lro->total_len);
6589 ip->check = 0;
6590 nchk = ip_fast_csum((u8 *)lro->iph, ip->ihl);
6591 ip->check = nchk;
6592
6593 /* Update L4 header */
6594 tcp->ack_seq = lro->tcp_ack;
6595 tcp->window = lro->window;
6596
6597 /* Update tsecr field if this session has timestamps enabled */
6598 if (lro->saw_ts) {
6599 u32 *ptr = (u32 *)(tcp + 1);
6600 *(ptr+2) = lro->cur_tsecr;
6601 }
6602
6603 /* Update counters required for calculation of
6604 * average no. of packets aggregated.
6605 */
6606 statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num;
6607 statinfo->sw_stat.num_aggregations++;
6608}
6609
6610static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
6611 struct tcphdr *tcp, u32 l4_pyld)
6612{
6613 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
6614 lro->total_len += l4_pyld;
6615 lro->frags_len += l4_pyld;
6616 lro->tcp_next_seq += l4_pyld;
6617 lro->sg_num++;
6618
6619 /* Update ack seq no. and window ad(from this pkt) in LRO object */
6620 lro->tcp_ack = tcp->ack_seq;
6621 lro->window = tcp->window;
6622
6623 if (lro->saw_ts) {
6624 u32 *ptr;
6625 /* Update tsecr and tsval from this packet */
6626 ptr = (u32 *) (tcp + 1);
6627 lro->cur_tsval = *(ptr + 1);
6628 lro->cur_tsecr = *(ptr + 2);
6629 }
6630}
6631
6632static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
6633 struct tcphdr *tcp, u32 tcp_pyld_len)
6634{
6635 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
6636 u8 *ptr;
6637
6638 if (!tcp_pyld_len) {
6639 /* Runt frame or a pure ack */
6640 return -1;
6641 }
6642
6643 if (ip->ihl != 5) /* IP has options */
6644 return -1;
6645
6646 if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin ||
6647 !tcp->ack) {
6648 /*
6649 * Currently recognize only the ack control word and
6650 * any other control field being set would result in
6651 * flushing the LRO session
6652 */
6653 return -1;
6654 }
6655
6656 /*
6657 * Allow only one TCP timestamp option. Don't aggregate if
6658 * any other options are detected.
6659 */
6660 if (tcp->doff != 5 && tcp->doff != 8)
6661 return -1;
6662
6663 if (tcp->doff == 8) {
6664 ptr = (u8 *)(tcp + 1);
6665 while (*ptr == TCPOPT_NOP)
6666 ptr++;
6667 if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP)
6668 return -1;
6669
6670 /* Ensure timestamp value increases monotonically */
6671 if (l_lro)
6672 if (l_lro->cur_tsval > *((u32 *)(ptr+2)))
6673 return -1;
6674
6675 /* timestamp echo reply should be non-zero */
6676 if (*((u32 *)(ptr+6)) == 0)
6677 return -1;
6678 }
6679
6680 return 0;
6681}
6682
6683static int
6684s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
6685 RxD_t *rxdp, nic_t *sp)
6686{
6687 struct iphdr *ip;
6688 struct tcphdr *tcph;
6689 int ret = 0, i;
6690
6691 if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp,
6692 rxdp))) {
6693 DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n",
6694 ip->saddr, ip->daddr);
6695 } else {
6696 return ret;
6697 }
6698
6699 tcph = (struct tcphdr *)*tcp;
6700 *tcp_len = get_l4_pyld_length(ip, tcph);
6701 for (i=0; i<MAX_LRO_SESSIONS; i++) {
6702 lro_t *l_lro = &sp->lro0_n[i];
6703 if (l_lro->in_use) {
6704 if (check_for_socket_match(l_lro, ip, tcph))
6705 continue;
6706 /* Sock pair matched */
6707 *lro = l_lro;
6708
6709 if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) {
6710 DBG_PRINT(INFO_DBG, "%s:Out of order. expected "
6711 "0x%x, actual 0x%x\n", __FUNCTION__,
6712 (*lro)->tcp_next_seq,
6713 ntohl(tcph->seq));
6714
6715 sp->mac_control.stats_info->
6716 sw_stat.outof_sequence_pkts++;
6717 ret = 2;
6718 break;
6719 }
6720
6721 if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len))
6722 ret = 1; /* Aggregate */
6723 else
6724 ret = 2; /* Flush both */
6725 break;
6726 }
6727 }
6728
6729 if (ret == 0) {
6730 /* Before searching for available LRO objects,
6731 * check if the pkt is L3/L4 aggregatable. If not
6732 * don't create new LRO session. Just send this
6733 * packet up.
6734 */
6735 if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) {
6736 return 5;
6737 }
6738
6739 for (i=0; i<MAX_LRO_SESSIONS; i++) {
6740 lro_t *l_lro = &sp->lro0_n[i];
6741 if (!(l_lro->in_use)) {
6742 *lro = l_lro;
6743 ret = 3; /* Begin anew */
6744 break;
6745 }
6746 }
6747 }
6748
6749 if (ret == 0) { /* sessions exceeded */
6750 DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n",
6751 __FUNCTION__);
6752 *lro = NULL;
6753 return ret;
6754 }
6755
6756 switch (ret) {
6757 case 3:
6758 initiate_new_session(*lro, buffer, ip, tcph, *tcp_len);
6759 break;
6760 case 2:
6761 update_L3L4_header(sp, *lro);
6762 break;
6763 case 1:
6764 aggregate_new_rx(*lro, ip, tcph, *tcp_len);
6765 if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) {
6766 update_L3L4_header(sp, *lro);
6767 ret = 4; /* Flush the LRO */
6768 }
6769 break;
6770 default:
6771 DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n",
6772 __FUNCTION__);
6773 break;
6774 }
6775
6776 return ret;
6777}
6778
6779static void clear_lro_session(lro_t *lro)
6780{
6781 static u16 lro_struct_size = sizeof(lro_t);
6782
6783 memset(lro, 0, lro_struct_size);
6784}
6785
6786static void queue_rx_frame(struct sk_buff *skb)
6787{
6788 struct net_device *dev = skb->dev;
6789
6790 skb->protocol = eth_type_trans(skb, dev);
6791#ifdef CONFIG_S2IO_NAPI
6792 netif_receive_skb(skb);
6793#else
6794 netif_rx(skb);
6795#endif
6796}
6797
6798static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
6799 u32 tcp_len)
6800{
6801 struct sk_buff *tmp, *first = lro->parent;
6802
6803 first->len += tcp_len;
6804 first->data_len = lro->frags_len;
6805 skb_pull(skb, (skb->len - tcp_len));
6806 if ((tmp = skb_shinfo(first)->frag_list)) {
6807 while (tmp->next)
6808 tmp = tmp->next;
6809 tmp->next = skb;
6810 }
6811 else
6812 skb_shinfo(first)->frag_list = skb;
6813 sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
6814 return;
6815}