blob: 600d3ff347fc83229cf7cbbb49fe4aa8e3810491 [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.
Ananda Raju9dc737a2006-04-21 19:05:41 -040029 *
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070030 * rx_ring_num : This can be used to program the number of receive rings used
31 * in the driver.
Ananda Raju9dc737a2006-04-21 19:05:41 -040032 * rx_ring_sz: This defines the number of receive blocks each ring can have.
33 * This is also an array of size 8.
Ananda Rajuda6971d2005-10-31 16:55:31 -050034 * rx_ring_mode: This defines the operation mode of all 8 rings. The valid
35 * values are 1, 2 and 3.
Linus Torvalds1da177e2005-04-16 15:20:36 -070036 * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070037 * tx_fifo_len: This too is an array of 8. Each element defines the number of
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 * Tx descriptors that can be associated with each corresponding FIFO.
Ananda Raju9dc737a2006-04-21 19:05:41 -040039 * intr_type: This defines the type of interrupt. The values can be 0(INTA),
40 * 1(MSI), 2(MSI_X). Default value is '0(INTA)'
41 * lro: Specifies whether to enable Large Receive Offload (LRO) or not.
42 * Possible values '1' for enable '0' for disable. Default is '0'
43 * lro_max_pkts: This parameter defines maximum number of packets can be
44 * aggregated as a single large packet
Sivakumar Subramani926930b2007-02-24 01:59:39 -050045 * napi: This parameter used to enable/disable NAPI (polling Rx)
46 * Possible values '1' for enable and '0' for disable. Default is '1'
47 * ufo: This parameter used to enable/disable UDP Fragmentation Offload(UFO)
48 * Possible values '1' for enable and '0' for disable. Default is '0'
49 * vlan_tag_strip: This can be used to enable or disable vlan stripping.
50 * Possible values '1' for enable , '0' for disable.
51 * Default is '2' - which means disable in promisc mode
52 * and enable in non-promiscuous mode.
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 ************************************************************************/
54
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#include <linux/module.h>
56#include <linux/types.h>
57#include <linux/errno.h>
58#include <linux/ioport.h>
59#include <linux/pci.h>
Domen Puncer1e7f0bd2005-06-26 18:22:14 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <linux/kernel.h>
62#include <linux/netdevice.h>
63#include <linux/etherdevice.h>
64#include <linux/skbuff.h>
65#include <linux/init.h>
66#include <linux/delay.h>
67#include <linux/stddef.h>
68#include <linux/ioctl.h>
69#include <linux/timex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#include <linux/ethtool.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#include <linux/workqueue.h>
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -070072#include <linux/if_vlan.h>
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -050073#include <linux/ip.h>
74#include <linux/tcp.h>
75#include <net/tcp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
Linus Torvalds1da177e2005-04-16 15:20:36 -070077#include <asm/system.h>
78#include <asm/uaccess.h>
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070079#include <asm/io.h>
Andrew Mortonfe931392006-02-03 01:45:12 -080080#include <asm/div64.h>
Andrew Morton330ce0d2006-08-14 23:00:14 -070081#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83/* local include */
84#include "s2io.h"
85#include "s2io-regs.h"
86
Sivakumar Subramanid8d70ca2007-02-24 02:04:24 -050087#define DRV_VERSION "2.0.17.1"
John Linville6c1792f2005-10-04 07:51:45 -040088
Linus Torvalds1da177e2005-04-16 15:20:36 -070089/* S2io Driver name & version. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070090static char s2io_driver_name[] = "Neterion";
John Linville6c1792f2005-10-04 07:51:45 -040091static char s2io_driver_version[] = DRV_VERSION;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Adrian Bunk26df54b2006-01-14 03:09:40 +010093static int rxd_size[4] = {32,48,48,64};
94static int rxd_count[4] = {127,85,85,63};
Ananda Rajuda6971d2005-10-31 16:55:31 -050095
Ralf Baechle1ee6dd72007-01-31 14:09:29 -050096static inline int RXD_IS_UP2DT(struct RxD_t *rxdp)
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -070097{
98 int ret;
99
100 ret = ((!(rxdp->Control_1 & RXD_OWN_XENA)) &&
101 (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK));
102
103 return ret;
104}
105
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700106/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 * Cards with following subsystem_id have a link state indication
108 * problem, 600B, 600C, 600D, 640B, 640C and 640D.
109 * macro below identifies these cards given the subsystem_id.
110 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700111#define CARDS_WITH_FAULTY_LINK_INDICATORS(dev_type, subid) \
112 (dev_type == XFRAME_I_DEVICE) ? \
113 ((((subid >= 0x600B) && (subid <= 0x600D)) || \
114 ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0) : 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116#define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \
117 ADAPTER_STATUS_RMAC_LOCAL_FAULT)))
118#define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status))
119#define PANIC 1
120#define LOW 2
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500121static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500123 struct mac_info *mac_control;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700124
125 mac_control = &sp->mac_control;
Ananda Raju863c11a2006-04-21 19:03:13 -0400126 if (rxb_size <= rxd_count[sp->rxd_mode])
127 return PANIC;
128 else if ((mac_control->rings[ring].pkt_cnt - rxb_size) > 16)
129 return LOW;
130 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
133/* Ethtool related variables and Macros. */
134static char s2io_gstrings[][ETH_GSTRING_LEN] = {
135 "Register test\t(offline)",
136 "Eeprom test\t(offline)",
137 "Link test\t(online)",
138 "RLDRAM test\t(offline)",
139 "BIST Test\t(offline)"
140};
141
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -0500142static char ethtool_xena_stats_keys[][ETH_GSTRING_LEN] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 {"tmac_frms"},
144 {"tmac_data_octets"},
145 {"tmac_drop_frms"},
146 {"tmac_mcst_frms"},
147 {"tmac_bcst_frms"},
148 {"tmac_pause_ctrl_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400149 {"tmac_ttl_octets"},
150 {"tmac_ucst_frms"},
151 {"tmac_nucst_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 {"tmac_any_err_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400153 {"tmac_ttl_less_fb_octets"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 {"tmac_vld_ip_octets"},
155 {"tmac_vld_ip"},
156 {"tmac_drop_ip"},
157 {"tmac_icmp"},
158 {"tmac_rst_tcp"},
159 {"tmac_tcp"},
160 {"tmac_udp"},
161 {"rmac_vld_frms"},
162 {"rmac_data_octets"},
163 {"rmac_fcs_err_frms"},
164 {"rmac_drop_frms"},
165 {"rmac_vld_mcst_frms"},
166 {"rmac_vld_bcst_frms"},
167 {"rmac_in_rng_len_err_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400168 {"rmac_out_rng_len_err_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 {"rmac_long_frms"},
170 {"rmac_pause_ctrl_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400171 {"rmac_unsup_ctrl_frms"},
172 {"rmac_ttl_octets"},
173 {"rmac_accepted_ucst_frms"},
174 {"rmac_accepted_nucst_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 {"rmac_discarded_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400176 {"rmac_drop_events"},
177 {"rmac_ttl_less_fb_octets"},
178 {"rmac_ttl_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 {"rmac_usized_frms"},
180 {"rmac_osized_frms"},
181 {"rmac_frag_frms"},
182 {"rmac_jabber_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400183 {"rmac_ttl_64_frms"},
184 {"rmac_ttl_65_127_frms"},
185 {"rmac_ttl_128_255_frms"},
186 {"rmac_ttl_256_511_frms"},
187 {"rmac_ttl_512_1023_frms"},
188 {"rmac_ttl_1024_1518_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 {"rmac_ip"},
190 {"rmac_ip_octets"},
191 {"rmac_hdr_err_ip"},
192 {"rmac_drop_ip"},
193 {"rmac_icmp"},
194 {"rmac_tcp"},
195 {"rmac_udp"},
196 {"rmac_err_drp_udp"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400197 {"rmac_xgmii_err_sym"},
198 {"rmac_frms_q0"},
199 {"rmac_frms_q1"},
200 {"rmac_frms_q2"},
201 {"rmac_frms_q3"},
202 {"rmac_frms_q4"},
203 {"rmac_frms_q5"},
204 {"rmac_frms_q6"},
205 {"rmac_frms_q7"},
206 {"rmac_full_q0"},
207 {"rmac_full_q1"},
208 {"rmac_full_q2"},
209 {"rmac_full_q3"},
210 {"rmac_full_q4"},
211 {"rmac_full_q5"},
212 {"rmac_full_q6"},
213 {"rmac_full_q7"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 {"rmac_pause_cnt"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400215 {"rmac_xgmii_data_err_cnt"},
216 {"rmac_xgmii_ctrl_err_cnt"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 {"rmac_accepted_ip"},
218 {"rmac_err_tcp"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400219 {"rd_req_cnt"},
220 {"new_rd_req_cnt"},
221 {"new_rd_req_rtry_cnt"},
222 {"rd_rtry_cnt"},
223 {"wr_rtry_rd_ack_cnt"},
224 {"wr_req_cnt"},
225 {"new_wr_req_cnt"},
226 {"new_wr_req_rtry_cnt"},
227 {"wr_rtry_cnt"},
228 {"wr_disc_cnt"},
229 {"rd_rtry_wr_ack_cnt"},
230 {"txp_wr_cnt"},
231 {"txd_rd_cnt"},
232 {"txd_wr_cnt"},
233 {"rxd_rd_cnt"},
234 {"rxd_wr_cnt"},
235 {"txf_rd_cnt"},
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -0500236 {"rxf_wr_cnt"}
237};
238
239static char ethtool_enhanced_stats_keys[][ETH_GSTRING_LEN] = {
Ananda Rajubd1034f2006-04-21 19:20:22 -0400240 {"rmac_ttl_1519_4095_frms"},
241 {"rmac_ttl_4096_8191_frms"},
242 {"rmac_ttl_8192_max_frms"},
243 {"rmac_ttl_gt_max_frms"},
244 {"rmac_osized_alt_frms"},
245 {"rmac_jabber_alt_frms"},
246 {"rmac_gt_max_alt_frms"},
247 {"rmac_vlan_frms"},
248 {"rmac_len_discard"},
249 {"rmac_fcs_discard"},
250 {"rmac_pf_discard"},
251 {"rmac_da_discard"},
252 {"rmac_red_discard"},
253 {"rmac_rts_discard"},
254 {"rmac_ingm_full_discard"},
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -0500255 {"link_fault_cnt"}
256};
257
258static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -0700259 {"\n DRIVER STATISTICS"},
260 {"single_bit_ecc_errs"},
261 {"double_bit_ecc_errs"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400262 {"parity_err_cnt"},
263 {"serious_err_cnt"},
264 {"soft_reset_cnt"},
265 {"fifo_full_cnt"},
266 {"ring_full_cnt"},
267 ("alarm_transceiver_temp_high"),
268 ("alarm_transceiver_temp_low"),
269 ("alarm_laser_bias_current_high"),
270 ("alarm_laser_bias_current_low"),
271 ("alarm_laser_output_power_high"),
272 ("alarm_laser_output_power_low"),
273 ("warn_transceiver_temp_high"),
274 ("warn_transceiver_temp_low"),
275 ("warn_laser_bias_current_high"),
276 ("warn_laser_bias_current_low"),
277 ("warn_laser_output_power_high"),
278 ("warn_laser_output_power_low"),
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -0500279 ("lro_aggregated_pkts"),
280 ("lro_flush_both_count"),
281 ("lro_out_of_sequence_pkts"),
282 ("lro_flush_due_to_max_pkts"),
283 ("lro_avg_aggr_pkts"),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284};
285
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -0500286#define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN
287#define S2IO_ENHANCED_STAT_LEN sizeof(ethtool_enhanced_stats_keys)/ \
288 ETH_GSTRING_LEN
289#define S2IO_DRIVER_STAT_LEN sizeof(ethtool_driver_stats_keys)/ ETH_GSTRING_LEN
290
291#define XFRAME_I_STAT_LEN (S2IO_XENA_STAT_LEN + S2IO_DRIVER_STAT_LEN )
292#define XFRAME_II_STAT_LEN (XFRAME_I_STAT_LEN + S2IO_ENHANCED_STAT_LEN )
293
294#define XFRAME_I_STAT_STRINGS_LEN ( XFRAME_I_STAT_LEN * ETH_GSTRING_LEN )
295#define XFRAME_II_STAT_STRINGS_LEN ( XFRAME_II_STAT_LEN * ETH_GSTRING_LEN )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297#define S2IO_TEST_LEN sizeof(s2io_gstrings) / ETH_GSTRING_LEN
298#define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN
299
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -0700300#define S2IO_TIMER_CONF(timer, handle, arg, exp) \
301 init_timer(&timer); \
302 timer.function = handle; \
303 timer.data = (unsigned long) arg; \
304 mod_timer(&timer, (jiffies + exp)) \
305
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -0700306/* Add the vlan */
307static void s2io_vlan_rx_register(struct net_device *dev,
308 struct vlan_group *grp)
309{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500310 struct s2io_nic *nic = dev->priv;
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -0700311 unsigned long flags;
312
313 spin_lock_irqsave(&nic->tx_lock, flags);
314 nic->vlgrp = grp;
315 spin_unlock_irqrestore(&nic->tx_lock, flags);
316}
317
Sivakumar Subramani926930b2007-02-24 01:59:39 -0500318/* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */
319int vlan_strip_flag;
320
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -0700321/* Unregister the vlan */
322static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
323{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500324 struct s2io_nic *nic = dev->priv;
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -0700325 unsigned long flags;
326
327 spin_lock_irqsave(&nic->tx_lock, flags);
Dan Aloni5c15bde2007-03-02 20:44:51 -0800328 vlan_group_set_device(nic->vlgrp, vid, NULL);
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -0700329 spin_unlock_irqrestore(&nic->tx_lock, flags);
330}
331
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700332/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 * Constants to be programmed into the Xena's registers, to configure
334 * the XAUI.
335 */
336
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337#define END_SIGN 0x0
Arjan van de Venf71e1302006-03-03 21:33:57 -0500338static const u64 herc_act_dtx_cfg[] = {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700339 /* Set address */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700340 0x8000051536750000ULL, 0x80000515367500E0ULL,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700341 /* Write data */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700342 0x8000051536750004ULL, 0x80000515367500E4ULL,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700343 /* Set address */
344 0x80010515003F0000ULL, 0x80010515003F00E0ULL,
345 /* Write data */
346 0x80010515003F0004ULL, 0x80010515003F00E4ULL,
347 /* Set address */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700348 0x801205150D440000ULL, 0x801205150D4400E0ULL,
349 /* Write data */
350 0x801205150D440004ULL, 0x801205150D4400E4ULL,
351 /* Set address */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700352 0x80020515F2100000ULL, 0x80020515F21000E0ULL,
353 /* Write data */
354 0x80020515F2100004ULL, 0x80020515F21000E4ULL,
355 /* Done */
356 END_SIGN
357};
358
Arjan van de Venf71e1302006-03-03 21:33:57 -0500359static const u64 xena_dtx_cfg[] = {
Ananda Rajuc92ca042006-04-21 19:18:03 -0400360 /* Set address */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 0x8000051500000000ULL, 0x80000515000000E0ULL,
Ananda Rajuc92ca042006-04-21 19:18:03 -0400362 /* Write data */
363 0x80000515D9350004ULL, 0x80000515D93500E4ULL,
364 /* Set address */
365 0x8001051500000000ULL, 0x80010515000000E0ULL,
366 /* Write data */
367 0x80010515001E0004ULL, 0x80010515001E00E4ULL,
368 /* Set address */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 0x8002051500000000ULL, 0x80020515000000E0ULL,
Ananda Rajuc92ca042006-04-21 19:18:03 -0400370 /* Write data */
371 0x80020515F2100004ULL, 0x80020515F21000E4ULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 END_SIGN
373};
374
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700375/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 * Constants for Fixing the MacAddress problem seen mostly on
377 * Alpha machines.
378 */
Arjan van de Venf71e1302006-03-03 21:33:57 -0500379static const u64 fix_mac[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 0x0060000000000000ULL, 0x0060600000000000ULL,
381 0x0040600000000000ULL, 0x0000600000000000ULL,
382 0x0020600000000000ULL, 0x0060600000000000ULL,
383 0x0020600000000000ULL, 0x0060600000000000ULL,
384 0x0020600000000000ULL, 0x0060600000000000ULL,
385 0x0020600000000000ULL, 0x0060600000000000ULL,
386 0x0020600000000000ULL, 0x0060600000000000ULL,
387 0x0020600000000000ULL, 0x0060600000000000ULL,
388 0x0020600000000000ULL, 0x0060600000000000ULL,
389 0x0020600000000000ULL, 0x0060600000000000ULL,
390 0x0020600000000000ULL, 0x0060600000000000ULL,
391 0x0020600000000000ULL, 0x0060600000000000ULL,
392 0x0020600000000000ULL, 0x0000600000000000ULL,
393 0x0040600000000000ULL, 0x0060600000000000ULL,
394 END_SIGN
395};
396
Ananda Rajub41477f2006-07-24 19:52:49 -0400397MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
398MODULE_LICENSE("GPL");
399MODULE_VERSION(DRV_VERSION);
400
401
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402/* Module Loadable parameters. */
Ananda Rajub41477f2006-07-24 19:52:49 -0400403S2IO_PARM_INT(tx_fifo_num, 1);
404S2IO_PARM_INT(rx_ring_num, 1);
405
406
407S2IO_PARM_INT(rx_ring_mode, 1);
408S2IO_PARM_INT(use_continuous_tx_intrs, 1);
409S2IO_PARM_INT(rmac_pause_time, 0x100);
410S2IO_PARM_INT(mc_pause_threshold_q0q3, 187);
411S2IO_PARM_INT(mc_pause_threshold_q4q7, 187);
412S2IO_PARM_INT(shared_splits, 0);
413S2IO_PARM_INT(tmac_util_period, 5);
414S2IO_PARM_INT(rmac_util_period, 5);
415S2IO_PARM_INT(bimodal, 0);
416S2IO_PARM_INT(l3l4hdr_size, 128);
417/* Frequency of Rx desc syncs expressed as power of 2 */
418S2IO_PARM_INT(rxsync_frequency, 3);
419/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */
420S2IO_PARM_INT(intr_type, 0);
421/* Large receive offload feature */
422S2IO_PARM_INT(lro, 0);
423/* Max pkts to be aggregated by LRO at one time. If not specified,
424 * aggregation happens until we hit max IP pkt size(64K)
425 */
426S2IO_PARM_INT(lro_max_pkts, 0xFFFF);
Ananda Rajub41477f2006-07-24 19:52:49 -0400427S2IO_PARM_INT(indicate_max_pkts, 0);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -0500428
429S2IO_PARM_INT(napi, 1);
430S2IO_PARM_INT(ufo, 0);
Sivakumar Subramani926930b2007-02-24 01:59:39 -0500431S2IO_PARM_INT(vlan_tag_strip, NO_STRIP_IN_PROMISC);
Ananda Rajub41477f2006-07-24 19:52:49 -0400432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
Ananda Raju9dc737a2006-04-21 19:05:41 -0400434 {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435static unsigned int rx_ring_sz[MAX_RX_RINGS] =
Ananda Raju9dc737a2006-04-21 19:05:41 -0400436 {[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT};
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700437static unsigned int rts_frm_len[MAX_RX_RINGS] =
438 {[0 ...(MAX_RX_RINGS - 1)] = 0 };
Ananda Rajub41477f2006-07-24 19:52:49 -0400439
440module_param_array(tx_fifo_len, uint, NULL, 0);
441module_param_array(rx_ring_sz, uint, NULL, 0);
442module_param_array(rts_frm_len, uint, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700444/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 * S2IO device table.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700446 * This table lists all the devices that this driver supports.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 */
448static struct pci_device_id s2io_tbl[] __devinitdata = {
449 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN,
450 PCI_ANY_ID, PCI_ANY_ID},
451 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI,
452 PCI_ANY_ID, PCI_ANY_ID},
453 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700454 PCI_ANY_ID, PCI_ANY_ID},
455 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI,
456 PCI_ANY_ID, PCI_ANY_ID},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 {0,}
458};
459
460MODULE_DEVICE_TABLE(pci, s2io_tbl);
461
462static struct pci_driver s2io_driver = {
463 .name = "S2IO",
464 .id_table = s2io_tbl,
465 .probe = s2io_init_nic,
466 .remove = __devexit_p(s2io_rem_nic),
467};
468
469/* A simplifier macro used both by init and free shared_mem Fns(). */
470#define TXD_MEM_PAGE_CNT(len, per_each) ((len+per_each - 1) / per_each)
471
472/**
473 * init_shared_mem - Allocation and Initialization of Memory
474 * @nic: Device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700475 * Description: The function allocates all the memory areas shared
476 * between the NIC and the driver. This includes Tx descriptors,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 * Rx descriptors and the statistics block.
478 */
479
480static int init_shared_mem(struct s2io_nic *nic)
481{
482 u32 size;
483 void *tmp_v_addr, *tmp_v_addr_next;
484 dma_addr_t tmp_p_addr, tmp_p_addr_next;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500485 struct RxD_block *pre_rxd_blk = NULL;
Sivakumar Subramani372cc592007-01-31 13:32:57 -0500486 int i, j, blk_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 int lst_size, lst_per_page;
488 struct net_device *dev = nic->dev;
viro@zenIV.linux.org.uk8ae418c2005-09-02 20:15:29 +0100489 unsigned long tmp;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500490 struct buffAdd *ba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500492 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 struct config_param *config;
494
495 mac_control = &nic->mac_control;
496 config = &nic->config;
497
498
499 /* Allocation and initialization of TXDLs in FIOFs */
500 size = 0;
501 for (i = 0; i < config->tx_fifo_num; i++) {
502 size += config->tx_cfg[i].fifo_len;
503 }
504 if (size > MAX_AVAILABLE_TXDS) {
Ananda Rajub41477f2006-07-24 19:52:49 -0400505 DBG_PRINT(ERR_DBG, "s2io: Requested TxDs too high, ");
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -0700506 DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size);
Ananda Rajub41477f2006-07-24 19:52:49 -0400507 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 }
509
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500510 lst_size = (sizeof(struct TxD) * config->max_txds);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 lst_per_page = PAGE_SIZE / lst_size;
512
513 for (i = 0; i < config->tx_fifo_num; i++) {
514 int fifo_len = config->tx_cfg[i].fifo_len;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500515 int list_holder_size = fifo_len * sizeof(struct list_info_hold);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700516 mac_control->fifos[i].list_info = kmalloc(list_holder_size,
517 GFP_KERNEL);
518 if (!mac_control->fifos[i].list_info) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 DBG_PRINT(ERR_DBG,
520 "Malloc failed for list_info\n");
521 return -ENOMEM;
522 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700523 memset(mac_control->fifos[i].list_info, 0, list_holder_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 }
525 for (i = 0; i < config->tx_fifo_num; i++) {
526 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
527 lst_per_page);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700528 mac_control->fifos[i].tx_curr_put_info.offset = 0;
529 mac_control->fifos[i].tx_curr_put_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700531 mac_control->fifos[i].tx_curr_get_info.offset = 0;
532 mac_control->fifos[i].tx_curr_get_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700534 mac_control->fifos[i].fifo_no = i;
535 mac_control->fifos[i].nic = nic;
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500536 mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 2;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 for (j = 0; j < page_num; j++) {
539 int k = 0;
540 dma_addr_t tmp_p;
541 void *tmp_v;
542 tmp_v = pci_alloc_consistent(nic->pdev,
543 PAGE_SIZE, &tmp_p);
544 if (!tmp_v) {
545 DBG_PRINT(ERR_DBG,
546 "pci_alloc_consistent ");
547 DBG_PRINT(ERR_DBG, "failed for TxDL\n");
548 return -ENOMEM;
549 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700550 /* If we got a zero DMA address(can happen on
551 * certain platforms like PPC), reallocate.
552 * Store virtual address of page we don't want,
553 * to be freed later.
554 */
555 if (!tmp_p) {
556 mac_control->zerodma_virt_addr = tmp_v;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400557 DBG_PRINT(INIT_DBG,
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700558 "%s: Zero DMA address for TxDL. ", dev->name);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400559 DBG_PRINT(INIT_DBG,
Andrew Morton6b4d6172005-09-12 23:21:55 -0700560 "Virtual address %p\n", tmp_v);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700561 tmp_v = pci_alloc_consistent(nic->pdev,
562 PAGE_SIZE, &tmp_p);
563 if (!tmp_v) {
564 DBG_PRINT(ERR_DBG,
565 "pci_alloc_consistent ");
566 DBG_PRINT(ERR_DBG, "failed for TxDL\n");
567 return -ENOMEM;
568 }
569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 while (k < lst_per_page) {
571 int l = (j * lst_per_page) + k;
572 if (l == config->tx_cfg[i].fifo_len)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700573 break;
574 mac_control->fifos[i].list_info[l].list_virt_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 tmp_v + (k * lst_size);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700576 mac_control->fifos[i].list_info[l].list_phy_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 tmp_p + (k * lst_size);
578 k++;
579 }
580 }
581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
Al Viro43842472007-01-23 12:25:08 +0000583 nic->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL);
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500584 if (!nic->ufo_in_band_v)
585 return -ENOMEM;
586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 /* Allocation and initialization of RXDs in Rings */
588 size = 0;
589 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -0500590 if (config->rx_cfg[i].num_rxd %
591 (rxd_count[nic->rxd_mode] + 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 DBG_PRINT(ERR_DBG, "%s: RxD count of ", dev->name);
593 DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ",
594 i);
595 DBG_PRINT(ERR_DBG, "RxDs per Block");
596 return FAILURE;
597 }
598 size += config->rx_cfg[i].num_rxd;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700599 mac_control->rings[i].block_count =
Ananda Rajuda6971d2005-10-31 16:55:31 -0500600 config->rx_cfg[i].num_rxd /
601 (rxd_count[nic->rxd_mode] + 1 );
602 mac_control->rings[i].pkt_cnt = config->rx_cfg[i].num_rxd -
603 mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500605 if (nic->rxd_mode == RXD_MODE_1)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500606 size = (size * (sizeof(struct RxD1)));
Ananda Rajuda6971d2005-10-31 16:55:31 -0500607 else
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500608 size = (size * (sizeof(struct RxD3)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700611 mac_control->rings[i].rx_curr_get_info.block_index = 0;
612 mac_control->rings[i].rx_curr_get_info.offset = 0;
613 mac_control->rings[i].rx_curr_get_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700615 mac_control->rings[i].rx_curr_put_info.block_index = 0;
616 mac_control->rings[i].rx_curr_put_info.offset = 0;
617 mac_control->rings[i].rx_curr_put_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700619 mac_control->rings[i].nic = nic;
620 mac_control->rings[i].ring_no = i;
621
Ananda Rajuda6971d2005-10-31 16:55:31 -0500622 blk_cnt = config->rx_cfg[i].num_rxd /
623 (rxd_count[nic->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 /* Allocating all the Rx blocks */
625 for (j = 0; j < blk_cnt; j++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500626 struct rx_block_info *rx_blocks;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500627 int l;
628
629 rx_blocks = &mac_control->rings[i].rx_blocks[j];
630 size = SIZE_OF_BLOCK; //size is always page size
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 tmp_v_addr = pci_alloc_consistent(nic->pdev, size,
632 &tmp_p_addr);
633 if (tmp_v_addr == NULL) {
634 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700635 * In case of failure, free_shared_mem()
636 * is called, which should free any
637 * memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 * failure happened.
639 */
Ananda Rajuda6971d2005-10-31 16:55:31 -0500640 rx_blocks->block_virt_addr = tmp_v_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 return -ENOMEM;
642 }
643 memset(tmp_v_addr, 0, size);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500644 rx_blocks->block_virt_addr = tmp_v_addr;
645 rx_blocks->block_dma_addr = tmp_p_addr;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500646 rx_blocks->rxds = kmalloc(sizeof(struct rxd_info)*
Ananda Rajuda6971d2005-10-31 16:55:31 -0500647 rxd_count[nic->rxd_mode],
648 GFP_KERNEL);
Sivakumar Subramani372cc592007-01-31 13:32:57 -0500649 if (!rx_blocks->rxds)
650 return -ENOMEM;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500651 for (l=0; l<rxd_count[nic->rxd_mode];l++) {
652 rx_blocks->rxds[l].virt_addr =
653 rx_blocks->block_virt_addr +
654 (rxd_size[nic->rxd_mode] * l);
655 rx_blocks->rxds[l].dma_addr =
656 rx_blocks->block_dma_addr +
657 (rxd_size[nic->rxd_mode] * l);
658 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
660 /* Interlinking all Rx Blocks */
661 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700662 tmp_v_addr =
663 mac_control->rings[i].rx_blocks[j].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 tmp_v_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700665 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 blk_cnt].block_virt_addr;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700667 tmp_p_addr =
668 mac_control->rings[i].rx_blocks[j].block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 tmp_p_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700670 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 blk_cnt].block_dma_addr;
672
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500673 pre_rxd_blk = (struct RxD_block *) tmp_v_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 pre_rxd_blk->reserved_2_pNext_RxD_block =
675 (unsigned long) tmp_v_addr_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 pre_rxd_blk->pNext_RxD_Blk_physical =
677 (u64) tmp_p_addr_next;
678 }
679 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500680 if (nic->rxd_mode >= RXD_MODE_3A) {
681 /*
682 * Allocation of Storages for buffer addresses in 2BUFF mode
683 * and the buffers as well.
684 */
685 for (i = 0; i < config->rx_ring_num; i++) {
686 blk_cnt = config->rx_cfg[i].num_rxd /
687 (rxd_count[nic->rxd_mode]+ 1);
688 mac_control->rings[i].ba =
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500689 kmalloc((sizeof(struct buffAdd *) * blk_cnt),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 GFP_KERNEL);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500691 if (!mac_control->rings[i].ba)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 return -ENOMEM;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500693 for (j = 0; j < blk_cnt; j++) {
694 int k = 0;
695 mac_control->rings[i].ba[j] =
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500696 kmalloc((sizeof(struct buffAdd) *
Ananda Rajuda6971d2005-10-31 16:55:31 -0500697 (rxd_count[nic->rxd_mode] + 1)),
698 GFP_KERNEL);
699 if (!mac_control->rings[i].ba[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 return -ENOMEM;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500701 while (k != rxd_count[nic->rxd_mode]) {
702 ba = &mac_control->rings[i].ba[j][k];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Ananda Rajuda6971d2005-10-31 16:55:31 -0500704 ba->ba_0_org = (void *) kmalloc
705 (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
706 if (!ba->ba_0_org)
707 return -ENOMEM;
708 tmp = (unsigned long)ba->ba_0_org;
709 tmp += ALIGN_SIZE;
710 tmp &= ~((unsigned long) ALIGN_SIZE);
711 ba->ba_0 = (void *) tmp;
712
713 ba->ba_1_org = (void *) kmalloc
714 (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
715 if (!ba->ba_1_org)
716 return -ENOMEM;
717 tmp = (unsigned long) ba->ba_1_org;
718 tmp += ALIGN_SIZE;
719 tmp &= ~((unsigned long) ALIGN_SIZE);
720 ba->ba_1 = (void *) tmp;
721 k++;
722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
724 }
725 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 /* Allocation and initialization of Statistics block */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500728 size = sizeof(struct stat_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 mac_control->stats_mem = pci_alloc_consistent
730 (nic->pdev, size, &mac_control->stats_mem_phy);
731
732 if (!mac_control->stats_mem) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700733 /*
734 * In case of failure, free_shared_mem() is called, which
735 * should free any memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 * failure happened.
737 */
738 return -ENOMEM;
739 }
740 mac_control->stats_mem_sz = size;
741
742 tmp_v_addr = mac_control->stats_mem;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500743 mac_control->stats_info = (struct stat_block *) tmp_v_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 memset(tmp_v_addr, 0, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name,
746 (unsigned long long) tmp_p_addr);
747
748 return SUCCESS;
749}
750
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700751/**
752 * free_shared_mem - Free the allocated Memory
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 * @nic: Device private variable.
754 * Description: This function is to free all memory locations allocated by
755 * the init_shared_mem() function and return it to the kernel.
756 */
757
758static void free_shared_mem(struct s2io_nic *nic)
759{
760 int i, j, blk_cnt, size;
761 void *tmp_v_addr;
762 dma_addr_t tmp_p_addr;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500763 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 struct config_param *config;
765 int lst_size, lst_per_page;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700766 struct net_device *dev = nic->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768 if (!nic)
769 return;
770
771 mac_control = &nic->mac_control;
772 config = &nic->config;
773
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500774 lst_size = (sizeof(struct TxD) * config->max_txds);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 lst_per_page = PAGE_SIZE / lst_size;
776
777 for (i = 0; i < config->tx_fifo_num; i++) {
778 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
779 lst_per_page);
780 for (j = 0; j < page_num; j++) {
781 int mem_blks = (j * lst_per_page);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700782 if (!mac_control->fifos[i].list_info)
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400783 return;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700784 if (!mac_control->fifos[i].list_info[mem_blks].
785 list_virt_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 break;
787 pci_free_consistent(nic->pdev, PAGE_SIZE,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700788 mac_control->fifos[i].
789 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 list_virt_addr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700791 mac_control->fifos[i].
792 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 list_phy_addr);
794 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700795 /* If we got a zero DMA address during allocation,
796 * free the page now
797 */
798 if (mac_control->zerodma_virt_addr) {
799 pci_free_consistent(nic->pdev, PAGE_SIZE,
800 mac_control->zerodma_virt_addr,
801 (dma_addr_t)0);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400802 DBG_PRINT(INIT_DBG,
Andrew Morton6b4d6172005-09-12 23:21:55 -0700803 "%s: Freeing TxDL with zero DMA addr. ",
804 dev->name);
805 DBG_PRINT(INIT_DBG, "Virtual address %p\n",
806 mac_control->zerodma_virt_addr);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700807 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700808 kfree(mac_control->fifos[i].list_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 }
810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 size = SIZE_OF_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700813 blk_cnt = mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700815 tmp_v_addr = mac_control->rings[i].rx_blocks[j].
816 block_virt_addr;
817 tmp_p_addr = mac_control->rings[i].rx_blocks[j].
818 block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 if (tmp_v_addr == NULL)
820 break;
821 pci_free_consistent(nic->pdev, size,
822 tmp_v_addr, tmp_p_addr);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500823 kfree(mac_control->rings[i].rx_blocks[j].rxds);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 }
825 }
826
Ananda Rajuda6971d2005-10-31 16:55:31 -0500827 if (nic->rxd_mode >= RXD_MODE_3A) {
828 /* Freeing buffer storage addresses in 2BUFF mode. */
829 for (i = 0; i < config->rx_ring_num; i++) {
830 blk_cnt = config->rx_cfg[i].num_rxd /
831 (rxd_count[nic->rxd_mode] + 1);
832 for (j = 0; j < blk_cnt; j++) {
833 int k = 0;
834 if (!mac_control->rings[i].ba[j])
835 continue;
836 while (k != rxd_count[nic->rxd_mode]) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500837 struct buffAdd *ba =
Ananda Rajuda6971d2005-10-31 16:55:31 -0500838 &mac_control->rings[i].ba[j][k];
839 kfree(ba->ba_0_org);
840 kfree(ba->ba_1_org);
841 k++;
842 }
843 kfree(mac_control->rings[i].ba[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500845 kfree(mac_control->rings[i].ba);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
849 if (mac_control->stats_mem) {
850 pci_free_consistent(nic->pdev,
851 mac_control->stats_mem_sz,
852 mac_control->stats_mem,
853 mac_control->stats_mem_phy);
854 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500855 if (nic->ufo_in_band_v)
856 kfree(nic->ufo_in_band_v);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857}
858
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700859/**
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700860 * s2io_verify_pci_mode -
861 */
862
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500863static int s2io_verify_pci_mode(struct s2io_nic *nic)
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700864{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500865 struct XENA_dev_config __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700866 register u64 val64 = 0;
867 int mode;
868
869 val64 = readq(&bar0->pci_mode);
870 mode = (u8)GET_PCI_MODE(val64);
871
872 if ( val64 & PCI_MODE_UNKNOWN_MODE)
873 return -1; /* Unknown PCI mode */
874 return mode;
875}
876
Ananda Rajuc92ca042006-04-21 19:18:03 -0400877#define NEC_VENID 0x1033
878#define NEC_DEVID 0x0125
879static int s2io_on_nec_bridge(struct pci_dev *s2io_pdev)
880{
881 struct pci_dev *tdev = NULL;
Alan Cox26d36b62006-09-15 15:22:51 +0100882 while ((tdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, tdev)) != NULL) {
883 if (tdev->vendor == NEC_VENID && tdev->device == NEC_DEVID) {
Ananda Rajuc92ca042006-04-21 19:18:03 -0400884 if (tdev->bus == s2io_pdev->bus->parent)
Alan Cox26d36b62006-09-15 15:22:51 +0100885 pci_dev_put(tdev);
Ananda Rajuc92ca042006-04-21 19:18:03 -0400886 return 1;
887 }
888 }
889 return 0;
890}
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700891
Adrian Bunk7b32a312006-05-16 17:30:50 +0200892static int bus_speed[8] = {33, 133, 133, 200, 266, 133, 200, 266};
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700893/**
894 * s2io_print_pci_mode -
895 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500896static int s2io_print_pci_mode(struct s2io_nic *nic)
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700897{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500898 struct XENA_dev_config __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700899 register u64 val64 = 0;
900 int mode;
901 struct config_param *config = &nic->config;
902
903 val64 = readq(&bar0->pci_mode);
904 mode = (u8)GET_PCI_MODE(val64);
905
906 if ( val64 & PCI_MODE_UNKNOWN_MODE)
907 return -1; /* Unknown PCI mode */
908
Ananda Rajuc92ca042006-04-21 19:18:03 -0400909 config->bus_speed = bus_speed[mode];
910
911 if (s2io_on_nec_bridge(nic->pdev)) {
912 DBG_PRINT(ERR_DBG, "%s: Device is on PCI-E bus\n",
913 nic->dev->name);
914 return mode;
915 }
916
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700917 if (val64 & PCI_MODE_32_BITS) {
918 DBG_PRINT(ERR_DBG, "%s: Device is on 32 bit ", nic->dev->name);
919 } else {
920 DBG_PRINT(ERR_DBG, "%s: Device is on 64 bit ", nic->dev->name);
921 }
922
923 switch(mode) {
924 case PCI_MODE_PCI_33:
925 DBG_PRINT(ERR_DBG, "33MHz PCI bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700926 break;
927 case PCI_MODE_PCI_66:
928 DBG_PRINT(ERR_DBG, "66MHz PCI bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700929 break;
930 case PCI_MODE_PCIX_M1_66:
931 DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700932 break;
933 case PCI_MODE_PCIX_M1_100:
934 DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700935 break;
936 case PCI_MODE_PCIX_M1_133:
937 DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700938 break;
939 case PCI_MODE_PCIX_M2_66:
940 DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700941 break;
942 case PCI_MODE_PCIX_M2_100:
943 DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700944 break;
945 case PCI_MODE_PCIX_M2_133:
946 DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700947 break;
948 default:
949 return -1; /* Unsupported bus speed */
950 }
951
952 return mode;
953}
954
955/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700956 * init_nic - Initialization of hardware
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 * @nic: device peivate variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700958 * Description: The function sequentially configures every block
959 * of the H/W from their reset values.
960 * Return Value: SUCCESS on success and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 * '-1' on failure (endian settings incorrect).
962 */
963
964static int init_nic(struct s2io_nic *nic)
965{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500966 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 struct net_device *dev = nic->dev;
968 register u64 val64 = 0;
969 void __iomem *add;
970 u32 time;
971 int i, j;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500972 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 struct config_param *config;
Ananda Rajuc92ca042006-04-21 19:18:03 -0400974 int dtx_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 unsigned long long mem_share;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700976 int mem_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
978 mac_control = &nic->mac_control;
979 config = &nic->config;
980
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700981 /* to set the swapper controle on the card */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700982 if(s2io_set_swapper(nic)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n");
984 return -1;
985 }
986
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700987 /*
988 * Herc requires EOI to be removed from reset before XGXS, so..
989 */
990 if (nic->device_type & XFRAME_II_DEVICE) {
991 val64 = 0xA500000000ULL;
992 writeq(val64, &bar0->sw_reset);
993 msleep(500);
994 val64 = readq(&bar0->sw_reset);
995 }
996
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 /* Remove XGXS from reset state */
998 val64 = 0;
999 writeq(val64, &bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 msleep(500);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001001 val64 = readq(&bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 /* Enable Receiving broadcasts */
1004 add = &bar0->mac_cfg;
1005 val64 = readq(&bar0->mac_cfg);
1006 val64 |= MAC_RMAC_BCAST_ENABLE;
1007 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1008 writel((u32) val64, add);
1009 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1010 writel((u32) (val64 >> 32), (add + 4));
1011
1012 /* Read registers in all blocks */
1013 val64 = readq(&bar0->mac_int_mask);
1014 val64 = readq(&bar0->mc_int_mask);
1015 val64 = readq(&bar0->xgxs_int_mask);
1016
1017 /* Set MTU */
1018 val64 = dev->mtu;
1019 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
1020
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001021 if (nic->device_type & XFRAME_II_DEVICE) {
1022 while (herc_act_dtx_cfg[dtx_cnt] != END_SIGN) {
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07001023 SPECIAL_REG_WRITE(herc_act_dtx_cfg[dtx_cnt],
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 &bar0->dtx_control, UF);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001025 if (dtx_cnt & 0x1)
1026 msleep(1); /* Necessary!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 dtx_cnt++;
1028 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001029 } else {
Ananda Rajuc92ca042006-04-21 19:18:03 -04001030 while (xena_dtx_cfg[dtx_cnt] != END_SIGN) {
1031 SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt],
1032 &bar0->dtx_control, UF);
1033 val64 = readq(&bar0->dtx_control);
1034 dtx_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 }
1036 }
1037
1038 /* Tx DMA Initialization */
1039 val64 = 0;
1040 writeq(val64, &bar0->tx_fifo_partition_0);
1041 writeq(val64, &bar0->tx_fifo_partition_1);
1042 writeq(val64, &bar0->tx_fifo_partition_2);
1043 writeq(val64, &bar0->tx_fifo_partition_3);
1044
1045
1046 for (i = 0, j = 0; i < config->tx_fifo_num; i++) {
1047 val64 |=
1048 vBIT(config->tx_cfg[i].fifo_len - 1, ((i * 32) + 19),
1049 13) | vBIT(config->tx_cfg[i].fifo_priority,
1050 ((i * 32) + 5), 3);
1051
1052 if (i == (config->tx_fifo_num - 1)) {
1053 if (i % 2 == 0)
1054 i++;
1055 }
1056
1057 switch (i) {
1058 case 1:
1059 writeq(val64, &bar0->tx_fifo_partition_0);
1060 val64 = 0;
1061 break;
1062 case 3:
1063 writeq(val64, &bar0->tx_fifo_partition_1);
1064 val64 = 0;
1065 break;
1066 case 5:
1067 writeq(val64, &bar0->tx_fifo_partition_2);
1068 val64 = 0;
1069 break;
1070 case 7:
1071 writeq(val64, &bar0->tx_fifo_partition_3);
1072 break;
1073 }
1074 }
1075
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001076 /*
1077 * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug
1078 * SXE-008 TRANSMIT DMA ARBITRATION ISSUE.
1079 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001080 if ((nic->device_type == XFRAME_I_DEVICE) &&
1081 (get_xena_rev_id(nic->pdev) < 4))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001082 writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable);
1083
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 val64 = readq(&bar0->tx_fifo_partition_0);
1085 DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n",
1086 &bar0->tx_fifo_partition_0, (unsigned long long) val64);
1087
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001088 /*
1089 * Initialization of Tx_PA_CONFIG register to ignore packet
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 * integrity checking.
1091 */
1092 val64 = readq(&bar0->tx_pa_cfg);
1093 val64 |= TX_PA_CFG_IGNORE_FRM_ERR | TX_PA_CFG_IGNORE_SNAP_OUI |
1094 TX_PA_CFG_IGNORE_LLC_CTRL | TX_PA_CFG_IGNORE_L2_ERR;
1095 writeq(val64, &bar0->tx_pa_cfg);
1096
1097 /* Rx DMA intialization. */
1098 val64 = 0;
1099 for (i = 0; i < config->rx_ring_num; i++) {
1100 val64 |=
1101 vBIT(config->rx_cfg[i].ring_priority, (5 + (i * 8)),
1102 3);
1103 }
1104 writeq(val64, &bar0->rx_queue_priority);
1105
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001106 /*
1107 * Allocating equal share of memory to all the
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 * configured Rings.
1109 */
1110 val64 = 0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001111 if (nic->device_type & XFRAME_II_DEVICE)
1112 mem_size = 32;
1113 else
1114 mem_size = 64;
1115
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 for (i = 0; i < config->rx_ring_num; i++) {
1117 switch (i) {
1118 case 0:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001119 mem_share = (mem_size / config->rx_ring_num +
1120 mem_size % config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 val64 |= RX_QUEUE_CFG_Q0_SZ(mem_share);
1122 continue;
1123 case 1:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001124 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 val64 |= RX_QUEUE_CFG_Q1_SZ(mem_share);
1126 continue;
1127 case 2:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001128 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 val64 |= RX_QUEUE_CFG_Q2_SZ(mem_share);
1130 continue;
1131 case 3:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001132 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 val64 |= RX_QUEUE_CFG_Q3_SZ(mem_share);
1134 continue;
1135 case 4:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001136 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 val64 |= RX_QUEUE_CFG_Q4_SZ(mem_share);
1138 continue;
1139 case 5:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001140 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 val64 |= RX_QUEUE_CFG_Q5_SZ(mem_share);
1142 continue;
1143 case 6:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001144 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 val64 |= RX_QUEUE_CFG_Q6_SZ(mem_share);
1146 continue;
1147 case 7:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001148 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 val64 |= RX_QUEUE_CFG_Q7_SZ(mem_share);
1150 continue;
1151 }
1152 }
1153 writeq(val64, &bar0->rx_queue_cfg);
1154
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001155 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001156 * Filling Tx round robin registers
1157 * as per the number of FIFOs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 */
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001159 switch (config->tx_fifo_num) {
1160 case 1:
1161 val64 = 0x0000000000000000ULL;
1162 writeq(val64, &bar0->tx_w_round_robin_0);
1163 writeq(val64, &bar0->tx_w_round_robin_1);
1164 writeq(val64, &bar0->tx_w_round_robin_2);
1165 writeq(val64, &bar0->tx_w_round_robin_3);
1166 writeq(val64, &bar0->tx_w_round_robin_4);
1167 break;
1168 case 2:
1169 val64 = 0x0000010000010000ULL;
1170 writeq(val64, &bar0->tx_w_round_robin_0);
1171 val64 = 0x0100000100000100ULL;
1172 writeq(val64, &bar0->tx_w_round_robin_1);
1173 val64 = 0x0001000001000001ULL;
1174 writeq(val64, &bar0->tx_w_round_robin_2);
1175 val64 = 0x0000010000010000ULL;
1176 writeq(val64, &bar0->tx_w_round_robin_3);
1177 val64 = 0x0100000000000000ULL;
1178 writeq(val64, &bar0->tx_w_round_robin_4);
1179 break;
1180 case 3:
1181 val64 = 0x0001000102000001ULL;
1182 writeq(val64, &bar0->tx_w_round_robin_0);
1183 val64 = 0x0001020000010001ULL;
1184 writeq(val64, &bar0->tx_w_round_robin_1);
1185 val64 = 0x0200000100010200ULL;
1186 writeq(val64, &bar0->tx_w_round_robin_2);
1187 val64 = 0x0001000102000001ULL;
1188 writeq(val64, &bar0->tx_w_round_robin_3);
1189 val64 = 0x0001020000000000ULL;
1190 writeq(val64, &bar0->tx_w_round_robin_4);
1191 break;
1192 case 4:
1193 val64 = 0x0001020300010200ULL;
1194 writeq(val64, &bar0->tx_w_round_robin_0);
1195 val64 = 0x0100000102030001ULL;
1196 writeq(val64, &bar0->tx_w_round_robin_1);
1197 val64 = 0x0200010000010203ULL;
1198 writeq(val64, &bar0->tx_w_round_robin_2);
1199 val64 = 0x0001020001000001ULL;
1200 writeq(val64, &bar0->tx_w_round_robin_3);
1201 val64 = 0x0203000100000000ULL;
1202 writeq(val64, &bar0->tx_w_round_robin_4);
1203 break;
1204 case 5:
1205 val64 = 0x0001000203000102ULL;
1206 writeq(val64, &bar0->tx_w_round_robin_0);
1207 val64 = 0x0001020001030004ULL;
1208 writeq(val64, &bar0->tx_w_round_robin_1);
1209 val64 = 0x0001000203000102ULL;
1210 writeq(val64, &bar0->tx_w_round_robin_2);
1211 val64 = 0x0001020001030004ULL;
1212 writeq(val64, &bar0->tx_w_round_robin_3);
1213 val64 = 0x0001000000000000ULL;
1214 writeq(val64, &bar0->tx_w_round_robin_4);
1215 break;
1216 case 6:
1217 val64 = 0x0001020304000102ULL;
1218 writeq(val64, &bar0->tx_w_round_robin_0);
1219 val64 = 0x0304050001020001ULL;
1220 writeq(val64, &bar0->tx_w_round_robin_1);
1221 val64 = 0x0203000100000102ULL;
1222 writeq(val64, &bar0->tx_w_round_robin_2);
1223 val64 = 0x0304000102030405ULL;
1224 writeq(val64, &bar0->tx_w_round_robin_3);
1225 val64 = 0x0001000200000000ULL;
1226 writeq(val64, &bar0->tx_w_round_robin_4);
1227 break;
1228 case 7:
1229 val64 = 0x0001020001020300ULL;
1230 writeq(val64, &bar0->tx_w_round_robin_0);
1231 val64 = 0x0102030400010203ULL;
1232 writeq(val64, &bar0->tx_w_round_robin_1);
1233 val64 = 0x0405060001020001ULL;
1234 writeq(val64, &bar0->tx_w_round_robin_2);
1235 val64 = 0x0304050000010200ULL;
1236 writeq(val64, &bar0->tx_w_round_robin_3);
1237 val64 = 0x0102030000000000ULL;
1238 writeq(val64, &bar0->tx_w_round_robin_4);
1239 break;
1240 case 8:
1241 val64 = 0x0001020300040105ULL;
1242 writeq(val64, &bar0->tx_w_round_robin_0);
1243 val64 = 0x0200030106000204ULL;
1244 writeq(val64, &bar0->tx_w_round_robin_1);
1245 val64 = 0x0103000502010007ULL;
1246 writeq(val64, &bar0->tx_w_round_robin_2);
1247 val64 = 0x0304010002060500ULL;
1248 writeq(val64, &bar0->tx_w_round_robin_3);
1249 val64 = 0x0103020400000000ULL;
1250 writeq(val64, &bar0->tx_w_round_robin_4);
1251 break;
1252 }
1253
Ananda Rajub41477f2006-07-24 19:52:49 -04001254 /* Enable all configured Tx FIFO partitions */
Ananda Raju5d3213c2006-04-21 19:23:26 -04001255 val64 = readq(&bar0->tx_fifo_partition_0);
1256 val64 |= (TX_FIFO_PARTITION_EN);
1257 writeq(val64, &bar0->tx_fifo_partition_0);
1258
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001259 /* Filling the Rx round robin registers as per the
1260 * number of Rings and steering based on QoS.
1261 */
1262 switch (config->rx_ring_num) {
1263 case 1:
1264 val64 = 0x8080808080808080ULL;
1265 writeq(val64, &bar0->rts_qos_steering);
1266 break;
1267 case 2:
1268 val64 = 0x0000010000010000ULL;
1269 writeq(val64, &bar0->rx_w_round_robin_0);
1270 val64 = 0x0100000100000100ULL;
1271 writeq(val64, &bar0->rx_w_round_robin_1);
1272 val64 = 0x0001000001000001ULL;
1273 writeq(val64, &bar0->rx_w_round_robin_2);
1274 val64 = 0x0000010000010000ULL;
1275 writeq(val64, &bar0->rx_w_round_robin_3);
1276 val64 = 0x0100000000000000ULL;
1277 writeq(val64, &bar0->rx_w_round_robin_4);
1278
1279 val64 = 0x8080808040404040ULL;
1280 writeq(val64, &bar0->rts_qos_steering);
1281 break;
1282 case 3:
1283 val64 = 0x0001000102000001ULL;
1284 writeq(val64, &bar0->rx_w_round_robin_0);
1285 val64 = 0x0001020000010001ULL;
1286 writeq(val64, &bar0->rx_w_round_robin_1);
1287 val64 = 0x0200000100010200ULL;
1288 writeq(val64, &bar0->rx_w_round_robin_2);
1289 val64 = 0x0001000102000001ULL;
1290 writeq(val64, &bar0->rx_w_round_robin_3);
1291 val64 = 0x0001020000000000ULL;
1292 writeq(val64, &bar0->rx_w_round_robin_4);
1293
1294 val64 = 0x8080804040402020ULL;
1295 writeq(val64, &bar0->rts_qos_steering);
1296 break;
1297 case 4:
1298 val64 = 0x0001020300010200ULL;
1299 writeq(val64, &bar0->rx_w_round_robin_0);
1300 val64 = 0x0100000102030001ULL;
1301 writeq(val64, &bar0->rx_w_round_robin_1);
1302 val64 = 0x0200010000010203ULL;
1303 writeq(val64, &bar0->rx_w_round_robin_2);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001304 val64 = 0x0001020001000001ULL;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001305 writeq(val64, &bar0->rx_w_round_robin_3);
1306 val64 = 0x0203000100000000ULL;
1307 writeq(val64, &bar0->rx_w_round_robin_4);
1308
1309 val64 = 0x8080404020201010ULL;
1310 writeq(val64, &bar0->rts_qos_steering);
1311 break;
1312 case 5:
1313 val64 = 0x0001000203000102ULL;
1314 writeq(val64, &bar0->rx_w_round_robin_0);
1315 val64 = 0x0001020001030004ULL;
1316 writeq(val64, &bar0->rx_w_round_robin_1);
1317 val64 = 0x0001000203000102ULL;
1318 writeq(val64, &bar0->rx_w_round_robin_2);
1319 val64 = 0x0001020001030004ULL;
1320 writeq(val64, &bar0->rx_w_round_robin_3);
1321 val64 = 0x0001000000000000ULL;
1322 writeq(val64, &bar0->rx_w_round_robin_4);
1323
1324 val64 = 0x8080404020201008ULL;
1325 writeq(val64, &bar0->rts_qos_steering);
1326 break;
1327 case 6:
1328 val64 = 0x0001020304000102ULL;
1329 writeq(val64, &bar0->rx_w_round_robin_0);
1330 val64 = 0x0304050001020001ULL;
1331 writeq(val64, &bar0->rx_w_round_robin_1);
1332 val64 = 0x0203000100000102ULL;
1333 writeq(val64, &bar0->rx_w_round_robin_2);
1334 val64 = 0x0304000102030405ULL;
1335 writeq(val64, &bar0->rx_w_round_robin_3);
1336 val64 = 0x0001000200000000ULL;
1337 writeq(val64, &bar0->rx_w_round_robin_4);
1338
1339 val64 = 0x8080404020100804ULL;
1340 writeq(val64, &bar0->rts_qos_steering);
1341 break;
1342 case 7:
1343 val64 = 0x0001020001020300ULL;
1344 writeq(val64, &bar0->rx_w_round_robin_0);
1345 val64 = 0x0102030400010203ULL;
1346 writeq(val64, &bar0->rx_w_round_robin_1);
1347 val64 = 0x0405060001020001ULL;
1348 writeq(val64, &bar0->rx_w_round_robin_2);
1349 val64 = 0x0304050000010200ULL;
1350 writeq(val64, &bar0->rx_w_round_robin_3);
1351 val64 = 0x0102030000000000ULL;
1352 writeq(val64, &bar0->rx_w_round_robin_4);
1353
1354 val64 = 0x8080402010080402ULL;
1355 writeq(val64, &bar0->rts_qos_steering);
1356 break;
1357 case 8:
1358 val64 = 0x0001020300040105ULL;
1359 writeq(val64, &bar0->rx_w_round_robin_0);
1360 val64 = 0x0200030106000204ULL;
1361 writeq(val64, &bar0->rx_w_round_robin_1);
1362 val64 = 0x0103000502010007ULL;
1363 writeq(val64, &bar0->rx_w_round_robin_2);
1364 val64 = 0x0304010002060500ULL;
1365 writeq(val64, &bar0->rx_w_round_robin_3);
1366 val64 = 0x0103020400000000ULL;
1367 writeq(val64, &bar0->rx_w_round_robin_4);
1368
1369 val64 = 0x8040201008040201ULL;
1370 writeq(val64, &bar0->rts_qos_steering);
1371 break;
1372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
1374 /* UDP Fix */
1375 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001376 for (i = 0; i < 8; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 writeq(val64, &bar0->rts_frm_len_n[i]);
1378
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001379 /* Set the default rts frame length for the rings configured */
1380 val64 = MAC_RTS_FRM_LEN_SET(dev->mtu+22);
1381 for (i = 0 ; i < config->rx_ring_num ; i++)
1382 writeq(val64, &bar0->rts_frm_len_n[i]);
1383
1384 /* Set the frame length for the configured rings
1385 * desired by the user
1386 */
1387 for (i = 0; i < config->rx_ring_num; i++) {
1388 /* If rts_frm_len[i] == 0 then it is assumed that user not
1389 * specified frame length steering.
1390 * If the user provides the frame length then program
1391 * the rts_frm_len register for those values or else
1392 * leave it as it is.
1393 */
1394 if (rts_frm_len[i] != 0) {
1395 writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]),
1396 &bar0->rts_frm_len_n[i]);
1397 }
1398 }
Sivakumar Subramani926930b2007-02-24 01:59:39 -05001399
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05001400 /* Disable differentiated services steering logic */
1401 for (i = 0; i < 64; i++) {
1402 if (rts_ds_steer(nic, i, 0) == FAILURE) {
1403 DBG_PRINT(ERR_DBG, "%s: failed rts ds steering",
1404 dev->name);
1405 DBG_PRINT(ERR_DBG, "set on codepoint %d\n", i);
1406 return FAILURE;
1407 }
1408 }
1409
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001410 /* Program statistics memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 writeq(mac_control->stats_mem_phy, &bar0->stat_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001413 if (nic->device_type == XFRAME_II_DEVICE) {
1414 val64 = STAT_BC(0x320);
1415 writeq(val64, &bar0->stat_byte_cnt);
1416 }
1417
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001418 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 * Initializing the sampling rate for the device to calculate the
1420 * bandwidth utilization.
1421 */
1422 val64 = MAC_TX_LINK_UTIL_VAL(tmac_util_period) |
1423 MAC_RX_LINK_UTIL_VAL(rmac_util_period);
1424 writeq(val64, &bar0->mac_link_util);
1425
1426
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001427 /*
1428 * Initializing the Transmit and Receive Traffic Interrupt
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 * Scheme.
1430 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001431 /*
1432 * TTI Initialization. Default Tx timer gets us about
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 * 250 interrupts per sec. Continuous interrupts are enabled
1434 * by default.
1435 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001436 if (nic->device_type == XFRAME_II_DEVICE) {
1437 int count = (nic->config.bus_speed * 125)/2;
1438 val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count);
1439 } else {
1440
1441 val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078);
1442 }
1443 val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 TTI_DATA1_MEM_TX_URNG_B(0x10) |
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001445 TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001446 if (use_continuous_tx_intrs)
1447 val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 writeq(val64, &bar0->tti_data1_mem);
1449
1450 val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
1451 TTI_DATA2_MEM_TX_UFC_B(0x20) |
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001452 TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 writeq(val64, &bar0->tti_data2_mem);
1454
1455 val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
1456 writeq(val64, &bar0->tti_command_mem);
1457
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001458 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 * Once the operation completes, the Strobe bit of the command
1460 * register will be reset. We poll for this particular condition
1461 * We wait for a maximum of 500ms for the operation to complete,
1462 * if it's not complete by then we return error.
1463 */
1464 time = 0;
1465 while (TRUE) {
1466 val64 = readq(&bar0->tti_command_mem);
1467 if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
1468 break;
1469 }
1470 if (time > 10) {
1471 DBG_PRINT(ERR_DBG, "%s: TTI init Failed\n",
1472 dev->name);
1473 return -1;
1474 }
1475 msleep(50);
1476 time++;
1477 }
1478
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001479 if (nic->config.bimodal) {
1480 int k = 0;
1481 for (k = 0; k < config->rx_ring_num; k++) {
1482 val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
1483 val64 |= TTI_CMD_MEM_OFFSET(0x38+k);
1484 writeq(val64, &bar0->tti_command_mem);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001485
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001486 /*
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001487 * Once the operation completes, the Strobe bit of the command
1488 * register will be reset. We poll for this particular condition
1489 * We wait for a maximum of 500ms for the operation to complete,
1490 * if it's not complete by then we return error.
1491 */
1492 time = 0;
1493 while (TRUE) {
1494 val64 = readq(&bar0->tti_command_mem);
1495 if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
1496 break;
1497 }
1498 if (time > 10) {
1499 DBG_PRINT(ERR_DBG,
1500 "%s: TTI init Failed\n",
1501 dev->name);
1502 return -1;
1503 }
1504 time++;
1505 msleep(50);
1506 }
1507 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001508 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001510 /* RTI Initialization */
1511 if (nic->device_type == XFRAME_II_DEVICE) {
1512 /*
1513 * Programmed to generate Apprx 500 Intrs per
1514 * second
1515 */
1516 int count = (nic->config.bus_speed * 125)/4;
1517 val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
1518 } else {
1519 val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 }
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001521 val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
1522 RTI_DATA1_MEM_RX_URNG_B(0x10) |
1523 RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
1524
1525 writeq(val64, &bar0->rti_data1_mem);
1526
1527 val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04001528 RTI_DATA2_MEM_RX_UFC_B(0x2) ;
1529 if (nic->intr_type == MSI_X)
1530 val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
1531 RTI_DATA2_MEM_RX_UFC_D(0x40));
1532 else
1533 val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \
1534 RTI_DATA2_MEM_RX_UFC_D(0x80));
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001535 writeq(val64, &bar0->rti_data2_mem);
1536
1537 for (i = 0; i < config->rx_ring_num; i++) {
1538 val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD
1539 | RTI_CMD_MEM_OFFSET(i);
1540 writeq(val64, &bar0->rti_command_mem);
1541
1542 /*
1543 * Once the operation completes, the Strobe bit of the
1544 * command register will be reset. We poll for this
1545 * particular condition. We wait for a maximum of 500ms
1546 * for the operation to complete, if it's not complete
1547 * by then we return error.
1548 */
1549 time = 0;
1550 while (TRUE) {
1551 val64 = readq(&bar0->rti_command_mem);
1552 if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) {
1553 break;
1554 }
1555 if (time > 10) {
1556 DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
1557 dev->name);
1558 return -1;
1559 }
1560 time++;
1561 msleep(50);
1562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 }
1565
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001566 /*
1567 * Initializing proper values as Pause threshold into all
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 * the 8 Queues on Rx side.
1569 */
1570 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q0q3);
1571 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7);
1572
1573 /* Disable RMAC PAD STRIPPING */
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01001574 add = &bar0->mac_cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 val64 = readq(&bar0->mac_cfg);
1576 val64 &= ~(MAC_CFG_RMAC_STRIP_PAD);
1577 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1578 writel((u32) (val64), add);
1579 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1580 writel((u32) (val64 >> 32), (add + 4));
1581 val64 = readq(&bar0->mac_cfg);
1582
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05001583 /* Enable FCS stripping by adapter */
1584 add = &bar0->mac_cfg;
1585 val64 = readq(&bar0->mac_cfg);
1586 val64 |= MAC_CFG_RMAC_STRIP_FCS;
1587 if (nic->device_type == XFRAME_II_DEVICE)
1588 writeq(val64, &bar0->mac_cfg);
1589 else {
1590 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1591 writel((u32) (val64), add);
1592 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1593 writel((u32) (val64 >> 32), (add + 4));
1594 }
1595
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001596 /*
1597 * Set the time value to be inserted in the pause frame
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 * generated by xena.
1599 */
1600 val64 = readq(&bar0->rmac_pause_cfg);
1601 val64 &= ~(RMAC_PAUSE_HG_PTIME(0xffff));
1602 val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time);
1603 writeq(val64, &bar0->rmac_pause_cfg);
1604
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001605 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 * Set the Threshold Limit for Generating the pause frame
1607 * If the amount of data in any Queue exceeds ratio of
1608 * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256
1609 * pause frame is generated
1610 */
1611 val64 = 0;
1612 for (i = 0; i < 4; i++) {
1613 val64 |=
1614 (((u64) 0xFF00 | nic->mac_control.
1615 mc_pause_threshold_q0q3)
1616 << (i * 2 * 8));
1617 }
1618 writeq(val64, &bar0->mc_pause_thresh_q0q3);
1619
1620 val64 = 0;
1621 for (i = 0; i < 4; i++) {
1622 val64 |=
1623 (((u64) 0xFF00 | nic->mac_control.
1624 mc_pause_threshold_q4q7)
1625 << (i * 2 * 8));
1626 }
1627 writeq(val64, &bar0->mc_pause_thresh_q4q7);
1628
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001629 /*
1630 * TxDMA will stop Read request if the number of read split has
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 * exceeded the limit pointed by shared_splits
1632 */
1633 val64 = readq(&bar0->pic_control);
1634 val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits);
1635 writeq(val64, &bar0->pic_control);
1636
Ananda Raju863c11a2006-04-21 19:03:13 -04001637 if (nic->config.bus_speed == 266) {
1638 writeq(TXREQTO_VAL(0x7f) | TXREQTO_EN, &bar0->txreqtimeout);
1639 writeq(0x0, &bar0->read_retry_delay);
1640 writeq(0x0, &bar0->write_retry_delay);
1641 }
1642
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001643 /*
1644 * Programming the Herc to split every write transaction
1645 * that does not start on an ADB to reduce disconnects.
1646 */
1647 if (nic->device_type == XFRAME_II_DEVICE) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001648 val64 = FAULT_BEHAVIOUR | EXT_REQ_EN |
1649 MISC_LINK_STABILITY_PRD(3);
Ananda Raju863c11a2006-04-21 19:03:13 -04001650 writeq(val64, &bar0->misc_control);
1651 val64 = readq(&bar0->pic_control2);
1652 val64 &= ~(BIT(13)|BIT(14)|BIT(15));
1653 writeq(val64, &bar0->pic_control2);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001654 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04001655 if (strstr(nic->product_name, "CX4")) {
1656 val64 = TMAC_AVG_IPG(0x17);
1657 writeq(val64, &bar0->tmac_avg_ipg);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001658 }
1659
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 return SUCCESS;
1661}
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001662#define LINK_UP_DOWN_INTERRUPT 1
1663#define MAC_RMAC_ERR_TIMER 2
1664
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001665static int s2io_link_fault_indication(struct s2io_nic *nic)
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001666{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04001667 if (nic->intr_type != INTA)
1668 return MAC_RMAC_ERR_TIMER;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001669 if (nic->device_type == XFRAME_II_DEVICE)
1670 return LINK_UP_DOWN_INTERRUPT;
1671 else
1672 return MAC_RMAC_ERR_TIMER;
1673}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001675/**
1676 * en_dis_able_nic_intrs - Enable or Disable the interrupts
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 * @nic: device private variable,
1678 * @mask: A mask indicating which Intr block must be modified and,
1679 * @flag: A flag indicating whether to enable or disable the Intrs.
1680 * Description: This function will either disable or enable the interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001681 * depending on the flag argument. The mask argument can be used to
1682 * enable/disable any Intr block.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 * Return Value: NONE.
1684 */
1685
1686static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
1687{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001688 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 register u64 val64 = 0, temp64 = 0;
1690
1691 /* Top level interrupt classification */
1692 /* PIC Interrupts */
1693 if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
1694 /* Enable PIC Intrs in the general intr mask register */
Sivakumar Subramania113ae02007-01-31 14:05:51 -05001695 val64 = TXPIC_INT_M;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 if (flag == ENABLE_INTRS) {
1697 temp64 = readq(&bar0->general_int_mask);
1698 temp64 &= ~((u64) val64);
1699 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001700 /*
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001701 * If Hercules adapter enable GPIO otherwise
Ananda Rajub41477f2006-07-24 19:52:49 -04001702 * disable all PCIX, Flash, MDIO, IIC and GPIO
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001703 * interrupts for now.
1704 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001706 if (s2io_link_fault_indication(nic) ==
1707 LINK_UP_DOWN_INTERRUPT ) {
1708 temp64 = readq(&bar0->pic_int_mask);
1709 temp64 &= ~((u64) PIC_INT_GPIO);
1710 writeq(temp64, &bar0->pic_int_mask);
1711 temp64 = readq(&bar0->gpio_int_mask);
1712 temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP);
1713 writeq(temp64, &bar0->gpio_int_mask);
1714 } else {
1715 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
1716 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001717 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 * No MSI Support is available presently, so TTI and
1719 * RTI interrupts are also disabled.
1720 */
1721 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001722 /*
1723 * Disable PIC Intrs in the general
1724 * intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 */
1726 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
1727 temp64 = readq(&bar0->general_int_mask);
1728 val64 |= temp64;
1729 writeq(val64, &bar0->general_int_mask);
1730 }
1731 }
1732
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 /* MAC Interrupts */
1734 /* Enabling/Disabling MAC interrupts */
1735 if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
1736 val64 = TXMAC_INT_M | RXMAC_INT_M;
1737 if (flag == ENABLE_INTRS) {
1738 temp64 = readq(&bar0->general_int_mask);
1739 temp64 &= ~((u64) val64);
1740 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001741 /*
1742 * All MAC block error interrupts are disabled for now
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 * TODO
1744 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001746 /*
1747 * Disable MAC Intrs in the general intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 */
1749 writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask);
1750 writeq(DISABLE_ALL_INTRS,
1751 &bar0->mac_rmac_err_mask);
1752
1753 temp64 = readq(&bar0->general_int_mask);
1754 val64 |= temp64;
1755 writeq(val64, &bar0->general_int_mask);
1756 }
1757 }
1758
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 /* Tx traffic interrupts */
1760 if (mask & TX_TRAFFIC_INTR) {
1761 val64 = TXTRAFFIC_INT_M;
1762 if (flag == ENABLE_INTRS) {
1763 temp64 = readq(&bar0->general_int_mask);
1764 temp64 &= ~((u64) val64);
1765 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001766 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 * Enable all the Tx side interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001768 * writing 0 Enables all 64 TX interrupt levels
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 */
1770 writeq(0x0, &bar0->tx_traffic_mask);
1771 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001772 /*
1773 * Disable Tx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 * register.
1775 */
1776 writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask);
1777 temp64 = readq(&bar0->general_int_mask);
1778 val64 |= temp64;
1779 writeq(val64, &bar0->general_int_mask);
1780 }
1781 }
1782
1783 /* Rx traffic interrupts */
1784 if (mask & RX_TRAFFIC_INTR) {
1785 val64 = RXTRAFFIC_INT_M;
1786 if (flag == ENABLE_INTRS) {
1787 temp64 = readq(&bar0->general_int_mask);
1788 temp64 &= ~((u64) val64);
1789 writeq(temp64, &bar0->general_int_mask);
1790 /* writing 0 Enables all 8 RX interrupt levels */
1791 writeq(0x0, &bar0->rx_traffic_mask);
1792 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001793 /*
1794 * Disable Rx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 * register.
1796 */
1797 writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask);
1798 temp64 = readq(&bar0->general_int_mask);
1799 val64 |= temp64;
1800 writeq(val64, &bar0->general_int_mask);
1801 }
1802 }
1803}
1804
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001805/**
1806 * verify_pcc_quiescent- Checks for PCC quiescent state
1807 * Return: 1 If PCC is quiescence
1808 * 0 If PCC is not quiescence
1809 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001810static int verify_pcc_quiescent(struct s2io_nic *sp, int flag)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001811{
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001812 int ret = 0, herc;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001813 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001814 u64 val64 = readq(&bar0->adapter_status);
1815
1816 herc = (sp->device_type == XFRAME_II_DEVICE);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001817
1818 if (flag == FALSE) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001819 if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
1820 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001821 ret = 1;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001822 } else {
1823 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001824 ret = 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001825 }
1826 } else {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001827 if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001828 if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001829 ADAPTER_STATUS_RMAC_PCC_IDLE))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001830 ret = 1;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001831 } else {
1832 if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001833 ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001834 ret = 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001835 }
1836 }
1837
1838 return ret;
1839}
1840/**
1841 * verify_xena_quiescence - Checks whether the H/W is ready
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 * Description: Returns whether the H/W is ready to go or not. Depending
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001843 * on whether adapter enable bit was written or not the comparison
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 * differs and the calling function passes the input argument flag to
1845 * indicate this.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001846 * Return: 1 If xena is quiescence
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 * 0 If Xena is not quiescence
1848 */
1849
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001850static int verify_xena_quiescence(struct s2io_nic *sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851{
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001852 int mode;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001853 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001854 u64 val64 = readq(&bar0->adapter_status);
1855 mode = s2io_verify_pci_mode(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001857 if (!(val64 & ADAPTER_STATUS_TDMA_READY)) {
1858 DBG_PRINT(ERR_DBG, "%s", "TDMA is not ready!");
1859 return 0;
1860 }
1861 if (!(val64 & ADAPTER_STATUS_RDMA_READY)) {
1862 DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!");
1863 return 0;
1864 }
1865 if (!(val64 & ADAPTER_STATUS_PFC_READY)) {
1866 DBG_PRINT(ERR_DBG, "%s", "PFC is not ready!");
1867 return 0;
1868 }
1869 if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) {
1870 DBG_PRINT(ERR_DBG, "%s", "TMAC BUF is not empty!");
1871 return 0;
1872 }
1873 if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) {
1874 DBG_PRINT(ERR_DBG, "%s", "PIC is not QUIESCENT!");
1875 return 0;
1876 }
1877 if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) {
1878 DBG_PRINT(ERR_DBG, "%s", "MC_DRAM is not ready!");
1879 return 0;
1880 }
1881 if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) {
1882 DBG_PRINT(ERR_DBG, "%s", "MC_QUEUES is not ready!");
1883 return 0;
1884 }
1885 if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) {
1886 DBG_PRINT(ERR_DBG, "%s", "M_PLL is not locked!");
1887 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 }
1889
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001890 /*
1891 * In PCI 33 mode, the P_PLL is not used, and therefore,
1892 * the the P_PLL_LOCK bit in the adapter_status register will
1893 * not be asserted.
1894 */
1895 if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) &&
1896 sp->device_type == XFRAME_II_DEVICE && mode !=
1897 PCI_MODE_PCI_33) {
1898 DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!");
1899 return 0;
1900 }
1901 if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1902 ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
1903 DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!");
1904 return 0;
1905 }
1906 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907}
1908
1909/**
1910 * fix_mac_address - Fix for Mac addr problem on Alpha platforms
1911 * @sp: Pointer to device specifc structure
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001912 * Description :
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 * New procedure to clear mac address reading problems on Alpha platforms
1914 *
1915 */
1916
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001917static void fix_mac_address(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001919 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 u64 val64;
1921 int i = 0;
1922
1923 while (fix_mac[i] != END_SIGN) {
1924 writeq(fix_mac[i++], &bar0->gpio_control);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001925 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 val64 = readq(&bar0->gpio_control);
1927 }
1928}
1929
1930/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001931 * start_nic - Turns the device on
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001933 * Description:
1934 * This function actually turns the device on. Before this function is
1935 * called,all Registers are configured from their reset states
1936 * and shared memory is allocated but the NIC is still quiescent. On
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 * calling this function, the device interrupts are cleared and the NIC is
1938 * literally switched on by writing into the adapter control register.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001939 * Return Value:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 * SUCCESS on success and -1 on failure.
1941 */
1942
1943static int start_nic(struct s2io_nic *nic)
1944{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001945 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 struct net_device *dev = nic->dev;
1947 register u64 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001948 u16 subid, i;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001949 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 struct config_param *config;
1951
1952 mac_control = &nic->mac_control;
1953 config = &nic->config;
1954
1955 /* PRC Initialization and configuration */
1956 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001957 writeq((u64) mac_control->rings[i].rx_blocks[0].block_dma_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 &bar0->prc_rxd0_n[i]);
1959
1960 val64 = readq(&bar0->prc_ctrl_n[i]);
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001961 if (nic->config.bimodal)
1962 val64 |= PRC_CTRL_BIMODAL_INTERRUPT;
Ananda Rajuda6971d2005-10-31 16:55:31 -05001963 if (nic->rxd_mode == RXD_MODE_1)
1964 val64 |= PRC_CTRL_RC_ENABLED;
1965 else
1966 val64 |= PRC_CTRL_RC_ENABLED | PRC_CTRL_RING_MODE_3;
Ananda Raju863c11a2006-04-21 19:03:13 -04001967 if (nic->device_type == XFRAME_II_DEVICE)
1968 val64 |= PRC_CTRL_GROUP_READS;
1969 val64 &= ~PRC_CTRL_RXD_BACKOFF_INTERVAL(0xFFFFFF);
1970 val64 |= PRC_CTRL_RXD_BACKOFF_INTERVAL(0x1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 writeq(val64, &bar0->prc_ctrl_n[i]);
1972 }
1973
Ananda Rajuda6971d2005-10-31 16:55:31 -05001974 if (nic->rxd_mode == RXD_MODE_3B) {
1975 /* Enabling 2 buffer mode by writing into Rx_pa_cfg reg. */
1976 val64 = readq(&bar0->rx_pa_cfg);
1977 val64 |= RX_PA_CFG_IGNORE_L2_ERR;
1978 writeq(val64, &bar0->rx_pa_cfg);
1979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
Sivakumar Subramani926930b2007-02-24 01:59:39 -05001981 if (vlan_tag_strip == 0) {
1982 val64 = readq(&bar0->rx_pa_cfg);
1983 val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG;
1984 writeq(val64, &bar0->rx_pa_cfg);
1985 vlan_strip_flag = 0;
1986 }
1987
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001988 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 * Enabling MC-RLDRAM. After enabling the device, we timeout
1990 * for around 100ms, which is approximately the time required
1991 * for the device to be ready for operation.
1992 */
1993 val64 = readq(&bar0->mc_rldram_mrs);
1994 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE | MC_RLDRAM_MRS_ENABLE;
1995 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
1996 val64 = readq(&bar0->mc_rldram_mrs);
1997
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001998 msleep(100); /* Delay by around 100 ms. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999
2000 /* Enabling ECC Protection. */
2001 val64 = readq(&bar0->adapter_control);
2002 val64 &= ~ADAPTER_ECC_EN;
2003 writeq(val64, &bar0->adapter_control);
2004
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002005 /*
2006 * Clearing any possible Link state change interrupts that
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 * could have popped up just before Enabling the card.
2008 */
2009 val64 = readq(&bar0->mac_rmac_err_reg);
2010 if (val64)
2011 writeq(val64, &bar0->mac_rmac_err_reg);
2012
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002013 /*
2014 * Verify if the device is ready to be enabled, if so enable
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 * it.
2016 */
2017 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002018 if (!verify_xena_quiescence(nic)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name);
2020 DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n",
2021 (unsigned long long) val64);
2022 return FAILURE;
2023 }
2024
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002025 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 * With some switches, link might be already up at this point.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002027 * Because of this weird behavior, when we enable laser,
2028 * we may not get link. We need to handle this. We cannot
2029 * figure out which switch is misbehaving. So we are forced to
2030 * make a global change.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 */
2032
2033 /* Enabling Laser. */
2034 val64 = readq(&bar0->adapter_control);
2035 val64 |= ADAPTER_EOI_TX_ON;
2036 writeq(val64, &bar0->adapter_control);
2037
Ananda Rajuc92ca042006-04-21 19:18:03 -04002038 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
2039 /*
2040 * Dont see link state interrupts initally on some switches,
2041 * so directly scheduling the link state task here.
2042 */
2043 schedule_work(&nic->set_link_task);
2044 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 /* SXE-002: Initialize link and activity LED */
2046 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07002047 if (((subid & 0xFF) >= 0x07) &&
2048 (nic->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 val64 = readq(&bar0->gpio_control);
2050 val64 |= 0x0000800000000000ULL;
2051 writeq(val64, &bar0->gpio_control);
2052 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01002053 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 }
2055
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 return SUCCESS;
2057}
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002058/**
2059 * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb
2060 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002061static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \
2062 TxD *txdlp, int get_off)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002063{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002064 struct s2io_nic *nic = fifo_data->nic;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002065 struct sk_buff *skb;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002066 struct TxD *txds;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002067 u16 j, frg_cnt;
2068
2069 txds = txdlp;
Andrew Morton26b76252005-12-14 19:25:23 -08002070 if (txds->Host_Control == (u64)(long)nic->ufo_in_band_v) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002071 pci_unmap_single(nic->pdev, (dma_addr_t)
2072 txds->Buffer_Pointer, sizeof(u64),
2073 PCI_DMA_TODEVICE);
2074 txds++;
2075 }
2076
2077 skb = (struct sk_buff *) ((unsigned long)
2078 txds->Host_Control);
2079 if (!skb) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002080 memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds));
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002081 return NULL;
2082 }
2083 pci_unmap_single(nic->pdev, (dma_addr_t)
2084 txds->Buffer_Pointer,
2085 skb->len - skb->data_len,
2086 PCI_DMA_TODEVICE);
2087 frg_cnt = skb_shinfo(skb)->nr_frags;
2088 if (frg_cnt) {
2089 txds++;
2090 for (j = 0; j < frg_cnt; j++, txds++) {
2091 skb_frag_t *frag = &skb_shinfo(skb)->frags[j];
2092 if (!txds->Buffer_Pointer)
2093 break;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002094 pci_unmap_page(nic->pdev, (dma_addr_t)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002095 txds->Buffer_Pointer,
2096 frag->size, PCI_DMA_TODEVICE);
2097 }
2098 }
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002099 memset(txdlp,0, (sizeof(struct TxD) * fifo_data->max_txds));
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002100 return(skb);
2101}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002103/**
2104 * free_tx_buffers - Free all queued Tx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002106 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 * Free all queued Tx buffers.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002108 * Return Value: void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109*/
2110
2111static void free_tx_buffers(struct s2io_nic *nic)
2112{
2113 struct net_device *dev = nic->dev;
2114 struct sk_buff *skb;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002115 struct TxD *txdp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 int i, j;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002117 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 struct config_param *config;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002119 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120
2121 mac_control = &nic->mac_control;
2122 config = &nic->config;
2123
2124 for (i = 0; i < config->tx_fifo_num; i++) {
2125 for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002126 txdp = (struct TxD *) mac_control->fifos[i].list_info[j].
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 list_virt_addr;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002128 skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
2129 if (skb) {
2130 dev_kfree_skb(skb);
2131 cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 }
2134 DBG_PRINT(INTR_DBG,
2135 "%s:forcibly freeing %d skbs on FIFO%d\n",
2136 dev->name, cnt, i);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002137 mac_control->fifos[i].tx_curr_get_info.offset = 0;
2138 mac_control->fifos[i].tx_curr_put_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 }
2140}
2141
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002142/**
2143 * stop_nic - To stop the nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 * @nic ; device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002145 * Description:
2146 * This function does exactly the opposite of what the start_nic()
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 * function does. This function is called to stop the device.
2148 * Return Value:
2149 * void.
2150 */
2151
2152static void stop_nic(struct s2io_nic *nic)
2153{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002154 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 register u64 val64 = 0;
Ananda Raju5d3213c2006-04-21 19:23:26 -04002156 u16 interruptible;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002157 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 struct config_param *config;
2159
2160 mac_control = &nic->mac_control;
2161 config = &nic->config;
2162
2163 /* Disable all interrupts */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002164 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07002165 interruptible |= TX_PIC_INTR | RX_PIC_INTR;
2166 interruptible |= TX_MAC_INTR | RX_MAC_INTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
2168
Ananda Raju5d3213c2006-04-21 19:23:26 -04002169 /* Clearing Adapter_En bit of ADAPTER_CONTROL Register */
2170 val64 = readq(&bar0->adapter_control);
2171 val64 &= ~(ADAPTER_CNTL_EN);
2172 writeq(val64, &bar0->adapter_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173}
2174
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002175static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \
2176 sk_buff *skb)
Ananda Rajuda6971d2005-10-31 16:55:31 -05002177{
2178 struct net_device *dev = nic->dev;
2179 struct sk_buff *frag_list;
Jeff Garzik50eb8002005-11-05 23:40:46 -05002180 void *tmp;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002181
2182 /* Buffer-1 receives L3/L4 headers */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002183 ((struct RxD3*)rxdp)->Buffer1_ptr = pci_map_single
Ananda Rajuda6971d2005-10-31 16:55:31 -05002184 (nic->pdev, skb->data, l3l4hdr_size + 4,
2185 PCI_DMA_FROMDEVICE);
2186
2187 /* skb_shinfo(skb)->frag_list will have L4 data payload */
2188 skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE);
2189 if (skb_shinfo(skb)->frag_list == NULL) {
2190 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
2191 return -ENOMEM ;
2192 }
2193 frag_list = skb_shinfo(skb)->frag_list;
Sivakumar Subramani372cc592007-01-31 13:32:57 -05002194 skb->truesize += frag_list->truesize;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002195 frag_list->next = NULL;
Jeff Garzik50eb8002005-11-05 23:40:46 -05002196 tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
2197 frag_list->data = tmp;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07002198 skb_reset_tail_pointer(frag_list);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002199
2200 /* Buffer-2 receives L4 data payload */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002201 ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002202 frag_list->data, dev->mtu,
2203 PCI_DMA_FROMDEVICE);
2204 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
2205 rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
2206
2207 return SUCCESS;
2208}
2209
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002210/**
2211 * fill_rx_buffers - Allocates the Rx side skbs
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002213 * @ring_no: ring number
2214 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 * The function allocates Rx side skbs and puts the physical
2216 * address of these buffers into the RxD buffer pointers, so that the NIC
2217 * can DMA the received frame into these locations.
2218 * The NIC supports 3 receive modes, viz
2219 * 1. single buffer,
2220 * 2. three buffer and
2221 * 3. Five buffer modes.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002222 * Each mode defines how many fragments the received frame will be split
2223 * up into by the NIC. The frame is split into L3 header, L4 Header,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 * L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself
2225 * is split into 3 fragments. As of now only single buffer mode is
2226 * supported.
2227 * Return Value:
2228 * SUCCESS on success or an appropriate -ve value on failure.
2229 */
2230
Adrian Bunkac1f60d2005-11-06 01:46:47 +01002231static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232{
2233 struct net_device *dev = nic->dev;
2234 struct sk_buff *skb;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002235 struct RxD_t *rxdp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 int off, off1, size, block_no, block_no1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 u32 alloc_tab = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002238 u32 alloc_cnt;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002239 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 struct config_param *config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002241 u64 tmp;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002242 struct buffAdd *ba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 unsigned long flags;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002244 struct RxD_t *first_rxdp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245
2246 mac_control = &nic->mac_control;
2247 config = &nic->config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002248 alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
2249 atomic_read(&nic->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
Ananda Raju5d3213c2006-04-21 19:23:26 -04002251 block_no1 = mac_control->rings[ring_no].rx_curr_get_info.block_index;
Ananda Raju863c11a2006-04-21 19:03:13 -04002252 off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 while (alloc_tab < alloc_cnt) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002254 block_no = mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 block_index;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002256 off = mac_control->rings[ring_no].rx_curr_put_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
Ananda Rajuda6971d2005-10-31 16:55:31 -05002258 rxdp = mac_control->rings[ring_no].
2259 rx_blocks[block_no].rxds[off].virt_addr;
2260
2261 if ((block_no == block_no1) && (off == off1) &&
2262 (rxdp->Host_Control)) {
2263 DBG_PRINT(INTR_DBG, "%s: Get and Put",
2264 dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 DBG_PRINT(INTR_DBG, " info equated\n");
2266 goto end;
2267 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002268 if (off && (off == rxd_count[nic->rxd_mode])) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002269 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 block_index++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002271 if (mac_control->rings[ring_no].rx_curr_put_info.
2272 block_index == mac_control->rings[ring_no].
2273 block_count)
2274 mac_control->rings[ring_no].rx_curr_put_info.
2275 block_index = 0;
2276 block_no = mac_control->rings[ring_no].
2277 rx_curr_put_info.block_index;
2278 if (off == rxd_count[nic->rxd_mode])
2279 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002280 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002281 offset = off;
2282 rxdp = mac_control->rings[ring_no].
2283 rx_blocks[block_no].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
2285 dev->name, rxdp);
2286 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002287 if(!napi) {
2288 spin_lock_irqsave(&nic->put_lock, flags);
2289 mac_control->rings[ring_no].put_pos =
2290 (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
2291 spin_unlock_irqrestore(&nic->put_lock, flags);
2292 } else {
2293 mac_control->rings[ring_no].put_pos =
2294 (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
2295 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002296 if ((rxdp->Control_1 & RXD_OWN_XENA) &&
2297 ((nic->rxd_mode >= RXD_MODE_3A) &&
2298 (rxdp->Control_2 & BIT(0)))) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002299 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002300 offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 goto end;
2302 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002303 /* calculate size of skb based on ring mode */
2304 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
2305 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
2306 if (nic->rxd_mode == RXD_MODE_1)
2307 size += NET_IP_ALIGN;
2308 else if (nic->rxd_mode == RXD_MODE_3B)
2309 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
2310 else
2311 size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312
Ananda Rajuda6971d2005-10-31 16:55:31 -05002313 /* allocate skb */
2314 skb = dev_alloc_skb(size);
2315 if(!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
2317 DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002318 if (first_rxdp) {
2319 wmb();
2320 first_rxdp->Control_1 |= RXD_OWN_XENA;
2321 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002322 return -ENOMEM ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002324 if (nic->rxd_mode == RXD_MODE_1) {
2325 /* 1 buffer mode - normal operation mode */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002326 memset(rxdp, 0, sizeof(struct RxD1));
Ananda Rajuda6971d2005-10-31 16:55:31 -05002327 skb_reserve(skb, NET_IP_ALIGN);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002328 ((struct RxD1*)rxdp)->Buffer0_ptr = pci_map_single
Ananda Raju863c11a2006-04-21 19:03:13 -04002329 (nic->pdev, skb->data, size - NET_IP_ALIGN,
2330 PCI_DMA_FROMDEVICE);
2331 rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002332
2333 } else if (nic->rxd_mode >= RXD_MODE_3A) {
2334 /*
2335 * 2 or 3 buffer mode -
2336 * Both 2 buffer mode and 3 buffer mode provides 128
2337 * byte aligned receive buffers.
2338 *
2339 * 3 buffer mode provides header separation where in
2340 * skb->data will have L3/L4 headers where as
2341 * skb_shinfo(skb)->frag_list will have the L4 data
2342 * payload
2343 */
2344
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002345 memset(rxdp, 0, sizeof(struct RxD3));
Ananda Rajuda6971d2005-10-31 16:55:31 -05002346 ba = &mac_control->rings[ring_no].ba[block_no][off];
2347 skb_reserve(skb, BUF0_LEN);
2348 tmp = (u64)(unsigned long) skb->data;
2349 tmp += ALIGN_SIZE;
2350 tmp &= ~ALIGN_SIZE;
2351 skb->data = (void *) (unsigned long)tmp;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07002352 skb_reset_tail_pointer(skb);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002353
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002354 if (!(((struct RxD3*)rxdp)->Buffer0_ptr))
2355 ((struct RxD3*)rxdp)->Buffer0_ptr =
Ananda Raju75c30b12006-07-24 19:55:09 -04002356 pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002357 PCI_DMA_FROMDEVICE);
Ananda Raju75c30b12006-07-24 19:55:09 -04002358 else
2359 pci_dma_sync_single_for_device(nic->pdev,
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002360 (dma_addr_t) ((struct RxD3*)rxdp)->Buffer0_ptr,
Ananda Raju75c30b12006-07-24 19:55:09 -04002361 BUF0_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002362 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
2363 if (nic->rxd_mode == RXD_MODE_3B) {
2364 /* Two buffer mode */
2365
2366 /*
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002367 * Buffer2 will have L3/L4 header plus
Ananda Rajuda6971d2005-10-31 16:55:31 -05002368 * L4 payload
2369 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002370 ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single
Ananda Rajuda6971d2005-10-31 16:55:31 -05002371 (nic->pdev, skb->data, dev->mtu + 4,
2372 PCI_DMA_FROMDEVICE);
2373
Ananda Raju75c30b12006-07-24 19:55:09 -04002374 /* Buffer-1 will be dummy buffer. Not used */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002375 if (!(((struct RxD3*)rxdp)->Buffer1_ptr)) {
2376 ((struct RxD3*)rxdp)->Buffer1_ptr =
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002377 pci_map_single(nic->pdev,
Ananda Raju75c30b12006-07-24 19:55:09 -04002378 ba->ba_1, BUF1_LEN,
2379 PCI_DMA_FROMDEVICE);
2380 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002381 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
2382 rxdp->Control_2 |= SET_BUFFER2_SIZE_3
2383 (dev->mtu + 4);
2384 } else {
2385 /* 3 buffer mode */
2386 if (fill_rxd_3buf(nic, rxdp, skb) == -ENOMEM) {
2387 dev_kfree_skb_irq(skb);
2388 if (first_rxdp) {
2389 wmb();
2390 first_rxdp->Control_1 |=
2391 RXD_OWN_XENA;
2392 }
2393 return -ENOMEM ;
2394 }
2395 }
2396 rxdp->Control_2 |= BIT(0);
2397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 rxdp->Host_Control = (unsigned long) (skb);
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002399 if (alloc_tab & ((1 << rxsync_frequency) - 1))
2400 rxdp->Control_1 |= RXD_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 off++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002402 if (off == (rxd_count[nic->rxd_mode] + 1))
2403 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002404 mac_control->rings[ring_no].rx_curr_put_info.offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002406 rxdp->Control_2 |= SET_RXD_MARKER;
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002407 if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
2408 if (first_rxdp) {
2409 wmb();
2410 first_rxdp->Control_1 |= RXD_OWN_XENA;
2411 }
2412 first_rxdp = rxdp;
2413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 atomic_inc(&nic->rx_bufs_left[ring_no]);
2415 alloc_tab++;
2416 }
2417
2418 end:
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002419 /* Transfer ownership of first descriptor to adapter just before
2420 * exiting. Before that, use memory barrier so that ownership
2421 * and other fields are seen by adapter correctly.
2422 */
2423 if (first_rxdp) {
2424 wmb();
2425 first_rxdp->Control_1 |= RXD_OWN_XENA;
2426 }
2427
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 return SUCCESS;
2429}
2430
Ananda Rajuda6971d2005-10-31 16:55:31 -05002431static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
2432{
2433 struct net_device *dev = sp->dev;
2434 int j;
2435 struct sk_buff *skb;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002436 struct RxD_t *rxdp;
2437 struct mac_info *mac_control;
2438 struct buffAdd *ba;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002439
2440 mac_control = &sp->mac_control;
2441 for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
2442 rxdp = mac_control->rings[ring_no].
2443 rx_blocks[blk].rxds[j].virt_addr;
2444 skb = (struct sk_buff *)
2445 ((unsigned long) rxdp->Host_Control);
2446 if (!skb) {
2447 continue;
2448 }
2449 if (sp->rxd_mode == RXD_MODE_1) {
2450 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002451 ((struct RxD1*)rxdp)->Buffer0_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002452 dev->mtu +
2453 HEADER_ETHERNET_II_802_3_SIZE
2454 + HEADER_802_2_SIZE +
2455 HEADER_SNAP_SIZE,
2456 PCI_DMA_FROMDEVICE);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002457 memset(rxdp, 0, sizeof(struct RxD1));
Ananda Rajuda6971d2005-10-31 16:55:31 -05002458 } else if(sp->rxd_mode == RXD_MODE_3B) {
2459 ba = &mac_control->rings[ring_no].
2460 ba[blk][j];
2461 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002462 ((struct RxD3*)rxdp)->Buffer0_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002463 BUF0_LEN,
2464 PCI_DMA_FROMDEVICE);
2465 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002466 ((struct RxD3*)rxdp)->Buffer1_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002467 BUF1_LEN,
2468 PCI_DMA_FROMDEVICE);
2469 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002470 ((struct RxD3*)rxdp)->Buffer2_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002471 dev->mtu + 4,
2472 PCI_DMA_FROMDEVICE);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002473 memset(rxdp, 0, sizeof(struct RxD3));
Ananda Rajuda6971d2005-10-31 16:55:31 -05002474 } else {
2475 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002476 ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002477 PCI_DMA_FROMDEVICE);
2478 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002479 ((struct RxD3*)rxdp)->Buffer1_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002480 l3l4hdr_size + 4,
2481 PCI_DMA_FROMDEVICE);
2482 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002483 ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002484 PCI_DMA_FROMDEVICE);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002485 memset(rxdp, 0, sizeof(struct RxD3));
Ananda Rajuda6971d2005-10-31 16:55:31 -05002486 }
2487 dev_kfree_skb(skb);
2488 atomic_dec(&sp->rx_bufs_left[ring_no]);
2489 }
2490}
2491
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002493 * free_rx_buffers - Frees all Rx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 * @sp: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002495 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 * This function will free all Rx buffers allocated by host.
2497 * Return Value:
2498 * NONE.
2499 */
2500
2501static void free_rx_buffers(struct s2io_nic *sp)
2502{
2503 struct net_device *dev = sp->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002504 int i, blk = 0, buf_cnt = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002505 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 struct config_param *config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507
2508 mac_control = &sp->mac_control;
2509 config = &sp->config;
2510
2511 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -05002512 for (blk = 0; blk < rx_ring_sz[i]; blk++)
2513 free_rxd_blk(sp,i,blk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002515 mac_control->rings[i].rx_curr_put_info.block_index = 0;
2516 mac_control->rings[i].rx_curr_get_info.block_index = 0;
2517 mac_control->rings[i].rx_curr_put_info.offset = 0;
2518 mac_control->rings[i].rx_curr_get_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 atomic_set(&sp->rx_bufs_left[i], 0);
2520 DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
2521 dev->name, buf_cnt, i);
2522 }
2523}
2524
2525/**
2526 * s2io_poll - Rx interrupt handler for NAPI support
2527 * @dev : pointer to the device structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002528 * @budget : The number of packets that were budgeted to be processed
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 * during one pass through the 'Poll" function.
2530 * Description:
2531 * Comes into picture only if NAPI support has been incorporated. It does
2532 * the same thing that rx_intr_handler does, but not in a interrupt context
2533 * also It will process only a given number of packets.
2534 * Return value:
2535 * 0 on success and 1 if there are No Rx packets to be processed.
2536 */
2537
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538static int s2io_poll(struct net_device *dev, int *budget)
2539{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002540 struct s2io_nic *nic = dev->priv;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002541 int pkt_cnt = 0, org_pkts_to_process;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002542 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 struct config_param *config;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002544 struct XENA_dev_config __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002545 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002547 atomic_inc(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 mac_control = &nic->mac_control;
2549 config = &nic->config;
2550
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002551 nic->pkts_to_process = *budget;
2552 if (nic->pkts_to_process > dev->quota)
2553 nic->pkts_to_process = dev->quota;
2554 org_pkts_to_process = nic->pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002556 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
2557 readl(&bar0->rx_traffic_int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558
2559 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002560 rx_intr_handler(&mac_control->rings[i]);
2561 pkt_cnt = org_pkts_to_process - nic->pkts_to_process;
2562 if (!nic->pkts_to_process) {
2563 /* Quota for the current iteration has been met */
2564 goto no_rx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 }
2567 if (!pkt_cnt)
2568 pkt_cnt = 1;
2569
2570 dev->quota -= pkt_cnt;
2571 *budget -= pkt_cnt;
2572 netif_rx_complete(dev);
2573
2574 for (i = 0; i < config->rx_ring_num; i++) {
2575 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2576 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2577 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2578 break;
2579 }
2580 }
2581 /* Re enable the Rx interrupts. */
Ananda Rajuc92ca042006-04-21 19:18:03 -04002582 writeq(0x0, &bar0->rx_traffic_mask);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002583 readl(&bar0->rx_traffic_mask);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002584 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 return 0;
2586
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002587no_rx:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 dev->quota -= pkt_cnt;
2589 *budget -= pkt_cnt;
2590
2591 for (i = 0; i < config->rx_ring_num; i++) {
2592 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2593 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2594 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2595 break;
2596 }
2597 }
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002598 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 return 1;
2600}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002601
Ananda Rajub41477f2006-07-24 19:52:49 -04002602#ifdef CONFIG_NET_POLL_CONTROLLER
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002603/**
Ananda Rajub41477f2006-07-24 19:52:49 -04002604 * s2io_netpoll - netpoll event handler entry point
Brian Haley612eff02006-06-15 14:36:36 -04002605 * @dev : pointer to the device structure.
2606 * Description:
Ananda Rajub41477f2006-07-24 19:52:49 -04002607 * This function will be called by upper layer to check for events on the
2608 * interface in situations where interrupts are disabled. It is used for
2609 * specific in-kernel networking tasks, such as remote consoles and kernel
2610 * debugging over the network (example netdump in RedHat).
Brian Haley612eff02006-06-15 14:36:36 -04002611 */
Brian Haley612eff02006-06-15 14:36:36 -04002612static void s2io_netpoll(struct net_device *dev)
2613{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002614 struct s2io_nic *nic = dev->priv;
2615 struct mac_info *mac_control;
Brian Haley612eff02006-06-15 14:36:36 -04002616 struct config_param *config;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002617 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ananda Rajub41477f2006-07-24 19:52:49 -04002618 u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
Brian Haley612eff02006-06-15 14:36:36 -04002619 int i;
2620
2621 disable_irq(dev->irq);
2622
2623 atomic_inc(&nic->isr_cnt);
2624 mac_control = &nic->mac_control;
2625 config = &nic->config;
2626
Brian Haley612eff02006-06-15 14:36:36 -04002627 writeq(val64, &bar0->rx_traffic_int);
Ananda Rajub41477f2006-07-24 19:52:49 -04002628 writeq(val64, &bar0->tx_traffic_int);
Brian Haley612eff02006-06-15 14:36:36 -04002629
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002630 /* we need to free up the transmitted skbufs or else netpoll will
Ananda Rajub41477f2006-07-24 19:52:49 -04002631 * run out of skbs and will fail and eventually netpoll application such
2632 * as netdump will fail.
2633 */
2634 for (i = 0; i < config->tx_fifo_num; i++)
2635 tx_intr_handler(&mac_control->fifos[i]);
2636
2637 /* check for received packet and indicate up to network */
Brian Haley612eff02006-06-15 14:36:36 -04002638 for (i = 0; i < config->rx_ring_num; i++)
2639 rx_intr_handler(&mac_control->rings[i]);
2640
2641 for (i = 0; i < config->rx_ring_num; i++) {
2642 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2643 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2644 DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n");
2645 break;
2646 }
2647 }
2648 atomic_dec(&nic->isr_cnt);
2649 enable_irq(dev->irq);
2650 return;
2651}
2652#endif
2653
2654/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 * rx_intr_handler - Rx interrupt handler
2656 * @nic: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002657 * Description:
2658 * If the interrupt is because of a received frame or if the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 * receive ring contains fresh as yet un-processed frames,this function is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002660 * called. It picks out the RxD at which place the last Rx processing had
2661 * stopped and sends the skb to the OSM's Rx handler and then increments
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 * the offset.
2663 * Return Value:
2664 * NONE.
2665 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002666static void rx_intr_handler(struct ring_info *ring_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002668 struct s2io_nic *nic = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 struct net_device *dev = (struct net_device *) nic->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002670 int get_block, put_block, put_offset;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002671 struct rx_curr_get_info get_info, put_info;
2672 struct RxD_t *rxdp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 struct sk_buff *skb;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002674 int pkt_cnt = 0;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002675 int i;
2676
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002677 spin_lock(&nic->rx_lock);
2678 if (atomic_read(&nic->card_state) == CARD_DOWN) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002679 DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002680 __FUNCTION__, dev->name);
2681 spin_unlock(&nic->rx_lock);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002682 return;
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002683 }
2684
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002685 get_info = ring_data->rx_curr_get_info;
2686 get_block = get_info.block_index;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002687 memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002688 put_block = put_info.block_index;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002689 rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002690 if (!napi) {
2691 spin_lock(&nic->put_lock);
2692 put_offset = ring_data->put_pos;
2693 spin_unlock(&nic->put_lock);
2694 } else
2695 put_offset = ring_data->put_pos;
2696
Ananda Rajuda6971d2005-10-31 16:55:31 -05002697 while (RXD_IS_UP2DT(rxdp)) {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002698 /*
2699 * If your are next to put index then it's
2700 * FIFO full condition
2701 */
Ananda Rajuda6971d2005-10-31 16:55:31 -05002702 if ((get_block == put_block) &&
2703 (get_info.offset + 1) == put_info.offset) {
Ananda Raju75c30b12006-07-24 19:55:09 -04002704 DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002705 break;
2706 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002707 skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
2708 if (skb == NULL) {
2709 DBG_PRINT(ERR_DBG, "%s: The skb is ",
2710 dev->name);
2711 DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002712 spin_unlock(&nic->rx_lock);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002713 return;
2714 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002715 if (nic->rxd_mode == RXD_MODE_1) {
2716 pci_unmap_single(nic->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002717 ((struct RxD1*)rxdp)->Buffer0_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002718 dev->mtu +
2719 HEADER_ETHERNET_II_802_3_SIZE +
2720 HEADER_802_2_SIZE +
2721 HEADER_SNAP_SIZE,
2722 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002723 } else if (nic->rxd_mode == RXD_MODE_3B) {
Ananda Raju75c30b12006-07-24 19:55:09 -04002724 pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002725 ((struct RxD3*)rxdp)->Buffer0_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002726 BUF0_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002727 pci_unmap_single(nic->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002728 ((struct RxD3*)rxdp)->Buffer2_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002729 dev->mtu + 4,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002730 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002731 } else {
Ananda Raju75c30b12006-07-24 19:55:09 -04002732 pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002733 ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002734 PCI_DMA_FROMDEVICE);
2735 pci_unmap_single(nic->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002736 ((struct RxD3*)rxdp)->Buffer1_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002737 l3l4hdr_size + 4,
2738 PCI_DMA_FROMDEVICE);
2739 pci_unmap_single(nic->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002740 ((struct RxD3*)rxdp)->Buffer2_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002741 dev->mtu, PCI_DMA_FROMDEVICE);
2742 }
Ananda Raju863c11a2006-04-21 19:03:13 -04002743 prefetch(skb->data);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002744 rx_osm_handler(ring_data, rxdp);
2745 get_info.offset++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002746 ring_data->rx_curr_get_info.offset = get_info.offset;
2747 rxdp = ring_data->rx_blocks[get_block].
2748 rxds[get_info.offset].virt_addr;
2749 if (get_info.offset == rxd_count[nic->rxd_mode]) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002750 get_info.offset = 0;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002751 ring_data->rx_curr_get_info.offset = get_info.offset;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002752 get_block++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002753 if (get_block == ring_data->block_count)
2754 get_block = 0;
2755 ring_data->rx_curr_get_info.block_index = get_block;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002756 rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
2757 }
2758
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002759 nic->pkts_to_process -= 1;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002760 if ((napi) && (!nic->pkts_to_process))
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002761 break;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002762 pkt_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
2764 break;
2765 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002766 if (nic->lro) {
2767 /* Clear all LRO sessions before exiting */
2768 for (i=0; i<MAX_LRO_SESSIONS; i++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002769 struct lro *lro = &nic->lro0_n[i];
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002770 if (lro->in_use) {
2771 update_L3L4_header(nic, lro);
2772 queue_rx_frame(lro->parent);
2773 clear_lro_session(lro);
2774 }
2775 }
2776 }
2777
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002778 spin_unlock(&nic->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002780
2781/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 * tx_intr_handler - Transmit interrupt handler
2783 * @nic : device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002784 * Description:
2785 * If an interrupt was raised to indicate DMA complete of the
2786 * Tx packet, this function is called. It identifies the last TxD
2787 * whose buffer was freed and frees all skbs whose data have already
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 * DMA'ed into the NICs internal memory.
2789 * Return Value:
2790 * NONE
2791 */
2792
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002793static void tx_intr_handler(struct fifo_info *fifo_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002795 struct s2io_nic *nic = fifo_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 struct net_device *dev = (struct net_device *) nic->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002797 struct tx_curr_get_info get_info, put_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 struct sk_buff *skb;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002799 struct TxD *txdlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002801 get_info = fifo_data->tx_curr_get_info;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002802 memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info));
2803 txdlp = (struct TxD *) fifo_data->list_info[get_info.offset].
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002804 list_virt_addr;
2805 while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
2806 (get_info.offset != put_info.offset) &&
2807 (txdlp->Host_Control)) {
2808 /* Check for TxD errors */
2809 if (txdlp->Control_1 & TXD_T_CODE) {
2810 unsigned long long err;
2811 err = txdlp->Control_1 & TXD_T_CODE;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002812 if (err & 0x1) {
2813 nic->mac_control.stats_info->sw_stat.
2814 parity_err_cnt++;
2815 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002816 if ((err >> 48) == 0xA) {
2817 DBG_PRINT(TX_DBG, "TxD returned due \
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002818 to loss of link\n");
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002819 }
2820 else {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002821 DBG_PRINT(ERR_DBG, "***TxD error %llx\n", err);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002822 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002824
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002825 skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002826 if (skb == NULL) {
2827 DBG_PRINT(ERR_DBG, "%s: Null skb ",
2828 __FUNCTION__);
2829 DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
2830 return;
2831 }
2832
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002833 /* Updating the statistics block */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002834 nic->stats.tx_bytes += skb->len;
2835 dev_kfree_skb_irq(skb);
2836
2837 get_info.offset++;
Ananda Raju863c11a2006-04-21 19:03:13 -04002838 if (get_info.offset == get_info.fifo_len + 1)
2839 get_info.offset = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002840 txdlp = (struct TxD *) fifo_data->list_info
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002841 [get_info.offset].list_virt_addr;
2842 fifo_data->tx_curr_get_info.offset =
2843 get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 }
2845
2846 spin_lock(&nic->tx_lock);
2847 if (netif_queue_stopped(dev))
2848 netif_wake_queue(dev);
2849 spin_unlock(&nic->tx_lock);
2850}
2851
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002852/**
Ananda Rajubd1034f2006-04-21 19:20:22 -04002853 * s2io_mdio_write - Function to write in to MDIO registers
2854 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
2855 * @addr : address value
2856 * @value : data value
2857 * @dev : pointer to net_device structure
2858 * Description:
2859 * This function is used to write values to the MDIO registers
2860 * NONE
2861 */
2862static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
2863{
2864 u64 val64 = 0x0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002865 struct s2io_nic *sp = dev->priv;
2866 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002867
2868 //address transaction
2869 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2870 | MDIO_MMD_DEV_ADDR(mmd_type)
2871 | MDIO_MMS_PRT_ADDR(0x0);
2872 writeq(val64, &bar0->mdio_control);
2873 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2874 writeq(val64, &bar0->mdio_control);
2875 udelay(100);
2876
2877 //Data transaction
2878 val64 = 0x0;
2879 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2880 | MDIO_MMD_DEV_ADDR(mmd_type)
2881 | MDIO_MMS_PRT_ADDR(0x0)
2882 | MDIO_MDIO_DATA(value)
2883 | MDIO_OP(MDIO_OP_WRITE_TRANS);
2884 writeq(val64, &bar0->mdio_control);
2885 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2886 writeq(val64, &bar0->mdio_control);
2887 udelay(100);
2888
2889 val64 = 0x0;
2890 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2891 | MDIO_MMD_DEV_ADDR(mmd_type)
2892 | MDIO_MMS_PRT_ADDR(0x0)
2893 | MDIO_OP(MDIO_OP_READ_TRANS);
2894 writeq(val64, &bar0->mdio_control);
2895 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2896 writeq(val64, &bar0->mdio_control);
2897 udelay(100);
2898
2899}
2900
2901/**
2902 * s2io_mdio_read - Function to write in to MDIO registers
2903 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
2904 * @addr : address value
2905 * @dev : pointer to net_device structure
2906 * Description:
2907 * This function is used to read values to the MDIO registers
2908 * NONE
2909 */
2910static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
2911{
2912 u64 val64 = 0x0;
2913 u64 rval64 = 0x0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002914 struct s2io_nic *sp = dev->priv;
2915 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002916
2917 /* address transaction */
2918 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2919 | MDIO_MMD_DEV_ADDR(mmd_type)
2920 | MDIO_MMS_PRT_ADDR(0x0);
2921 writeq(val64, &bar0->mdio_control);
2922 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2923 writeq(val64, &bar0->mdio_control);
2924 udelay(100);
2925
2926 /* Data transaction */
2927 val64 = 0x0;
2928 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2929 | MDIO_MMD_DEV_ADDR(mmd_type)
2930 | MDIO_MMS_PRT_ADDR(0x0)
2931 | MDIO_OP(MDIO_OP_READ_TRANS);
2932 writeq(val64, &bar0->mdio_control);
2933 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2934 writeq(val64, &bar0->mdio_control);
2935 udelay(100);
2936
2937 /* Read the value from regs */
2938 rval64 = readq(&bar0->mdio_control);
2939 rval64 = rval64 & 0xFFFF0000;
2940 rval64 = rval64 >> 16;
2941 return rval64;
2942}
2943/**
2944 * s2io_chk_xpak_counter - Function to check the status of the xpak counters
2945 * @counter : couter value to be updated
2946 * @flag : flag to indicate the status
2947 * @type : counter type
2948 * Description:
2949 * This function is to check the status of the xpak counters value
2950 * NONE
2951 */
2952
2953static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, u16 flag, u16 type)
2954{
2955 u64 mask = 0x3;
2956 u64 val64;
2957 int i;
2958 for(i = 0; i <index; i++)
2959 mask = mask << 0x2;
2960
2961 if(flag > 0)
2962 {
2963 *counter = *counter + 1;
2964 val64 = *regs_stat & mask;
2965 val64 = val64 >> (index * 0x2);
2966 val64 = val64 + 1;
2967 if(val64 == 3)
2968 {
2969 switch(type)
2970 {
2971 case 1:
2972 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
2973 "service. Excessive temperatures may "
2974 "result in premature transceiver "
2975 "failure \n");
2976 break;
2977 case 2:
2978 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
2979 "service Excessive bias currents may "
2980 "indicate imminent laser diode "
2981 "failure \n");
2982 break;
2983 case 3:
2984 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
2985 "service Excessive laser output "
2986 "power may saturate far-end "
2987 "receiver\n");
2988 break;
2989 default:
2990 DBG_PRINT(ERR_DBG, "Incorrect XPAK Alarm "
2991 "type \n");
2992 }
2993 val64 = 0x0;
2994 }
2995 val64 = val64 << (index * 0x2);
2996 *regs_stat = (*regs_stat & (~mask)) | (val64);
2997
2998 } else {
2999 *regs_stat = *regs_stat & (~mask);
3000 }
3001}
3002
3003/**
3004 * s2io_updt_xpak_counter - Function to update the xpak counters
3005 * @dev : pointer to net_device struct
3006 * Description:
3007 * This function is to upate the status of the xpak counters value
3008 * NONE
3009 */
3010static void s2io_updt_xpak_counter(struct net_device *dev)
3011{
3012 u16 flag = 0x0;
3013 u16 type = 0x0;
3014 u16 val16 = 0x0;
3015 u64 val64 = 0x0;
3016 u64 addr = 0x0;
3017
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003018 struct s2io_nic *sp = dev->priv;
3019 struct stat_block *stat_info = sp->mac_control.stats_info;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003020
3021 /* Check the communication with the MDIO slave */
3022 addr = 0x0000;
3023 val64 = 0x0;
3024 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3025 if((val64 == 0xFFFF) || (val64 == 0x0000))
3026 {
3027 DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - "
3028 "Returned %llx\n", (unsigned long long)val64);
3029 return;
3030 }
3031
3032 /* Check for the expecte value of 2040 at PMA address 0x0000 */
3033 if(val64 != 0x2040)
3034 {
3035 DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - ");
3036 DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x2040\n",
3037 (unsigned long long)val64);
3038 return;
3039 }
3040
3041 /* Loading the DOM register to MDIO register */
3042 addr = 0xA100;
3043 s2io_mdio_write(MDIO_MMD_PMA_DEV_ADDR, addr, val16, dev);
3044 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3045
3046 /* Reading the Alarm flags */
3047 addr = 0xA070;
3048 val64 = 0x0;
3049 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3050
3051 flag = CHECKBIT(val64, 0x7);
3052 type = 1;
3053 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_transceiver_temp_high,
3054 &stat_info->xpak_stat.xpak_regs_stat,
3055 0x0, flag, type);
3056
3057 if(CHECKBIT(val64, 0x6))
3058 stat_info->xpak_stat.alarm_transceiver_temp_low++;
3059
3060 flag = CHECKBIT(val64, 0x3);
3061 type = 2;
3062 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_bias_current_high,
3063 &stat_info->xpak_stat.xpak_regs_stat,
3064 0x2, flag, type);
3065
3066 if(CHECKBIT(val64, 0x2))
3067 stat_info->xpak_stat.alarm_laser_bias_current_low++;
3068
3069 flag = CHECKBIT(val64, 0x1);
3070 type = 3;
3071 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_output_power_high,
3072 &stat_info->xpak_stat.xpak_regs_stat,
3073 0x4, flag, type);
3074
3075 if(CHECKBIT(val64, 0x0))
3076 stat_info->xpak_stat.alarm_laser_output_power_low++;
3077
3078 /* Reading the Warning flags */
3079 addr = 0xA074;
3080 val64 = 0x0;
3081 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3082
3083 if(CHECKBIT(val64, 0x7))
3084 stat_info->xpak_stat.warn_transceiver_temp_high++;
3085
3086 if(CHECKBIT(val64, 0x6))
3087 stat_info->xpak_stat.warn_transceiver_temp_low++;
3088
3089 if(CHECKBIT(val64, 0x3))
3090 stat_info->xpak_stat.warn_laser_bias_current_high++;
3091
3092 if(CHECKBIT(val64, 0x2))
3093 stat_info->xpak_stat.warn_laser_bias_current_low++;
3094
3095 if(CHECKBIT(val64, 0x1))
3096 stat_info->xpak_stat.warn_laser_output_power_high++;
3097
3098 if(CHECKBIT(val64, 0x0))
3099 stat_info->xpak_stat.warn_laser_output_power_low++;
3100}
3101
3102/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 * alarm_intr_handler - Alarm Interrrupt handler
3104 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003105 * Description: If the interrupt was neither because of Rx packet or Tx
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 * complete, this function is called. If the interrupt was to indicate
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003107 * a loss of link, the OSM link status handler is invoked for any other
3108 * alarm interrupt the block that raised the interrupt is displayed
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 * and a H/W reset is issued.
3110 * Return Value:
3111 * NONE
3112*/
3113
3114static void alarm_intr_handler(struct s2io_nic *nic)
3115{
3116 struct net_device *dev = (struct net_device *) nic->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003117 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 register u64 val64 = 0, err_reg = 0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003119 u64 cnt;
3120 int i;
Sivakumar Subramani372cc592007-01-31 13:32:57 -05003121 if (atomic_read(&nic->card_state) == CARD_DOWN)
3122 return;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003123 nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
3124 /* Handling the XPAK counters update */
3125 if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
3126 /* waiting for an hour */
3127 nic->mac_control.stats_info->xpak_stat.xpak_timer_count++;
3128 } else {
3129 s2io_updt_xpak_counter(dev);
3130 /* reset the count to zero */
3131 nic->mac_control.stats_info->xpak_stat.xpak_timer_count = 0;
3132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133
3134 /* Handling link status change error Intr */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07003135 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
3136 err_reg = readq(&bar0->mac_rmac_err_reg);
3137 writeq(err_reg, &bar0->mac_rmac_err_reg);
3138 if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
3139 schedule_work(&nic->set_link_task);
3140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 }
3142
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003143 /* Handling Ecc errors */
3144 val64 = readq(&bar0->mc_err_reg);
3145 writeq(val64, &bar0->mc_err_reg);
3146 if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
3147 if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003148 nic->mac_control.stats_info->sw_stat.
3149 double_ecc_errs++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003150 DBG_PRINT(INIT_DBG, "%s: Device indicates ",
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003151 dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003152 DBG_PRINT(INIT_DBG, "double ECC error!!\n");
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003153 if (nic->device_type != XFRAME_II_DEVICE) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003154 /* Reset XframeI only if critical error */
3155 if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
3156 MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
3157 netif_stop_queue(dev);
3158 schedule_work(&nic->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04003159 nic->mac_control.stats_info->sw_stat.
3160 soft_reset_cnt++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003161 }
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003162 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003163 } else {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003164 nic->mac_control.stats_info->sw_stat.
3165 single_ecc_errs++;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003166 }
3167 }
3168
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 /* In case of a serious error, the device will be Reset. */
3170 val64 = readq(&bar0->serr_source);
3171 if (val64 & SERR_SOURCE_ANY) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04003172 nic->mac_control.stats_info->sw_stat.serious_err_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003174 DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003175 (unsigned long long)val64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 netif_stop_queue(dev);
3177 schedule_work(&nic->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04003178 nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 }
3180
3181 /*
3182 * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
3183 * Error occurs, the adapter will be recycled by disabling the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003184 * adapter enable bit and enabling it again after the device
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 * becomes Quiescent.
3186 */
3187 val64 = readq(&bar0->pcc_err_reg);
3188 writeq(val64, &bar0->pcc_err_reg);
3189 if (val64 & PCC_FB_ECC_DB_ERR) {
3190 u64 ac = readq(&bar0->adapter_control);
3191 ac &= ~(ADAPTER_CNTL_EN);
3192 writeq(ac, &bar0->adapter_control);
3193 ac = readq(&bar0->adapter_control);
3194 schedule_work(&nic->set_link_task);
3195 }
Ananda Rajubd1034f2006-04-21 19:20:22 -04003196 /* Check for data parity error */
3197 val64 = readq(&bar0->pic_int_status);
3198 if (val64 & PIC_INT_GPIO) {
3199 val64 = readq(&bar0->gpio_int_reg);
3200 if (val64 & GPIO_INT_REG_DP_ERR_INT) {
3201 nic->mac_control.stats_info->sw_stat.parity_err_cnt++;
3202 schedule_work(&nic->rst_timer_task);
3203 nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
3204 }
3205 }
3206
3207 /* Check for ring full counter */
3208 if (nic->device_type & XFRAME_II_DEVICE) {
3209 val64 = readq(&bar0->ring_bump_counter1);
3210 for (i=0; i<4; i++) {
3211 cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
3212 cnt >>= 64 - ((i+1)*16);
3213 nic->mac_control.stats_info->sw_stat.ring_full_cnt
3214 += cnt;
3215 }
3216
3217 val64 = readq(&bar0->ring_bump_counter2);
3218 for (i=0; i<4; i++) {
3219 cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
3220 cnt >>= 64 - ((i+1)*16);
3221 nic->mac_control.stats_info->sw_stat.ring_full_cnt
3222 += cnt;
3223 }
3224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225
3226 /* Other type of interrupts are not being handled now, TODO */
3227}
3228
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003229/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 * wait_for_cmd_complete - waits for a command to complete.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003231 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003233 * Description: Function that waits for a command to Write into RMAC
3234 * ADDR DATA registers to be completed and returns either success or
3235 * error depending on whether the command was complete or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 * Return value:
3237 * SUCCESS on success and FAILURE on failure.
3238 */
3239
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003240static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit,
3241 int bit_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242{
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003243 int ret = FAILURE, cnt = 0, delay = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 u64 val64;
3245
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003246 if ((bit_state != S2IO_BIT_RESET) && (bit_state != S2IO_BIT_SET))
3247 return FAILURE;
3248
3249 do {
Ananda Rajuc92ca042006-04-21 19:18:03 -04003250 val64 = readq(addr);
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003251 if (bit_state == S2IO_BIT_RESET) {
3252 if (!(val64 & busy_bit)) {
3253 ret = SUCCESS;
3254 break;
3255 }
3256 } else {
3257 if (!(val64 & busy_bit)) {
3258 ret = SUCCESS;
3259 break;
3260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003262
3263 if(in_interrupt())
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003264 mdelay(delay);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003265 else
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003266 msleep(delay);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003267
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003268 if (++cnt >= 10)
3269 delay = 50;
3270 } while (cnt < 20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 return ret;
3272}
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003273/*
3274 * check_pci_device_id - Checks if the device id is supported
3275 * @id : device id
3276 * Description: Function to check if the pci device id is supported by driver.
3277 * Return value: Actual device id if supported else PCI_ANY_ID
3278 */
3279static u16 check_pci_device_id(u16 id)
3280{
3281 switch (id) {
3282 case PCI_DEVICE_ID_HERC_WIN:
3283 case PCI_DEVICE_ID_HERC_UNI:
3284 return XFRAME_II_DEVICE;
3285 case PCI_DEVICE_ID_S2IO_UNI:
3286 case PCI_DEVICE_ID_S2IO_WIN:
3287 return XFRAME_I_DEVICE;
3288 default:
3289 return PCI_ANY_ID;
3290 }
3291}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003293/**
3294 * s2io_reset - Resets the card.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 * @sp : private member of the device structure.
3296 * Description: Function to Reset the card. This function then also
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003297 * restores the previously saved PCI configuration space registers as
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 * the card reset also resets the configuration space.
3299 * Return value:
3300 * void.
3301 */
3302
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003303static void s2io_reset(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003305 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 u64 val64;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003307 u16 subid, pci_cmd;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003308 int i;
3309 u16 val16;
3310 DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
3311 __FUNCTION__, sp->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003313 /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003314 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003315
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003316 if (sp->device_type == XFRAME_II_DEVICE) {
3317 int ret;
3318 ret = pci_set_power_state(sp->pdev, 3);
3319 if (!ret)
3320 ret = pci_set_power_state(sp->pdev, 0);
3321 else {
3322 DBG_PRINT(ERR_DBG,"%s PME based SW_Reset failed!\n",
3323 __FUNCTION__);
3324 goto old_way;
3325 }
3326 msleep(20);
3327 goto new_way;
3328 }
3329old_way:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 val64 = SW_RESET_ALL;
3331 writeq(val64, &bar0->sw_reset);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003332new_way:
Ananda Rajuc92ca042006-04-21 19:18:03 -04003333 if (strstr(sp->product_name, "CX4")) {
3334 msleep(750);
3335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 msleep(250);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003337 for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) {
3338
3339 /* Restore the PCI state saved during initialization. */
3340 pci_restore_state(sp->pdev);
3341 pci_read_config_word(sp->pdev, 0x2, &val16);
3342 if (check_pci_device_id(val16) != (u16)PCI_ANY_ID)
3343 break;
3344 msleep(200);
3345 }
3346
3347 if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) {
3348 DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__);
3349 }
3350
3351 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd);
3352
3353 s2io_init_pci(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003355 /* Set swapper to enable I/O register access */
3356 s2io_set_swapper(sp);
3357
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003358 /* Restore the MSIX table entries from local variables */
3359 restore_xmsi_data(sp);
3360
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003361 /* Clear certain PCI/PCI-X fields after reset */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003362 if (sp->device_type == XFRAME_II_DEVICE) {
Ananda Rajub41477f2006-07-24 19:52:49 -04003363 /* Clear "detected parity error" bit */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003364 pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003365
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003366 /* Clearing PCIX Ecc status register */
3367 pci_write_config_dword(sp->pdev, 0x68, 0x7C);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003368
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003369 /* Clearing PCI_STATUS error reflected here */
3370 writeq(BIT(62), &bar0->txpic_int_reg);
3371 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003372
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003373 /* Reset device statistics maintained by OS */
3374 memset(&sp->stats, 0, sizeof (struct net_device_stats));
3375
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 /* SXE-002: Configure link and activity LED to turn it off */
3377 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003378 if (((subid & 0xFF) >= 0x07) &&
3379 (sp->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 val64 = readq(&bar0->gpio_control);
3381 val64 |= 0x0000800000000000ULL;
3382 writeq(val64, &bar0->gpio_control);
3383 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01003384 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 }
3386
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003387 /*
3388 * Clear spurious ECC interrupts that would have occured on
3389 * XFRAME II cards after reset.
3390 */
3391 if (sp->device_type == XFRAME_II_DEVICE) {
3392 val64 = readq(&bar0->pcc_err_reg);
3393 writeq(val64, &bar0->pcc_err_reg);
3394 }
3395
Sivakumar Subramanid8d70ca2007-02-24 02:04:24 -05003396 /* restore the previously assigned mac address */
3397 s2io_set_mac_addr(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr);
3398
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 sp->device_enabled_once = FALSE;
3400}
3401
3402/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003403 * s2io_set_swapper - to set the swapper controle on the card
3404 * @sp : private member of the device structure,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 * pointer to the s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003406 * Description: Function to set the swapper control on the card
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 * correctly depending on the 'endianness' of the system.
3408 * Return value:
3409 * SUCCESS on success and FAILURE on failure.
3410 */
3411
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003412static int s2io_set_swapper(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413{
3414 struct net_device *dev = sp->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003415 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 u64 val64, valt, valr;
3417
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003418 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 * Set proper endian settings and verify the same by reading
3420 * the PIF Feed-back register.
3421 */
3422
3423 val64 = readq(&bar0->pif_rd_swapper_fb);
3424 if (val64 != 0x0123456789ABCDEFULL) {
3425 int i = 0;
3426 u64 value[] = { 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */
3427 0x8100008181000081ULL, /* FE=1, SE=0 */
3428 0x4200004242000042ULL, /* FE=0, SE=1 */
3429 0}; /* FE=0, SE=0 */
3430
3431 while(i<4) {
3432 writeq(value[i], &bar0->swapper_ctrl);
3433 val64 = readq(&bar0->pif_rd_swapper_fb);
3434 if (val64 == 0x0123456789ABCDEFULL)
3435 break;
3436 i++;
3437 }
3438 if (i == 4) {
3439 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3440 dev->name);
3441 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3442 (unsigned long long) val64);
3443 return FAILURE;
3444 }
3445 valr = value[i];
3446 } else {
3447 valr = readq(&bar0->swapper_ctrl);
3448 }
3449
3450 valt = 0x0123456789ABCDEFULL;
3451 writeq(valt, &bar0->xmsi_address);
3452 val64 = readq(&bar0->xmsi_address);
3453
3454 if(val64 != valt) {
3455 int i = 0;
3456 u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */
3457 0x0081810000818100ULL, /* FE=1, SE=0 */
3458 0x0042420000424200ULL, /* FE=0, SE=1 */
3459 0}; /* FE=0, SE=0 */
3460
3461 while(i<4) {
3462 writeq((value[i] | valr), &bar0->swapper_ctrl);
3463 writeq(valt, &bar0->xmsi_address);
3464 val64 = readq(&bar0->xmsi_address);
3465 if(val64 == valt)
3466 break;
3467 i++;
3468 }
3469 if(i == 4) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003470 unsigned long long x = val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr ");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003472 DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 return FAILURE;
3474 }
3475 }
3476 val64 = readq(&bar0->swapper_ctrl);
3477 val64 &= 0xFFFF000000000000ULL;
3478
3479#ifdef __BIG_ENDIAN
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003480 /*
3481 * The device by default set to a big endian format, so a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 * big endian driver need not set anything.
3483 */
3484 val64 |= (SWAPPER_CTRL_TXP_FE |
3485 SWAPPER_CTRL_TXP_SE |
3486 SWAPPER_CTRL_TXD_R_FE |
3487 SWAPPER_CTRL_TXD_W_FE |
3488 SWAPPER_CTRL_TXF_R_FE |
3489 SWAPPER_CTRL_RXD_R_FE |
3490 SWAPPER_CTRL_RXD_W_FE |
3491 SWAPPER_CTRL_RXF_W_FE |
3492 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Andrew Morton92383342005-10-16 00:11:29 -07003494 if (sp->intr_type == INTA)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003495 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 writeq(val64, &bar0->swapper_ctrl);
3497#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003498 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 * Initially we enable all bits to make it accessible by the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003500 * driver, then we selectively enable only those bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 * we want to set.
3502 */
3503 val64 |= (SWAPPER_CTRL_TXP_FE |
3504 SWAPPER_CTRL_TXP_SE |
3505 SWAPPER_CTRL_TXD_R_FE |
3506 SWAPPER_CTRL_TXD_R_SE |
3507 SWAPPER_CTRL_TXD_W_FE |
3508 SWAPPER_CTRL_TXD_W_SE |
3509 SWAPPER_CTRL_TXF_R_FE |
3510 SWAPPER_CTRL_RXD_R_FE |
3511 SWAPPER_CTRL_RXD_R_SE |
3512 SWAPPER_CTRL_RXD_W_FE |
3513 SWAPPER_CTRL_RXD_W_SE |
3514 SWAPPER_CTRL_RXF_W_FE |
3515 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003517 if (sp->intr_type == INTA)
3518 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519 writeq(val64, &bar0->swapper_ctrl);
3520#endif
3521 val64 = readq(&bar0->swapper_ctrl);
3522
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003523 /*
3524 * Verifying if endian settings are accurate by reading a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 * feedback register.
3526 */
3527 val64 = readq(&bar0->pif_rd_swapper_fb);
3528 if (val64 != 0x0123456789ABCDEFULL) {
3529 /* Endian settings are incorrect, calls for another dekko. */
3530 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3531 dev->name);
3532 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3533 (unsigned long long) val64);
3534 return FAILURE;
3535 }
3536
3537 return SUCCESS;
3538}
3539
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003540static int wait_for_msix_trans(struct s2io_nic *nic, int i)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003541{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003542 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003543 u64 val64;
3544 int ret = 0, cnt = 0;
3545
3546 do {
3547 val64 = readq(&bar0->xmsi_access);
3548 if (!(val64 & BIT(15)))
3549 break;
3550 mdelay(1);
3551 cnt++;
3552 } while(cnt < 5);
3553 if (cnt == 5) {
3554 DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i);
3555 ret = 1;
3556 }
3557
3558 return ret;
3559}
3560
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003561static void restore_xmsi_data(struct s2io_nic *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003562{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003563 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003564 u64 val64;
3565 int i;
3566
Ananda Raju75c30b12006-07-24 19:55:09 -04003567 for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003568 writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
3569 writeq(nic->msix_info[i].data, &bar0->xmsi_data);
3570 val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
3571 writeq(val64, &bar0->xmsi_access);
3572 if (wait_for_msix_trans(nic, i)) {
3573 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3574 continue;
3575 }
3576 }
3577}
3578
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003579static void store_xmsi_data(struct s2io_nic *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003580{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003581 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003582 u64 val64, addr, data;
3583 int i;
3584
3585 /* Store and display */
Ananda Raju75c30b12006-07-24 19:55:09 -04003586 for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003587 val64 = (BIT(15) | vBIT(i, 26, 6));
3588 writeq(val64, &bar0->xmsi_access);
3589 if (wait_for_msix_trans(nic, i)) {
3590 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3591 continue;
3592 }
3593 addr = readq(&bar0->xmsi_address);
3594 data = readq(&bar0->xmsi_data);
3595 if (addr && data) {
3596 nic->msix_info[i].addr = addr;
3597 nic->msix_info[i].data = data;
3598 }
3599 }
3600}
3601
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003602int s2io_enable_msi(struct s2io_nic *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003603{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003604 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003605 u16 msi_ctrl, msg_val;
3606 struct config_param *config = &nic->config;
3607 struct net_device *dev = nic->dev;
3608 u64 val64, tx_mat, rx_mat;
3609 int i, err;
3610
3611 val64 = readq(&bar0->pic_control);
3612 val64 &= ~BIT(1);
3613 writeq(val64, &bar0->pic_control);
3614
3615 err = pci_enable_msi(nic->pdev);
3616 if (err) {
3617 DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n",
3618 nic->dev->name);
3619 return err;
3620 }
3621
3622 /*
3623 * Enable MSI and use MSI-1 in stead of the standard MSI-0
3624 * for interrupt handling.
3625 */
3626 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3627 msg_val ^= 0x1;
3628 pci_write_config_word(nic->pdev, 0x4c, msg_val);
3629 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3630
3631 pci_read_config_word(nic->pdev, 0x42, &msi_ctrl);
3632 msi_ctrl |= 0x10;
3633 pci_write_config_word(nic->pdev, 0x42, msi_ctrl);
3634
3635 /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */
3636 tx_mat = readq(&bar0->tx_mat0_n[0]);
3637 for (i=0; i<config->tx_fifo_num; i++) {
3638 tx_mat |= TX_MAT_SET(i, 1);
3639 }
3640 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3641
3642 rx_mat = readq(&bar0->rx_mat);
3643 for (i=0; i<config->rx_ring_num; i++) {
3644 rx_mat |= RX_MAT_SET(i, 1);
3645 }
3646 writeq(rx_mat, &bar0->rx_mat);
3647
3648 dev->irq = nic->pdev->irq;
3649 return 0;
3650}
3651
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003652static int s2io_enable_msi_x(struct s2io_nic *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003653{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003654 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003655 u64 tx_mat, rx_mat;
3656 u16 msi_control; /* Temp variable */
3657 int ret, i, j, msix_indx = 1;
3658
3659 nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
3660 GFP_KERNEL);
3661 if (nic->entries == NULL) {
3662 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3663 return -ENOMEM;
3664 }
3665 memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
3666
3667 nic->s2io_entries =
3668 kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
3669 GFP_KERNEL);
3670 if (nic->s2io_entries == NULL) {
3671 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3672 kfree(nic->entries);
3673 return -ENOMEM;
3674 }
3675 memset(nic->s2io_entries, 0,
3676 MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
3677
3678 for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
3679 nic->entries[i].entry = i;
3680 nic->s2io_entries[i].entry = i;
3681 nic->s2io_entries[i].arg = NULL;
3682 nic->s2io_entries[i].in_use = 0;
3683 }
3684
3685 tx_mat = readq(&bar0->tx_mat0_n[0]);
3686 for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) {
3687 tx_mat |= TX_MAT_SET(i, msix_indx);
3688 nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i];
3689 nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE;
3690 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3691 }
3692 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3693
3694 if (!nic->config.bimodal) {
3695 rx_mat = readq(&bar0->rx_mat);
3696 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3697 rx_mat |= RX_MAT_SET(j, msix_indx);
3698 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3699 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3700 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3701 }
3702 writeq(rx_mat, &bar0->rx_mat);
3703 } else {
3704 tx_mat = readq(&bar0->tx_mat0_n[7]);
3705 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3706 tx_mat |= TX_MAT_SET(i, msix_indx);
3707 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3708 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3709 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3710 }
3711 writeq(tx_mat, &bar0->tx_mat0_n[7]);
3712 }
3713
Ananda Rajuc92ca042006-04-21 19:18:03 -04003714 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003715 ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003716 /* We fail init if error or we get less vectors than min required */
3717 if (ret >= (nic->config.tx_fifo_num + nic->config.rx_ring_num + 1)) {
3718 nic->avail_msix_vectors = ret;
3719 ret = pci_enable_msix(nic->pdev, nic->entries, ret);
3720 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003721 if (ret) {
3722 DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
3723 kfree(nic->entries);
3724 kfree(nic->s2io_entries);
3725 nic->entries = NULL;
3726 nic->s2io_entries = NULL;
Ananda Rajuc92ca042006-04-21 19:18:03 -04003727 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003728 return -ENOMEM;
3729 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003730 if (!nic->avail_msix_vectors)
3731 nic->avail_msix_vectors = MAX_REQUESTED_MSI_X;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003732
3733 /*
3734 * To enable MSI-X, MSI also needs to be enabled, due to a bug
3735 * in the herc NIC. (Temp change, needs to be removed later)
3736 */
3737 pci_read_config_word(nic->pdev, 0x42, &msi_control);
3738 msi_control |= 0x1; /* Enable MSI */
3739 pci_write_config_word(nic->pdev, 0x42, msi_control);
3740
3741 return 0;
3742}
3743
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744/* ********************************************************* *
3745 * Functions defined below concern the OS part of the driver *
3746 * ********************************************************* */
3747
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003748/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 * s2io_open - open entry point of the driver
3750 * @dev : pointer to the device structure.
3751 * Description:
3752 * This function is the open entry point of the driver. It mainly calls a
3753 * function to allocate Rx buffers and inserts them into the buffer
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003754 * descriptors and then enables the Rx part of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 * Return value:
3756 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3757 * file on failure.
3758 */
3759
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003760static int s2io_open(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003762 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 int err = 0;
3764
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003765 /*
3766 * Make sure you have link off by default every time
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 * Nic is initialized
3768 */
3769 netif_carrier_off(dev);
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003770 sp->last_link_state = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771
3772 /* Initialize H/W and enable interrupts */
Ananda Rajuc92ca042006-04-21 19:18:03 -04003773 err = s2io_card_up(sp);
3774 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
3776 dev->name);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003777 goto hw_init_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 }
3779
3780 if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
3781 DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003782 s2io_card_down(sp);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003783 err = -ENODEV;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003784 goto hw_init_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 }
3786
3787 netif_start_queue(dev);
3788 return 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003789
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003790hw_init_failed:
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003791 if (sp->intr_type == MSI_X) {
3792 if (sp->entries)
3793 kfree(sp->entries);
3794 if (sp->s2io_entries)
3795 kfree(sp->s2io_entries);
3796 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003797 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798}
3799
3800/**
3801 * s2io_close -close entry point of the driver
3802 * @dev : device pointer.
3803 * Description:
3804 * This is the stop entry point of the driver. It needs to undo exactly
3805 * whatever was done by the open entry point,thus it's usually referred to
3806 * as the close function.Among other things this function mainly stops the
3807 * Rx side of the NIC and frees all the Rx buffers in the Rx rings.
3808 * Return value:
3809 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3810 * file on failure.
3811 */
3812
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003813static int s2io_close(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003815 struct s2io_nic *sp = dev->priv;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003816
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 netif_stop_queue(dev);
3818 /* Reset card, kill tasklet and free Tx and Rx buffers. */
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003819 s2io_card_down(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 sp->device_close_flag = TRUE; /* Device is shut down. */
3822 return 0;
3823}
3824
3825/**
3826 * s2io_xmit - Tx entry point of te driver
3827 * @skb : the socket buffer containing the Tx data.
3828 * @dev : device pointer.
3829 * Description :
3830 * This function is the Tx entry point of the driver. S2IO NIC supports
3831 * certain protocol assist features on Tx side, namely CSO, S/G, LSO.
3832 * NOTE: when device cant queue the pkt,just the trans_start variable will
3833 * not be upadted.
3834 * Return value:
3835 * 0 on success & 1 on failure.
3836 */
3837
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003838static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003840 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
3842 register u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003843 struct TxD *txdp;
3844 struct TxFIFO_element __iomem *tx_fifo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 unsigned long flags;
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003846 u16 vlan_tag = 0;
3847 int vlan_priority = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003848 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 struct config_param *config;
Ananda Raju75c30b12006-07-24 19:55:09 -04003850 int offload_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851
3852 mac_control = &sp->mac_control;
3853 config = &sp->config;
3854
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003855 DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 spin_lock_irqsave(&sp->tx_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 if (atomic_read(&sp->card_state) == CARD_DOWN) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003858 DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 dev->name);
3860 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003861 dev_kfree_skb(skb);
3862 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 }
3864
3865 queue = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003867 /* Get Fifo number to Transmit based on vlan priority */
3868 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3869 vlan_tag = vlan_tx_tag_get(skb);
3870 vlan_priority = vlan_tag >> 13;
3871 queue = config->fifo_mapping[vlan_priority];
3872 }
3873
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003874 put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
3875 get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003876 txdp = (struct TxD *) mac_control->fifos[queue].list_info[put_off].
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003877 list_virt_addr;
3878
3879 queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04003881 if (txdp->Host_Control ||
3882 ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003883 DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 netif_stop_queue(dev);
3885 dev_kfree_skb(skb);
3886 spin_unlock_irqrestore(&sp->tx_lock, flags);
3887 return 0;
3888 }
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003889
3890 /* A buffer with no data will be dropped */
3891 if (!skb->len) {
3892 DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
3893 dev_kfree_skb(skb);
3894 spin_unlock_irqrestore(&sp->tx_lock, flags);
3895 return 0;
3896 }
3897
Ananda Raju75c30b12006-07-24 19:55:09 -04003898 offload_type = s2io_offload_type(skb);
Ananda Raju75c30b12006-07-24 19:55:09 -04003899 if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 txdp->Control_1 |= TXD_TCP_LSO_EN;
Ananda Raju75c30b12006-07-24 19:55:09 -04003901 txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 }
Patrick McHardy84fa7932006-08-29 16:44:56 -07003903 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 txdp->Control_2 |=
3905 (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
3906 TXD_TX_CKO_UDP_EN);
3907 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003908 txdp->Control_1 |= TXD_GATHER_CODE_FIRST;
3909 txdp->Control_1 |= TXD_LIST_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 txdp->Control_2 |= config->tx_intr_type;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07003911
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003912 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3913 txdp->Control_2 |= TXD_VLAN_ENABLE;
3914 txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
3915 }
3916
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003917 frg_len = skb->len - skb->data_len;
Ananda Raju75c30b12006-07-24 19:55:09 -04003918 if (offload_type == SKB_GSO_UDP) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003919 int ufo_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920
Ananda Raju75c30b12006-07-24 19:55:09 -04003921 ufo_size = s2io_udp_mss(skb);
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003922 ufo_size &= ~7;
3923 txdp->Control_1 |= TXD_UFO_EN;
3924 txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
3925 txdp->Control_1 |= TXD_BUFFER0_SIZE(8);
3926#ifdef __BIG_ENDIAN
3927 sp->ufo_in_band_v[put_off] =
3928 (u64)skb_shinfo(skb)->ip6_frag_id;
3929#else
3930 sp->ufo_in_band_v[put_off] =
3931 (u64)skb_shinfo(skb)->ip6_frag_id << 32;
3932#endif
3933 txdp->Host_Control = (unsigned long)sp->ufo_in_band_v;
3934 txdp->Buffer_Pointer = pci_map_single(sp->pdev,
3935 sp->ufo_in_band_v,
3936 sizeof(u64), PCI_DMA_TODEVICE);
3937 txdp++;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003938 }
3939
3940 txdp->Buffer_Pointer = pci_map_single
3941 (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
3942 txdp->Host_Control = (unsigned long) skb;
3943 txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
Ananda Raju75c30b12006-07-24 19:55:09 -04003944 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003945 txdp->Control_1 |= TXD_UFO_EN;
3946
3947 frg_cnt = skb_shinfo(skb)->nr_frags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948 /* For fragmented SKB. */
3949 for (i = 0; i < frg_cnt; i++) {
3950 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003951 /* A '0' length fragment will be ignored */
3952 if (!frag->size)
3953 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 txdp++;
3955 txdp->Buffer_Pointer = (u64) pci_map_page
3956 (sp->pdev, frag->page, frag->page_offset,
3957 frag->size, PCI_DMA_TODEVICE);
Ananda Rajuefd51b52006-01-19 14:11:54 -05003958 txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
Ananda Raju75c30b12006-07-24 19:55:09 -04003959 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003960 txdp->Control_1 |= TXD_UFO_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 }
3962 txdp->Control_1 |= TXD_GATHER_CODE_LAST;
3963
Ananda Raju75c30b12006-07-24 19:55:09 -04003964 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003965 frg_cnt++; /* as Txd0 was used for inband header */
3966
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 tx_fifo = mac_control->tx_FIFO_start[queue];
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003968 val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 writeq(val64, &tx_fifo->TxDL_Pointer);
3970
3971 val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
3972 TX_FIFO_LAST_LIST);
Ananda Raju75c30b12006-07-24 19:55:09 -04003973 if (offload_type)
3974 val64 |= TX_FIFO_SPECIAL_FUNC;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003975
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 writeq(val64, &tx_fifo->List_Control);
3977
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003978 mmiowb();
3979
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 put_off++;
Ananda Raju863c11a2006-04-21 19:03:13 -04003981 if (put_off == mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1)
3982 put_off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003983 mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984
3985 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04003986 if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04003987 sp->mac_control.stats_info->sw_stat.fifo_full_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 DBG_PRINT(TX_DBG,
3989 "No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
3990 put_off, get_off);
3991 netif_stop_queue(dev);
3992 }
3993
3994 dev->trans_start = jiffies;
3995 spin_unlock_irqrestore(&sp->tx_lock, flags);
3996
3997 return 0;
3998}
3999
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07004000static void
4001s2io_alarm_handle(unsigned long data)
4002{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004003 struct s2io_nic *sp = (struct s2io_nic *)data;
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07004004
4005 alarm_intr_handler(sp);
4006 mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
4007}
4008
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004009static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
Ananda Raju75c30b12006-07-24 19:55:09 -04004010{
4011 int rxb_size, level;
4012
4013 if (!sp->lro) {
4014 rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
4015 level = rx_buffer_level(sp, rxb_size, rng_n);
4016
4017 if ((level == PANIC) && (!TASKLET_IN_USE)) {
4018 int ret;
4019 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
4020 DBG_PRINT(INTR_DBG, "PANIC levels\n");
4021 if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
4022 DBG_PRINT(ERR_DBG, "Out of memory in %s",
4023 __FUNCTION__);
4024 clear_bit(0, (&sp->tasklet_status));
4025 return -1;
4026 }
4027 clear_bit(0, (&sp->tasklet_status));
4028 } else if (level == LOW)
4029 tasklet_schedule(&sp->task);
4030
4031 } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
4032 DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name);
4033 DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
4034 }
4035 return 0;
4036}
4037
David Howells7d12e782006-10-05 14:55:46 +01004038static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004039{
4040 struct net_device *dev = (struct net_device *) dev_id;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004041 struct s2io_nic *sp = dev->priv;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004042 int i;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004043 struct mac_info *mac_control;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004044 struct config_param *config;
4045
4046 atomic_inc(&sp->isr_cnt);
4047 mac_control = &sp->mac_control;
4048 config = &sp->config;
4049 DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__);
4050
4051 /* If Intr is because of Rx Traffic */
4052 for (i = 0; i < config->rx_ring_num; i++)
4053 rx_intr_handler(&mac_control->rings[i]);
4054
4055 /* If Intr is because of Tx Traffic */
4056 for (i = 0; i < config->tx_fifo_num; i++)
4057 tx_intr_handler(&mac_control->fifos[i]);
4058
4059 /*
4060 * If the Rx buffer count is below the panic threshold then
4061 * reallocate the buffers from the interrupt handler itself,
4062 * else schedule a tasklet to reallocate the buffers.
4063 */
Ananda Raju75c30b12006-07-24 19:55:09 -04004064 for (i = 0; i < config->rx_ring_num; i++)
4065 s2io_chk_rx_buffers(sp, i);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004066
4067 atomic_dec(&sp->isr_cnt);
4068 return IRQ_HANDLED;
4069}
4070
David Howells7d12e782006-10-05 14:55:46 +01004071static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004072{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004073 struct ring_info *ring = (struct ring_info *)dev_id;
4074 struct s2io_nic *sp = ring->nic;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004075
4076 atomic_inc(&sp->isr_cnt);
Ananda Raju75c30b12006-07-24 19:55:09 -04004077
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004078 rx_intr_handler(ring);
Ananda Raju75c30b12006-07-24 19:55:09 -04004079 s2io_chk_rx_buffers(sp, ring->ring_no);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004080
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004081 atomic_dec(&sp->isr_cnt);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004082 return IRQ_HANDLED;
4083}
4084
David Howells7d12e782006-10-05 14:55:46 +01004085static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004086{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004087 struct fifo_info *fifo = (struct fifo_info *)dev_id;
4088 struct s2io_nic *sp = fifo->nic;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004089
4090 atomic_inc(&sp->isr_cnt);
4091 tx_intr_handler(fifo);
4092 atomic_dec(&sp->isr_cnt);
4093 return IRQ_HANDLED;
4094}
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004095static void s2io_txpic_intr_handle(struct s2io_nic *sp)
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004096{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004097 struct XENA_dev_config __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004098 u64 val64;
4099
4100 val64 = readq(&bar0->pic_int_status);
4101 if (val64 & PIC_INT_GPIO) {
4102 val64 = readq(&bar0->gpio_int_reg);
4103 if ((val64 & GPIO_INT_REG_LINK_DOWN) &&
4104 (val64 & GPIO_INT_REG_LINK_UP)) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04004105 /*
4106 * This is unstable state so clear both up/down
4107 * interrupt and adapter to re-evaluate the link state.
4108 */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004109 val64 |= GPIO_INT_REG_LINK_DOWN;
4110 val64 |= GPIO_INT_REG_LINK_UP;
4111 writeq(val64, &bar0->gpio_int_reg);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004112 val64 = readq(&bar0->gpio_int_mask);
4113 val64 &= ~(GPIO_INT_MASK_LINK_UP |
4114 GPIO_INT_MASK_LINK_DOWN);
4115 writeq(val64, &bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004116 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04004117 else if (val64 & GPIO_INT_REG_LINK_UP) {
4118 val64 = readq(&bar0->adapter_status);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004119 /* Enable Adapter */
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004120 val64 = readq(&bar0->adapter_control);
4121 val64 |= ADAPTER_CNTL_EN;
4122 writeq(val64, &bar0->adapter_control);
4123 val64 |= ADAPTER_LED_ON;
4124 writeq(val64, &bar0->adapter_control);
4125 if (!sp->device_enabled_once)
4126 sp->device_enabled_once = 1;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004127
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004128 s2io_link(sp, LINK_UP);
4129 /*
4130 * unmask link down interrupt and mask link-up
4131 * intr
4132 */
4133 val64 = readq(&bar0->gpio_int_mask);
4134 val64 &= ~GPIO_INT_MASK_LINK_DOWN;
4135 val64 |= GPIO_INT_MASK_LINK_UP;
4136 writeq(val64, &bar0->gpio_int_mask);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004137
Ananda Rajuc92ca042006-04-21 19:18:03 -04004138 }else if (val64 & GPIO_INT_REG_LINK_DOWN) {
4139 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004140 s2io_link(sp, LINK_DOWN);
4141 /* Link is down so unmaks link up interrupt */
4142 val64 = readq(&bar0->gpio_int_mask);
4143 val64 &= ~GPIO_INT_MASK_LINK_UP;
4144 val64 |= GPIO_INT_MASK_LINK_DOWN;
4145 writeq(val64, &bar0->gpio_int_mask);
Sivakumar Subramaniac1f90d2007-02-24 02:01:31 -05004146
4147 /* turn off LED */
4148 val64 = readq(&bar0->adapter_control);
4149 val64 = val64 &(~ADAPTER_LED_ON);
4150 writeq(val64, &bar0->adapter_control);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004151 }
4152 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04004153 val64 = readq(&bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004154}
4155
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156/**
4157 * s2io_isr - ISR handler of the device .
4158 * @irq: the irq of the device.
4159 * @dev_id: a void pointer to the dev structure of the NIC.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004160 * Description: This function is the ISR handler of the device. It
4161 * identifies the reason for the interrupt and calls the relevant
4162 * service routines. As a contongency measure, this ISR allocates the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 * recv buffers, if their numbers are below the panic value which is
4164 * presently set to 25% of the original number of rcv buffers allocated.
4165 * Return value:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004166 * IRQ_HANDLED: will be returned if IRQ was handled by this routine
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 * IRQ_NONE: will be returned if interrupt is not from our device
4168 */
David Howells7d12e782006-10-05 14:55:46 +01004169static irqreturn_t s2io_isr(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170{
4171 struct net_device *dev = (struct net_device *) dev_id;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004172 struct s2io_nic *sp = dev->priv;
4173 struct XENA_dev_config __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004174 int i;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004175 u64 reason = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004176 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 struct config_param *config;
4178
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004179 atomic_inc(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 mac_control = &sp->mac_control;
4181 config = &sp->config;
4182
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004183 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 * Identify the cause for interrupt and call the appropriate
4185 * interrupt handler. Causes for the interrupt could be;
4186 * 1. Rx of packet.
4187 * 2. Tx complete.
4188 * 3. Link down.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004189 * 4. Error in any functional blocks of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 */
4191 reason = readq(&bar0->general_int_status);
4192
4193 if (!reason) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004194 /* The interrupt was not raised by us. */
4195 atomic_dec(&sp->isr_cnt);
4196 return IRQ_NONE;
4197 }
4198 else if (unlikely(reason == S2IO_MINUS_ONE) ) {
4199 /* Disable device and get out */
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004200 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 return IRQ_NONE;
4202 }
4203
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004204 if (napi) {
4205 if (reason & GEN_INTR_RXTRAFFIC) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004206 if ( likely ( netif_rx_schedule_prep(dev)) ) {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004207 __netif_rx_schedule(dev);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004208 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004209 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004210 else
4211 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004212 }
4213 } else {
4214 /*
4215 * Rx handler is called by default, without checking for the
4216 * cause of interrupt.
4217 * rx_traffic_int reg is an R1 register, writing all 1's
4218 * will ensure that the actual interrupt causing bit get's
4219 * cleared and hence a read can be avoided.
4220 */
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004221 if (reason & GEN_INTR_RXTRAFFIC)
4222 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
4223
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004224 for (i = 0; i < config->rx_ring_num; i++) {
4225 rx_intr_handler(&mac_control->rings[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 }
4227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228
Ananda Raju863c11a2006-04-21 19:03:13 -04004229 /*
4230 * tx_traffic_int reg is an R1 register, writing all 1's
4231 * will ensure that the actual interrupt causing bit get's
4232 * cleared and hence a read can be avoided.
4233 */
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004234 if (reason & GEN_INTR_TXTRAFFIC)
4235 writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -07004236
Ananda Raju863c11a2006-04-21 19:03:13 -04004237 for (i = 0; i < config->tx_fifo_num; i++)
4238 tx_intr_handler(&mac_control->fifos[i]);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004239
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004240 if (reason & GEN_INTR_TXPIC)
4241 s2io_txpic_intr_handle(sp);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004242 /*
4243 * If the Rx buffer count is below the panic threshold then
4244 * reallocate the buffers from the interrupt handler itself,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 * else schedule a tasklet to reallocate the buffers.
4246 */
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004247 if (!napi) {
4248 for (i = 0; i < config->rx_ring_num; i++)
4249 s2io_chk_rx_buffers(sp, i);
4250 }
4251
4252 writeq(0, &bar0->general_int_mask);
4253 readl(&bar0->general_int_status);
4254
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004255 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 return IRQ_HANDLED;
4257}
4258
4259/**
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004260 * s2io_updt_stats -
4261 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004262static void s2io_updt_stats(struct s2io_nic *sp)
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004263{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004264 struct XENA_dev_config __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004265 u64 val64;
4266 int cnt = 0;
4267
4268 if (atomic_read(&sp->card_state) == CARD_UP) {
4269 /* Apprx 30us on a 133 MHz bus */
4270 val64 = SET_UPDT_CLICKS(10) |
4271 STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
4272 writeq(val64, &bar0->stat_cfg);
4273 do {
4274 udelay(100);
4275 val64 = readq(&bar0->stat_cfg);
4276 if (!(val64 & BIT(0)))
4277 break;
4278 cnt++;
4279 if (cnt == 5)
4280 break; /* Updt failed */
4281 } while(1);
Ananda Raju75c30b12006-07-24 19:55:09 -04004282 } else {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004283 memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004284 }
4285}
4286
4287/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004288 * s2io_get_stats - Updates the device statistics structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 * @dev : pointer to the device structure.
4290 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004291 * This function updates the device statistics structure in the s2io_nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 * structure and returns a pointer to the same.
4293 * Return value:
4294 * pointer to the updated net_device_stats structure.
4295 */
4296
Adrian Bunkac1f60d2005-11-06 01:46:47 +01004297static struct net_device_stats *s2io_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004299 struct s2io_nic *sp = dev->priv;
4300 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 struct config_param *config;
4302
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004303
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 mac_control = &sp->mac_control;
4305 config = &sp->config;
4306
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004307 /* Configure Stats for immediate updt */
4308 s2io_updt_stats(sp);
4309
4310 sp->stats.tx_packets =
4311 le32_to_cpu(mac_control->stats_info->tmac_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004312 sp->stats.tx_errors =
4313 le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
4314 sp->stats.rx_errors =
Al Viroee705db2006-09-23 01:28:17 +01004315 le64_to_cpu(mac_control->stats_info->rmac_drop_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004316 sp->stats.multicast =
4317 le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 sp->stats.rx_length_errors =
Al Viroee705db2006-09-23 01:28:17 +01004319 le64_to_cpu(mac_control->stats_info->rmac_long_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320
4321 return (&sp->stats);
4322}
4323
4324/**
4325 * s2io_set_multicast - entry point for multicast address enable/disable.
4326 * @dev : pointer to the device structure
4327 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004328 * This function is a driver entry point which gets called by the kernel
4329 * whenever multicast addresses must be enabled/disabled. This also gets
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 * called to set/reset promiscuous mode. Depending on the deivce flag, we
4331 * determine, if multicast address must be enabled or if promiscuous mode
4332 * is to be disabled etc.
4333 * Return value:
4334 * void.
4335 */
4336
4337static void s2io_set_multicast(struct net_device *dev)
4338{
4339 int i, j, prev_cnt;
4340 struct dev_mc_list *mclist;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004341 struct s2io_nic *sp = dev->priv;
4342 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
4344 0xfeffffffffffULL;
4345 u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
4346 void __iomem *add;
4347
4348 if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) {
4349 /* Enable all Multicast addresses */
4350 writeq(RMAC_ADDR_DATA0_MEM_ADDR(multi_mac),
4351 &bar0->rmac_addr_data0_mem);
4352 writeq(RMAC_ADDR_DATA1_MEM_MASK(mask),
4353 &bar0->rmac_addr_data1_mem);
4354 val64 = RMAC_ADDR_CMD_MEM_WE |
4355 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4356 RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
4357 writeq(val64, &bar0->rmac_addr_cmd_mem);
4358 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004359 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004360 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
4361 S2IO_BIT_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362
4363 sp->m_cast_flg = 1;
4364 sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
4365 } else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) {
4366 /* Disable all Multicast addresses */
4367 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4368 &bar0->rmac_addr_data0_mem);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07004369 writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0),
4370 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 val64 = RMAC_ADDR_CMD_MEM_WE |
4372 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4373 RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos);
4374 writeq(val64, &bar0->rmac_addr_cmd_mem);
4375 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004376 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004377 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
4378 S2IO_BIT_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379
4380 sp->m_cast_flg = 0;
4381 sp->all_multi_pos = 0;
4382 }
4383
4384 if ((dev->flags & IFF_PROMISC) && (!sp->promisc_flg)) {
4385 /* Put the NIC into promiscuous mode */
4386 add = &bar0->mac_cfg;
4387 val64 = readq(&bar0->mac_cfg);
4388 val64 |= MAC_CFG_RMAC_PROM_ENABLE;
4389
4390 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4391 writel((u32) val64, add);
4392 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4393 writel((u32) (val64 >> 32), (add + 4));
4394
Sivakumar Subramani926930b2007-02-24 01:59:39 -05004395 if (vlan_tag_strip != 1) {
4396 val64 = readq(&bar0->rx_pa_cfg);
4397 val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG;
4398 writeq(val64, &bar0->rx_pa_cfg);
4399 vlan_strip_flag = 0;
4400 }
4401
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 val64 = readq(&bar0->mac_cfg);
4403 sp->promisc_flg = 1;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004404 DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 dev->name);
4406 } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) {
4407 /* Remove the NIC from promiscuous mode */
4408 add = &bar0->mac_cfg;
4409 val64 = readq(&bar0->mac_cfg);
4410 val64 &= ~MAC_CFG_RMAC_PROM_ENABLE;
4411
4412 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4413 writel((u32) val64, add);
4414 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4415 writel((u32) (val64 >> 32), (add + 4));
4416
Sivakumar Subramani926930b2007-02-24 01:59:39 -05004417 if (vlan_tag_strip != 0) {
4418 val64 = readq(&bar0->rx_pa_cfg);
4419 val64 |= RX_PA_CFG_STRIP_VLAN_TAG;
4420 writeq(val64, &bar0->rx_pa_cfg);
4421 vlan_strip_flag = 1;
4422 }
4423
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 val64 = readq(&bar0->mac_cfg);
4425 sp->promisc_flg = 0;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004426 DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 dev->name);
4428 }
4429
4430 /* Update individual M_CAST address list */
4431 if ((!sp->m_cast_flg) && dev->mc_count) {
4432 if (dev->mc_count >
4433 (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) {
4434 DBG_PRINT(ERR_DBG, "%s: No more Rx filters ",
4435 dev->name);
4436 DBG_PRINT(ERR_DBG, "can be added, please enable ");
4437 DBG_PRINT(ERR_DBG, "ALL_MULTI instead\n");
4438 return;
4439 }
4440
4441 prev_cnt = sp->mc_addr_count;
4442 sp->mc_addr_count = dev->mc_count;
4443
4444 /* Clear out the previous list of Mc in the H/W. */
4445 for (i = 0; i < prev_cnt; i++) {
4446 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4447 &bar0->rmac_addr_data0_mem);
4448 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004449 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 val64 = RMAC_ADDR_CMD_MEM_WE |
4451 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4452 RMAC_ADDR_CMD_MEM_OFFSET
4453 (MAC_MC_ADDR_START_OFFSET + i);
4454 writeq(val64, &bar0->rmac_addr_cmd_mem);
4455
4456 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004457 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004458 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
4459 S2IO_BIT_RESET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 DBG_PRINT(ERR_DBG, "%s: Adding ",
4461 dev->name);
4462 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4463 return;
4464 }
4465 }
4466
4467 /* Create the new Rx filter list and update the same in H/W. */
4468 for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
4469 i++, mclist = mclist->next) {
4470 memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr,
4471 ETH_ALEN);
Jeff Garzika7a80d52006-03-04 12:06:51 -05004472 mac_addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 for (j = 0; j < ETH_ALEN; j++) {
4474 mac_addr |= mclist->dmi_addr[j];
4475 mac_addr <<= 8;
4476 }
4477 mac_addr >>= 8;
4478 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4479 &bar0->rmac_addr_data0_mem);
4480 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004481 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 val64 = RMAC_ADDR_CMD_MEM_WE |
4483 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4484 RMAC_ADDR_CMD_MEM_OFFSET
4485 (i + MAC_MC_ADDR_START_OFFSET);
4486 writeq(val64, &bar0->rmac_addr_cmd_mem);
4487
4488 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004489 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004490 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
4491 S2IO_BIT_RESET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 DBG_PRINT(ERR_DBG, "%s: Adding ",
4493 dev->name);
4494 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4495 return;
4496 }
4497 }
4498 }
4499}
4500
4501/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004502 * s2io_set_mac_addr - Programs the Xframe mac address
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 * @dev : pointer to the device structure.
4504 * @addr: a uchar pointer to the new mac address which is to be set.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004505 * Description : This procedure will program the Xframe to receive
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 * frames with new Mac Address
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004507 * Return value: SUCCESS on success and an appropriate (-)ve integer
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 * as defined in errno.h file on failure.
4509 */
4510
Adrian Bunk26df54b2006-01-14 03:09:40 +01004511static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004513 struct s2io_nic *sp = dev->priv;
4514 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 register u64 val64, mac_addr = 0;
4516 int i;
Sivakumar Subramanid8d70ca2007-02-24 02:04:24 -05004517 u64 old_mac_addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004519 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 * Set the new MAC address as the new unicast filter and reflect this
4521 * change on the device address registered with the OS. It will be
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004522 * at offset 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523 */
4524 for (i = 0; i < ETH_ALEN; i++) {
4525 mac_addr <<= 8;
4526 mac_addr |= addr[i];
Sivakumar Subramanid8d70ca2007-02-24 02:04:24 -05004527 old_mac_addr <<= 8;
4528 old_mac_addr |= sp->def_mac_addr[0].mac_addr[i];
4529 }
4530
4531 if(0 == mac_addr)
4532 return SUCCESS;
4533
4534 /* Update the internal structure with this new mac address */
4535 if(mac_addr != old_mac_addr) {
4536 memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
4537 sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_addr);
4538 sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_addr >> 8);
4539 sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_addr >> 16);
4540 sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_addr >> 24);
4541 sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_addr >> 32);
4542 sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_addr >> 40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 }
4544
4545 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4546 &bar0->rmac_addr_data0_mem);
4547
4548 val64 =
4549 RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4550 RMAC_ADDR_CMD_MEM_OFFSET(0);
4551 writeq(val64, &bar0->rmac_addr_cmd_mem);
4552 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004553 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004554 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
4556 return FAILURE;
4557 }
4558
4559 return SUCCESS;
4560}
4561
4562/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004563 * s2io_ethtool_sset - Sets different link parameters.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure.
4565 * @info: pointer to the structure with parameters given by ethtool to set
4566 * link information.
4567 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004568 * The function sets different link parameters provided by the user onto
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 * the NIC.
4570 * Return value:
4571 * 0 on success.
4572*/
4573
4574static int s2io_ethtool_sset(struct net_device *dev,
4575 struct ethtool_cmd *info)
4576{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004577 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 if ((info->autoneg == AUTONEG_ENABLE) ||
4579 (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
4580 return -EINVAL;
4581 else {
4582 s2io_close(sp->dev);
4583 s2io_open(sp->dev);
4584 }
4585
4586 return 0;
4587}
4588
4589/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004590 * s2io_ethtol_gset - Return link specific information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 * @sp : private member of the device structure, pointer to the
4592 * s2io_nic structure.
4593 * @info : pointer to the structure with parameters given by ethtool
4594 * to return link information.
4595 * Description:
4596 * Returns link specific information like speed, duplex etc.. to ethtool.
4597 * Return value :
4598 * return 0 on success.
4599 */
4600
4601static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
4602{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004603 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604 info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4605 info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4606 info->port = PORT_FIBRE;
4607 /* info->transceiver?? TODO */
4608
4609 if (netif_carrier_ok(sp->dev)) {
4610 info->speed = 10000;
4611 info->duplex = DUPLEX_FULL;
4612 } else {
4613 info->speed = -1;
4614 info->duplex = -1;
4615 }
4616
4617 info->autoneg = AUTONEG_DISABLE;
4618 return 0;
4619}
4620
4621/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004622 * s2io_ethtool_gdrvinfo - Returns driver specific information.
4623 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 * s2io_nic structure.
4625 * @info : pointer to the structure with parameters given by ethtool to
4626 * return driver information.
4627 * Description:
4628 * Returns driver specefic information like name, version etc.. to ethtool.
4629 * Return value:
4630 * void
4631 */
4632
4633static void s2io_ethtool_gdrvinfo(struct net_device *dev,
4634 struct ethtool_drvinfo *info)
4635{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004636 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637
John W. Linvilledbc23092005-09-28 17:50:51 -04004638 strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
4639 strncpy(info->version, s2io_driver_version, sizeof(info->version));
4640 strncpy(info->fw_version, "", sizeof(info->fw_version));
4641 strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 info->regdump_len = XENA_REG_SPACE;
4643 info->eedump_len = XENA_EEPROM_SPACE;
4644 info->testinfo_len = S2IO_TEST_LEN;
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -05004645
4646 if (sp->device_type == XFRAME_I_DEVICE)
4647 info->n_stats = XFRAME_I_STAT_LEN;
4648 else
4649 info->n_stats = XFRAME_II_STAT_LEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650}
4651
4652/**
4653 * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004654 * @sp: private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004656 * @regs : pointer to the structure with parameters given by ethtool for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 * dumping the registers.
4658 * @reg_space: The input argumnet into which all the registers are dumped.
4659 * Description:
4660 * Dumps the entire register space of xFrame NIC into the user given
4661 * buffer area.
4662 * Return value :
4663 * void .
4664*/
4665
4666static void s2io_ethtool_gregs(struct net_device *dev,
4667 struct ethtool_regs *regs, void *space)
4668{
4669 int i;
4670 u64 reg;
4671 u8 *reg_space = (u8 *) space;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004672 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673
4674 regs->len = XENA_REG_SPACE;
4675 regs->version = sp->pdev->subsystem_device;
4676
4677 for (i = 0; i < regs->len; i += 8) {
4678 reg = readq(sp->bar0 + i);
4679 memcpy((reg_space + i), &reg, 8);
4680 }
4681}
4682
4683/**
4684 * s2io_phy_id - timer function that alternates adapter LED.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004685 * @data : address of the private member of the device structure, which
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 * is a pointer to the s2io_nic structure, provided as an u32.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004687 * Description: This is actually the timer function that alternates the
4688 * adapter LED bit of the adapter control bit to set/reset every time on
4689 * invocation. The timer is set for 1/2 a second, hence tha NIC blinks
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 * once every second.
4691*/
4692static void s2io_phy_id(unsigned long data)
4693{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004694 struct s2io_nic *sp = (struct s2io_nic *) data;
4695 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696 u64 val64 = 0;
4697 u16 subid;
4698
4699 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004700 if ((sp->device_type == XFRAME_II_DEVICE) ||
4701 ((subid & 0xFF) >= 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 val64 = readq(&bar0->gpio_control);
4703 val64 ^= GPIO_CTRL_GPIO_0;
4704 writeq(val64, &bar0->gpio_control);
4705 } else {
4706 val64 = readq(&bar0->adapter_control);
4707 val64 ^= ADAPTER_LED_ON;
4708 writeq(val64, &bar0->adapter_control);
4709 }
4710
4711 mod_timer(&sp->id_timer, jiffies + HZ / 2);
4712}
4713
4714/**
4715 * s2io_ethtool_idnic - To physically identify the nic on the system.
4716 * @sp : private member of the device structure, which is a pointer to the
4717 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004718 * @id : pointer to the structure with identification parameters given by
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 * ethtool.
4720 * Description: Used to physically identify the NIC on the system.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004721 * The Link LED will blink for a time specified by the user for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 * identification.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004723 * NOTE: The Link has to be Up to be able to blink the LED. Hence
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 * identification is possible only if it's link is up.
4725 * Return value:
4726 * int , returns 0 on success
4727 */
4728
4729static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
4730{
4731 u64 val64 = 0, last_gpio_ctrl_val;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004732 struct s2io_nic *sp = dev->priv;
4733 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 u16 subid;
4735
4736 subid = sp->pdev->subsystem_device;
4737 last_gpio_ctrl_val = readq(&bar0->gpio_control);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004738 if ((sp->device_type == XFRAME_I_DEVICE) &&
4739 ((subid & 0xFF) < 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 val64 = readq(&bar0->adapter_control);
4741 if (!(val64 & ADAPTER_CNTL_EN)) {
4742 printk(KERN_ERR
4743 "Adapter Link down, cannot blink LED\n");
4744 return -EFAULT;
4745 }
4746 }
4747 if (sp->id_timer.function == NULL) {
4748 init_timer(&sp->id_timer);
4749 sp->id_timer.function = s2io_phy_id;
4750 sp->id_timer.data = (unsigned long) sp;
4751 }
4752 mod_timer(&sp->id_timer, jiffies);
4753 if (data)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004754 msleep_interruptible(data * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004756 msleep_interruptible(MAX_FLICKER_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 del_timer_sync(&sp->id_timer);
4758
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004759 if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 writeq(last_gpio_ctrl_val, &bar0->gpio_control);
4761 last_gpio_ctrl_val = readq(&bar0->gpio_control);
4762 }
4763
4764 return 0;
4765}
4766
4767/**
4768 * s2io_ethtool_getpause_data -Pause frame frame generation and reception.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004769 * @sp : private member of the device structure, which is a pointer to the
4770 * s2io_nic structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 * @ep : pointer to the structure with pause parameters given by ethtool.
4772 * Description:
4773 * Returns the Pause frame generation and reception capability of the NIC.
4774 * Return value:
4775 * void
4776 */
4777static void s2io_ethtool_getpause_data(struct net_device *dev,
4778 struct ethtool_pauseparam *ep)
4779{
4780 u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004781 struct s2io_nic *sp = dev->priv;
4782 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783
4784 val64 = readq(&bar0->rmac_pause_cfg);
4785 if (val64 & RMAC_PAUSE_GEN_ENABLE)
4786 ep->tx_pause = TRUE;
4787 if (val64 & RMAC_PAUSE_RX_ENABLE)
4788 ep->rx_pause = TRUE;
4789 ep->autoneg = FALSE;
4790}
4791
4792/**
4793 * s2io_ethtool_setpause_data - set/reset pause frame generation.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004794 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 * s2io_nic structure.
4796 * @ep : pointer to the structure with pause parameters given by ethtool.
4797 * Description:
4798 * It can be used to set or reset Pause frame generation or reception
4799 * support of the NIC.
4800 * Return value:
4801 * int, returns 0 on Success
4802 */
4803
4804static int s2io_ethtool_setpause_data(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004805 struct ethtool_pauseparam *ep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806{
4807 u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004808 struct s2io_nic *sp = dev->priv;
4809 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810
4811 val64 = readq(&bar0->rmac_pause_cfg);
4812 if (ep->tx_pause)
4813 val64 |= RMAC_PAUSE_GEN_ENABLE;
4814 else
4815 val64 &= ~RMAC_PAUSE_GEN_ENABLE;
4816 if (ep->rx_pause)
4817 val64 |= RMAC_PAUSE_RX_ENABLE;
4818 else
4819 val64 &= ~RMAC_PAUSE_RX_ENABLE;
4820 writeq(val64, &bar0->rmac_pause_cfg);
4821 return 0;
4822}
4823
4824/**
4825 * read_eeprom - reads 4 bytes of data from user given offset.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004826 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 * s2io_nic structure.
4828 * @off : offset at which the data must be written
4829 * @data : Its an output parameter where the data read at the given
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004830 * offset is stored.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004832 * Will read 4 bytes of data from the user given offset and return the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 * read data.
4834 * NOTE: Will allow to read only part of the EEPROM visible through the
4835 * I2C bus.
4836 * Return value:
4837 * -1 on failure and 0 on success.
4838 */
4839
4840#define S2IO_DEV_ID 5
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004841static int read_eeprom(struct s2io_nic * sp, int off, u64 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842{
4843 int ret = -1;
4844 u32 exit_cnt = 0;
4845 u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004846 struct XENA_dev_config __iomem *bar0 = sp->bar0;
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 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4850 I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ |
4851 I2C_CONTROL_CNTL_START;
4852 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004854 while (exit_cnt < 5) {
4855 val64 = readq(&bar0->i2c_control);
4856 if (I2C_CONTROL_CNTL_END(val64)) {
4857 *data = I2C_CONTROL_GET_DATA(val64);
4858 ret = 0;
4859 break;
4860 }
4861 msleep(50);
4862 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864 }
4865
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004866 if (sp->device_type == XFRAME_II_DEVICE) {
4867 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004868 SPI_CONTROL_BYTECNT(0x3) |
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004869 SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off);
4870 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4871 val64 |= SPI_CONTROL_REQ;
4872 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4873 while (exit_cnt < 5) {
4874 val64 = readq(&bar0->spi_control);
4875 if (val64 & SPI_CONTROL_NACK) {
4876 ret = 1;
4877 break;
4878 } else if (val64 & SPI_CONTROL_DONE) {
4879 *data = readq(&bar0->spi_data);
4880 *data &= 0xffffff;
4881 ret = 0;
4882 break;
4883 }
4884 msleep(50);
4885 exit_cnt++;
4886 }
4887 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888 return ret;
4889}
4890
4891/**
4892 * write_eeprom - actually writes the relevant part of the data value.
4893 * @sp : private member of the device structure, which is a pointer to the
4894 * s2io_nic structure.
4895 * @off : offset at which the data must be written
4896 * @data : The data that is to be written
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004897 * @cnt : Number of bytes of the data that are actually to be written into
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 * the Eeprom. (max of 3)
4899 * Description:
4900 * Actually writes the relevant part of the data value into the Eeprom
4901 * through the I2C bus.
4902 * Return value:
4903 * 0 on success, -1 on failure.
4904 */
4905
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004906static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907{
4908 int exit_cnt = 0, ret = -1;
4909 u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004910 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004912 if (sp->device_type == XFRAME_I_DEVICE) {
4913 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4914 I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) |
4915 I2C_CONTROL_CNTL_START;
4916 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004918 while (exit_cnt < 5) {
4919 val64 = readq(&bar0->i2c_control);
4920 if (I2C_CONTROL_CNTL_END(val64)) {
4921 if (!(val64 & I2C_CONTROL_NACK))
4922 ret = 0;
4923 break;
4924 }
4925 msleep(50);
4926 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928 }
4929
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004930 if (sp->device_type == XFRAME_II_DEVICE) {
4931 int write_cnt = (cnt == 8) ? 0 : cnt;
4932 writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data);
4933
4934 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004935 SPI_CONTROL_BYTECNT(write_cnt) |
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004936 SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off);
4937 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4938 val64 |= SPI_CONTROL_REQ;
4939 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4940 while (exit_cnt < 5) {
4941 val64 = readq(&bar0->spi_control);
4942 if (val64 & SPI_CONTROL_NACK) {
4943 ret = 1;
4944 break;
4945 } else if (val64 & SPI_CONTROL_DONE) {
4946 ret = 0;
4947 break;
4948 }
4949 msleep(50);
4950 exit_cnt++;
4951 }
4952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 return ret;
4954}
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004955static void s2io_vpd_read(struct s2io_nic *nic)
Ananda Raju9dc737a2006-04-21 19:05:41 -04004956{
Ananda Rajub41477f2006-07-24 19:52:49 -04004957 u8 *vpd_data;
4958 u8 data;
Ananda Raju9dc737a2006-04-21 19:05:41 -04004959 int i=0, cnt, fail = 0;
4960 int vpd_addr = 0x80;
4961
4962 if (nic->device_type == XFRAME_II_DEVICE) {
4963 strcpy(nic->product_name, "Xframe II 10GbE network adapter");
4964 vpd_addr = 0x80;
4965 }
4966 else {
4967 strcpy(nic->product_name, "Xframe I 10GbE network adapter");
4968 vpd_addr = 0x50;
4969 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004970 strcpy(nic->serial_num, "NOT AVAILABLE");
Ananda Raju9dc737a2006-04-21 19:05:41 -04004971
Ananda Rajub41477f2006-07-24 19:52:49 -04004972 vpd_data = kmalloc(256, GFP_KERNEL);
4973 if (!vpd_data)
4974 return;
4975
Ananda Raju9dc737a2006-04-21 19:05:41 -04004976 for (i = 0; i < 256; i +=4 ) {
4977 pci_write_config_byte(nic->pdev, (vpd_addr + 2), i);
4978 pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data);
4979 pci_write_config_byte(nic->pdev, (vpd_addr + 3), 0);
4980 for (cnt = 0; cnt <5; cnt++) {
4981 msleep(2);
4982 pci_read_config_byte(nic->pdev, (vpd_addr + 3), &data);
4983 if (data == 0x80)
4984 break;
4985 }
4986 if (cnt >= 5) {
4987 DBG_PRINT(ERR_DBG, "Read of VPD data failed\n");
4988 fail = 1;
4989 break;
4990 }
4991 pci_read_config_dword(nic->pdev, (vpd_addr + 4),
4992 (u32 *)&vpd_data[i]);
4993 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004994
4995 if(!fail) {
4996 /* read serial number of adapter */
4997 for (cnt = 0; cnt < 256; cnt++) {
4998 if ((vpd_data[cnt] == 'S') &&
4999 (vpd_data[cnt+1] == 'N') &&
5000 (vpd_data[cnt+2] < VPD_STRING_LEN)) {
5001 memset(nic->serial_num, 0, VPD_STRING_LEN);
5002 memcpy(nic->serial_num, &vpd_data[cnt + 3],
5003 vpd_data[cnt+2]);
5004 break;
5005 }
5006 }
5007 }
5008
5009 if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04005010 memset(nic->product_name, 0, vpd_data[1]);
5011 memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
5012 }
Ananda Rajub41477f2006-07-24 19:52:49 -04005013 kfree(vpd_data);
Ananda Raju9dc737a2006-04-21 19:05:41 -04005014}
5015
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016/**
5017 * s2io_ethtool_geeprom - reads the value stored in the Eeprom.
5018 * @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 -07005019 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 * containing all relevant information.
5021 * @data_buf : user defined value to be written into Eeprom.
5022 * Description: Reads the values stored in the Eeprom at given offset
5023 * for a given length. Stores these values int the input argument data
5024 * buffer 'data_buf' and returns these to the caller (ethtool.)
5025 * Return value:
5026 * int 0 on success
5027 */
5028
5029static int s2io_ethtool_geeprom(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005030 struct ethtool_eeprom *eeprom, u8 * data_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031{
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005032 u32 i, valid;
5033 u64 data;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005034 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035
5036 eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
5037
5038 if ((eeprom->offset + eeprom->len) > (XENA_EEPROM_SPACE))
5039 eeprom->len = XENA_EEPROM_SPACE - eeprom->offset;
5040
5041 for (i = 0; i < eeprom->len; i += 4) {
5042 if (read_eeprom(sp, (eeprom->offset + i), &data)) {
5043 DBG_PRINT(ERR_DBG, "Read of EEPROM failed\n");
5044 return -EFAULT;
5045 }
5046 valid = INV(data);
5047 memcpy((data_buf + i), &valid, 4);
5048 }
5049 return 0;
5050}
5051
5052/**
5053 * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom
5054 * @sp : private member of the device structure, which is a pointer to the
5055 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005056 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 * containing all relevant information.
5058 * @data_buf ; user defined value to be written into Eeprom.
5059 * Description:
5060 * Tries to write the user provided value in the Eeprom, at the offset
5061 * given by the user.
5062 * Return value:
5063 * 0 on success, -EFAULT on failure.
5064 */
5065
5066static int s2io_ethtool_seeprom(struct net_device *dev,
5067 struct ethtool_eeprom *eeprom,
5068 u8 * data_buf)
5069{
5070 int len = eeprom->len, cnt = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005071 u64 valid = 0, data;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005072 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073
5074 if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
5075 DBG_PRINT(ERR_DBG,
5076 "ETHTOOL_WRITE_EEPROM Err: Magic value ");
5077 DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n",
5078 eeprom->magic);
5079 return -EFAULT;
5080 }
5081
5082 while (len) {
5083 data = (u32) data_buf[cnt] & 0x000000FF;
5084 if (data) {
5085 valid = (u32) (data << 24);
5086 } else
5087 valid = data;
5088
5089 if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) {
5090 DBG_PRINT(ERR_DBG,
5091 "ETHTOOL_WRITE_EEPROM Err: Cannot ");
5092 DBG_PRINT(ERR_DBG,
5093 "write into the specified offset\n");
5094 return -EFAULT;
5095 }
5096 cnt++;
5097 len--;
5098 }
5099
5100 return 0;
5101}
5102
5103/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005104 * s2io_register_test - reads and writes into all clock domains.
5105 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 * s2io_nic structure.
5107 * @data : variable that returns the result of each of the test conducted b
5108 * by the driver.
5109 * Description:
5110 * Read and write into all clock domains. The NIC has 3 clock domains,
5111 * see that registers in all the three regions are accessible.
5112 * Return value:
5113 * 0 on success.
5114 */
5115
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005116static int s2io_register_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005118 struct XENA_dev_config __iomem *bar0 = sp->bar0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005119 u64 val64 = 0, exp_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 int fail = 0;
5121
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005122 val64 = readq(&bar0->pif_rd_swapper_fb);
5123 if (val64 != 0x123456789abcdefULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 fail = 1;
5125 DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n");
5126 }
5127
5128 val64 = readq(&bar0->rmac_pause_cfg);
5129 if (val64 != 0xc000ffff00000000ULL) {
5130 fail = 1;
5131 DBG_PRINT(INFO_DBG, "Read Test level 2 fails\n");
5132 }
5133
5134 val64 = readq(&bar0->rx_queue_cfg);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005135 if (sp->device_type == XFRAME_II_DEVICE)
5136 exp_val = 0x0404040404040404ULL;
5137 else
5138 exp_val = 0x0808080808080808ULL;
5139 if (val64 != exp_val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 fail = 1;
5141 DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n");
5142 }
5143
5144 val64 = readq(&bar0->xgxs_efifo_cfg);
5145 if (val64 != 0x000000001923141EULL) {
5146 fail = 1;
5147 DBG_PRINT(INFO_DBG, "Read Test level 4 fails\n");
5148 }
5149
5150 val64 = 0x5A5A5A5A5A5A5A5AULL;
5151 writeq(val64, &bar0->xmsi_data);
5152 val64 = readq(&bar0->xmsi_data);
5153 if (val64 != 0x5A5A5A5A5A5A5A5AULL) {
5154 fail = 1;
5155 DBG_PRINT(ERR_DBG, "Write Test level 1 fails\n");
5156 }
5157
5158 val64 = 0xA5A5A5A5A5A5A5A5ULL;
5159 writeq(val64, &bar0->xmsi_data);
5160 val64 = readq(&bar0->xmsi_data);
5161 if (val64 != 0xA5A5A5A5A5A5A5A5ULL) {
5162 fail = 1;
5163 DBG_PRINT(ERR_DBG, "Write Test level 2 fails\n");
5164 }
5165
5166 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005167 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168}
5169
5170/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005171 * s2io_eeprom_test - to verify that EEprom in the xena can be programmed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 * @sp : private member of the device structure, which is a pointer to the
5173 * s2io_nic structure.
5174 * @data:variable that returns the result of each of the test conducted by
5175 * the driver.
5176 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005177 * Verify that EEPROM in the xena can be programmed using I2C_CONTROL
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 * register.
5179 * Return value:
5180 * 0 on success.
5181 */
5182
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005183static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184{
5185 int fail = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005186 u64 ret_data, org_4F0, org_7F0;
5187 u8 saved_4F0 = 0, saved_7F0 = 0;
5188 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189
5190 /* Test Write Error at offset 0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005191 /* Note that SPI interface allows write access to all areas
5192 * of EEPROM. Hence doing all negative testing only for Xframe I.
5193 */
5194 if (sp->device_type == XFRAME_I_DEVICE)
5195 if (!write_eeprom(sp, 0, 0, 3))
5196 fail = 1;
5197
5198 /* Save current values at offsets 0x4F0 and 0x7F0 */
5199 if (!read_eeprom(sp, 0x4F0, &org_4F0))
5200 saved_4F0 = 1;
5201 if (!read_eeprom(sp, 0x7F0, &org_7F0))
5202 saved_7F0 = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203
5204 /* Test Write at offset 4f0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005205 if (write_eeprom(sp, 0x4F0, 0x012345, 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 fail = 1;
5207 if (read_eeprom(sp, 0x4F0, &ret_data))
5208 fail = 1;
5209
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005210 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005211 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. "
5212 "Data written %llx Data read %llx\n",
5213 dev->name, (unsigned long long)0x12345,
5214 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005216 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217
5218 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005219 write_eeprom(sp, 0x4F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220
5221 /* Test Write Request Error at offset 0x7c */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005222 if (sp->device_type == XFRAME_I_DEVICE)
5223 if (!write_eeprom(sp, 0x07C, 0, 3))
5224 fail = 1;
5225
5226 /* Test Write Request at offset 0x7f0 */
5227 if (write_eeprom(sp, 0x7F0, 0x012345, 3))
5228 fail = 1;
5229 if (read_eeprom(sp, 0x7F0, &ret_data))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 fail = 1;
5231
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005232 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005233 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. "
5234 "Data written %llx Data read %llx\n",
5235 dev->name, (unsigned long long)0x12345,
5236 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239
5240 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005241 write_eeprom(sp, 0x7F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005243 if (sp->device_type == XFRAME_I_DEVICE) {
5244 /* Test Write Error at offset 0x80 */
5245 if (!write_eeprom(sp, 0x080, 0, 3))
5246 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005248 /* Test Write Error at offset 0xfc */
5249 if (!write_eeprom(sp, 0x0FC, 0, 3))
5250 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005252 /* Test Write Error at offset 0x100 */
5253 if (!write_eeprom(sp, 0x100, 0, 3))
5254 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005256 /* Test Write Error at offset 4ec */
5257 if (!write_eeprom(sp, 0x4EC, 0, 3))
5258 fail = 1;
5259 }
5260
5261 /* Restore values at offsets 0x4F0 and 0x7F0 */
5262 if (saved_4F0)
5263 write_eeprom(sp, 0x4F0, org_4F0, 3);
5264 if (saved_7F0)
5265 write_eeprom(sp, 0x7F0, org_7F0, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266
5267 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005268 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269}
5270
5271/**
5272 * s2io_bist_test - invokes the MemBist test of the card .
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005273 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005275 * @data:variable that returns the result of each of the test conducted by
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 * the driver.
5277 * Description:
5278 * This invokes the MemBist test of the card. We give around
5279 * 2 secs time for the Test to complete. If it's still not complete
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005280 * within this peiod, we consider that the test failed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 * Return value:
5282 * 0 on success and -1 on failure.
5283 */
5284
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005285static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286{
5287 u8 bist = 0;
5288 int cnt = 0, ret = -1;
5289
5290 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5291 bist |= PCI_BIST_START;
5292 pci_write_config_word(sp->pdev, PCI_BIST, bist);
5293
5294 while (cnt < 20) {
5295 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5296 if (!(bist & PCI_BIST_START)) {
5297 *data = (bist & PCI_BIST_CODE_MASK);
5298 ret = 0;
5299 break;
5300 }
5301 msleep(100);
5302 cnt++;
5303 }
5304
5305 return ret;
5306}
5307
5308/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005309 * s2io-link_test - verifies the link state of the nic
5310 * @sp ; private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 * s2io_nic structure.
5312 * @data: variable that returns the result of each of the test conducted by
5313 * the driver.
5314 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005315 * The function verifies the link state of the NIC and updates the input
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 * argument 'data' appropriately.
5317 * Return value:
5318 * 0 on success.
5319 */
5320
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005321static int s2io_link_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005323 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 u64 val64;
5325
5326 val64 = readq(&bar0->adapter_status);
Ananda Rajuc92ca042006-04-21 19:18:03 -04005327 if(!(LINK_IS_UP(val64)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328 *data = 1;
Ananda Rajuc92ca042006-04-21 19:18:03 -04005329 else
5330 *data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331
Ananda Rajub41477f2006-07-24 19:52:49 -04005332 return *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333}
5334
5335/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005336 * s2io_rldram_test - offline test for access to the RldRam chip on the NIC
5337 * @sp - private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005339 * @data - variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 * conducted by the driver.
5341 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005342 * This is one of the offline test that tests the read and write
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 * access to the RldRam chip on the NIC.
5344 * Return value:
5345 * 0 on success.
5346 */
5347
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005348static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005349{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005350 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 u64 val64;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005352 int cnt, iteration = 0, test_fail = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353
5354 val64 = readq(&bar0->adapter_control);
5355 val64 &= ~ADAPTER_ECC_EN;
5356 writeq(val64, &bar0->adapter_control);
5357
5358 val64 = readq(&bar0->mc_rldram_test_ctrl);
5359 val64 |= MC_RLDRAM_TEST_MODE;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005360 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361
5362 val64 = readq(&bar0->mc_rldram_mrs);
5363 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE;
5364 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5365
5366 val64 |= MC_RLDRAM_MRS_ENABLE;
5367 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5368
5369 while (iteration < 2) {
5370 val64 = 0x55555555aaaa0000ULL;
5371 if (iteration == 1) {
5372 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5373 }
5374 writeq(val64, &bar0->mc_rldram_test_d0);
5375
5376 val64 = 0xaaaa5a5555550000ULL;
5377 if (iteration == 1) {
5378 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5379 }
5380 writeq(val64, &bar0->mc_rldram_test_d1);
5381
5382 val64 = 0x55aaaaaaaa5a0000ULL;
5383 if (iteration == 1) {
5384 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5385 }
5386 writeq(val64, &bar0->mc_rldram_test_d2);
5387
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005388 val64 = (u64) (0x0000003ffffe0100ULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 writeq(val64, &bar0->mc_rldram_test_add);
5390
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005391 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE |
5392 MC_RLDRAM_TEST_GO;
5393 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394
5395 for (cnt = 0; cnt < 5; cnt++) {
5396 val64 = readq(&bar0->mc_rldram_test_ctrl);
5397 if (val64 & MC_RLDRAM_TEST_DONE)
5398 break;
5399 msleep(200);
5400 }
5401
5402 if (cnt == 5)
5403 break;
5404
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005405 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO;
5406 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407
5408 for (cnt = 0; cnt < 5; cnt++) {
5409 val64 = readq(&bar0->mc_rldram_test_ctrl);
5410 if (val64 & MC_RLDRAM_TEST_DONE)
5411 break;
5412 msleep(500);
5413 }
5414
5415 if (cnt == 5)
5416 break;
5417
5418 val64 = readq(&bar0->mc_rldram_test_ctrl);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005419 if (!(val64 & MC_RLDRAM_TEST_PASS))
5420 test_fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421
5422 iteration++;
5423 }
5424
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005425 *data = test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005427 /* Bring the adapter out of test mode */
5428 SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF);
5429
5430 return test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431}
5432
5433/**
5434 * s2io_ethtool_test - conducts 6 tsets to determine the health of card.
5435 * @sp : private member of the device structure, which is a pointer to the
5436 * s2io_nic structure.
5437 * @ethtest : pointer to a ethtool command specific structure that will be
5438 * returned to the user.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005439 * @data : variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440 * conducted by the driver.
5441 * Description:
5442 * This function conducts 6 tests ( 4 offline and 2 online) to determine
5443 * the health of the card.
5444 * Return value:
5445 * void
5446 */
5447
5448static void s2io_ethtool_test(struct net_device *dev,
5449 struct ethtool_test *ethtest,
5450 uint64_t * data)
5451{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005452 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 int orig_state = netif_running(sp->dev);
5454
5455 if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
5456 /* Offline Tests. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005457 if (orig_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 s2io_close(sp->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459
5460 if (s2io_register_test(sp, &data[0]))
5461 ethtest->flags |= ETH_TEST_FL_FAILED;
5462
5463 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464
5465 if (s2io_rldram_test(sp, &data[3]))
5466 ethtest->flags |= ETH_TEST_FL_FAILED;
5467
5468 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469
5470 if (s2io_eeprom_test(sp, &data[1]))
5471 ethtest->flags |= ETH_TEST_FL_FAILED;
5472
5473 if (s2io_bist_test(sp, &data[4]))
5474 ethtest->flags |= ETH_TEST_FL_FAILED;
5475
5476 if (orig_state)
5477 s2io_open(sp->dev);
5478
5479 data[2] = 0;
5480 } else {
5481 /* Online Tests. */
5482 if (!orig_state) {
5483 DBG_PRINT(ERR_DBG,
5484 "%s: is not up, cannot run test\n",
5485 dev->name);
5486 data[0] = -1;
5487 data[1] = -1;
5488 data[2] = -1;
5489 data[3] = -1;
5490 data[4] = -1;
5491 }
5492
5493 if (s2io_link_test(sp, &data[2]))
5494 ethtest->flags |= ETH_TEST_FL_FAILED;
5495
5496 data[0] = 0;
5497 data[1] = 0;
5498 data[3] = 0;
5499 data[4] = 0;
5500 }
5501}
5502
5503static void s2io_get_ethtool_stats(struct net_device *dev,
5504 struct ethtool_stats *estats,
5505 u64 * tmp_stats)
5506{
5507 int i = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005508 struct s2io_nic *sp = dev->priv;
5509 struct stat_block *stat_info = sp->mac_control.stats_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005511 s2io_updt_stats(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005512 tmp_stats[i++] =
5513 (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32 |
5514 le32_to_cpu(stat_info->tmac_frms);
5515 tmp_stats[i++] =
5516 (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 |
5517 le32_to_cpu(stat_info->tmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005519 tmp_stats[i++] =
5520 (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 |
5521 le32_to_cpu(stat_info->tmac_mcst_frms);
5522 tmp_stats[i++] =
5523 (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 |
5524 le32_to_cpu(stat_info->tmac_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005526 tmp_stats[i++] =
5527 (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 |
5528 le32_to_cpu(stat_info->tmac_ttl_octets);
5529 tmp_stats[i++] =
5530 (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 |
5531 le32_to_cpu(stat_info->tmac_ucst_frms);
5532 tmp_stats[i++] =
5533 (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 |
5534 le32_to_cpu(stat_info->tmac_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005535 tmp_stats[i++] =
5536 (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 |
5537 le32_to_cpu(stat_info->tmac_any_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005538 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005540 tmp_stats[i++] =
5541 (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 |
5542 le32_to_cpu(stat_info->tmac_vld_ip);
5543 tmp_stats[i++] =
5544 (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 |
5545 le32_to_cpu(stat_info->tmac_drop_ip);
5546 tmp_stats[i++] =
5547 (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 |
5548 le32_to_cpu(stat_info->tmac_icmp);
5549 tmp_stats[i++] =
5550 (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 |
5551 le32_to_cpu(stat_info->tmac_rst_tcp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005553 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 |
5554 le32_to_cpu(stat_info->tmac_udp);
5555 tmp_stats[i++] =
5556 (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 |
5557 le32_to_cpu(stat_info->rmac_vld_frms);
5558 tmp_stats[i++] =
5559 (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 |
5560 le32_to_cpu(stat_info->rmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms);
5562 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005563 tmp_stats[i++] =
5564 (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 |
5565 le32_to_cpu(stat_info->rmac_vld_mcst_frms);
5566 tmp_stats[i++] =
5567 (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 |
5568 le32_to_cpu(stat_info->rmac_vld_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005570 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_out_rng_len_err_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms);
5572 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005573 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_unsup_ctrl_frms);
5574 tmp_stats[i++] =
5575 (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 |
5576 le32_to_cpu(stat_info->rmac_ttl_octets);
5577 tmp_stats[i++] =
5578 (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow)
5579 << 32 | le32_to_cpu(stat_info->rmac_accepted_ucst_frms);
5580 tmp_stats[i++] =
5581 (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow)
5582 << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005583 tmp_stats[i++] =
5584 (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 |
5585 le32_to_cpu(stat_info->rmac_discarded_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005586 tmp_stats[i++] =
5587 (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow)
5588 << 32 | le32_to_cpu(stat_info->rmac_drop_events);
5589 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets);
5590 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005591 tmp_stats[i++] =
5592 (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 |
5593 le32_to_cpu(stat_info->rmac_usized_frms);
5594 tmp_stats[i++] =
5595 (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 |
5596 le32_to_cpu(stat_info->rmac_osized_frms);
5597 tmp_stats[i++] =
5598 (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 |
5599 le32_to_cpu(stat_info->rmac_frag_frms);
5600 tmp_stats[i++] =
5601 (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 |
5602 le32_to_cpu(stat_info->rmac_jabber_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005603 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_64_frms);
5604 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms);
5605 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms);
5606 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms);
5607 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms);
5608 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms);
5609 tmp_stats[i++] =
5610 (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005611 le32_to_cpu(stat_info->rmac_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets);
5613 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005614 tmp_stats[i++] =
5615 (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005616 le32_to_cpu(stat_info->rmac_drop_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005617 tmp_stats[i++] =
5618 (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005619 le32_to_cpu(stat_info->rmac_icmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005621 tmp_stats[i++] =
5622 (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005623 le32_to_cpu(stat_info->rmac_udp);
5624 tmp_stats[i++] =
5625 (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 |
5626 le32_to_cpu(stat_info->rmac_err_drp_udp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005627 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_err_sym);
5628 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0);
5629 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1);
5630 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2);
5631 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3);
5632 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4);
5633 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5);
5634 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6);
5635 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7);
5636 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0);
5637 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1);
5638 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2);
5639 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3);
5640 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4);
5641 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5);
5642 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6);
5643 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005644 tmp_stats[i++] =
5645 (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 |
5646 le32_to_cpu(stat_info->rmac_pause_cnt);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005647 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_data_err_cnt);
5648 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005649 tmp_stats[i++] =
5650 (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 |
5651 le32_to_cpu(stat_info->rmac_accepted_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005653 tmp_stats[i++] = le32_to_cpu(stat_info->rd_req_cnt);
5654 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_cnt);
5655 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_rtry_cnt);
5656 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_cnt);
5657 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_rd_ack_cnt);
5658 tmp_stats[i++] = le32_to_cpu(stat_info->wr_req_cnt);
5659 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_cnt);
5660 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_rtry_cnt);
5661 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_cnt);
5662 tmp_stats[i++] = le32_to_cpu(stat_info->wr_disc_cnt);
5663 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_wr_ack_cnt);
5664 tmp_stats[i++] = le32_to_cpu(stat_info->txp_wr_cnt);
5665 tmp_stats[i++] = le32_to_cpu(stat_info->txd_rd_cnt);
5666 tmp_stats[i++] = le32_to_cpu(stat_info->txd_wr_cnt);
5667 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_rd_cnt);
5668 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_wr_cnt);
5669 tmp_stats[i++] = le32_to_cpu(stat_info->txf_rd_cnt);
5670 tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt);
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -05005671
5672 /* Enhanced statistics exist only for Hercules */
5673 if(sp->device_type == XFRAME_II_DEVICE) {
5674 tmp_stats[i++] =
5675 le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms);
5676 tmp_stats[i++] =
5677 le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms);
5678 tmp_stats[i++] =
5679 le64_to_cpu(stat_info->rmac_ttl_8192_max_frms);
5680 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms);
5681 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms);
5682 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms);
5683 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms);
5684 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms);
5685 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard);
5686 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard);
5687 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard);
5688 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard);
5689 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard);
5690 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard);
5691 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard);
5692 tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt);
5693 }
5694
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005695 tmp_stats[i++] = 0;
5696 tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
5697 tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
Ananda Rajubd1034f2006-04-21 19:20:22 -04005698 tmp_stats[i++] = stat_info->sw_stat.parity_err_cnt;
5699 tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt;
5700 tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt;
5701 tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt;
5702 tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt;
5703 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high;
5704 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low;
5705 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high;
5706 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_low;
5707 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_high;
5708 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_low;
5709 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_high;
5710 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_low;
5711 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_high;
5712 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_low;
5713 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_high;
5714 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_low;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005715 tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt;
5716 tmp_stats[i++] = stat_info->sw_stat.sending_both;
5717 tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts;
5718 tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts;
Andrew Mortonfe931392006-02-03 01:45:12 -08005719 if (stat_info->sw_stat.num_aggregations) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04005720 u64 tmp = stat_info->sw_stat.sum_avg_pkts_aggregated;
5721 int count = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005722 /*
Ananda Rajubd1034f2006-04-21 19:20:22 -04005723 * Since 64-bit divide does not work on all platforms,
5724 * do repeated subtraction.
5725 */
5726 while (tmp >= stat_info->sw_stat.num_aggregations) {
5727 tmp -= stat_info->sw_stat.num_aggregations;
5728 count++;
5729 }
5730 tmp_stats[i++] = count;
Andrew Mortonfe931392006-02-03 01:45:12 -08005731 }
Ananda Rajubd1034f2006-04-21 19:20:22 -04005732 else
5733 tmp_stats[i++] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734}
5735
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005736static int s2io_ethtool_get_regs_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737{
5738 return (XENA_REG_SPACE);
5739}
5740
5741
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005742static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005744 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745
5746 return (sp->rx_csum);
5747}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005748
5749static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005751 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752
5753 if (data)
5754 sp->rx_csum = 1;
5755 else
5756 sp->rx_csum = 0;
5757
5758 return 0;
5759}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005760
5761static int s2io_get_eeprom_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762{
5763 return (XENA_EEPROM_SPACE);
5764}
5765
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005766static int s2io_ethtool_self_test_count(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767{
5768 return (S2IO_TEST_LEN);
5769}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005770
5771static void s2io_ethtool_get_strings(struct net_device *dev,
5772 u32 stringset, u8 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773{
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -05005774 int stat_size = 0;
5775 struct s2io_nic *sp = dev->priv;
5776
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777 switch (stringset) {
5778 case ETH_SS_TEST:
5779 memcpy(data, s2io_gstrings, S2IO_STRINGS_LEN);
5780 break;
5781 case ETH_SS_STATS:
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -05005782 stat_size = sizeof(ethtool_xena_stats_keys);
5783 memcpy(data, &ethtool_xena_stats_keys,stat_size);
5784 if(sp->device_type == XFRAME_II_DEVICE) {
5785 memcpy(data + stat_size,
5786 &ethtool_enhanced_stats_keys,
5787 sizeof(ethtool_enhanced_stats_keys));
5788 stat_size += sizeof(ethtool_enhanced_stats_keys);
5789 }
5790
5791 memcpy(data + stat_size, &ethtool_driver_stats_keys,
5792 sizeof(ethtool_driver_stats_keys));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793 }
5794}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795static int s2io_ethtool_get_stats_count(struct net_device *dev)
5796{
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -05005797 struct s2io_nic *sp = dev->priv;
5798 int stat_count = 0;
5799 switch(sp->device_type) {
5800 case XFRAME_I_DEVICE:
5801 stat_count = XFRAME_I_STAT_LEN;
5802 break;
5803
5804 case XFRAME_II_DEVICE:
5805 stat_count = XFRAME_II_STAT_LEN;
5806 break;
5807 }
5808
5809 return stat_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810}
5811
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005812static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813{
5814 if (data)
5815 dev->features |= NETIF_F_IP_CSUM;
5816 else
5817 dev->features &= ~NETIF_F_IP_CSUM;
5818
5819 return 0;
5820}
5821
Ananda Raju75c30b12006-07-24 19:55:09 -04005822static u32 s2io_ethtool_op_get_tso(struct net_device *dev)
5823{
5824 return (dev->features & NETIF_F_TSO) != 0;
5825}
5826static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data)
5827{
5828 if (data)
5829 dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
5830 else
5831 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
5832
5833 return 0;
5834}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835
Jeff Garzik7282d492006-09-13 14:30:00 -04005836static const struct ethtool_ops netdev_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837 .get_settings = s2io_ethtool_gset,
5838 .set_settings = s2io_ethtool_sset,
5839 .get_drvinfo = s2io_ethtool_gdrvinfo,
5840 .get_regs_len = s2io_ethtool_get_regs_len,
5841 .get_regs = s2io_ethtool_gregs,
5842 .get_link = ethtool_op_get_link,
5843 .get_eeprom_len = s2io_get_eeprom_len,
5844 .get_eeprom = s2io_ethtool_geeprom,
5845 .set_eeprom = s2io_ethtool_seeprom,
5846 .get_pauseparam = s2io_ethtool_getpause_data,
5847 .set_pauseparam = s2io_ethtool_setpause_data,
5848 .get_rx_csum = s2io_ethtool_get_rx_csum,
5849 .set_rx_csum = s2io_ethtool_set_rx_csum,
5850 .get_tx_csum = ethtool_op_get_tx_csum,
5851 .set_tx_csum = s2io_ethtool_op_set_tx_csum,
5852 .get_sg = ethtool_op_get_sg,
5853 .set_sg = ethtool_op_set_sg,
Ananda Raju75c30b12006-07-24 19:55:09 -04005854 .get_tso = s2io_ethtool_op_get_tso,
5855 .set_tso = s2io_ethtool_op_set_tso,
Ananda Rajufed5ecc2005-11-14 15:25:08 -05005856 .get_ufo = ethtool_op_get_ufo,
5857 .set_ufo = ethtool_op_set_ufo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858 .self_test_count = s2io_ethtool_self_test_count,
5859 .self_test = s2io_ethtool_test,
5860 .get_strings = s2io_ethtool_get_strings,
5861 .phys_id = s2io_ethtool_idnic,
5862 .get_stats_count = s2io_ethtool_get_stats_count,
5863 .get_ethtool_stats = s2io_get_ethtool_stats
5864};
5865
5866/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005867 * s2io_ioctl - Entry point for the Ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868 * @dev : Device pointer.
5869 * @ifr : An IOCTL specefic structure, that can contain a pointer to
5870 * a proprietary structure used to pass information to the driver.
5871 * @cmd : This is used to distinguish between the different commands that
5872 * can be passed to the IOCTL functions.
5873 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005874 * Currently there are no special functionality supported in IOCTL, hence
5875 * function always return EOPNOTSUPPORTED
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876 */
5877
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005878static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005879{
5880 return -EOPNOTSUPP;
5881}
5882
5883/**
5884 * s2io_change_mtu - entry point to change MTU size for the device.
5885 * @dev : device pointer.
5886 * @new_mtu : the new MTU size for the device.
5887 * Description: A driver entry point to change MTU size for the device.
5888 * Before changing the MTU the device must be stopped.
5889 * Return value:
5890 * 0 on success and an appropriate (-)ve integer as defined in errno.h
5891 * file on failure.
5892 */
5893
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005894static int s2io_change_mtu(struct net_device *dev, int new_mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005896 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897
5898 if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
5899 DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
5900 dev->name);
5901 return -EPERM;
5902 }
5903
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904 dev->mtu = new_mtu;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005905 if (netif_running(dev)) {
Ananda Rajue6a8fee2006-07-06 23:58:23 -07005906 s2io_card_down(sp);
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005907 netif_stop_queue(dev);
5908 if (s2io_card_up(sp)) {
5909 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
5910 __FUNCTION__);
5911 }
5912 if (netif_queue_stopped(dev))
5913 netif_wake_queue(dev);
5914 } else { /* Device is down */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005915 struct XENA_dev_config __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005916 u64 val64 = new_mtu;
5917
5918 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
5919 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920
5921 return 0;
5922}
5923
5924/**
5925 * s2io_tasklet - Bottom half of the ISR.
5926 * @dev_adr : address of the device structure in dma_addr_t format.
5927 * Description:
5928 * This is the tasklet or the bottom half of the ISR. This is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005929 * an extension of the ISR which is scheduled by the scheduler to be run
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930 * 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 -07005931 * be pushed into the tasklet. For now the tasklet is used only to
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932 * replenish the Rx buffers in the Rx buffer descriptors.
5933 * Return value:
5934 * void.
5935 */
5936
5937static void s2io_tasklet(unsigned long dev_addr)
5938{
5939 struct net_device *dev = (struct net_device *) dev_addr;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005940 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941 int i, ret;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005942 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943 struct config_param *config;
5944
5945 mac_control = &sp->mac_control;
5946 config = &sp->config;
5947
5948 if (!TASKLET_IN_USE) {
5949 for (i = 0; i < config->rx_ring_num; i++) {
5950 ret = fill_rx_buffers(sp, i);
5951 if (ret == -ENOMEM) {
5952 DBG_PRINT(ERR_DBG, "%s: Out of ",
5953 dev->name);
5954 DBG_PRINT(ERR_DBG, "memory in tasklet\n");
5955 break;
5956 } else if (ret == -EFILL) {
5957 DBG_PRINT(ERR_DBG,
5958 "%s: Rx Ring %d is full\n",
5959 dev->name, i);
5960 break;
5961 }
5962 }
5963 clear_bit(0, (&sp->tasklet_status));
5964 }
5965}
5966
5967/**
5968 * s2io_set_link - Set the LInk status
5969 * @data: long pointer to device private structue
5970 * Description: Sets the link status for the adapter
5971 */
5972
David Howellsc4028952006-11-22 14:57:56 +00005973static void s2io_set_link(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005974{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005975 struct s2io_nic *nic = container_of(work, struct s2io_nic, set_link_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976 struct net_device *dev = nic->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005977 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978 register u64 val64;
5979 u16 subid;
5980
Francois Romieu22747d62007-02-15 23:37:50 +01005981 rtnl_lock();
5982
5983 if (!netif_running(dev))
5984 goto out_unlock;
5985
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986 if (test_and_set_bit(0, &(nic->link_state))) {
5987 /* The card is being reset, no point doing anything */
Francois Romieu22747d62007-02-15 23:37:50 +01005988 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989 }
5990
5991 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07005992 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
5993 /*
5994 * Allow a small delay for the NICs self initiated
5995 * cleanup to complete.
5996 */
5997 msleep(100);
5998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999
6000 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006001 if (LINK_IS_UP(val64)) {
6002 if (!(readq(&bar0->adapter_control) & ADAPTER_CNTL_EN)) {
6003 if (verify_xena_quiescence(nic)) {
6004 val64 = readq(&bar0->adapter_control);
6005 val64 |= ADAPTER_CNTL_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006 writeq(val64, &bar0->adapter_control);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006007 if (CARDS_WITH_FAULTY_LINK_INDICATORS(
6008 nic->device_type, subid)) {
6009 val64 = readq(&bar0->gpio_control);
6010 val64 |= GPIO_CTRL_GPIO_0;
6011 writeq(val64, &bar0->gpio_control);
6012 val64 = readq(&bar0->gpio_control);
6013 } else {
6014 val64 |= ADAPTER_LED_ON;
6015 writeq(val64, &bar0->adapter_control);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07006016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017 nic->device_enabled_once = TRUE;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006018 } else {
6019 DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
6020 DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
6021 netif_stop_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006022 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006024 val64 = readq(&bar0->adapter_status);
6025 if (!LINK_IS_UP(val64)) {
6026 DBG_PRINT(ERR_DBG, "%s:", dev->name);
6027 DBG_PRINT(ERR_DBG, " Link down after enabling ");
6028 DBG_PRINT(ERR_DBG, "device \n");
6029 } else
6030 s2io_link(nic, LINK_UP);
6031 } else {
6032 if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
6033 subid)) {
6034 val64 = readq(&bar0->gpio_control);
6035 val64 &= ~GPIO_CTRL_GPIO_0;
6036 writeq(val64, &bar0->gpio_control);
6037 val64 = readq(&bar0->gpio_control);
6038 }
6039 s2io_link(nic, LINK_DOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040 }
6041 clear_bit(0, &(nic->link_state));
Francois Romieu22747d62007-02-15 23:37:50 +01006042
6043out_unlock:
Sivakumar Subramanid8d70ca2007-02-24 02:04:24 -05006044 rtnl_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045}
6046
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006047static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
6048 struct buffAdd *ba,
6049 struct sk_buff **skb, u64 *temp0, u64 *temp1,
6050 u64 *temp2, int size)
Ananda Raju5d3213c2006-04-21 19:23:26 -04006051{
6052 struct net_device *dev = sp->dev;
6053 struct sk_buff *frag_list;
6054
6055 if ((sp->rxd_mode == RXD_MODE_1) && (rxdp->Host_Control == 0)) {
6056 /* allocate skb */
6057 if (*skb) {
6058 DBG_PRINT(INFO_DBG, "SKB is not NULL\n");
6059 /*
6060 * As Rx frame are not going to be processed,
6061 * using same mapped address for the Rxd
6062 * buffer pointer
6063 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006064 ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006065 } else {
6066 *skb = dev_alloc_skb(size);
6067 if (!(*skb)) {
6068 DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
6069 DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
6070 return -ENOMEM ;
6071 }
6072 /* storing the mapped addr in a temp variable
6073 * such it will be used for next rxd whose
6074 * Host Control is NULL
6075 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006076 ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006077 pci_map_single( sp->pdev, (*skb)->data,
6078 size - NET_IP_ALIGN,
6079 PCI_DMA_FROMDEVICE);
6080 rxdp->Host_Control = (unsigned long) (*skb);
6081 }
6082 } else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
6083 /* Two buffer Mode */
6084 if (*skb) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006085 ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
6086 ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
6087 ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006088 } else {
6089 *skb = dev_alloc_skb(size);
David Rientjes2ceaac72006-10-30 14:19:25 -08006090 if (!(*skb)) {
6091 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006092 dev->name);
David Rientjes2ceaac72006-10-30 14:19:25 -08006093 return -ENOMEM;
6094 }
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006095 ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006096 pci_map_single(sp->pdev, (*skb)->data,
6097 dev->mtu + 4,
6098 PCI_DMA_FROMDEVICE);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006099 ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006100 pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
6101 PCI_DMA_FROMDEVICE);
6102 rxdp->Host_Control = (unsigned long) (*skb);
6103
6104 /* Buffer-1 will be dummy buffer not used */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006105 ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006106 pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
6107 PCI_DMA_FROMDEVICE);
6108 }
6109 } else if ((rxdp->Host_Control == 0)) {
6110 /* Three buffer mode */
6111 if (*skb) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006112 ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
6113 ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
6114 ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006115 } else {
6116 *skb = dev_alloc_skb(size);
David Rientjes2ceaac72006-10-30 14:19:25 -08006117 if (!(*skb)) {
6118 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
6119 dev->name);
6120 return -ENOMEM;
6121 }
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006122 ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006123 pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
6124 PCI_DMA_FROMDEVICE);
6125 /* Buffer-1 receives L3/L4 headers */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006126 ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006127 pci_map_single( sp->pdev, (*skb)->data,
6128 l3l4hdr_size + 4,
6129 PCI_DMA_FROMDEVICE);
6130 /*
6131 * skb_shinfo(skb)->frag_list will have L4
6132 * data payload
6133 */
6134 skb_shinfo(*skb)->frag_list = dev_alloc_skb(dev->mtu +
6135 ALIGN_SIZE);
6136 if (skb_shinfo(*skb)->frag_list == NULL) {
6137 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb \
6138 failed\n ", dev->name);
6139 return -ENOMEM ;
6140 }
6141 frag_list = skb_shinfo(*skb)->frag_list;
6142 frag_list->next = NULL;
6143 /*
6144 * Buffer-2 receives L4 data payload
6145 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006146 ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006147 pci_map_single( sp->pdev, frag_list->data,
6148 dev->mtu, PCI_DMA_FROMDEVICE);
6149 }
6150 }
6151 return 0;
6152}
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006153static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp,
6154 int size)
Ananda Raju5d3213c2006-04-21 19:23:26 -04006155{
6156 struct net_device *dev = sp->dev;
6157 if (sp->rxd_mode == RXD_MODE_1) {
6158 rxdp->Control_2 = SET_BUFFER0_SIZE_1( size - NET_IP_ALIGN);
6159 } else if (sp->rxd_mode == RXD_MODE_3B) {
6160 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
6161 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
6162 rxdp->Control_2 |= SET_BUFFER2_SIZE_3( dev->mtu + 4);
6163 } else {
6164 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
6165 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
6166 rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
6167 }
6168}
6169
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006170static int rxd_owner_bit_reset(struct s2io_nic *sp)
Ananda Raju5d3213c2006-04-21 19:23:26 -04006171{
6172 int i, j, k, blk_cnt = 0, size;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006173 struct mac_info * mac_control = &sp->mac_control;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006174 struct config_param *config = &sp->config;
6175 struct net_device *dev = sp->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006176 struct RxD_t *rxdp = NULL;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006177 struct sk_buff *skb = NULL;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006178 struct buffAdd *ba = NULL;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006179 u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0;
6180
6181 /* Calculate the size based on ring mode */
6182 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
6183 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
6184 if (sp->rxd_mode == RXD_MODE_1)
6185 size += NET_IP_ALIGN;
6186 else if (sp->rxd_mode == RXD_MODE_3B)
6187 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
6188 else
6189 size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
6190
6191 for (i = 0; i < config->rx_ring_num; i++) {
6192 blk_cnt = config->rx_cfg[i].num_rxd /
6193 (rxd_count[sp->rxd_mode] +1);
6194
6195 for (j = 0; j < blk_cnt; j++) {
6196 for (k = 0; k < rxd_count[sp->rxd_mode]; k++) {
6197 rxdp = mac_control->rings[i].
6198 rx_blocks[j].rxds[k].virt_addr;
6199 if(sp->rxd_mode >= RXD_MODE_3A)
6200 ba = &mac_control->rings[i].ba[j][k];
Sivakumar Subramaniac1f90d2007-02-24 02:01:31 -05006201 if (set_rxd_buffer_pointer(sp, rxdp, ba,
Ananda Raju5d3213c2006-04-21 19:23:26 -04006202 &skb,(u64 *)&temp0_64,
6203 (u64 *)&temp1_64,
Sivakumar Subramaniac1f90d2007-02-24 02:01:31 -05006204 (u64 *)&temp2_64,
6205 size) == ENOMEM) {
6206 return 0;
6207 }
Ananda Raju5d3213c2006-04-21 19:23:26 -04006208
6209 set_rxd_buffer_size(sp, rxdp, size);
6210 wmb();
6211 /* flip the Ownership bit to Hardware */
6212 rxdp->Control_1 |= RXD_OWN_XENA;
6213 }
6214 }
6215 }
6216 return 0;
6217
6218}
6219
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006220static int s2io_add_isr(struct s2io_nic * sp)
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006221{
6222 int ret = 0;
6223 struct net_device *dev = sp->dev;
6224 int err = 0;
6225
6226 if (sp->intr_type == MSI)
6227 ret = s2io_enable_msi(sp);
6228 else if (sp->intr_type == MSI_X)
6229 ret = s2io_enable_msi_x(sp);
6230 if (ret) {
6231 DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
6232 sp->intr_type = INTA;
6233 }
6234
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006235 /* Store the values of the MSIX table in the struct s2io_nic structure */
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006236 store_xmsi_data(sp);
6237
6238 /* After proper initialization of H/W, register ISR */
6239 if (sp->intr_type == MSI) {
6240 err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
6241 IRQF_SHARED, sp->name, dev);
6242 if (err) {
6243 pci_disable_msi(sp->pdev);
6244 DBG_PRINT(ERR_DBG, "%s: MSI registration failed\n",
6245 dev->name);
6246 return -1;
6247 }
6248 }
6249 if (sp->intr_type == MSI_X) {
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006250 int i, msix_tx_cnt=0,msix_rx_cnt=0;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006251
6252 for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
6253 if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
6254 sprintf(sp->desc[i], "%s:MSI-X-%d-TX",
6255 dev->name, i);
6256 err = request_irq(sp->entries[i].vector,
6257 s2io_msix_fifo_handle, 0, sp->desc[i],
6258 sp->s2io_entries[i].arg);
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006259 /* If either data or addr is zero print it */
6260 if(!(sp->msix_info[i].addr &&
6261 sp->msix_info[i].data)) {
6262 DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx"
6263 "Data:0x%lx\n",sp->desc[i],
6264 (unsigned long long)
6265 sp->msix_info[i].addr,
6266 (unsigned long)
6267 ntohl(sp->msix_info[i].data));
6268 } else {
6269 msix_tx_cnt++;
6270 }
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006271 } else {
6272 sprintf(sp->desc[i], "%s:MSI-X-%d-RX",
6273 dev->name, i);
6274 err = request_irq(sp->entries[i].vector,
6275 s2io_msix_ring_handle, 0, sp->desc[i],
6276 sp->s2io_entries[i].arg);
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006277 /* If either data or addr is zero print it */
6278 if(!(sp->msix_info[i].addr &&
6279 sp->msix_info[i].data)) {
6280 DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx"
6281 "Data:0x%lx\n",sp->desc[i],
6282 (unsigned long long)
6283 sp->msix_info[i].addr,
6284 (unsigned long)
6285 ntohl(sp->msix_info[i].data));
6286 } else {
6287 msix_rx_cnt++;
6288 }
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006289 }
6290 if (err) {
6291 DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
6292 "failed\n", dev->name, i);
6293 DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
6294 return -1;
6295 }
6296 sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
6297 }
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006298 printk("MSI-X-TX %d entries enabled\n",msix_tx_cnt);
6299 printk("MSI-X-RX %d entries enabled\n",msix_rx_cnt);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006300 }
6301 if (sp->intr_type == INTA) {
6302 err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
6303 sp->name, dev);
6304 if (err) {
6305 DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
6306 dev->name);
6307 return -1;
6308 }
6309 }
6310 return 0;
6311}
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006312static void s2io_rem_isr(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006313{
6314 int cnt = 0;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006315 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006317 if (sp->intr_type == MSI_X) {
6318 int i;
6319 u16 msi_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006321 for (i=1; (sp->s2io_entries[i].in_use ==
6322 MSIX_REGISTERED_SUCCESS); i++) {
6323 int vector = sp->entries[i].vector;
6324 void *arg = sp->s2io_entries[i].arg;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006325
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006326 free_irq(vector, arg);
6327 }
6328 pci_read_config_word(sp->pdev, 0x42, &msi_control);
6329 msi_control &= 0xFFFE; /* Disable MSI */
6330 pci_write_config_word(sp->pdev, 0x42, msi_control);
Ananda Rajuc92ca042006-04-21 19:18:03 -04006331
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006332 pci_disable_msix(sp->pdev);
6333 } else {
6334 free_irq(sp->pdev->irq, dev);
6335 if (sp->intr_type == MSI) {
6336 u16 val;
6337
6338 pci_disable_msi(sp->pdev);
6339 pci_read_config_word(sp->pdev, 0x4c, &val);
6340 val ^= 0x1;
6341 pci_write_config_word(sp->pdev, 0x4c, val);
Ananda Rajuc92ca042006-04-21 19:18:03 -04006342 }
6343 }
6344 /* Waiting till all Interrupt handlers are complete */
6345 cnt = 0;
6346 do {
6347 msleep(10);
6348 if (!atomic_read(&sp->isr_cnt))
6349 break;
6350 cnt++;
6351 } while(cnt < 5);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006352}
6353
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006354static void s2io_card_down(struct s2io_nic * sp)
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006355{
6356 int cnt = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006357 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006358 unsigned long flags;
6359 register u64 val64 = 0;
6360
6361 del_timer_sync(&sp->alarm_timer);
6362 /* If s2io_set_link task is executing, wait till it completes. */
6363 while (test_and_set_bit(0, &(sp->link_state))) {
6364 msleep(50);
6365 }
6366 atomic_set(&sp->card_state, CARD_DOWN);
6367
6368 /* disable Tx and Rx traffic on the NIC */
6369 stop_nic(sp);
6370
6371 s2io_rem_isr(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372
6373 /* Kill tasklet. */
6374 tasklet_kill(&sp->task);
6375
6376 /* Check if the device is Quiescent and then Reset the NIC */
6377 do {
Ananda Raju5d3213c2006-04-21 19:23:26 -04006378 /* As per the HW requirement we need to replenish the
6379 * receive buffer to avoid the ring bump. Since there is
6380 * no intention of processing the Rx frame at this pointwe are
6381 * just settting the ownership bit of rxd in Each Rx
6382 * ring to HW and set the appropriate buffer size
6383 * based on the ring mode
6384 */
6385 rxd_owner_bit_reset(sp);
6386
Linus Torvalds1da177e2005-04-16 15:20:36 -07006387 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006388 if (verify_xena_quiescence(sp)) {
6389 if(verify_pcc_quiescent(sp, sp->device_enabled_once))
Linus Torvalds1da177e2005-04-16 15:20:36 -07006390 break;
6391 }
6392
6393 msleep(50);
6394 cnt++;
6395 if (cnt == 10) {
6396 DBG_PRINT(ERR_DBG,
6397 "s2io_close:Device not Quiescent ");
6398 DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n",
6399 (unsigned long long) val64);
6400 break;
6401 }
6402 } while (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403 s2io_reset(sp);
6404
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006405 spin_lock_irqsave(&sp->tx_lock, flags);
6406 /* Free all Tx buffers */
6407 free_tx_buffers(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006409
6410 /* Free all Rx buffers */
6411 spin_lock_irqsave(&sp->rx_lock, flags);
6412 free_rx_buffers(sp);
6413 spin_unlock_irqrestore(&sp->rx_lock, flags);
6414
Linus Torvalds1da177e2005-04-16 15:20:36 -07006415 clear_bit(0, &(sp->link_state));
6416}
6417
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006418static int s2io_card_up(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006419{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006420 int i, ret = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006421 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006422 struct config_param *config;
6423 struct net_device *dev = (struct net_device *) sp->dev;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006424 u16 interruptible;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006425
6426 /* Initialize the H/W I/O registers */
6427 if (init_nic(sp) != 0) {
6428 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
6429 dev->name);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006430 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006431 return -ENODEV;
6432 }
6433
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006434 /*
6435 * Initializing the Rx buffers. For now we are considering only 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07006436 * Rx ring and initializing buffers into 30 Rx blocks
6437 */
6438 mac_control = &sp->mac_control;
6439 config = &sp->config;
6440
6441 for (i = 0; i < config->rx_ring_num; i++) {
6442 if ((ret = fill_rx_buffers(sp, i))) {
6443 DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
6444 dev->name);
6445 s2io_reset(sp);
6446 free_rx_buffers(sp);
6447 return -ENOMEM;
6448 }
6449 DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
6450 atomic_read(&sp->rx_bufs_left[i]));
6451 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006452 /* Maintain the state prior to the open */
6453 if (sp->promisc_flg)
6454 sp->promisc_flg = 0;
6455 if (sp->m_cast_flg) {
6456 sp->m_cast_flg = 0;
6457 sp->all_multi_pos= 0;
6458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006459
6460 /* Setting its receive mode */
6461 s2io_set_multicast(dev);
6462
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006463 if (sp->lro) {
Ananda Rajub41477f2006-07-24 19:52:49 -04006464 /* Initialize max aggregatable pkts per session based on MTU */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006465 sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
6466 /* Check if we can use(if specified) user provided value */
6467 if (lro_max_pkts < sp->lro_max_aggr_per_sess)
6468 sp->lro_max_aggr_per_sess = lro_max_pkts;
6469 }
6470
Linus Torvalds1da177e2005-04-16 15:20:36 -07006471 /* Enable Rx Traffic and interrupts on the NIC */
6472 if (start_nic(sp)) {
6473 DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006474 s2io_reset(sp);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006475 free_rx_buffers(sp);
6476 return -ENODEV;
6477 }
6478
6479 /* Add interrupt service routine */
6480 if (s2io_add_isr(sp) != 0) {
6481 if (sp->intr_type == MSI_X)
6482 s2io_rem_isr(sp);
6483 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006484 free_rx_buffers(sp);
6485 return -ENODEV;
6486 }
6487
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07006488 S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
6489
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006490 /* Enable tasklet for the device */
6491 tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
6492
6493 /* Enable select interrupts */
6494 if (sp->intr_type != INTA)
6495 en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
6496 else {
6497 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
6498 interruptible |= TX_PIC_INTR | RX_PIC_INTR;
6499 interruptible |= TX_MAC_INTR | RX_MAC_INTR;
6500 en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS);
6501 }
6502
6503
Linus Torvalds1da177e2005-04-16 15:20:36 -07006504 atomic_set(&sp->card_state, CARD_UP);
6505 return 0;
6506}
6507
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006508/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006509 * s2io_restart_nic - Resets the NIC.
6510 * @data : long pointer to the device private structure
6511 * Description:
6512 * This function is scheduled to be run by the s2io_tx_watchdog
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006513 * function after 0.5 secs to reset the NIC. The idea is to reduce
Linus Torvalds1da177e2005-04-16 15:20:36 -07006514 * the run time of the watch dog routine which is run holding a
6515 * spin lock.
6516 */
6517
David Howellsc4028952006-11-22 14:57:56 +00006518static void s2io_restart_nic(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006519{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006520 struct s2io_nic *sp = container_of(work, struct s2io_nic, rst_timer_task);
David Howellsc4028952006-11-22 14:57:56 +00006521 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006522
Francois Romieu22747d62007-02-15 23:37:50 +01006523 rtnl_lock();
6524
6525 if (!netif_running(dev))
6526 goto out_unlock;
6527
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006528 s2io_card_down(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006529 if (s2io_card_up(sp)) {
6530 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
6531 dev->name);
6532 }
6533 netif_wake_queue(dev);
6534 DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
6535 dev->name);
Francois Romieu22747d62007-02-15 23:37:50 +01006536out_unlock:
6537 rtnl_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006538}
6539
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006540/**
6541 * s2io_tx_watchdog - Watchdog for transmit side.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006542 * @dev : Pointer to net device structure
6543 * Description:
6544 * This function is triggered if the Tx Queue is stopped
6545 * for a pre-defined amount of time when the Interface is still up.
6546 * If the Interface is jammed in such a situation, the hardware is
6547 * reset (by s2io_close) and restarted again (by s2io_open) to
6548 * overcome any problem that might have been caused in the hardware.
6549 * Return value:
6550 * void
6551 */
6552
6553static void s2io_tx_watchdog(struct net_device *dev)
6554{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006555 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006556
6557 if (netif_carrier_ok(dev)) {
6558 schedule_work(&sp->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04006559 sp->mac_control.stats_info->sw_stat.soft_reset_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006560 }
6561}
6562
6563/**
6564 * rx_osm_handler - To perform some OS related operations on SKB.
6565 * @sp: private member of the device structure,pointer to s2io_nic structure.
6566 * @skb : the socket buffer pointer.
6567 * @len : length of the packet
6568 * @cksum : FCS checksum of the frame.
6569 * @ring_no : the ring from which this RxD was extracted.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006570 * Description:
Ananda Rajub41477f2006-07-24 19:52:49 -04006571 * This function is called by the Rx interrupt serivce routine to perform
Linus Torvalds1da177e2005-04-16 15:20:36 -07006572 * some OS related operations on the SKB before passing it to the upper
6573 * layers. It mainly checks if the checksum is OK, if so adds it to the
6574 * SKBs cksum variable, increments the Rx packet count and passes the SKB
6575 * to the upper layer. If the checksum is wrong, it increments the Rx
6576 * packet error count, frees the SKB and returns error.
6577 * Return value:
6578 * SUCCESS on success and -1 on failure.
6579 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006580static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006581{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006582 struct s2io_nic *sp = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006583 struct net_device *dev = (struct net_device *) sp->dev;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006584 struct sk_buff *skb = (struct sk_buff *)
6585 ((unsigned long) rxdp->Host_Control);
6586 int ring_no = ring_data->ring_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006587 u16 l3_csum, l4_csum;
Ananda Raju863c11a2006-04-21 19:03:13 -04006588 unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006589 struct lro *lro;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006590
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006591 skb->dev = dev;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006592
Ananda Raju863c11a2006-04-21 19:03:13 -04006593 if (err) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04006594 /* Check for parity error */
6595 if (err & 0x1) {
6596 sp->mac_control.stats_info->sw_stat.parity_err_cnt++;
6597 }
6598
Ananda Raju863c11a2006-04-21 19:03:13 -04006599 /*
6600 * Drop the packet if bad transfer code. Exception being
6601 * 0x5, which could be due to unsupported IPv6 extension header.
6602 * In this case, we let stack handle the packet.
6603 * Note that in this case, since checksum will be incorrect,
6604 * stack will validate the same.
6605 */
6606 if (err && ((err >> 48) != 0x5)) {
6607 DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
6608 dev->name, err);
6609 sp->stats.rx_crc_errors++;
6610 dev_kfree_skb(skb);
6611 atomic_dec(&sp->rx_bufs_left[ring_no]);
6612 rxdp->Host_Control = 0;
6613 return 0;
6614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006616
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006617 /* Updating statistics */
6618 rxdp->Host_Control = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006619 sp->rx_pkt_count++;
6620 sp->stats.rx_packets++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006621 if (sp->rxd_mode == RXD_MODE_1) {
6622 int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006623
Ananda Rajuda6971d2005-10-31 16:55:31 -05006624 sp->stats.rx_bytes += len;
6625 skb_put(skb, len);
6626
6627 } else if (sp->rxd_mode >= RXD_MODE_3A) {
6628 int get_block = ring_data->rx_curr_get_info.block_index;
6629 int get_off = ring_data->rx_curr_get_info.offset;
6630 int buf0_len = RXD_GET_BUFFER0_SIZE_3(rxdp->Control_2);
6631 int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
6632 unsigned char *buff = skb_push(skb, buf0_len);
6633
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006634 struct buffAdd *ba = &ring_data->ba[get_block][get_off];
Ananda Rajuda6971d2005-10-31 16:55:31 -05006635 sp->stats.rx_bytes += buf0_len + buf2_len;
6636 memcpy(buff, ba->ba_0, buf0_len);
6637
6638 if (sp->rxd_mode == RXD_MODE_3A) {
6639 int buf1_len = RXD_GET_BUFFER1_SIZE_3(rxdp->Control_2);
6640
6641 skb_put(skb, buf1_len);
6642 skb->len += buf2_len;
6643 skb->data_len += buf2_len;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006644 skb_put(skb_shinfo(skb)->frag_list, buf2_len);
6645 sp->stats.rx_bytes += buf1_len;
6646
6647 } else
6648 skb_put(skb, buf2_len);
6649 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006650
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006651 if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
6652 (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006653 (sp->rx_csum)) {
6654 l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
6655 l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
6656 if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) {
6657 /*
6658 * NIC verifies if the Checksum of the received
6659 * frame is Ok or not and accordingly returns
6660 * a flag in the RxD.
6661 */
6662 skb->ip_summed = CHECKSUM_UNNECESSARY;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006663 if (sp->lro) {
6664 u32 tcp_len;
6665 u8 *tcp;
6666 int ret = 0;
6667
6668 ret = s2io_club_tcp_session(skb->data, &tcp,
6669 &tcp_len, &lro, rxdp, sp);
6670 switch (ret) {
6671 case 3: /* Begin anew */
6672 lro->parent = skb;
6673 goto aggregate;
6674 case 1: /* Aggregate */
6675 {
6676 lro_append_pkt(sp, lro,
6677 skb, tcp_len);
6678 goto aggregate;
6679 }
6680 case 4: /* Flush session */
6681 {
6682 lro_append_pkt(sp, lro,
6683 skb, tcp_len);
6684 queue_rx_frame(lro->parent);
6685 clear_lro_session(lro);
6686 sp->mac_control.stats_info->
6687 sw_stat.flush_max_pkts++;
6688 goto aggregate;
6689 }
6690 case 2: /* Flush both */
6691 lro->parent->data_len =
6692 lro->frags_len;
6693 sp->mac_control.stats_info->
6694 sw_stat.sending_both++;
6695 queue_rx_frame(lro->parent);
6696 clear_lro_session(lro);
6697 goto send_up;
6698 case 0: /* sessions exceeded */
Ananda Rajuc92ca042006-04-21 19:18:03 -04006699 case -1: /* non-TCP or not
6700 * L2 aggregatable
6701 */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006702 case 5: /*
6703 * First pkt in session not
6704 * L3/L4 aggregatable
6705 */
6706 break;
6707 default:
6708 DBG_PRINT(ERR_DBG,
6709 "%s: Samadhana!!\n",
6710 __FUNCTION__);
6711 BUG();
6712 }
6713 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006714 } else {
6715 /*
6716 * Packet with erroneous checksum, let the
6717 * upper layers deal with it.
6718 */
6719 skb->ip_summed = CHECKSUM_NONE;
6720 }
6721 } else {
6722 skb->ip_summed = CHECKSUM_NONE;
6723 }
6724
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006725 if (!sp->lro) {
6726 skb->protocol = eth_type_trans(skb, dev);
Sivakumar Subramani926930b2007-02-24 01:59:39 -05006727 if ((sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2) &&
6728 vlan_strip_flag)) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006729 /* Queueing the vlan frame to the upper layer */
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05006730 if (napi)
6731 vlan_hwaccel_receive_skb(skb, sp->vlgrp,
6732 RXD_GET_VLAN_TAG(rxdp->Control_2));
6733 else
6734 vlan_hwaccel_rx(skb, sp->vlgrp,
6735 RXD_GET_VLAN_TAG(rxdp->Control_2));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006736 } else {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05006737 if (napi)
6738 netif_receive_skb(skb);
6739 else
6740 netif_rx(skb);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006741 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006742 } else {
6743send_up:
6744 queue_rx_frame(skb);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006745 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006746 dev->last_rx = jiffies;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006747aggregate:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006748 atomic_dec(&sp->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006749 return SUCCESS;
6750}
6751
6752/**
6753 * s2io_link - stops/starts the Tx queue.
6754 * @sp : private member of the device structure, which is a pointer to the
6755 * s2io_nic structure.
6756 * @link : inidicates whether link is UP/DOWN.
6757 * Description:
6758 * This function stops/starts the Tx queue depending on whether the link
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006759 * status of the NIC is is down or up. This is called by the Alarm
6760 * interrupt handler whenever a link change interrupt comes up.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006761 * Return value:
6762 * void.
6763 */
6764
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006765static void s2io_link(struct s2io_nic * sp, int link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006766{
6767 struct net_device *dev = (struct net_device *) sp->dev;
6768
6769 if (link != sp->last_link_state) {
6770 if (link == LINK_DOWN) {
6771 DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
6772 netif_carrier_off(dev);
6773 } else {
6774 DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
6775 netif_carrier_on(dev);
6776 }
6777 }
6778 sp->last_link_state = link;
6779}
6780
6781/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006782 * get_xena_rev_id - to identify revision ID of xena.
6783 * @pdev : PCI Dev structure
6784 * Description:
6785 * Function to identify the Revision ID of xena.
6786 * Return value:
6787 * returns the revision ID of the device.
6788 */
6789
Adrian Bunk26df54b2006-01-14 03:09:40 +01006790static int get_xena_rev_id(struct pci_dev *pdev)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006791{
6792 u8 id = 0;
6793 int ret;
6794 ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id);
6795 return id;
6796}
6797
6798/**
6799 * s2io_init_pci -Initialization of PCI and PCI-X configuration registers .
6800 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07006801 * s2io_nic structure.
6802 * Description:
6803 * This function initializes a few of the PCI and PCI-X configuration registers
6804 * with recommended values.
6805 * Return value:
6806 * void
6807 */
6808
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006809static void s2io_init_pci(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006810{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006811 u16 pci_cmd = 0, pcix_cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006812
6813 /* Enable Data Parity Error Recovery in PCI-X command register. */
6814 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006815 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006816 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006817 (pcix_cmd | 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006818 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006819 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006820
6821 /* Set the PErr Response bit in PCI command register. */
6822 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
6823 pci_write_config_word(sp->pdev, PCI_COMMAND,
6824 (pci_cmd | PCI_COMMAND_PARITY));
6825 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006826}
6827
Ananda Raju9dc737a2006-04-21 19:05:41 -04006828static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
6829{
6830 if ( tx_fifo_num > 8) {
6831 DBG_PRINT(ERR_DBG, "s2io: Requested number of Tx fifos not "
6832 "supported\n");
6833 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Tx fifos\n");
6834 tx_fifo_num = 8;
6835 }
6836 if ( rx_ring_num > 8) {
6837 DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
6838 "supported\n");
6839 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
6840 rx_ring_num = 8;
6841 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05006842 if (*dev_intr_type != INTA)
6843 napi = 0;
6844
Ananda Raju9dc737a2006-04-21 19:05:41 -04006845#ifndef CONFIG_PCI_MSI
6846 if (*dev_intr_type != INTA) {
6847 DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
6848 "MSI/MSI-X. Defaulting to INTA\n");
6849 *dev_intr_type = INTA;
6850 }
6851#else
6852 if (*dev_intr_type > MSI_X) {
6853 DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
6854 "Defaulting to INTA\n");
6855 *dev_intr_type = INTA;
6856 }
6857#endif
6858 if ((*dev_intr_type == MSI_X) &&
6859 ((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
6860 (pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006861 DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. "
Ananda Raju9dc737a2006-04-21 19:05:41 -04006862 "Defaulting to INTA\n");
6863 *dev_intr_type = INTA;
6864 }
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006865
Ananda Raju9dc737a2006-04-21 19:05:41 -04006866 if (rx_ring_mode > 3) {
6867 DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
6868 DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
6869 rx_ring_mode = 3;
6870 }
6871 return SUCCESS;
6872}
6873
Linus Torvalds1da177e2005-04-16 15:20:36 -07006874/**
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05006875 * rts_ds_steer - Receive traffic steering based on IPv4 or IPv6 TOS
6876 * or Traffic class respectively.
6877 * @nic: device peivate variable
6878 * Description: The function configures the receive steering to
6879 * desired receive ring.
6880 * Return Value: SUCCESS on success and
6881 * '-1' on failure (endian settings incorrect).
6882 */
6883static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring)
6884{
6885 struct XENA_dev_config __iomem *bar0 = nic->bar0;
6886 register u64 val64 = 0;
6887
6888 if (ds_codepoint > 63)
6889 return FAILURE;
6890
6891 val64 = RTS_DS_MEM_DATA(ring);
6892 writeq(val64, &bar0->rts_ds_mem_data);
6893
6894 val64 = RTS_DS_MEM_CTRL_WE |
6895 RTS_DS_MEM_CTRL_STROBE_NEW_CMD |
6896 RTS_DS_MEM_CTRL_OFFSET(ds_codepoint);
6897
6898 writeq(val64, &bar0->rts_ds_mem_ctrl);
6899
6900 return wait_for_cmd_complete(&bar0->rts_ds_mem_ctrl,
6901 RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED,
6902 S2IO_BIT_RESET);
6903}
6904
6905/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006906 * s2io_init_nic - Initialization of the adapter .
Linus Torvalds1da177e2005-04-16 15:20:36 -07006907 * @pdev : structure containing the PCI related information of the device.
6908 * @pre: List of PCI devices supported by the driver listed in s2io_tbl.
6909 * Description:
6910 * The function initializes an adapter identified by the pci_dec structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006911 * All OS related initialization including memory and device structure and
6912 * initlaization of the device private variable is done. Also the swapper
6913 * control register is initialized to enable read and write into the I/O
Linus Torvalds1da177e2005-04-16 15:20:36 -07006914 * registers of the device.
6915 * Return value:
6916 * returns 0 on success and negative on failure.
6917 */
6918
6919static int __devinit
6920s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
6921{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006922 struct s2io_nic *sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006923 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006924 int i, j, ret;
6925 int dma_flag = FALSE;
6926 u32 mac_up, mac_down;
6927 u64 val64 = 0, tmp64 = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006928 struct XENA_dev_config __iomem *bar0 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006929 u16 subid;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006930 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006931 struct config_param *config;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006932 int mode;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006933 u8 dev_intr_type = intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006934
Ananda Raju9dc737a2006-04-21 19:05:41 -04006935 if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
6936 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006937
6938 if ((ret = pci_enable_device(pdev))) {
6939 DBG_PRINT(ERR_DBG,
6940 "s2io_init_nic: pci_enable_device failed\n");
6941 return ret;
6942 }
6943
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006944 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006945 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
6946 dma_flag = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006947 if (pci_set_consistent_dma_mask
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006948 (pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006949 DBG_PRINT(ERR_DBG,
6950 "Unable to obtain 64bit DMA for \
6951 consistent allocations\n");
6952 pci_disable_device(pdev);
6953 return -ENOMEM;
6954 }
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006955 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006956 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n");
6957 } else {
6958 pci_disable_device(pdev);
6959 return -ENOMEM;
6960 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006961 if (dev_intr_type != MSI_X) {
6962 if (pci_request_regions(pdev, s2io_driver_name)) {
Ananda Rajub41477f2006-07-24 19:52:49 -04006963 DBG_PRINT(ERR_DBG, "Request Regions failed\n");
6964 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006965 return -ENODEV;
6966 }
6967 }
6968 else {
6969 if (!(request_mem_region(pci_resource_start(pdev, 0),
6970 pci_resource_len(pdev, 0), s2io_driver_name))) {
6971 DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n");
6972 pci_disable_device(pdev);
6973 return -ENODEV;
6974 }
6975 if (!(request_mem_region(pci_resource_start(pdev, 2),
6976 pci_resource_len(pdev, 2), s2io_driver_name))) {
6977 DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n");
6978 release_mem_region(pci_resource_start(pdev, 0),
6979 pci_resource_len(pdev, 0));
6980 pci_disable_device(pdev);
6981 return -ENODEV;
6982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006983 }
6984
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006985 dev = alloc_etherdev(sizeof(struct s2io_nic));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006986 if (dev == NULL) {
6987 DBG_PRINT(ERR_DBG, "Device allocation failed\n");
6988 pci_disable_device(pdev);
6989 pci_release_regions(pdev);
6990 return -ENODEV;
6991 }
6992
6993 pci_set_master(pdev);
6994 pci_set_drvdata(pdev, dev);
6995 SET_MODULE_OWNER(dev);
6996 SET_NETDEV_DEV(dev, &pdev->dev);
6997
6998 /* Private member variable initialized to s2io NIC structure */
6999 sp = dev->priv;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007000 memset(sp, 0, sizeof(struct s2io_nic));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007001 sp->dev = dev;
7002 sp->pdev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007003 sp->high_dma_flag = dma_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007004 sp->device_enabled_once = FALSE;
Ananda Rajuda6971d2005-10-31 16:55:31 -05007005 if (rx_ring_mode == 1)
7006 sp->rxd_mode = RXD_MODE_1;
7007 if (rx_ring_mode == 2)
7008 sp->rxd_mode = RXD_MODE_3B;
7009 if (rx_ring_mode == 3)
7010 sp->rxd_mode = RXD_MODE_3A;
7011
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007012 sp->intr_type = dev_intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007013
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007014 if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
7015 (pdev->device == PCI_DEVICE_ID_HERC_UNI))
7016 sp->device_type = XFRAME_II_DEVICE;
7017 else
7018 sp->device_type = XFRAME_I_DEVICE;
7019
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007020 sp->lro = lro;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007021
Linus Torvalds1da177e2005-04-16 15:20:36 -07007022 /* Initialize some PCI/PCI-X fields of the NIC. */
7023 s2io_init_pci(sp);
7024
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007025 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007026 * Setting the device configuration parameters.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007027 * Most of these parameters can be specified by the user during
7028 * module insertion as they are module loadable parameters. If
7029 * these parameters are not not specified during load time, they
Linus Torvalds1da177e2005-04-16 15:20:36 -07007030 * are initialized with default values.
7031 */
7032 mac_control = &sp->mac_control;
7033 config = &sp->config;
7034
7035 /* Tx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007036 config->tx_fifo_num = tx_fifo_num;
7037 for (i = 0; i < MAX_TX_FIFOS; i++) {
7038 config->tx_cfg[i].fifo_len = tx_fifo_len[i];
7039 config->tx_cfg[i].fifo_priority = i;
7040 }
7041
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007042 /* mapping the QoS priority to the configured fifos */
7043 for (i = 0; i < MAX_TX_FIFOS; i++)
7044 config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i];
7045
Linus Torvalds1da177e2005-04-16 15:20:36 -07007046 config->tx_intr_type = TXD_INT_TYPE_UTILZ;
7047 for (i = 0; i < config->tx_fifo_num; i++) {
7048 config->tx_cfg[i].f_no_snoop =
7049 (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER);
7050 if (config->tx_cfg[i].fifo_len < 65) {
7051 config->tx_intr_type = TXD_INT_TYPE_PER_LIST;
7052 break;
7053 }
7054 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05007055 /* + 2 because one Txd for skb->data and one Txd for UFO */
7056 config->max_txds = MAX_SKB_FRAGS + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007057
7058 /* Rx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007059 config->rx_ring_num = rx_ring_num;
7060 for (i = 0; i < MAX_RX_RINGS; i++) {
7061 config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
Ananda Rajuda6971d2005-10-31 16:55:31 -05007062 (rxd_count[sp->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007063 config->rx_cfg[i].ring_priority = i;
7064 }
7065
7066 for (i = 0; i < rx_ring_num; i++) {
7067 config->rx_cfg[i].ring_org = RING_ORG_BUFF1;
7068 config->rx_cfg[i].f_no_snoop =
7069 (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER);
7070 }
7071
7072 /* Setting Mac Control parameters */
7073 mac_control->rmac_pause_time = rmac_pause_time;
7074 mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3;
7075 mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
7076
7077
7078 /* Initialize Ring buffer parameters. */
7079 for (i = 0; i < config->rx_ring_num; i++)
7080 atomic_set(&sp->rx_bufs_left[i], 0);
7081
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007082 /* Initialize the number of ISRs currently running */
7083 atomic_set(&sp->isr_cnt, 0);
7084
Linus Torvalds1da177e2005-04-16 15:20:36 -07007085 /* initialize the shared memory used by the NIC and the host */
7086 if (init_shared_mem(sp)) {
7087 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
Ananda Rajub41477f2006-07-24 19:52:49 -04007088 dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007089 ret = -ENOMEM;
7090 goto mem_alloc_failed;
7091 }
7092
7093 sp->bar0 = ioremap(pci_resource_start(pdev, 0),
7094 pci_resource_len(pdev, 0));
7095 if (!sp->bar0) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007096 DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007097 dev->name);
7098 ret = -ENOMEM;
7099 goto bar0_remap_failed;
7100 }
7101
7102 sp->bar1 = ioremap(pci_resource_start(pdev, 2),
7103 pci_resource_len(pdev, 2));
7104 if (!sp->bar1) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007105 DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007106 dev->name);
7107 ret = -ENOMEM;
7108 goto bar1_remap_failed;
7109 }
7110
7111 dev->irq = pdev->irq;
7112 dev->base_addr = (unsigned long) sp->bar0;
7113
7114 /* Initializing the BAR1 address as the start of the FIFO pointer. */
7115 for (j = 0; j < MAX_TX_FIFOS; j++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007116 mac_control->tx_FIFO_start[j] = (struct TxFIFO_element __iomem *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007117 (sp->bar1 + (j * 0x00020000));
7118 }
7119
7120 /* Driver entry points */
7121 dev->open = &s2io_open;
7122 dev->stop = &s2io_close;
7123 dev->hard_start_xmit = &s2io_xmit;
7124 dev->get_stats = &s2io_get_stats;
7125 dev->set_multicast_list = &s2io_set_multicast;
7126 dev->do_ioctl = &s2io_ioctl;
7127 dev->change_mtu = &s2io_change_mtu;
7128 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07007129 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
7130 dev->vlan_rx_register = s2io_vlan_rx_register;
7131 dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007132
Linus Torvalds1da177e2005-04-16 15:20:36 -07007133 /*
7134 * will use eth_mac_addr() for dev->set_mac_address
7135 * mac address will be set every time dev->open() is called
7136 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007137 dev->poll = s2io_poll;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007138 dev->weight = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007139
Brian Haley612eff02006-06-15 14:36:36 -04007140#ifdef CONFIG_NET_POLL_CONTROLLER
7141 dev->poll_controller = s2io_netpoll;
7142#endif
7143
Linus Torvalds1da177e2005-04-16 15:20:36 -07007144 dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
7145 if (sp->high_dma_flag == TRUE)
7146 dev->features |= NETIF_F_HIGHDMA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007147 dev->features |= NETIF_F_TSO;
Herbert Xuf83ef8c2006-06-30 13:37:03 -07007148 dev->features |= NETIF_F_TSO6;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007149 if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05007150 dev->features |= NETIF_F_UFO;
7151 dev->features |= NETIF_F_HW_CSUM;
7152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007153
7154 dev->tx_timeout = &s2io_tx_watchdog;
7155 dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
David Howellsc4028952006-11-22 14:57:56 +00007156 INIT_WORK(&sp->rst_timer_task, s2io_restart_nic);
7157 INIT_WORK(&sp->set_link_task, s2io_set_link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007158
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07007159 pci_save_state(sp->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007160
7161 /* Setting swapper control on the NIC, for proper reset operation */
7162 if (s2io_set_swapper(sp)) {
7163 DBG_PRINT(ERR_DBG, "%s:swapper settings are wrong\n",
7164 dev->name);
7165 ret = -EAGAIN;
7166 goto set_swap_failed;
7167 }
7168
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007169 /* Verify if the Herc works on the slot its placed into */
7170 if (sp->device_type & XFRAME_II_DEVICE) {
7171 mode = s2io_verify_pci_mode(sp);
7172 if (mode < 0) {
7173 DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__);
7174 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
7175 ret = -EBADSLT;
7176 goto set_swap_failed;
7177 }
7178 }
7179
7180 /* Not needed for Herc */
7181 if (sp->device_type & XFRAME_I_DEVICE) {
7182 /*
7183 * Fix for all "FFs" MAC address problems observed on
7184 * Alpha platforms
7185 */
7186 fix_mac_address(sp);
7187 s2io_reset(sp);
7188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007189
7190 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007191 * MAC address initialization.
7192 * For now only one mac address will be read and used.
7193 */
7194 bar0 = sp->bar0;
7195 val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
7196 RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
7197 writeq(val64, &bar0->rmac_addr_cmd_mem);
Ananda Rajuc92ca042006-04-21 19:18:03 -04007198 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05007199 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007200 tmp64 = readq(&bar0->rmac_addr_data0_mem);
7201 mac_down = (u32) tmp64;
7202 mac_up = (u32) (tmp64 >> 32);
7203
Linus Torvalds1da177e2005-04-16 15:20:36 -07007204 sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up);
7205 sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8);
7206 sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16);
7207 sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_up >> 24);
7208 sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16);
7209 sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24);
7210
Linus Torvalds1da177e2005-04-16 15:20:36 -07007211 /* Set the factory defined MAC address initially */
7212 dev->addr_len = ETH_ALEN;
7213 memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
7214
Ananda Rajub41477f2006-07-24 19:52:49 -04007215 /* reset Nic and bring it to known state */
7216 s2io_reset(sp);
7217
Linus Torvalds1da177e2005-04-16 15:20:36 -07007218 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007219 * Initialize the tasklet status and link state flags
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007220 * and the card state parameter
Linus Torvalds1da177e2005-04-16 15:20:36 -07007221 */
7222 atomic_set(&(sp->card_state), 0);
7223 sp->tasklet_status = 0;
7224 sp->link_state = 0;
7225
Linus Torvalds1da177e2005-04-16 15:20:36 -07007226 /* Initialize spinlocks */
7227 spin_lock_init(&sp->tx_lock);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007228
7229 if (!napi)
7230 spin_lock_init(&sp->put_lock);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007231 spin_lock_init(&sp->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007232
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007233 /*
7234 * SXE-002: Configure link and activity LED to init state
7235 * on driver load.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007236 */
7237 subid = sp->pdev->subsystem_device;
7238 if ((subid & 0xFF) >= 0x07) {
7239 val64 = readq(&bar0->gpio_control);
7240 val64 |= 0x0000800000000000ULL;
7241 writeq(val64, &bar0->gpio_control);
7242 val64 = 0x0411040400000000ULL;
7243 writeq(val64, (void __iomem *) bar0 + 0x2700);
7244 val64 = readq(&bar0->gpio_control);
7245 }
7246
7247 sp->rx_csum = 1; /* Rx chksum verify enabled by default */
7248
7249 if (register_netdev(dev)) {
7250 DBG_PRINT(ERR_DBG, "Device registration failed\n");
7251 ret = -ENODEV;
7252 goto register_failed;
7253 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04007254 s2io_vpd_read(sp);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007255 DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n");
Ananda Rajub41477f2006-07-24 19:52:49 -04007256 DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name,
7257 sp->product_name, get_xena_rev_id(sp->pdev));
7258 DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
7259 s2io_driver_version);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007260 DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007261 "%02x:%02x:%02x:%02x:%02x:%02x", dev->name,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007262 sp->def_mac_addr[0].mac_addr[0],
7263 sp->def_mac_addr[0].mac_addr[1],
7264 sp->def_mac_addr[0].mac_addr[2],
7265 sp->def_mac_addr[0].mac_addr[3],
7266 sp->def_mac_addr[0].mac_addr[4],
7267 sp->def_mac_addr[0].mac_addr[5]);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007268 DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007269 if (sp->device_type & XFRAME_II_DEVICE) {
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07007270 mode = s2io_print_pci_mode(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007271 if (mode < 0) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04007272 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007273 ret = -EBADSLT;
Ananda Raju9dc737a2006-04-21 19:05:41 -04007274 unregister_netdev(dev);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007275 goto set_swap_failed;
7276 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007277 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04007278 switch(sp->rxd_mode) {
7279 case RXD_MODE_1:
7280 DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n",
7281 dev->name);
7282 break;
7283 case RXD_MODE_3B:
7284 DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n",
7285 dev->name);
7286 break;
7287 case RXD_MODE_3A:
7288 DBG_PRINT(ERR_DBG, "%s: 3-Buffer receive mode enabled\n",
7289 dev->name);
7290 break;
7291 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007292
7293 if (napi)
7294 DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007295 switch(sp->intr_type) {
7296 case INTA:
7297 DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
7298 break;
7299 case MSI:
7300 DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI\n", dev->name);
7301 break;
7302 case MSI_X:
7303 DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
7304 break;
7305 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007306 if (sp->lro)
7307 DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
Ananda Raju9dc737a2006-04-21 19:05:41 -04007308 dev->name);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007309 if (ufo)
7310 DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)"
7311 " enabled\n", dev->name);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007312 /* Initialize device name */
Ananda Raju9dc737a2006-04-21 19:05:41 -04007313 sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007314
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07007315 /* Initialize bimodal Interrupts */
7316 sp->config.bimodal = bimodal;
7317 if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) {
7318 sp->config.bimodal = 0;
7319 DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n",
7320 dev->name);
7321 }
7322
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007323 /*
7324 * Make Link state as off at this point, when the Link change
7325 * interrupt comes the state will be automatically changed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07007326 * the right state.
7327 */
7328 netif_carrier_off(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007329
7330 return 0;
7331
7332 register_failed:
7333 set_swap_failed:
7334 iounmap(sp->bar1);
7335 bar1_remap_failed:
7336 iounmap(sp->bar0);
7337 bar0_remap_failed:
7338 mem_alloc_failed:
7339 free_shared_mem(sp);
7340 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007341 if (dev_intr_type != MSI_X)
7342 pci_release_regions(pdev);
7343 else {
7344 release_mem_region(pci_resource_start(pdev, 0),
7345 pci_resource_len(pdev, 0));
7346 release_mem_region(pci_resource_start(pdev, 2),
7347 pci_resource_len(pdev, 2));
7348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007349 pci_set_drvdata(pdev, NULL);
7350 free_netdev(dev);
7351
7352 return ret;
7353}
7354
7355/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007356 * s2io_rem_nic - Free the PCI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07007357 * @pdev: structure containing the PCI related information of the device.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007358 * Description: This function is called by the Pci subsystem to release a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007359 * PCI device and free up all resource held up by the device. This could
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007360 * be in response to a Hot plug event or when the driver is to be removed
Linus Torvalds1da177e2005-04-16 15:20:36 -07007361 * from memory.
7362 */
7363
7364static void __devexit s2io_rem_nic(struct pci_dev *pdev)
7365{
7366 struct net_device *dev =
7367 (struct net_device *) pci_get_drvdata(pdev);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007368 struct s2io_nic *sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007369
7370 if (dev == NULL) {
7371 DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
7372 return;
7373 }
7374
Francois Romieu22747d62007-02-15 23:37:50 +01007375 flush_scheduled_work();
7376
Linus Torvalds1da177e2005-04-16 15:20:36 -07007377 sp = dev->priv;
7378 unregister_netdev(dev);
7379
7380 free_shared_mem(sp);
7381 iounmap(sp->bar0);
7382 iounmap(sp->bar1);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007383 if (sp->intr_type != MSI_X)
7384 pci_release_regions(pdev);
7385 else {
7386 release_mem_region(pci_resource_start(pdev, 0),
7387 pci_resource_len(pdev, 0));
7388 release_mem_region(pci_resource_start(pdev, 2),
7389 pci_resource_len(pdev, 2));
7390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007391 pci_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007392 free_netdev(dev);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007393 pci_disable_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007394}
7395
7396/**
7397 * s2io_starter - Entry point for the driver
7398 * Description: This function is the entry point for the driver. It verifies
7399 * the module loadable parameters and initializes PCI configuration space.
7400 */
7401
7402int __init s2io_starter(void)
7403{
Jeff Garzik29917622006-08-19 17:48:59 -04007404 return pci_register_driver(&s2io_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007405}
7406
7407/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007408 * s2io_closer - Cleanup routine for the driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07007409 * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
7410 */
7411
Sivakumar Subramani372cc592007-01-31 13:32:57 -05007412static __exit void s2io_closer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007413{
7414 pci_unregister_driver(&s2io_driver);
7415 DBG_PRINT(INIT_DBG, "cleanup done\n");
7416}
7417
7418module_init(s2io_starter);
7419module_exit(s2io_closer);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007420
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007421static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007422 struct tcphdr **tcp, struct RxD_t *rxdp)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007423{
7424 int ip_off;
7425 u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
7426
7427 if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) {
7428 DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n",
7429 __FUNCTION__);
7430 return -1;
7431 }
7432
7433 /* TODO:
7434 * By default the VLAN field in the MAC is stripped by the card, if this
7435 * feature is turned off in rx_pa_cfg register, then the ip_off field
7436 * has to be shifted by a further 2 bytes
7437 */
7438 switch (l2_type) {
7439 case 0: /* DIX type */
7440 case 4: /* DIX type with VLAN */
7441 ip_off = HEADER_ETHERNET_II_802_3_SIZE;
7442 break;
7443 /* LLC, SNAP etc are considered non-mergeable */
7444 default:
7445 return -1;
7446 }
7447
7448 *ip = (struct iphdr *)((u8 *)buffer + ip_off);
7449 ip_len = (u8)((*ip)->ihl);
7450 ip_len <<= 2;
7451 *tcp = (struct tcphdr *)((unsigned long)*ip + ip_len);
7452
7453 return 0;
7454}
7455
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007456static int check_for_socket_match(struct lro *lro, struct iphdr *ip,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007457 struct tcphdr *tcp)
7458{
7459 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7460 if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) ||
7461 (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest))
7462 return -1;
7463 return 0;
7464}
7465
7466static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
7467{
7468 return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
7469}
7470
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007471static void initiate_new_session(struct lro *lro, u8 *l2h,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007472 struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
7473{
7474 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7475 lro->l2h = l2h;
7476 lro->iph = ip;
7477 lro->tcph = tcp;
7478 lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq);
7479 lro->tcp_ack = ntohl(tcp->ack_seq);
7480 lro->sg_num = 1;
7481 lro->total_len = ntohs(ip->tot_len);
7482 lro->frags_len = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007483 /*
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007484 * check if we saw TCP timestamp. Other consistency checks have
7485 * already been done.
7486 */
7487 if (tcp->doff == 8) {
7488 u32 *ptr;
7489 ptr = (u32 *)(tcp+1);
7490 lro->saw_ts = 1;
7491 lro->cur_tsval = *(ptr+1);
7492 lro->cur_tsecr = *(ptr+2);
7493 }
7494 lro->in_use = 1;
7495}
7496
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007497static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007498{
7499 struct iphdr *ip = lro->iph;
7500 struct tcphdr *tcp = lro->tcph;
Al Virobd4f3ae2007-02-09 16:40:15 +00007501 __sum16 nchk;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007502 struct stat_block *statinfo = sp->mac_control.stats_info;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007503 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7504
7505 /* Update L3 header */
7506 ip->tot_len = htons(lro->total_len);
7507 ip->check = 0;
7508 nchk = ip_fast_csum((u8 *)lro->iph, ip->ihl);
7509 ip->check = nchk;
7510
7511 /* Update L4 header */
7512 tcp->ack_seq = lro->tcp_ack;
7513 tcp->window = lro->window;
7514
7515 /* Update tsecr field if this session has timestamps enabled */
7516 if (lro->saw_ts) {
7517 u32 *ptr = (u32 *)(tcp + 1);
7518 *(ptr+2) = lro->cur_tsecr;
7519 }
7520
7521 /* Update counters required for calculation of
7522 * average no. of packets aggregated.
7523 */
7524 statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num;
7525 statinfo->sw_stat.num_aggregations++;
7526}
7527
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007528static void aggregate_new_rx(struct lro *lro, struct iphdr *ip,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007529 struct tcphdr *tcp, u32 l4_pyld)
7530{
7531 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7532 lro->total_len += l4_pyld;
7533 lro->frags_len += l4_pyld;
7534 lro->tcp_next_seq += l4_pyld;
7535 lro->sg_num++;
7536
7537 /* Update ack seq no. and window ad(from this pkt) in LRO object */
7538 lro->tcp_ack = tcp->ack_seq;
7539 lro->window = tcp->window;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007540
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007541 if (lro->saw_ts) {
7542 u32 *ptr;
7543 /* Update tsecr and tsval from this packet */
7544 ptr = (u32 *) (tcp + 1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007545 lro->cur_tsval = *(ptr + 1);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007546 lro->cur_tsecr = *(ptr + 2);
7547 }
7548}
7549
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007550static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007551 struct tcphdr *tcp, u32 tcp_pyld_len)
7552{
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007553 u8 *ptr;
7554
Andrew Morton79dc1902006-02-03 01:45:13 -08007555 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7556
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007557 if (!tcp_pyld_len) {
7558 /* Runt frame or a pure ack */
7559 return -1;
7560 }
7561
7562 if (ip->ihl != 5) /* IP has options */
7563 return -1;
7564
Ananda Raju75c30b12006-07-24 19:55:09 -04007565 /* If we see CE codepoint in IP header, packet is not mergeable */
7566 if (INET_ECN_is_ce(ipv4_get_dsfield(ip)))
7567 return -1;
7568
7569 /* If we see ECE or CWR flags in TCP header, packet is not mergeable */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007570 if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin ||
Ananda Raju75c30b12006-07-24 19:55:09 -04007571 tcp->ece || tcp->cwr || !tcp->ack) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007572 /*
7573 * Currently recognize only the ack control word and
7574 * any other control field being set would result in
7575 * flushing the LRO session
7576 */
7577 return -1;
7578 }
7579
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007580 /*
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007581 * Allow only one TCP timestamp option. Don't aggregate if
7582 * any other options are detected.
7583 */
7584 if (tcp->doff != 5 && tcp->doff != 8)
7585 return -1;
7586
7587 if (tcp->doff == 8) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007588 ptr = (u8 *)(tcp + 1);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007589 while (*ptr == TCPOPT_NOP)
7590 ptr++;
7591 if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP)
7592 return -1;
7593
7594 /* Ensure timestamp value increases monotonically */
7595 if (l_lro)
7596 if (l_lro->cur_tsval > *((u32 *)(ptr+2)))
7597 return -1;
7598
7599 /* timestamp echo reply should be non-zero */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007600 if (*((u32 *)(ptr+6)) == 0)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007601 return -1;
7602 }
7603
7604 return 0;
7605}
7606
7607static int
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007608s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
7609 struct RxD_t *rxdp, struct s2io_nic *sp)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007610{
7611 struct iphdr *ip;
7612 struct tcphdr *tcph;
7613 int ret = 0, i;
7614
7615 if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp,
7616 rxdp))) {
7617 DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n",
7618 ip->saddr, ip->daddr);
7619 } else {
7620 return ret;
7621 }
7622
7623 tcph = (struct tcphdr *)*tcp;
7624 *tcp_len = get_l4_pyld_length(ip, tcph);
7625 for (i=0; i<MAX_LRO_SESSIONS; i++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007626 struct lro *l_lro = &sp->lro0_n[i];
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007627 if (l_lro->in_use) {
7628 if (check_for_socket_match(l_lro, ip, tcph))
7629 continue;
7630 /* Sock pair matched */
7631 *lro = l_lro;
7632
7633 if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) {
7634 DBG_PRINT(INFO_DBG, "%s:Out of order. expected "
7635 "0x%x, actual 0x%x\n", __FUNCTION__,
7636 (*lro)->tcp_next_seq,
7637 ntohl(tcph->seq));
7638
7639 sp->mac_control.stats_info->
7640 sw_stat.outof_sequence_pkts++;
7641 ret = 2;
7642 break;
7643 }
7644
7645 if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len))
7646 ret = 1; /* Aggregate */
7647 else
7648 ret = 2; /* Flush both */
7649 break;
7650 }
7651 }
7652
7653 if (ret == 0) {
7654 /* Before searching for available LRO objects,
7655 * check if the pkt is L3/L4 aggregatable. If not
7656 * don't create new LRO session. Just send this
7657 * packet up.
7658 */
7659 if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) {
7660 return 5;
7661 }
7662
7663 for (i=0; i<MAX_LRO_SESSIONS; i++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007664 struct lro *l_lro = &sp->lro0_n[i];
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007665 if (!(l_lro->in_use)) {
7666 *lro = l_lro;
7667 ret = 3; /* Begin anew */
7668 break;
7669 }
7670 }
7671 }
7672
7673 if (ret == 0) { /* sessions exceeded */
7674 DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n",
7675 __FUNCTION__);
7676 *lro = NULL;
7677 return ret;
7678 }
7679
7680 switch (ret) {
7681 case 3:
7682 initiate_new_session(*lro, buffer, ip, tcph, *tcp_len);
7683 break;
7684 case 2:
7685 update_L3L4_header(sp, *lro);
7686 break;
7687 case 1:
7688 aggregate_new_rx(*lro, ip, tcph, *tcp_len);
7689 if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) {
7690 update_L3L4_header(sp, *lro);
7691 ret = 4; /* Flush the LRO */
7692 }
7693 break;
7694 default:
7695 DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n",
7696 __FUNCTION__);
7697 break;
7698 }
7699
7700 return ret;
7701}
7702
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007703static void clear_lro_session(struct lro *lro)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007704{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007705 static u16 lro_struct_size = sizeof(struct lro);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007706
7707 memset(lro, 0, lro_struct_size);
7708}
7709
7710static void queue_rx_frame(struct sk_buff *skb)
7711{
7712 struct net_device *dev = skb->dev;
7713
7714 skb->protocol = eth_type_trans(skb, dev);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007715 if (napi)
7716 netif_receive_skb(skb);
7717 else
7718 netif_rx(skb);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007719}
7720
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007721static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
7722 struct sk_buff *skb,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007723 u32 tcp_len)
7724{
Ananda Raju75c30b12006-07-24 19:55:09 -04007725 struct sk_buff *first = lro->parent;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007726
7727 first->len += tcp_len;
7728 first->data_len = lro->frags_len;
7729 skb_pull(skb, (skb->len - tcp_len));
Ananda Raju75c30b12006-07-24 19:55:09 -04007730 if (skb_shinfo(first)->frag_list)
7731 lro->last_frag->next = skb;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007732 else
7733 skb_shinfo(first)->frag_list = skb;
Sivakumar Subramani372cc592007-01-31 13:32:57 -05007734 first->truesize += skb->truesize;
Ananda Raju75c30b12006-07-24 19:55:09 -04007735 lro->last_frag = skb;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007736 sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
7737 return;
7738}