blob: 983f38313d87792b7b23f254ee90048e54c8ecd8 [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
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08003 * Copyright(c) 2002-2007 Neterion Inc.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004
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
Ramkrishna Vepa363dc362007-03-06 17:01:00 -080087#define DRV_VERSION "2.0.19.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 */
Adrian Bunk7b490342007-03-05 02:49:25 +0100319static int vlan_strip_flag;
Sivakumar Subramani926930b2007-02-24 01:59:39 -0500320
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) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -0800519 DBG_PRINT(INFO_DBG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 "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) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -0800545 DBG_PRINT(INFO_DBG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 "pci_alloc_consistent ");
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -0800547 DBG_PRINT(INFO_DBG, "failed for TxDL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 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) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -0800564 DBG_PRINT(INFO_DBG,
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700565 "pci_alloc_consistent ");
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -0800566 DBG_PRINT(INFO_DBG, "failed for TxDL\n");
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700567 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) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08002190 DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002191 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;
Ramkrishna Vepa363dc362007-03-06 17:01:00 -08002245 u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
2247 mac_control = &nic->mac_control;
2248 config = &nic->config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002249 alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
2250 atomic_read(&nic->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251
Ananda Raju5d3213c2006-04-21 19:23:26 -04002252 block_no1 = mac_control->rings[ring_no].rx_curr_get_info.block_index;
Ananda Raju863c11a2006-04-21 19:03:13 -04002253 off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 while (alloc_tab < alloc_cnt) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002255 block_no = mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 block_index;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002257 off = mac_control->rings[ring_no].rx_curr_put_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
Ananda Rajuda6971d2005-10-31 16:55:31 -05002259 rxdp = mac_control->rings[ring_no].
2260 rx_blocks[block_no].rxds[off].virt_addr;
2261
2262 if ((block_no == block_no1) && (off == off1) &&
2263 (rxdp->Host_Control)) {
2264 DBG_PRINT(INTR_DBG, "%s: Get and Put",
2265 dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 DBG_PRINT(INTR_DBG, " info equated\n");
2267 goto end;
2268 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002269 if (off && (off == rxd_count[nic->rxd_mode])) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002270 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 block_index++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002272 if (mac_control->rings[ring_no].rx_curr_put_info.
2273 block_index == mac_control->rings[ring_no].
2274 block_count)
2275 mac_control->rings[ring_no].rx_curr_put_info.
2276 block_index = 0;
2277 block_no = mac_control->rings[ring_no].
2278 rx_curr_put_info.block_index;
2279 if (off == rxd_count[nic->rxd_mode])
2280 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002281 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002282 offset = off;
2283 rxdp = mac_control->rings[ring_no].
2284 rx_blocks[block_no].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
2286 dev->name, rxdp);
2287 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002288 if(!napi) {
2289 spin_lock_irqsave(&nic->put_lock, flags);
2290 mac_control->rings[ring_no].put_pos =
2291 (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
2292 spin_unlock_irqrestore(&nic->put_lock, flags);
2293 } else {
2294 mac_control->rings[ring_no].put_pos =
2295 (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
2296 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002297 if ((rxdp->Control_1 & RXD_OWN_XENA) &&
2298 ((nic->rxd_mode >= RXD_MODE_3A) &&
2299 (rxdp->Control_2 & BIT(0)))) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002300 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002301 offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 goto end;
2303 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002304 /* calculate size of skb based on ring mode */
2305 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
2306 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
2307 if (nic->rxd_mode == RXD_MODE_1)
2308 size += NET_IP_ALIGN;
2309 else if (nic->rxd_mode == RXD_MODE_3B)
2310 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
2311 else
2312 size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
Ananda Rajuda6971d2005-10-31 16:55:31 -05002314 /* allocate skb */
2315 skb = dev_alloc_skb(size);
2316 if(!skb) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08002317 DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
2318 DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002319 if (first_rxdp) {
2320 wmb();
2321 first_rxdp->Control_1 |= RXD_OWN_XENA;
2322 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002323 return -ENOMEM ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002325 if (nic->rxd_mode == RXD_MODE_1) {
2326 /* 1 buffer mode - normal operation mode */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002327 memset(rxdp, 0, sizeof(struct RxD1));
Ananda Rajuda6971d2005-10-31 16:55:31 -05002328 skb_reserve(skb, NET_IP_ALIGN);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002329 ((struct RxD1*)rxdp)->Buffer0_ptr = pci_map_single
Ananda Raju863c11a2006-04-21 19:03:13 -04002330 (nic->pdev, skb->data, size - NET_IP_ALIGN,
2331 PCI_DMA_FROMDEVICE);
2332 rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002333
2334 } else if (nic->rxd_mode >= RXD_MODE_3A) {
2335 /*
2336 * 2 or 3 buffer mode -
2337 * Both 2 buffer mode and 3 buffer mode provides 128
2338 * byte aligned receive buffers.
2339 *
2340 * 3 buffer mode provides header separation where in
2341 * skb->data will have L3/L4 headers where as
2342 * skb_shinfo(skb)->frag_list will have the L4 data
2343 * payload
2344 */
2345
Ramkrishna Vepa363dc362007-03-06 17:01:00 -08002346 /* save the buffer pointers to avoid frequent dma mapping */
2347 Buffer0_ptr = ((struct RxD3*)rxdp)->Buffer0_ptr;
2348 Buffer1_ptr = ((struct RxD3*)rxdp)->Buffer1_ptr;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002349 memset(rxdp, 0, sizeof(struct RxD3));
Ramkrishna Vepa363dc362007-03-06 17:01:00 -08002350 /* restore the buffer pointers for dma sync*/
2351 ((struct RxD3*)rxdp)->Buffer0_ptr = Buffer0_ptr;
2352 ((struct RxD3*)rxdp)->Buffer1_ptr = Buffer1_ptr;
2353
Ananda Rajuda6971d2005-10-31 16:55:31 -05002354 ba = &mac_control->rings[ring_no].ba[block_no][off];
2355 skb_reserve(skb, BUF0_LEN);
2356 tmp = (u64)(unsigned long) skb->data;
2357 tmp += ALIGN_SIZE;
2358 tmp &= ~ALIGN_SIZE;
2359 skb->data = (void *) (unsigned long)tmp;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07002360 skb_reset_tail_pointer(skb);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002361
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002362 if (!(((struct RxD3*)rxdp)->Buffer0_ptr))
2363 ((struct RxD3*)rxdp)->Buffer0_ptr =
Ananda Raju75c30b12006-07-24 19:55:09 -04002364 pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002365 PCI_DMA_FROMDEVICE);
Ananda Raju75c30b12006-07-24 19:55:09 -04002366 else
2367 pci_dma_sync_single_for_device(nic->pdev,
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002368 (dma_addr_t) ((struct RxD3*)rxdp)->Buffer0_ptr,
Ananda Raju75c30b12006-07-24 19:55:09 -04002369 BUF0_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002370 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
2371 if (nic->rxd_mode == RXD_MODE_3B) {
2372 /* Two buffer mode */
2373
2374 /*
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002375 * Buffer2 will have L3/L4 header plus
Ananda Rajuda6971d2005-10-31 16:55:31 -05002376 * L4 payload
2377 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002378 ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single
Ananda Rajuda6971d2005-10-31 16:55:31 -05002379 (nic->pdev, skb->data, dev->mtu + 4,
2380 PCI_DMA_FROMDEVICE);
2381
Ananda Raju75c30b12006-07-24 19:55:09 -04002382 /* Buffer-1 will be dummy buffer. Not used */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002383 if (!(((struct RxD3*)rxdp)->Buffer1_ptr)) {
2384 ((struct RxD3*)rxdp)->Buffer1_ptr =
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002385 pci_map_single(nic->pdev,
Ananda Raju75c30b12006-07-24 19:55:09 -04002386 ba->ba_1, BUF1_LEN,
2387 PCI_DMA_FROMDEVICE);
2388 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002389 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
2390 rxdp->Control_2 |= SET_BUFFER2_SIZE_3
2391 (dev->mtu + 4);
2392 } else {
2393 /* 3 buffer mode */
2394 if (fill_rxd_3buf(nic, rxdp, skb) == -ENOMEM) {
2395 dev_kfree_skb_irq(skb);
2396 if (first_rxdp) {
2397 wmb();
2398 first_rxdp->Control_1 |=
2399 RXD_OWN_XENA;
2400 }
2401 return -ENOMEM ;
2402 }
2403 }
2404 rxdp->Control_2 |= BIT(0);
2405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 rxdp->Host_Control = (unsigned long) (skb);
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002407 if (alloc_tab & ((1 << rxsync_frequency) - 1))
2408 rxdp->Control_1 |= RXD_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 off++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002410 if (off == (rxd_count[nic->rxd_mode] + 1))
2411 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002412 mac_control->rings[ring_no].rx_curr_put_info.offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002414 rxdp->Control_2 |= SET_RXD_MARKER;
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002415 if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
2416 if (first_rxdp) {
2417 wmb();
2418 first_rxdp->Control_1 |= RXD_OWN_XENA;
2419 }
2420 first_rxdp = rxdp;
2421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 atomic_inc(&nic->rx_bufs_left[ring_no]);
2423 alloc_tab++;
2424 }
2425
2426 end:
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002427 /* Transfer ownership of first descriptor to adapter just before
2428 * exiting. Before that, use memory barrier so that ownership
2429 * and other fields are seen by adapter correctly.
2430 */
2431 if (first_rxdp) {
2432 wmb();
2433 first_rxdp->Control_1 |= RXD_OWN_XENA;
2434 }
2435
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 return SUCCESS;
2437}
2438
Ananda Rajuda6971d2005-10-31 16:55:31 -05002439static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
2440{
2441 struct net_device *dev = sp->dev;
2442 int j;
2443 struct sk_buff *skb;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002444 struct RxD_t *rxdp;
2445 struct mac_info *mac_control;
2446 struct buffAdd *ba;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002447
2448 mac_control = &sp->mac_control;
2449 for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
2450 rxdp = mac_control->rings[ring_no].
2451 rx_blocks[blk].rxds[j].virt_addr;
2452 skb = (struct sk_buff *)
2453 ((unsigned long) rxdp->Host_Control);
2454 if (!skb) {
2455 continue;
2456 }
2457 if (sp->rxd_mode == RXD_MODE_1) {
2458 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002459 ((struct RxD1*)rxdp)->Buffer0_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002460 dev->mtu +
2461 HEADER_ETHERNET_II_802_3_SIZE
2462 + HEADER_802_2_SIZE +
2463 HEADER_SNAP_SIZE,
2464 PCI_DMA_FROMDEVICE);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002465 memset(rxdp, 0, sizeof(struct RxD1));
Ananda Rajuda6971d2005-10-31 16:55:31 -05002466 } else if(sp->rxd_mode == RXD_MODE_3B) {
2467 ba = &mac_control->rings[ring_no].
2468 ba[blk][j];
2469 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002470 ((struct RxD3*)rxdp)->Buffer0_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002471 BUF0_LEN,
2472 PCI_DMA_FROMDEVICE);
2473 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002474 ((struct RxD3*)rxdp)->Buffer1_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002475 BUF1_LEN,
2476 PCI_DMA_FROMDEVICE);
2477 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002478 ((struct RxD3*)rxdp)->Buffer2_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002479 dev->mtu + 4,
2480 PCI_DMA_FROMDEVICE);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002481 memset(rxdp, 0, sizeof(struct RxD3));
Ananda Rajuda6971d2005-10-31 16:55:31 -05002482 } else {
2483 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002484 ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002485 PCI_DMA_FROMDEVICE);
2486 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002487 ((struct RxD3*)rxdp)->Buffer1_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002488 l3l4hdr_size + 4,
2489 PCI_DMA_FROMDEVICE);
2490 pci_unmap_single(sp->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002491 ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002492 PCI_DMA_FROMDEVICE);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002493 memset(rxdp, 0, sizeof(struct RxD3));
Ananda Rajuda6971d2005-10-31 16:55:31 -05002494 }
2495 dev_kfree_skb(skb);
2496 atomic_dec(&sp->rx_bufs_left[ring_no]);
2497 }
2498}
2499
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002501 * free_rx_buffers - Frees all Rx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 * @sp: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002503 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 * This function will free all Rx buffers allocated by host.
2505 * Return Value:
2506 * NONE.
2507 */
2508
2509static void free_rx_buffers(struct s2io_nic *sp)
2510{
2511 struct net_device *dev = sp->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002512 int i, blk = 0, buf_cnt = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002513 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 struct config_param *config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516 mac_control = &sp->mac_control;
2517 config = &sp->config;
2518
2519 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -05002520 for (blk = 0; blk < rx_ring_sz[i]; blk++)
2521 free_rxd_blk(sp,i,blk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002523 mac_control->rings[i].rx_curr_put_info.block_index = 0;
2524 mac_control->rings[i].rx_curr_get_info.block_index = 0;
2525 mac_control->rings[i].rx_curr_put_info.offset = 0;
2526 mac_control->rings[i].rx_curr_get_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 atomic_set(&sp->rx_bufs_left[i], 0);
2528 DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
2529 dev->name, buf_cnt, i);
2530 }
2531}
2532
2533/**
2534 * s2io_poll - Rx interrupt handler for NAPI support
2535 * @dev : pointer to the device structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002536 * @budget : The number of packets that were budgeted to be processed
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 * during one pass through the 'Poll" function.
2538 * Description:
2539 * Comes into picture only if NAPI support has been incorporated. It does
2540 * the same thing that rx_intr_handler does, but not in a interrupt context
2541 * also It will process only a given number of packets.
2542 * Return value:
2543 * 0 on success and 1 if there are No Rx packets to be processed.
2544 */
2545
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546static int s2io_poll(struct net_device *dev, int *budget)
2547{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002548 struct s2io_nic *nic = dev->priv;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002549 int pkt_cnt = 0, org_pkts_to_process;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002550 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 struct config_param *config;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002552 struct XENA_dev_config __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002553 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002555 atomic_inc(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 mac_control = &nic->mac_control;
2557 config = &nic->config;
2558
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002559 nic->pkts_to_process = *budget;
2560 if (nic->pkts_to_process > dev->quota)
2561 nic->pkts_to_process = dev->quota;
2562 org_pkts_to_process = nic->pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002564 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
2565 readl(&bar0->rx_traffic_int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566
2567 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002568 rx_intr_handler(&mac_control->rings[i]);
2569 pkt_cnt = org_pkts_to_process - nic->pkts_to_process;
2570 if (!nic->pkts_to_process) {
2571 /* Quota for the current iteration has been met */
2572 goto no_rx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 }
2575 if (!pkt_cnt)
2576 pkt_cnt = 1;
2577
2578 dev->quota -= pkt_cnt;
2579 *budget -= pkt_cnt;
2580 netif_rx_complete(dev);
2581
2582 for (i = 0; i < config->rx_ring_num; i++) {
2583 if (fill_rx_buffers(nic, i) == -ENOMEM) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08002584 DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
2585 DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 break;
2587 }
2588 }
2589 /* Re enable the Rx interrupts. */
Ananda Rajuc92ca042006-04-21 19:18:03 -04002590 writeq(0x0, &bar0->rx_traffic_mask);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002591 readl(&bar0->rx_traffic_mask);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002592 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 return 0;
2594
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002595no_rx:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 dev->quota -= pkt_cnt;
2597 *budget -= pkt_cnt;
2598
2599 for (i = 0; i < config->rx_ring_num; i++) {
2600 if (fill_rx_buffers(nic, i) == -ENOMEM) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08002601 DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
2602 DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 break;
2604 }
2605 }
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002606 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 return 1;
2608}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002609
Ananda Rajub41477f2006-07-24 19:52:49 -04002610#ifdef CONFIG_NET_POLL_CONTROLLER
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002611/**
Ananda Rajub41477f2006-07-24 19:52:49 -04002612 * s2io_netpoll - netpoll event handler entry point
Brian Haley612eff02006-06-15 14:36:36 -04002613 * @dev : pointer to the device structure.
2614 * Description:
Ananda Rajub41477f2006-07-24 19:52:49 -04002615 * This function will be called by upper layer to check for events on the
2616 * interface in situations where interrupts are disabled. It is used for
2617 * specific in-kernel networking tasks, such as remote consoles and kernel
2618 * debugging over the network (example netdump in RedHat).
Brian Haley612eff02006-06-15 14:36:36 -04002619 */
Brian Haley612eff02006-06-15 14:36:36 -04002620static void s2io_netpoll(struct net_device *dev)
2621{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002622 struct s2io_nic *nic = dev->priv;
2623 struct mac_info *mac_control;
Brian Haley612eff02006-06-15 14:36:36 -04002624 struct config_param *config;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002625 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ananda Rajub41477f2006-07-24 19:52:49 -04002626 u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
Brian Haley612eff02006-06-15 14:36:36 -04002627 int i;
2628
2629 disable_irq(dev->irq);
2630
2631 atomic_inc(&nic->isr_cnt);
2632 mac_control = &nic->mac_control;
2633 config = &nic->config;
2634
Brian Haley612eff02006-06-15 14:36:36 -04002635 writeq(val64, &bar0->rx_traffic_int);
Ananda Rajub41477f2006-07-24 19:52:49 -04002636 writeq(val64, &bar0->tx_traffic_int);
Brian Haley612eff02006-06-15 14:36:36 -04002637
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002638 /* we need to free up the transmitted skbufs or else netpoll will
Ananda Rajub41477f2006-07-24 19:52:49 -04002639 * run out of skbs and will fail and eventually netpoll application such
2640 * as netdump will fail.
2641 */
2642 for (i = 0; i < config->tx_fifo_num; i++)
2643 tx_intr_handler(&mac_control->fifos[i]);
2644
2645 /* check for received packet and indicate up to network */
Brian Haley612eff02006-06-15 14:36:36 -04002646 for (i = 0; i < config->rx_ring_num; i++)
2647 rx_intr_handler(&mac_control->rings[i]);
2648
2649 for (i = 0; i < config->rx_ring_num; i++) {
2650 if (fill_rx_buffers(nic, i) == -ENOMEM) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08002651 DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
2652 DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n");
Brian Haley612eff02006-06-15 14:36:36 -04002653 break;
2654 }
2655 }
2656 atomic_dec(&nic->isr_cnt);
2657 enable_irq(dev->irq);
2658 return;
2659}
2660#endif
2661
2662/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 * rx_intr_handler - Rx interrupt handler
2664 * @nic: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002665 * Description:
2666 * If the interrupt is because of a received frame or if the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 * receive ring contains fresh as yet un-processed frames,this function is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002668 * called. It picks out the RxD at which place the last Rx processing had
2669 * stopped and sends the skb to the OSM's Rx handler and then increments
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 * the offset.
2671 * Return Value:
2672 * NONE.
2673 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002674static void rx_intr_handler(struct ring_info *ring_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002676 struct s2io_nic *nic = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 struct net_device *dev = (struct net_device *) nic->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002678 int get_block, put_block, put_offset;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002679 struct rx_curr_get_info get_info, put_info;
2680 struct RxD_t *rxdp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 struct sk_buff *skb;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002682 int pkt_cnt = 0;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002683 int i;
2684
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002685 spin_lock(&nic->rx_lock);
2686 if (atomic_read(&nic->card_state) == CARD_DOWN) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002687 DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002688 __FUNCTION__, dev->name);
2689 spin_unlock(&nic->rx_lock);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002690 return;
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002691 }
2692
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002693 get_info = ring_data->rx_curr_get_info;
2694 get_block = get_info.block_index;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002695 memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002696 put_block = put_info.block_index;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002697 rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002698 if (!napi) {
2699 spin_lock(&nic->put_lock);
2700 put_offset = ring_data->put_pos;
2701 spin_unlock(&nic->put_lock);
2702 } else
2703 put_offset = ring_data->put_pos;
2704
Ananda Rajuda6971d2005-10-31 16:55:31 -05002705 while (RXD_IS_UP2DT(rxdp)) {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002706 /*
2707 * If your are next to put index then it's
2708 * FIFO full condition
2709 */
Ananda Rajuda6971d2005-10-31 16:55:31 -05002710 if ((get_block == put_block) &&
2711 (get_info.offset + 1) == put_info.offset) {
Ananda Raju75c30b12006-07-24 19:55:09 -04002712 DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002713 break;
2714 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002715 skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
2716 if (skb == NULL) {
2717 DBG_PRINT(ERR_DBG, "%s: The skb is ",
2718 dev->name);
2719 DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002720 spin_unlock(&nic->rx_lock);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002721 return;
2722 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002723 if (nic->rxd_mode == RXD_MODE_1) {
2724 pci_unmap_single(nic->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002725 ((struct RxD1*)rxdp)->Buffer0_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002726 dev->mtu +
2727 HEADER_ETHERNET_II_802_3_SIZE +
2728 HEADER_802_2_SIZE +
2729 HEADER_SNAP_SIZE,
2730 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002731 } else if (nic->rxd_mode == RXD_MODE_3B) {
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,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002734 BUF0_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002735 pci_unmap_single(nic->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002736 ((struct RxD3*)rxdp)->Buffer2_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002737 dev->mtu + 4,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002738 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002739 } else {
Ananda Raju75c30b12006-07-24 19:55:09 -04002740 pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002741 ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002742 PCI_DMA_FROMDEVICE);
2743 pci_unmap_single(nic->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002744 ((struct RxD3*)rxdp)->Buffer1_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002745 l3l4hdr_size + 4,
2746 PCI_DMA_FROMDEVICE);
2747 pci_unmap_single(nic->pdev, (dma_addr_t)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002748 ((struct RxD3*)rxdp)->Buffer2_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002749 dev->mtu, PCI_DMA_FROMDEVICE);
2750 }
Ananda Raju863c11a2006-04-21 19:03:13 -04002751 prefetch(skb->data);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002752 rx_osm_handler(ring_data, rxdp);
2753 get_info.offset++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002754 ring_data->rx_curr_get_info.offset = get_info.offset;
2755 rxdp = ring_data->rx_blocks[get_block].
2756 rxds[get_info.offset].virt_addr;
2757 if (get_info.offset == rxd_count[nic->rxd_mode]) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002758 get_info.offset = 0;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002759 ring_data->rx_curr_get_info.offset = get_info.offset;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002760 get_block++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002761 if (get_block == ring_data->block_count)
2762 get_block = 0;
2763 ring_data->rx_curr_get_info.block_index = get_block;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002764 rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
2765 }
2766
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002767 nic->pkts_to_process -= 1;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002768 if ((napi) && (!nic->pkts_to_process))
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002769 break;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002770 pkt_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
2772 break;
2773 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002774 if (nic->lro) {
2775 /* Clear all LRO sessions before exiting */
2776 for (i=0; i<MAX_LRO_SESSIONS; i++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002777 struct lro *lro = &nic->lro0_n[i];
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002778 if (lro->in_use) {
2779 update_L3L4_header(nic, lro);
2780 queue_rx_frame(lro->parent);
2781 clear_lro_session(lro);
2782 }
2783 }
2784 }
2785
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002786 spin_unlock(&nic->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002788
2789/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 * tx_intr_handler - Transmit interrupt handler
2791 * @nic : device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002792 * Description:
2793 * If an interrupt was raised to indicate DMA complete of the
2794 * Tx packet, this function is called. It identifies the last TxD
2795 * whose buffer was freed and frees all skbs whose data have already
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 * DMA'ed into the NICs internal memory.
2797 * Return Value:
2798 * NONE
2799 */
2800
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002801static void tx_intr_handler(struct fifo_info *fifo_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002803 struct s2io_nic *nic = fifo_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 struct net_device *dev = (struct net_device *) nic->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002805 struct tx_curr_get_info get_info, put_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 struct sk_buff *skb;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002807 struct TxD *txdlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002809 get_info = fifo_data->tx_curr_get_info;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002810 memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info));
2811 txdlp = (struct TxD *) fifo_data->list_info[get_info.offset].
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002812 list_virt_addr;
2813 while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
2814 (get_info.offset != put_info.offset) &&
2815 (txdlp->Host_Control)) {
2816 /* Check for TxD errors */
2817 if (txdlp->Control_1 & TXD_T_CODE) {
2818 unsigned long long err;
2819 err = txdlp->Control_1 & TXD_T_CODE;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002820 if (err & 0x1) {
2821 nic->mac_control.stats_info->sw_stat.
2822 parity_err_cnt++;
2823 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002824 if ((err >> 48) == 0xA) {
2825 DBG_PRINT(TX_DBG, "TxD returned due \
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002826 to loss of link\n");
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002827 }
2828 else {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002829 DBG_PRINT(ERR_DBG, "***TxD error %llx\n", err);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002832
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002833 skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002834 if (skb == NULL) {
2835 DBG_PRINT(ERR_DBG, "%s: Null skb ",
2836 __FUNCTION__);
2837 DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
2838 return;
2839 }
2840
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002841 /* Updating the statistics block */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002842 nic->stats.tx_bytes += skb->len;
2843 dev_kfree_skb_irq(skb);
2844
2845 get_info.offset++;
Ananda Raju863c11a2006-04-21 19:03:13 -04002846 if (get_info.offset == get_info.fifo_len + 1)
2847 get_info.offset = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002848 txdlp = (struct TxD *) fifo_data->list_info
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002849 [get_info.offset].list_virt_addr;
2850 fifo_data->tx_curr_get_info.offset =
2851 get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 }
2853
2854 spin_lock(&nic->tx_lock);
2855 if (netif_queue_stopped(dev))
2856 netif_wake_queue(dev);
2857 spin_unlock(&nic->tx_lock);
2858}
2859
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002860/**
Ananda Rajubd1034f2006-04-21 19:20:22 -04002861 * s2io_mdio_write - Function to write in to MDIO registers
2862 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
2863 * @addr : address value
2864 * @value : data value
2865 * @dev : pointer to net_device structure
2866 * Description:
2867 * This function is used to write values to the MDIO registers
2868 * NONE
2869 */
2870static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
2871{
2872 u64 val64 = 0x0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002873 struct s2io_nic *sp = dev->priv;
2874 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002875
2876 //address transaction
2877 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2878 | MDIO_MMD_DEV_ADDR(mmd_type)
2879 | MDIO_MMS_PRT_ADDR(0x0);
2880 writeq(val64, &bar0->mdio_control);
2881 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2882 writeq(val64, &bar0->mdio_control);
2883 udelay(100);
2884
2885 //Data transaction
2886 val64 = 0x0;
2887 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2888 | MDIO_MMD_DEV_ADDR(mmd_type)
2889 | MDIO_MMS_PRT_ADDR(0x0)
2890 | MDIO_MDIO_DATA(value)
2891 | MDIO_OP(MDIO_OP_WRITE_TRANS);
2892 writeq(val64, &bar0->mdio_control);
2893 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2894 writeq(val64, &bar0->mdio_control);
2895 udelay(100);
2896
2897 val64 = 0x0;
2898 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2899 | MDIO_MMD_DEV_ADDR(mmd_type)
2900 | MDIO_MMS_PRT_ADDR(0x0)
2901 | MDIO_OP(MDIO_OP_READ_TRANS);
2902 writeq(val64, &bar0->mdio_control);
2903 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2904 writeq(val64, &bar0->mdio_control);
2905 udelay(100);
2906
2907}
2908
2909/**
2910 * s2io_mdio_read - Function to write in to MDIO registers
2911 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
2912 * @addr : address value
2913 * @dev : pointer to net_device structure
2914 * Description:
2915 * This function is used to read values to the MDIO registers
2916 * NONE
2917 */
2918static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
2919{
2920 u64 val64 = 0x0;
2921 u64 rval64 = 0x0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002922 struct s2io_nic *sp = dev->priv;
2923 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002924
2925 /* address transaction */
2926 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2927 | MDIO_MMD_DEV_ADDR(mmd_type)
2928 | MDIO_MMS_PRT_ADDR(0x0);
2929 writeq(val64, &bar0->mdio_control);
2930 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2931 writeq(val64, &bar0->mdio_control);
2932 udelay(100);
2933
2934 /* Data transaction */
2935 val64 = 0x0;
2936 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2937 | MDIO_MMD_DEV_ADDR(mmd_type)
2938 | MDIO_MMS_PRT_ADDR(0x0)
2939 | MDIO_OP(MDIO_OP_READ_TRANS);
2940 writeq(val64, &bar0->mdio_control);
2941 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2942 writeq(val64, &bar0->mdio_control);
2943 udelay(100);
2944
2945 /* Read the value from regs */
2946 rval64 = readq(&bar0->mdio_control);
2947 rval64 = rval64 & 0xFFFF0000;
2948 rval64 = rval64 >> 16;
2949 return rval64;
2950}
2951/**
2952 * s2io_chk_xpak_counter - Function to check the status of the xpak counters
2953 * @counter : couter value to be updated
2954 * @flag : flag to indicate the status
2955 * @type : counter type
2956 * Description:
2957 * This function is to check the status of the xpak counters value
2958 * NONE
2959 */
2960
2961static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, u16 flag, u16 type)
2962{
2963 u64 mask = 0x3;
2964 u64 val64;
2965 int i;
2966 for(i = 0; i <index; i++)
2967 mask = mask << 0x2;
2968
2969 if(flag > 0)
2970 {
2971 *counter = *counter + 1;
2972 val64 = *regs_stat & mask;
2973 val64 = val64 >> (index * 0x2);
2974 val64 = val64 + 1;
2975 if(val64 == 3)
2976 {
2977 switch(type)
2978 {
2979 case 1:
2980 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
2981 "service. Excessive temperatures may "
2982 "result in premature transceiver "
2983 "failure \n");
2984 break;
2985 case 2:
2986 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
2987 "service Excessive bias currents may "
2988 "indicate imminent laser diode "
2989 "failure \n");
2990 break;
2991 case 3:
2992 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
2993 "service Excessive laser output "
2994 "power may saturate far-end "
2995 "receiver\n");
2996 break;
2997 default:
2998 DBG_PRINT(ERR_DBG, "Incorrect XPAK Alarm "
2999 "type \n");
3000 }
3001 val64 = 0x0;
3002 }
3003 val64 = val64 << (index * 0x2);
3004 *regs_stat = (*regs_stat & (~mask)) | (val64);
3005
3006 } else {
3007 *regs_stat = *regs_stat & (~mask);
3008 }
3009}
3010
3011/**
3012 * s2io_updt_xpak_counter - Function to update the xpak counters
3013 * @dev : pointer to net_device struct
3014 * Description:
3015 * This function is to upate the status of the xpak counters value
3016 * NONE
3017 */
3018static void s2io_updt_xpak_counter(struct net_device *dev)
3019{
3020 u16 flag = 0x0;
3021 u16 type = 0x0;
3022 u16 val16 = 0x0;
3023 u64 val64 = 0x0;
3024 u64 addr = 0x0;
3025
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003026 struct s2io_nic *sp = dev->priv;
3027 struct stat_block *stat_info = sp->mac_control.stats_info;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003028
3029 /* Check the communication with the MDIO slave */
3030 addr = 0x0000;
3031 val64 = 0x0;
3032 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3033 if((val64 == 0xFFFF) || (val64 == 0x0000))
3034 {
3035 DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - "
3036 "Returned %llx\n", (unsigned long long)val64);
3037 return;
3038 }
3039
3040 /* Check for the expecte value of 2040 at PMA address 0x0000 */
3041 if(val64 != 0x2040)
3042 {
3043 DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - ");
3044 DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x2040\n",
3045 (unsigned long long)val64);
3046 return;
3047 }
3048
3049 /* Loading the DOM register to MDIO register */
3050 addr = 0xA100;
3051 s2io_mdio_write(MDIO_MMD_PMA_DEV_ADDR, addr, val16, dev);
3052 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3053
3054 /* Reading the Alarm flags */
3055 addr = 0xA070;
3056 val64 = 0x0;
3057 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3058
3059 flag = CHECKBIT(val64, 0x7);
3060 type = 1;
3061 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_transceiver_temp_high,
3062 &stat_info->xpak_stat.xpak_regs_stat,
3063 0x0, flag, type);
3064
3065 if(CHECKBIT(val64, 0x6))
3066 stat_info->xpak_stat.alarm_transceiver_temp_low++;
3067
3068 flag = CHECKBIT(val64, 0x3);
3069 type = 2;
3070 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_bias_current_high,
3071 &stat_info->xpak_stat.xpak_regs_stat,
3072 0x2, flag, type);
3073
3074 if(CHECKBIT(val64, 0x2))
3075 stat_info->xpak_stat.alarm_laser_bias_current_low++;
3076
3077 flag = CHECKBIT(val64, 0x1);
3078 type = 3;
3079 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_output_power_high,
3080 &stat_info->xpak_stat.xpak_regs_stat,
3081 0x4, flag, type);
3082
3083 if(CHECKBIT(val64, 0x0))
3084 stat_info->xpak_stat.alarm_laser_output_power_low++;
3085
3086 /* Reading the Warning flags */
3087 addr = 0xA074;
3088 val64 = 0x0;
3089 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3090
3091 if(CHECKBIT(val64, 0x7))
3092 stat_info->xpak_stat.warn_transceiver_temp_high++;
3093
3094 if(CHECKBIT(val64, 0x6))
3095 stat_info->xpak_stat.warn_transceiver_temp_low++;
3096
3097 if(CHECKBIT(val64, 0x3))
3098 stat_info->xpak_stat.warn_laser_bias_current_high++;
3099
3100 if(CHECKBIT(val64, 0x2))
3101 stat_info->xpak_stat.warn_laser_bias_current_low++;
3102
3103 if(CHECKBIT(val64, 0x1))
3104 stat_info->xpak_stat.warn_laser_output_power_high++;
3105
3106 if(CHECKBIT(val64, 0x0))
3107 stat_info->xpak_stat.warn_laser_output_power_low++;
3108}
3109
3110/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 * alarm_intr_handler - Alarm Interrrupt handler
3112 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003113 * Description: If the interrupt was neither because of Rx packet or Tx
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 * complete, this function is called. If the interrupt was to indicate
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003115 * a loss of link, the OSM link status handler is invoked for any other
3116 * alarm interrupt the block that raised the interrupt is displayed
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 * and a H/W reset is issued.
3118 * Return Value:
3119 * NONE
3120*/
3121
3122static void alarm_intr_handler(struct s2io_nic *nic)
3123{
3124 struct net_device *dev = (struct net_device *) nic->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003125 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 register u64 val64 = 0, err_reg = 0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003127 u64 cnt;
3128 int i;
Sivakumar Subramani372cc592007-01-31 13:32:57 -05003129 if (atomic_read(&nic->card_state) == CARD_DOWN)
3130 return;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003131 nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
3132 /* Handling the XPAK counters update */
3133 if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
3134 /* waiting for an hour */
3135 nic->mac_control.stats_info->xpak_stat.xpak_timer_count++;
3136 } else {
3137 s2io_updt_xpak_counter(dev);
3138 /* reset the count to zero */
3139 nic->mac_control.stats_info->xpak_stat.xpak_timer_count = 0;
3140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141
3142 /* Handling link status change error Intr */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07003143 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
3144 err_reg = readq(&bar0->mac_rmac_err_reg);
3145 writeq(err_reg, &bar0->mac_rmac_err_reg);
3146 if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
3147 schedule_work(&nic->set_link_task);
3148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 }
3150
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003151 /* Handling Ecc errors */
3152 val64 = readq(&bar0->mc_err_reg);
3153 writeq(val64, &bar0->mc_err_reg);
3154 if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
3155 if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003156 nic->mac_control.stats_info->sw_stat.
3157 double_ecc_errs++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003158 DBG_PRINT(INIT_DBG, "%s: Device indicates ",
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003159 dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003160 DBG_PRINT(INIT_DBG, "double ECC error!!\n");
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003161 if (nic->device_type != XFRAME_II_DEVICE) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003162 /* Reset XframeI only if critical error */
3163 if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
3164 MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
3165 netif_stop_queue(dev);
3166 schedule_work(&nic->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04003167 nic->mac_control.stats_info->sw_stat.
3168 soft_reset_cnt++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003169 }
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003170 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003171 } else {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003172 nic->mac_control.stats_info->sw_stat.
3173 single_ecc_errs++;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003174 }
3175 }
3176
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 /* In case of a serious error, the device will be Reset. */
3178 val64 = readq(&bar0->serr_source);
3179 if (val64 & SERR_SOURCE_ANY) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04003180 nic->mac_control.stats_info->sw_stat.serious_err_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003182 DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003183 (unsigned long long)val64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 netif_stop_queue(dev);
3185 schedule_work(&nic->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04003186 nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 }
3188
3189 /*
3190 * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
3191 * Error occurs, the adapter will be recycled by disabling the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003192 * adapter enable bit and enabling it again after the device
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 * becomes Quiescent.
3194 */
3195 val64 = readq(&bar0->pcc_err_reg);
3196 writeq(val64, &bar0->pcc_err_reg);
3197 if (val64 & PCC_FB_ECC_DB_ERR) {
3198 u64 ac = readq(&bar0->adapter_control);
3199 ac &= ~(ADAPTER_CNTL_EN);
3200 writeq(ac, &bar0->adapter_control);
3201 ac = readq(&bar0->adapter_control);
3202 schedule_work(&nic->set_link_task);
3203 }
Ananda Rajubd1034f2006-04-21 19:20:22 -04003204 /* Check for data parity error */
3205 val64 = readq(&bar0->pic_int_status);
3206 if (val64 & PIC_INT_GPIO) {
3207 val64 = readq(&bar0->gpio_int_reg);
3208 if (val64 & GPIO_INT_REG_DP_ERR_INT) {
3209 nic->mac_control.stats_info->sw_stat.parity_err_cnt++;
3210 schedule_work(&nic->rst_timer_task);
3211 nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
3212 }
3213 }
3214
3215 /* Check for ring full counter */
3216 if (nic->device_type & XFRAME_II_DEVICE) {
3217 val64 = readq(&bar0->ring_bump_counter1);
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
3225 val64 = readq(&bar0->ring_bump_counter2);
3226 for (i=0; i<4; i++) {
3227 cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
3228 cnt >>= 64 - ((i+1)*16);
3229 nic->mac_control.stats_info->sw_stat.ring_full_cnt
3230 += cnt;
3231 }
3232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233
3234 /* Other type of interrupts are not being handled now, TODO */
3235}
3236
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003237/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 * wait_for_cmd_complete - waits for a command to complete.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003239 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003241 * Description: Function that waits for a command to Write into RMAC
3242 * ADDR DATA registers to be completed and returns either success or
3243 * error depending on whether the command was complete or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 * Return value:
3245 * SUCCESS on success and FAILURE on failure.
3246 */
3247
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003248static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit,
3249 int bit_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250{
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003251 int ret = FAILURE, cnt = 0, delay = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 u64 val64;
3253
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003254 if ((bit_state != S2IO_BIT_RESET) && (bit_state != S2IO_BIT_SET))
3255 return FAILURE;
3256
3257 do {
Ananda Rajuc92ca042006-04-21 19:18:03 -04003258 val64 = readq(addr);
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003259 if (bit_state == S2IO_BIT_RESET) {
3260 if (!(val64 & busy_bit)) {
3261 ret = SUCCESS;
3262 break;
3263 }
3264 } else {
3265 if (!(val64 & busy_bit)) {
3266 ret = SUCCESS;
3267 break;
3268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003270
3271 if(in_interrupt())
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003272 mdelay(delay);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003273 else
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003274 msleep(delay);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003275
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003276 if (++cnt >= 10)
3277 delay = 50;
3278 } while (cnt < 20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 return ret;
3280}
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003281/*
3282 * check_pci_device_id - Checks if the device id is supported
3283 * @id : device id
3284 * Description: Function to check if the pci device id is supported by driver.
3285 * Return value: Actual device id if supported else PCI_ANY_ID
3286 */
3287static u16 check_pci_device_id(u16 id)
3288{
3289 switch (id) {
3290 case PCI_DEVICE_ID_HERC_WIN:
3291 case PCI_DEVICE_ID_HERC_UNI:
3292 return XFRAME_II_DEVICE;
3293 case PCI_DEVICE_ID_S2IO_UNI:
3294 case PCI_DEVICE_ID_S2IO_WIN:
3295 return XFRAME_I_DEVICE;
3296 default:
3297 return PCI_ANY_ID;
3298 }
3299}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003301/**
3302 * s2io_reset - Resets the card.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 * @sp : private member of the device structure.
3304 * Description: Function to Reset the card. This function then also
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003305 * restores the previously saved PCI configuration space registers as
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 * the card reset also resets the configuration space.
3307 * Return value:
3308 * void.
3309 */
3310
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003311static void s2io_reset(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003313 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 u64 val64;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003315 u16 subid, pci_cmd;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003316 int i;
3317 u16 val16;
Ramkrishna Vepa363dc362007-03-06 17:01:00 -08003318 unsigned long long reset_cnt = 0;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003319 DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
3320 __FUNCTION__, sp->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003322 /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003323 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003324
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003325 if (sp->device_type == XFRAME_II_DEVICE) {
3326 int ret;
3327 ret = pci_set_power_state(sp->pdev, 3);
3328 if (!ret)
3329 ret = pci_set_power_state(sp->pdev, 0);
3330 else {
3331 DBG_PRINT(ERR_DBG,"%s PME based SW_Reset failed!\n",
3332 __FUNCTION__);
3333 goto old_way;
3334 }
3335 msleep(20);
3336 goto new_way;
3337 }
3338old_way:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 val64 = SW_RESET_ALL;
3340 writeq(val64, &bar0->sw_reset);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003341new_way:
Ananda Rajuc92ca042006-04-21 19:18:03 -04003342 if (strstr(sp->product_name, "CX4")) {
3343 msleep(750);
3344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 msleep(250);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003346 for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) {
3347
3348 /* Restore the PCI state saved during initialization. */
3349 pci_restore_state(sp->pdev);
3350 pci_read_config_word(sp->pdev, 0x2, &val16);
3351 if (check_pci_device_id(val16) != (u16)PCI_ANY_ID)
3352 break;
3353 msleep(200);
3354 }
3355
3356 if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) {
3357 DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__);
3358 }
3359
3360 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd);
3361
3362 s2io_init_pci(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003364 /* Set swapper to enable I/O register access */
3365 s2io_set_swapper(sp);
3366
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003367 /* Restore the MSIX table entries from local variables */
3368 restore_xmsi_data(sp);
3369
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003370 /* Clear certain PCI/PCI-X fields after reset */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003371 if (sp->device_type == XFRAME_II_DEVICE) {
Ananda Rajub41477f2006-07-24 19:52:49 -04003372 /* Clear "detected parity error" bit */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003373 pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003374
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003375 /* Clearing PCIX Ecc status register */
3376 pci_write_config_dword(sp->pdev, 0x68, 0x7C);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003377
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003378 /* Clearing PCI_STATUS error reflected here */
3379 writeq(BIT(62), &bar0->txpic_int_reg);
3380 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003381
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003382 /* Reset device statistics maintained by OS */
3383 memset(&sp->stats, 0, sizeof (struct net_device_stats));
Ramkrishna Vepa363dc362007-03-06 17:01:00 -08003384 /* save reset count */
3385 reset_cnt = sp->mac_control.stats_info->sw_stat.soft_reset_cnt;
3386 memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
3387 /* restore reset count */
3388 sp->mac_control.stats_info->sw_stat.soft_reset_cnt = reset_cnt;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003389
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 /* SXE-002: Configure link and activity LED to turn it off */
3391 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003392 if (((subid & 0xFF) >= 0x07) &&
3393 (sp->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 val64 = readq(&bar0->gpio_control);
3395 val64 |= 0x0000800000000000ULL;
3396 writeq(val64, &bar0->gpio_control);
3397 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01003398 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 }
3400
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003401 /*
3402 * Clear spurious ECC interrupts that would have occured on
3403 * XFRAME II cards after reset.
3404 */
3405 if (sp->device_type == XFRAME_II_DEVICE) {
3406 val64 = readq(&bar0->pcc_err_reg);
3407 writeq(val64, &bar0->pcc_err_reg);
3408 }
3409
Sivakumar Subramanid8d70ca2007-02-24 02:04:24 -05003410 /* restore the previously assigned mac address */
3411 s2io_set_mac_addr(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr);
3412
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 sp->device_enabled_once = FALSE;
3414}
3415
3416/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003417 * s2io_set_swapper - to set the swapper controle on the card
3418 * @sp : private member of the device structure,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 * pointer to the s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003420 * Description: Function to set the swapper control on the card
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 * correctly depending on the 'endianness' of the system.
3422 * Return value:
3423 * SUCCESS on success and FAILURE on failure.
3424 */
3425
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003426static int s2io_set_swapper(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427{
3428 struct net_device *dev = sp->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003429 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 u64 val64, valt, valr;
3431
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003432 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 * Set proper endian settings and verify the same by reading
3434 * the PIF Feed-back register.
3435 */
3436
3437 val64 = readq(&bar0->pif_rd_swapper_fb);
3438 if (val64 != 0x0123456789ABCDEFULL) {
3439 int i = 0;
3440 u64 value[] = { 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */
3441 0x8100008181000081ULL, /* FE=1, SE=0 */
3442 0x4200004242000042ULL, /* FE=0, SE=1 */
3443 0}; /* FE=0, SE=0 */
3444
3445 while(i<4) {
3446 writeq(value[i], &bar0->swapper_ctrl);
3447 val64 = readq(&bar0->pif_rd_swapper_fb);
3448 if (val64 == 0x0123456789ABCDEFULL)
3449 break;
3450 i++;
3451 }
3452 if (i == 4) {
3453 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3454 dev->name);
3455 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3456 (unsigned long long) val64);
3457 return FAILURE;
3458 }
3459 valr = value[i];
3460 } else {
3461 valr = readq(&bar0->swapper_ctrl);
3462 }
3463
3464 valt = 0x0123456789ABCDEFULL;
3465 writeq(valt, &bar0->xmsi_address);
3466 val64 = readq(&bar0->xmsi_address);
3467
3468 if(val64 != valt) {
3469 int i = 0;
3470 u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */
3471 0x0081810000818100ULL, /* FE=1, SE=0 */
3472 0x0042420000424200ULL, /* FE=0, SE=1 */
3473 0}; /* FE=0, SE=0 */
3474
3475 while(i<4) {
3476 writeq((value[i] | valr), &bar0->swapper_ctrl);
3477 writeq(valt, &bar0->xmsi_address);
3478 val64 = readq(&bar0->xmsi_address);
3479 if(val64 == valt)
3480 break;
3481 i++;
3482 }
3483 if(i == 4) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003484 unsigned long long x = val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr ");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003486 DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 return FAILURE;
3488 }
3489 }
3490 val64 = readq(&bar0->swapper_ctrl);
3491 val64 &= 0xFFFF000000000000ULL;
3492
3493#ifdef __BIG_ENDIAN
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003494 /*
3495 * The device by default set to a big endian format, so a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 * big endian driver need not set anything.
3497 */
3498 val64 |= (SWAPPER_CTRL_TXP_FE |
3499 SWAPPER_CTRL_TXP_SE |
3500 SWAPPER_CTRL_TXD_R_FE |
3501 SWAPPER_CTRL_TXD_W_FE |
3502 SWAPPER_CTRL_TXF_R_FE |
3503 SWAPPER_CTRL_RXD_R_FE |
3504 SWAPPER_CTRL_RXD_W_FE |
3505 SWAPPER_CTRL_RXF_W_FE |
3506 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Andrew Morton92383342005-10-16 00:11:29 -07003508 if (sp->intr_type == INTA)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003509 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 writeq(val64, &bar0->swapper_ctrl);
3511#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003512 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 * Initially we enable all bits to make it accessible by the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003514 * driver, then we selectively enable only those bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 * we want to set.
3516 */
3517 val64 |= (SWAPPER_CTRL_TXP_FE |
3518 SWAPPER_CTRL_TXP_SE |
3519 SWAPPER_CTRL_TXD_R_FE |
3520 SWAPPER_CTRL_TXD_R_SE |
3521 SWAPPER_CTRL_TXD_W_FE |
3522 SWAPPER_CTRL_TXD_W_SE |
3523 SWAPPER_CTRL_TXF_R_FE |
3524 SWAPPER_CTRL_RXD_R_FE |
3525 SWAPPER_CTRL_RXD_R_SE |
3526 SWAPPER_CTRL_RXD_W_FE |
3527 SWAPPER_CTRL_RXD_W_SE |
3528 SWAPPER_CTRL_RXF_W_FE |
3529 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003531 if (sp->intr_type == INTA)
3532 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 writeq(val64, &bar0->swapper_ctrl);
3534#endif
3535 val64 = readq(&bar0->swapper_ctrl);
3536
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003537 /*
3538 * Verifying if endian settings are accurate by reading a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 * feedback register.
3540 */
3541 val64 = readq(&bar0->pif_rd_swapper_fb);
3542 if (val64 != 0x0123456789ABCDEFULL) {
3543 /* Endian settings are incorrect, calls for another dekko. */
3544 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3545 dev->name);
3546 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3547 (unsigned long long) val64);
3548 return FAILURE;
3549 }
3550
3551 return SUCCESS;
3552}
3553
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003554static int wait_for_msix_trans(struct s2io_nic *nic, int i)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003555{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003556 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003557 u64 val64;
3558 int ret = 0, cnt = 0;
3559
3560 do {
3561 val64 = readq(&bar0->xmsi_access);
3562 if (!(val64 & BIT(15)))
3563 break;
3564 mdelay(1);
3565 cnt++;
3566 } while(cnt < 5);
3567 if (cnt == 5) {
3568 DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i);
3569 ret = 1;
3570 }
3571
3572 return ret;
3573}
3574
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003575static void restore_xmsi_data(struct s2io_nic *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003576{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003577 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003578 u64 val64;
3579 int i;
3580
Ananda Raju75c30b12006-07-24 19:55:09 -04003581 for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003582 writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
3583 writeq(nic->msix_info[i].data, &bar0->xmsi_data);
3584 val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
3585 writeq(val64, &bar0->xmsi_access);
3586 if (wait_for_msix_trans(nic, i)) {
3587 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3588 continue;
3589 }
3590 }
3591}
3592
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003593static void store_xmsi_data(struct s2io_nic *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003594{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003595 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003596 u64 val64, addr, data;
3597 int i;
3598
3599 /* Store and display */
Ananda Raju75c30b12006-07-24 19:55:09 -04003600 for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003601 val64 = (BIT(15) | vBIT(i, 26, 6));
3602 writeq(val64, &bar0->xmsi_access);
3603 if (wait_for_msix_trans(nic, i)) {
3604 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3605 continue;
3606 }
3607 addr = readq(&bar0->xmsi_address);
3608 data = readq(&bar0->xmsi_data);
3609 if (addr && data) {
3610 nic->msix_info[i].addr = addr;
3611 nic->msix_info[i].data = data;
3612 }
3613 }
3614}
3615
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003616int s2io_enable_msi(struct s2io_nic *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003617{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003618 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003619 u16 msi_ctrl, msg_val;
3620 struct config_param *config = &nic->config;
3621 struct net_device *dev = nic->dev;
3622 u64 val64, tx_mat, rx_mat;
3623 int i, err;
3624
3625 val64 = readq(&bar0->pic_control);
3626 val64 &= ~BIT(1);
3627 writeq(val64, &bar0->pic_control);
3628
3629 err = pci_enable_msi(nic->pdev);
3630 if (err) {
3631 DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n",
3632 nic->dev->name);
3633 return err;
3634 }
3635
3636 /*
3637 * Enable MSI and use MSI-1 in stead of the standard MSI-0
3638 * for interrupt handling.
3639 */
3640 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3641 msg_val ^= 0x1;
3642 pci_write_config_word(nic->pdev, 0x4c, msg_val);
3643 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3644
3645 pci_read_config_word(nic->pdev, 0x42, &msi_ctrl);
3646 msi_ctrl |= 0x10;
3647 pci_write_config_word(nic->pdev, 0x42, msi_ctrl);
3648
3649 /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */
3650 tx_mat = readq(&bar0->tx_mat0_n[0]);
3651 for (i=0; i<config->tx_fifo_num; i++) {
3652 tx_mat |= TX_MAT_SET(i, 1);
3653 }
3654 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3655
3656 rx_mat = readq(&bar0->rx_mat);
3657 for (i=0; i<config->rx_ring_num; i++) {
3658 rx_mat |= RX_MAT_SET(i, 1);
3659 }
3660 writeq(rx_mat, &bar0->rx_mat);
3661
3662 dev->irq = nic->pdev->irq;
3663 return 0;
3664}
3665
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003666static int s2io_enable_msi_x(struct s2io_nic *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003667{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003668 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003669 u64 tx_mat, rx_mat;
3670 u16 msi_control; /* Temp variable */
3671 int ret, i, j, msix_indx = 1;
3672
3673 nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
3674 GFP_KERNEL);
3675 if (nic->entries == NULL) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08003676 DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003677 return -ENOMEM;
3678 }
3679 memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
3680
3681 nic->s2io_entries =
3682 kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
3683 GFP_KERNEL);
3684 if (nic->s2io_entries == NULL) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08003685 DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003686 kfree(nic->entries);
3687 return -ENOMEM;
3688 }
3689 memset(nic->s2io_entries, 0,
3690 MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
3691
3692 for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
3693 nic->entries[i].entry = i;
3694 nic->s2io_entries[i].entry = i;
3695 nic->s2io_entries[i].arg = NULL;
3696 nic->s2io_entries[i].in_use = 0;
3697 }
3698
3699 tx_mat = readq(&bar0->tx_mat0_n[0]);
3700 for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) {
3701 tx_mat |= TX_MAT_SET(i, msix_indx);
3702 nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i];
3703 nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE;
3704 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3705 }
3706 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3707
3708 if (!nic->config.bimodal) {
3709 rx_mat = readq(&bar0->rx_mat);
3710 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3711 rx_mat |= RX_MAT_SET(j, msix_indx);
3712 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3713 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3714 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3715 }
3716 writeq(rx_mat, &bar0->rx_mat);
3717 } else {
3718 tx_mat = readq(&bar0->tx_mat0_n[7]);
3719 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3720 tx_mat |= TX_MAT_SET(i, msix_indx);
3721 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3722 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3723 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3724 }
3725 writeq(tx_mat, &bar0->tx_mat0_n[7]);
3726 }
3727
Ananda Rajuc92ca042006-04-21 19:18:03 -04003728 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003729 ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003730 /* We fail init if error or we get less vectors than min required */
3731 if (ret >= (nic->config.tx_fifo_num + nic->config.rx_ring_num + 1)) {
3732 nic->avail_msix_vectors = ret;
3733 ret = pci_enable_msix(nic->pdev, nic->entries, ret);
3734 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003735 if (ret) {
3736 DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
3737 kfree(nic->entries);
3738 kfree(nic->s2io_entries);
3739 nic->entries = NULL;
3740 nic->s2io_entries = NULL;
Ananda Rajuc92ca042006-04-21 19:18:03 -04003741 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003742 return -ENOMEM;
3743 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003744 if (!nic->avail_msix_vectors)
3745 nic->avail_msix_vectors = MAX_REQUESTED_MSI_X;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003746
3747 /*
3748 * To enable MSI-X, MSI also needs to be enabled, due to a bug
3749 * in the herc NIC. (Temp change, needs to be removed later)
3750 */
3751 pci_read_config_word(nic->pdev, 0x42, &msi_control);
3752 msi_control |= 0x1; /* Enable MSI */
3753 pci_write_config_word(nic->pdev, 0x42, msi_control);
3754
3755 return 0;
3756}
3757
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758/* ********************************************************* *
3759 * Functions defined below concern the OS part of the driver *
3760 * ********************************************************* */
3761
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003762/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 * s2io_open - open entry point of the driver
3764 * @dev : pointer to the device structure.
3765 * Description:
3766 * This function is the open entry point of the driver. It mainly calls a
3767 * function to allocate Rx buffers and inserts them into the buffer
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003768 * descriptors and then enables the Rx part of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 * Return value:
3770 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3771 * file on failure.
3772 */
3773
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003774static int s2io_open(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003776 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 int err = 0;
3778
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003779 /*
3780 * Make sure you have link off by default every time
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781 * Nic is initialized
3782 */
3783 netif_carrier_off(dev);
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003784 sp->last_link_state = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785
3786 /* Initialize H/W and enable interrupts */
Ananda Rajuc92ca042006-04-21 19:18:03 -04003787 err = s2io_card_up(sp);
3788 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
3790 dev->name);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003791 goto hw_init_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 }
3793
3794 if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
3795 DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003796 s2io_card_down(sp);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003797 err = -ENODEV;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003798 goto hw_init_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 }
3800
3801 netif_start_queue(dev);
3802 return 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003803
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003804hw_init_failed:
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003805 if (sp->intr_type == MSI_X) {
3806 if (sp->entries)
3807 kfree(sp->entries);
3808 if (sp->s2io_entries)
3809 kfree(sp->s2io_entries);
3810 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003811 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812}
3813
3814/**
3815 * s2io_close -close entry point of the driver
3816 * @dev : device pointer.
3817 * Description:
3818 * This is the stop entry point of the driver. It needs to undo exactly
3819 * whatever was done by the open entry point,thus it's usually referred to
3820 * as the close function.Among other things this function mainly stops the
3821 * Rx side of the NIC and frees all the Rx buffers in the Rx rings.
3822 * Return value:
3823 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3824 * file on failure.
3825 */
3826
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003827static int s2io_close(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003829 struct s2io_nic *sp = dev->priv;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003830
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 netif_stop_queue(dev);
3832 /* Reset card, kill tasklet and free Tx and Rx buffers. */
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003833 s2io_card_down(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 sp->device_close_flag = TRUE; /* Device is shut down. */
3836 return 0;
3837}
3838
3839/**
3840 * s2io_xmit - Tx entry point of te driver
3841 * @skb : the socket buffer containing the Tx data.
3842 * @dev : device pointer.
3843 * Description :
3844 * This function is the Tx entry point of the driver. S2IO NIC supports
3845 * certain protocol assist features on Tx side, namely CSO, S/G, LSO.
3846 * NOTE: when device cant queue the pkt,just the trans_start variable will
3847 * not be upadted.
3848 * Return value:
3849 * 0 on success & 1 on failure.
3850 */
3851
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003852static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003854 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
3856 register u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003857 struct TxD *txdp;
3858 struct TxFIFO_element __iomem *tx_fifo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 unsigned long flags;
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003860 u16 vlan_tag = 0;
3861 int vlan_priority = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003862 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 struct config_param *config;
Ananda Raju75c30b12006-07-24 19:55:09 -04003864 int offload_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865
3866 mac_control = &sp->mac_control;
3867 config = &sp->config;
3868
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003869 DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 spin_lock_irqsave(&sp->tx_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 if (atomic_read(&sp->card_state) == CARD_DOWN) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003872 DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 dev->name);
3874 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003875 dev_kfree_skb(skb);
3876 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 }
3878
3879 queue = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003881 /* Get Fifo number to Transmit based on vlan priority */
3882 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3883 vlan_tag = vlan_tx_tag_get(skb);
3884 vlan_priority = vlan_tag >> 13;
3885 queue = config->fifo_mapping[vlan_priority];
3886 }
3887
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003888 put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
3889 get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003890 txdp = (struct TxD *) mac_control->fifos[queue].list_info[put_off].
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003891 list_virt_addr;
3892
3893 queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04003895 if (txdp->Host_Control ||
3896 ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003897 DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 netif_stop_queue(dev);
3899 dev_kfree_skb(skb);
3900 spin_unlock_irqrestore(&sp->tx_lock, flags);
3901 return 0;
3902 }
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003903
3904 /* A buffer with no data will be dropped */
3905 if (!skb->len) {
3906 DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
3907 dev_kfree_skb(skb);
3908 spin_unlock_irqrestore(&sp->tx_lock, flags);
3909 return 0;
3910 }
3911
Ananda Raju75c30b12006-07-24 19:55:09 -04003912 offload_type = s2io_offload_type(skb);
Ananda Raju75c30b12006-07-24 19:55:09 -04003913 if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 txdp->Control_1 |= TXD_TCP_LSO_EN;
Ananda Raju75c30b12006-07-24 19:55:09 -04003915 txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 }
Patrick McHardy84fa7932006-08-29 16:44:56 -07003917 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 txdp->Control_2 |=
3919 (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
3920 TXD_TX_CKO_UDP_EN);
3921 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003922 txdp->Control_1 |= TXD_GATHER_CODE_FIRST;
3923 txdp->Control_1 |= TXD_LIST_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 txdp->Control_2 |= config->tx_intr_type;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07003925
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003926 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3927 txdp->Control_2 |= TXD_VLAN_ENABLE;
3928 txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
3929 }
3930
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003931 frg_len = skb->len - skb->data_len;
Ananda Raju75c30b12006-07-24 19:55:09 -04003932 if (offload_type == SKB_GSO_UDP) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003933 int ufo_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934
Ananda Raju75c30b12006-07-24 19:55:09 -04003935 ufo_size = s2io_udp_mss(skb);
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003936 ufo_size &= ~7;
3937 txdp->Control_1 |= TXD_UFO_EN;
3938 txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
3939 txdp->Control_1 |= TXD_BUFFER0_SIZE(8);
3940#ifdef __BIG_ENDIAN
3941 sp->ufo_in_band_v[put_off] =
3942 (u64)skb_shinfo(skb)->ip6_frag_id;
3943#else
3944 sp->ufo_in_band_v[put_off] =
3945 (u64)skb_shinfo(skb)->ip6_frag_id << 32;
3946#endif
3947 txdp->Host_Control = (unsigned long)sp->ufo_in_band_v;
3948 txdp->Buffer_Pointer = pci_map_single(sp->pdev,
3949 sp->ufo_in_band_v,
3950 sizeof(u64), PCI_DMA_TODEVICE);
3951 txdp++;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003952 }
3953
3954 txdp->Buffer_Pointer = pci_map_single
3955 (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
3956 txdp->Host_Control = (unsigned long) skb;
3957 txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
Ananda Raju75c30b12006-07-24 19:55:09 -04003958 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003959 txdp->Control_1 |= TXD_UFO_EN;
3960
3961 frg_cnt = skb_shinfo(skb)->nr_frags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 /* For fragmented SKB. */
3963 for (i = 0; i < frg_cnt; i++) {
3964 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003965 /* A '0' length fragment will be ignored */
3966 if (!frag->size)
3967 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 txdp++;
3969 txdp->Buffer_Pointer = (u64) pci_map_page
3970 (sp->pdev, frag->page, frag->page_offset,
3971 frag->size, PCI_DMA_TODEVICE);
Ananda Rajuefd51b52006-01-19 14:11:54 -05003972 txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
Ananda Raju75c30b12006-07-24 19:55:09 -04003973 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003974 txdp->Control_1 |= TXD_UFO_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 }
3976 txdp->Control_1 |= TXD_GATHER_CODE_LAST;
3977
Ananda Raju75c30b12006-07-24 19:55:09 -04003978 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003979 frg_cnt++; /* as Txd0 was used for inband header */
3980
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 tx_fifo = mac_control->tx_FIFO_start[queue];
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003982 val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 writeq(val64, &tx_fifo->TxDL_Pointer);
3984
3985 val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
3986 TX_FIFO_LAST_LIST);
Ananda Raju75c30b12006-07-24 19:55:09 -04003987 if (offload_type)
3988 val64 |= TX_FIFO_SPECIAL_FUNC;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003989
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 writeq(val64, &tx_fifo->List_Control);
3991
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003992 mmiowb();
3993
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 put_off++;
Ananda Raju863c11a2006-04-21 19:03:13 -04003995 if (put_off == mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1)
3996 put_off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003997 mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998
3999 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04004000 if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04004001 sp->mac_control.stats_info->sw_stat.fifo_full_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 DBG_PRINT(TX_DBG,
4003 "No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
4004 put_off, get_off);
4005 netif_stop_queue(dev);
4006 }
4007
4008 dev->trans_start = jiffies;
4009 spin_unlock_irqrestore(&sp->tx_lock, flags);
4010
4011 return 0;
4012}
4013
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07004014static void
4015s2io_alarm_handle(unsigned long data)
4016{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004017 struct s2io_nic *sp = (struct s2io_nic *)data;
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07004018
4019 alarm_intr_handler(sp);
4020 mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
4021}
4022
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004023static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
Ananda Raju75c30b12006-07-24 19:55:09 -04004024{
4025 int rxb_size, level;
4026
4027 if (!sp->lro) {
4028 rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
4029 level = rx_buffer_level(sp, rxb_size, rng_n);
4030
4031 if ((level == PANIC) && (!TASKLET_IN_USE)) {
4032 int ret;
4033 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
4034 DBG_PRINT(INTR_DBG, "PANIC levels\n");
4035 if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08004036 DBG_PRINT(INFO_DBG, "Out of memory in %s",
Ananda Raju75c30b12006-07-24 19:55:09 -04004037 __FUNCTION__);
4038 clear_bit(0, (&sp->tasklet_status));
4039 return -1;
4040 }
4041 clear_bit(0, (&sp->tasklet_status));
4042 } else if (level == LOW)
4043 tasklet_schedule(&sp->task);
4044
4045 } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08004046 DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
4047 DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
Ananda Raju75c30b12006-07-24 19:55:09 -04004048 }
4049 return 0;
4050}
4051
David Howells7d12e782006-10-05 14:55:46 +01004052static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004053{
4054 struct net_device *dev = (struct net_device *) dev_id;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004055 struct s2io_nic *sp = dev->priv;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004056 int i;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004057 struct mac_info *mac_control;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004058 struct config_param *config;
4059
4060 atomic_inc(&sp->isr_cnt);
4061 mac_control = &sp->mac_control;
4062 config = &sp->config;
4063 DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__);
4064
4065 /* If Intr is because of Rx Traffic */
4066 for (i = 0; i < config->rx_ring_num; i++)
4067 rx_intr_handler(&mac_control->rings[i]);
4068
4069 /* If Intr is because of Tx Traffic */
4070 for (i = 0; i < config->tx_fifo_num; i++)
4071 tx_intr_handler(&mac_control->fifos[i]);
4072
4073 /*
4074 * If the Rx buffer count is below the panic threshold then
4075 * reallocate the buffers from the interrupt handler itself,
4076 * else schedule a tasklet to reallocate the buffers.
4077 */
Ananda Raju75c30b12006-07-24 19:55:09 -04004078 for (i = 0; i < config->rx_ring_num; i++)
4079 s2io_chk_rx_buffers(sp, i);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004080
4081 atomic_dec(&sp->isr_cnt);
4082 return IRQ_HANDLED;
4083}
4084
David Howells7d12e782006-10-05 14:55:46 +01004085static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004086{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004087 struct ring_info *ring = (struct ring_info *)dev_id;
4088 struct s2io_nic *sp = ring->nic;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004089
4090 atomic_inc(&sp->isr_cnt);
Ananda Raju75c30b12006-07-24 19:55:09 -04004091
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004092 rx_intr_handler(ring);
Ananda Raju75c30b12006-07-24 19:55:09 -04004093 s2io_chk_rx_buffers(sp, ring->ring_no);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004094
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004095 atomic_dec(&sp->isr_cnt);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004096 return IRQ_HANDLED;
4097}
4098
David Howells7d12e782006-10-05 14:55:46 +01004099static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004100{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004101 struct fifo_info *fifo = (struct fifo_info *)dev_id;
4102 struct s2io_nic *sp = fifo->nic;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004103
4104 atomic_inc(&sp->isr_cnt);
4105 tx_intr_handler(fifo);
4106 atomic_dec(&sp->isr_cnt);
4107 return IRQ_HANDLED;
4108}
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004109static void s2io_txpic_intr_handle(struct s2io_nic *sp)
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004110{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004111 struct XENA_dev_config __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004112 u64 val64;
4113
4114 val64 = readq(&bar0->pic_int_status);
4115 if (val64 & PIC_INT_GPIO) {
4116 val64 = readq(&bar0->gpio_int_reg);
4117 if ((val64 & GPIO_INT_REG_LINK_DOWN) &&
4118 (val64 & GPIO_INT_REG_LINK_UP)) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04004119 /*
4120 * This is unstable state so clear both up/down
4121 * interrupt and adapter to re-evaluate the link state.
4122 */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004123 val64 |= GPIO_INT_REG_LINK_DOWN;
4124 val64 |= GPIO_INT_REG_LINK_UP;
4125 writeq(val64, &bar0->gpio_int_reg);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004126 val64 = readq(&bar0->gpio_int_mask);
4127 val64 &= ~(GPIO_INT_MASK_LINK_UP |
4128 GPIO_INT_MASK_LINK_DOWN);
4129 writeq(val64, &bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004130 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04004131 else if (val64 & GPIO_INT_REG_LINK_UP) {
4132 val64 = readq(&bar0->adapter_status);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004133 /* Enable Adapter */
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004134 val64 = readq(&bar0->adapter_control);
4135 val64 |= ADAPTER_CNTL_EN;
4136 writeq(val64, &bar0->adapter_control);
4137 val64 |= ADAPTER_LED_ON;
4138 writeq(val64, &bar0->adapter_control);
4139 if (!sp->device_enabled_once)
4140 sp->device_enabled_once = 1;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004141
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004142 s2io_link(sp, LINK_UP);
4143 /*
4144 * unmask link down interrupt and mask link-up
4145 * intr
4146 */
4147 val64 = readq(&bar0->gpio_int_mask);
4148 val64 &= ~GPIO_INT_MASK_LINK_DOWN;
4149 val64 |= GPIO_INT_MASK_LINK_UP;
4150 writeq(val64, &bar0->gpio_int_mask);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004151
Ananda Rajuc92ca042006-04-21 19:18:03 -04004152 }else if (val64 & GPIO_INT_REG_LINK_DOWN) {
4153 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004154 s2io_link(sp, LINK_DOWN);
4155 /* Link is down so unmaks link up interrupt */
4156 val64 = readq(&bar0->gpio_int_mask);
4157 val64 &= ~GPIO_INT_MASK_LINK_UP;
4158 val64 |= GPIO_INT_MASK_LINK_DOWN;
4159 writeq(val64, &bar0->gpio_int_mask);
Sivakumar Subramaniac1f90d2007-02-24 02:01:31 -05004160
4161 /* turn off LED */
4162 val64 = readq(&bar0->adapter_control);
4163 val64 = val64 &(~ADAPTER_LED_ON);
4164 writeq(val64, &bar0->adapter_control);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004165 }
4166 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04004167 val64 = readq(&bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004168}
4169
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170/**
4171 * s2io_isr - ISR handler of the device .
4172 * @irq: the irq of the device.
4173 * @dev_id: a void pointer to the dev structure of the NIC.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004174 * Description: This function is the ISR handler of the device. It
4175 * identifies the reason for the interrupt and calls the relevant
4176 * service routines. As a contongency measure, this ISR allocates the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 * recv buffers, if their numbers are below the panic value which is
4178 * presently set to 25% of the original number of rcv buffers allocated.
4179 * Return value:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004180 * IRQ_HANDLED: will be returned if IRQ was handled by this routine
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 * IRQ_NONE: will be returned if interrupt is not from our device
4182 */
David Howells7d12e782006-10-05 14:55:46 +01004183static irqreturn_t s2io_isr(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184{
4185 struct net_device *dev = (struct net_device *) dev_id;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004186 struct s2io_nic *sp = dev->priv;
4187 struct XENA_dev_config __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004188 int i;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004189 u64 reason = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004190 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 struct config_param *config;
4192
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004193 atomic_inc(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 mac_control = &sp->mac_control;
4195 config = &sp->config;
4196
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004197 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 * Identify the cause for interrupt and call the appropriate
4199 * interrupt handler. Causes for the interrupt could be;
4200 * 1. Rx of packet.
4201 * 2. Tx complete.
4202 * 3. Link down.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004203 * 4. Error in any functional blocks of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 */
4205 reason = readq(&bar0->general_int_status);
4206
4207 if (!reason) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004208 /* The interrupt was not raised by us. */
4209 atomic_dec(&sp->isr_cnt);
4210 return IRQ_NONE;
4211 }
4212 else if (unlikely(reason == S2IO_MINUS_ONE) ) {
4213 /* Disable device and get out */
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004214 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 return IRQ_NONE;
4216 }
4217
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004218 if (napi) {
4219 if (reason & GEN_INTR_RXTRAFFIC) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004220 if ( likely ( netif_rx_schedule_prep(dev)) ) {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004221 __netif_rx_schedule(dev);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004222 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004223 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004224 else
4225 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004226 }
4227 } else {
4228 /*
4229 * Rx handler is called by default, without checking for the
4230 * cause of interrupt.
4231 * rx_traffic_int reg is an R1 register, writing all 1's
4232 * will ensure that the actual interrupt causing bit get's
4233 * cleared and hence a read can be avoided.
4234 */
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004235 if (reason & GEN_INTR_RXTRAFFIC)
4236 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
4237
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004238 for (i = 0; i < config->rx_ring_num; i++) {
4239 rx_intr_handler(&mac_control->rings[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 }
4241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242
Ananda Raju863c11a2006-04-21 19:03:13 -04004243 /*
4244 * tx_traffic_int reg is an R1 register, writing all 1's
4245 * will ensure that the actual interrupt causing bit get's
4246 * cleared and hence a read can be avoided.
4247 */
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004248 if (reason & GEN_INTR_TXTRAFFIC)
4249 writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -07004250
Ananda Raju863c11a2006-04-21 19:03:13 -04004251 for (i = 0; i < config->tx_fifo_num; i++)
4252 tx_intr_handler(&mac_control->fifos[i]);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004253
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004254 if (reason & GEN_INTR_TXPIC)
4255 s2io_txpic_intr_handle(sp);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004256 /*
4257 * If the Rx buffer count is below the panic threshold then
4258 * reallocate the buffers from the interrupt handler itself,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 * else schedule a tasklet to reallocate the buffers.
4260 */
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004261 if (!napi) {
4262 for (i = 0; i < config->rx_ring_num; i++)
4263 s2io_chk_rx_buffers(sp, i);
4264 }
4265
4266 writeq(0, &bar0->general_int_mask);
4267 readl(&bar0->general_int_status);
4268
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004269 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 return IRQ_HANDLED;
4271}
4272
4273/**
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004274 * s2io_updt_stats -
4275 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004276static void s2io_updt_stats(struct s2io_nic *sp)
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004277{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004278 struct XENA_dev_config __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004279 u64 val64;
4280 int cnt = 0;
4281
4282 if (atomic_read(&sp->card_state) == CARD_UP) {
4283 /* Apprx 30us on a 133 MHz bus */
4284 val64 = SET_UPDT_CLICKS(10) |
4285 STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
4286 writeq(val64, &bar0->stat_cfg);
4287 do {
4288 udelay(100);
4289 val64 = readq(&bar0->stat_cfg);
4290 if (!(val64 & BIT(0)))
4291 break;
4292 cnt++;
4293 if (cnt == 5)
4294 break; /* Updt failed */
4295 } while(1);
Ramkrishna Vepa363dc362007-03-06 17:01:00 -08004296 }
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004297}
4298
4299/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004300 * s2io_get_stats - Updates the device statistics structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 * @dev : pointer to the device structure.
4302 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004303 * This function updates the device statistics structure in the s2io_nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 * structure and returns a pointer to the same.
4305 * Return value:
4306 * pointer to the updated net_device_stats structure.
4307 */
4308
Adrian Bunkac1f60d2005-11-06 01:46:47 +01004309static struct net_device_stats *s2io_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004311 struct s2io_nic *sp = dev->priv;
4312 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 struct config_param *config;
4314
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004315
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 mac_control = &sp->mac_control;
4317 config = &sp->config;
4318
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004319 /* Configure Stats for immediate updt */
4320 s2io_updt_stats(sp);
4321
4322 sp->stats.tx_packets =
4323 le32_to_cpu(mac_control->stats_info->tmac_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004324 sp->stats.tx_errors =
4325 le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
4326 sp->stats.rx_errors =
Al Viroee705db2006-09-23 01:28:17 +01004327 le64_to_cpu(mac_control->stats_info->rmac_drop_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004328 sp->stats.multicast =
4329 le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 sp->stats.rx_length_errors =
Al Viroee705db2006-09-23 01:28:17 +01004331 le64_to_cpu(mac_control->stats_info->rmac_long_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332
4333 return (&sp->stats);
4334}
4335
4336/**
4337 * s2io_set_multicast - entry point for multicast address enable/disable.
4338 * @dev : pointer to the device structure
4339 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004340 * This function is a driver entry point which gets called by the kernel
4341 * whenever multicast addresses must be enabled/disabled. This also gets
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 * called to set/reset promiscuous mode. Depending on the deivce flag, we
4343 * determine, if multicast address must be enabled or if promiscuous mode
4344 * is to be disabled etc.
4345 * Return value:
4346 * void.
4347 */
4348
4349static void s2io_set_multicast(struct net_device *dev)
4350{
4351 int i, j, prev_cnt;
4352 struct dev_mc_list *mclist;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004353 struct s2io_nic *sp = dev->priv;
4354 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
4356 0xfeffffffffffULL;
4357 u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
4358 void __iomem *add;
4359
4360 if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) {
4361 /* Enable all Multicast addresses */
4362 writeq(RMAC_ADDR_DATA0_MEM_ADDR(multi_mac),
4363 &bar0->rmac_addr_data0_mem);
4364 writeq(RMAC_ADDR_DATA1_MEM_MASK(mask),
4365 &bar0->rmac_addr_data1_mem);
4366 val64 = RMAC_ADDR_CMD_MEM_WE |
4367 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4368 RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
4369 writeq(val64, &bar0->rmac_addr_cmd_mem);
4370 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004371 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004372 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
4373 S2IO_BIT_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374
4375 sp->m_cast_flg = 1;
4376 sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
4377 } else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) {
4378 /* Disable all Multicast addresses */
4379 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4380 &bar0->rmac_addr_data0_mem);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07004381 writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0),
4382 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 val64 = RMAC_ADDR_CMD_MEM_WE |
4384 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4385 RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos);
4386 writeq(val64, &bar0->rmac_addr_cmd_mem);
4387 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004388 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004389 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
4390 S2IO_BIT_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391
4392 sp->m_cast_flg = 0;
4393 sp->all_multi_pos = 0;
4394 }
4395
4396 if ((dev->flags & IFF_PROMISC) && (!sp->promisc_flg)) {
4397 /* Put the NIC into promiscuous mode */
4398 add = &bar0->mac_cfg;
4399 val64 = readq(&bar0->mac_cfg);
4400 val64 |= MAC_CFG_RMAC_PROM_ENABLE;
4401
4402 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4403 writel((u32) val64, add);
4404 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4405 writel((u32) (val64 >> 32), (add + 4));
4406
Sivakumar Subramani926930b2007-02-24 01:59:39 -05004407 if (vlan_tag_strip != 1) {
4408 val64 = readq(&bar0->rx_pa_cfg);
4409 val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG;
4410 writeq(val64, &bar0->rx_pa_cfg);
4411 vlan_strip_flag = 0;
4412 }
4413
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 val64 = readq(&bar0->mac_cfg);
4415 sp->promisc_flg = 1;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004416 DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 dev->name);
4418 } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) {
4419 /* Remove the NIC from promiscuous mode */
4420 add = &bar0->mac_cfg;
4421 val64 = readq(&bar0->mac_cfg);
4422 val64 &= ~MAC_CFG_RMAC_PROM_ENABLE;
4423
4424 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4425 writel((u32) val64, add);
4426 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4427 writel((u32) (val64 >> 32), (add + 4));
4428
Sivakumar Subramani926930b2007-02-24 01:59:39 -05004429 if (vlan_tag_strip != 0) {
4430 val64 = readq(&bar0->rx_pa_cfg);
4431 val64 |= RX_PA_CFG_STRIP_VLAN_TAG;
4432 writeq(val64, &bar0->rx_pa_cfg);
4433 vlan_strip_flag = 1;
4434 }
4435
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 val64 = readq(&bar0->mac_cfg);
4437 sp->promisc_flg = 0;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004438 DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 dev->name);
4440 }
4441
4442 /* Update individual M_CAST address list */
4443 if ((!sp->m_cast_flg) && dev->mc_count) {
4444 if (dev->mc_count >
4445 (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) {
4446 DBG_PRINT(ERR_DBG, "%s: No more Rx filters ",
4447 dev->name);
4448 DBG_PRINT(ERR_DBG, "can be added, please enable ");
4449 DBG_PRINT(ERR_DBG, "ALL_MULTI instead\n");
4450 return;
4451 }
4452
4453 prev_cnt = sp->mc_addr_count;
4454 sp->mc_addr_count = dev->mc_count;
4455
4456 /* Clear out the previous list of Mc in the H/W. */
4457 for (i = 0; i < prev_cnt; i++) {
4458 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4459 &bar0->rmac_addr_data0_mem);
4460 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004461 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 val64 = RMAC_ADDR_CMD_MEM_WE |
4463 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4464 RMAC_ADDR_CMD_MEM_OFFSET
4465 (MAC_MC_ADDR_START_OFFSET + i);
4466 writeq(val64, &bar0->rmac_addr_cmd_mem);
4467
4468 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004469 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004470 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
4471 S2IO_BIT_RESET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 DBG_PRINT(ERR_DBG, "%s: Adding ",
4473 dev->name);
4474 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4475 return;
4476 }
4477 }
4478
4479 /* Create the new Rx filter list and update the same in H/W. */
4480 for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
4481 i++, mclist = mclist->next) {
4482 memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr,
4483 ETH_ALEN);
Jeff Garzika7a80d52006-03-04 12:06:51 -05004484 mac_addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 for (j = 0; j < ETH_ALEN; j++) {
4486 mac_addr |= mclist->dmi_addr[j];
4487 mac_addr <<= 8;
4488 }
4489 mac_addr >>= 8;
4490 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4491 &bar0->rmac_addr_data0_mem);
4492 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004493 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 val64 = RMAC_ADDR_CMD_MEM_WE |
4495 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4496 RMAC_ADDR_CMD_MEM_OFFSET
4497 (i + MAC_MC_ADDR_START_OFFSET);
4498 writeq(val64, &bar0->rmac_addr_cmd_mem);
4499
4500 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004501 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004502 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
4503 S2IO_BIT_RESET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 DBG_PRINT(ERR_DBG, "%s: Adding ",
4505 dev->name);
4506 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4507 return;
4508 }
4509 }
4510 }
4511}
4512
4513/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004514 * s2io_set_mac_addr - Programs the Xframe mac address
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 * @dev : pointer to the device structure.
4516 * @addr: a uchar pointer to the new mac address which is to be set.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004517 * Description : This procedure will program the Xframe to receive
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 * frames with new Mac Address
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004519 * Return value: SUCCESS on success and an appropriate (-)ve integer
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 * as defined in errno.h file on failure.
4521 */
4522
Adrian Bunk26df54b2006-01-14 03:09:40 +01004523static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004525 struct s2io_nic *sp = dev->priv;
4526 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 register u64 val64, mac_addr = 0;
4528 int i;
Sivakumar Subramanid8d70ca2007-02-24 02:04:24 -05004529 u64 old_mac_addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004531 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 * Set the new MAC address as the new unicast filter and reflect this
4533 * change on the device address registered with the OS. It will be
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004534 * at offset 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 */
4536 for (i = 0; i < ETH_ALEN; i++) {
4537 mac_addr <<= 8;
4538 mac_addr |= addr[i];
Sivakumar Subramanid8d70ca2007-02-24 02:04:24 -05004539 old_mac_addr <<= 8;
4540 old_mac_addr |= sp->def_mac_addr[0].mac_addr[i];
4541 }
4542
4543 if(0 == mac_addr)
4544 return SUCCESS;
4545
4546 /* Update the internal structure with this new mac address */
4547 if(mac_addr != old_mac_addr) {
4548 memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
4549 sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_addr);
4550 sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_addr >> 8);
4551 sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_addr >> 16);
4552 sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_addr >> 24);
4553 sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_addr >> 32);
4554 sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_addr >> 40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 }
4556
4557 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4558 &bar0->rmac_addr_data0_mem);
4559
4560 val64 =
4561 RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4562 RMAC_ADDR_CMD_MEM_OFFSET(0);
4563 writeq(val64, &bar0->rmac_addr_cmd_mem);
4564 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004565 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004566 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
4568 return FAILURE;
4569 }
4570
4571 return SUCCESS;
4572}
4573
4574/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004575 * s2io_ethtool_sset - Sets different link parameters.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure.
4577 * @info: pointer to the structure with parameters given by ethtool to set
4578 * link information.
4579 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004580 * The function sets different link parameters provided by the user onto
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 * the NIC.
4582 * Return value:
4583 * 0 on success.
4584*/
4585
4586static int s2io_ethtool_sset(struct net_device *dev,
4587 struct ethtool_cmd *info)
4588{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004589 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 if ((info->autoneg == AUTONEG_ENABLE) ||
4591 (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
4592 return -EINVAL;
4593 else {
4594 s2io_close(sp->dev);
4595 s2io_open(sp->dev);
4596 }
4597
4598 return 0;
4599}
4600
4601/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004602 * s2io_ethtol_gset - Return link specific information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 * @sp : private member of the device structure, pointer to the
4604 * s2io_nic structure.
4605 * @info : pointer to the structure with parameters given by ethtool
4606 * to return link information.
4607 * Description:
4608 * Returns link specific information like speed, duplex etc.. to ethtool.
4609 * Return value :
4610 * return 0 on success.
4611 */
4612
4613static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
4614{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004615 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4617 info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4618 info->port = PORT_FIBRE;
4619 /* info->transceiver?? TODO */
4620
4621 if (netif_carrier_ok(sp->dev)) {
4622 info->speed = 10000;
4623 info->duplex = DUPLEX_FULL;
4624 } else {
4625 info->speed = -1;
4626 info->duplex = -1;
4627 }
4628
4629 info->autoneg = AUTONEG_DISABLE;
4630 return 0;
4631}
4632
4633/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004634 * s2io_ethtool_gdrvinfo - Returns driver specific information.
4635 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 * s2io_nic structure.
4637 * @info : pointer to the structure with parameters given by ethtool to
4638 * return driver information.
4639 * Description:
4640 * Returns driver specefic information like name, version etc.. to ethtool.
4641 * Return value:
4642 * void
4643 */
4644
4645static void s2io_ethtool_gdrvinfo(struct net_device *dev,
4646 struct ethtool_drvinfo *info)
4647{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004648 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649
John W. Linvilledbc23092005-09-28 17:50:51 -04004650 strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
4651 strncpy(info->version, s2io_driver_version, sizeof(info->version));
4652 strncpy(info->fw_version, "", sizeof(info->fw_version));
4653 strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 info->regdump_len = XENA_REG_SPACE;
4655 info->eedump_len = XENA_EEPROM_SPACE;
4656 info->testinfo_len = S2IO_TEST_LEN;
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -05004657
4658 if (sp->device_type == XFRAME_I_DEVICE)
4659 info->n_stats = XFRAME_I_STAT_LEN;
4660 else
4661 info->n_stats = XFRAME_II_STAT_LEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662}
4663
4664/**
4665 * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004666 * @sp: private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004668 * @regs : pointer to the structure with parameters given by ethtool for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 * dumping the registers.
4670 * @reg_space: The input argumnet into which all the registers are dumped.
4671 * Description:
4672 * Dumps the entire register space of xFrame NIC into the user given
4673 * buffer area.
4674 * Return value :
4675 * void .
4676*/
4677
4678static void s2io_ethtool_gregs(struct net_device *dev,
4679 struct ethtool_regs *regs, void *space)
4680{
4681 int i;
4682 u64 reg;
4683 u8 *reg_space = (u8 *) space;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004684 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685
4686 regs->len = XENA_REG_SPACE;
4687 regs->version = sp->pdev->subsystem_device;
4688
4689 for (i = 0; i < regs->len; i += 8) {
4690 reg = readq(sp->bar0 + i);
4691 memcpy((reg_space + i), &reg, 8);
4692 }
4693}
4694
4695/**
4696 * s2io_phy_id - timer function that alternates adapter LED.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004697 * @data : address of the private member of the device structure, which
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 * is a pointer to the s2io_nic structure, provided as an u32.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004699 * Description: This is actually the timer function that alternates the
4700 * adapter LED bit of the adapter control bit to set/reset every time on
4701 * invocation. The timer is set for 1/2 a second, hence tha NIC blinks
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 * once every second.
4703*/
4704static void s2io_phy_id(unsigned long data)
4705{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004706 struct s2io_nic *sp = (struct s2io_nic *) data;
4707 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 u64 val64 = 0;
4709 u16 subid;
4710
4711 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004712 if ((sp->device_type == XFRAME_II_DEVICE) ||
4713 ((subid & 0xFF) >= 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 val64 = readq(&bar0->gpio_control);
4715 val64 ^= GPIO_CTRL_GPIO_0;
4716 writeq(val64, &bar0->gpio_control);
4717 } else {
4718 val64 = readq(&bar0->adapter_control);
4719 val64 ^= ADAPTER_LED_ON;
4720 writeq(val64, &bar0->adapter_control);
4721 }
4722
4723 mod_timer(&sp->id_timer, jiffies + HZ / 2);
4724}
4725
4726/**
4727 * s2io_ethtool_idnic - To physically identify the nic on the system.
4728 * @sp : private member of the device structure, which is a pointer to the
4729 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004730 * @id : pointer to the structure with identification parameters given by
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 * ethtool.
4732 * Description: Used to physically identify the NIC on the system.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004733 * The Link LED will blink for a time specified by the user for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 * identification.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004735 * NOTE: The Link has to be Up to be able to blink the LED. Hence
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 * identification is possible only if it's link is up.
4737 * Return value:
4738 * int , returns 0 on success
4739 */
4740
4741static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
4742{
4743 u64 val64 = 0, last_gpio_ctrl_val;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004744 struct s2io_nic *sp = dev->priv;
4745 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 u16 subid;
4747
4748 subid = sp->pdev->subsystem_device;
4749 last_gpio_ctrl_val = readq(&bar0->gpio_control);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004750 if ((sp->device_type == XFRAME_I_DEVICE) &&
4751 ((subid & 0xFF) < 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 val64 = readq(&bar0->adapter_control);
4753 if (!(val64 & ADAPTER_CNTL_EN)) {
4754 printk(KERN_ERR
4755 "Adapter Link down, cannot blink LED\n");
4756 return -EFAULT;
4757 }
4758 }
4759 if (sp->id_timer.function == NULL) {
4760 init_timer(&sp->id_timer);
4761 sp->id_timer.function = s2io_phy_id;
4762 sp->id_timer.data = (unsigned long) sp;
4763 }
4764 mod_timer(&sp->id_timer, jiffies);
4765 if (data)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004766 msleep_interruptible(data * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004768 msleep_interruptible(MAX_FLICKER_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 del_timer_sync(&sp->id_timer);
4770
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004771 if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 writeq(last_gpio_ctrl_val, &bar0->gpio_control);
4773 last_gpio_ctrl_val = readq(&bar0->gpio_control);
4774 }
4775
4776 return 0;
4777}
4778
4779/**
4780 * s2io_ethtool_getpause_data -Pause frame frame generation and reception.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004781 * @sp : private member of the device structure, which is a pointer to the
4782 * s2io_nic structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 * @ep : pointer to the structure with pause parameters given by ethtool.
4784 * Description:
4785 * Returns the Pause frame generation and reception capability of the NIC.
4786 * Return value:
4787 * void
4788 */
4789static void s2io_ethtool_getpause_data(struct net_device *dev,
4790 struct ethtool_pauseparam *ep)
4791{
4792 u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004793 struct s2io_nic *sp = dev->priv;
4794 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795
4796 val64 = readq(&bar0->rmac_pause_cfg);
4797 if (val64 & RMAC_PAUSE_GEN_ENABLE)
4798 ep->tx_pause = TRUE;
4799 if (val64 & RMAC_PAUSE_RX_ENABLE)
4800 ep->rx_pause = TRUE;
4801 ep->autoneg = FALSE;
4802}
4803
4804/**
4805 * s2io_ethtool_setpause_data - set/reset pause frame generation.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004806 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 * s2io_nic structure.
4808 * @ep : pointer to the structure with pause parameters given by ethtool.
4809 * Description:
4810 * It can be used to set or reset Pause frame generation or reception
4811 * support of the NIC.
4812 * Return value:
4813 * int, returns 0 on Success
4814 */
4815
4816static int s2io_ethtool_setpause_data(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004817 struct ethtool_pauseparam *ep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818{
4819 u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004820 struct s2io_nic *sp = dev->priv;
4821 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822
4823 val64 = readq(&bar0->rmac_pause_cfg);
4824 if (ep->tx_pause)
4825 val64 |= RMAC_PAUSE_GEN_ENABLE;
4826 else
4827 val64 &= ~RMAC_PAUSE_GEN_ENABLE;
4828 if (ep->rx_pause)
4829 val64 |= RMAC_PAUSE_RX_ENABLE;
4830 else
4831 val64 &= ~RMAC_PAUSE_RX_ENABLE;
4832 writeq(val64, &bar0->rmac_pause_cfg);
4833 return 0;
4834}
4835
4836/**
4837 * read_eeprom - reads 4 bytes of data from user given offset.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004838 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 * s2io_nic structure.
4840 * @off : offset at which the data must be written
4841 * @data : Its an output parameter where the data read at the given
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004842 * offset is stored.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004844 * Will read 4 bytes of data from the user given offset and return the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 * read data.
4846 * NOTE: Will allow to read only part of the EEPROM visible through the
4847 * I2C bus.
4848 * Return value:
4849 * -1 on failure and 0 on success.
4850 */
4851
4852#define S2IO_DEV_ID 5
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004853static int read_eeprom(struct s2io_nic * sp, int off, u64 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854{
4855 int ret = -1;
4856 u32 exit_cnt = 0;
4857 u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004858 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004860 if (sp->device_type == XFRAME_I_DEVICE) {
4861 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4862 I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ |
4863 I2C_CONTROL_CNTL_START;
4864 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004866 while (exit_cnt < 5) {
4867 val64 = readq(&bar0->i2c_control);
4868 if (I2C_CONTROL_CNTL_END(val64)) {
4869 *data = I2C_CONTROL_GET_DATA(val64);
4870 ret = 0;
4871 break;
4872 }
4873 msleep(50);
4874 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 }
4877
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004878 if (sp->device_type == XFRAME_II_DEVICE) {
4879 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004880 SPI_CONTROL_BYTECNT(0x3) |
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004881 SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off);
4882 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4883 val64 |= SPI_CONTROL_REQ;
4884 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4885 while (exit_cnt < 5) {
4886 val64 = readq(&bar0->spi_control);
4887 if (val64 & SPI_CONTROL_NACK) {
4888 ret = 1;
4889 break;
4890 } else if (val64 & SPI_CONTROL_DONE) {
4891 *data = readq(&bar0->spi_data);
4892 *data &= 0xffffff;
4893 ret = 0;
4894 break;
4895 }
4896 msleep(50);
4897 exit_cnt++;
4898 }
4899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 return ret;
4901}
4902
4903/**
4904 * write_eeprom - actually writes the relevant part of the data value.
4905 * @sp : private member of the device structure, which is a pointer to the
4906 * s2io_nic structure.
4907 * @off : offset at which the data must be written
4908 * @data : The data that is to be written
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004909 * @cnt : Number of bytes of the data that are actually to be written into
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 * the Eeprom. (max of 3)
4911 * Description:
4912 * Actually writes the relevant part of the data value into the Eeprom
4913 * through the I2C bus.
4914 * Return value:
4915 * 0 on success, -1 on failure.
4916 */
4917
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004918static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919{
4920 int exit_cnt = 0, ret = -1;
4921 u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004922 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004924 if (sp->device_type == XFRAME_I_DEVICE) {
4925 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4926 I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) |
4927 I2C_CONTROL_CNTL_START;
4928 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004930 while (exit_cnt < 5) {
4931 val64 = readq(&bar0->i2c_control);
4932 if (I2C_CONTROL_CNTL_END(val64)) {
4933 if (!(val64 & I2C_CONTROL_NACK))
4934 ret = 0;
4935 break;
4936 }
4937 msleep(50);
4938 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940 }
4941
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004942 if (sp->device_type == XFRAME_II_DEVICE) {
4943 int write_cnt = (cnt == 8) ? 0 : cnt;
4944 writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data);
4945
4946 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004947 SPI_CONTROL_BYTECNT(write_cnt) |
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004948 SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off);
4949 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4950 val64 |= SPI_CONTROL_REQ;
4951 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4952 while (exit_cnt < 5) {
4953 val64 = readq(&bar0->spi_control);
4954 if (val64 & SPI_CONTROL_NACK) {
4955 ret = 1;
4956 break;
4957 } else if (val64 & SPI_CONTROL_DONE) {
4958 ret = 0;
4959 break;
4960 }
4961 msleep(50);
4962 exit_cnt++;
4963 }
4964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 return ret;
4966}
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004967static void s2io_vpd_read(struct s2io_nic *nic)
Ananda Raju9dc737a2006-04-21 19:05:41 -04004968{
Ananda Rajub41477f2006-07-24 19:52:49 -04004969 u8 *vpd_data;
4970 u8 data;
Ananda Raju9dc737a2006-04-21 19:05:41 -04004971 int i=0, cnt, fail = 0;
4972 int vpd_addr = 0x80;
4973
4974 if (nic->device_type == XFRAME_II_DEVICE) {
4975 strcpy(nic->product_name, "Xframe II 10GbE network adapter");
4976 vpd_addr = 0x80;
4977 }
4978 else {
4979 strcpy(nic->product_name, "Xframe I 10GbE network adapter");
4980 vpd_addr = 0x50;
4981 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004982 strcpy(nic->serial_num, "NOT AVAILABLE");
Ananda Raju9dc737a2006-04-21 19:05:41 -04004983
Ananda Rajub41477f2006-07-24 19:52:49 -04004984 vpd_data = kmalloc(256, GFP_KERNEL);
4985 if (!vpd_data)
4986 return;
4987
Ananda Raju9dc737a2006-04-21 19:05:41 -04004988 for (i = 0; i < 256; i +=4 ) {
4989 pci_write_config_byte(nic->pdev, (vpd_addr + 2), i);
4990 pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data);
4991 pci_write_config_byte(nic->pdev, (vpd_addr + 3), 0);
4992 for (cnt = 0; cnt <5; cnt++) {
4993 msleep(2);
4994 pci_read_config_byte(nic->pdev, (vpd_addr + 3), &data);
4995 if (data == 0x80)
4996 break;
4997 }
4998 if (cnt >= 5) {
4999 DBG_PRINT(ERR_DBG, "Read of VPD data failed\n");
5000 fail = 1;
5001 break;
5002 }
5003 pci_read_config_dword(nic->pdev, (vpd_addr + 4),
5004 (u32 *)&vpd_data[i]);
5005 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05005006
5007 if(!fail) {
5008 /* read serial number of adapter */
5009 for (cnt = 0; cnt < 256; cnt++) {
5010 if ((vpd_data[cnt] == 'S') &&
5011 (vpd_data[cnt+1] == 'N') &&
5012 (vpd_data[cnt+2] < VPD_STRING_LEN)) {
5013 memset(nic->serial_num, 0, VPD_STRING_LEN);
5014 memcpy(nic->serial_num, &vpd_data[cnt + 3],
5015 vpd_data[cnt+2]);
5016 break;
5017 }
5018 }
5019 }
5020
5021 if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04005022 memset(nic->product_name, 0, vpd_data[1]);
5023 memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
5024 }
Ananda Rajub41477f2006-07-24 19:52:49 -04005025 kfree(vpd_data);
Ananda Raju9dc737a2006-04-21 19:05:41 -04005026}
5027
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028/**
5029 * s2io_ethtool_geeprom - reads the value stored in the Eeprom.
5030 * @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 -07005031 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032 * containing all relevant information.
5033 * @data_buf : user defined value to be written into Eeprom.
5034 * Description: Reads the values stored in the Eeprom at given offset
5035 * for a given length. Stores these values int the input argument data
5036 * buffer 'data_buf' and returns these to the caller (ethtool.)
5037 * Return value:
5038 * int 0 on success
5039 */
5040
5041static int s2io_ethtool_geeprom(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005042 struct ethtool_eeprom *eeprom, u8 * data_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043{
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005044 u32 i, valid;
5045 u64 data;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005046 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047
5048 eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
5049
5050 if ((eeprom->offset + eeprom->len) > (XENA_EEPROM_SPACE))
5051 eeprom->len = XENA_EEPROM_SPACE - eeprom->offset;
5052
5053 for (i = 0; i < eeprom->len; i += 4) {
5054 if (read_eeprom(sp, (eeprom->offset + i), &data)) {
5055 DBG_PRINT(ERR_DBG, "Read of EEPROM failed\n");
5056 return -EFAULT;
5057 }
5058 valid = INV(data);
5059 memcpy((data_buf + i), &valid, 4);
5060 }
5061 return 0;
5062}
5063
5064/**
5065 * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom
5066 * @sp : private member of the device structure, which is a pointer to the
5067 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005068 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 * containing all relevant information.
5070 * @data_buf ; user defined value to be written into Eeprom.
5071 * Description:
5072 * Tries to write the user provided value in the Eeprom, at the offset
5073 * given by the user.
5074 * Return value:
5075 * 0 on success, -EFAULT on failure.
5076 */
5077
5078static int s2io_ethtool_seeprom(struct net_device *dev,
5079 struct ethtool_eeprom *eeprom,
5080 u8 * data_buf)
5081{
5082 int len = eeprom->len, cnt = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005083 u64 valid = 0, data;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005084 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085
5086 if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
5087 DBG_PRINT(ERR_DBG,
5088 "ETHTOOL_WRITE_EEPROM Err: Magic value ");
5089 DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n",
5090 eeprom->magic);
5091 return -EFAULT;
5092 }
5093
5094 while (len) {
5095 data = (u32) data_buf[cnt] & 0x000000FF;
5096 if (data) {
5097 valid = (u32) (data << 24);
5098 } else
5099 valid = data;
5100
5101 if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) {
5102 DBG_PRINT(ERR_DBG,
5103 "ETHTOOL_WRITE_EEPROM Err: Cannot ");
5104 DBG_PRINT(ERR_DBG,
5105 "write into the specified offset\n");
5106 return -EFAULT;
5107 }
5108 cnt++;
5109 len--;
5110 }
5111
5112 return 0;
5113}
5114
5115/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005116 * s2io_register_test - reads and writes into all clock domains.
5117 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118 * s2io_nic structure.
5119 * @data : variable that returns the result of each of the test conducted b
5120 * by the driver.
5121 * Description:
5122 * Read and write into all clock domains. The NIC has 3 clock domains,
5123 * see that registers in all the three regions are accessible.
5124 * Return value:
5125 * 0 on success.
5126 */
5127
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005128static int s2io_register_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005130 struct XENA_dev_config __iomem *bar0 = sp->bar0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005131 u64 val64 = 0, exp_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 int fail = 0;
5133
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005134 val64 = readq(&bar0->pif_rd_swapper_fb);
5135 if (val64 != 0x123456789abcdefULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136 fail = 1;
5137 DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n");
5138 }
5139
5140 val64 = readq(&bar0->rmac_pause_cfg);
5141 if (val64 != 0xc000ffff00000000ULL) {
5142 fail = 1;
5143 DBG_PRINT(INFO_DBG, "Read Test level 2 fails\n");
5144 }
5145
5146 val64 = readq(&bar0->rx_queue_cfg);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005147 if (sp->device_type == XFRAME_II_DEVICE)
5148 exp_val = 0x0404040404040404ULL;
5149 else
5150 exp_val = 0x0808080808080808ULL;
5151 if (val64 != exp_val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 fail = 1;
5153 DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n");
5154 }
5155
5156 val64 = readq(&bar0->xgxs_efifo_cfg);
5157 if (val64 != 0x000000001923141EULL) {
5158 fail = 1;
5159 DBG_PRINT(INFO_DBG, "Read Test level 4 fails\n");
5160 }
5161
5162 val64 = 0x5A5A5A5A5A5A5A5AULL;
5163 writeq(val64, &bar0->xmsi_data);
5164 val64 = readq(&bar0->xmsi_data);
5165 if (val64 != 0x5A5A5A5A5A5A5A5AULL) {
5166 fail = 1;
5167 DBG_PRINT(ERR_DBG, "Write Test level 1 fails\n");
5168 }
5169
5170 val64 = 0xA5A5A5A5A5A5A5A5ULL;
5171 writeq(val64, &bar0->xmsi_data);
5172 val64 = readq(&bar0->xmsi_data);
5173 if (val64 != 0xA5A5A5A5A5A5A5A5ULL) {
5174 fail = 1;
5175 DBG_PRINT(ERR_DBG, "Write Test level 2 fails\n");
5176 }
5177
5178 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005179 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180}
5181
5182/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005183 * s2io_eeprom_test - to verify that EEprom in the xena can be programmed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 * @sp : private member of the device structure, which is a pointer to the
5185 * s2io_nic structure.
5186 * @data:variable that returns the result of each of the test conducted by
5187 * the driver.
5188 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005189 * Verify that EEPROM in the xena can be programmed using I2C_CONTROL
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 * register.
5191 * Return value:
5192 * 0 on success.
5193 */
5194
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005195static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196{
5197 int fail = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005198 u64 ret_data, org_4F0, org_7F0;
5199 u8 saved_4F0 = 0, saved_7F0 = 0;
5200 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201
5202 /* Test Write Error at offset 0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005203 /* Note that SPI interface allows write access to all areas
5204 * of EEPROM. Hence doing all negative testing only for Xframe I.
5205 */
5206 if (sp->device_type == XFRAME_I_DEVICE)
5207 if (!write_eeprom(sp, 0, 0, 3))
5208 fail = 1;
5209
5210 /* Save current values at offsets 0x4F0 and 0x7F0 */
5211 if (!read_eeprom(sp, 0x4F0, &org_4F0))
5212 saved_4F0 = 1;
5213 if (!read_eeprom(sp, 0x7F0, &org_7F0))
5214 saved_7F0 = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215
5216 /* Test Write at offset 4f0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005217 if (write_eeprom(sp, 0x4F0, 0x012345, 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 fail = 1;
5219 if (read_eeprom(sp, 0x4F0, &ret_data))
5220 fail = 1;
5221
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005222 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005223 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. "
5224 "Data written %llx Data read %llx\n",
5225 dev->name, (unsigned long long)0x12345,
5226 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229
5230 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005231 write_eeprom(sp, 0x4F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232
5233 /* Test Write Request Error at offset 0x7c */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005234 if (sp->device_type == XFRAME_I_DEVICE)
5235 if (!write_eeprom(sp, 0x07C, 0, 3))
5236 fail = 1;
5237
5238 /* Test Write Request at offset 0x7f0 */
5239 if (write_eeprom(sp, 0x7F0, 0x012345, 3))
5240 fail = 1;
5241 if (read_eeprom(sp, 0x7F0, &ret_data))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 fail = 1;
5243
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005244 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005245 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. "
5246 "Data written %llx Data read %llx\n",
5247 dev->name, (unsigned long long)0x12345,
5248 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251
5252 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005253 write_eeprom(sp, 0x7F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005255 if (sp->device_type == XFRAME_I_DEVICE) {
5256 /* Test Write Error at offset 0x80 */
5257 if (!write_eeprom(sp, 0x080, 0, 3))
5258 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005260 /* Test Write Error at offset 0xfc */
5261 if (!write_eeprom(sp, 0x0FC, 0, 3))
5262 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005264 /* Test Write Error at offset 0x100 */
5265 if (!write_eeprom(sp, 0x100, 0, 3))
5266 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005268 /* Test Write Error at offset 4ec */
5269 if (!write_eeprom(sp, 0x4EC, 0, 3))
5270 fail = 1;
5271 }
5272
5273 /* Restore values at offsets 0x4F0 and 0x7F0 */
5274 if (saved_4F0)
5275 write_eeprom(sp, 0x4F0, org_4F0, 3);
5276 if (saved_7F0)
5277 write_eeprom(sp, 0x7F0, org_7F0, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278
5279 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005280 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281}
5282
5283/**
5284 * s2io_bist_test - invokes the MemBist test of the card .
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005285 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005287 * @data:variable that returns the result of each of the test conducted by
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 * the driver.
5289 * Description:
5290 * This invokes the MemBist test of the card. We give around
5291 * 2 secs time for the Test to complete. If it's still not complete
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005292 * within this peiod, we consider that the test failed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 * Return value:
5294 * 0 on success and -1 on failure.
5295 */
5296
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005297static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298{
5299 u8 bist = 0;
5300 int cnt = 0, ret = -1;
5301
5302 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5303 bist |= PCI_BIST_START;
5304 pci_write_config_word(sp->pdev, PCI_BIST, bist);
5305
5306 while (cnt < 20) {
5307 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5308 if (!(bist & PCI_BIST_START)) {
5309 *data = (bist & PCI_BIST_CODE_MASK);
5310 ret = 0;
5311 break;
5312 }
5313 msleep(100);
5314 cnt++;
5315 }
5316
5317 return ret;
5318}
5319
5320/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005321 * s2io-link_test - verifies the link state of the nic
5322 * @sp ; private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323 * s2io_nic structure.
5324 * @data: variable that returns the result of each of the test conducted by
5325 * the driver.
5326 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005327 * The function verifies the link state of the NIC and updates the input
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328 * argument 'data' appropriately.
5329 * Return value:
5330 * 0 on success.
5331 */
5332
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005333static int s2io_link_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005335 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336 u64 val64;
5337
5338 val64 = readq(&bar0->adapter_status);
Ananda Rajuc92ca042006-04-21 19:18:03 -04005339 if(!(LINK_IS_UP(val64)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 *data = 1;
Ananda Rajuc92ca042006-04-21 19:18:03 -04005341 else
5342 *data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343
Ananda Rajub41477f2006-07-24 19:52:49 -04005344 return *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345}
5346
5347/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005348 * s2io_rldram_test - offline test for access to the RldRam chip on the NIC
5349 * @sp - private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005350 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005351 * @data - variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 * conducted by the driver.
5353 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005354 * This is one of the offline test that tests the read and write
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 * access to the RldRam chip on the NIC.
5356 * Return value:
5357 * 0 on success.
5358 */
5359
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005360static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005362 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 u64 val64;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005364 int cnt, iteration = 0, test_fail = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365
5366 val64 = readq(&bar0->adapter_control);
5367 val64 &= ~ADAPTER_ECC_EN;
5368 writeq(val64, &bar0->adapter_control);
5369
5370 val64 = readq(&bar0->mc_rldram_test_ctrl);
5371 val64 |= MC_RLDRAM_TEST_MODE;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005372 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373
5374 val64 = readq(&bar0->mc_rldram_mrs);
5375 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE;
5376 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5377
5378 val64 |= MC_RLDRAM_MRS_ENABLE;
5379 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5380
5381 while (iteration < 2) {
5382 val64 = 0x55555555aaaa0000ULL;
5383 if (iteration == 1) {
5384 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5385 }
5386 writeq(val64, &bar0->mc_rldram_test_d0);
5387
5388 val64 = 0xaaaa5a5555550000ULL;
5389 if (iteration == 1) {
5390 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5391 }
5392 writeq(val64, &bar0->mc_rldram_test_d1);
5393
5394 val64 = 0x55aaaaaaaa5a0000ULL;
5395 if (iteration == 1) {
5396 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5397 }
5398 writeq(val64, &bar0->mc_rldram_test_d2);
5399
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005400 val64 = (u64) (0x0000003ffffe0100ULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 writeq(val64, &bar0->mc_rldram_test_add);
5402
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005403 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE |
5404 MC_RLDRAM_TEST_GO;
5405 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406
5407 for (cnt = 0; cnt < 5; cnt++) {
5408 val64 = readq(&bar0->mc_rldram_test_ctrl);
5409 if (val64 & MC_RLDRAM_TEST_DONE)
5410 break;
5411 msleep(200);
5412 }
5413
5414 if (cnt == 5)
5415 break;
5416
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005417 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO;
5418 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419
5420 for (cnt = 0; cnt < 5; cnt++) {
5421 val64 = readq(&bar0->mc_rldram_test_ctrl);
5422 if (val64 & MC_RLDRAM_TEST_DONE)
5423 break;
5424 msleep(500);
5425 }
5426
5427 if (cnt == 5)
5428 break;
5429
5430 val64 = readq(&bar0->mc_rldram_test_ctrl);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005431 if (!(val64 & MC_RLDRAM_TEST_PASS))
5432 test_fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433
5434 iteration++;
5435 }
5436
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005437 *data = test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005439 /* Bring the adapter out of test mode */
5440 SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF);
5441
5442 return test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443}
5444
5445/**
5446 * s2io_ethtool_test - conducts 6 tsets to determine the health of card.
5447 * @sp : private member of the device structure, which is a pointer to the
5448 * s2io_nic structure.
5449 * @ethtest : pointer to a ethtool command specific structure that will be
5450 * returned to the user.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005451 * @data : variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 * conducted by the driver.
5453 * Description:
5454 * This function conducts 6 tests ( 4 offline and 2 online) to determine
5455 * the health of the card.
5456 * Return value:
5457 * void
5458 */
5459
5460static void s2io_ethtool_test(struct net_device *dev,
5461 struct ethtool_test *ethtest,
5462 uint64_t * data)
5463{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005464 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 int orig_state = netif_running(sp->dev);
5466
5467 if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
5468 /* Offline Tests. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005469 if (orig_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 s2io_close(sp->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471
5472 if (s2io_register_test(sp, &data[0]))
5473 ethtest->flags |= ETH_TEST_FL_FAILED;
5474
5475 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476
5477 if (s2io_rldram_test(sp, &data[3]))
5478 ethtest->flags |= ETH_TEST_FL_FAILED;
5479
5480 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481
5482 if (s2io_eeprom_test(sp, &data[1]))
5483 ethtest->flags |= ETH_TEST_FL_FAILED;
5484
5485 if (s2io_bist_test(sp, &data[4]))
5486 ethtest->flags |= ETH_TEST_FL_FAILED;
5487
5488 if (orig_state)
5489 s2io_open(sp->dev);
5490
5491 data[2] = 0;
5492 } else {
5493 /* Online Tests. */
5494 if (!orig_state) {
5495 DBG_PRINT(ERR_DBG,
5496 "%s: is not up, cannot run test\n",
5497 dev->name);
5498 data[0] = -1;
5499 data[1] = -1;
5500 data[2] = -1;
5501 data[3] = -1;
5502 data[4] = -1;
5503 }
5504
5505 if (s2io_link_test(sp, &data[2]))
5506 ethtest->flags |= ETH_TEST_FL_FAILED;
5507
5508 data[0] = 0;
5509 data[1] = 0;
5510 data[3] = 0;
5511 data[4] = 0;
5512 }
5513}
5514
5515static void s2io_get_ethtool_stats(struct net_device *dev,
5516 struct ethtool_stats *estats,
5517 u64 * tmp_stats)
5518{
5519 int i = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005520 struct s2io_nic *sp = dev->priv;
5521 struct stat_block *stat_info = sp->mac_control.stats_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005523 s2io_updt_stats(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005524 tmp_stats[i++] =
5525 (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32 |
5526 le32_to_cpu(stat_info->tmac_frms);
5527 tmp_stats[i++] =
5528 (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 |
5529 le32_to_cpu(stat_info->tmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005531 tmp_stats[i++] =
5532 (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 |
5533 le32_to_cpu(stat_info->tmac_mcst_frms);
5534 tmp_stats[i++] =
5535 (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 |
5536 le32_to_cpu(stat_info->tmac_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005538 tmp_stats[i++] =
5539 (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 |
5540 le32_to_cpu(stat_info->tmac_ttl_octets);
5541 tmp_stats[i++] =
5542 (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 |
5543 le32_to_cpu(stat_info->tmac_ucst_frms);
5544 tmp_stats[i++] =
5545 (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 |
5546 le32_to_cpu(stat_info->tmac_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005547 tmp_stats[i++] =
5548 (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 |
5549 le32_to_cpu(stat_info->tmac_any_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005550 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005552 tmp_stats[i++] =
5553 (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 |
5554 le32_to_cpu(stat_info->tmac_vld_ip);
5555 tmp_stats[i++] =
5556 (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 |
5557 le32_to_cpu(stat_info->tmac_drop_ip);
5558 tmp_stats[i++] =
5559 (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 |
5560 le32_to_cpu(stat_info->tmac_icmp);
5561 tmp_stats[i++] =
5562 (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 |
5563 le32_to_cpu(stat_info->tmac_rst_tcp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005565 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 |
5566 le32_to_cpu(stat_info->tmac_udp);
5567 tmp_stats[i++] =
5568 (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 |
5569 le32_to_cpu(stat_info->rmac_vld_frms);
5570 tmp_stats[i++] =
5571 (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 |
5572 le32_to_cpu(stat_info->rmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms);
5574 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005575 tmp_stats[i++] =
5576 (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 |
5577 le32_to_cpu(stat_info->rmac_vld_mcst_frms);
5578 tmp_stats[i++] =
5579 (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 |
5580 le32_to_cpu(stat_info->rmac_vld_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005582 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_out_rng_len_err_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms);
5584 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005585 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_unsup_ctrl_frms);
5586 tmp_stats[i++] =
5587 (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 |
5588 le32_to_cpu(stat_info->rmac_ttl_octets);
5589 tmp_stats[i++] =
5590 (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow)
5591 << 32 | le32_to_cpu(stat_info->rmac_accepted_ucst_frms);
5592 tmp_stats[i++] =
5593 (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow)
5594 << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005595 tmp_stats[i++] =
5596 (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 |
5597 le32_to_cpu(stat_info->rmac_discarded_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005598 tmp_stats[i++] =
5599 (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow)
5600 << 32 | le32_to_cpu(stat_info->rmac_drop_events);
5601 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets);
5602 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005603 tmp_stats[i++] =
5604 (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 |
5605 le32_to_cpu(stat_info->rmac_usized_frms);
5606 tmp_stats[i++] =
5607 (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 |
5608 le32_to_cpu(stat_info->rmac_osized_frms);
5609 tmp_stats[i++] =
5610 (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 |
5611 le32_to_cpu(stat_info->rmac_frag_frms);
5612 tmp_stats[i++] =
5613 (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 |
5614 le32_to_cpu(stat_info->rmac_jabber_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005615 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_64_frms);
5616 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms);
5617 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms);
5618 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms);
5619 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms);
5620 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms);
5621 tmp_stats[i++] =
5622 (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005623 le32_to_cpu(stat_info->rmac_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets);
5625 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005626 tmp_stats[i++] =
5627 (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005628 le32_to_cpu(stat_info->rmac_drop_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005629 tmp_stats[i++] =
5630 (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005631 le32_to_cpu(stat_info->rmac_icmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005633 tmp_stats[i++] =
5634 (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005635 le32_to_cpu(stat_info->rmac_udp);
5636 tmp_stats[i++] =
5637 (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 |
5638 le32_to_cpu(stat_info->rmac_err_drp_udp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005639 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_err_sym);
5640 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0);
5641 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1);
5642 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2);
5643 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3);
5644 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4);
5645 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5);
5646 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6);
5647 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7);
5648 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0);
5649 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1);
5650 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2);
5651 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3);
5652 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4);
5653 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5);
5654 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6);
5655 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005656 tmp_stats[i++] =
5657 (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 |
5658 le32_to_cpu(stat_info->rmac_pause_cnt);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005659 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_data_err_cnt);
5660 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005661 tmp_stats[i++] =
5662 (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 |
5663 le32_to_cpu(stat_info->rmac_accepted_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005665 tmp_stats[i++] = le32_to_cpu(stat_info->rd_req_cnt);
5666 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_cnt);
5667 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_rtry_cnt);
5668 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_cnt);
5669 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_rd_ack_cnt);
5670 tmp_stats[i++] = le32_to_cpu(stat_info->wr_req_cnt);
5671 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_cnt);
5672 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_rtry_cnt);
5673 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_cnt);
5674 tmp_stats[i++] = le32_to_cpu(stat_info->wr_disc_cnt);
5675 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_wr_ack_cnt);
5676 tmp_stats[i++] = le32_to_cpu(stat_info->txp_wr_cnt);
5677 tmp_stats[i++] = le32_to_cpu(stat_info->txd_rd_cnt);
5678 tmp_stats[i++] = le32_to_cpu(stat_info->txd_wr_cnt);
5679 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_rd_cnt);
5680 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_wr_cnt);
5681 tmp_stats[i++] = le32_to_cpu(stat_info->txf_rd_cnt);
5682 tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt);
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -05005683
5684 /* Enhanced statistics exist only for Hercules */
5685 if(sp->device_type == XFRAME_II_DEVICE) {
5686 tmp_stats[i++] =
5687 le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms);
5688 tmp_stats[i++] =
5689 le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms);
5690 tmp_stats[i++] =
5691 le64_to_cpu(stat_info->rmac_ttl_8192_max_frms);
5692 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms);
5693 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms);
5694 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms);
5695 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms);
5696 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms);
5697 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard);
5698 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard);
5699 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard);
5700 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard);
5701 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard);
5702 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard);
5703 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard);
5704 tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt);
5705 }
5706
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005707 tmp_stats[i++] = 0;
5708 tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
5709 tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
Ananda Rajubd1034f2006-04-21 19:20:22 -04005710 tmp_stats[i++] = stat_info->sw_stat.parity_err_cnt;
5711 tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt;
5712 tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt;
5713 tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt;
5714 tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt;
5715 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high;
5716 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low;
5717 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high;
5718 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_low;
5719 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_high;
5720 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_low;
5721 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_high;
5722 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_low;
5723 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_high;
5724 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_low;
5725 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_high;
5726 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_low;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005727 tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt;
5728 tmp_stats[i++] = stat_info->sw_stat.sending_both;
5729 tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts;
5730 tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts;
Andrew Mortonfe931392006-02-03 01:45:12 -08005731 if (stat_info->sw_stat.num_aggregations) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04005732 u64 tmp = stat_info->sw_stat.sum_avg_pkts_aggregated;
5733 int count = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005734 /*
Ananda Rajubd1034f2006-04-21 19:20:22 -04005735 * Since 64-bit divide does not work on all platforms,
5736 * do repeated subtraction.
5737 */
5738 while (tmp >= stat_info->sw_stat.num_aggregations) {
5739 tmp -= stat_info->sw_stat.num_aggregations;
5740 count++;
5741 }
5742 tmp_stats[i++] = count;
Andrew Mortonfe931392006-02-03 01:45:12 -08005743 }
Ananda Rajubd1034f2006-04-21 19:20:22 -04005744 else
5745 tmp_stats[i++] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746}
5747
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005748static int s2io_ethtool_get_regs_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749{
5750 return (XENA_REG_SPACE);
5751}
5752
5753
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005754static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005756 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757
5758 return (sp->rx_csum);
5759}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005760
5761static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005763 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764
5765 if (data)
5766 sp->rx_csum = 1;
5767 else
5768 sp->rx_csum = 0;
5769
5770 return 0;
5771}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005772
5773static int s2io_get_eeprom_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774{
5775 return (XENA_EEPROM_SPACE);
5776}
5777
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005778static int s2io_ethtool_self_test_count(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779{
5780 return (S2IO_TEST_LEN);
5781}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005782
5783static void s2io_ethtool_get_strings(struct net_device *dev,
5784 u32 stringset, u8 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785{
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -05005786 int stat_size = 0;
5787 struct s2io_nic *sp = dev->priv;
5788
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789 switch (stringset) {
5790 case ETH_SS_TEST:
5791 memcpy(data, s2io_gstrings, S2IO_STRINGS_LEN);
5792 break;
5793 case ETH_SS_STATS:
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -05005794 stat_size = sizeof(ethtool_xena_stats_keys);
5795 memcpy(data, &ethtool_xena_stats_keys,stat_size);
5796 if(sp->device_type == XFRAME_II_DEVICE) {
5797 memcpy(data + stat_size,
5798 &ethtool_enhanced_stats_keys,
5799 sizeof(ethtool_enhanced_stats_keys));
5800 stat_size += sizeof(ethtool_enhanced_stats_keys);
5801 }
5802
5803 memcpy(data + stat_size, &ethtool_driver_stats_keys,
5804 sizeof(ethtool_driver_stats_keys));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805 }
5806}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807static int s2io_ethtool_get_stats_count(struct net_device *dev)
5808{
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -05005809 struct s2io_nic *sp = dev->priv;
5810 int stat_count = 0;
5811 switch(sp->device_type) {
5812 case XFRAME_I_DEVICE:
5813 stat_count = XFRAME_I_STAT_LEN;
5814 break;
5815
5816 case XFRAME_II_DEVICE:
5817 stat_count = XFRAME_II_STAT_LEN;
5818 break;
5819 }
5820
5821 return stat_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822}
5823
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005824static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825{
5826 if (data)
5827 dev->features |= NETIF_F_IP_CSUM;
5828 else
5829 dev->features &= ~NETIF_F_IP_CSUM;
5830
5831 return 0;
5832}
5833
Ananda Raju75c30b12006-07-24 19:55:09 -04005834static u32 s2io_ethtool_op_get_tso(struct net_device *dev)
5835{
5836 return (dev->features & NETIF_F_TSO) != 0;
5837}
5838static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data)
5839{
5840 if (data)
5841 dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
5842 else
5843 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
5844
5845 return 0;
5846}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847
Jeff Garzik7282d492006-09-13 14:30:00 -04005848static const struct ethtool_ops netdev_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005849 .get_settings = s2io_ethtool_gset,
5850 .set_settings = s2io_ethtool_sset,
5851 .get_drvinfo = s2io_ethtool_gdrvinfo,
5852 .get_regs_len = s2io_ethtool_get_regs_len,
5853 .get_regs = s2io_ethtool_gregs,
5854 .get_link = ethtool_op_get_link,
5855 .get_eeprom_len = s2io_get_eeprom_len,
5856 .get_eeprom = s2io_ethtool_geeprom,
5857 .set_eeprom = s2io_ethtool_seeprom,
5858 .get_pauseparam = s2io_ethtool_getpause_data,
5859 .set_pauseparam = s2io_ethtool_setpause_data,
5860 .get_rx_csum = s2io_ethtool_get_rx_csum,
5861 .set_rx_csum = s2io_ethtool_set_rx_csum,
5862 .get_tx_csum = ethtool_op_get_tx_csum,
5863 .set_tx_csum = s2io_ethtool_op_set_tx_csum,
5864 .get_sg = ethtool_op_get_sg,
5865 .set_sg = ethtool_op_set_sg,
Ananda Raju75c30b12006-07-24 19:55:09 -04005866 .get_tso = s2io_ethtool_op_get_tso,
5867 .set_tso = s2io_ethtool_op_set_tso,
Ananda Rajufed5ecc2005-11-14 15:25:08 -05005868 .get_ufo = ethtool_op_get_ufo,
5869 .set_ufo = ethtool_op_set_ufo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870 .self_test_count = s2io_ethtool_self_test_count,
5871 .self_test = s2io_ethtool_test,
5872 .get_strings = s2io_ethtool_get_strings,
5873 .phys_id = s2io_ethtool_idnic,
5874 .get_stats_count = s2io_ethtool_get_stats_count,
5875 .get_ethtool_stats = s2io_get_ethtool_stats
5876};
5877
5878/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005879 * s2io_ioctl - Entry point for the Ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 * @dev : Device pointer.
5881 * @ifr : An IOCTL specefic structure, that can contain a pointer to
5882 * a proprietary structure used to pass information to the driver.
5883 * @cmd : This is used to distinguish between the different commands that
5884 * can be passed to the IOCTL functions.
5885 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005886 * Currently there are no special functionality supported in IOCTL, hence
5887 * function always return EOPNOTSUPPORTED
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888 */
5889
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005890static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891{
5892 return -EOPNOTSUPP;
5893}
5894
5895/**
5896 * s2io_change_mtu - entry point to change MTU size for the device.
5897 * @dev : device pointer.
5898 * @new_mtu : the new MTU size for the device.
5899 * Description: A driver entry point to change MTU size for the device.
5900 * Before changing the MTU the device must be stopped.
5901 * Return value:
5902 * 0 on success and an appropriate (-)ve integer as defined in errno.h
5903 * file on failure.
5904 */
5905
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005906static int s2io_change_mtu(struct net_device *dev, int new_mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005908 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909
5910 if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
5911 DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
5912 dev->name);
5913 return -EPERM;
5914 }
5915
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916 dev->mtu = new_mtu;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005917 if (netif_running(dev)) {
Ananda Rajue6a8fee2006-07-06 23:58:23 -07005918 s2io_card_down(sp);
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005919 netif_stop_queue(dev);
5920 if (s2io_card_up(sp)) {
5921 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
5922 __FUNCTION__);
5923 }
5924 if (netif_queue_stopped(dev))
5925 netif_wake_queue(dev);
5926 } else { /* Device is down */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005927 struct XENA_dev_config __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005928 u64 val64 = new_mtu;
5929
5930 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
5931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932
5933 return 0;
5934}
5935
5936/**
5937 * s2io_tasklet - Bottom half of the ISR.
5938 * @dev_adr : address of the device structure in dma_addr_t format.
5939 * Description:
5940 * This is the tasklet or the bottom half of the ISR. This is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005941 * an extension of the ISR which is scheduled by the scheduler to be run
Linus Torvalds1da177e2005-04-16 15:20:36 -07005942 * 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 -07005943 * be pushed into the tasklet. For now the tasklet is used only to
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944 * replenish the Rx buffers in the Rx buffer descriptors.
5945 * Return value:
5946 * void.
5947 */
5948
5949static void s2io_tasklet(unsigned long dev_addr)
5950{
5951 struct net_device *dev = (struct net_device *) dev_addr;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005952 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 int i, ret;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005954 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955 struct config_param *config;
5956
5957 mac_control = &sp->mac_control;
5958 config = &sp->config;
5959
5960 if (!TASKLET_IN_USE) {
5961 for (i = 0; i < config->rx_ring_num; i++) {
5962 ret = fill_rx_buffers(sp, i);
5963 if (ret == -ENOMEM) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08005964 DBG_PRINT(INFO_DBG, "%s: Out of ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965 dev->name);
5966 DBG_PRINT(ERR_DBG, "memory in tasklet\n");
5967 break;
5968 } else if (ret == -EFILL) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08005969 DBG_PRINT(INFO_DBG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970 "%s: Rx Ring %d is full\n",
5971 dev->name, i);
5972 break;
5973 }
5974 }
5975 clear_bit(0, (&sp->tasklet_status));
5976 }
5977}
5978
5979/**
5980 * s2io_set_link - Set the LInk status
5981 * @data: long pointer to device private structue
5982 * Description: Sets the link status for the adapter
5983 */
5984
David Howellsc4028952006-11-22 14:57:56 +00005985static void s2io_set_link(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005987 struct s2io_nic *nic = container_of(work, struct s2io_nic, set_link_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988 struct net_device *dev = nic->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005989 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990 register u64 val64;
5991 u16 subid;
5992
Francois Romieu22747d62007-02-15 23:37:50 +01005993 rtnl_lock();
5994
5995 if (!netif_running(dev))
5996 goto out_unlock;
5997
Linus Torvalds1da177e2005-04-16 15:20:36 -07005998 if (test_and_set_bit(0, &(nic->link_state))) {
5999 /* The card is being reset, no point doing anything */
Francois Romieu22747d62007-02-15 23:37:50 +01006000 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001 }
6002
6003 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07006004 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
6005 /*
6006 * Allow a small delay for the NICs self initiated
6007 * cleanup to complete.
6008 */
6009 msleep(100);
6010 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011
6012 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006013 if (LINK_IS_UP(val64)) {
6014 if (!(readq(&bar0->adapter_control) & ADAPTER_CNTL_EN)) {
6015 if (verify_xena_quiescence(nic)) {
6016 val64 = readq(&bar0->adapter_control);
6017 val64 |= ADAPTER_CNTL_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018 writeq(val64, &bar0->adapter_control);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006019 if (CARDS_WITH_FAULTY_LINK_INDICATORS(
6020 nic->device_type, subid)) {
6021 val64 = readq(&bar0->gpio_control);
6022 val64 |= GPIO_CTRL_GPIO_0;
6023 writeq(val64, &bar0->gpio_control);
6024 val64 = readq(&bar0->gpio_control);
6025 } else {
6026 val64 |= ADAPTER_LED_ON;
6027 writeq(val64, &bar0->adapter_control);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07006028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029 nic->device_enabled_once = TRUE;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006030 } else {
6031 DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
6032 DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
6033 netif_stop_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006036 val64 = readq(&bar0->adapter_status);
6037 if (!LINK_IS_UP(val64)) {
6038 DBG_PRINT(ERR_DBG, "%s:", dev->name);
6039 DBG_PRINT(ERR_DBG, " Link down after enabling ");
6040 DBG_PRINT(ERR_DBG, "device \n");
6041 } else
6042 s2io_link(nic, LINK_UP);
6043 } else {
6044 if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
6045 subid)) {
6046 val64 = readq(&bar0->gpio_control);
6047 val64 &= ~GPIO_CTRL_GPIO_0;
6048 writeq(val64, &bar0->gpio_control);
6049 val64 = readq(&bar0->gpio_control);
6050 }
6051 s2io_link(nic, LINK_DOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052 }
6053 clear_bit(0, &(nic->link_state));
Francois Romieu22747d62007-02-15 23:37:50 +01006054
6055out_unlock:
Sivakumar Subramanid8d70ca2007-02-24 02:04:24 -05006056 rtnl_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057}
6058
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006059static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
6060 struct buffAdd *ba,
6061 struct sk_buff **skb, u64 *temp0, u64 *temp1,
6062 u64 *temp2, int size)
Ananda Raju5d3213c2006-04-21 19:23:26 -04006063{
6064 struct net_device *dev = sp->dev;
6065 struct sk_buff *frag_list;
6066
6067 if ((sp->rxd_mode == RXD_MODE_1) && (rxdp->Host_Control == 0)) {
6068 /* allocate skb */
6069 if (*skb) {
6070 DBG_PRINT(INFO_DBG, "SKB is not NULL\n");
6071 /*
6072 * As Rx frame are not going to be processed,
6073 * using same mapped address for the Rxd
6074 * buffer pointer
6075 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006076 ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006077 } else {
6078 *skb = dev_alloc_skb(size);
6079 if (!(*skb)) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08006080 DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
6081 DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
Ananda Raju5d3213c2006-04-21 19:23:26 -04006082 return -ENOMEM ;
6083 }
6084 /* storing the mapped addr in a temp variable
6085 * such it will be used for next rxd whose
6086 * Host Control is NULL
6087 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006088 ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006089 pci_map_single( sp->pdev, (*skb)->data,
6090 size - NET_IP_ALIGN,
6091 PCI_DMA_FROMDEVICE);
6092 rxdp->Host_Control = (unsigned long) (*skb);
6093 }
6094 } else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
6095 /* Two buffer Mode */
6096 if (*skb) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006097 ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
6098 ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
6099 ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006100 } else {
6101 *skb = dev_alloc_skb(size);
David Rientjes2ceaac72006-10-30 14:19:25 -08006102 if (!(*skb)) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08006103 DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n",
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006104 dev->name);
David Rientjes2ceaac72006-10-30 14:19:25 -08006105 return -ENOMEM;
6106 }
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006107 ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006108 pci_map_single(sp->pdev, (*skb)->data,
6109 dev->mtu + 4,
6110 PCI_DMA_FROMDEVICE);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006111 ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006112 pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
6113 PCI_DMA_FROMDEVICE);
6114 rxdp->Host_Control = (unsigned long) (*skb);
6115
6116 /* Buffer-1 will be dummy buffer not used */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006117 ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006118 pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
6119 PCI_DMA_FROMDEVICE);
6120 }
6121 } else if ((rxdp->Host_Control == 0)) {
6122 /* Three buffer mode */
6123 if (*skb) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006124 ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
6125 ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
6126 ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006127 } else {
6128 *skb = dev_alloc_skb(size);
David Rientjes2ceaac72006-10-30 14:19:25 -08006129 if (!(*skb)) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08006130 DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n",
David Rientjes2ceaac72006-10-30 14:19:25 -08006131 dev->name);
6132 return -ENOMEM;
6133 }
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006134 ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006135 pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
6136 PCI_DMA_FROMDEVICE);
6137 /* Buffer-1 receives L3/L4 headers */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006138 ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006139 pci_map_single( sp->pdev, (*skb)->data,
6140 l3l4hdr_size + 4,
6141 PCI_DMA_FROMDEVICE);
6142 /*
6143 * skb_shinfo(skb)->frag_list will have L4
6144 * data payload
6145 */
6146 skb_shinfo(*skb)->frag_list = dev_alloc_skb(dev->mtu +
6147 ALIGN_SIZE);
6148 if (skb_shinfo(*skb)->frag_list == NULL) {
6149 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb \
6150 failed\n ", dev->name);
6151 return -ENOMEM ;
6152 }
6153 frag_list = skb_shinfo(*skb)->frag_list;
6154 frag_list->next = NULL;
6155 /*
6156 * Buffer-2 receives L4 data payload
6157 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006158 ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006159 pci_map_single( sp->pdev, frag_list->data,
6160 dev->mtu, PCI_DMA_FROMDEVICE);
6161 }
6162 }
6163 return 0;
6164}
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006165static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp,
6166 int size)
Ananda Raju5d3213c2006-04-21 19:23:26 -04006167{
6168 struct net_device *dev = sp->dev;
6169 if (sp->rxd_mode == RXD_MODE_1) {
6170 rxdp->Control_2 = SET_BUFFER0_SIZE_1( size - NET_IP_ALIGN);
6171 } else if (sp->rxd_mode == RXD_MODE_3B) {
6172 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
6173 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
6174 rxdp->Control_2 |= SET_BUFFER2_SIZE_3( dev->mtu + 4);
6175 } else {
6176 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
6177 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
6178 rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
6179 }
6180}
6181
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006182static int rxd_owner_bit_reset(struct s2io_nic *sp)
Ananda Raju5d3213c2006-04-21 19:23:26 -04006183{
6184 int i, j, k, blk_cnt = 0, size;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006185 struct mac_info * mac_control = &sp->mac_control;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006186 struct config_param *config = &sp->config;
6187 struct net_device *dev = sp->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006188 struct RxD_t *rxdp = NULL;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006189 struct sk_buff *skb = NULL;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006190 struct buffAdd *ba = NULL;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006191 u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0;
6192
6193 /* Calculate the size based on ring mode */
6194 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
6195 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
6196 if (sp->rxd_mode == RXD_MODE_1)
6197 size += NET_IP_ALIGN;
6198 else if (sp->rxd_mode == RXD_MODE_3B)
6199 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
6200 else
6201 size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
6202
6203 for (i = 0; i < config->rx_ring_num; i++) {
6204 blk_cnt = config->rx_cfg[i].num_rxd /
6205 (rxd_count[sp->rxd_mode] +1);
6206
6207 for (j = 0; j < blk_cnt; j++) {
6208 for (k = 0; k < rxd_count[sp->rxd_mode]; k++) {
6209 rxdp = mac_control->rings[i].
6210 rx_blocks[j].rxds[k].virt_addr;
6211 if(sp->rxd_mode >= RXD_MODE_3A)
6212 ba = &mac_control->rings[i].ba[j][k];
Sivakumar Subramaniac1f90d2007-02-24 02:01:31 -05006213 if (set_rxd_buffer_pointer(sp, rxdp, ba,
Ananda Raju5d3213c2006-04-21 19:23:26 -04006214 &skb,(u64 *)&temp0_64,
6215 (u64 *)&temp1_64,
Sivakumar Subramaniac1f90d2007-02-24 02:01:31 -05006216 (u64 *)&temp2_64,
6217 size) == ENOMEM) {
6218 return 0;
6219 }
Ananda Raju5d3213c2006-04-21 19:23:26 -04006220
6221 set_rxd_buffer_size(sp, rxdp, size);
6222 wmb();
6223 /* flip the Ownership bit to Hardware */
6224 rxdp->Control_1 |= RXD_OWN_XENA;
6225 }
6226 }
6227 }
6228 return 0;
6229
6230}
6231
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006232static int s2io_add_isr(struct s2io_nic * sp)
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006233{
6234 int ret = 0;
6235 struct net_device *dev = sp->dev;
6236 int err = 0;
6237
6238 if (sp->intr_type == MSI)
6239 ret = s2io_enable_msi(sp);
6240 else if (sp->intr_type == MSI_X)
6241 ret = s2io_enable_msi_x(sp);
6242 if (ret) {
6243 DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
6244 sp->intr_type = INTA;
6245 }
6246
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006247 /* Store the values of the MSIX table in the struct s2io_nic structure */
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006248 store_xmsi_data(sp);
6249
6250 /* After proper initialization of H/W, register ISR */
6251 if (sp->intr_type == MSI) {
6252 err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
6253 IRQF_SHARED, sp->name, dev);
6254 if (err) {
6255 pci_disable_msi(sp->pdev);
6256 DBG_PRINT(ERR_DBG, "%s: MSI registration failed\n",
6257 dev->name);
6258 return -1;
6259 }
6260 }
6261 if (sp->intr_type == MSI_X) {
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006262 int i, msix_tx_cnt=0,msix_rx_cnt=0;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006263
6264 for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
6265 if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
6266 sprintf(sp->desc[i], "%s:MSI-X-%d-TX",
6267 dev->name, i);
6268 err = request_irq(sp->entries[i].vector,
6269 s2io_msix_fifo_handle, 0, sp->desc[i],
6270 sp->s2io_entries[i].arg);
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006271 /* If either data or addr is zero print it */
6272 if(!(sp->msix_info[i].addr &&
6273 sp->msix_info[i].data)) {
6274 DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx"
6275 "Data:0x%lx\n",sp->desc[i],
6276 (unsigned long long)
6277 sp->msix_info[i].addr,
6278 (unsigned long)
6279 ntohl(sp->msix_info[i].data));
6280 } else {
6281 msix_tx_cnt++;
6282 }
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006283 } else {
6284 sprintf(sp->desc[i], "%s:MSI-X-%d-RX",
6285 dev->name, i);
6286 err = request_irq(sp->entries[i].vector,
6287 s2io_msix_ring_handle, 0, sp->desc[i],
6288 sp->s2io_entries[i].arg);
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006289 /* If either data or addr is zero print it */
6290 if(!(sp->msix_info[i].addr &&
6291 sp->msix_info[i].data)) {
6292 DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx"
6293 "Data:0x%lx\n",sp->desc[i],
6294 (unsigned long long)
6295 sp->msix_info[i].addr,
6296 (unsigned long)
6297 ntohl(sp->msix_info[i].data));
6298 } else {
6299 msix_rx_cnt++;
6300 }
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006301 }
6302 if (err) {
6303 DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
6304 "failed\n", dev->name, i);
6305 DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
6306 return -1;
6307 }
6308 sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
6309 }
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006310 printk("MSI-X-TX %d entries enabled\n",msix_tx_cnt);
6311 printk("MSI-X-RX %d entries enabled\n",msix_rx_cnt);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006312 }
6313 if (sp->intr_type == INTA) {
6314 err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
6315 sp->name, dev);
6316 if (err) {
6317 DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
6318 dev->name);
6319 return -1;
6320 }
6321 }
6322 return 0;
6323}
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006324static void s2io_rem_isr(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325{
6326 int cnt = 0;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006327 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006328
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006329 if (sp->intr_type == MSI_X) {
6330 int i;
6331 u16 msi_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006333 for (i=1; (sp->s2io_entries[i].in_use ==
6334 MSIX_REGISTERED_SUCCESS); i++) {
6335 int vector = sp->entries[i].vector;
6336 void *arg = sp->s2io_entries[i].arg;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006337
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006338 free_irq(vector, arg);
6339 }
6340 pci_read_config_word(sp->pdev, 0x42, &msi_control);
6341 msi_control &= 0xFFFE; /* Disable MSI */
6342 pci_write_config_word(sp->pdev, 0x42, msi_control);
Ananda Rajuc92ca042006-04-21 19:18:03 -04006343
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006344 pci_disable_msix(sp->pdev);
6345 } else {
6346 free_irq(sp->pdev->irq, dev);
6347 if (sp->intr_type == MSI) {
6348 u16 val;
6349
6350 pci_disable_msi(sp->pdev);
6351 pci_read_config_word(sp->pdev, 0x4c, &val);
6352 val ^= 0x1;
6353 pci_write_config_word(sp->pdev, 0x4c, val);
Ananda Rajuc92ca042006-04-21 19:18:03 -04006354 }
6355 }
6356 /* Waiting till all Interrupt handlers are complete */
6357 cnt = 0;
6358 do {
6359 msleep(10);
6360 if (!atomic_read(&sp->isr_cnt))
6361 break;
6362 cnt++;
6363 } while(cnt < 5);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006364}
6365
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006366static void s2io_card_down(struct s2io_nic * sp)
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006367{
6368 int cnt = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006369 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006370 unsigned long flags;
6371 register u64 val64 = 0;
6372
6373 del_timer_sync(&sp->alarm_timer);
6374 /* If s2io_set_link task is executing, wait till it completes. */
6375 while (test_and_set_bit(0, &(sp->link_state))) {
6376 msleep(50);
6377 }
6378 atomic_set(&sp->card_state, CARD_DOWN);
6379
6380 /* disable Tx and Rx traffic on the NIC */
6381 stop_nic(sp);
6382
6383 s2io_rem_isr(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384
6385 /* Kill tasklet. */
6386 tasklet_kill(&sp->task);
6387
6388 /* Check if the device is Quiescent and then Reset the NIC */
6389 do {
Ananda Raju5d3213c2006-04-21 19:23:26 -04006390 /* As per the HW requirement we need to replenish the
6391 * receive buffer to avoid the ring bump. Since there is
6392 * no intention of processing the Rx frame at this pointwe are
6393 * just settting the ownership bit of rxd in Each Rx
6394 * ring to HW and set the appropriate buffer size
6395 * based on the ring mode
6396 */
6397 rxd_owner_bit_reset(sp);
6398
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006400 if (verify_xena_quiescence(sp)) {
6401 if(verify_pcc_quiescent(sp, sp->device_enabled_once))
Linus Torvalds1da177e2005-04-16 15:20:36 -07006402 break;
6403 }
6404
6405 msleep(50);
6406 cnt++;
6407 if (cnt == 10) {
6408 DBG_PRINT(ERR_DBG,
6409 "s2io_close:Device not Quiescent ");
6410 DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n",
6411 (unsigned long long) val64);
6412 break;
6413 }
6414 } while (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006415 s2io_reset(sp);
6416
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006417 spin_lock_irqsave(&sp->tx_lock, flags);
6418 /* Free all Tx buffers */
6419 free_tx_buffers(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006420 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006421
6422 /* Free all Rx buffers */
6423 spin_lock_irqsave(&sp->rx_lock, flags);
6424 free_rx_buffers(sp);
6425 spin_unlock_irqrestore(&sp->rx_lock, flags);
6426
Linus Torvalds1da177e2005-04-16 15:20:36 -07006427 clear_bit(0, &(sp->link_state));
6428}
6429
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006430static int s2io_card_up(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006431{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006432 int i, ret = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006433 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006434 struct config_param *config;
6435 struct net_device *dev = (struct net_device *) sp->dev;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006436 u16 interruptible;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006437
6438 /* Initialize the H/W I/O registers */
6439 if (init_nic(sp) != 0) {
6440 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
6441 dev->name);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006442 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006443 return -ENODEV;
6444 }
6445
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006446 /*
6447 * Initializing the Rx buffers. For now we are considering only 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07006448 * Rx ring and initializing buffers into 30 Rx blocks
6449 */
6450 mac_control = &sp->mac_control;
6451 config = &sp->config;
6452
6453 for (i = 0; i < config->rx_ring_num; i++) {
6454 if ((ret = fill_rx_buffers(sp, i))) {
6455 DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
6456 dev->name);
6457 s2io_reset(sp);
6458 free_rx_buffers(sp);
6459 return -ENOMEM;
6460 }
6461 DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
6462 atomic_read(&sp->rx_bufs_left[i]));
6463 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006464 /* Maintain the state prior to the open */
6465 if (sp->promisc_flg)
6466 sp->promisc_flg = 0;
6467 if (sp->m_cast_flg) {
6468 sp->m_cast_flg = 0;
6469 sp->all_multi_pos= 0;
6470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006471
6472 /* Setting its receive mode */
6473 s2io_set_multicast(dev);
6474
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006475 if (sp->lro) {
Ananda Rajub41477f2006-07-24 19:52:49 -04006476 /* Initialize max aggregatable pkts per session based on MTU */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006477 sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
6478 /* Check if we can use(if specified) user provided value */
6479 if (lro_max_pkts < sp->lro_max_aggr_per_sess)
6480 sp->lro_max_aggr_per_sess = lro_max_pkts;
6481 }
6482
Linus Torvalds1da177e2005-04-16 15:20:36 -07006483 /* Enable Rx Traffic and interrupts on the NIC */
6484 if (start_nic(sp)) {
6485 DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006486 s2io_reset(sp);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006487 free_rx_buffers(sp);
6488 return -ENODEV;
6489 }
6490
6491 /* Add interrupt service routine */
6492 if (s2io_add_isr(sp) != 0) {
6493 if (sp->intr_type == MSI_X)
6494 s2io_rem_isr(sp);
6495 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006496 free_rx_buffers(sp);
6497 return -ENODEV;
6498 }
6499
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07006500 S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
6501
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006502 /* Enable tasklet for the device */
6503 tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
6504
6505 /* Enable select interrupts */
6506 if (sp->intr_type != INTA)
6507 en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
6508 else {
6509 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
6510 interruptible |= TX_PIC_INTR | RX_PIC_INTR;
6511 interruptible |= TX_MAC_INTR | RX_MAC_INTR;
6512 en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS);
6513 }
6514
6515
Linus Torvalds1da177e2005-04-16 15:20:36 -07006516 atomic_set(&sp->card_state, CARD_UP);
6517 return 0;
6518}
6519
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006520/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006521 * s2io_restart_nic - Resets the NIC.
6522 * @data : long pointer to the device private structure
6523 * Description:
6524 * This function is scheduled to be run by the s2io_tx_watchdog
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006525 * function after 0.5 secs to reset the NIC. The idea is to reduce
Linus Torvalds1da177e2005-04-16 15:20:36 -07006526 * the run time of the watch dog routine which is run holding a
6527 * spin lock.
6528 */
6529
David Howellsc4028952006-11-22 14:57:56 +00006530static void s2io_restart_nic(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006531{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006532 struct s2io_nic *sp = container_of(work, struct s2io_nic, rst_timer_task);
David Howellsc4028952006-11-22 14:57:56 +00006533 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006534
Francois Romieu22747d62007-02-15 23:37:50 +01006535 rtnl_lock();
6536
6537 if (!netif_running(dev))
6538 goto out_unlock;
6539
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006540 s2io_card_down(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006541 if (s2io_card_up(sp)) {
6542 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
6543 dev->name);
6544 }
6545 netif_wake_queue(dev);
6546 DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
6547 dev->name);
Francois Romieu22747d62007-02-15 23:37:50 +01006548out_unlock:
6549 rtnl_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006550}
6551
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006552/**
6553 * s2io_tx_watchdog - Watchdog for transmit side.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006554 * @dev : Pointer to net device structure
6555 * Description:
6556 * This function is triggered if the Tx Queue is stopped
6557 * for a pre-defined amount of time when the Interface is still up.
6558 * If the Interface is jammed in such a situation, the hardware is
6559 * reset (by s2io_close) and restarted again (by s2io_open) to
6560 * overcome any problem that might have been caused in the hardware.
6561 * Return value:
6562 * void
6563 */
6564
6565static void s2io_tx_watchdog(struct net_device *dev)
6566{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006567 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006568
6569 if (netif_carrier_ok(dev)) {
6570 schedule_work(&sp->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04006571 sp->mac_control.stats_info->sw_stat.soft_reset_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006572 }
6573}
6574
6575/**
6576 * rx_osm_handler - To perform some OS related operations on SKB.
6577 * @sp: private member of the device structure,pointer to s2io_nic structure.
6578 * @skb : the socket buffer pointer.
6579 * @len : length of the packet
6580 * @cksum : FCS checksum of the frame.
6581 * @ring_no : the ring from which this RxD was extracted.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006582 * Description:
Ananda Rajub41477f2006-07-24 19:52:49 -04006583 * This function is called by the Rx interrupt serivce routine to perform
Linus Torvalds1da177e2005-04-16 15:20:36 -07006584 * some OS related operations on the SKB before passing it to the upper
6585 * layers. It mainly checks if the checksum is OK, if so adds it to the
6586 * SKBs cksum variable, increments the Rx packet count and passes the SKB
6587 * to the upper layer. If the checksum is wrong, it increments the Rx
6588 * packet error count, frees the SKB and returns error.
6589 * Return value:
6590 * SUCCESS on success and -1 on failure.
6591 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006592static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006593{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006594 struct s2io_nic *sp = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006595 struct net_device *dev = (struct net_device *) sp->dev;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006596 struct sk_buff *skb = (struct sk_buff *)
6597 ((unsigned long) rxdp->Host_Control);
6598 int ring_no = ring_data->ring_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006599 u16 l3_csum, l4_csum;
Ananda Raju863c11a2006-04-21 19:03:13 -04006600 unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006601 struct lro *lro;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006602
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006603 skb->dev = dev;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006604
Ananda Raju863c11a2006-04-21 19:03:13 -04006605 if (err) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04006606 /* Check for parity error */
6607 if (err & 0x1) {
6608 sp->mac_control.stats_info->sw_stat.parity_err_cnt++;
6609 }
6610
Ananda Raju863c11a2006-04-21 19:03:13 -04006611 /*
6612 * Drop the packet if bad transfer code. Exception being
6613 * 0x5, which could be due to unsupported IPv6 extension header.
6614 * In this case, we let stack handle the packet.
6615 * Note that in this case, since checksum will be incorrect,
6616 * stack will validate the same.
6617 */
6618 if (err && ((err >> 48) != 0x5)) {
6619 DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
6620 dev->name, err);
6621 sp->stats.rx_crc_errors++;
6622 dev_kfree_skb(skb);
6623 atomic_dec(&sp->rx_bufs_left[ring_no]);
6624 rxdp->Host_Control = 0;
6625 return 0;
6626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006628
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006629 /* Updating statistics */
6630 rxdp->Host_Control = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006631 sp->stats.rx_packets++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006632 if (sp->rxd_mode == RXD_MODE_1) {
6633 int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006634
Ananda Rajuda6971d2005-10-31 16:55:31 -05006635 sp->stats.rx_bytes += len;
6636 skb_put(skb, len);
6637
6638 } else if (sp->rxd_mode >= RXD_MODE_3A) {
6639 int get_block = ring_data->rx_curr_get_info.block_index;
6640 int get_off = ring_data->rx_curr_get_info.offset;
6641 int buf0_len = RXD_GET_BUFFER0_SIZE_3(rxdp->Control_2);
6642 int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
6643 unsigned char *buff = skb_push(skb, buf0_len);
6644
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006645 struct buffAdd *ba = &ring_data->ba[get_block][get_off];
Ananda Rajuda6971d2005-10-31 16:55:31 -05006646 sp->stats.rx_bytes += buf0_len + buf2_len;
6647 memcpy(buff, ba->ba_0, buf0_len);
6648
6649 if (sp->rxd_mode == RXD_MODE_3A) {
6650 int buf1_len = RXD_GET_BUFFER1_SIZE_3(rxdp->Control_2);
6651
6652 skb_put(skb, buf1_len);
6653 skb->len += buf2_len;
6654 skb->data_len += buf2_len;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006655 skb_put(skb_shinfo(skb)->frag_list, buf2_len);
6656 sp->stats.rx_bytes += buf1_len;
6657
6658 } else
6659 skb_put(skb, buf2_len);
6660 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006661
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006662 if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
6663 (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006664 (sp->rx_csum)) {
6665 l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
6666 l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
6667 if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) {
6668 /*
6669 * NIC verifies if the Checksum of the received
6670 * frame is Ok or not and accordingly returns
6671 * a flag in the RxD.
6672 */
6673 skb->ip_summed = CHECKSUM_UNNECESSARY;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006674 if (sp->lro) {
6675 u32 tcp_len;
6676 u8 *tcp;
6677 int ret = 0;
6678
6679 ret = s2io_club_tcp_session(skb->data, &tcp,
6680 &tcp_len, &lro, rxdp, sp);
6681 switch (ret) {
6682 case 3: /* Begin anew */
6683 lro->parent = skb;
6684 goto aggregate;
6685 case 1: /* Aggregate */
6686 {
6687 lro_append_pkt(sp, lro,
6688 skb, tcp_len);
6689 goto aggregate;
6690 }
6691 case 4: /* Flush session */
6692 {
6693 lro_append_pkt(sp, lro,
6694 skb, tcp_len);
6695 queue_rx_frame(lro->parent);
6696 clear_lro_session(lro);
6697 sp->mac_control.stats_info->
6698 sw_stat.flush_max_pkts++;
6699 goto aggregate;
6700 }
6701 case 2: /* Flush both */
6702 lro->parent->data_len =
6703 lro->frags_len;
6704 sp->mac_control.stats_info->
6705 sw_stat.sending_both++;
6706 queue_rx_frame(lro->parent);
6707 clear_lro_session(lro);
6708 goto send_up;
6709 case 0: /* sessions exceeded */
Ananda Rajuc92ca042006-04-21 19:18:03 -04006710 case -1: /* non-TCP or not
6711 * L2 aggregatable
6712 */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006713 case 5: /*
6714 * First pkt in session not
6715 * L3/L4 aggregatable
6716 */
6717 break;
6718 default:
6719 DBG_PRINT(ERR_DBG,
6720 "%s: Samadhana!!\n",
6721 __FUNCTION__);
6722 BUG();
6723 }
6724 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006725 } else {
6726 /*
6727 * Packet with erroneous checksum, let the
6728 * upper layers deal with it.
6729 */
6730 skb->ip_summed = CHECKSUM_NONE;
6731 }
6732 } else {
6733 skb->ip_summed = CHECKSUM_NONE;
6734 }
6735
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006736 if (!sp->lro) {
6737 skb->protocol = eth_type_trans(skb, dev);
Sivakumar Subramani926930b2007-02-24 01:59:39 -05006738 if ((sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2) &&
6739 vlan_strip_flag)) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006740 /* Queueing the vlan frame to the upper layer */
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05006741 if (napi)
6742 vlan_hwaccel_receive_skb(skb, sp->vlgrp,
6743 RXD_GET_VLAN_TAG(rxdp->Control_2));
6744 else
6745 vlan_hwaccel_rx(skb, sp->vlgrp,
6746 RXD_GET_VLAN_TAG(rxdp->Control_2));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006747 } else {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05006748 if (napi)
6749 netif_receive_skb(skb);
6750 else
6751 netif_rx(skb);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006752 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006753 } else {
6754send_up:
6755 queue_rx_frame(skb);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006756 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006757 dev->last_rx = jiffies;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006758aggregate:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006759 atomic_dec(&sp->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006760 return SUCCESS;
6761}
6762
6763/**
6764 * s2io_link - stops/starts the Tx queue.
6765 * @sp : private member of the device structure, which is a pointer to the
6766 * s2io_nic structure.
6767 * @link : inidicates whether link is UP/DOWN.
6768 * Description:
6769 * This function stops/starts the Tx queue depending on whether the link
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006770 * status of the NIC is is down or up. This is called by the Alarm
6771 * interrupt handler whenever a link change interrupt comes up.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006772 * Return value:
6773 * void.
6774 */
6775
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006776static void s2io_link(struct s2io_nic * sp, int link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006777{
6778 struct net_device *dev = (struct net_device *) sp->dev;
6779
6780 if (link != sp->last_link_state) {
6781 if (link == LINK_DOWN) {
6782 DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
6783 netif_carrier_off(dev);
6784 } else {
6785 DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
6786 netif_carrier_on(dev);
6787 }
6788 }
6789 sp->last_link_state = link;
6790}
6791
6792/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006793 * get_xena_rev_id - to identify revision ID of xena.
6794 * @pdev : PCI Dev structure
6795 * Description:
6796 * Function to identify the Revision ID of xena.
6797 * Return value:
6798 * returns the revision ID of the device.
6799 */
6800
Adrian Bunk26df54b2006-01-14 03:09:40 +01006801static int get_xena_rev_id(struct pci_dev *pdev)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006802{
6803 u8 id = 0;
6804 int ret;
6805 ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id);
6806 return id;
6807}
6808
6809/**
6810 * s2io_init_pci -Initialization of PCI and PCI-X configuration registers .
6811 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07006812 * s2io_nic structure.
6813 * Description:
6814 * This function initializes a few of the PCI and PCI-X configuration registers
6815 * with recommended values.
6816 * Return value:
6817 * void
6818 */
6819
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006820static void s2io_init_pci(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006821{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006822 u16 pci_cmd = 0, pcix_cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006823
6824 /* Enable Data Parity Error Recovery in PCI-X command register. */
6825 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006826 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006827 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006828 (pcix_cmd | 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006829 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006830 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006831
6832 /* Set the PErr Response bit in PCI command register. */
6833 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
6834 pci_write_config_word(sp->pdev, PCI_COMMAND,
6835 (pci_cmd | PCI_COMMAND_PARITY));
6836 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006837}
6838
Ananda Raju9dc737a2006-04-21 19:05:41 -04006839static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
6840{
6841 if ( tx_fifo_num > 8) {
6842 DBG_PRINT(ERR_DBG, "s2io: Requested number of Tx fifos not "
6843 "supported\n");
6844 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Tx fifos\n");
6845 tx_fifo_num = 8;
6846 }
6847 if ( rx_ring_num > 8) {
6848 DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
6849 "supported\n");
6850 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
6851 rx_ring_num = 8;
6852 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05006853 if (*dev_intr_type != INTA)
6854 napi = 0;
6855
Ananda Raju9dc737a2006-04-21 19:05:41 -04006856#ifndef CONFIG_PCI_MSI
6857 if (*dev_intr_type != INTA) {
6858 DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
6859 "MSI/MSI-X. Defaulting to INTA\n");
6860 *dev_intr_type = INTA;
6861 }
6862#else
6863 if (*dev_intr_type > MSI_X) {
6864 DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
6865 "Defaulting to INTA\n");
6866 *dev_intr_type = INTA;
6867 }
6868#endif
6869 if ((*dev_intr_type == MSI_X) &&
6870 ((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
6871 (pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006872 DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. "
Ananda Raju9dc737a2006-04-21 19:05:41 -04006873 "Defaulting to INTA\n");
6874 *dev_intr_type = INTA;
6875 }
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006876
Ananda Raju9dc737a2006-04-21 19:05:41 -04006877 if (rx_ring_mode > 3) {
6878 DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
6879 DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
6880 rx_ring_mode = 3;
6881 }
6882 return SUCCESS;
6883}
6884
Linus Torvalds1da177e2005-04-16 15:20:36 -07006885/**
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05006886 * rts_ds_steer - Receive traffic steering based on IPv4 or IPv6 TOS
6887 * or Traffic class respectively.
6888 * @nic: device peivate variable
6889 * Description: The function configures the receive steering to
6890 * desired receive ring.
6891 * Return Value: SUCCESS on success and
6892 * '-1' on failure (endian settings incorrect).
6893 */
6894static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring)
6895{
6896 struct XENA_dev_config __iomem *bar0 = nic->bar0;
6897 register u64 val64 = 0;
6898
6899 if (ds_codepoint > 63)
6900 return FAILURE;
6901
6902 val64 = RTS_DS_MEM_DATA(ring);
6903 writeq(val64, &bar0->rts_ds_mem_data);
6904
6905 val64 = RTS_DS_MEM_CTRL_WE |
6906 RTS_DS_MEM_CTRL_STROBE_NEW_CMD |
6907 RTS_DS_MEM_CTRL_OFFSET(ds_codepoint);
6908
6909 writeq(val64, &bar0->rts_ds_mem_ctrl);
6910
6911 return wait_for_cmd_complete(&bar0->rts_ds_mem_ctrl,
6912 RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED,
6913 S2IO_BIT_RESET);
6914}
6915
6916/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006917 * s2io_init_nic - Initialization of the adapter .
Linus Torvalds1da177e2005-04-16 15:20:36 -07006918 * @pdev : structure containing the PCI related information of the device.
6919 * @pre: List of PCI devices supported by the driver listed in s2io_tbl.
6920 * Description:
6921 * The function initializes an adapter identified by the pci_dec structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006922 * All OS related initialization including memory and device structure and
6923 * initlaization of the device private variable is done. Also the swapper
6924 * control register is initialized to enable read and write into the I/O
Linus Torvalds1da177e2005-04-16 15:20:36 -07006925 * registers of the device.
6926 * Return value:
6927 * returns 0 on success and negative on failure.
6928 */
6929
6930static int __devinit
6931s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
6932{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006933 struct s2io_nic *sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006934 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006935 int i, j, ret;
6936 int dma_flag = FALSE;
6937 u32 mac_up, mac_down;
6938 u64 val64 = 0, tmp64 = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006939 struct XENA_dev_config __iomem *bar0 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006940 u16 subid;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006941 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006942 struct config_param *config;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006943 int mode;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006944 u8 dev_intr_type = intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006945
Ananda Raju9dc737a2006-04-21 19:05:41 -04006946 if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
6947 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006948
6949 if ((ret = pci_enable_device(pdev))) {
6950 DBG_PRINT(ERR_DBG,
6951 "s2io_init_nic: pci_enable_device failed\n");
6952 return ret;
6953 }
6954
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006955 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006956 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
6957 dma_flag = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006958 if (pci_set_consistent_dma_mask
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006959 (pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006960 DBG_PRINT(ERR_DBG,
6961 "Unable to obtain 64bit DMA for \
6962 consistent allocations\n");
6963 pci_disable_device(pdev);
6964 return -ENOMEM;
6965 }
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006966 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006967 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n");
6968 } else {
6969 pci_disable_device(pdev);
6970 return -ENOMEM;
6971 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006972 if (dev_intr_type != MSI_X) {
6973 if (pci_request_regions(pdev, s2io_driver_name)) {
Ananda Rajub41477f2006-07-24 19:52:49 -04006974 DBG_PRINT(ERR_DBG, "Request Regions failed\n");
6975 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006976 return -ENODEV;
6977 }
6978 }
6979 else {
6980 if (!(request_mem_region(pci_resource_start(pdev, 0),
6981 pci_resource_len(pdev, 0), s2io_driver_name))) {
6982 DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n");
6983 pci_disable_device(pdev);
6984 return -ENODEV;
6985 }
6986 if (!(request_mem_region(pci_resource_start(pdev, 2),
6987 pci_resource_len(pdev, 2), s2io_driver_name))) {
6988 DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n");
6989 release_mem_region(pci_resource_start(pdev, 0),
6990 pci_resource_len(pdev, 0));
6991 pci_disable_device(pdev);
6992 return -ENODEV;
6993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006994 }
6995
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006996 dev = alloc_etherdev(sizeof(struct s2io_nic));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006997 if (dev == NULL) {
6998 DBG_PRINT(ERR_DBG, "Device allocation failed\n");
6999 pci_disable_device(pdev);
7000 pci_release_regions(pdev);
7001 return -ENODEV;
7002 }
7003
7004 pci_set_master(pdev);
7005 pci_set_drvdata(pdev, dev);
7006 SET_MODULE_OWNER(dev);
7007 SET_NETDEV_DEV(dev, &pdev->dev);
7008
7009 /* Private member variable initialized to s2io NIC structure */
7010 sp = dev->priv;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007011 memset(sp, 0, sizeof(struct s2io_nic));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007012 sp->dev = dev;
7013 sp->pdev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007014 sp->high_dma_flag = dma_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007015 sp->device_enabled_once = FALSE;
Ananda Rajuda6971d2005-10-31 16:55:31 -05007016 if (rx_ring_mode == 1)
7017 sp->rxd_mode = RXD_MODE_1;
7018 if (rx_ring_mode == 2)
7019 sp->rxd_mode = RXD_MODE_3B;
7020 if (rx_ring_mode == 3)
7021 sp->rxd_mode = RXD_MODE_3A;
7022
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007023 sp->intr_type = dev_intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007024
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007025 if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
7026 (pdev->device == PCI_DEVICE_ID_HERC_UNI))
7027 sp->device_type = XFRAME_II_DEVICE;
7028 else
7029 sp->device_type = XFRAME_I_DEVICE;
7030
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007031 sp->lro = lro;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007032
Linus Torvalds1da177e2005-04-16 15:20:36 -07007033 /* Initialize some PCI/PCI-X fields of the NIC. */
7034 s2io_init_pci(sp);
7035
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007036 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007037 * Setting the device configuration parameters.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007038 * Most of these parameters can be specified by the user during
7039 * module insertion as they are module loadable parameters. If
7040 * these parameters are not not specified during load time, they
Linus Torvalds1da177e2005-04-16 15:20:36 -07007041 * are initialized with default values.
7042 */
7043 mac_control = &sp->mac_control;
7044 config = &sp->config;
7045
7046 /* Tx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007047 config->tx_fifo_num = tx_fifo_num;
7048 for (i = 0; i < MAX_TX_FIFOS; i++) {
7049 config->tx_cfg[i].fifo_len = tx_fifo_len[i];
7050 config->tx_cfg[i].fifo_priority = i;
7051 }
7052
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007053 /* mapping the QoS priority to the configured fifos */
7054 for (i = 0; i < MAX_TX_FIFOS; i++)
7055 config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i];
7056
Linus Torvalds1da177e2005-04-16 15:20:36 -07007057 config->tx_intr_type = TXD_INT_TYPE_UTILZ;
7058 for (i = 0; i < config->tx_fifo_num; i++) {
7059 config->tx_cfg[i].f_no_snoop =
7060 (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER);
7061 if (config->tx_cfg[i].fifo_len < 65) {
7062 config->tx_intr_type = TXD_INT_TYPE_PER_LIST;
7063 break;
7064 }
7065 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05007066 /* + 2 because one Txd for skb->data and one Txd for UFO */
7067 config->max_txds = MAX_SKB_FRAGS + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007068
7069 /* Rx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007070 config->rx_ring_num = rx_ring_num;
7071 for (i = 0; i < MAX_RX_RINGS; i++) {
7072 config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
Ananda Rajuda6971d2005-10-31 16:55:31 -05007073 (rxd_count[sp->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007074 config->rx_cfg[i].ring_priority = i;
7075 }
7076
7077 for (i = 0; i < rx_ring_num; i++) {
7078 config->rx_cfg[i].ring_org = RING_ORG_BUFF1;
7079 config->rx_cfg[i].f_no_snoop =
7080 (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER);
7081 }
7082
7083 /* Setting Mac Control parameters */
7084 mac_control->rmac_pause_time = rmac_pause_time;
7085 mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3;
7086 mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
7087
7088
7089 /* Initialize Ring buffer parameters. */
7090 for (i = 0; i < config->rx_ring_num; i++)
7091 atomic_set(&sp->rx_bufs_left[i], 0);
7092
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007093 /* Initialize the number of ISRs currently running */
7094 atomic_set(&sp->isr_cnt, 0);
7095
Linus Torvalds1da177e2005-04-16 15:20:36 -07007096 /* initialize the shared memory used by the NIC and the host */
7097 if (init_shared_mem(sp)) {
7098 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
Ananda Rajub41477f2006-07-24 19:52:49 -04007099 dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007100 ret = -ENOMEM;
7101 goto mem_alloc_failed;
7102 }
7103
7104 sp->bar0 = ioremap(pci_resource_start(pdev, 0),
7105 pci_resource_len(pdev, 0));
7106 if (!sp->bar0) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007107 DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007108 dev->name);
7109 ret = -ENOMEM;
7110 goto bar0_remap_failed;
7111 }
7112
7113 sp->bar1 = ioremap(pci_resource_start(pdev, 2),
7114 pci_resource_len(pdev, 2));
7115 if (!sp->bar1) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007116 DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007117 dev->name);
7118 ret = -ENOMEM;
7119 goto bar1_remap_failed;
7120 }
7121
7122 dev->irq = pdev->irq;
7123 dev->base_addr = (unsigned long) sp->bar0;
7124
7125 /* Initializing the BAR1 address as the start of the FIFO pointer. */
7126 for (j = 0; j < MAX_TX_FIFOS; j++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007127 mac_control->tx_FIFO_start[j] = (struct TxFIFO_element __iomem *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007128 (sp->bar1 + (j * 0x00020000));
7129 }
7130
7131 /* Driver entry points */
7132 dev->open = &s2io_open;
7133 dev->stop = &s2io_close;
7134 dev->hard_start_xmit = &s2io_xmit;
7135 dev->get_stats = &s2io_get_stats;
7136 dev->set_multicast_list = &s2io_set_multicast;
7137 dev->do_ioctl = &s2io_ioctl;
7138 dev->change_mtu = &s2io_change_mtu;
7139 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07007140 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
7141 dev->vlan_rx_register = s2io_vlan_rx_register;
7142 dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007143
Linus Torvalds1da177e2005-04-16 15:20:36 -07007144 /*
7145 * will use eth_mac_addr() for dev->set_mac_address
7146 * mac address will be set every time dev->open() is called
7147 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007148 dev->poll = s2io_poll;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007149 dev->weight = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007150
Brian Haley612eff02006-06-15 14:36:36 -04007151#ifdef CONFIG_NET_POLL_CONTROLLER
7152 dev->poll_controller = s2io_netpoll;
7153#endif
7154
Linus Torvalds1da177e2005-04-16 15:20:36 -07007155 dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
7156 if (sp->high_dma_flag == TRUE)
7157 dev->features |= NETIF_F_HIGHDMA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007158 dev->features |= NETIF_F_TSO;
Herbert Xuf83ef8c2006-06-30 13:37:03 -07007159 dev->features |= NETIF_F_TSO6;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007160 if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05007161 dev->features |= NETIF_F_UFO;
7162 dev->features |= NETIF_F_HW_CSUM;
7163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007164
7165 dev->tx_timeout = &s2io_tx_watchdog;
7166 dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
David Howellsc4028952006-11-22 14:57:56 +00007167 INIT_WORK(&sp->rst_timer_task, s2io_restart_nic);
7168 INIT_WORK(&sp->set_link_task, s2io_set_link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007169
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07007170 pci_save_state(sp->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007171
7172 /* Setting swapper control on the NIC, for proper reset operation */
7173 if (s2io_set_swapper(sp)) {
7174 DBG_PRINT(ERR_DBG, "%s:swapper settings are wrong\n",
7175 dev->name);
7176 ret = -EAGAIN;
7177 goto set_swap_failed;
7178 }
7179
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007180 /* Verify if the Herc works on the slot its placed into */
7181 if (sp->device_type & XFRAME_II_DEVICE) {
7182 mode = s2io_verify_pci_mode(sp);
7183 if (mode < 0) {
7184 DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__);
7185 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
7186 ret = -EBADSLT;
7187 goto set_swap_failed;
7188 }
7189 }
7190
7191 /* Not needed for Herc */
7192 if (sp->device_type & XFRAME_I_DEVICE) {
7193 /*
7194 * Fix for all "FFs" MAC address problems observed on
7195 * Alpha platforms
7196 */
7197 fix_mac_address(sp);
7198 s2io_reset(sp);
7199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007200
7201 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007202 * MAC address initialization.
7203 * For now only one mac address will be read and used.
7204 */
7205 bar0 = sp->bar0;
7206 val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
7207 RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
7208 writeq(val64, &bar0->rmac_addr_cmd_mem);
Ananda Rajuc92ca042006-04-21 19:18:03 -04007209 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05007210 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007211 tmp64 = readq(&bar0->rmac_addr_data0_mem);
7212 mac_down = (u32) tmp64;
7213 mac_up = (u32) (tmp64 >> 32);
7214
Linus Torvalds1da177e2005-04-16 15:20:36 -07007215 sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up);
7216 sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8);
7217 sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16);
7218 sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_up >> 24);
7219 sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16);
7220 sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24);
7221
Linus Torvalds1da177e2005-04-16 15:20:36 -07007222 /* Set the factory defined MAC address initially */
7223 dev->addr_len = ETH_ALEN;
7224 memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
7225
Ananda Rajub41477f2006-07-24 19:52:49 -04007226 /* reset Nic and bring it to known state */
7227 s2io_reset(sp);
7228
Linus Torvalds1da177e2005-04-16 15:20:36 -07007229 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007230 * Initialize the tasklet status and link state flags
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007231 * and the card state parameter
Linus Torvalds1da177e2005-04-16 15:20:36 -07007232 */
7233 atomic_set(&(sp->card_state), 0);
7234 sp->tasklet_status = 0;
7235 sp->link_state = 0;
7236
Linus Torvalds1da177e2005-04-16 15:20:36 -07007237 /* Initialize spinlocks */
7238 spin_lock_init(&sp->tx_lock);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007239
7240 if (!napi)
7241 spin_lock_init(&sp->put_lock);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007242 spin_lock_init(&sp->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007243
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007244 /*
7245 * SXE-002: Configure link and activity LED to init state
7246 * on driver load.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007247 */
7248 subid = sp->pdev->subsystem_device;
7249 if ((subid & 0xFF) >= 0x07) {
7250 val64 = readq(&bar0->gpio_control);
7251 val64 |= 0x0000800000000000ULL;
7252 writeq(val64, &bar0->gpio_control);
7253 val64 = 0x0411040400000000ULL;
7254 writeq(val64, (void __iomem *) bar0 + 0x2700);
7255 val64 = readq(&bar0->gpio_control);
7256 }
7257
7258 sp->rx_csum = 1; /* Rx chksum verify enabled by default */
7259
7260 if (register_netdev(dev)) {
7261 DBG_PRINT(ERR_DBG, "Device registration failed\n");
7262 ret = -ENODEV;
7263 goto register_failed;
7264 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04007265 s2io_vpd_read(sp);
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08007266 DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n");
Ananda Rajub41477f2006-07-24 19:52:49 -04007267 DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name,
7268 sp->product_name, get_xena_rev_id(sp->pdev));
7269 DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
7270 s2io_driver_version);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007271 DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007272 "%02x:%02x:%02x:%02x:%02x:%02x", dev->name,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007273 sp->def_mac_addr[0].mac_addr[0],
7274 sp->def_mac_addr[0].mac_addr[1],
7275 sp->def_mac_addr[0].mac_addr[2],
7276 sp->def_mac_addr[0].mac_addr[3],
7277 sp->def_mac_addr[0].mac_addr[4],
7278 sp->def_mac_addr[0].mac_addr[5]);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007279 DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007280 if (sp->device_type & XFRAME_II_DEVICE) {
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07007281 mode = s2io_print_pci_mode(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007282 if (mode < 0) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04007283 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007284 ret = -EBADSLT;
Ananda Raju9dc737a2006-04-21 19:05:41 -04007285 unregister_netdev(dev);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007286 goto set_swap_failed;
7287 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007288 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04007289 switch(sp->rxd_mode) {
7290 case RXD_MODE_1:
7291 DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n",
7292 dev->name);
7293 break;
7294 case RXD_MODE_3B:
7295 DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n",
7296 dev->name);
7297 break;
7298 case RXD_MODE_3A:
7299 DBG_PRINT(ERR_DBG, "%s: 3-Buffer receive mode enabled\n",
7300 dev->name);
7301 break;
7302 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007303
7304 if (napi)
7305 DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007306 switch(sp->intr_type) {
7307 case INTA:
7308 DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
7309 break;
7310 case MSI:
7311 DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI\n", dev->name);
7312 break;
7313 case MSI_X:
7314 DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
7315 break;
7316 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007317 if (sp->lro)
7318 DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
Ananda Raju9dc737a2006-04-21 19:05:41 -04007319 dev->name);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007320 if (ufo)
7321 DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)"
7322 " enabled\n", dev->name);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007323 /* Initialize device name */
Ananda Raju9dc737a2006-04-21 19:05:41 -04007324 sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007325
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07007326 /* Initialize bimodal Interrupts */
7327 sp->config.bimodal = bimodal;
7328 if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) {
7329 sp->config.bimodal = 0;
7330 DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n",
7331 dev->name);
7332 }
7333
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007334 /*
7335 * Make Link state as off at this point, when the Link change
7336 * interrupt comes the state will be automatically changed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07007337 * the right state.
7338 */
7339 netif_carrier_off(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007340
7341 return 0;
7342
7343 register_failed:
7344 set_swap_failed:
7345 iounmap(sp->bar1);
7346 bar1_remap_failed:
7347 iounmap(sp->bar0);
7348 bar0_remap_failed:
7349 mem_alloc_failed:
7350 free_shared_mem(sp);
7351 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007352 if (dev_intr_type != MSI_X)
7353 pci_release_regions(pdev);
7354 else {
7355 release_mem_region(pci_resource_start(pdev, 0),
7356 pci_resource_len(pdev, 0));
7357 release_mem_region(pci_resource_start(pdev, 2),
7358 pci_resource_len(pdev, 2));
7359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007360 pci_set_drvdata(pdev, NULL);
7361 free_netdev(dev);
7362
7363 return ret;
7364}
7365
7366/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007367 * s2io_rem_nic - Free the PCI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07007368 * @pdev: structure containing the PCI related information of the device.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007369 * Description: This function is called by the Pci subsystem to release a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007370 * PCI device and free up all resource held up by the device. This could
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007371 * be in response to a Hot plug event or when the driver is to be removed
Linus Torvalds1da177e2005-04-16 15:20:36 -07007372 * from memory.
7373 */
7374
7375static void __devexit s2io_rem_nic(struct pci_dev *pdev)
7376{
7377 struct net_device *dev =
7378 (struct net_device *) pci_get_drvdata(pdev);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007379 struct s2io_nic *sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007380
7381 if (dev == NULL) {
7382 DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
7383 return;
7384 }
7385
Francois Romieu22747d62007-02-15 23:37:50 +01007386 flush_scheduled_work();
7387
Linus Torvalds1da177e2005-04-16 15:20:36 -07007388 sp = dev->priv;
7389 unregister_netdev(dev);
7390
7391 free_shared_mem(sp);
7392 iounmap(sp->bar0);
7393 iounmap(sp->bar1);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007394 if (sp->intr_type != MSI_X)
7395 pci_release_regions(pdev);
7396 else {
7397 release_mem_region(pci_resource_start(pdev, 0),
7398 pci_resource_len(pdev, 0));
7399 release_mem_region(pci_resource_start(pdev, 2),
7400 pci_resource_len(pdev, 2));
7401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007402 pci_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007403 free_netdev(dev);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007404 pci_disable_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007405}
7406
7407/**
7408 * s2io_starter - Entry point for the driver
7409 * Description: This function is the entry point for the driver. It verifies
7410 * the module loadable parameters and initializes PCI configuration space.
7411 */
7412
7413int __init s2io_starter(void)
7414{
Jeff Garzik29917622006-08-19 17:48:59 -04007415 return pci_register_driver(&s2io_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007416}
7417
7418/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007419 * s2io_closer - Cleanup routine for the driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07007420 * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
7421 */
7422
Sivakumar Subramani372cc592007-01-31 13:32:57 -05007423static __exit void s2io_closer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007424{
7425 pci_unregister_driver(&s2io_driver);
7426 DBG_PRINT(INIT_DBG, "cleanup done\n");
7427}
7428
7429module_init(s2io_starter);
7430module_exit(s2io_closer);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007431
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007432static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007433 struct tcphdr **tcp, struct RxD_t *rxdp)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007434{
7435 int ip_off;
7436 u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
7437
7438 if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) {
7439 DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n",
7440 __FUNCTION__);
7441 return -1;
7442 }
7443
7444 /* TODO:
7445 * By default the VLAN field in the MAC is stripped by the card, if this
7446 * feature is turned off in rx_pa_cfg register, then the ip_off field
7447 * has to be shifted by a further 2 bytes
7448 */
7449 switch (l2_type) {
7450 case 0: /* DIX type */
7451 case 4: /* DIX type with VLAN */
7452 ip_off = HEADER_ETHERNET_II_802_3_SIZE;
7453 break;
7454 /* LLC, SNAP etc are considered non-mergeable */
7455 default:
7456 return -1;
7457 }
7458
7459 *ip = (struct iphdr *)((u8 *)buffer + ip_off);
7460 ip_len = (u8)((*ip)->ihl);
7461 ip_len <<= 2;
7462 *tcp = (struct tcphdr *)((unsigned long)*ip + ip_len);
7463
7464 return 0;
7465}
7466
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007467static int check_for_socket_match(struct lro *lro, struct iphdr *ip,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007468 struct tcphdr *tcp)
7469{
7470 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7471 if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) ||
7472 (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest))
7473 return -1;
7474 return 0;
7475}
7476
7477static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
7478{
7479 return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
7480}
7481
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007482static void initiate_new_session(struct lro *lro, u8 *l2h,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007483 struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
7484{
7485 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7486 lro->l2h = l2h;
7487 lro->iph = ip;
7488 lro->tcph = tcp;
7489 lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq);
7490 lro->tcp_ack = ntohl(tcp->ack_seq);
7491 lro->sg_num = 1;
7492 lro->total_len = ntohs(ip->tot_len);
7493 lro->frags_len = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007494 /*
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007495 * check if we saw TCP timestamp. Other consistency checks have
7496 * already been done.
7497 */
7498 if (tcp->doff == 8) {
7499 u32 *ptr;
7500 ptr = (u32 *)(tcp+1);
7501 lro->saw_ts = 1;
7502 lro->cur_tsval = *(ptr+1);
7503 lro->cur_tsecr = *(ptr+2);
7504 }
7505 lro->in_use = 1;
7506}
7507
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007508static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007509{
7510 struct iphdr *ip = lro->iph;
7511 struct tcphdr *tcp = lro->tcph;
Al Virobd4f3ae2007-02-09 16:40:15 +00007512 __sum16 nchk;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007513 struct stat_block *statinfo = sp->mac_control.stats_info;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007514 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7515
7516 /* Update L3 header */
7517 ip->tot_len = htons(lro->total_len);
7518 ip->check = 0;
7519 nchk = ip_fast_csum((u8 *)lro->iph, ip->ihl);
7520 ip->check = nchk;
7521
7522 /* Update L4 header */
7523 tcp->ack_seq = lro->tcp_ack;
7524 tcp->window = lro->window;
7525
7526 /* Update tsecr field if this session has timestamps enabled */
7527 if (lro->saw_ts) {
7528 u32 *ptr = (u32 *)(tcp + 1);
7529 *(ptr+2) = lro->cur_tsecr;
7530 }
7531
7532 /* Update counters required for calculation of
7533 * average no. of packets aggregated.
7534 */
7535 statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num;
7536 statinfo->sw_stat.num_aggregations++;
7537}
7538
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007539static void aggregate_new_rx(struct lro *lro, struct iphdr *ip,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007540 struct tcphdr *tcp, u32 l4_pyld)
7541{
7542 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7543 lro->total_len += l4_pyld;
7544 lro->frags_len += l4_pyld;
7545 lro->tcp_next_seq += l4_pyld;
7546 lro->sg_num++;
7547
7548 /* Update ack seq no. and window ad(from this pkt) in LRO object */
7549 lro->tcp_ack = tcp->ack_seq;
7550 lro->window = tcp->window;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007551
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007552 if (lro->saw_ts) {
7553 u32 *ptr;
7554 /* Update tsecr and tsval from this packet */
7555 ptr = (u32 *) (tcp + 1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007556 lro->cur_tsval = *(ptr + 1);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007557 lro->cur_tsecr = *(ptr + 2);
7558 }
7559}
7560
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007561static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007562 struct tcphdr *tcp, u32 tcp_pyld_len)
7563{
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007564 u8 *ptr;
7565
Andrew Morton79dc1902006-02-03 01:45:13 -08007566 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7567
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007568 if (!tcp_pyld_len) {
7569 /* Runt frame or a pure ack */
7570 return -1;
7571 }
7572
7573 if (ip->ihl != 5) /* IP has options */
7574 return -1;
7575
Ananda Raju75c30b12006-07-24 19:55:09 -04007576 /* If we see CE codepoint in IP header, packet is not mergeable */
7577 if (INET_ECN_is_ce(ipv4_get_dsfield(ip)))
7578 return -1;
7579
7580 /* If we see ECE or CWR flags in TCP header, packet is not mergeable */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007581 if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin ||
Ananda Raju75c30b12006-07-24 19:55:09 -04007582 tcp->ece || tcp->cwr || !tcp->ack) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007583 /*
7584 * Currently recognize only the ack control word and
7585 * any other control field being set would result in
7586 * flushing the LRO session
7587 */
7588 return -1;
7589 }
7590
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007591 /*
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007592 * Allow only one TCP timestamp option. Don't aggregate if
7593 * any other options are detected.
7594 */
7595 if (tcp->doff != 5 && tcp->doff != 8)
7596 return -1;
7597
7598 if (tcp->doff == 8) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007599 ptr = (u8 *)(tcp + 1);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007600 while (*ptr == TCPOPT_NOP)
7601 ptr++;
7602 if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP)
7603 return -1;
7604
7605 /* Ensure timestamp value increases monotonically */
7606 if (l_lro)
7607 if (l_lro->cur_tsval > *((u32 *)(ptr+2)))
7608 return -1;
7609
7610 /* timestamp echo reply should be non-zero */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007611 if (*((u32 *)(ptr+6)) == 0)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007612 return -1;
7613 }
7614
7615 return 0;
7616}
7617
7618static int
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007619s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
7620 struct RxD_t *rxdp, struct s2io_nic *sp)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007621{
7622 struct iphdr *ip;
7623 struct tcphdr *tcph;
7624 int ret = 0, i;
7625
7626 if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp,
7627 rxdp))) {
7628 DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n",
7629 ip->saddr, ip->daddr);
7630 } else {
7631 return ret;
7632 }
7633
7634 tcph = (struct tcphdr *)*tcp;
7635 *tcp_len = get_l4_pyld_length(ip, tcph);
7636 for (i=0; i<MAX_LRO_SESSIONS; i++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007637 struct lro *l_lro = &sp->lro0_n[i];
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007638 if (l_lro->in_use) {
7639 if (check_for_socket_match(l_lro, ip, tcph))
7640 continue;
7641 /* Sock pair matched */
7642 *lro = l_lro;
7643
7644 if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) {
7645 DBG_PRINT(INFO_DBG, "%s:Out of order. expected "
7646 "0x%x, actual 0x%x\n", __FUNCTION__,
7647 (*lro)->tcp_next_seq,
7648 ntohl(tcph->seq));
7649
7650 sp->mac_control.stats_info->
7651 sw_stat.outof_sequence_pkts++;
7652 ret = 2;
7653 break;
7654 }
7655
7656 if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len))
7657 ret = 1; /* Aggregate */
7658 else
7659 ret = 2; /* Flush both */
7660 break;
7661 }
7662 }
7663
7664 if (ret == 0) {
7665 /* Before searching for available LRO objects,
7666 * check if the pkt is L3/L4 aggregatable. If not
7667 * don't create new LRO session. Just send this
7668 * packet up.
7669 */
7670 if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) {
7671 return 5;
7672 }
7673
7674 for (i=0; i<MAX_LRO_SESSIONS; i++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007675 struct lro *l_lro = &sp->lro0_n[i];
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007676 if (!(l_lro->in_use)) {
7677 *lro = l_lro;
7678 ret = 3; /* Begin anew */
7679 break;
7680 }
7681 }
7682 }
7683
7684 if (ret == 0) { /* sessions exceeded */
7685 DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n",
7686 __FUNCTION__);
7687 *lro = NULL;
7688 return ret;
7689 }
7690
7691 switch (ret) {
7692 case 3:
7693 initiate_new_session(*lro, buffer, ip, tcph, *tcp_len);
7694 break;
7695 case 2:
7696 update_L3L4_header(sp, *lro);
7697 break;
7698 case 1:
7699 aggregate_new_rx(*lro, ip, tcph, *tcp_len);
7700 if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) {
7701 update_L3L4_header(sp, *lro);
7702 ret = 4; /* Flush the LRO */
7703 }
7704 break;
7705 default:
7706 DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n",
7707 __FUNCTION__);
7708 break;
7709 }
7710
7711 return ret;
7712}
7713
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007714static void clear_lro_session(struct lro *lro)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007715{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007716 static u16 lro_struct_size = sizeof(struct lro);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007717
7718 memset(lro, 0, lro_struct_size);
7719}
7720
7721static void queue_rx_frame(struct sk_buff *skb)
7722{
7723 struct net_device *dev = skb->dev;
7724
7725 skb->protocol = eth_type_trans(skb, dev);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007726 if (napi)
7727 netif_receive_skb(skb);
7728 else
7729 netif_rx(skb);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007730}
7731
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007732static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
7733 struct sk_buff *skb,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007734 u32 tcp_len)
7735{
Ananda Raju75c30b12006-07-24 19:55:09 -04007736 struct sk_buff *first = lro->parent;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007737
7738 first->len += tcp_len;
7739 first->data_len = lro->frags_len;
7740 skb_pull(skb, (skb->len - tcp_len));
Ananda Raju75c30b12006-07-24 19:55:09 -04007741 if (skb_shinfo(first)->frag_list)
7742 lro->last_frag->next = skb;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007743 else
7744 skb_shinfo(first)->frag_list = skb;
Sivakumar Subramani372cc592007-01-31 13:32:57 -05007745 first->truesize += skb->truesize;
Ananda Raju75c30b12006-07-24 19:55:09 -04007746 lro->last_frag = skb;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007747 sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
7748 return;
7749}