blob: 3885f6b83cc31648724294571ab01b90f94c984a [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
Veena Parat6d517a22007-07-23 02:20:51 -040035 * values are 1, 2.
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),
Sivakumar Subramani8abc4d52007-09-15 13:11:34 -070040 * 2(MSI_X). Default value is '2(MSI_X)'
Ananda Raju9dc737a2006-04-21 19:05:41 -040041 * lro: Specifies whether to enable Large Receive Offload (LRO) or not.
42 * Possible values '1' for enable '0' for disable. Default is '0'
43 * lro_max_pkts: This parameter defines maximum number of packets can be
44 * aggregated as a single large packet
Sivakumar Subramani926930b2007-02-24 01:59:39 -050045 * napi: This parameter used to enable/disable NAPI (polling Rx)
46 * Possible values '1' for enable and '0' for disable. Default is '1'
47 * ufo: This parameter used to enable/disable UDP Fragmentation Offload(UFO)
48 * Possible values '1' for enable and '0' for disable. Default is '0'
49 * vlan_tag_strip: This can be used to enable or disable vlan stripping.
50 * Possible values '1' for enable , '0' for disable.
51 * Default is '2' - which means disable in promisc mode
52 * and enable in non-promiscuous mode.
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 ************************************************************************/
54
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#include <linux/module.h>
56#include <linux/types.h>
57#include <linux/errno.h>
58#include <linux/ioport.h>
59#include <linux/pci.h>
Domen Puncer1e7f0bd2005-06-26 18:22:14 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <linux/kernel.h>
62#include <linux/netdevice.h>
63#include <linux/etherdevice.h>
64#include <linux/skbuff.h>
65#include <linux/init.h>
66#include <linux/delay.h>
67#include <linux/stddef.h>
68#include <linux/ioctl.h>
69#include <linux/timex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#include <linux/ethtool.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#include <linux/workqueue.h>
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -070072#include <linux/if_vlan.h>
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -050073#include <linux/ip.h>
74#include <linux/tcp.h>
75#include <net/tcp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
Linus Torvalds1da177e2005-04-16 15:20:36 -070077#include <asm/system.h>
78#include <asm/uaccess.h>
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070079#include <asm/io.h>
Andrew Mortonfe931392006-02-03 01:45:12 -080080#include <asm/div64.h>
Andrew Morton330ce0d2006-08-14 23:00:14 -070081#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83/* local include */
84#include "s2io.h"
85#include "s2io-regs.h"
86
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -040087#define DRV_VERSION "2.0.26.4"
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
Veena Parat6d517a22007-07-23 02:20:51 -040093static int rxd_size[2] = {32,48};
94static int rxd_count[2] = {127,85};
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
Sivakumar Subramani92b84432007-09-06 06:51:14 -0400133static inline int is_s2io_card_up(const struct s2io_nic * sp)
134{
135 return test_bit(__S2IO_STATE_CARD_UP, &sp->state);
136}
137
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138/* Ethtool related variables and Macros. */
139static char s2io_gstrings[][ETH_GSTRING_LEN] = {
140 "Register test\t(offline)",
141 "Eeprom test\t(offline)",
142 "Link test\t(online)",
143 "RLDRAM test\t(offline)",
144 "BIST Test\t(offline)"
145};
146
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -0500147static char ethtool_xena_stats_keys[][ETH_GSTRING_LEN] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 {"tmac_frms"},
149 {"tmac_data_octets"},
150 {"tmac_drop_frms"},
151 {"tmac_mcst_frms"},
152 {"tmac_bcst_frms"},
153 {"tmac_pause_ctrl_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400154 {"tmac_ttl_octets"},
155 {"tmac_ucst_frms"},
156 {"tmac_nucst_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 {"tmac_any_err_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400158 {"tmac_ttl_less_fb_octets"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 {"tmac_vld_ip_octets"},
160 {"tmac_vld_ip"},
161 {"tmac_drop_ip"},
162 {"tmac_icmp"},
163 {"tmac_rst_tcp"},
164 {"tmac_tcp"},
165 {"tmac_udp"},
166 {"rmac_vld_frms"},
167 {"rmac_data_octets"},
168 {"rmac_fcs_err_frms"},
169 {"rmac_drop_frms"},
170 {"rmac_vld_mcst_frms"},
171 {"rmac_vld_bcst_frms"},
172 {"rmac_in_rng_len_err_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400173 {"rmac_out_rng_len_err_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 {"rmac_long_frms"},
175 {"rmac_pause_ctrl_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400176 {"rmac_unsup_ctrl_frms"},
177 {"rmac_ttl_octets"},
178 {"rmac_accepted_ucst_frms"},
179 {"rmac_accepted_nucst_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 {"rmac_discarded_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400181 {"rmac_drop_events"},
182 {"rmac_ttl_less_fb_octets"},
183 {"rmac_ttl_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 {"rmac_usized_frms"},
185 {"rmac_osized_frms"},
186 {"rmac_frag_frms"},
187 {"rmac_jabber_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400188 {"rmac_ttl_64_frms"},
189 {"rmac_ttl_65_127_frms"},
190 {"rmac_ttl_128_255_frms"},
191 {"rmac_ttl_256_511_frms"},
192 {"rmac_ttl_512_1023_frms"},
193 {"rmac_ttl_1024_1518_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 {"rmac_ip"},
195 {"rmac_ip_octets"},
196 {"rmac_hdr_err_ip"},
197 {"rmac_drop_ip"},
198 {"rmac_icmp"},
199 {"rmac_tcp"},
200 {"rmac_udp"},
201 {"rmac_err_drp_udp"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400202 {"rmac_xgmii_err_sym"},
203 {"rmac_frms_q0"},
204 {"rmac_frms_q1"},
205 {"rmac_frms_q2"},
206 {"rmac_frms_q3"},
207 {"rmac_frms_q4"},
208 {"rmac_frms_q5"},
209 {"rmac_frms_q6"},
210 {"rmac_frms_q7"},
211 {"rmac_full_q0"},
212 {"rmac_full_q1"},
213 {"rmac_full_q2"},
214 {"rmac_full_q3"},
215 {"rmac_full_q4"},
216 {"rmac_full_q5"},
217 {"rmac_full_q6"},
218 {"rmac_full_q7"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 {"rmac_pause_cnt"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400220 {"rmac_xgmii_data_err_cnt"},
221 {"rmac_xgmii_ctrl_err_cnt"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 {"rmac_accepted_ip"},
223 {"rmac_err_tcp"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400224 {"rd_req_cnt"},
225 {"new_rd_req_cnt"},
226 {"new_rd_req_rtry_cnt"},
227 {"rd_rtry_cnt"},
228 {"wr_rtry_rd_ack_cnt"},
229 {"wr_req_cnt"},
230 {"new_wr_req_cnt"},
231 {"new_wr_req_rtry_cnt"},
232 {"wr_rtry_cnt"},
233 {"wr_disc_cnt"},
234 {"rd_rtry_wr_ack_cnt"},
235 {"txp_wr_cnt"},
236 {"txd_rd_cnt"},
237 {"txd_wr_cnt"},
238 {"rxd_rd_cnt"},
239 {"rxd_wr_cnt"},
240 {"txf_rd_cnt"},
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -0500241 {"rxf_wr_cnt"}
242};
243
244static char ethtool_enhanced_stats_keys[][ETH_GSTRING_LEN] = {
Ananda Rajubd1034f2006-04-21 19:20:22 -0400245 {"rmac_ttl_1519_4095_frms"},
246 {"rmac_ttl_4096_8191_frms"},
247 {"rmac_ttl_8192_max_frms"},
248 {"rmac_ttl_gt_max_frms"},
249 {"rmac_osized_alt_frms"},
250 {"rmac_jabber_alt_frms"},
251 {"rmac_gt_max_alt_frms"},
252 {"rmac_vlan_frms"},
253 {"rmac_len_discard"},
254 {"rmac_fcs_discard"},
255 {"rmac_pf_discard"},
256 {"rmac_da_discard"},
257 {"rmac_red_discard"},
258 {"rmac_rts_discard"},
259 {"rmac_ingm_full_discard"},
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -0500260 {"link_fault_cnt"}
261};
262
263static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -0700264 {"\n DRIVER STATISTICS"},
265 {"single_bit_ecc_errs"},
266 {"double_bit_ecc_errs"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400267 {"parity_err_cnt"},
268 {"serious_err_cnt"},
269 {"soft_reset_cnt"},
270 {"fifo_full_cnt"},
Sivakumar Subramani8116f3c2007-09-17 13:05:35 -0700271 {"ring_0_full_cnt"},
272 {"ring_1_full_cnt"},
273 {"ring_2_full_cnt"},
274 {"ring_3_full_cnt"},
275 {"ring_4_full_cnt"},
276 {"ring_5_full_cnt"},
277 {"ring_6_full_cnt"},
278 {"ring_7_full_cnt"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400279 ("alarm_transceiver_temp_high"),
280 ("alarm_transceiver_temp_low"),
281 ("alarm_laser_bias_current_high"),
282 ("alarm_laser_bias_current_low"),
283 ("alarm_laser_output_power_high"),
284 ("alarm_laser_output_power_low"),
285 ("warn_transceiver_temp_high"),
286 ("warn_transceiver_temp_low"),
287 ("warn_laser_bias_current_high"),
288 ("warn_laser_bias_current_low"),
289 ("warn_laser_output_power_high"),
290 ("warn_laser_output_power_low"),
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -0500291 ("lro_aggregated_pkts"),
292 ("lro_flush_both_count"),
293 ("lro_out_of_sequence_pkts"),
294 ("lro_flush_due_to_max_pkts"),
295 ("lro_avg_aggr_pkts"),
Sreenivasa Honnurc53d4942007-05-10 04:18:54 -0400296 ("mem_alloc_fail_cnt"),
Veena Parat491abf22007-07-23 02:37:14 -0400297 ("pci_map_fail_cnt"),
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400298 ("watchdog_timer_cnt"),
299 ("mem_allocated"),
300 ("mem_freed"),
301 ("link_up_cnt"),
302 ("link_down_cnt"),
303 ("link_up_time"),
304 ("link_down_time"),
305 ("tx_tcode_buf_abort_cnt"),
306 ("tx_tcode_desc_abort_cnt"),
307 ("tx_tcode_parity_err_cnt"),
308 ("tx_tcode_link_loss_cnt"),
309 ("tx_tcode_list_proc_err_cnt"),
310 ("rx_tcode_parity_err_cnt"),
311 ("rx_tcode_abort_cnt"),
312 ("rx_tcode_parity_abort_cnt"),
313 ("rx_tcode_rda_fail_cnt"),
314 ("rx_tcode_unkn_prot_cnt"),
315 ("rx_tcode_fcs_err_cnt"),
316 ("rx_tcode_buf_size_err_cnt"),
317 ("rx_tcode_rxd_corrupt_cnt"),
Sivakumar Subramani8116f3c2007-09-17 13:05:35 -0700318 ("rx_tcode_unkn_err_cnt"),
319 {"tda_err_cnt"},
320 {"pfc_err_cnt"},
321 {"pcc_err_cnt"},
322 {"tti_err_cnt"},
323 {"tpa_err_cnt"},
324 {"sm_err_cnt"},
325 {"lso_err_cnt"},
326 {"mac_tmac_err_cnt"},
327 {"mac_rmac_err_cnt"},
328 {"xgxs_txgxs_err_cnt"},
329 {"xgxs_rxgxs_err_cnt"},
330 {"rc_err_cnt"},
331 {"prc_pcix_err_cnt"},
332 {"rpa_err_cnt"},
333 {"rda_err_cnt"},
334 {"rti_err_cnt"},
335 {"mc_err_cnt"}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336};
337
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -0500338#define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN
339#define S2IO_ENHANCED_STAT_LEN sizeof(ethtool_enhanced_stats_keys)/ \
340 ETH_GSTRING_LEN
341#define S2IO_DRIVER_STAT_LEN sizeof(ethtool_driver_stats_keys)/ ETH_GSTRING_LEN
342
343#define XFRAME_I_STAT_LEN (S2IO_XENA_STAT_LEN + S2IO_DRIVER_STAT_LEN )
344#define XFRAME_II_STAT_LEN (XFRAME_I_STAT_LEN + S2IO_ENHANCED_STAT_LEN )
345
346#define XFRAME_I_STAT_STRINGS_LEN ( XFRAME_I_STAT_LEN * ETH_GSTRING_LEN )
347#define XFRAME_II_STAT_STRINGS_LEN ( XFRAME_II_STAT_LEN * ETH_GSTRING_LEN )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349#define S2IO_TEST_LEN sizeof(s2io_gstrings) / ETH_GSTRING_LEN
350#define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN
351
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -0700352#define S2IO_TIMER_CONF(timer, handle, arg, exp) \
353 init_timer(&timer); \
354 timer.function = handle; \
355 timer.data = (unsigned long) arg; \
356 mod_timer(&timer, (jiffies + exp)) \
357
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -0700358/* Add the vlan */
359static void s2io_vlan_rx_register(struct net_device *dev,
360 struct vlan_group *grp)
361{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500362 struct s2io_nic *nic = dev->priv;
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -0700363 unsigned long flags;
364
365 spin_lock_irqsave(&nic->tx_lock, flags);
366 nic->vlgrp = grp;
367 spin_unlock_irqrestore(&nic->tx_lock, flags);
368}
369
Sivakumar Subramani926930b2007-02-24 01:59:39 -0500370/* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */
Adrian Bunk7b490342007-03-05 02:49:25 +0100371static int vlan_strip_flag;
Sivakumar Subramani926930b2007-02-24 01:59:39 -0500372
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700373/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 * Constants to be programmed into the Xena's registers, to configure
375 * the XAUI.
376 */
377
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378#define END_SIGN 0x0
Arjan van de Venf71e1302006-03-03 21:33:57 -0500379static const u64 herc_act_dtx_cfg[] = {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700380 /* Set address */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700381 0x8000051536750000ULL, 0x80000515367500E0ULL,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700382 /* Write data */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700383 0x8000051536750004ULL, 0x80000515367500E4ULL,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700384 /* Set address */
385 0x80010515003F0000ULL, 0x80010515003F00E0ULL,
386 /* Write data */
387 0x80010515003F0004ULL, 0x80010515003F00E4ULL,
388 /* Set address */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700389 0x801205150D440000ULL, 0x801205150D4400E0ULL,
390 /* Write data */
391 0x801205150D440004ULL, 0x801205150D4400E4ULL,
392 /* Set address */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700393 0x80020515F2100000ULL, 0x80020515F21000E0ULL,
394 /* Write data */
395 0x80020515F2100004ULL, 0x80020515F21000E4ULL,
396 /* Done */
397 END_SIGN
398};
399
Arjan van de Venf71e1302006-03-03 21:33:57 -0500400static const u64 xena_dtx_cfg[] = {
Ananda Rajuc92ca042006-04-21 19:18:03 -0400401 /* Set address */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 0x8000051500000000ULL, 0x80000515000000E0ULL,
Ananda Rajuc92ca042006-04-21 19:18:03 -0400403 /* Write data */
404 0x80000515D9350004ULL, 0x80000515D93500E4ULL,
405 /* Set address */
406 0x8001051500000000ULL, 0x80010515000000E0ULL,
407 /* Write data */
408 0x80010515001E0004ULL, 0x80010515001E00E4ULL,
409 /* Set address */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 0x8002051500000000ULL, 0x80020515000000E0ULL,
Ananda Rajuc92ca042006-04-21 19:18:03 -0400411 /* Write data */
412 0x80020515F2100004ULL, 0x80020515F21000E4ULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 END_SIGN
414};
415
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700416/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 * Constants for Fixing the MacAddress problem seen mostly on
418 * Alpha machines.
419 */
Arjan van de Venf71e1302006-03-03 21:33:57 -0500420static const u64 fix_mac[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 0x0060000000000000ULL, 0x0060600000000000ULL,
422 0x0040600000000000ULL, 0x0000600000000000ULL,
423 0x0020600000000000ULL, 0x0060600000000000ULL,
424 0x0020600000000000ULL, 0x0060600000000000ULL,
425 0x0020600000000000ULL, 0x0060600000000000ULL,
426 0x0020600000000000ULL, 0x0060600000000000ULL,
427 0x0020600000000000ULL, 0x0060600000000000ULL,
428 0x0020600000000000ULL, 0x0060600000000000ULL,
429 0x0020600000000000ULL, 0x0060600000000000ULL,
430 0x0020600000000000ULL, 0x0060600000000000ULL,
431 0x0020600000000000ULL, 0x0060600000000000ULL,
432 0x0020600000000000ULL, 0x0060600000000000ULL,
433 0x0020600000000000ULL, 0x0000600000000000ULL,
434 0x0040600000000000ULL, 0x0060600000000000ULL,
435 END_SIGN
436};
437
Ananda Rajub41477f2006-07-24 19:52:49 -0400438MODULE_LICENSE("GPL");
439MODULE_VERSION(DRV_VERSION);
440
441
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442/* Module Loadable parameters. */
Ananda Rajub41477f2006-07-24 19:52:49 -0400443S2IO_PARM_INT(tx_fifo_num, 1);
444S2IO_PARM_INT(rx_ring_num, 1);
445
446
447S2IO_PARM_INT(rx_ring_mode, 1);
448S2IO_PARM_INT(use_continuous_tx_intrs, 1);
449S2IO_PARM_INT(rmac_pause_time, 0x100);
450S2IO_PARM_INT(mc_pause_threshold_q0q3, 187);
451S2IO_PARM_INT(mc_pause_threshold_q4q7, 187);
452S2IO_PARM_INT(shared_splits, 0);
453S2IO_PARM_INT(tmac_util_period, 5);
454S2IO_PARM_INT(rmac_util_period, 5);
Ananda Rajub41477f2006-07-24 19:52:49 -0400455S2IO_PARM_INT(l3l4hdr_size, 128);
456/* Frequency of Rx desc syncs expressed as power of 2 */
457S2IO_PARM_INT(rxsync_frequency, 3);
Veena Parateccb8622007-07-23 02:23:54 -0400458/* Interrupt type. Values can be 0(INTA), 2(MSI_X) */
Sivakumar Subramani8abc4d52007-09-15 13:11:34 -0700459S2IO_PARM_INT(intr_type, 2);
Ananda Rajub41477f2006-07-24 19:52:49 -0400460/* Large receive offload feature */
461S2IO_PARM_INT(lro, 0);
462/* Max pkts to be aggregated by LRO at one time. If not specified,
463 * aggregation happens until we hit max IP pkt size(64K)
464 */
465S2IO_PARM_INT(lro_max_pkts, 0xFFFF);
Ananda Rajub41477f2006-07-24 19:52:49 -0400466S2IO_PARM_INT(indicate_max_pkts, 0);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -0500467
468S2IO_PARM_INT(napi, 1);
469S2IO_PARM_INT(ufo, 0);
Sivakumar Subramani926930b2007-02-24 01:59:39 -0500470S2IO_PARM_INT(vlan_tag_strip, NO_STRIP_IN_PROMISC);
Ananda Rajub41477f2006-07-24 19:52:49 -0400471
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
Ananda Raju9dc737a2006-04-21 19:05:41 -0400473 {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474static unsigned int rx_ring_sz[MAX_RX_RINGS] =
Ananda Raju9dc737a2006-04-21 19:05:41 -0400475 {[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT};
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700476static unsigned int rts_frm_len[MAX_RX_RINGS] =
477 {[0 ...(MAX_RX_RINGS - 1)] = 0 };
Ananda Rajub41477f2006-07-24 19:52:49 -0400478
479module_param_array(tx_fifo_len, uint, NULL, 0);
480module_param_array(rx_ring_sz, uint, NULL, 0);
481module_param_array(rts_frm_len, uint, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700483/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 * S2IO device table.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700485 * This table lists all the devices that this driver supports.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 */
487static struct pci_device_id s2io_tbl[] __devinitdata = {
488 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN,
489 PCI_ANY_ID, PCI_ANY_ID},
490 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI,
491 PCI_ANY_ID, PCI_ANY_ID},
492 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700493 PCI_ANY_ID, PCI_ANY_ID},
494 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI,
495 PCI_ANY_ID, PCI_ANY_ID},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 {0,}
497};
498
499MODULE_DEVICE_TABLE(pci, s2io_tbl);
500
Linas Vepstasd796fdb2007-05-14 18:37:30 -0500501static struct pci_error_handlers s2io_err_handler = {
502 .error_detected = s2io_io_error_detected,
503 .slot_reset = s2io_io_slot_reset,
504 .resume = s2io_io_resume,
505};
506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507static struct pci_driver s2io_driver = {
508 .name = "S2IO",
509 .id_table = s2io_tbl,
510 .probe = s2io_init_nic,
511 .remove = __devexit_p(s2io_rem_nic),
Linas Vepstasd796fdb2007-05-14 18:37:30 -0500512 .err_handler = &s2io_err_handler,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513};
514
515/* A simplifier macro used both by init and free shared_mem Fns(). */
516#define TXD_MEM_PAGE_CNT(len, per_each) ((len+per_each - 1) / per_each)
517
518/**
519 * init_shared_mem - Allocation and Initialization of Memory
520 * @nic: Device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700521 * Description: The function allocates all the memory areas shared
522 * between the NIC and the driver. This includes Tx descriptors,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 * Rx descriptors and the statistics block.
524 */
525
526static int init_shared_mem(struct s2io_nic *nic)
527{
528 u32 size;
529 void *tmp_v_addr, *tmp_v_addr_next;
530 dma_addr_t tmp_p_addr, tmp_p_addr_next;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500531 struct RxD_block *pre_rxd_blk = NULL;
Sivakumar Subramani372cc592007-01-31 13:32:57 -0500532 int i, j, blk_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 int lst_size, lst_per_page;
534 struct net_device *dev = nic->dev;
viro@zenIV.linux.org.uk8ae418c2005-09-02 20:15:29 +0100535 unsigned long tmp;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500536 struct buffAdd *ba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500538 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 struct config_param *config;
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400540 unsigned long long mem_allocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
542 mac_control = &nic->mac_control;
543 config = &nic->config;
544
545
546 /* Allocation and initialization of TXDLs in FIOFs */
547 size = 0;
548 for (i = 0; i < config->tx_fifo_num; i++) {
549 size += config->tx_cfg[i].fifo_len;
550 }
551 if (size > MAX_AVAILABLE_TXDS) {
Ananda Rajub41477f2006-07-24 19:52:49 -0400552 DBG_PRINT(ERR_DBG, "s2io: Requested TxDs too high, ");
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -0700553 DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size);
Ananda Rajub41477f2006-07-24 19:52:49 -0400554 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 }
556
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500557 lst_size = (sizeof(struct TxD) * config->max_txds);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 lst_per_page = PAGE_SIZE / lst_size;
559
560 for (i = 0; i < config->tx_fifo_num; i++) {
561 int fifo_len = config->tx_cfg[i].fifo_len;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500562 int list_holder_size = fifo_len * sizeof(struct list_info_hold);
Sivakumar Subramanibd684e42007-09-14 07:28:50 -0400563 mac_control->fifos[i].list_info = kzalloc(list_holder_size,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700564 GFP_KERNEL);
565 if (!mac_control->fifos[i].list_info) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -0800566 DBG_PRINT(INFO_DBG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 "Malloc failed for list_info\n");
568 return -ENOMEM;
569 }
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400570 mem_allocated += list_holder_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 }
572 for (i = 0; i < config->tx_fifo_num; i++) {
573 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
574 lst_per_page);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700575 mac_control->fifos[i].tx_curr_put_info.offset = 0;
576 mac_control->fifos[i].tx_curr_put_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700578 mac_control->fifos[i].tx_curr_get_info.offset = 0;
579 mac_control->fifos[i].tx_curr_get_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700581 mac_control->fifos[i].fifo_no = i;
582 mac_control->fifos[i].nic = nic;
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500583 mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 2;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 for (j = 0; j < page_num; j++) {
586 int k = 0;
587 dma_addr_t tmp_p;
588 void *tmp_v;
589 tmp_v = pci_alloc_consistent(nic->pdev,
590 PAGE_SIZE, &tmp_p);
591 if (!tmp_v) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -0800592 DBG_PRINT(INFO_DBG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 "pci_alloc_consistent ");
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -0800594 DBG_PRINT(INFO_DBG, "failed for TxDL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 return -ENOMEM;
596 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700597 /* If we got a zero DMA address(can happen on
598 * certain platforms like PPC), reallocate.
599 * Store virtual address of page we don't want,
600 * to be freed later.
601 */
602 if (!tmp_p) {
603 mac_control->zerodma_virt_addr = tmp_v;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400604 DBG_PRINT(INIT_DBG,
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700605 "%s: Zero DMA address for TxDL. ", dev->name);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400606 DBG_PRINT(INIT_DBG,
Andrew Morton6b4d6172005-09-12 23:21:55 -0700607 "Virtual address %p\n", tmp_v);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700608 tmp_v = pci_alloc_consistent(nic->pdev,
609 PAGE_SIZE, &tmp_p);
610 if (!tmp_v) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -0800611 DBG_PRINT(INFO_DBG,
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700612 "pci_alloc_consistent ");
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -0800613 DBG_PRINT(INFO_DBG, "failed for TxDL\n");
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700614 return -ENOMEM;
615 }
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400616 mem_allocated += PAGE_SIZE;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 while (k < lst_per_page) {
619 int l = (j * lst_per_page) + k;
620 if (l == config->tx_cfg[i].fifo_len)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700621 break;
622 mac_control->fifos[i].list_info[l].list_virt_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 tmp_v + (k * lst_size);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700624 mac_control->fifos[i].list_info[l].list_phy_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 tmp_p + (k * lst_size);
626 k++;
627 }
628 }
629 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
Al Viro43842472007-01-23 12:25:08 +0000631 nic->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL);
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500632 if (!nic->ufo_in_band_v)
633 return -ENOMEM;
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400634 mem_allocated += (size * sizeof(u64));
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500635
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 /* Allocation and initialization of RXDs in Rings */
637 size = 0;
638 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -0500639 if (config->rx_cfg[i].num_rxd %
640 (rxd_count[nic->rxd_mode] + 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 DBG_PRINT(ERR_DBG, "%s: RxD count of ", dev->name);
642 DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ",
643 i);
644 DBG_PRINT(ERR_DBG, "RxDs per Block");
645 return FAILURE;
646 }
647 size += config->rx_cfg[i].num_rxd;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700648 mac_control->rings[i].block_count =
Ananda Rajuda6971d2005-10-31 16:55:31 -0500649 config->rx_cfg[i].num_rxd /
650 (rxd_count[nic->rxd_mode] + 1 );
651 mac_control->rings[i].pkt_cnt = config->rx_cfg[i].num_rxd -
652 mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500654 if (nic->rxd_mode == RXD_MODE_1)
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500655 size = (size * (sizeof(struct RxD1)));
Ananda Rajuda6971d2005-10-31 16:55:31 -0500656 else
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500657 size = (size * (sizeof(struct RxD3)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
659 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700660 mac_control->rings[i].rx_curr_get_info.block_index = 0;
661 mac_control->rings[i].rx_curr_get_info.offset = 0;
662 mac_control->rings[i].rx_curr_get_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700664 mac_control->rings[i].rx_curr_put_info.block_index = 0;
665 mac_control->rings[i].rx_curr_put_info.offset = 0;
666 mac_control->rings[i].rx_curr_put_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700668 mac_control->rings[i].nic = nic;
669 mac_control->rings[i].ring_no = i;
670
Ananda Rajuda6971d2005-10-31 16:55:31 -0500671 blk_cnt = config->rx_cfg[i].num_rxd /
672 (rxd_count[nic->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 /* Allocating all the Rx blocks */
674 for (j = 0; j < blk_cnt; j++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500675 struct rx_block_info *rx_blocks;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500676 int l;
677
678 rx_blocks = &mac_control->rings[i].rx_blocks[j];
679 size = SIZE_OF_BLOCK; //size is always page size
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 tmp_v_addr = pci_alloc_consistent(nic->pdev, size,
681 &tmp_p_addr);
682 if (tmp_v_addr == NULL) {
683 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700684 * In case of failure, free_shared_mem()
685 * is called, which should free any
686 * memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 * failure happened.
688 */
Ananda Rajuda6971d2005-10-31 16:55:31 -0500689 rx_blocks->block_virt_addr = tmp_v_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 return -ENOMEM;
691 }
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400692 mem_allocated += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 memset(tmp_v_addr, 0, size);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500694 rx_blocks->block_virt_addr = tmp_v_addr;
695 rx_blocks->block_dma_addr = tmp_p_addr;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500696 rx_blocks->rxds = kmalloc(sizeof(struct rxd_info)*
Ananda Rajuda6971d2005-10-31 16:55:31 -0500697 rxd_count[nic->rxd_mode],
698 GFP_KERNEL);
Sivakumar Subramani372cc592007-01-31 13:32:57 -0500699 if (!rx_blocks->rxds)
700 return -ENOMEM;
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -0400701 mem_allocated +=
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400702 (sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500703 for (l=0; l<rxd_count[nic->rxd_mode];l++) {
704 rx_blocks->rxds[l].virt_addr =
705 rx_blocks->block_virt_addr +
706 (rxd_size[nic->rxd_mode] * l);
707 rx_blocks->rxds[l].dma_addr =
708 rx_blocks->block_dma_addr +
709 (rxd_size[nic->rxd_mode] * l);
710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 }
712 /* Interlinking all Rx Blocks */
713 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700714 tmp_v_addr =
715 mac_control->rings[i].rx_blocks[j].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 tmp_v_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700717 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 blk_cnt].block_virt_addr;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700719 tmp_p_addr =
720 mac_control->rings[i].rx_blocks[j].block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 tmp_p_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700722 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 blk_cnt].block_dma_addr;
724
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500725 pre_rxd_blk = (struct RxD_block *) tmp_v_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 pre_rxd_blk->reserved_2_pNext_RxD_block =
727 (unsigned long) tmp_v_addr_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 pre_rxd_blk->pNext_RxD_Blk_physical =
729 (u64) tmp_p_addr_next;
730 }
731 }
Veena Parat6d517a22007-07-23 02:20:51 -0400732 if (nic->rxd_mode == RXD_MODE_3B) {
Ananda Rajuda6971d2005-10-31 16:55:31 -0500733 /*
734 * Allocation of Storages for buffer addresses in 2BUFF mode
735 * and the buffers as well.
736 */
737 for (i = 0; i < config->rx_ring_num; i++) {
738 blk_cnt = config->rx_cfg[i].num_rxd /
739 (rxd_count[nic->rxd_mode]+ 1);
740 mac_control->rings[i].ba =
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500741 kmalloc((sizeof(struct buffAdd *) * blk_cnt),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 GFP_KERNEL);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500743 if (!mac_control->rings[i].ba)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 return -ENOMEM;
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400745 mem_allocated +=(sizeof(struct buffAdd *) * blk_cnt);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500746 for (j = 0; j < blk_cnt; j++) {
747 int k = 0;
748 mac_control->rings[i].ba[j] =
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500749 kmalloc((sizeof(struct buffAdd) *
Ananda Rajuda6971d2005-10-31 16:55:31 -0500750 (rxd_count[nic->rxd_mode] + 1)),
751 GFP_KERNEL);
752 if (!mac_control->rings[i].ba[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 return -ENOMEM;
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400754 mem_allocated += (sizeof(struct buffAdd) * \
755 (rxd_count[nic->rxd_mode] + 1));
Ananda Rajuda6971d2005-10-31 16:55:31 -0500756 while (k != rxd_count[nic->rxd_mode]) {
757 ba = &mac_control->rings[i].ba[j][k];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Ananda Rajuda6971d2005-10-31 16:55:31 -0500759 ba->ba_0_org = (void *) kmalloc
760 (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
761 if (!ba->ba_0_org)
762 return -ENOMEM;
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -0400763 mem_allocated +=
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400764 (BUF0_LEN + ALIGN_SIZE);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500765 tmp = (unsigned long)ba->ba_0_org;
766 tmp += ALIGN_SIZE;
767 tmp &= ~((unsigned long) ALIGN_SIZE);
768 ba->ba_0 = (void *) tmp;
769
770 ba->ba_1_org = (void *) kmalloc
771 (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
772 if (!ba->ba_1_org)
773 return -ENOMEM;
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -0400774 mem_allocated
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400775 += (BUF1_LEN + ALIGN_SIZE);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500776 tmp = (unsigned long) ba->ba_1_org;
777 tmp += ALIGN_SIZE;
778 tmp &= ~((unsigned long) ALIGN_SIZE);
779 ba->ba_1 = (void *) tmp;
780 k++;
781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 }
783 }
784 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
786 /* Allocation and initialization of Statistics block */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500787 size = sizeof(struct stat_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 mac_control->stats_mem = pci_alloc_consistent
789 (nic->pdev, size, &mac_control->stats_mem_phy);
790
791 if (!mac_control->stats_mem) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700792 /*
793 * In case of failure, free_shared_mem() is called, which
794 * should free any memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 * failure happened.
796 */
797 return -ENOMEM;
798 }
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400799 mem_allocated += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 mac_control->stats_mem_sz = size;
801
802 tmp_v_addr = mac_control->stats_mem;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500803 mac_control->stats_info = (struct stat_block *) tmp_v_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 memset(tmp_v_addr, 0, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name,
806 (unsigned long long) tmp_p_addr);
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400807 mac_control->stats_info->sw_stat.mem_allocated += mem_allocated;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 return SUCCESS;
809}
810
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700811/**
812 * free_shared_mem - Free the allocated Memory
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 * @nic: Device private variable.
814 * Description: This function is to free all memory locations allocated by
815 * the init_shared_mem() function and return it to the kernel.
816 */
817
818static void free_shared_mem(struct s2io_nic *nic)
819{
820 int i, j, blk_cnt, size;
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400821 u32 ufo_size = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 void *tmp_v_addr;
823 dma_addr_t tmp_p_addr;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500824 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 struct config_param *config;
826 int lst_size, lst_per_page;
Micah Gruber8910b492007-07-09 11:29:04 +0800827 struct net_device *dev;
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400828 int page_num = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830 if (!nic)
831 return;
832
Micah Gruber8910b492007-07-09 11:29:04 +0800833 dev = nic->dev;
834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 mac_control = &nic->mac_control;
836 config = &nic->config;
837
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500838 lst_size = (sizeof(struct TxD) * config->max_txds);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 lst_per_page = PAGE_SIZE / lst_size;
840
841 for (i = 0; i < config->tx_fifo_num; i++) {
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400842 ufo_size += config->tx_cfg[i].fifo_len;
843 page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
844 lst_per_page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 for (j = 0; j < page_num; j++) {
846 int mem_blks = (j * lst_per_page);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700847 if (!mac_control->fifos[i].list_info)
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400848 return;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700849 if (!mac_control->fifos[i].list_info[mem_blks].
850 list_virt_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 break;
852 pci_free_consistent(nic->pdev, PAGE_SIZE,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700853 mac_control->fifos[i].
854 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 list_virt_addr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700856 mac_control->fifos[i].
857 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 list_phy_addr);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -0400859 nic->mac_control.stats_info->sw_stat.mem_freed
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400860 += PAGE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700862 /* If we got a zero DMA address during allocation,
863 * free the page now
864 */
865 if (mac_control->zerodma_virt_addr) {
866 pci_free_consistent(nic->pdev, PAGE_SIZE,
867 mac_control->zerodma_virt_addr,
868 (dma_addr_t)0);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400869 DBG_PRINT(INIT_DBG,
Andrew Morton6b4d6172005-09-12 23:21:55 -0700870 "%s: Freeing TxDL with zero DMA addr. ",
871 dev->name);
872 DBG_PRINT(INIT_DBG, "Virtual address %p\n",
873 mac_control->zerodma_virt_addr);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -0400874 nic->mac_control.stats_info->sw_stat.mem_freed
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400875 += PAGE_SIZE;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700876 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700877 kfree(mac_control->fifos[i].list_info);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -0400878 nic->mac_control.stats_info->sw_stat.mem_freed +=
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400879 (nic->config.tx_cfg[i].fifo_len *sizeof(struct list_info_hold));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 }
881
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 size = SIZE_OF_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700884 blk_cnt = mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700886 tmp_v_addr = mac_control->rings[i].rx_blocks[j].
887 block_virt_addr;
888 tmp_p_addr = mac_control->rings[i].rx_blocks[j].
889 block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 if (tmp_v_addr == NULL)
891 break;
892 pci_free_consistent(nic->pdev, size,
893 tmp_v_addr, tmp_p_addr);
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400894 nic->mac_control.stats_info->sw_stat.mem_freed += size;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500895 kfree(mac_control->rings[i].rx_blocks[j].rxds);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -0400896 nic->mac_control.stats_info->sw_stat.mem_freed +=
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400897 ( sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 }
899 }
900
Veena Parat6d517a22007-07-23 02:20:51 -0400901 if (nic->rxd_mode == RXD_MODE_3B) {
Ananda Rajuda6971d2005-10-31 16:55:31 -0500902 /* Freeing buffer storage addresses in 2BUFF mode. */
903 for (i = 0; i < config->rx_ring_num; i++) {
904 blk_cnt = config->rx_cfg[i].num_rxd /
905 (rxd_count[nic->rxd_mode] + 1);
906 for (j = 0; j < blk_cnt; j++) {
907 int k = 0;
908 if (!mac_control->rings[i].ba[j])
909 continue;
910 while (k != rxd_count[nic->rxd_mode]) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500911 struct buffAdd *ba =
Ananda Rajuda6971d2005-10-31 16:55:31 -0500912 &mac_control->rings[i].ba[j][k];
913 kfree(ba->ba_0_org);
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400914 nic->mac_control.stats_info->sw_stat.\
915 mem_freed += (BUF0_LEN + ALIGN_SIZE);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500916 kfree(ba->ba_1_org);
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400917 nic->mac_control.stats_info->sw_stat.\
918 mem_freed += (BUF1_LEN + ALIGN_SIZE);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500919 k++;
920 }
921 kfree(mac_control->rings[i].ba[j]);
Sivakumar Subramani9caab452007-09-06 06:21:54 -0400922 nic->mac_control.stats_info->sw_stat.mem_freed +=
923 (sizeof(struct buffAdd) *
924 (rxd_count[nic->rxd_mode] + 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500926 kfree(mac_control->rings[i].ba);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -0400927 nic->mac_control.stats_info->sw_stat.mem_freed +=
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400928 (sizeof(struct buffAdd *) * blk_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
932 if (mac_control->stats_mem) {
933 pci_free_consistent(nic->pdev,
934 mac_control->stats_mem_sz,
935 mac_control->stats_mem,
936 mac_control->stats_mem_phy);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -0400937 nic->mac_control.stats_info->sw_stat.mem_freed +=
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400938 mac_control->stats_mem_sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 }
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400940 if (nic->ufo_in_band_v) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500941 kfree(nic->ufo_in_band_v);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -0400942 nic->mac_control.stats_info->sw_stat.mem_freed
Sreenivasa Honnur491976b2007-05-10 04:22:25 -0400943 += (ufo_size * sizeof(u64));
944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945}
946
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700947/**
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700948 * s2io_verify_pci_mode -
949 */
950
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500951static int s2io_verify_pci_mode(struct s2io_nic *nic)
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700952{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500953 struct XENA_dev_config __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700954 register u64 val64 = 0;
955 int mode;
956
957 val64 = readq(&bar0->pci_mode);
958 mode = (u8)GET_PCI_MODE(val64);
959
960 if ( val64 & PCI_MODE_UNKNOWN_MODE)
961 return -1; /* Unknown PCI mode */
962 return mode;
963}
964
Ananda Rajuc92ca042006-04-21 19:18:03 -0400965#define NEC_VENID 0x1033
966#define NEC_DEVID 0x0125
967static int s2io_on_nec_bridge(struct pci_dev *s2io_pdev)
968{
969 struct pci_dev *tdev = NULL;
Alan Cox26d36b62006-09-15 15:22:51 +0100970 while ((tdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, tdev)) != NULL) {
971 if (tdev->vendor == NEC_VENID && tdev->device == NEC_DEVID) {
Ananda Rajuc92ca042006-04-21 19:18:03 -0400972 if (tdev->bus == s2io_pdev->bus->parent)
Alan Cox26d36b62006-09-15 15:22:51 +0100973 pci_dev_put(tdev);
Ananda Rajuc92ca042006-04-21 19:18:03 -0400974 return 1;
975 }
976 }
977 return 0;
978}
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700979
Adrian Bunk7b32a312006-05-16 17:30:50 +0200980static int bus_speed[8] = {33, 133, 133, 200, 266, 133, 200, 266};
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700981/**
982 * s2io_print_pci_mode -
983 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500984static int s2io_print_pci_mode(struct s2io_nic *nic)
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700985{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -0500986 struct XENA_dev_config __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700987 register u64 val64 = 0;
988 int mode;
989 struct config_param *config = &nic->config;
990
991 val64 = readq(&bar0->pci_mode);
992 mode = (u8)GET_PCI_MODE(val64);
993
994 if ( val64 & PCI_MODE_UNKNOWN_MODE)
995 return -1; /* Unknown PCI mode */
996
Ananda Rajuc92ca042006-04-21 19:18:03 -0400997 config->bus_speed = bus_speed[mode];
998
999 if (s2io_on_nec_bridge(nic->pdev)) {
1000 DBG_PRINT(ERR_DBG, "%s: Device is on PCI-E bus\n",
1001 nic->dev->name);
1002 return mode;
1003 }
1004
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001005 if (val64 & PCI_MODE_32_BITS) {
1006 DBG_PRINT(ERR_DBG, "%s: Device is on 32 bit ", nic->dev->name);
1007 } else {
1008 DBG_PRINT(ERR_DBG, "%s: Device is on 64 bit ", nic->dev->name);
1009 }
1010
1011 switch(mode) {
1012 case PCI_MODE_PCI_33:
1013 DBG_PRINT(ERR_DBG, "33MHz PCI bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001014 break;
1015 case PCI_MODE_PCI_66:
1016 DBG_PRINT(ERR_DBG, "66MHz PCI bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001017 break;
1018 case PCI_MODE_PCIX_M1_66:
1019 DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001020 break;
1021 case PCI_MODE_PCIX_M1_100:
1022 DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001023 break;
1024 case PCI_MODE_PCIX_M1_133:
1025 DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001026 break;
1027 case PCI_MODE_PCIX_M2_66:
1028 DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001029 break;
1030 case PCI_MODE_PCIX_M2_100:
1031 DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001032 break;
1033 case PCI_MODE_PCIX_M2_133:
1034 DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001035 break;
1036 default:
1037 return -1; /* Unsupported bus speed */
1038 }
1039
1040 return mode;
1041}
1042
1043/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001044 * init_nic - Initialization of hardware
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 * @nic: device peivate variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001046 * Description: The function sequentially configures every block
1047 * of the H/W from their reset values.
1048 * Return Value: SUCCESS on success and
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 * '-1' on failure (endian settings incorrect).
1050 */
1051
1052static int init_nic(struct s2io_nic *nic)
1053{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001054 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 struct net_device *dev = nic->dev;
1056 register u64 val64 = 0;
1057 void __iomem *add;
1058 u32 time;
1059 int i, j;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001060 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 struct config_param *config;
Ananda Rajuc92ca042006-04-21 19:18:03 -04001062 int dtx_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 unsigned long long mem_share;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001064 int mem_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
1066 mac_control = &nic->mac_control;
1067 config = &nic->config;
1068
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001069 /* to set the swapper controle on the card */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001070 if(s2io_set_swapper(nic)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n");
1072 return -1;
1073 }
1074
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001075 /*
1076 * Herc requires EOI to be removed from reset before XGXS, so..
1077 */
1078 if (nic->device_type & XFRAME_II_DEVICE) {
1079 val64 = 0xA500000000ULL;
1080 writeq(val64, &bar0->sw_reset);
1081 msleep(500);
1082 val64 = readq(&bar0->sw_reset);
1083 }
1084
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 /* Remove XGXS from reset state */
1086 val64 = 0;
1087 writeq(val64, &bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 msleep(500);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001089 val64 = readq(&bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
1091 /* Enable Receiving broadcasts */
1092 add = &bar0->mac_cfg;
1093 val64 = readq(&bar0->mac_cfg);
1094 val64 |= MAC_RMAC_BCAST_ENABLE;
1095 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1096 writel((u32) val64, add);
1097 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1098 writel((u32) (val64 >> 32), (add + 4));
1099
1100 /* Read registers in all blocks */
1101 val64 = readq(&bar0->mac_int_mask);
1102 val64 = readq(&bar0->mc_int_mask);
1103 val64 = readq(&bar0->xgxs_int_mask);
1104
1105 /* Set MTU */
1106 val64 = dev->mtu;
1107 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
1108
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001109 if (nic->device_type & XFRAME_II_DEVICE) {
1110 while (herc_act_dtx_cfg[dtx_cnt] != END_SIGN) {
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07001111 SPECIAL_REG_WRITE(herc_act_dtx_cfg[dtx_cnt],
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 &bar0->dtx_control, UF);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001113 if (dtx_cnt & 0x1)
1114 msleep(1); /* Necessary!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 dtx_cnt++;
1116 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001117 } else {
Ananda Rajuc92ca042006-04-21 19:18:03 -04001118 while (xena_dtx_cfg[dtx_cnt] != END_SIGN) {
1119 SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt],
1120 &bar0->dtx_control, UF);
1121 val64 = readq(&bar0->dtx_control);
1122 dtx_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 }
1124 }
1125
1126 /* Tx DMA Initialization */
1127 val64 = 0;
1128 writeq(val64, &bar0->tx_fifo_partition_0);
1129 writeq(val64, &bar0->tx_fifo_partition_1);
1130 writeq(val64, &bar0->tx_fifo_partition_2);
1131 writeq(val64, &bar0->tx_fifo_partition_3);
1132
1133
1134 for (i = 0, j = 0; i < config->tx_fifo_num; i++) {
1135 val64 |=
1136 vBIT(config->tx_cfg[i].fifo_len - 1, ((i * 32) + 19),
1137 13) | vBIT(config->tx_cfg[i].fifo_priority,
1138 ((i * 32) + 5), 3);
1139
1140 if (i == (config->tx_fifo_num - 1)) {
1141 if (i % 2 == 0)
1142 i++;
1143 }
1144
1145 switch (i) {
1146 case 1:
1147 writeq(val64, &bar0->tx_fifo_partition_0);
1148 val64 = 0;
1149 break;
1150 case 3:
1151 writeq(val64, &bar0->tx_fifo_partition_1);
1152 val64 = 0;
1153 break;
1154 case 5:
1155 writeq(val64, &bar0->tx_fifo_partition_2);
1156 val64 = 0;
1157 break;
1158 case 7:
1159 writeq(val64, &bar0->tx_fifo_partition_3);
1160 break;
1161 }
1162 }
1163
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001164 /*
1165 * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug
1166 * SXE-008 TRANSMIT DMA ARBITRATION ISSUE.
1167 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001168 if ((nic->device_type == XFRAME_I_DEVICE) &&
Auke Kok44c10132007-06-08 15:46:36 -07001169 (nic->pdev->revision < 4))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001170 writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable);
1171
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 val64 = readq(&bar0->tx_fifo_partition_0);
1173 DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n",
1174 &bar0->tx_fifo_partition_0, (unsigned long long) val64);
1175
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001176 /*
1177 * Initialization of Tx_PA_CONFIG register to ignore packet
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 * integrity checking.
1179 */
1180 val64 = readq(&bar0->tx_pa_cfg);
1181 val64 |= TX_PA_CFG_IGNORE_FRM_ERR | TX_PA_CFG_IGNORE_SNAP_OUI |
1182 TX_PA_CFG_IGNORE_LLC_CTRL | TX_PA_CFG_IGNORE_L2_ERR;
1183 writeq(val64, &bar0->tx_pa_cfg);
1184
1185 /* Rx DMA intialization. */
1186 val64 = 0;
1187 for (i = 0; i < config->rx_ring_num; i++) {
1188 val64 |=
1189 vBIT(config->rx_cfg[i].ring_priority, (5 + (i * 8)),
1190 3);
1191 }
1192 writeq(val64, &bar0->rx_queue_priority);
1193
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001194 /*
1195 * Allocating equal share of memory to all the
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 * configured Rings.
1197 */
1198 val64 = 0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001199 if (nic->device_type & XFRAME_II_DEVICE)
1200 mem_size = 32;
1201 else
1202 mem_size = 64;
1203
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 for (i = 0; i < config->rx_ring_num; i++) {
1205 switch (i) {
1206 case 0:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001207 mem_share = (mem_size / config->rx_ring_num +
1208 mem_size % config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 val64 |= RX_QUEUE_CFG_Q0_SZ(mem_share);
1210 continue;
1211 case 1:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001212 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 val64 |= RX_QUEUE_CFG_Q1_SZ(mem_share);
1214 continue;
1215 case 2:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001216 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 val64 |= RX_QUEUE_CFG_Q2_SZ(mem_share);
1218 continue;
1219 case 3:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001220 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 val64 |= RX_QUEUE_CFG_Q3_SZ(mem_share);
1222 continue;
1223 case 4:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001224 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 val64 |= RX_QUEUE_CFG_Q4_SZ(mem_share);
1226 continue;
1227 case 5:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001228 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 val64 |= RX_QUEUE_CFG_Q5_SZ(mem_share);
1230 continue;
1231 case 6:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001232 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 val64 |= RX_QUEUE_CFG_Q6_SZ(mem_share);
1234 continue;
1235 case 7:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001236 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 val64 |= RX_QUEUE_CFG_Q7_SZ(mem_share);
1238 continue;
1239 }
1240 }
1241 writeq(val64, &bar0->rx_queue_cfg);
1242
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001243 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001244 * Filling Tx round robin registers
1245 * as per the number of FIFOs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 */
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001247 switch (config->tx_fifo_num) {
1248 case 1:
1249 val64 = 0x0000000000000000ULL;
1250 writeq(val64, &bar0->tx_w_round_robin_0);
1251 writeq(val64, &bar0->tx_w_round_robin_1);
1252 writeq(val64, &bar0->tx_w_round_robin_2);
1253 writeq(val64, &bar0->tx_w_round_robin_3);
1254 writeq(val64, &bar0->tx_w_round_robin_4);
1255 break;
1256 case 2:
1257 val64 = 0x0000010000010000ULL;
1258 writeq(val64, &bar0->tx_w_round_robin_0);
1259 val64 = 0x0100000100000100ULL;
1260 writeq(val64, &bar0->tx_w_round_robin_1);
1261 val64 = 0x0001000001000001ULL;
1262 writeq(val64, &bar0->tx_w_round_robin_2);
1263 val64 = 0x0000010000010000ULL;
1264 writeq(val64, &bar0->tx_w_round_robin_3);
1265 val64 = 0x0100000000000000ULL;
1266 writeq(val64, &bar0->tx_w_round_robin_4);
1267 break;
1268 case 3:
1269 val64 = 0x0001000102000001ULL;
1270 writeq(val64, &bar0->tx_w_round_robin_0);
1271 val64 = 0x0001020000010001ULL;
1272 writeq(val64, &bar0->tx_w_round_robin_1);
1273 val64 = 0x0200000100010200ULL;
1274 writeq(val64, &bar0->tx_w_round_robin_2);
1275 val64 = 0x0001000102000001ULL;
1276 writeq(val64, &bar0->tx_w_round_robin_3);
1277 val64 = 0x0001020000000000ULL;
1278 writeq(val64, &bar0->tx_w_round_robin_4);
1279 break;
1280 case 4:
1281 val64 = 0x0001020300010200ULL;
1282 writeq(val64, &bar0->tx_w_round_robin_0);
1283 val64 = 0x0100000102030001ULL;
1284 writeq(val64, &bar0->tx_w_round_robin_1);
1285 val64 = 0x0200010000010203ULL;
1286 writeq(val64, &bar0->tx_w_round_robin_2);
1287 val64 = 0x0001020001000001ULL;
1288 writeq(val64, &bar0->tx_w_round_robin_3);
1289 val64 = 0x0203000100000000ULL;
1290 writeq(val64, &bar0->tx_w_round_robin_4);
1291 break;
1292 case 5:
1293 val64 = 0x0001000203000102ULL;
1294 writeq(val64, &bar0->tx_w_round_robin_0);
1295 val64 = 0x0001020001030004ULL;
1296 writeq(val64, &bar0->tx_w_round_robin_1);
1297 val64 = 0x0001000203000102ULL;
1298 writeq(val64, &bar0->tx_w_round_robin_2);
1299 val64 = 0x0001020001030004ULL;
1300 writeq(val64, &bar0->tx_w_round_robin_3);
1301 val64 = 0x0001000000000000ULL;
1302 writeq(val64, &bar0->tx_w_round_robin_4);
1303 break;
1304 case 6:
1305 val64 = 0x0001020304000102ULL;
1306 writeq(val64, &bar0->tx_w_round_robin_0);
1307 val64 = 0x0304050001020001ULL;
1308 writeq(val64, &bar0->tx_w_round_robin_1);
1309 val64 = 0x0203000100000102ULL;
1310 writeq(val64, &bar0->tx_w_round_robin_2);
1311 val64 = 0x0304000102030405ULL;
1312 writeq(val64, &bar0->tx_w_round_robin_3);
1313 val64 = 0x0001000200000000ULL;
1314 writeq(val64, &bar0->tx_w_round_robin_4);
1315 break;
1316 case 7:
1317 val64 = 0x0001020001020300ULL;
1318 writeq(val64, &bar0->tx_w_round_robin_0);
1319 val64 = 0x0102030400010203ULL;
1320 writeq(val64, &bar0->tx_w_round_robin_1);
1321 val64 = 0x0405060001020001ULL;
1322 writeq(val64, &bar0->tx_w_round_robin_2);
1323 val64 = 0x0304050000010200ULL;
1324 writeq(val64, &bar0->tx_w_round_robin_3);
1325 val64 = 0x0102030000000000ULL;
1326 writeq(val64, &bar0->tx_w_round_robin_4);
1327 break;
1328 case 8:
1329 val64 = 0x0001020300040105ULL;
1330 writeq(val64, &bar0->tx_w_round_robin_0);
1331 val64 = 0x0200030106000204ULL;
1332 writeq(val64, &bar0->tx_w_round_robin_1);
1333 val64 = 0x0103000502010007ULL;
1334 writeq(val64, &bar0->tx_w_round_robin_2);
1335 val64 = 0x0304010002060500ULL;
1336 writeq(val64, &bar0->tx_w_round_robin_3);
1337 val64 = 0x0103020400000000ULL;
1338 writeq(val64, &bar0->tx_w_round_robin_4);
1339 break;
1340 }
1341
Ananda Rajub41477f2006-07-24 19:52:49 -04001342 /* Enable all configured Tx FIFO partitions */
Ananda Raju5d3213c2006-04-21 19:23:26 -04001343 val64 = readq(&bar0->tx_fifo_partition_0);
1344 val64 |= (TX_FIFO_PARTITION_EN);
1345 writeq(val64, &bar0->tx_fifo_partition_0);
1346
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001347 /* Filling the Rx round robin registers as per the
1348 * number of Rings and steering based on QoS.
1349 */
1350 switch (config->rx_ring_num) {
1351 case 1:
1352 val64 = 0x8080808080808080ULL;
1353 writeq(val64, &bar0->rts_qos_steering);
1354 break;
1355 case 2:
1356 val64 = 0x0000010000010000ULL;
1357 writeq(val64, &bar0->rx_w_round_robin_0);
1358 val64 = 0x0100000100000100ULL;
1359 writeq(val64, &bar0->rx_w_round_robin_1);
1360 val64 = 0x0001000001000001ULL;
1361 writeq(val64, &bar0->rx_w_round_robin_2);
1362 val64 = 0x0000010000010000ULL;
1363 writeq(val64, &bar0->rx_w_round_robin_3);
1364 val64 = 0x0100000000000000ULL;
1365 writeq(val64, &bar0->rx_w_round_robin_4);
1366
1367 val64 = 0x8080808040404040ULL;
1368 writeq(val64, &bar0->rts_qos_steering);
1369 break;
1370 case 3:
1371 val64 = 0x0001000102000001ULL;
1372 writeq(val64, &bar0->rx_w_round_robin_0);
1373 val64 = 0x0001020000010001ULL;
1374 writeq(val64, &bar0->rx_w_round_robin_1);
1375 val64 = 0x0200000100010200ULL;
1376 writeq(val64, &bar0->rx_w_round_robin_2);
1377 val64 = 0x0001000102000001ULL;
1378 writeq(val64, &bar0->rx_w_round_robin_3);
1379 val64 = 0x0001020000000000ULL;
1380 writeq(val64, &bar0->rx_w_round_robin_4);
1381
1382 val64 = 0x8080804040402020ULL;
1383 writeq(val64, &bar0->rts_qos_steering);
1384 break;
1385 case 4:
1386 val64 = 0x0001020300010200ULL;
1387 writeq(val64, &bar0->rx_w_round_robin_0);
1388 val64 = 0x0100000102030001ULL;
1389 writeq(val64, &bar0->rx_w_round_robin_1);
1390 val64 = 0x0200010000010203ULL;
1391 writeq(val64, &bar0->rx_w_round_robin_2);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001392 val64 = 0x0001020001000001ULL;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001393 writeq(val64, &bar0->rx_w_round_robin_3);
1394 val64 = 0x0203000100000000ULL;
1395 writeq(val64, &bar0->rx_w_round_robin_4);
1396
1397 val64 = 0x8080404020201010ULL;
1398 writeq(val64, &bar0->rts_qos_steering);
1399 break;
1400 case 5:
1401 val64 = 0x0001000203000102ULL;
1402 writeq(val64, &bar0->rx_w_round_robin_0);
1403 val64 = 0x0001020001030004ULL;
1404 writeq(val64, &bar0->rx_w_round_robin_1);
1405 val64 = 0x0001000203000102ULL;
1406 writeq(val64, &bar0->rx_w_round_robin_2);
1407 val64 = 0x0001020001030004ULL;
1408 writeq(val64, &bar0->rx_w_round_robin_3);
1409 val64 = 0x0001000000000000ULL;
1410 writeq(val64, &bar0->rx_w_round_robin_4);
1411
1412 val64 = 0x8080404020201008ULL;
1413 writeq(val64, &bar0->rts_qos_steering);
1414 break;
1415 case 6:
1416 val64 = 0x0001020304000102ULL;
1417 writeq(val64, &bar0->rx_w_round_robin_0);
1418 val64 = 0x0304050001020001ULL;
1419 writeq(val64, &bar0->rx_w_round_robin_1);
1420 val64 = 0x0203000100000102ULL;
1421 writeq(val64, &bar0->rx_w_round_robin_2);
1422 val64 = 0x0304000102030405ULL;
1423 writeq(val64, &bar0->rx_w_round_robin_3);
1424 val64 = 0x0001000200000000ULL;
1425 writeq(val64, &bar0->rx_w_round_robin_4);
1426
1427 val64 = 0x8080404020100804ULL;
1428 writeq(val64, &bar0->rts_qos_steering);
1429 break;
1430 case 7:
1431 val64 = 0x0001020001020300ULL;
1432 writeq(val64, &bar0->rx_w_round_robin_0);
1433 val64 = 0x0102030400010203ULL;
1434 writeq(val64, &bar0->rx_w_round_robin_1);
1435 val64 = 0x0405060001020001ULL;
1436 writeq(val64, &bar0->rx_w_round_robin_2);
1437 val64 = 0x0304050000010200ULL;
1438 writeq(val64, &bar0->rx_w_round_robin_3);
1439 val64 = 0x0102030000000000ULL;
1440 writeq(val64, &bar0->rx_w_round_robin_4);
1441
1442 val64 = 0x8080402010080402ULL;
1443 writeq(val64, &bar0->rts_qos_steering);
1444 break;
1445 case 8:
1446 val64 = 0x0001020300040105ULL;
1447 writeq(val64, &bar0->rx_w_round_robin_0);
1448 val64 = 0x0200030106000204ULL;
1449 writeq(val64, &bar0->rx_w_round_robin_1);
1450 val64 = 0x0103000502010007ULL;
1451 writeq(val64, &bar0->rx_w_round_robin_2);
1452 val64 = 0x0304010002060500ULL;
1453 writeq(val64, &bar0->rx_w_round_robin_3);
1454 val64 = 0x0103020400000000ULL;
1455 writeq(val64, &bar0->rx_w_round_robin_4);
1456
1457 val64 = 0x8040201008040201ULL;
1458 writeq(val64, &bar0->rts_qos_steering);
1459 break;
1460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
1462 /* UDP Fix */
1463 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001464 for (i = 0; i < 8; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 writeq(val64, &bar0->rts_frm_len_n[i]);
1466
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001467 /* Set the default rts frame length for the rings configured */
1468 val64 = MAC_RTS_FRM_LEN_SET(dev->mtu+22);
1469 for (i = 0 ; i < config->rx_ring_num ; i++)
1470 writeq(val64, &bar0->rts_frm_len_n[i]);
1471
1472 /* Set the frame length for the configured rings
1473 * desired by the user
1474 */
1475 for (i = 0; i < config->rx_ring_num; i++) {
1476 /* If rts_frm_len[i] == 0 then it is assumed that user not
1477 * specified frame length steering.
1478 * If the user provides the frame length then program
1479 * the rts_frm_len register for those values or else
1480 * leave it as it is.
1481 */
1482 if (rts_frm_len[i] != 0) {
1483 writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]),
1484 &bar0->rts_frm_len_n[i]);
1485 }
1486 }
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04001487
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05001488 /* Disable differentiated services steering logic */
1489 for (i = 0; i < 64; i++) {
1490 if (rts_ds_steer(nic, i, 0) == FAILURE) {
1491 DBG_PRINT(ERR_DBG, "%s: failed rts ds steering",
1492 dev->name);
1493 DBG_PRINT(ERR_DBG, "set on codepoint %d\n", i);
1494 return FAILURE;
1495 }
1496 }
1497
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001498 /* Program statistics memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 writeq(mac_control->stats_mem_phy, &bar0->stat_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001501 if (nic->device_type == XFRAME_II_DEVICE) {
1502 val64 = STAT_BC(0x320);
1503 writeq(val64, &bar0->stat_byte_cnt);
1504 }
1505
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001506 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 * Initializing the sampling rate for the device to calculate the
1508 * bandwidth utilization.
1509 */
1510 val64 = MAC_TX_LINK_UTIL_VAL(tmac_util_period) |
1511 MAC_RX_LINK_UTIL_VAL(rmac_util_period);
1512 writeq(val64, &bar0->mac_link_util);
1513
1514
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001515 /*
1516 * Initializing the Transmit and Receive Traffic Interrupt
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 * Scheme.
1518 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001519 /*
1520 * TTI Initialization. Default Tx timer gets us about
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 * 250 interrupts per sec. Continuous interrupts are enabled
1522 * by default.
1523 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001524 if (nic->device_type == XFRAME_II_DEVICE) {
1525 int count = (nic->config.bus_speed * 125)/2;
1526 val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count);
1527 } else {
1528
1529 val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078);
1530 }
1531 val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 TTI_DATA1_MEM_TX_URNG_B(0x10) |
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001533 TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001534 if (use_continuous_tx_intrs)
1535 val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 writeq(val64, &bar0->tti_data1_mem);
1537
1538 val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
1539 TTI_DATA2_MEM_TX_UFC_B(0x20) |
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001540 TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 writeq(val64, &bar0->tti_data2_mem);
1542
1543 val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
1544 writeq(val64, &bar0->tti_command_mem);
1545
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001546 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 * Once the operation completes, the Strobe bit of the command
1548 * register will be reset. We poll for this particular condition
1549 * We wait for a maximum of 500ms for the operation to complete,
1550 * if it's not complete by then we return error.
1551 */
1552 time = 0;
1553 while (TRUE) {
1554 val64 = readq(&bar0->tti_command_mem);
1555 if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
1556 break;
1557 }
1558 if (time > 10) {
1559 DBG_PRINT(ERR_DBG, "%s: TTI init Failed\n",
1560 dev->name);
1561 return -1;
1562 }
1563 msleep(50);
1564 time++;
1565 }
1566
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04001567 /* RTI Initialization */
1568 if (nic->device_type == XFRAME_II_DEVICE) {
1569 /*
1570 * Programmed to generate Apprx 500 Intrs per
1571 * second
1572 */
1573 int count = (nic->config.bus_speed * 125)/4;
1574 val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
1575 } else
1576 val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
1577 val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
1578 RTI_DATA1_MEM_RX_URNG_B(0x10) |
1579 RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
1580
1581 writeq(val64, &bar0->rti_data1_mem);
1582
1583 val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
1584 RTI_DATA2_MEM_RX_UFC_B(0x2) ;
1585 if (nic->config.intr_type == MSI_X)
1586 val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
1587 RTI_DATA2_MEM_RX_UFC_D(0x40));
1588 else
1589 val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \
1590 RTI_DATA2_MEM_RX_UFC_D(0x80));
1591 writeq(val64, &bar0->rti_data2_mem);
1592
1593 for (i = 0; i < config->rx_ring_num; i++) {
1594 val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD
1595 | RTI_CMD_MEM_OFFSET(i);
1596 writeq(val64, &bar0->rti_command_mem);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001597
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001598 /*
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04001599 * Once the operation completes, the Strobe bit of the
1600 * command register will be reset. We poll for this
1601 * particular condition. We wait for a maximum of 500ms
1602 * for the operation to complete, if it's not complete
1603 * by then we return error.
1604 */
1605 time = 0;
1606 while (TRUE) {
1607 val64 = readq(&bar0->rti_command_mem);
1608 if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD))
1609 break;
1610
1611 if (time > 10) {
1612 DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
1613 dev->name);
1614 return -1;
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001615 }
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04001616 time++;
1617 msleep(50);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 }
1620
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001621 /*
1622 * Initializing proper values as Pause threshold into all
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 * the 8 Queues on Rx side.
1624 */
1625 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q0q3);
1626 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7);
1627
1628 /* Disable RMAC PAD STRIPPING */
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01001629 add = &bar0->mac_cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 val64 = readq(&bar0->mac_cfg);
1631 val64 &= ~(MAC_CFG_RMAC_STRIP_PAD);
1632 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1633 writel((u32) (val64), add);
1634 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1635 writel((u32) (val64 >> 32), (add + 4));
1636 val64 = readq(&bar0->mac_cfg);
1637
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05001638 /* Enable FCS stripping by adapter */
1639 add = &bar0->mac_cfg;
1640 val64 = readq(&bar0->mac_cfg);
1641 val64 |= MAC_CFG_RMAC_STRIP_FCS;
1642 if (nic->device_type == XFRAME_II_DEVICE)
1643 writeq(val64, &bar0->mac_cfg);
1644 else {
1645 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1646 writel((u32) (val64), add);
1647 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1648 writel((u32) (val64 >> 32), (add + 4));
1649 }
1650
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001651 /*
1652 * Set the time value to be inserted in the pause frame
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 * generated by xena.
1654 */
1655 val64 = readq(&bar0->rmac_pause_cfg);
1656 val64 &= ~(RMAC_PAUSE_HG_PTIME(0xffff));
1657 val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time);
1658 writeq(val64, &bar0->rmac_pause_cfg);
1659
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001660 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 * Set the Threshold Limit for Generating the pause frame
1662 * If the amount of data in any Queue exceeds ratio of
1663 * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256
1664 * pause frame is generated
1665 */
1666 val64 = 0;
1667 for (i = 0; i < 4; i++) {
1668 val64 |=
1669 (((u64) 0xFF00 | nic->mac_control.
1670 mc_pause_threshold_q0q3)
1671 << (i * 2 * 8));
1672 }
1673 writeq(val64, &bar0->mc_pause_thresh_q0q3);
1674
1675 val64 = 0;
1676 for (i = 0; i < 4; i++) {
1677 val64 |=
1678 (((u64) 0xFF00 | nic->mac_control.
1679 mc_pause_threshold_q4q7)
1680 << (i * 2 * 8));
1681 }
1682 writeq(val64, &bar0->mc_pause_thresh_q4q7);
1683
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001684 /*
1685 * TxDMA will stop Read request if the number of read split has
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 * exceeded the limit pointed by shared_splits
1687 */
1688 val64 = readq(&bar0->pic_control);
1689 val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits);
1690 writeq(val64, &bar0->pic_control);
1691
Ananda Raju863c11a2006-04-21 19:03:13 -04001692 if (nic->config.bus_speed == 266) {
1693 writeq(TXREQTO_VAL(0x7f) | TXREQTO_EN, &bar0->txreqtimeout);
1694 writeq(0x0, &bar0->read_retry_delay);
1695 writeq(0x0, &bar0->write_retry_delay);
1696 }
1697
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001698 /*
1699 * Programming the Herc to split every write transaction
1700 * that does not start on an ADB to reduce disconnects.
1701 */
1702 if (nic->device_type == XFRAME_II_DEVICE) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001703 val64 = FAULT_BEHAVIOUR | EXT_REQ_EN |
1704 MISC_LINK_STABILITY_PRD(3);
Ananda Raju863c11a2006-04-21 19:03:13 -04001705 writeq(val64, &bar0->misc_control);
1706 val64 = readq(&bar0->pic_control2);
1707 val64 &= ~(BIT(13)|BIT(14)|BIT(15));
1708 writeq(val64, &bar0->pic_control2);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001709 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04001710 if (strstr(nic->product_name, "CX4")) {
1711 val64 = TMAC_AVG_IPG(0x17);
1712 writeq(val64, &bar0->tmac_avg_ipg);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001713 }
1714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 return SUCCESS;
1716}
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001717#define LINK_UP_DOWN_INTERRUPT 1
1718#define MAC_RMAC_ERR_TIMER 2
1719
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001720static int s2io_link_fault_indication(struct s2io_nic *nic)
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001721{
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07001722 if (nic->config.intr_type != INTA)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04001723 return MAC_RMAC_ERR_TIMER;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001724 if (nic->device_type == XFRAME_II_DEVICE)
1725 return LINK_UP_DOWN_INTERRUPT;
1726 else
1727 return MAC_RMAC_ERR_TIMER;
1728}
Sivakumar Subramani8116f3c2007-09-17 13:05:35 -07001729
Sivakumar Subramani9caab452007-09-06 06:21:54 -04001730/**
1731 * do_s2io_write_bits - update alarm bits in alarm register
1732 * @value: alarm bits
1733 * @flag: interrupt status
1734 * @addr: address value
1735 * Description: update alarm bits in alarm register
1736 * Return Value:
1737 * NONE.
1738 */
1739static void do_s2io_write_bits(u64 value, int flag, void __iomem *addr)
1740{
1741 u64 temp64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742
Sivakumar Subramani9caab452007-09-06 06:21:54 -04001743 temp64 = readq(addr);
1744
1745 if(flag == ENABLE_INTRS)
1746 temp64 &= ~((u64) value);
1747 else
1748 temp64 |= ((u64) value);
1749 writeq(temp64, addr);
1750}
1751
1752void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag)
1753{
1754 struct XENA_dev_config __iomem *bar0 = nic->bar0;
1755 register u64 gen_int_mask = 0;
1756
1757 if (mask & TX_DMA_INTR) {
1758
1759 gen_int_mask |= TXDMA_INT_M;
1760
1761 do_s2io_write_bits(TXDMA_TDA_INT | TXDMA_PFC_INT |
1762 TXDMA_PCC_INT | TXDMA_TTI_INT |
1763 TXDMA_LSO_INT | TXDMA_TPA_INT |
1764 TXDMA_SM_INT, flag, &bar0->txdma_int_mask);
1765
1766 do_s2io_write_bits(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM |
1767 PFC_MISC_0_ERR | PFC_MISC_1_ERR |
1768 PFC_PCIX_ERR | PFC_ECC_SG_ERR, flag,
1769 &bar0->pfc_err_mask);
1770
1771 do_s2io_write_bits(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM |
1772 TDA_SM1_ERR_ALARM | TDA_Fn_ECC_SG_ERR |
1773 TDA_PCIX_ERR, flag, &bar0->tda_err_mask);
1774
1775 do_s2io_write_bits(PCC_FB_ECC_DB_ERR | PCC_TXB_ECC_DB_ERR |
1776 PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM |
1777 PCC_N_SERR | PCC_6_COF_OV_ERR |
1778 PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR |
1779 PCC_7_LSO_OV_ERR | PCC_FB_ECC_SG_ERR |
1780 PCC_TXB_ECC_SG_ERR, flag, &bar0->pcc_err_mask);
1781
1782 do_s2io_write_bits(TTI_SM_ERR_ALARM | TTI_ECC_SG_ERR |
1783 TTI_ECC_DB_ERR, flag, &bar0->tti_err_mask);
1784
1785 do_s2io_write_bits(LSO6_ABORT | LSO7_ABORT |
1786 LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM |
1787 LSO6_SEND_OFLOW | LSO7_SEND_OFLOW,
1788 flag, &bar0->lso_err_mask);
1789
1790 do_s2io_write_bits(TPA_SM_ERR_ALARM | TPA_TX_FRM_DROP,
1791 flag, &bar0->tpa_err_mask);
1792
1793 do_s2io_write_bits(SM_SM_ERR_ALARM, flag, &bar0->sm_err_mask);
1794
1795 }
1796
1797 if (mask & TX_MAC_INTR) {
1798 gen_int_mask |= TXMAC_INT_M;
1799 do_s2io_write_bits(MAC_INT_STATUS_TMAC_INT, flag,
1800 &bar0->mac_int_mask);
1801 do_s2io_write_bits(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR |
1802 TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR |
1803 TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR,
1804 flag, &bar0->mac_tmac_err_mask);
1805 }
1806
1807 if (mask & TX_XGXS_INTR) {
1808 gen_int_mask |= TXXGXS_INT_M;
1809 do_s2io_write_bits(XGXS_INT_STATUS_TXGXS, flag,
1810 &bar0->xgxs_int_mask);
1811 do_s2io_write_bits(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR |
1812 TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR,
1813 flag, &bar0->xgxs_txgxs_err_mask);
1814 }
1815
1816 if (mask & RX_DMA_INTR) {
1817 gen_int_mask |= RXDMA_INT_M;
1818 do_s2io_write_bits(RXDMA_INT_RC_INT_M | RXDMA_INT_RPA_INT_M |
1819 RXDMA_INT_RDA_INT_M | RXDMA_INT_RTI_INT_M,
1820 flag, &bar0->rxdma_int_mask);
1821 do_s2io_write_bits(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR |
1822 RC_PRCn_SM_ERR_ALARM | RC_FTC_SM_ERR_ALARM |
1823 RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR |
1824 RC_RDA_FAIL_WR_Rn, flag, &bar0->rc_err_mask);
1825 do_s2io_write_bits(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn |
1826 PRC_PCI_AB_F_WR_Rn | PRC_PCI_DP_RD_Rn |
1827 PRC_PCI_DP_WR_Rn | PRC_PCI_DP_F_WR_Rn, flag,
1828 &bar0->prc_pcix_err_mask);
1829 do_s2io_write_bits(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR |
1830 RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, flag,
1831 &bar0->rpa_err_mask);
1832 do_s2io_write_bits(RDA_RXDn_ECC_DB_ERR | RDA_FRM_ECC_DB_N_AERR |
1833 RDA_SM1_ERR_ALARM | RDA_SM0_ERR_ALARM |
1834 RDA_RXD_ECC_DB_SERR | RDA_RXDn_ECC_SG_ERR |
1835 RDA_FRM_ECC_SG_ERR | RDA_MISC_ERR|RDA_PCIX_ERR,
1836 flag, &bar0->rda_err_mask);
1837 do_s2io_write_bits(RTI_SM_ERR_ALARM |
1838 RTI_ECC_SG_ERR | RTI_ECC_DB_ERR,
1839 flag, &bar0->rti_err_mask);
1840 }
1841
1842 if (mask & RX_MAC_INTR) {
1843 gen_int_mask |= RXMAC_INT_M;
1844 do_s2io_write_bits(MAC_INT_STATUS_RMAC_INT, flag,
1845 &bar0->mac_int_mask);
1846 do_s2io_write_bits(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR |
1847 RMAC_UNUSED_INT | RMAC_SINGLE_ECC_ERR |
1848 RMAC_DOUBLE_ECC_ERR |
1849 RMAC_LINK_STATE_CHANGE_INT,
1850 flag, &bar0->mac_rmac_err_mask);
1851 }
1852
1853 if (mask & RX_XGXS_INTR)
1854 {
1855 gen_int_mask |= RXXGXS_INT_M;
1856 do_s2io_write_bits(XGXS_INT_STATUS_RXGXS, flag,
1857 &bar0->xgxs_int_mask);
1858 do_s2io_write_bits(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, flag,
1859 &bar0->xgxs_rxgxs_err_mask);
1860 }
1861
1862 if (mask & MC_INTR) {
1863 gen_int_mask |= MC_INT_M;
1864 do_s2io_write_bits(MC_INT_MASK_MC_INT, flag, &bar0->mc_int_mask);
1865 do_s2io_write_bits(MC_ERR_REG_SM_ERR | MC_ERR_REG_ECC_ALL_SNG |
1866 MC_ERR_REG_ECC_ALL_DBL | PLL_LOCK_N, flag,
1867 &bar0->mc_err_mask);
1868 }
1869 nic->general_int_mask = gen_int_mask;
1870
1871 /* Remove this line when alarm interrupts are enabled */
1872 nic->general_int_mask = 0;
1873}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001874/**
1875 * en_dis_able_nic_intrs - Enable or Disable the interrupts
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 * @nic: device private variable,
1877 * @mask: A mask indicating which Intr block must be modified and,
1878 * @flag: A flag indicating whether to enable or disable the Intrs.
1879 * Description: This function will either disable or enable the interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001880 * depending on the flag argument. The mask argument can be used to
1881 * enable/disable any Intr block.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 * Return Value: NONE.
1883 */
1884
1885static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
1886{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001887 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Sivakumar Subramani9caab452007-09-06 06:21:54 -04001888 register u64 temp64 = 0, intr_mask = 0;
1889
1890 intr_mask = nic->general_int_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891
1892 /* Top level interrupt classification */
1893 /* PIC Interrupts */
Sivakumar Subramani9caab452007-09-06 06:21:54 -04001894 if (mask & TX_PIC_INTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 /* Enable PIC Intrs in the general intr mask register */
Sivakumar Subramani9caab452007-09-06 06:21:54 -04001896 intr_mask |= TXPIC_INT_M;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 if (flag == ENABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001898 /*
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001899 * If Hercules adapter enable GPIO otherwise
Ananda Rajub41477f2006-07-24 19:52:49 -04001900 * disable all PCIX, Flash, MDIO, IIC and GPIO
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001901 * interrupts for now.
1902 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001904 if (s2io_link_fault_indication(nic) ==
1905 LINK_UP_DOWN_INTERRUPT ) {
Sivakumar Subramani9caab452007-09-06 06:21:54 -04001906 do_s2io_write_bits(PIC_INT_GPIO, flag,
1907 &bar0->pic_int_mask);
1908 do_s2io_write_bits(GPIO_INT_MASK_LINK_UP, flag,
1909 &bar0->gpio_int_mask);
1910 } else
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001911 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001913 /*
1914 * Disable PIC Intrs in the general
1915 * intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 */
1917 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 }
1919 }
1920
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 /* Tx traffic interrupts */
1922 if (mask & TX_TRAFFIC_INTR) {
Sivakumar Subramani9caab452007-09-06 06:21:54 -04001923 intr_mask |= TXTRAFFIC_INT_M;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 if (flag == ENABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001925 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 * Enable all the Tx side interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001927 * writing 0 Enables all 64 TX interrupt levels
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 */
1929 writeq(0x0, &bar0->tx_traffic_mask);
1930 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001931 /*
1932 * Disable Tx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 * register.
1934 */
1935 writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 }
1937 }
1938
1939 /* Rx traffic interrupts */
1940 if (mask & RX_TRAFFIC_INTR) {
Sivakumar Subramani9caab452007-09-06 06:21:54 -04001941 intr_mask |= RXTRAFFIC_INT_M;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 if (flag == ENABLE_INTRS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 /* writing 0 Enables all 8 RX interrupt levels */
1944 writeq(0x0, &bar0->rx_traffic_mask);
1945 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001946 /*
1947 * Disable Rx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 * register.
1949 */
1950 writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 }
1952 }
Sivakumar Subramani9caab452007-09-06 06:21:54 -04001953
1954 temp64 = readq(&bar0->general_int_mask);
1955 if (flag == ENABLE_INTRS)
1956 temp64 &= ~((u64) intr_mask);
1957 else
1958 temp64 = DISABLE_ALL_INTRS;
1959 writeq(temp64, &bar0->general_int_mask);
1960
1961 nic->general_int_mask = readq(&bar0->general_int_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962}
1963
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001964/**
1965 * verify_pcc_quiescent- Checks for PCC quiescent state
1966 * Return: 1 If PCC is quiescence
1967 * 0 If PCC is not quiescence
1968 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001969static int verify_pcc_quiescent(struct s2io_nic *sp, int flag)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001970{
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001971 int ret = 0, herc;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05001972 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001973 u64 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04001974
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001975 herc = (sp->device_type == XFRAME_II_DEVICE);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001976
1977 if (flag == FALSE) {
Auke Kok44c10132007-06-08 15:46:36 -07001978 if ((!herc && (sp->pdev->revision >= 4)) || herc) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001979 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001980 ret = 1;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001981 } else {
1982 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001983 ret = 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001984 }
1985 } else {
Auke Kok44c10132007-06-08 15:46:36 -07001986 if ((!herc && (sp->pdev->revision >= 4)) || herc) {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001987 if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001988 ADAPTER_STATUS_RMAC_PCC_IDLE))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001989 ret = 1;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001990 } else {
1991 if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001992 ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001993 ret = 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001994 }
1995 }
1996
1997 return ret;
1998}
1999/**
2000 * verify_xena_quiescence - Checks whether the H/W is ready
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 * Description: Returns whether the H/W is ready to go or not. Depending
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002002 * on whether adapter enable bit was written or not the comparison
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 * differs and the calling function passes the input argument flag to
2004 * indicate this.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002005 * Return: 1 If xena is quiescence
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 * 0 If Xena is not quiescence
2007 */
2008
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002009static int verify_xena_quiescence(struct s2io_nic *sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010{
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002011 int mode;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002012 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002013 u64 val64 = readq(&bar0->adapter_status);
2014 mode = s2io_verify_pci_mode(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002016 if (!(val64 & ADAPTER_STATUS_TDMA_READY)) {
2017 DBG_PRINT(ERR_DBG, "%s", "TDMA is not ready!");
2018 return 0;
2019 }
2020 if (!(val64 & ADAPTER_STATUS_RDMA_READY)) {
2021 DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!");
2022 return 0;
2023 }
2024 if (!(val64 & ADAPTER_STATUS_PFC_READY)) {
2025 DBG_PRINT(ERR_DBG, "%s", "PFC is not ready!");
2026 return 0;
2027 }
2028 if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) {
2029 DBG_PRINT(ERR_DBG, "%s", "TMAC BUF is not empty!");
2030 return 0;
2031 }
2032 if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) {
2033 DBG_PRINT(ERR_DBG, "%s", "PIC is not QUIESCENT!");
2034 return 0;
2035 }
2036 if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) {
2037 DBG_PRINT(ERR_DBG, "%s", "MC_DRAM is not ready!");
2038 return 0;
2039 }
2040 if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) {
2041 DBG_PRINT(ERR_DBG, "%s", "MC_QUEUES is not ready!");
2042 return 0;
2043 }
2044 if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) {
2045 DBG_PRINT(ERR_DBG, "%s", "M_PLL is not locked!");
2046 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 }
2048
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002049 /*
2050 * In PCI 33 mode, the P_PLL is not used, and therefore,
2051 * the the P_PLL_LOCK bit in the adapter_status register will
2052 * not be asserted.
2053 */
2054 if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) &&
2055 sp->device_type == XFRAME_II_DEVICE && mode !=
2056 PCI_MODE_PCI_33) {
2057 DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!");
2058 return 0;
2059 }
2060 if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
2061 ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
2062 DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!");
2063 return 0;
2064 }
2065 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066}
2067
2068/**
2069 * fix_mac_address - Fix for Mac addr problem on Alpha platforms
2070 * @sp: Pointer to device specifc structure
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002071 * Description :
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 * New procedure to clear mac address reading problems on Alpha platforms
2073 *
2074 */
2075
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002076static void fix_mac_address(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002078 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 u64 val64;
2080 int i = 0;
2081
2082 while (fix_mac[i] != END_SIGN) {
2083 writeq(fix_mac[i++], &bar0->gpio_control);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002084 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 val64 = readq(&bar0->gpio_control);
2086 }
2087}
2088
2089/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002090 * start_nic - Turns the device on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002092 * Description:
2093 * This function actually turns the device on. Before this function is
2094 * called,all Registers are configured from their reset states
2095 * and shared memory is allocated but the NIC is still quiescent. On
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 * calling this function, the device interrupts are cleared and the NIC is
2097 * literally switched on by writing into the adapter control register.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002098 * Return Value:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 * SUCCESS on success and -1 on failure.
2100 */
2101
2102static int start_nic(struct s2io_nic *nic)
2103{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002104 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 struct net_device *dev = nic->dev;
2106 register u64 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002107 u16 subid, i;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002108 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 struct config_param *config;
2110
2111 mac_control = &nic->mac_control;
2112 config = &nic->config;
2113
2114 /* PRC Initialization and configuration */
2115 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002116 writeq((u64) mac_control->rings[i].rx_blocks[0].block_dma_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 &bar0->prc_rxd0_n[i]);
2118
2119 val64 = readq(&bar0->prc_ctrl_n[i]);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002120 if (nic->rxd_mode == RXD_MODE_1)
2121 val64 |= PRC_CTRL_RC_ENABLED;
2122 else
2123 val64 |= PRC_CTRL_RC_ENABLED | PRC_CTRL_RING_MODE_3;
Ananda Raju863c11a2006-04-21 19:03:13 -04002124 if (nic->device_type == XFRAME_II_DEVICE)
2125 val64 |= PRC_CTRL_GROUP_READS;
2126 val64 &= ~PRC_CTRL_RXD_BACKOFF_INTERVAL(0xFFFFFF);
2127 val64 |= PRC_CTRL_RXD_BACKOFF_INTERVAL(0x1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 writeq(val64, &bar0->prc_ctrl_n[i]);
2129 }
2130
Ananda Rajuda6971d2005-10-31 16:55:31 -05002131 if (nic->rxd_mode == RXD_MODE_3B) {
2132 /* Enabling 2 buffer mode by writing into Rx_pa_cfg reg. */
2133 val64 = readq(&bar0->rx_pa_cfg);
2134 val64 |= RX_PA_CFG_IGNORE_L2_ERR;
2135 writeq(val64, &bar0->rx_pa_cfg);
2136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137
Sivakumar Subramani926930b2007-02-24 01:59:39 -05002138 if (vlan_tag_strip == 0) {
2139 val64 = readq(&bar0->rx_pa_cfg);
2140 val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG;
2141 writeq(val64, &bar0->rx_pa_cfg);
2142 vlan_strip_flag = 0;
2143 }
2144
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002145 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 * Enabling MC-RLDRAM. After enabling the device, we timeout
2147 * for around 100ms, which is approximately the time required
2148 * for the device to be ready for operation.
2149 */
2150 val64 = readq(&bar0->mc_rldram_mrs);
2151 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE | MC_RLDRAM_MRS_ENABLE;
2152 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
2153 val64 = readq(&bar0->mc_rldram_mrs);
2154
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002155 msleep(100); /* Delay by around 100 ms. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156
2157 /* Enabling ECC Protection. */
2158 val64 = readq(&bar0->adapter_control);
2159 val64 &= ~ADAPTER_ECC_EN;
2160 writeq(val64, &bar0->adapter_control);
2161
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002162 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002163 * Verify if the device is ready to be enabled, if so enable
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 * it.
2165 */
2166 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002167 if (!verify_xena_quiescence(nic)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name);
2169 DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n",
2170 (unsigned long long) val64);
2171 return FAILURE;
2172 }
2173
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002174 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 * With some switches, link might be already up at this point.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002176 * Because of this weird behavior, when we enable laser,
2177 * we may not get link. We need to handle this. We cannot
2178 * figure out which switch is misbehaving. So we are forced to
2179 * make a global change.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 */
2181
2182 /* Enabling Laser. */
2183 val64 = readq(&bar0->adapter_control);
2184 val64 |= ADAPTER_EOI_TX_ON;
2185 writeq(val64, &bar0->adapter_control);
2186
Ananda Rajuc92ca042006-04-21 19:18:03 -04002187 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
2188 /*
2189 * Dont see link state interrupts initally on some switches,
2190 * so directly scheduling the link state task here.
2191 */
2192 schedule_work(&nic->set_link_task);
2193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 /* SXE-002: Initialize link and activity LED */
2195 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07002196 if (((subid & 0xFF) >= 0x07) &&
2197 (nic->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 val64 = readq(&bar0->gpio_control);
2199 val64 |= 0x0000800000000000ULL;
2200 writeq(val64, &bar0->gpio_control);
2201 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01002202 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 }
2204
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 return SUCCESS;
2206}
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002207/**
2208 * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb
2209 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002210static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \
2211 TxD *txdlp, int get_off)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002212{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002213 struct s2io_nic *nic = fifo_data->nic;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002214 struct sk_buff *skb;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002215 struct TxD *txds;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002216 u16 j, frg_cnt;
2217
2218 txds = txdlp;
Andrew Morton26b76252005-12-14 19:25:23 -08002219 if (txds->Host_Control == (u64)(long)nic->ufo_in_band_v) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002220 pci_unmap_single(nic->pdev, (dma_addr_t)
2221 txds->Buffer_Pointer, sizeof(u64),
2222 PCI_DMA_TODEVICE);
2223 txds++;
2224 }
2225
2226 skb = (struct sk_buff *) ((unsigned long)
2227 txds->Host_Control);
2228 if (!skb) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002229 memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds));
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002230 return NULL;
2231 }
2232 pci_unmap_single(nic->pdev, (dma_addr_t)
2233 txds->Buffer_Pointer,
2234 skb->len - skb->data_len,
2235 PCI_DMA_TODEVICE);
2236 frg_cnt = skb_shinfo(skb)->nr_frags;
2237 if (frg_cnt) {
2238 txds++;
2239 for (j = 0; j < frg_cnt; j++, txds++) {
2240 skb_frag_t *frag = &skb_shinfo(skb)->frags[j];
2241 if (!txds->Buffer_Pointer)
2242 break;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002243 pci_unmap_page(nic->pdev, (dma_addr_t)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002244 txds->Buffer_Pointer,
2245 frag->size, PCI_DMA_TODEVICE);
2246 }
2247 }
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002248 memset(txdlp,0, (sizeof(struct TxD) * fifo_data->max_txds));
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002249 return(skb);
2250}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002252/**
2253 * free_tx_buffers - Free all queued Tx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002255 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 * Free all queued Tx buffers.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002257 * Return Value: void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258*/
2259
2260static void free_tx_buffers(struct s2io_nic *nic)
2261{
2262 struct net_device *dev = nic->dev;
2263 struct sk_buff *skb;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002264 struct TxD *txdp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 int i, j;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002266 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 struct config_param *config;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002268 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269
2270 mac_control = &nic->mac_control;
2271 config = &nic->config;
2272
2273 for (i = 0; i < config->tx_fifo_num; i++) {
2274 for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04002275 txdp = (struct TxD *) \
2276 mac_control->fifos[i].list_info[j].list_virt_addr;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002277 skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
2278 if (skb) {
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04002279 nic->mac_control.stats_info->sw_stat.mem_freed
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04002280 += skb->truesize;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002281 dev_kfree_skb(skb);
2282 cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 }
2285 DBG_PRINT(INTR_DBG,
2286 "%s:forcibly freeing %d skbs on FIFO%d\n",
2287 dev->name, cnt, i);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002288 mac_control->fifos[i].tx_curr_get_info.offset = 0;
2289 mac_control->fifos[i].tx_curr_put_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 }
2291}
2292
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002293/**
2294 * stop_nic - To stop the nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 * @nic ; device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002296 * Description:
2297 * This function does exactly the opposite of what the start_nic()
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 * function does. This function is called to stop the device.
2299 * Return Value:
2300 * void.
2301 */
2302
2303static void stop_nic(struct s2io_nic *nic)
2304{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002305 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 register u64 val64 = 0;
Ananda Raju5d3213c2006-04-21 19:23:26 -04002307 u16 interruptible;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002308 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 struct config_param *config;
2310
2311 mac_control = &nic->mac_control;
2312 config = &nic->config;
2313
2314 /* Disable all interrupts */
Sivakumar Subramani9caab452007-09-06 06:21:54 -04002315 en_dis_err_alarms(nic, ENA_ALL_INTRS, DISABLE_INTRS);
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002316 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
Sivakumar Subramani9caab452007-09-06 06:21:54 -04002317 interruptible |= TX_PIC_INTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
2319
Ananda Raju5d3213c2006-04-21 19:23:26 -04002320 /* Clearing Adapter_En bit of ADAPTER_CONTROL Register */
2321 val64 = readq(&bar0->adapter_control);
2322 val64 &= ~(ADAPTER_CNTL_EN);
2323 writeq(val64, &bar0->adapter_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324}
2325
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002326/**
2327 * fill_rx_buffers - Allocates the Rx side skbs
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002329 * @ring_no: ring number
2330 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 * The function allocates Rx side skbs and puts the physical
2332 * address of these buffers into the RxD buffer pointers, so that the NIC
2333 * can DMA the received frame into these locations.
2334 * The NIC supports 3 receive modes, viz
2335 * 1. single buffer,
2336 * 2. three buffer and
2337 * 3. Five buffer modes.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002338 * Each mode defines how many fragments the received frame will be split
2339 * up into by the NIC. The frame is split into L3 header, L4 Header,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 * L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself
2341 * is split into 3 fragments. As of now only single buffer mode is
2342 * supported.
2343 * Return Value:
2344 * SUCCESS on success or an appropriate -ve value on failure.
2345 */
2346
Adrian Bunkac1f60d2005-11-06 01:46:47 +01002347static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348{
2349 struct net_device *dev = nic->dev;
2350 struct sk_buff *skb;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002351 struct RxD_t *rxdp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 int off, off1, size, block_no, block_no1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 u32 alloc_tab = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002354 u32 alloc_cnt;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002355 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 struct config_param *config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002357 u64 tmp;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002358 struct buffAdd *ba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 unsigned long flags;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002360 struct RxD_t *first_rxdp = NULL;
Ramkrishna Vepa363dc362007-03-06 17:01:00 -08002361 u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
Veena Parat6d517a22007-07-23 02:20:51 -04002362 struct RxD1 *rxdp1;
2363 struct RxD3 *rxdp3;
Veena Parat491abf22007-07-23 02:37:14 -04002364 struct swStat *stats = &nic->mac_control.stats_info->sw_stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365
2366 mac_control = &nic->mac_control;
2367 config = &nic->config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002368 alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
2369 atomic_read(&nic->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370
Ananda Raju5d3213c2006-04-21 19:23:26 -04002371 block_no1 = mac_control->rings[ring_no].rx_curr_get_info.block_index;
Ananda Raju863c11a2006-04-21 19:03:13 -04002372 off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 while (alloc_tab < alloc_cnt) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002374 block_no = mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 block_index;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002376 off = mac_control->rings[ring_no].rx_curr_put_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377
Ananda Rajuda6971d2005-10-31 16:55:31 -05002378 rxdp = mac_control->rings[ring_no].
2379 rx_blocks[block_no].rxds[off].virt_addr;
2380
2381 if ((block_no == block_no1) && (off == off1) &&
2382 (rxdp->Host_Control)) {
2383 DBG_PRINT(INTR_DBG, "%s: Get and Put",
2384 dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 DBG_PRINT(INTR_DBG, " info equated\n");
2386 goto end;
2387 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002388 if (off && (off == rxd_count[nic->rxd_mode])) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002389 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 block_index++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002391 if (mac_control->rings[ring_no].rx_curr_put_info.
2392 block_index == mac_control->rings[ring_no].
2393 block_count)
2394 mac_control->rings[ring_no].rx_curr_put_info.
2395 block_index = 0;
2396 block_no = mac_control->rings[ring_no].
2397 rx_curr_put_info.block_index;
2398 if (off == rxd_count[nic->rxd_mode])
2399 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002400 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002401 offset = off;
2402 rxdp = mac_control->rings[ring_no].
2403 rx_blocks[block_no].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
2405 dev->name, rxdp);
2406 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002407 if(!napi) {
2408 spin_lock_irqsave(&nic->put_lock, flags);
2409 mac_control->rings[ring_no].put_pos =
2410 (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
2411 spin_unlock_irqrestore(&nic->put_lock, flags);
2412 } else {
2413 mac_control->rings[ring_no].put_pos =
2414 (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
2415 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002416 if ((rxdp->Control_1 & RXD_OWN_XENA) &&
Veena Parat6d517a22007-07-23 02:20:51 -04002417 ((nic->rxd_mode == RXD_MODE_3B) &&
Ananda Rajuda6971d2005-10-31 16:55:31 -05002418 (rxdp->Control_2 & BIT(0)))) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002419 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002420 offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 goto end;
2422 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002423 /* calculate size of skb based on ring mode */
2424 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
2425 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
2426 if (nic->rxd_mode == RXD_MODE_1)
2427 size += NET_IP_ALIGN;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002428 else
Veena Parat6d517a22007-07-23 02:20:51 -04002429 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
Ananda Rajuda6971d2005-10-31 16:55:31 -05002431 /* allocate skb */
2432 skb = dev_alloc_skb(size);
2433 if(!skb) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08002434 DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
2435 DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002436 if (first_rxdp) {
2437 wmb();
2438 first_rxdp->Control_1 |= RXD_OWN_XENA;
2439 }
Sreenivasa Honnurc53d4942007-05-10 04:18:54 -04002440 nic->mac_control.stats_info->sw_stat. \
2441 mem_alloc_fail_cnt++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002442 return -ENOMEM ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 }
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04002444 nic->mac_control.stats_info->sw_stat.mem_allocated
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04002445 += skb->truesize;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002446 if (nic->rxd_mode == RXD_MODE_1) {
2447 /* 1 buffer mode - normal operation mode */
Veena Parat6d517a22007-07-23 02:20:51 -04002448 rxdp1 = (struct RxD1*)rxdp;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002449 memset(rxdp, 0, sizeof(struct RxD1));
Ananda Rajuda6971d2005-10-31 16:55:31 -05002450 skb_reserve(skb, NET_IP_ALIGN);
Veena Parat6d517a22007-07-23 02:20:51 -04002451 rxdp1->Buffer0_ptr = pci_map_single
Ananda Raju863c11a2006-04-21 19:03:13 -04002452 (nic->pdev, skb->data, size - NET_IP_ALIGN,
2453 PCI_DMA_FROMDEVICE);
Veena Parat491abf22007-07-23 02:37:14 -04002454 if( (rxdp1->Buffer0_ptr == 0) ||
2455 (rxdp1->Buffer0_ptr ==
2456 DMA_ERROR_CODE))
2457 goto pci_map_failed;
2458
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04002459 rxdp->Control_2 =
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04002460 SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002461
Veena Parat6d517a22007-07-23 02:20:51 -04002462 } else if (nic->rxd_mode == RXD_MODE_3B) {
Ananda Rajuda6971d2005-10-31 16:55:31 -05002463 /*
Veena Parat6d517a22007-07-23 02:20:51 -04002464 * 2 buffer mode -
2465 * 2 buffer mode provides 128
Ananda Rajuda6971d2005-10-31 16:55:31 -05002466 * byte aligned receive buffers.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002467 */
2468
Veena Parat6d517a22007-07-23 02:20:51 -04002469 rxdp3 = (struct RxD3*)rxdp;
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04002470 /* save buffer pointers to avoid frequent dma mapping */
Veena Parat6d517a22007-07-23 02:20:51 -04002471 Buffer0_ptr = rxdp3->Buffer0_ptr;
2472 Buffer1_ptr = rxdp3->Buffer1_ptr;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002473 memset(rxdp, 0, sizeof(struct RxD3));
Ramkrishna Vepa363dc362007-03-06 17:01:00 -08002474 /* restore the buffer pointers for dma sync*/
Veena Parat6d517a22007-07-23 02:20:51 -04002475 rxdp3->Buffer0_ptr = Buffer0_ptr;
2476 rxdp3->Buffer1_ptr = Buffer1_ptr;
Ramkrishna Vepa363dc362007-03-06 17:01:00 -08002477
Ananda Rajuda6971d2005-10-31 16:55:31 -05002478 ba = &mac_control->rings[ring_no].ba[block_no][off];
2479 skb_reserve(skb, BUF0_LEN);
2480 tmp = (u64)(unsigned long) skb->data;
2481 tmp += ALIGN_SIZE;
2482 tmp &= ~ALIGN_SIZE;
2483 skb->data = (void *) (unsigned long)tmp;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07002484 skb_reset_tail_pointer(skb);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002485
Veena Parat6d517a22007-07-23 02:20:51 -04002486 if (!(rxdp3->Buffer0_ptr))
2487 rxdp3->Buffer0_ptr =
Ananda Raju75c30b12006-07-24 19:55:09 -04002488 pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002489 PCI_DMA_FROMDEVICE);
Ananda Raju75c30b12006-07-24 19:55:09 -04002490 else
2491 pci_dma_sync_single_for_device(nic->pdev,
Veena Parat6d517a22007-07-23 02:20:51 -04002492 (dma_addr_t) rxdp3->Buffer0_ptr,
Ananda Raju75c30b12006-07-24 19:55:09 -04002493 BUF0_LEN, PCI_DMA_FROMDEVICE);
Veena Parat491abf22007-07-23 02:37:14 -04002494 if( (rxdp3->Buffer0_ptr == 0) ||
2495 (rxdp3->Buffer0_ptr == DMA_ERROR_CODE))
2496 goto pci_map_failed;
2497
Ananda Rajuda6971d2005-10-31 16:55:31 -05002498 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
2499 if (nic->rxd_mode == RXD_MODE_3B) {
2500 /* Two buffer mode */
2501
2502 /*
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002503 * Buffer2 will have L3/L4 header plus
Ananda Rajuda6971d2005-10-31 16:55:31 -05002504 * L4 payload
2505 */
Veena Parat6d517a22007-07-23 02:20:51 -04002506 rxdp3->Buffer2_ptr = pci_map_single
Ananda Rajuda6971d2005-10-31 16:55:31 -05002507 (nic->pdev, skb->data, dev->mtu + 4,
2508 PCI_DMA_FROMDEVICE);
2509
Veena Parat491abf22007-07-23 02:37:14 -04002510 if( (rxdp3->Buffer2_ptr == 0) ||
2511 (rxdp3->Buffer2_ptr == DMA_ERROR_CODE))
2512 goto pci_map_failed;
2513
2514 rxdp3->Buffer1_ptr =
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002515 pci_map_single(nic->pdev,
Ananda Raju75c30b12006-07-24 19:55:09 -04002516 ba->ba_1, BUF1_LEN,
2517 PCI_DMA_FROMDEVICE);
Veena Parat491abf22007-07-23 02:37:14 -04002518 if( (rxdp3->Buffer1_ptr == 0) ||
2519 (rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
2520 pci_unmap_single
2521 (nic->pdev,
Al Viro3e847422007-08-02 19:21:30 +01002522 (dma_addr_t)rxdp3->Buffer2_ptr,
Veena Parat491abf22007-07-23 02:37:14 -04002523 dev->mtu + 4,
2524 PCI_DMA_FROMDEVICE);
2525 goto pci_map_failed;
Ananda Raju75c30b12006-07-24 19:55:09 -04002526 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002527 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
2528 rxdp->Control_2 |= SET_BUFFER2_SIZE_3
2529 (dev->mtu + 4);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002530 }
2531 rxdp->Control_2 |= BIT(0);
2532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 rxdp->Host_Control = (unsigned long) (skb);
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002534 if (alloc_tab & ((1 << rxsync_frequency) - 1))
2535 rxdp->Control_1 |= RXD_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 off++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002537 if (off == (rxd_count[nic->rxd_mode] + 1))
2538 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002539 mac_control->rings[ring_no].rx_curr_put_info.offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002541 rxdp->Control_2 |= SET_RXD_MARKER;
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002542 if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
2543 if (first_rxdp) {
2544 wmb();
2545 first_rxdp->Control_1 |= RXD_OWN_XENA;
2546 }
2547 first_rxdp = rxdp;
2548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 atomic_inc(&nic->rx_bufs_left[ring_no]);
2550 alloc_tab++;
2551 }
2552
2553 end:
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002554 /* Transfer ownership of first descriptor to adapter just before
2555 * exiting. Before that, use memory barrier so that ownership
2556 * and other fields are seen by adapter correctly.
2557 */
2558 if (first_rxdp) {
2559 wmb();
2560 first_rxdp->Control_1 |= RXD_OWN_XENA;
2561 }
2562
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 return SUCCESS;
Veena Parat491abf22007-07-23 02:37:14 -04002564pci_map_failed:
2565 stats->pci_map_fail_cnt++;
2566 stats->mem_freed += skb->truesize;
2567 dev_kfree_skb_irq(skb);
2568 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569}
2570
Ananda Rajuda6971d2005-10-31 16:55:31 -05002571static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
2572{
2573 struct net_device *dev = sp->dev;
2574 int j;
2575 struct sk_buff *skb;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002576 struct RxD_t *rxdp;
2577 struct mac_info *mac_control;
2578 struct buffAdd *ba;
Veena Parat6d517a22007-07-23 02:20:51 -04002579 struct RxD1 *rxdp1;
2580 struct RxD3 *rxdp3;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002581
2582 mac_control = &sp->mac_control;
2583 for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
2584 rxdp = mac_control->rings[ring_no].
2585 rx_blocks[blk].rxds[j].virt_addr;
2586 skb = (struct sk_buff *)
2587 ((unsigned long) rxdp->Host_Control);
2588 if (!skb) {
2589 continue;
2590 }
2591 if (sp->rxd_mode == RXD_MODE_1) {
Veena Parat6d517a22007-07-23 02:20:51 -04002592 rxdp1 = (struct RxD1*)rxdp;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002593 pci_unmap_single(sp->pdev, (dma_addr_t)
Veena Parat6d517a22007-07-23 02:20:51 -04002594 rxdp1->Buffer0_ptr,
2595 dev->mtu +
2596 HEADER_ETHERNET_II_802_3_SIZE
2597 + HEADER_802_2_SIZE +
2598 HEADER_SNAP_SIZE,
2599 PCI_DMA_FROMDEVICE);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002600 memset(rxdp, 0, sizeof(struct RxD1));
Ananda Rajuda6971d2005-10-31 16:55:31 -05002601 } else if(sp->rxd_mode == RXD_MODE_3B) {
Veena Parat6d517a22007-07-23 02:20:51 -04002602 rxdp3 = (struct RxD3*)rxdp;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002603 ba = &mac_control->rings[ring_no].
2604 ba[blk][j];
2605 pci_unmap_single(sp->pdev, (dma_addr_t)
Veena Parat6d517a22007-07-23 02:20:51 -04002606 rxdp3->Buffer0_ptr,
2607 BUF0_LEN,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002608 PCI_DMA_FROMDEVICE);
2609 pci_unmap_single(sp->pdev, (dma_addr_t)
Veena Parat6d517a22007-07-23 02:20:51 -04002610 rxdp3->Buffer1_ptr,
2611 BUF1_LEN,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002612 PCI_DMA_FROMDEVICE);
2613 pci_unmap_single(sp->pdev, (dma_addr_t)
Veena Parat6d517a22007-07-23 02:20:51 -04002614 rxdp3->Buffer2_ptr,
2615 dev->mtu + 4,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002616 PCI_DMA_FROMDEVICE);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002617 memset(rxdp, 0, sizeof(struct RxD3));
Ananda Rajuda6971d2005-10-31 16:55:31 -05002618 }
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04002619 sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002620 dev_kfree_skb(skb);
2621 atomic_dec(&sp->rx_bufs_left[ring_no]);
2622 }
2623}
2624
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002626 * free_rx_buffers - Frees all Rx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 * @sp: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002628 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 * This function will free all Rx buffers allocated by host.
2630 * Return Value:
2631 * NONE.
2632 */
2633
2634static void free_rx_buffers(struct s2io_nic *sp)
2635{
2636 struct net_device *dev = sp->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002637 int i, blk = 0, buf_cnt = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002638 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 struct config_param *config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640
2641 mac_control = &sp->mac_control;
2642 config = &sp->config;
2643
2644 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -05002645 for (blk = 0; blk < rx_ring_sz[i]; blk++)
2646 free_rxd_blk(sp,i,blk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002648 mac_control->rings[i].rx_curr_put_info.block_index = 0;
2649 mac_control->rings[i].rx_curr_get_info.block_index = 0;
2650 mac_control->rings[i].rx_curr_put_info.offset = 0;
2651 mac_control->rings[i].rx_curr_get_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 atomic_set(&sp->rx_bufs_left[i], 0);
2653 DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
2654 dev->name, buf_cnt, i);
2655 }
2656}
2657
2658/**
2659 * s2io_poll - Rx interrupt handler for NAPI support
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002660 * @napi : pointer to the napi structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002661 * @budget : The number of packets that were budgeted to be processed
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 * during one pass through the 'Poll" function.
2663 * Description:
2664 * Comes into picture only if NAPI support has been incorporated. It does
2665 * the same thing that rx_intr_handler does, but not in a interrupt context
2666 * also It will process only a given number of packets.
2667 * Return value:
2668 * 0 on success and 1 if there are No Rx packets to be processed.
2669 */
2670
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002671static int s2io_poll(struct napi_struct *napi, int budget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672{
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002673 struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi);
2674 struct net_device *dev = nic->dev;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002675 int pkt_cnt = 0, org_pkts_to_process;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002676 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 struct config_param *config;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002678 struct XENA_dev_config __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002679 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07002681 if (!is_s2io_card_up(nic))
Sivakumar Subramani92b84432007-09-06 06:51:14 -04002682 return 0;
Sivakumar Subramani92b84432007-09-06 06:51:14 -04002683
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 mac_control = &nic->mac_control;
2685 config = &nic->config;
2686
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002687 nic->pkts_to_process = budget;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002688 org_pkts_to_process = nic->pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002690 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
2691 readl(&bar0->rx_traffic_int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
2693 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002694 rx_intr_handler(&mac_control->rings[i]);
2695 pkt_cnt = org_pkts_to_process - nic->pkts_to_process;
2696 if (!nic->pkts_to_process) {
2697 /* Quota for the current iteration has been met */
2698 goto no_rx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002702 netif_rx_complete(dev, napi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
2704 for (i = 0; i < config->rx_ring_num; i++) {
2705 if (fill_rx_buffers(nic, i) == -ENOMEM) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08002706 DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
2707 DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 break;
2709 }
2710 }
2711 /* Re enable the Rx interrupts. */
Ananda Rajuc92ca042006-04-21 19:18:03 -04002712 writeq(0x0, &bar0->rx_traffic_mask);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002713 readl(&bar0->rx_traffic_mask);
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002714 return pkt_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002716no_rx:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 for (i = 0; i < config->rx_ring_num; i++) {
2718 if (fill_rx_buffers(nic, i) == -ENOMEM) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08002719 DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
2720 DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 break;
2722 }
2723 }
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002724 return pkt_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002726
Ananda Rajub41477f2006-07-24 19:52:49 -04002727#ifdef CONFIG_NET_POLL_CONTROLLER
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002728/**
Ananda Rajub41477f2006-07-24 19:52:49 -04002729 * s2io_netpoll - netpoll event handler entry point
Brian Haley612eff02006-06-15 14:36:36 -04002730 * @dev : pointer to the device structure.
2731 * Description:
Ananda Rajub41477f2006-07-24 19:52:49 -04002732 * This function will be called by upper layer to check for events on the
2733 * interface in situations where interrupts are disabled. It is used for
2734 * specific in-kernel networking tasks, such as remote consoles and kernel
2735 * debugging over the network (example netdump in RedHat).
Brian Haley612eff02006-06-15 14:36:36 -04002736 */
Brian Haley612eff02006-06-15 14:36:36 -04002737static void s2io_netpoll(struct net_device *dev)
2738{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002739 struct s2io_nic *nic = dev->priv;
2740 struct mac_info *mac_control;
Brian Haley612eff02006-06-15 14:36:36 -04002741 struct config_param *config;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002742 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ananda Rajub41477f2006-07-24 19:52:49 -04002743 u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
Brian Haley612eff02006-06-15 14:36:36 -04002744 int i;
2745
Linas Vepstasd796fdb2007-05-14 18:37:30 -05002746 if (pci_channel_offline(nic->pdev))
2747 return;
2748
Brian Haley612eff02006-06-15 14:36:36 -04002749 disable_irq(dev->irq);
2750
Brian Haley612eff02006-06-15 14:36:36 -04002751 mac_control = &nic->mac_control;
2752 config = &nic->config;
2753
Brian Haley612eff02006-06-15 14:36:36 -04002754 writeq(val64, &bar0->rx_traffic_int);
Ananda Rajub41477f2006-07-24 19:52:49 -04002755 writeq(val64, &bar0->tx_traffic_int);
Brian Haley612eff02006-06-15 14:36:36 -04002756
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002757 /* we need to free up the transmitted skbufs or else netpoll will
Ananda Rajub41477f2006-07-24 19:52:49 -04002758 * run out of skbs and will fail and eventually netpoll application such
2759 * as netdump will fail.
2760 */
2761 for (i = 0; i < config->tx_fifo_num; i++)
2762 tx_intr_handler(&mac_control->fifos[i]);
2763
2764 /* check for received packet and indicate up to network */
Brian Haley612eff02006-06-15 14:36:36 -04002765 for (i = 0; i < config->rx_ring_num; i++)
2766 rx_intr_handler(&mac_control->rings[i]);
2767
2768 for (i = 0; i < config->rx_ring_num; i++) {
2769 if (fill_rx_buffers(nic, i) == -ENOMEM) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08002770 DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
2771 DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n");
Brian Haley612eff02006-06-15 14:36:36 -04002772 break;
2773 }
2774 }
Brian Haley612eff02006-06-15 14:36:36 -04002775 enable_irq(dev->irq);
2776 return;
2777}
2778#endif
2779
2780/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 * rx_intr_handler - Rx interrupt handler
2782 * @nic: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002783 * Description:
2784 * If the interrupt is because of a received frame or if the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 * receive ring contains fresh as yet un-processed frames,this function is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002786 * called. It picks out the RxD at which place the last Rx processing had
2787 * stopped and sends the skb to the OSM's Rx handler and then increments
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 * the offset.
2789 * Return Value:
2790 * NONE.
2791 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002792static void rx_intr_handler(struct ring_info *ring_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002794 struct s2io_nic *nic = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 struct net_device *dev = (struct net_device *) nic->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002796 int get_block, put_block, put_offset;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002797 struct rx_curr_get_info get_info, put_info;
2798 struct RxD_t *rxdp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 struct sk_buff *skb;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002800 int pkt_cnt = 0;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002801 int i;
Veena Parat6d517a22007-07-23 02:20:51 -04002802 struct RxD1* rxdp1;
2803 struct RxD3* rxdp3;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002804
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002805 spin_lock(&nic->rx_lock);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002806
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002807 get_info = ring_data->rx_curr_get_info;
2808 get_block = get_info.block_index;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002809 memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002810 put_block = put_info.block_index;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002811 rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002812 if (!napi) {
2813 spin_lock(&nic->put_lock);
2814 put_offset = ring_data->put_pos;
2815 spin_unlock(&nic->put_lock);
2816 } else
2817 put_offset = ring_data->put_pos;
2818
Ananda Rajuda6971d2005-10-31 16:55:31 -05002819 while (RXD_IS_UP2DT(rxdp)) {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002820 /*
2821 * If your are next to put index then it's
2822 * FIFO full condition
2823 */
Ananda Rajuda6971d2005-10-31 16:55:31 -05002824 if ((get_block == put_block) &&
2825 (get_info.offset + 1) == put_info.offset) {
Ananda Raju75c30b12006-07-24 19:55:09 -04002826 DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002827 break;
2828 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002829 skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
2830 if (skb == NULL) {
2831 DBG_PRINT(ERR_DBG, "%s: The skb is ",
2832 dev->name);
2833 DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002834 spin_unlock(&nic->rx_lock);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002835 return;
2836 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002837 if (nic->rxd_mode == RXD_MODE_1) {
Veena Parat6d517a22007-07-23 02:20:51 -04002838 rxdp1 = (struct RxD1*)rxdp;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002839 pci_unmap_single(nic->pdev, (dma_addr_t)
Veena Parat6d517a22007-07-23 02:20:51 -04002840 rxdp1->Buffer0_ptr,
2841 dev->mtu +
2842 HEADER_ETHERNET_II_802_3_SIZE +
2843 HEADER_802_2_SIZE +
2844 HEADER_SNAP_SIZE,
2845 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002846 } else if (nic->rxd_mode == RXD_MODE_3B) {
Veena Parat6d517a22007-07-23 02:20:51 -04002847 rxdp3 = (struct RxD3*)rxdp;
Ananda Raju75c30b12006-07-24 19:55:09 -04002848 pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
Veena Parat6d517a22007-07-23 02:20:51 -04002849 rxdp3->Buffer0_ptr,
2850 BUF0_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002851 pci_unmap_single(nic->pdev, (dma_addr_t)
Veena Parat6d517a22007-07-23 02:20:51 -04002852 rxdp3->Buffer2_ptr,
2853 dev->mtu + 4,
2854 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002855 }
Ananda Raju863c11a2006-04-21 19:03:13 -04002856 prefetch(skb->data);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002857 rx_osm_handler(ring_data, rxdp);
2858 get_info.offset++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002859 ring_data->rx_curr_get_info.offset = get_info.offset;
2860 rxdp = ring_data->rx_blocks[get_block].
2861 rxds[get_info.offset].virt_addr;
2862 if (get_info.offset == rxd_count[nic->rxd_mode]) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002863 get_info.offset = 0;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002864 ring_data->rx_curr_get_info.offset = get_info.offset;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002865 get_block++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002866 if (get_block == ring_data->block_count)
2867 get_block = 0;
2868 ring_data->rx_curr_get_info.block_index = get_block;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002869 rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
2870 }
2871
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002872 nic->pkts_to_process -= 1;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002873 if ((napi) && (!nic->pkts_to_process))
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002874 break;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002875 pkt_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
2877 break;
2878 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002879 if (nic->lro) {
2880 /* Clear all LRO sessions before exiting */
2881 for (i=0; i<MAX_LRO_SESSIONS; i++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002882 struct lro *lro = &nic->lro0_n[i];
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002883 if (lro->in_use) {
2884 update_L3L4_header(nic, lro);
2885 queue_rx_frame(lro->parent);
2886 clear_lro_session(lro);
2887 }
2888 }
2889 }
2890
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002891 spin_unlock(&nic->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002893
2894/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 * tx_intr_handler - Transmit interrupt handler
2896 * @nic : device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002897 * Description:
2898 * If an interrupt was raised to indicate DMA complete of the
2899 * Tx packet, this function is called. It identifies the last TxD
2900 * whose buffer was freed and frees all skbs whose data have already
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 * DMA'ed into the NICs internal memory.
2902 * Return Value:
2903 * NONE
2904 */
2905
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002906static void tx_intr_handler(struct fifo_info *fifo_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002908 struct s2io_nic *nic = fifo_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 struct net_device *dev = (struct net_device *) nic->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002910 struct tx_curr_get_info get_info, put_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 struct sk_buff *skb;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002912 struct TxD *txdlp;
Olaf Heringf9046eb2007-06-19 22:41:10 +02002913 u8 err_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002915 get_info = fifo_data->tx_curr_get_info;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002916 memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info));
2917 txdlp = (struct TxD *) fifo_data->list_info[get_info.offset].
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002918 list_virt_addr;
2919 while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
2920 (get_info.offset != put_info.offset) &&
2921 (txdlp->Host_Control)) {
2922 /* Check for TxD errors */
2923 if (txdlp->Control_1 & TXD_T_CODE) {
2924 unsigned long long err;
2925 err = txdlp->Control_1 & TXD_T_CODE;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002926 if (err & 0x1) {
2927 nic->mac_control.stats_info->sw_stat.
2928 parity_err_cnt++;
2929 }
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04002930
2931 /* update t_code statistics */
Olaf Heringf9046eb2007-06-19 22:41:10 +02002932 err_mask = err >> 48;
2933 switch(err_mask) {
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04002934 case 2:
2935 nic->mac_control.stats_info->sw_stat.
2936 tx_buf_abort_cnt++;
2937 break;
2938
2939 case 3:
2940 nic->mac_control.stats_info->sw_stat.
2941 tx_desc_abort_cnt++;
2942 break;
2943
2944 case 7:
2945 nic->mac_control.stats_info->sw_stat.
2946 tx_parity_err_cnt++;
2947 break;
2948
2949 case 10:
2950 nic->mac_control.stats_info->sw_stat.
2951 tx_link_loss_cnt++;
2952 break;
2953
2954 case 15:
2955 nic->mac_control.stats_info->sw_stat.
2956 tx_list_proc_err_cnt++;
2957 break;
2958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002960
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002961 skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002962 if (skb == NULL) {
2963 DBG_PRINT(ERR_DBG, "%s: Null skb ",
2964 __FUNCTION__);
2965 DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
2966 return;
2967 }
2968
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002969 /* Updating the statistics block */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002970 nic->stats.tx_bytes += skb->len;
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04002971 nic->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002972 dev_kfree_skb_irq(skb);
2973
2974 get_info.offset++;
Ananda Raju863c11a2006-04-21 19:03:13 -04002975 if (get_info.offset == get_info.fifo_len + 1)
2976 get_info.offset = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05002977 txdlp = (struct TxD *) fifo_data->list_info
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002978 [get_info.offset].list_virt_addr;
2979 fifo_data->tx_curr_get_info.offset =
2980 get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 }
2982
2983 spin_lock(&nic->tx_lock);
2984 if (netif_queue_stopped(dev))
2985 netif_wake_queue(dev);
2986 spin_unlock(&nic->tx_lock);
2987}
2988
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002989/**
Ananda Rajubd1034f2006-04-21 19:20:22 -04002990 * s2io_mdio_write - Function to write in to MDIO registers
2991 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
2992 * @addr : address value
2993 * @value : data value
2994 * @dev : pointer to net_device structure
2995 * Description:
2996 * This function is used to write values to the MDIO registers
2997 * NONE
2998 */
2999static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
3000{
3001 u64 val64 = 0x0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003002 struct s2io_nic *sp = dev->priv;
3003 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003004
3005 //address transaction
3006 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
3007 | MDIO_MMD_DEV_ADDR(mmd_type)
3008 | MDIO_MMS_PRT_ADDR(0x0);
3009 writeq(val64, &bar0->mdio_control);
3010 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
3011 writeq(val64, &bar0->mdio_control);
3012 udelay(100);
3013
3014 //Data transaction
3015 val64 = 0x0;
3016 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
3017 | MDIO_MMD_DEV_ADDR(mmd_type)
3018 | MDIO_MMS_PRT_ADDR(0x0)
3019 | MDIO_MDIO_DATA(value)
3020 | MDIO_OP(MDIO_OP_WRITE_TRANS);
3021 writeq(val64, &bar0->mdio_control);
3022 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
3023 writeq(val64, &bar0->mdio_control);
3024 udelay(100);
3025
3026 val64 = 0x0;
3027 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
3028 | MDIO_MMD_DEV_ADDR(mmd_type)
3029 | MDIO_MMS_PRT_ADDR(0x0)
3030 | MDIO_OP(MDIO_OP_READ_TRANS);
3031 writeq(val64, &bar0->mdio_control);
3032 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
3033 writeq(val64, &bar0->mdio_control);
3034 udelay(100);
3035
3036}
3037
3038/**
3039 * s2io_mdio_read - Function to write in to MDIO registers
3040 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
3041 * @addr : address value
3042 * @dev : pointer to net_device structure
3043 * Description:
3044 * This function is used to read values to the MDIO registers
3045 * NONE
3046 */
3047static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
3048{
3049 u64 val64 = 0x0;
3050 u64 rval64 = 0x0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003051 struct s2io_nic *sp = dev->priv;
3052 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003053
3054 /* address transaction */
3055 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
3056 | MDIO_MMD_DEV_ADDR(mmd_type)
3057 | MDIO_MMS_PRT_ADDR(0x0);
3058 writeq(val64, &bar0->mdio_control);
3059 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
3060 writeq(val64, &bar0->mdio_control);
3061 udelay(100);
3062
3063 /* Data transaction */
3064 val64 = 0x0;
3065 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
3066 | MDIO_MMD_DEV_ADDR(mmd_type)
3067 | MDIO_MMS_PRT_ADDR(0x0)
3068 | MDIO_OP(MDIO_OP_READ_TRANS);
3069 writeq(val64, &bar0->mdio_control);
3070 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
3071 writeq(val64, &bar0->mdio_control);
3072 udelay(100);
3073
3074 /* Read the value from regs */
3075 rval64 = readq(&bar0->mdio_control);
3076 rval64 = rval64 & 0xFFFF0000;
3077 rval64 = rval64 >> 16;
3078 return rval64;
3079}
3080/**
3081 * s2io_chk_xpak_counter - Function to check the status of the xpak counters
3082 * @counter : couter value to be updated
3083 * @flag : flag to indicate the status
3084 * @type : counter type
3085 * Description:
3086 * This function is to check the status of the xpak counters value
3087 * NONE
3088 */
3089
3090static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, u16 flag, u16 type)
3091{
3092 u64 mask = 0x3;
3093 u64 val64;
3094 int i;
3095 for(i = 0; i <index; i++)
3096 mask = mask << 0x2;
3097
3098 if(flag > 0)
3099 {
3100 *counter = *counter + 1;
3101 val64 = *regs_stat & mask;
3102 val64 = val64 >> (index * 0x2);
3103 val64 = val64 + 1;
3104 if(val64 == 3)
3105 {
3106 switch(type)
3107 {
3108 case 1:
3109 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
3110 "service. Excessive temperatures may "
3111 "result in premature transceiver "
3112 "failure \n");
3113 break;
3114 case 2:
3115 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
3116 "service Excessive bias currents may "
3117 "indicate imminent laser diode "
3118 "failure \n");
3119 break;
3120 case 3:
3121 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
3122 "service Excessive laser output "
3123 "power may saturate far-end "
3124 "receiver\n");
3125 break;
3126 default:
3127 DBG_PRINT(ERR_DBG, "Incorrect XPAK Alarm "
3128 "type \n");
3129 }
3130 val64 = 0x0;
3131 }
3132 val64 = val64 << (index * 0x2);
3133 *regs_stat = (*regs_stat & (~mask)) | (val64);
3134
3135 } else {
3136 *regs_stat = *regs_stat & (~mask);
3137 }
3138}
3139
3140/**
3141 * s2io_updt_xpak_counter - Function to update the xpak counters
3142 * @dev : pointer to net_device struct
3143 * Description:
3144 * This function is to upate the status of the xpak counters value
3145 * NONE
3146 */
3147static void s2io_updt_xpak_counter(struct net_device *dev)
3148{
3149 u16 flag = 0x0;
3150 u16 type = 0x0;
3151 u16 val16 = 0x0;
3152 u64 val64 = 0x0;
3153 u64 addr = 0x0;
3154
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003155 struct s2io_nic *sp = dev->priv;
3156 struct stat_block *stat_info = sp->mac_control.stats_info;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003157
3158 /* Check the communication with the MDIO slave */
3159 addr = 0x0000;
3160 val64 = 0x0;
3161 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3162 if((val64 == 0xFFFF) || (val64 == 0x0000))
3163 {
3164 DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - "
3165 "Returned %llx\n", (unsigned long long)val64);
3166 return;
3167 }
3168
3169 /* Check for the expecte value of 2040 at PMA address 0x0000 */
3170 if(val64 != 0x2040)
3171 {
3172 DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - ");
3173 DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x2040\n",
3174 (unsigned long long)val64);
3175 return;
3176 }
3177
3178 /* Loading the DOM register to MDIO register */
3179 addr = 0xA100;
3180 s2io_mdio_write(MDIO_MMD_PMA_DEV_ADDR, addr, val16, dev);
3181 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3182
3183 /* Reading the Alarm flags */
3184 addr = 0xA070;
3185 val64 = 0x0;
3186 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3187
3188 flag = CHECKBIT(val64, 0x7);
3189 type = 1;
3190 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_transceiver_temp_high,
3191 &stat_info->xpak_stat.xpak_regs_stat,
3192 0x0, flag, type);
3193
3194 if(CHECKBIT(val64, 0x6))
3195 stat_info->xpak_stat.alarm_transceiver_temp_low++;
3196
3197 flag = CHECKBIT(val64, 0x3);
3198 type = 2;
3199 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_bias_current_high,
3200 &stat_info->xpak_stat.xpak_regs_stat,
3201 0x2, flag, type);
3202
3203 if(CHECKBIT(val64, 0x2))
3204 stat_info->xpak_stat.alarm_laser_bias_current_low++;
3205
3206 flag = CHECKBIT(val64, 0x1);
3207 type = 3;
3208 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_output_power_high,
3209 &stat_info->xpak_stat.xpak_regs_stat,
3210 0x4, flag, type);
3211
3212 if(CHECKBIT(val64, 0x0))
3213 stat_info->xpak_stat.alarm_laser_output_power_low++;
3214
3215 /* Reading the Warning flags */
3216 addr = 0xA074;
3217 val64 = 0x0;
3218 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3219
3220 if(CHECKBIT(val64, 0x7))
3221 stat_info->xpak_stat.warn_transceiver_temp_high++;
3222
3223 if(CHECKBIT(val64, 0x6))
3224 stat_info->xpak_stat.warn_transceiver_temp_low++;
3225
3226 if(CHECKBIT(val64, 0x3))
3227 stat_info->xpak_stat.warn_laser_bias_current_high++;
3228
3229 if(CHECKBIT(val64, 0x2))
3230 stat_info->xpak_stat.warn_laser_bias_current_low++;
3231
3232 if(CHECKBIT(val64, 0x1))
3233 stat_info->xpak_stat.warn_laser_output_power_high++;
3234
3235 if(CHECKBIT(val64, 0x0))
3236 stat_info->xpak_stat.warn_laser_output_power_low++;
3237}
3238
3239/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 * wait_for_cmd_complete - waits for a command to complete.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003241 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003243 * Description: Function that waits for a command to Write into RMAC
3244 * ADDR DATA registers to be completed and returns either success or
3245 * error depending on whether the command was complete or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 * Return value:
3247 * SUCCESS on success and FAILURE on failure.
3248 */
3249
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003250static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit,
3251 int bit_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252{
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003253 int ret = FAILURE, cnt = 0, delay = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 u64 val64;
3255
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003256 if ((bit_state != S2IO_BIT_RESET) && (bit_state != S2IO_BIT_SET))
3257 return FAILURE;
3258
3259 do {
Ananda Rajuc92ca042006-04-21 19:18:03 -04003260 val64 = readq(addr);
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003261 if (bit_state == S2IO_BIT_RESET) {
3262 if (!(val64 & busy_bit)) {
3263 ret = SUCCESS;
3264 break;
3265 }
3266 } else {
3267 if (!(val64 & busy_bit)) {
3268 ret = SUCCESS;
3269 break;
3270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003272
3273 if(in_interrupt())
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003274 mdelay(delay);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003275 else
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003276 msleep(delay);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003277
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05003278 if (++cnt >= 10)
3279 delay = 50;
3280 } while (cnt < 20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 return ret;
3282}
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003283/*
3284 * check_pci_device_id - Checks if the device id is supported
3285 * @id : device id
3286 * Description: Function to check if the pci device id is supported by driver.
3287 * Return value: Actual device id if supported else PCI_ANY_ID
3288 */
3289static u16 check_pci_device_id(u16 id)
3290{
3291 switch (id) {
3292 case PCI_DEVICE_ID_HERC_WIN:
3293 case PCI_DEVICE_ID_HERC_UNI:
3294 return XFRAME_II_DEVICE;
3295 case PCI_DEVICE_ID_S2IO_UNI:
3296 case PCI_DEVICE_ID_S2IO_WIN:
3297 return XFRAME_I_DEVICE;
3298 default:
3299 return PCI_ANY_ID;
3300 }
3301}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003303/**
3304 * s2io_reset - Resets the card.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 * @sp : private member of the device structure.
3306 * Description: Function to Reset the card. This function then also
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003307 * restores the previously saved PCI configuration space registers as
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 * the card reset also resets the configuration space.
3309 * Return value:
3310 * void.
3311 */
3312
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003313static void s2io_reset(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003315 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 u64 val64;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003317 u16 subid, pci_cmd;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003318 int i;
3319 u16 val16;
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003320 unsigned long long up_cnt, down_cnt, up_time, down_time, reset_cnt;
3321 unsigned long long mem_alloc_cnt, mem_free_cnt, watchdog_cnt;
3322
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003323 DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
3324 __FUNCTION__, sp->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003326 /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003327 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003328
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 val64 = SW_RESET_ALL;
3330 writeq(val64, &bar0->sw_reset);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003331 if (strstr(sp->product_name, "CX4")) {
3332 msleep(750);
3333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 msleep(250);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003335 for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) {
3336
3337 /* Restore the PCI state saved during initialization. */
3338 pci_restore_state(sp->pdev);
3339 pci_read_config_word(sp->pdev, 0x2, &val16);
3340 if (check_pci_device_id(val16) != (u16)PCI_ANY_ID)
3341 break;
3342 msleep(200);
3343 }
3344
3345 if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) {
3346 DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__);
3347 }
3348
3349 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd);
3350
3351 s2io_init_pci(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003353 /* Set swapper to enable I/O register access */
3354 s2io_set_swapper(sp);
3355
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003356 /* Restore the MSIX table entries from local variables */
3357 restore_xmsi_data(sp);
3358
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003359 /* Clear certain PCI/PCI-X fields after reset */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003360 if (sp->device_type == XFRAME_II_DEVICE) {
Ananda Rajub41477f2006-07-24 19:52:49 -04003361 /* Clear "detected parity error" bit */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003362 pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003363
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003364 /* Clearing PCIX Ecc status register */
3365 pci_write_config_dword(sp->pdev, 0x68, 0x7C);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003366
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003367 /* Clearing PCI_STATUS error reflected here */
3368 writeq(BIT(62), &bar0->txpic_int_reg);
3369 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003370
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003371 /* Reset device statistics maintained by OS */
3372 memset(&sp->stats, 0, sizeof (struct net_device_stats));
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04003373
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003374 up_cnt = sp->mac_control.stats_info->sw_stat.link_up_cnt;
3375 down_cnt = sp->mac_control.stats_info->sw_stat.link_down_cnt;
3376 up_time = sp->mac_control.stats_info->sw_stat.link_up_time;
3377 down_time = sp->mac_control.stats_info->sw_stat.link_down_time;
Ramkrishna Vepa363dc362007-03-06 17:01:00 -08003378 reset_cnt = sp->mac_control.stats_info->sw_stat.soft_reset_cnt;
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003379 mem_alloc_cnt = sp->mac_control.stats_info->sw_stat.mem_allocated;
3380 mem_free_cnt = sp->mac_control.stats_info->sw_stat.mem_freed;
3381 watchdog_cnt = sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt;
3382 /* save link up/down time/cnt, reset/memory/watchdog cnt */
Ramkrishna Vepa363dc362007-03-06 17:01:00 -08003383 memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003384 /* restore link up/down time/cnt, reset/memory/watchdog cnt */
3385 sp->mac_control.stats_info->sw_stat.link_up_cnt = up_cnt;
3386 sp->mac_control.stats_info->sw_stat.link_down_cnt = down_cnt;
3387 sp->mac_control.stats_info->sw_stat.link_up_time = up_time;
3388 sp->mac_control.stats_info->sw_stat.link_down_time = down_time;
Ramkrishna Vepa363dc362007-03-06 17:01:00 -08003389 sp->mac_control.stats_info->sw_stat.soft_reset_cnt = reset_cnt;
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003390 sp->mac_control.stats_info->sw_stat.mem_allocated = mem_alloc_cnt;
3391 sp->mac_control.stats_info->sw_stat.mem_freed = mem_free_cnt;
3392 sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt = watchdog_cnt;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003393
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 /* SXE-002: Configure link and activity LED to turn it off */
3395 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003396 if (((subid & 0xFF) >= 0x07) &&
3397 (sp->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 val64 = readq(&bar0->gpio_control);
3399 val64 |= 0x0000800000000000ULL;
3400 writeq(val64, &bar0->gpio_control);
3401 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01003402 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 }
3404
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003405 /*
3406 * Clear spurious ECC interrupts that would have occured on
3407 * XFRAME II cards after reset.
3408 */
3409 if (sp->device_type == XFRAME_II_DEVICE) {
3410 val64 = readq(&bar0->pcc_err_reg);
3411 writeq(val64, &bar0->pcc_err_reg);
3412 }
3413
Sivakumar Subramanid8d70ca2007-02-24 02:04:24 -05003414 /* restore the previously assigned mac address */
3415 s2io_set_mac_addr(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr);
3416
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 sp->device_enabled_once = FALSE;
3418}
3419
3420/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003421 * s2io_set_swapper - to set the swapper controle on the card
3422 * @sp : private member of the device structure,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 * pointer to the s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003424 * Description: Function to set the swapper control on the card
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 * correctly depending on the 'endianness' of the system.
3426 * Return value:
3427 * SUCCESS on success and FAILURE on failure.
3428 */
3429
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003430static int s2io_set_swapper(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431{
3432 struct net_device *dev = sp->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003433 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 u64 val64, valt, valr;
3435
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003436 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 * Set proper endian settings and verify the same by reading
3438 * the PIF Feed-back register.
3439 */
3440
3441 val64 = readq(&bar0->pif_rd_swapper_fb);
3442 if (val64 != 0x0123456789ABCDEFULL) {
3443 int i = 0;
3444 u64 value[] = { 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */
3445 0x8100008181000081ULL, /* FE=1, SE=0 */
3446 0x4200004242000042ULL, /* FE=0, SE=1 */
3447 0}; /* FE=0, SE=0 */
3448
3449 while(i<4) {
3450 writeq(value[i], &bar0->swapper_ctrl);
3451 val64 = readq(&bar0->pif_rd_swapper_fb);
3452 if (val64 == 0x0123456789ABCDEFULL)
3453 break;
3454 i++;
3455 }
3456 if (i == 4) {
3457 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3458 dev->name);
3459 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3460 (unsigned long long) val64);
3461 return FAILURE;
3462 }
3463 valr = value[i];
3464 } else {
3465 valr = readq(&bar0->swapper_ctrl);
3466 }
3467
3468 valt = 0x0123456789ABCDEFULL;
3469 writeq(valt, &bar0->xmsi_address);
3470 val64 = readq(&bar0->xmsi_address);
3471
3472 if(val64 != valt) {
3473 int i = 0;
3474 u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */
3475 0x0081810000818100ULL, /* FE=1, SE=0 */
3476 0x0042420000424200ULL, /* FE=0, SE=1 */
3477 0}; /* FE=0, SE=0 */
3478
3479 while(i<4) {
3480 writeq((value[i] | valr), &bar0->swapper_ctrl);
3481 writeq(valt, &bar0->xmsi_address);
3482 val64 = readq(&bar0->xmsi_address);
3483 if(val64 == valt)
3484 break;
3485 i++;
3486 }
3487 if(i == 4) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003488 unsigned long long x = val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr ");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003490 DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 return FAILURE;
3492 }
3493 }
3494 val64 = readq(&bar0->swapper_ctrl);
3495 val64 &= 0xFFFF000000000000ULL;
3496
3497#ifdef __BIG_ENDIAN
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003498 /*
3499 * The device by default set to a big endian format, so a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 * big endian driver need not set anything.
3501 */
3502 val64 |= (SWAPPER_CTRL_TXP_FE |
3503 SWAPPER_CTRL_TXP_SE |
3504 SWAPPER_CTRL_TXD_R_FE |
3505 SWAPPER_CTRL_TXD_W_FE |
3506 SWAPPER_CTRL_TXF_R_FE |
3507 SWAPPER_CTRL_RXD_R_FE |
3508 SWAPPER_CTRL_RXD_W_FE |
3509 SWAPPER_CTRL_RXF_W_FE |
3510 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07003512 if (sp->config.intr_type == INTA)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003513 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 writeq(val64, &bar0->swapper_ctrl);
3515#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003516 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 * Initially we enable all bits to make it accessible by the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003518 * driver, then we selectively enable only those bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519 * we want to set.
3520 */
3521 val64 |= (SWAPPER_CTRL_TXP_FE |
3522 SWAPPER_CTRL_TXP_SE |
3523 SWAPPER_CTRL_TXD_R_FE |
3524 SWAPPER_CTRL_TXD_R_SE |
3525 SWAPPER_CTRL_TXD_W_FE |
3526 SWAPPER_CTRL_TXD_W_SE |
3527 SWAPPER_CTRL_TXF_R_FE |
3528 SWAPPER_CTRL_RXD_R_FE |
3529 SWAPPER_CTRL_RXD_R_SE |
3530 SWAPPER_CTRL_RXD_W_FE |
3531 SWAPPER_CTRL_RXD_W_SE |
3532 SWAPPER_CTRL_RXF_W_FE |
3533 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07003535 if (sp->config.intr_type == INTA)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003536 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 writeq(val64, &bar0->swapper_ctrl);
3538#endif
3539 val64 = readq(&bar0->swapper_ctrl);
3540
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003541 /*
3542 * Verifying if endian settings are accurate by reading a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 * feedback register.
3544 */
3545 val64 = readq(&bar0->pif_rd_swapper_fb);
3546 if (val64 != 0x0123456789ABCDEFULL) {
3547 /* Endian settings are incorrect, calls for another dekko. */
3548 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3549 dev->name);
3550 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3551 (unsigned long long) val64);
3552 return FAILURE;
3553 }
3554
3555 return SUCCESS;
3556}
3557
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003558static int wait_for_msix_trans(struct s2io_nic *nic, int i)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003559{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003560 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003561 u64 val64;
3562 int ret = 0, cnt = 0;
3563
3564 do {
3565 val64 = readq(&bar0->xmsi_access);
3566 if (!(val64 & BIT(15)))
3567 break;
3568 mdelay(1);
3569 cnt++;
3570 } while(cnt < 5);
3571 if (cnt == 5) {
3572 DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i);
3573 ret = 1;
3574 }
3575
3576 return ret;
3577}
3578
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003579static void restore_xmsi_data(struct s2io_nic *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003580{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003581 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003582 u64 val64;
3583 int i;
3584
Ananda Raju75c30b12006-07-24 19:55:09 -04003585 for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003586 writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
3587 writeq(nic->msix_info[i].data, &bar0->xmsi_data);
3588 val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
3589 writeq(val64, &bar0->xmsi_access);
3590 if (wait_for_msix_trans(nic, i)) {
3591 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3592 continue;
3593 }
3594 }
3595}
3596
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003597static void store_xmsi_data(struct s2io_nic *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003598{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003599 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003600 u64 val64, addr, data;
3601 int i;
3602
3603 /* Store and display */
Ananda Raju75c30b12006-07-24 19:55:09 -04003604 for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003605 val64 = (BIT(15) | vBIT(i, 26, 6));
3606 writeq(val64, &bar0->xmsi_access);
3607 if (wait_for_msix_trans(nic, i)) {
3608 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3609 continue;
3610 }
3611 addr = readq(&bar0->xmsi_address);
3612 data = readq(&bar0->xmsi_data);
3613 if (addr && data) {
3614 nic->msix_info[i].addr = addr;
3615 nic->msix_info[i].data = data;
3616 }
3617 }
3618}
3619
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003620static int s2io_enable_msi_x(struct s2io_nic *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003621{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003622 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003623 u64 tx_mat, rx_mat;
3624 u16 msi_control; /* Temp variable */
3625 int ret, i, j, msix_indx = 1;
3626
Sivakumar Subramanibd684e42007-09-14 07:28:50 -04003627 nic->entries = kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct msix_entry),
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003628 GFP_KERNEL);
Sivakumar Subramanibd684e42007-09-14 07:28:50 -04003629 if (!nic->entries) {
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003630 DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \
3631 __FUNCTION__);
Sreenivasa Honnurc53d4942007-05-10 04:18:54 -04003632 nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003633 return -ENOMEM;
3634 }
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04003635 nic->mac_control.stats_info->sw_stat.mem_allocated
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003636 += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003637
3638 nic->s2io_entries =
Sivakumar Subramanibd684e42007-09-14 07:28:50 -04003639 kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct s2io_msix_entry),
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003640 GFP_KERNEL);
Sivakumar Subramanibd684e42007-09-14 07:28:50 -04003641 if (!nic->s2io_entries) {
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04003642 DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n",
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003643 __FUNCTION__);
Sreenivasa Honnurc53d4942007-05-10 04:18:54 -04003644 nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003645 kfree(nic->entries);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04003646 nic->mac_control.stats_info->sw_stat.mem_freed
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003647 += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003648 return -ENOMEM;
3649 }
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04003650 nic->mac_control.stats_info->sw_stat.mem_allocated
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003651 += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003652
3653 for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
3654 nic->entries[i].entry = i;
3655 nic->s2io_entries[i].entry = i;
3656 nic->s2io_entries[i].arg = NULL;
3657 nic->s2io_entries[i].in_use = 0;
3658 }
3659
3660 tx_mat = readq(&bar0->tx_mat0_n[0]);
3661 for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) {
3662 tx_mat |= TX_MAT_SET(i, msix_indx);
3663 nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i];
3664 nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE;
3665 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3666 }
3667 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3668
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04003669 rx_mat = readq(&bar0->rx_mat);
3670 for (j = 0; j < nic->config.rx_ring_num; j++, msix_indx++) {
3671 rx_mat |= RX_MAT_SET(j, msix_indx);
3672 nic->s2io_entries[msix_indx].arg
3673 = &nic->mac_control.rings[j];
3674 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3675 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003676 }
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04003677 writeq(rx_mat, &bar0->rx_mat);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003678
Ananda Rajuc92ca042006-04-21 19:18:03 -04003679 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003680 ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003681 /* We fail init if error or we get less vectors than min required */
3682 if (ret >= (nic->config.tx_fifo_num + nic->config.rx_ring_num + 1)) {
3683 nic->avail_msix_vectors = ret;
3684 ret = pci_enable_msix(nic->pdev, nic->entries, ret);
3685 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003686 if (ret) {
3687 DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
3688 kfree(nic->entries);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04003689 nic->mac_control.stats_info->sw_stat.mem_freed
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003690 += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003691 kfree(nic->s2io_entries);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04003692 nic->mac_control.stats_info->sw_stat.mem_freed
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003693 += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003694 nic->entries = NULL;
3695 nic->s2io_entries = NULL;
Ananda Rajuc92ca042006-04-21 19:18:03 -04003696 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003697 return -ENOMEM;
3698 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003699 if (!nic->avail_msix_vectors)
3700 nic->avail_msix_vectors = MAX_REQUESTED_MSI_X;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003701
3702 /*
3703 * To enable MSI-X, MSI also needs to be enabled, due to a bug
3704 * in the herc NIC. (Temp change, needs to be removed later)
3705 */
3706 pci_read_config_word(nic->pdev, 0x42, &msi_control);
3707 msi_control |= 0x1; /* Enable MSI */
3708 pci_write_config_word(nic->pdev, 0x42, msi_control);
3709
3710 return 0;
3711}
3712
Sivakumar Subramani8abc4d52007-09-15 13:11:34 -07003713/* Handle software interrupt used during MSI(X) test */
3714static irqreturn_t __devinit s2io_test_intr(int irq, void *dev_id)
3715{
3716 struct s2io_nic *sp = dev_id;
3717
3718 sp->msi_detected = 1;
3719 wake_up(&sp->msi_wait);
3720
3721 return IRQ_HANDLED;
3722}
3723
3724/* Test interrupt path by forcing a a software IRQ */
3725static int __devinit s2io_test_msi(struct s2io_nic *sp)
3726{
3727 struct pci_dev *pdev = sp->pdev;
3728 struct XENA_dev_config __iomem *bar0 = sp->bar0;
3729 int err;
3730 u64 val64, saved64;
3731
3732 err = request_irq(sp->entries[1].vector, s2io_test_intr, 0,
3733 sp->name, sp);
3734 if (err) {
3735 DBG_PRINT(ERR_DBG, "%s: PCI %s: cannot assign irq %d\n",
3736 sp->dev->name, pci_name(pdev), pdev->irq);
3737 return err;
3738 }
3739
3740 init_waitqueue_head (&sp->msi_wait);
3741 sp->msi_detected = 0;
3742
3743 saved64 = val64 = readq(&bar0->scheduled_int_ctrl);
3744 val64 |= SCHED_INT_CTRL_ONE_SHOT;
3745 val64 |= SCHED_INT_CTRL_TIMER_EN;
3746 val64 |= SCHED_INT_CTRL_INT2MSI(1);
3747 writeq(val64, &bar0->scheduled_int_ctrl);
3748
3749 wait_event_timeout(sp->msi_wait, sp->msi_detected, HZ/10);
3750
3751 if (!sp->msi_detected) {
3752 /* MSI(X) test failed, go back to INTx mode */
3753 DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated"
3754 "using MSI(X) during test\n", sp->dev->name,
3755 pci_name(pdev));
3756
3757 err = -EOPNOTSUPP;
3758 }
3759
3760 free_irq(sp->entries[1].vector, sp);
3761
3762 writeq(saved64, &bar0->scheduled_int_ctrl);
3763
3764 return err;
3765}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766/* ********************************************************* *
3767 * Functions defined below concern the OS part of the driver *
3768 * ********************************************************* */
3769
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003770/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 * s2io_open - open entry point of the driver
3772 * @dev : pointer to the device structure.
3773 * Description:
3774 * This function is the open entry point of the driver. It mainly calls a
3775 * function to allocate Rx buffers and inserts them into the buffer
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003776 * descriptors and then enables the Rx part of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 * Return value:
3778 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3779 * file on failure.
3780 */
3781
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003782static int s2io_open(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003784 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 int err = 0;
3786
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003787 /*
3788 * Make sure you have link off by default every time
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 * Nic is initialized
3790 */
3791 netif_carrier_off(dev);
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003792 sp->last_link_state = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003794 napi_enable(&sp->napi);
3795
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07003796 if (sp->config.intr_type == MSI_X) {
Sivakumar Subramani8abc4d52007-09-15 13:11:34 -07003797 int ret = s2io_enable_msi_x(sp);
3798
3799 if (!ret) {
3800 u16 msi_control;
3801
3802 ret = s2io_test_msi(sp);
3803
3804 /* rollback MSI-X, will re-enable during add_isr() */
3805 kfree(sp->entries);
3806 sp->mac_control.stats_info->sw_stat.mem_freed +=
3807 (MAX_REQUESTED_MSI_X *
3808 sizeof(struct msix_entry));
3809 kfree(sp->s2io_entries);
3810 sp->mac_control.stats_info->sw_stat.mem_freed +=
3811 (MAX_REQUESTED_MSI_X *
3812 sizeof(struct s2io_msix_entry));
3813 sp->entries = NULL;
3814 sp->s2io_entries = NULL;
3815
3816 pci_read_config_word(sp->pdev, 0x42, &msi_control);
3817 msi_control &= 0xFFFE; /* Disable MSI */
3818 pci_write_config_word(sp->pdev, 0x42, msi_control);
3819
3820 pci_disable_msix(sp->pdev);
3821
3822 }
3823 if (ret) {
3824
3825 DBG_PRINT(ERR_DBG,
3826 "%s: MSI-X requested but failed to enable\n",
3827 dev->name);
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07003828 sp->config.intr_type = INTA;
Sivakumar Subramani8abc4d52007-09-15 13:11:34 -07003829 }
3830 }
3831
Sivakumar Subramanic77dd432007-08-06 05:36:28 -04003832 /* NAPI doesn't work well with MSI(X) */
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07003833 if (sp->config.intr_type != INTA) {
Sivakumar Subramanic77dd432007-08-06 05:36:28 -04003834 if(sp->config.napi)
3835 sp->config.napi = 0;
3836 }
3837
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 /* Initialize H/W and enable interrupts */
Ananda Rajuc92ca042006-04-21 19:18:03 -04003839 err = s2io_card_up(sp);
3840 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
3842 dev->name);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003843 goto hw_init_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 }
3845
3846 if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
3847 DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003848 s2io_card_down(sp);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003849 err = -ENODEV;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003850 goto hw_init_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851 }
3852
3853 netif_start_queue(dev);
3854 return 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003855
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003856hw_init_failed:
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003857 napi_disable(&sp->napi);
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07003858 if (sp->config.intr_type == MSI_X) {
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003859 if (sp->entries) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003860 kfree(sp->entries);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04003861 sp->mac_control.stats_info->sw_stat.mem_freed
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003862 += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
3863 }
3864 if (sp->s2io_entries) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003865 kfree(sp->s2io_entries);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04003866 sp->mac_control.stats_info->sw_stat.mem_freed
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003867 += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
3868 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003869 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003870 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871}
3872
3873/**
3874 * s2io_close -close entry point of the driver
3875 * @dev : device pointer.
3876 * Description:
3877 * This is the stop entry point of the driver. It needs to undo exactly
3878 * whatever was done by the open entry point,thus it's usually referred to
3879 * as the close function.Among other things this function mainly stops the
3880 * Rx side of the NIC and frees all the Rx buffers in the Rx rings.
3881 * Return value:
3882 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3883 * file on failure.
3884 */
3885
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003886static int s2io_close(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003888 struct s2io_nic *sp = dev->priv;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003889
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 netif_stop_queue(dev);
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003891 napi_disable(&sp->napi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 /* Reset card, kill tasklet and free Tx and Rx buffers. */
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003893 s2io_card_down(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 return 0;
3896}
3897
3898/**
3899 * s2io_xmit - Tx entry point of te driver
3900 * @skb : the socket buffer containing the Tx data.
3901 * @dev : device pointer.
3902 * Description :
3903 * This function is the Tx entry point of the driver. S2IO NIC supports
3904 * certain protocol assist features on Tx side, namely CSO, S/G, LSO.
3905 * NOTE: when device cant queue the pkt,just the trans_start variable will
3906 * not be upadted.
3907 * Return value:
3908 * 0 on success & 1 on failure.
3909 */
3910
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003911static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003913 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
3915 register u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003916 struct TxD *txdp;
3917 struct TxFIFO_element __iomem *tx_fifo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 unsigned long flags;
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003919 u16 vlan_tag = 0;
3920 int vlan_priority = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003921 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 struct config_param *config;
Ananda Raju75c30b12006-07-24 19:55:09 -04003923 int offload_type;
Veena Parat491abf22007-07-23 02:37:14 -04003924 struct swStat *stats = &sp->mac_control.stats_info->sw_stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925
3926 mac_control = &sp->mac_control;
3927 config = &sp->config;
3928
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003929 DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name);
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04003930
3931 if (unlikely(skb->len <= 0)) {
3932 DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
3933 dev_kfree_skb_any(skb);
3934 return 0;
3935}
3936
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 spin_lock_irqsave(&sp->tx_lock, flags);
Sivakumar Subramani92b84432007-09-06 06:51:14 -04003938 if (!is_s2io_card_up(sp)) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003939 DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 dev->name);
3941 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003942 dev_kfree_skb(skb);
3943 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 }
3945
3946 queue = 0;
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003947 /* Get Fifo number to Transmit based on vlan priority */
3948 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3949 vlan_tag = vlan_tx_tag_get(skb);
3950 vlan_priority = vlan_tag >> 13;
3951 queue = config->fifo_mapping[vlan_priority];
3952 }
3953
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003954 put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
3955 get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05003956 txdp = (struct TxD *) mac_control->fifos[queue].list_info[put_off].
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003957 list_virt_addr;
3958
3959 queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04003961 if (txdp->Host_Control ||
3962 ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003963 DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 netif_stop_queue(dev);
3965 dev_kfree_skb(skb);
3966 spin_unlock_irqrestore(&sp->tx_lock, flags);
3967 return 0;
3968 }
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003969
Ananda Raju75c30b12006-07-24 19:55:09 -04003970 offload_type = s2io_offload_type(skb);
Ananda Raju75c30b12006-07-24 19:55:09 -04003971 if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 txdp->Control_1 |= TXD_TCP_LSO_EN;
Ananda Raju75c30b12006-07-24 19:55:09 -04003973 txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 }
Patrick McHardy84fa7932006-08-29 16:44:56 -07003975 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 txdp->Control_2 |=
3977 (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
3978 TXD_TX_CKO_UDP_EN);
3979 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003980 txdp->Control_1 |= TXD_GATHER_CODE_FIRST;
3981 txdp->Control_1 |= TXD_LIST_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 txdp->Control_2 |= config->tx_intr_type;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07003983
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003984 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3985 txdp->Control_2 |= TXD_VLAN_ENABLE;
3986 txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
3987 }
3988
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003989 frg_len = skb->len - skb->data_len;
Ananda Raju75c30b12006-07-24 19:55:09 -04003990 if (offload_type == SKB_GSO_UDP) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003991 int ufo_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992
Ananda Raju75c30b12006-07-24 19:55:09 -04003993 ufo_size = s2io_udp_mss(skb);
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003994 ufo_size &= ~7;
3995 txdp->Control_1 |= TXD_UFO_EN;
3996 txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
3997 txdp->Control_1 |= TXD_BUFFER0_SIZE(8);
3998#ifdef __BIG_ENDIAN
3999 sp->ufo_in_band_v[put_off] =
4000 (u64)skb_shinfo(skb)->ip6_frag_id;
4001#else
4002 sp->ufo_in_band_v[put_off] =
4003 (u64)skb_shinfo(skb)->ip6_frag_id << 32;
4004#endif
4005 txdp->Host_Control = (unsigned long)sp->ufo_in_band_v;
4006 txdp->Buffer_Pointer = pci_map_single(sp->pdev,
4007 sp->ufo_in_band_v,
4008 sizeof(u64), PCI_DMA_TODEVICE);
Veena Parat491abf22007-07-23 02:37:14 -04004009 if((txdp->Buffer_Pointer == 0) ||
4010 (txdp->Buffer_Pointer == DMA_ERROR_CODE))
4011 goto pci_map_failed;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05004012 txdp++;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05004013 }
4014
4015 txdp->Buffer_Pointer = pci_map_single
4016 (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
Veena Parat491abf22007-07-23 02:37:14 -04004017 if((txdp->Buffer_Pointer == 0) ||
4018 (txdp->Buffer_Pointer == DMA_ERROR_CODE))
4019 goto pci_map_failed;
4020
Ananda Rajufed5ecc2005-11-14 15:25:08 -05004021 txdp->Host_Control = (unsigned long) skb;
4022 txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
Ananda Raju75c30b12006-07-24 19:55:09 -04004023 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05004024 txdp->Control_1 |= TXD_UFO_EN;
4025
4026 frg_cnt = skb_shinfo(skb)->nr_frags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 /* For fragmented SKB. */
4028 for (i = 0; i < frg_cnt; i++) {
4029 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07004030 /* A '0' length fragment will be ignored */
4031 if (!frag->size)
4032 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 txdp++;
4034 txdp->Buffer_Pointer = (u64) pci_map_page
4035 (sp->pdev, frag->page, frag->page_offset,
4036 frag->size, PCI_DMA_TODEVICE);
Ananda Rajuefd51b52006-01-19 14:11:54 -05004037 txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
Ananda Raju75c30b12006-07-24 19:55:09 -04004038 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05004039 txdp->Control_1 |= TXD_UFO_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 }
4041 txdp->Control_1 |= TXD_GATHER_CODE_LAST;
4042
Ananda Raju75c30b12006-07-24 19:55:09 -04004043 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05004044 frg_cnt++; /* as Txd0 was used for inband header */
4045
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 tx_fifo = mac_control->tx_FIFO_start[queue];
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004047 val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 writeq(val64, &tx_fifo->TxDL_Pointer);
4049
4050 val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
4051 TX_FIFO_LAST_LIST);
Ananda Raju75c30b12006-07-24 19:55:09 -04004052 if (offload_type)
4053 val64 |= TX_FIFO_SPECIAL_FUNC;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004054
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055 writeq(val64, &tx_fifo->List_Control);
4056
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07004057 mmiowb();
4058
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 put_off++;
Ananda Raju863c11a2006-04-21 19:03:13 -04004060 if (put_off == mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1)
4061 put_off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004062 mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063
4064 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04004065 if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04004066 sp->mac_control.stats_info->sw_stat.fifo_full_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 DBG_PRINT(TX_DBG,
4068 "No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
4069 put_off, get_off);
4070 netif_stop_queue(dev);
4071 }
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04004072 mac_control->stats_info->sw_stat.mem_allocated += skb->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073 dev->trans_start = jiffies;
4074 spin_unlock_irqrestore(&sp->tx_lock, flags);
4075
4076 return 0;
Veena Parat491abf22007-07-23 02:37:14 -04004077pci_map_failed:
4078 stats->pci_map_fail_cnt++;
4079 netif_stop_queue(dev);
4080 stats->mem_freed += skb->truesize;
4081 dev_kfree_skb(skb);
4082 spin_unlock_irqrestore(&sp->tx_lock, flags);
4083 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084}
4085
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07004086static void
4087s2io_alarm_handle(unsigned long data)
4088{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004089 struct s2io_nic *sp = (struct s2io_nic *)data;
Sivakumar Subramani8116f3c2007-09-17 13:05:35 -07004090 struct net_device *dev = sp->dev;
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07004091
Sivakumar Subramani8116f3c2007-09-17 13:05:35 -07004092 s2io_handle_errors(dev);
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07004093 mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
4094}
4095
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004096static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
Ananda Raju75c30b12006-07-24 19:55:09 -04004097{
4098 int rxb_size, level;
4099
4100 if (!sp->lro) {
4101 rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
4102 level = rx_buffer_level(sp, rxb_size, rng_n);
4103
4104 if ((level == PANIC) && (!TASKLET_IN_USE)) {
4105 int ret;
4106 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
4107 DBG_PRINT(INTR_DBG, "PANIC levels\n");
4108 if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08004109 DBG_PRINT(INFO_DBG, "Out of memory in %s",
Ananda Raju75c30b12006-07-24 19:55:09 -04004110 __FUNCTION__);
4111 clear_bit(0, (&sp->tasklet_status));
4112 return -1;
4113 }
4114 clear_bit(0, (&sp->tasklet_status));
4115 } else if (level == LOW)
4116 tasklet_schedule(&sp->task);
4117
4118 } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08004119 DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
4120 DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
Ananda Raju75c30b12006-07-24 19:55:09 -04004121 }
4122 return 0;
4123}
4124
David Howells7d12e782006-10-05 14:55:46 +01004125static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004126{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004127 struct ring_info *ring = (struct ring_info *)dev_id;
4128 struct s2io_nic *sp = ring->nic;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004129
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07004130 if (!is_s2io_card_up(sp))
Sivakumar Subramani92b84432007-09-06 06:51:14 -04004131 return IRQ_HANDLED;
Sivakumar Subramani92b84432007-09-06 06:51:14 -04004132
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004133 rx_intr_handler(ring);
Ananda Raju75c30b12006-07-24 19:55:09 -04004134 s2io_chk_rx_buffers(sp, ring->ring_no);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004135
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004136 return IRQ_HANDLED;
4137}
4138
David Howells7d12e782006-10-05 14:55:46 +01004139static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004140{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004141 struct fifo_info *fifo = (struct fifo_info *)dev_id;
4142 struct s2io_nic *sp = fifo->nic;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004143
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07004144 if (!is_s2io_card_up(sp))
Sivakumar Subramani92b84432007-09-06 06:51:14 -04004145 return IRQ_HANDLED;
Sivakumar Subramani92b84432007-09-06 06:51:14 -04004146
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004147 tx_intr_handler(fifo);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004148 return IRQ_HANDLED;
4149}
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004150static void s2io_txpic_intr_handle(struct s2io_nic *sp)
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004151{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004152 struct XENA_dev_config __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004153 u64 val64;
4154
4155 val64 = readq(&bar0->pic_int_status);
4156 if (val64 & PIC_INT_GPIO) {
4157 val64 = readq(&bar0->gpio_int_reg);
4158 if ((val64 & GPIO_INT_REG_LINK_DOWN) &&
4159 (val64 & GPIO_INT_REG_LINK_UP)) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04004160 /*
4161 * This is unstable state so clear both up/down
4162 * interrupt and adapter to re-evaluate the link state.
4163 */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004164 val64 |= GPIO_INT_REG_LINK_DOWN;
4165 val64 |= GPIO_INT_REG_LINK_UP;
4166 writeq(val64, &bar0->gpio_int_reg);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004167 val64 = readq(&bar0->gpio_int_mask);
4168 val64 &= ~(GPIO_INT_MASK_LINK_UP |
4169 GPIO_INT_MASK_LINK_DOWN);
4170 writeq(val64, &bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004171 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04004172 else if (val64 & GPIO_INT_REG_LINK_UP) {
4173 val64 = readq(&bar0->adapter_status);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004174 /* Enable Adapter */
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004175 val64 = readq(&bar0->adapter_control);
4176 val64 |= ADAPTER_CNTL_EN;
4177 writeq(val64, &bar0->adapter_control);
4178 val64 |= ADAPTER_LED_ON;
4179 writeq(val64, &bar0->adapter_control);
4180 if (!sp->device_enabled_once)
4181 sp->device_enabled_once = 1;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004182
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004183 s2io_link(sp, LINK_UP);
4184 /*
4185 * unmask link down interrupt and mask link-up
4186 * intr
4187 */
4188 val64 = readq(&bar0->gpio_int_mask);
4189 val64 &= ~GPIO_INT_MASK_LINK_DOWN;
4190 val64 |= GPIO_INT_MASK_LINK_UP;
4191 writeq(val64, &bar0->gpio_int_mask);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004192
Ananda Rajuc92ca042006-04-21 19:18:03 -04004193 }else if (val64 & GPIO_INT_REG_LINK_DOWN) {
4194 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004195 s2io_link(sp, LINK_DOWN);
4196 /* Link is down so unmaks link up interrupt */
4197 val64 = readq(&bar0->gpio_int_mask);
4198 val64 &= ~GPIO_INT_MASK_LINK_UP;
4199 val64 |= GPIO_INT_MASK_LINK_DOWN;
4200 writeq(val64, &bar0->gpio_int_mask);
Sivakumar Subramaniac1f90d2007-02-24 02:01:31 -05004201
4202 /* turn off LED */
4203 val64 = readq(&bar0->adapter_control);
4204 val64 = val64 &(~ADAPTER_LED_ON);
4205 writeq(val64, &bar0->adapter_control);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004206 }
4207 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04004208 val64 = readq(&bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004209}
4210
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211/**
Sivakumar Subramani8116f3c2007-09-17 13:05:35 -07004212 * do_s2io_chk_alarm_bit - Check for alarm and incrment the counter
4213 * @value: alarm bits
4214 * @addr: address value
4215 * @cnt: counter variable
4216 * Description: Check for alarm and increment the counter
4217 * Return Value:
4218 * 1 - if alarm bit set
4219 * 0 - if alarm bit is not set
4220 */
4221int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr,
4222 unsigned long long *cnt)
4223{
4224 u64 val64;
4225 val64 = readq(addr);
4226 if ( val64 & value ) {
4227 writeq(val64, addr);
4228 (*cnt)++;
4229 return 1;
4230 }
4231 return 0;
4232
4233}
4234
4235/**
4236 * s2io_handle_errors - Xframe error indication handler
4237 * @nic: device private variable
4238 * Description: Handle alarms such as loss of link, single or
4239 * double ECC errors, critical and serious errors.
4240 * Return Value:
4241 * NONE
4242 */
4243static void s2io_handle_errors(void * dev_id)
4244{
4245 struct net_device *dev = (struct net_device *) dev_id;
4246 struct s2io_nic *sp = dev->priv;
4247 struct XENA_dev_config __iomem *bar0 = sp->bar0;
4248 u64 temp64 = 0,val64=0;
4249 int i = 0;
4250
4251 struct swStat *sw_stat = &sp->mac_control.stats_info->sw_stat;
4252 struct xpakStat *stats = &sp->mac_control.stats_info->xpak_stat;
4253
Sivakumar Subramani92b84432007-09-06 06:51:14 -04004254 if (!is_s2io_card_up(sp))
Sivakumar Subramani8116f3c2007-09-17 13:05:35 -07004255 return;
4256
4257 if (pci_channel_offline(sp->pdev))
4258 return;
4259
4260 memset(&sw_stat->ring_full_cnt, 0,
4261 sizeof(sw_stat->ring_full_cnt));
4262
4263 /* Handling the XPAK counters update */
4264 if(stats->xpak_timer_count < 72000) {
4265 /* waiting for an hour */
4266 stats->xpak_timer_count++;
4267 } else {
4268 s2io_updt_xpak_counter(dev);
4269 /* reset the count to zero */
4270 stats->xpak_timer_count = 0;
4271 }
4272
4273 /* Handling link status change error Intr */
4274 if (s2io_link_fault_indication(sp) == MAC_RMAC_ERR_TIMER) {
4275 val64 = readq(&bar0->mac_rmac_err_reg);
4276 writeq(val64, &bar0->mac_rmac_err_reg);
4277 if (val64 & RMAC_LINK_STATE_CHANGE_INT)
4278 schedule_work(&sp->set_link_task);
4279 }
4280
4281 /* In case of a serious error, the device will be Reset. */
4282 if (do_s2io_chk_alarm_bit(SERR_SOURCE_ANY, &bar0->serr_source,
4283 &sw_stat->serious_err_cnt))
4284 goto reset;
4285
4286 /* Check for data parity error */
4287 if (do_s2io_chk_alarm_bit(GPIO_INT_REG_DP_ERR_INT, &bar0->gpio_int_reg,
4288 &sw_stat->parity_err_cnt))
4289 goto reset;
4290
4291 /* Check for ring full counter */
4292 if (sp->device_type == XFRAME_II_DEVICE) {
4293 val64 = readq(&bar0->ring_bump_counter1);
4294 for (i=0; i<4; i++) {
4295 temp64 = ( val64 & vBIT(0xFFFF,(i*16),16));
4296 temp64 >>= 64 - ((i+1)*16);
4297 sw_stat->ring_full_cnt[i] += temp64;
4298 }
4299
4300 val64 = readq(&bar0->ring_bump_counter2);
4301 for (i=0; i<4; i++) {
4302 temp64 = ( val64 & vBIT(0xFFFF,(i*16),16));
4303 temp64 >>= 64 - ((i+1)*16);
4304 sw_stat->ring_full_cnt[i+4] += temp64;
4305 }
4306 }
4307
4308 val64 = readq(&bar0->txdma_int_status);
4309 /*check for pfc_err*/
4310 if (val64 & TXDMA_PFC_INT) {
4311 if (do_s2io_chk_alarm_bit(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM|
4312 PFC_MISC_0_ERR | PFC_MISC_1_ERR|
4313 PFC_PCIX_ERR, &bar0->pfc_err_reg,
4314 &sw_stat->pfc_err_cnt))
4315 goto reset;
4316 do_s2io_chk_alarm_bit(PFC_ECC_SG_ERR, &bar0->pfc_err_reg,
4317 &sw_stat->pfc_err_cnt);
4318 }
4319
4320 /*check for tda_err*/
4321 if (val64 & TXDMA_TDA_INT) {
4322 if(do_s2io_chk_alarm_bit(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM |
4323 TDA_SM1_ERR_ALARM, &bar0->tda_err_reg,
4324 &sw_stat->tda_err_cnt))
4325 goto reset;
4326 do_s2io_chk_alarm_bit(TDA_Fn_ECC_SG_ERR | TDA_PCIX_ERR,
4327 &bar0->tda_err_reg, &sw_stat->tda_err_cnt);
4328 }
4329 /*check for pcc_err*/
4330 if (val64 & TXDMA_PCC_INT) {
4331 if (do_s2io_chk_alarm_bit(PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM
4332 | PCC_N_SERR | PCC_6_COF_OV_ERR
4333 | PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR
4334 | PCC_7_LSO_OV_ERR | PCC_FB_ECC_DB_ERR
4335 | PCC_TXB_ECC_DB_ERR, &bar0->pcc_err_reg,
4336 &sw_stat->pcc_err_cnt))
4337 goto reset;
4338 do_s2io_chk_alarm_bit(PCC_FB_ECC_SG_ERR | PCC_TXB_ECC_SG_ERR,
4339 &bar0->pcc_err_reg, &sw_stat->pcc_err_cnt);
4340 }
4341
4342 /*check for tti_err*/
4343 if (val64 & TXDMA_TTI_INT) {
4344 if (do_s2io_chk_alarm_bit(TTI_SM_ERR_ALARM, &bar0->tti_err_reg,
4345 &sw_stat->tti_err_cnt))
4346 goto reset;
4347 do_s2io_chk_alarm_bit(TTI_ECC_SG_ERR | TTI_ECC_DB_ERR,
4348 &bar0->tti_err_reg, &sw_stat->tti_err_cnt);
4349 }
4350
4351 /*check for lso_err*/
4352 if (val64 & TXDMA_LSO_INT) {
4353 if (do_s2io_chk_alarm_bit(LSO6_ABORT | LSO7_ABORT
4354 | LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM,
4355 &bar0->lso_err_reg, &sw_stat->lso_err_cnt))
4356 goto reset;
4357 do_s2io_chk_alarm_bit(LSO6_SEND_OFLOW | LSO7_SEND_OFLOW,
4358 &bar0->lso_err_reg, &sw_stat->lso_err_cnt);
4359 }
4360
4361 /*check for tpa_err*/
4362 if (val64 & TXDMA_TPA_INT) {
4363 if (do_s2io_chk_alarm_bit(TPA_SM_ERR_ALARM, &bar0->tpa_err_reg,
4364 &sw_stat->tpa_err_cnt))
4365 goto reset;
4366 do_s2io_chk_alarm_bit(TPA_TX_FRM_DROP, &bar0->tpa_err_reg,
4367 &sw_stat->tpa_err_cnt);
4368 }
4369
4370 /*check for sm_err*/
4371 if (val64 & TXDMA_SM_INT) {
4372 if (do_s2io_chk_alarm_bit(SM_SM_ERR_ALARM, &bar0->sm_err_reg,
4373 &sw_stat->sm_err_cnt))
4374 goto reset;
4375 }
4376
4377 val64 = readq(&bar0->mac_int_status);
4378 if (val64 & MAC_INT_STATUS_TMAC_INT) {
4379 if (do_s2io_chk_alarm_bit(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR,
4380 &bar0->mac_tmac_err_reg,
4381 &sw_stat->mac_tmac_err_cnt))
4382 goto reset;
4383 do_s2io_chk_alarm_bit(TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR
4384 | TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR,
4385 &bar0->mac_tmac_err_reg,
4386 &sw_stat->mac_tmac_err_cnt);
4387 }
4388
4389 val64 = readq(&bar0->xgxs_int_status);
4390 if (val64 & XGXS_INT_STATUS_TXGXS) {
4391 if (do_s2io_chk_alarm_bit(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR,
4392 &bar0->xgxs_txgxs_err_reg,
4393 &sw_stat->xgxs_txgxs_err_cnt))
4394 goto reset;
4395 do_s2io_chk_alarm_bit(TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR,
4396 &bar0->xgxs_txgxs_err_reg,
4397 &sw_stat->xgxs_txgxs_err_cnt);
4398 }
4399
4400 val64 = readq(&bar0->rxdma_int_status);
4401 if (val64 & RXDMA_INT_RC_INT_M) {
4402 if (do_s2io_chk_alarm_bit(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR
4403 | RC_PRCn_SM_ERR_ALARM |RC_FTC_SM_ERR_ALARM,
4404 &bar0->rc_err_reg, &sw_stat->rc_err_cnt))
4405 goto reset;
4406 do_s2io_chk_alarm_bit(RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR
4407 | RC_RDA_FAIL_WR_Rn, &bar0->rc_err_reg,
4408 &sw_stat->rc_err_cnt);
4409 if (do_s2io_chk_alarm_bit(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn
4410 | PRC_PCI_AB_F_WR_Rn, &bar0->prc_pcix_err_reg,
4411 &sw_stat->prc_pcix_err_cnt))
4412 goto reset;
4413 do_s2io_chk_alarm_bit(PRC_PCI_DP_RD_Rn | PRC_PCI_DP_WR_Rn
4414 | PRC_PCI_DP_F_WR_Rn, &bar0->prc_pcix_err_reg,
4415 &sw_stat->prc_pcix_err_cnt);
4416 }
4417
4418 if (val64 & RXDMA_INT_RPA_INT_M) {
4419 if (do_s2io_chk_alarm_bit(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR,
4420 &bar0->rpa_err_reg, &sw_stat->rpa_err_cnt))
4421 goto reset;
4422 do_s2io_chk_alarm_bit(RPA_ECC_SG_ERR | RPA_ECC_DB_ERR,
4423 &bar0->rpa_err_reg, &sw_stat->rpa_err_cnt);
4424 }
4425
4426 if (val64 & RXDMA_INT_RDA_INT_M) {
4427 if (do_s2io_chk_alarm_bit(RDA_RXDn_ECC_DB_ERR
4428 | RDA_FRM_ECC_DB_N_AERR | RDA_SM1_ERR_ALARM
4429 | RDA_SM0_ERR_ALARM | RDA_RXD_ECC_DB_SERR,
4430 &bar0->rda_err_reg, &sw_stat->rda_err_cnt))
4431 goto reset;
4432 do_s2io_chk_alarm_bit(RDA_RXDn_ECC_SG_ERR | RDA_FRM_ECC_SG_ERR
4433 | RDA_MISC_ERR | RDA_PCIX_ERR,
4434 &bar0->rda_err_reg, &sw_stat->rda_err_cnt);
4435 }
4436
4437 if (val64 & RXDMA_INT_RTI_INT_M) {
4438 if (do_s2io_chk_alarm_bit(RTI_SM_ERR_ALARM, &bar0->rti_err_reg,
4439 &sw_stat->rti_err_cnt))
4440 goto reset;
4441 do_s2io_chk_alarm_bit(RTI_ECC_SG_ERR | RTI_ECC_DB_ERR,
4442 &bar0->rti_err_reg, &sw_stat->rti_err_cnt);
4443 }
4444
4445 val64 = readq(&bar0->mac_int_status);
4446 if (val64 & MAC_INT_STATUS_RMAC_INT) {
4447 if (do_s2io_chk_alarm_bit(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR,
4448 &bar0->mac_rmac_err_reg,
4449 &sw_stat->mac_rmac_err_cnt))
4450 goto reset;
4451 do_s2io_chk_alarm_bit(RMAC_UNUSED_INT|RMAC_SINGLE_ECC_ERR|
4452 RMAC_DOUBLE_ECC_ERR, &bar0->mac_rmac_err_reg,
4453 &sw_stat->mac_rmac_err_cnt);
4454 }
4455
4456 val64 = readq(&bar0->xgxs_int_status);
4457 if (val64 & XGXS_INT_STATUS_RXGXS) {
4458 if (do_s2io_chk_alarm_bit(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR,
4459 &bar0->xgxs_rxgxs_err_reg,
4460 &sw_stat->xgxs_rxgxs_err_cnt))
4461 goto reset;
4462 }
4463
4464 val64 = readq(&bar0->mc_int_status);
4465 if(val64 & MC_INT_STATUS_MC_INT) {
4466 if (do_s2io_chk_alarm_bit(MC_ERR_REG_SM_ERR, &bar0->mc_err_reg,
4467 &sw_stat->mc_err_cnt))
4468 goto reset;
4469
4470 /* Handling Ecc errors */
4471 if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
4472 writeq(val64, &bar0->mc_err_reg);
4473 if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
4474 sw_stat->double_ecc_errs++;
4475 if (sp->device_type != XFRAME_II_DEVICE) {
4476 /*
4477 * Reset XframeI only if critical error
4478 */
4479 if (val64 &
4480 (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
4481 MC_ERR_REG_MIRI_ECC_DB_ERR_1))
4482 goto reset;
4483 }
4484 } else
4485 sw_stat->single_ecc_errs++;
4486 }
4487 }
4488 return;
4489
4490reset:
4491 netif_stop_queue(dev);
4492 schedule_work(&sp->rst_timer_task);
4493 sw_stat->soft_reset_cnt++;
4494 return;
4495}
4496
4497/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 * s2io_isr - ISR handler of the device .
4499 * @irq: the irq of the device.
4500 * @dev_id: a void pointer to the dev structure of the NIC.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004501 * Description: This function is the ISR handler of the device. It
4502 * identifies the reason for the interrupt and calls the relevant
4503 * service routines. As a contongency measure, this ISR allocates the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 * recv buffers, if their numbers are below the panic value which is
4505 * presently set to 25% of the original number of rcv buffers allocated.
4506 * Return value:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004507 * IRQ_HANDLED: will be returned if IRQ was handled by this routine
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 * IRQ_NONE: will be returned if interrupt is not from our device
4509 */
David Howells7d12e782006-10-05 14:55:46 +01004510static irqreturn_t s2io_isr(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511{
4512 struct net_device *dev = (struct net_device *) dev_id;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004513 struct s2io_nic *sp = dev->priv;
4514 struct XENA_dev_config __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004515 int i;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004516 u64 reason = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004517 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 struct config_param *config;
4519
Linas Vepstasd796fdb2007-05-14 18:37:30 -05004520 /* Pretend we handled any irq's from a disconnected card */
4521 if (pci_channel_offline(sp->pdev))
4522 return IRQ_NONE;
4523
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07004524 if (!is_s2io_card_up(sp))
Sivakumar Subramani92b84432007-09-06 06:51:14 -04004525 return IRQ_NONE;
Sivakumar Subramani92b84432007-09-06 06:51:14 -04004526
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 mac_control = &sp->mac_control;
4528 config = &sp->config;
4529
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004530 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 * Identify the cause for interrupt and call the appropriate
4532 * interrupt handler. Causes for the interrupt could be;
4533 * 1. Rx of packet.
4534 * 2. Tx complete.
4535 * 3. Link down.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 */
4537 reason = readq(&bar0->general_int_status);
4538
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07004539 if (unlikely(reason == S2IO_MINUS_ONE) ) {
4540 /* Nothing much can be done. Get out */
4541 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 }
4543
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07004544 if (reason & (GEN_INTR_RXTRAFFIC |
4545 GEN_INTR_TXTRAFFIC | GEN_INTR_TXPIC))
4546 {
4547 writeq(S2IO_MINUS_ONE, &bar0->general_int_mask);
4548
4549 if (config->napi) {
4550 if (reason & GEN_INTR_RXTRAFFIC) {
4551 if (likely(netif_rx_schedule_prep(dev,
4552 &sp->napi))) {
4553 __netif_rx_schedule(dev, &sp->napi);
4554 writeq(S2IO_MINUS_ONE,
4555 &bar0->rx_traffic_mask);
4556 } else
4557 writeq(S2IO_MINUS_ONE,
4558 &bar0->rx_traffic_int);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004559 }
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07004560 } else {
4561 /*
4562 * rx_traffic_int reg is an R1 register, writing all 1's
4563 * will ensure that the actual interrupt causing bit
4564 * get's cleared and hence a read can be avoided.
4565 */
4566 if (reason & GEN_INTR_RXTRAFFIC)
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004567 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07004568
4569 for (i = 0; i < config->rx_ring_num; i++)
4570 rx_intr_handler(&mac_control->rings[i]);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004571 }
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07004572
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004573 /*
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07004574 * tx_traffic_int reg is an R1 register, writing all 1's
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004575 * will ensure that the actual interrupt causing bit get's
4576 * cleared and hence a read can be avoided.
4577 */
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07004578 if (reason & GEN_INTR_TXTRAFFIC)
4579 writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004580
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07004581 for (i = 0; i < config->tx_fifo_num; i++)
4582 tx_intr_handler(&mac_control->fifos[i]);
4583
4584 if (reason & GEN_INTR_TXPIC)
4585 s2io_txpic_intr_handle(sp);
4586
4587 /*
4588 * Reallocate the buffers from the interrupt handler itself.
4589 */
4590 if (!config->napi) {
4591 for (i = 0; i < config->rx_ring_num; i++)
4592 s2io_chk_rx_buffers(sp, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 }
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07004594 writeq(sp->general_int_mask, &bar0->general_int_mask);
4595 readl(&bar0->general_int_status);
4596
4597 return IRQ_HANDLED;
4598
4599 }
4600 else if (!reason) {
4601 /* The interrupt was not raised by us */
4602 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 return IRQ_HANDLED;
4606}
4607
4608/**
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004609 * s2io_updt_stats -
4610 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004611static void s2io_updt_stats(struct s2io_nic *sp)
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004612{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004613 struct XENA_dev_config __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004614 u64 val64;
4615 int cnt = 0;
4616
Sivakumar Subramani92b84432007-09-06 06:51:14 -04004617 if (is_s2io_card_up(sp)) {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004618 /* Apprx 30us on a 133 MHz bus */
4619 val64 = SET_UPDT_CLICKS(10) |
4620 STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
4621 writeq(val64, &bar0->stat_cfg);
4622 do {
4623 udelay(100);
4624 val64 = readq(&bar0->stat_cfg);
4625 if (!(val64 & BIT(0)))
4626 break;
4627 cnt++;
4628 if (cnt == 5)
4629 break; /* Updt failed */
4630 } while(1);
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04004631 }
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004632}
4633
4634/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004635 * s2io_get_stats - Updates the device statistics structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 * @dev : pointer to the device structure.
4637 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004638 * This function updates the device statistics structure in the s2io_nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 * structure and returns a pointer to the same.
4640 * Return value:
4641 * pointer to the updated net_device_stats structure.
4642 */
4643
Adrian Bunkac1f60d2005-11-06 01:46:47 +01004644static struct net_device_stats *s2io_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004646 struct s2io_nic *sp = dev->priv;
4647 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 struct config_param *config;
4649
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004650
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 mac_control = &sp->mac_control;
4652 config = &sp->config;
4653
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004654 /* Configure Stats for immediate updt */
4655 s2io_updt_stats(sp);
4656
4657 sp->stats.tx_packets =
4658 le32_to_cpu(mac_control->stats_info->tmac_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004659 sp->stats.tx_errors =
4660 le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
4661 sp->stats.rx_errors =
Al Viroee705db2006-09-23 01:28:17 +01004662 le64_to_cpu(mac_control->stats_info->rmac_drop_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004663 sp->stats.multicast =
4664 le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 sp->stats.rx_length_errors =
Al Viroee705db2006-09-23 01:28:17 +01004666 le64_to_cpu(mac_control->stats_info->rmac_long_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667
4668 return (&sp->stats);
4669}
4670
4671/**
4672 * s2io_set_multicast - entry point for multicast address enable/disable.
4673 * @dev : pointer to the device structure
4674 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004675 * This function is a driver entry point which gets called by the kernel
4676 * whenever multicast addresses must be enabled/disabled. This also gets
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 * called to set/reset promiscuous mode. Depending on the deivce flag, we
4678 * determine, if multicast address must be enabled or if promiscuous mode
4679 * is to be disabled etc.
4680 * Return value:
4681 * void.
4682 */
4683
4684static void s2io_set_multicast(struct net_device *dev)
4685{
4686 int i, j, prev_cnt;
4687 struct dev_mc_list *mclist;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004688 struct s2io_nic *sp = dev->priv;
4689 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
4691 0xfeffffffffffULL;
4692 u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
4693 void __iomem *add;
4694
4695 if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) {
4696 /* Enable all Multicast addresses */
4697 writeq(RMAC_ADDR_DATA0_MEM_ADDR(multi_mac),
4698 &bar0->rmac_addr_data0_mem);
4699 writeq(RMAC_ADDR_DATA1_MEM_MASK(mask),
4700 &bar0->rmac_addr_data1_mem);
4701 val64 = RMAC_ADDR_CMD_MEM_WE |
4702 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4703 RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
4704 writeq(val64, &bar0->rmac_addr_cmd_mem);
4705 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004706 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004707 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
4708 S2IO_BIT_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709
4710 sp->m_cast_flg = 1;
4711 sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
4712 } else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) {
4713 /* Disable all Multicast addresses */
4714 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4715 &bar0->rmac_addr_data0_mem);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07004716 writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0),
4717 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718 val64 = RMAC_ADDR_CMD_MEM_WE |
4719 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4720 RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos);
4721 writeq(val64, &bar0->rmac_addr_cmd_mem);
4722 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004723 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004724 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
4725 S2IO_BIT_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726
4727 sp->m_cast_flg = 0;
4728 sp->all_multi_pos = 0;
4729 }
4730
4731 if ((dev->flags & IFF_PROMISC) && (!sp->promisc_flg)) {
4732 /* Put the NIC into promiscuous mode */
4733 add = &bar0->mac_cfg;
4734 val64 = readq(&bar0->mac_cfg);
4735 val64 |= MAC_CFG_RMAC_PROM_ENABLE;
4736
4737 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4738 writel((u32) val64, add);
4739 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4740 writel((u32) (val64 >> 32), (add + 4));
4741
Sivakumar Subramani926930b2007-02-24 01:59:39 -05004742 if (vlan_tag_strip != 1) {
4743 val64 = readq(&bar0->rx_pa_cfg);
4744 val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG;
4745 writeq(val64, &bar0->rx_pa_cfg);
4746 vlan_strip_flag = 0;
4747 }
4748
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749 val64 = readq(&bar0->mac_cfg);
4750 sp->promisc_flg = 1;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004751 DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 dev->name);
4753 } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) {
4754 /* Remove the NIC from promiscuous mode */
4755 add = &bar0->mac_cfg;
4756 val64 = readq(&bar0->mac_cfg);
4757 val64 &= ~MAC_CFG_RMAC_PROM_ENABLE;
4758
4759 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4760 writel((u32) val64, add);
4761 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4762 writel((u32) (val64 >> 32), (add + 4));
4763
Sivakumar Subramani926930b2007-02-24 01:59:39 -05004764 if (vlan_tag_strip != 0) {
4765 val64 = readq(&bar0->rx_pa_cfg);
4766 val64 |= RX_PA_CFG_STRIP_VLAN_TAG;
4767 writeq(val64, &bar0->rx_pa_cfg);
4768 vlan_strip_flag = 1;
4769 }
4770
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 val64 = readq(&bar0->mac_cfg);
4772 sp->promisc_flg = 0;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004773 DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774 dev->name);
4775 }
4776
4777 /* Update individual M_CAST address list */
4778 if ((!sp->m_cast_flg) && dev->mc_count) {
4779 if (dev->mc_count >
4780 (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) {
4781 DBG_PRINT(ERR_DBG, "%s: No more Rx filters ",
4782 dev->name);
4783 DBG_PRINT(ERR_DBG, "can be added, please enable ");
4784 DBG_PRINT(ERR_DBG, "ALL_MULTI instead\n");
4785 return;
4786 }
4787
4788 prev_cnt = sp->mc_addr_count;
4789 sp->mc_addr_count = dev->mc_count;
4790
4791 /* Clear out the previous list of Mc in the H/W. */
4792 for (i = 0; i < prev_cnt; i++) {
4793 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4794 &bar0->rmac_addr_data0_mem);
4795 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004796 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 val64 = RMAC_ADDR_CMD_MEM_WE |
4798 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4799 RMAC_ADDR_CMD_MEM_OFFSET
4800 (MAC_MC_ADDR_START_OFFSET + i);
4801 writeq(val64, &bar0->rmac_addr_cmd_mem);
4802
4803 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004804 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004805 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
4806 S2IO_BIT_RESET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 DBG_PRINT(ERR_DBG, "%s: Adding ",
4808 dev->name);
4809 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4810 return;
4811 }
4812 }
4813
4814 /* Create the new Rx filter list and update the same in H/W. */
4815 for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
4816 i++, mclist = mclist->next) {
4817 memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr,
4818 ETH_ALEN);
Jeff Garzika7a80d52006-03-04 12:06:51 -05004819 mac_addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 for (j = 0; j < ETH_ALEN; j++) {
4821 mac_addr |= mclist->dmi_addr[j];
4822 mac_addr <<= 8;
4823 }
4824 mac_addr >>= 8;
4825 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4826 &bar0->rmac_addr_data0_mem);
4827 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004828 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 val64 = RMAC_ADDR_CMD_MEM_WE |
4830 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4831 RMAC_ADDR_CMD_MEM_OFFSET
4832 (i + MAC_MC_ADDR_START_OFFSET);
4833 writeq(val64, &bar0->rmac_addr_cmd_mem);
4834
4835 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004836 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004837 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
4838 S2IO_BIT_RESET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 DBG_PRINT(ERR_DBG, "%s: Adding ",
4840 dev->name);
4841 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4842 return;
4843 }
4844 }
4845 }
4846}
4847
4848/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004849 * s2io_set_mac_addr - Programs the Xframe mac address
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 * @dev : pointer to the device structure.
4851 * @addr: a uchar pointer to the new mac address which is to be set.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004852 * Description : This procedure will program the Xframe to receive
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 * frames with new Mac Address
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004854 * Return value: SUCCESS on success and an appropriate (-)ve integer
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 * as defined in errno.h file on failure.
4856 */
4857
Adrian Bunk26df54b2006-01-14 03:09:40 +01004858static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004860 struct s2io_nic *sp = dev->priv;
4861 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 register u64 val64, mac_addr = 0;
4863 int i;
Sivakumar Subramanid8d70ca2007-02-24 02:04:24 -05004864 u64 old_mac_addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004866 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 * Set the new MAC address as the new unicast filter and reflect this
4868 * change on the device address registered with the OS. It will be
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004869 * at offset 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870 */
4871 for (i = 0; i < ETH_ALEN; i++) {
4872 mac_addr <<= 8;
4873 mac_addr |= addr[i];
Sivakumar Subramanid8d70ca2007-02-24 02:04:24 -05004874 old_mac_addr <<= 8;
4875 old_mac_addr |= sp->def_mac_addr[0].mac_addr[i];
4876 }
4877
4878 if(0 == mac_addr)
4879 return SUCCESS;
4880
4881 /* Update the internal structure with this new mac address */
4882 if(mac_addr != old_mac_addr) {
4883 memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
4884 sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_addr);
4885 sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_addr >> 8);
4886 sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_addr >> 16);
4887 sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_addr >> 24);
4888 sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_addr >> 32);
4889 sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_addr >> 40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 }
4891
4892 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4893 &bar0->rmac_addr_data0_mem);
4894
4895 val64 =
4896 RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4897 RMAC_ADDR_CMD_MEM_OFFSET(0);
4898 writeq(val64, &bar0->rmac_addr_cmd_mem);
4899 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004900 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05004901 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
4903 return FAILURE;
4904 }
4905
4906 return SUCCESS;
4907}
4908
4909/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004910 * s2io_ethtool_sset - Sets different link parameters.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure.
4912 * @info: pointer to the structure with parameters given by ethtool to set
4913 * link information.
4914 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004915 * The function sets different link parameters provided by the user onto
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 * the NIC.
4917 * Return value:
4918 * 0 on success.
4919*/
4920
4921static int s2io_ethtool_sset(struct net_device *dev,
4922 struct ethtool_cmd *info)
4923{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004924 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925 if ((info->autoneg == AUTONEG_ENABLE) ||
4926 (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
4927 return -EINVAL;
4928 else {
4929 s2io_close(sp->dev);
4930 s2io_open(sp->dev);
4931 }
4932
4933 return 0;
4934}
4935
4936/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004937 * s2io_ethtol_gset - Return link specific information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 * @sp : private member of the device structure, pointer to the
4939 * s2io_nic structure.
4940 * @info : pointer to the structure with parameters given by ethtool
4941 * to return link information.
4942 * Description:
4943 * Returns link specific information like speed, duplex etc.. to ethtool.
4944 * Return value :
4945 * return 0 on success.
4946 */
4947
4948static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
4949{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004950 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951 info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4952 info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4953 info->port = PORT_FIBRE;
4954 /* info->transceiver?? TODO */
4955
4956 if (netif_carrier_ok(sp->dev)) {
4957 info->speed = 10000;
4958 info->duplex = DUPLEX_FULL;
4959 } else {
4960 info->speed = -1;
4961 info->duplex = -1;
4962 }
4963
4964 info->autoneg = AUTONEG_DISABLE;
4965 return 0;
4966}
4967
4968/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004969 * s2io_ethtool_gdrvinfo - Returns driver specific information.
4970 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 * s2io_nic structure.
4972 * @info : pointer to the structure with parameters given by ethtool to
4973 * return driver information.
4974 * Description:
4975 * Returns driver specefic information like name, version etc.. to ethtool.
4976 * Return value:
4977 * void
4978 */
4979
4980static void s2io_ethtool_gdrvinfo(struct net_device *dev,
4981 struct ethtool_drvinfo *info)
4982{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05004983 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984
John W. Linvilledbc23092005-09-28 17:50:51 -04004985 strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
4986 strncpy(info->version, s2io_driver_version, sizeof(info->version));
4987 strncpy(info->fw_version, "", sizeof(info->fw_version));
4988 strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989 info->regdump_len = XENA_REG_SPACE;
4990 info->eedump_len = XENA_EEPROM_SPACE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991}
4992
4993/**
4994 * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004995 * @sp: private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004997 * @regs : pointer to the structure with parameters given by ethtool for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998 * dumping the registers.
4999 * @reg_space: The input argumnet into which all the registers are dumped.
5000 * Description:
5001 * Dumps the entire register space of xFrame NIC into the user given
5002 * buffer area.
5003 * Return value :
5004 * void .
5005*/
5006
5007static void s2io_ethtool_gregs(struct net_device *dev,
5008 struct ethtool_regs *regs, void *space)
5009{
5010 int i;
5011 u64 reg;
5012 u8 *reg_space = (u8 *) space;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005013 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014
5015 regs->len = XENA_REG_SPACE;
5016 regs->version = sp->pdev->subsystem_device;
5017
5018 for (i = 0; i < regs->len; i += 8) {
5019 reg = readq(sp->bar0 + i);
5020 memcpy((reg_space + i), &reg, 8);
5021 }
5022}
5023
5024/**
5025 * s2io_phy_id - timer function that alternates adapter LED.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005026 * @data : address of the private member of the device structure, which
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027 * is a pointer to the s2io_nic structure, provided as an u32.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005028 * Description: This is actually the timer function that alternates the
5029 * adapter LED bit of the adapter control bit to set/reset every time on
5030 * invocation. The timer is set for 1/2 a second, hence tha NIC blinks
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 * once every second.
5032*/
5033static void s2io_phy_id(unsigned long data)
5034{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005035 struct s2io_nic *sp = (struct s2io_nic *) data;
5036 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 u64 val64 = 0;
5038 u16 subid;
5039
5040 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005041 if ((sp->device_type == XFRAME_II_DEVICE) ||
5042 ((subid & 0xFF) >= 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 val64 = readq(&bar0->gpio_control);
5044 val64 ^= GPIO_CTRL_GPIO_0;
5045 writeq(val64, &bar0->gpio_control);
5046 } else {
5047 val64 = readq(&bar0->adapter_control);
5048 val64 ^= ADAPTER_LED_ON;
5049 writeq(val64, &bar0->adapter_control);
5050 }
5051
5052 mod_timer(&sp->id_timer, jiffies + HZ / 2);
5053}
5054
5055/**
5056 * s2io_ethtool_idnic - To physically identify the nic on the system.
5057 * @sp : private member of the device structure, which is a pointer to the
5058 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005059 * @id : pointer to the structure with identification parameters given by
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 * ethtool.
5061 * Description: Used to physically identify the NIC on the system.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005062 * The Link LED will blink for a time specified by the user for
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 * identification.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005064 * NOTE: The Link has to be Up to be able to blink the LED. Hence
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 * identification is possible only if it's link is up.
5066 * Return value:
5067 * int , returns 0 on success
5068 */
5069
5070static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
5071{
5072 u64 val64 = 0, last_gpio_ctrl_val;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005073 struct s2io_nic *sp = dev->priv;
5074 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075 u16 subid;
5076
5077 subid = sp->pdev->subsystem_device;
5078 last_gpio_ctrl_val = readq(&bar0->gpio_control);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005079 if ((sp->device_type == XFRAME_I_DEVICE) &&
5080 ((subid & 0xFF) < 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 val64 = readq(&bar0->adapter_control);
5082 if (!(val64 & ADAPTER_CNTL_EN)) {
5083 printk(KERN_ERR
5084 "Adapter Link down, cannot blink LED\n");
5085 return -EFAULT;
5086 }
5087 }
5088 if (sp->id_timer.function == NULL) {
5089 init_timer(&sp->id_timer);
5090 sp->id_timer.function = s2io_phy_id;
5091 sp->id_timer.data = (unsigned long) sp;
5092 }
5093 mod_timer(&sp->id_timer, jiffies);
5094 if (data)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005095 msleep_interruptible(data * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005097 msleep_interruptible(MAX_FLICKER_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 del_timer_sync(&sp->id_timer);
5099
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005100 if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 writeq(last_gpio_ctrl_val, &bar0->gpio_control);
5102 last_gpio_ctrl_val = readq(&bar0->gpio_control);
5103 }
5104
5105 return 0;
5106}
5107
Sreenivasa Honnur0cec35e2007-05-10 04:06:28 -04005108static void s2io_ethtool_gringparam(struct net_device *dev,
5109 struct ethtool_ringparam *ering)
5110{
5111 struct s2io_nic *sp = dev->priv;
5112 int i,tx_desc_count=0,rx_desc_count=0;
5113
5114 if (sp->rxd_mode == RXD_MODE_1)
5115 ering->rx_max_pending = MAX_RX_DESC_1;
5116 else if (sp->rxd_mode == RXD_MODE_3B)
5117 ering->rx_max_pending = MAX_RX_DESC_2;
Sreenivasa Honnur0cec35e2007-05-10 04:06:28 -04005118
5119 ering->tx_max_pending = MAX_TX_DESC;
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04005120 for (i = 0 ; i < sp->config.tx_fifo_num ; i++)
Sreenivasa Honnur0cec35e2007-05-10 04:06:28 -04005121 tx_desc_count += sp->config.tx_cfg[i].fifo_len;
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04005122
Sreenivasa Honnur0cec35e2007-05-10 04:06:28 -04005123 DBG_PRINT(INFO_DBG,"\nmax txds : %d\n",sp->config.max_txds);
5124 ering->tx_pending = tx_desc_count;
5125 rx_desc_count = 0;
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04005126 for (i = 0 ; i < sp->config.rx_ring_num ; i++)
Sreenivasa Honnur0cec35e2007-05-10 04:06:28 -04005127 rx_desc_count += sp->config.rx_cfg[i].num_rxd;
Veena Paratb6627672007-07-23 02:39:43 -04005128
Sreenivasa Honnur0cec35e2007-05-10 04:06:28 -04005129 ering->rx_pending = rx_desc_count;
5130
5131 ering->rx_mini_max_pending = 0;
5132 ering->rx_mini_pending = 0;
5133 if(sp->rxd_mode == RXD_MODE_1)
5134 ering->rx_jumbo_max_pending = MAX_RX_DESC_1;
5135 else if (sp->rxd_mode == RXD_MODE_3B)
5136 ering->rx_jumbo_max_pending = MAX_RX_DESC_2;
5137 ering->rx_jumbo_pending = rx_desc_count;
5138}
5139
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140/**
5141 * s2io_ethtool_getpause_data -Pause frame frame generation and reception.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005142 * @sp : private member of the device structure, which is a pointer to the
5143 * s2io_nic structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 * @ep : pointer to the structure with pause parameters given by ethtool.
5145 * Description:
5146 * Returns the Pause frame generation and reception capability of the NIC.
5147 * Return value:
5148 * void
5149 */
5150static void s2io_ethtool_getpause_data(struct net_device *dev,
5151 struct ethtool_pauseparam *ep)
5152{
5153 u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005154 struct s2io_nic *sp = dev->priv;
5155 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156
5157 val64 = readq(&bar0->rmac_pause_cfg);
5158 if (val64 & RMAC_PAUSE_GEN_ENABLE)
5159 ep->tx_pause = TRUE;
5160 if (val64 & RMAC_PAUSE_RX_ENABLE)
5161 ep->rx_pause = TRUE;
5162 ep->autoneg = FALSE;
5163}
5164
5165/**
5166 * s2io_ethtool_setpause_data - set/reset pause frame generation.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005167 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 * s2io_nic structure.
5169 * @ep : pointer to the structure with pause parameters given by ethtool.
5170 * Description:
5171 * It can be used to set or reset Pause frame generation or reception
5172 * support of the NIC.
5173 * Return value:
5174 * int, returns 0 on Success
5175 */
5176
5177static int s2io_ethtool_setpause_data(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005178 struct ethtool_pauseparam *ep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005179{
5180 u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005181 struct s2io_nic *sp = dev->priv;
5182 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183
5184 val64 = readq(&bar0->rmac_pause_cfg);
5185 if (ep->tx_pause)
5186 val64 |= RMAC_PAUSE_GEN_ENABLE;
5187 else
5188 val64 &= ~RMAC_PAUSE_GEN_ENABLE;
5189 if (ep->rx_pause)
5190 val64 |= RMAC_PAUSE_RX_ENABLE;
5191 else
5192 val64 &= ~RMAC_PAUSE_RX_ENABLE;
5193 writeq(val64, &bar0->rmac_pause_cfg);
5194 return 0;
5195}
5196
5197/**
5198 * read_eeprom - reads 4 bytes of data from user given offset.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005199 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 * s2io_nic structure.
5201 * @off : offset at which the data must be written
5202 * @data : Its an output parameter where the data read at the given
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005203 * offset is stored.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005205 * Will read 4 bytes of data from the user given offset and return the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 * read data.
5207 * NOTE: Will allow to read only part of the EEPROM visible through the
5208 * I2C bus.
5209 * Return value:
5210 * -1 on failure and 0 on success.
5211 */
5212
5213#define S2IO_DEV_ID 5
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005214static int read_eeprom(struct s2io_nic * sp, int off, u64 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215{
5216 int ret = -1;
5217 u32 exit_cnt = 0;
5218 u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005219 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005221 if (sp->device_type == XFRAME_I_DEVICE) {
5222 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
5223 I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ |
5224 I2C_CONTROL_CNTL_START;
5225 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005227 while (exit_cnt < 5) {
5228 val64 = readq(&bar0->i2c_control);
5229 if (I2C_CONTROL_CNTL_END(val64)) {
5230 *data = I2C_CONTROL_GET_DATA(val64);
5231 ret = 0;
5232 break;
5233 }
5234 msleep(50);
5235 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 }
5238
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005239 if (sp->device_type == XFRAME_II_DEVICE) {
5240 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005241 SPI_CONTROL_BYTECNT(0x3) |
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005242 SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off);
5243 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
5244 val64 |= SPI_CONTROL_REQ;
5245 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
5246 while (exit_cnt < 5) {
5247 val64 = readq(&bar0->spi_control);
5248 if (val64 & SPI_CONTROL_NACK) {
5249 ret = 1;
5250 break;
5251 } else if (val64 & SPI_CONTROL_DONE) {
5252 *data = readq(&bar0->spi_data);
5253 *data &= 0xffffff;
5254 ret = 0;
5255 break;
5256 }
5257 msleep(50);
5258 exit_cnt++;
5259 }
5260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261 return ret;
5262}
5263
5264/**
5265 * write_eeprom - actually writes the relevant part of the data value.
5266 * @sp : private member of the device structure, which is a pointer to the
5267 * s2io_nic structure.
5268 * @off : offset at which the data must be written
5269 * @data : The data that is to be written
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005270 * @cnt : Number of bytes of the data that are actually to be written into
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 * the Eeprom. (max of 3)
5272 * Description:
5273 * Actually writes the relevant part of the data value into the Eeprom
5274 * through the I2C bus.
5275 * Return value:
5276 * 0 on success, -1 on failure.
5277 */
5278
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005279static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280{
5281 int exit_cnt = 0, ret = -1;
5282 u64 val64;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005283 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005285 if (sp->device_type == XFRAME_I_DEVICE) {
5286 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
5287 I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) |
5288 I2C_CONTROL_CNTL_START;
5289 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005291 while (exit_cnt < 5) {
5292 val64 = readq(&bar0->i2c_control);
5293 if (I2C_CONTROL_CNTL_END(val64)) {
5294 if (!(val64 & I2C_CONTROL_NACK))
5295 ret = 0;
5296 break;
5297 }
5298 msleep(50);
5299 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 }
5302
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005303 if (sp->device_type == XFRAME_II_DEVICE) {
5304 int write_cnt = (cnt == 8) ? 0 : cnt;
5305 writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data);
5306
5307 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005308 SPI_CONTROL_BYTECNT(write_cnt) |
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005309 SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off);
5310 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
5311 val64 |= SPI_CONTROL_REQ;
5312 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
5313 while (exit_cnt < 5) {
5314 val64 = readq(&bar0->spi_control);
5315 if (val64 & SPI_CONTROL_NACK) {
5316 ret = 1;
5317 break;
5318 } else if (val64 & SPI_CONTROL_DONE) {
5319 ret = 0;
5320 break;
5321 }
5322 msleep(50);
5323 exit_cnt++;
5324 }
5325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326 return ret;
5327}
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005328static void s2io_vpd_read(struct s2io_nic *nic)
Ananda Raju9dc737a2006-04-21 19:05:41 -04005329{
Ananda Rajub41477f2006-07-24 19:52:49 -04005330 u8 *vpd_data;
5331 u8 data;
Ananda Raju9dc737a2006-04-21 19:05:41 -04005332 int i=0, cnt, fail = 0;
5333 int vpd_addr = 0x80;
5334
5335 if (nic->device_type == XFRAME_II_DEVICE) {
5336 strcpy(nic->product_name, "Xframe II 10GbE network adapter");
5337 vpd_addr = 0x80;
5338 }
5339 else {
5340 strcpy(nic->product_name, "Xframe I 10GbE network adapter");
5341 vpd_addr = 0x50;
5342 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05005343 strcpy(nic->serial_num, "NOT AVAILABLE");
Ananda Raju9dc737a2006-04-21 19:05:41 -04005344
Ananda Rajub41477f2006-07-24 19:52:49 -04005345 vpd_data = kmalloc(256, GFP_KERNEL);
Sreenivasa Honnurc53d4942007-05-10 04:18:54 -04005346 if (!vpd_data) {
5347 nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
Ananda Rajub41477f2006-07-24 19:52:49 -04005348 return;
Sreenivasa Honnurc53d4942007-05-10 04:18:54 -04005349 }
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04005350 nic->mac_control.stats_info->sw_stat.mem_allocated += 256;
Ananda Rajub41477f2006-07-24 19:52:49 -04005351
Ananda Raju9dc737a2006-04-21 19:05:41 -04005352 for (i = 0; i < 256; i +=4 ) {
5353 pci_write_config_byte(nic->pdev, (vpd_addr + 2), i);
5354 pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data);
5355 pci_write_config_byte(nic->pdev, (vpd_addr + 3), 0);
5356 for (cnt = 0; cnt <5; cnt++) {
5357 msleep(2);
5358 pci_read_config_byte(nic->pdev, (vpd_addr + 3), &data);
5359 if (data == 0x80)
5360 break;
5361 }
5362 if (cnt >= 5) {
5363 DBG_PRINT(ERR_DBG, "Read of VPD data failed\n");
5364 fail = 1;
5365 break;
5366 }
5367 pci_read_config_dword(nic->pdev, (vpd_addr + 4),
5368 (u32 *)&vpd_data[i]);
5369 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05005370
5371 if(!fail) {
5372 /* read serial number of adapter */
5373 for (cnt = 0; cnt < 256; cnt++) {
5374 if ((vpd_data[cnt] == 'S') &&
5375 (vpd_data[cnt+1] == 'N') &&
5376 (vpd_data[cnt+2] < VPD_STRING_LEN)) {
5377 memset(nic->serial_num, 0, VPD_STRING_LEN);
5378 memcpy(nic->serial_num, &vpd_data[cnt + 3],
5379 vpd_data[cnt+2]);
5380 break;
5381 }
5382 }
5383 }
5384
5385 if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04005386 memset(nic->product_name, 0, vpd_data[1]);
5387 memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
5388 }
Ananda Rajub41477f2006-07-24 19:52:49 -04005389 kfree(vpd_data);
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04005390 nic->mac_control.stats_info->sw_stat.mem_freed += 256;
Ananda Raju9dc737a2006-04-21 19:05:41 -04005391}
5392
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393/**
5394 * s2io_ethtool_geeprom - reads the value stored in the Eeprom.
5395 * @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 -07005396 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 * containing all relevant information.
5398 * @data_buf : user defined value to be written into Eeprom.
5399 * Description: Reads the values stored in the Eeprom at given offset
5400 * for a given length. Stores these values int the input argument data
5401 * buffer 'data_buf' and returns these to the caller (ethtool.)
5402 * Return value:
5403 * int 0 on success
5404 */
5405
5406static int s2io_ethtool_geeprom(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005407 struct ethtool_eeprom *eeprom, u8 * data_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408{
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005409 u32 i, valid;
5410 u64 data;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005411 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412
5413 eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
5414
5415 if ((eeprom->offset + eeprom->len) > (XENA_EEPROM_SPACE))
5416 eeprom->len = XENA_EEPROM_SPACE - eeprom->offset;
5417
5418 for (i = 0; i < eeprom->len; i += 4) {
5419 if (read_eeprom(sp, (eeprom->offset + i), &data)) {
5420 DBG_PRINT(ERR_DBG, "Read of EEPROM failed\n");
5421 return -EFAULT;
5422 }
5423 valid = INV(data);
5424 memcpy((data_buf + i), &valid, 4);
5425 }
5426 return 0;
5427}
5428
5429/**
5430 * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom
5431 * @sp : private member of the device structure, which is a pointer to the
5432 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005433 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 * containing all relevant information.
5435 * @data_buf ; user defined value to be written into Eeprom.
5436 * Description:
5437 * Tries to write the user provided value in the Eeprom, at the offset
5438 * given by the user.
5439 * Return value:
5440 * 0 on success, -EFAULT on failure.
5441 */
5442
5443static int s2io_ethtool_seeprom(struct net_device *dev,
5444 struct ethtool_eeprom *eeprom,
5445 u8 * data_buf)
5446{
5447 int len = eeprom->len, cnt = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005448 u64 valid = 0, data;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005449 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450
5451 if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
5452 DBG_PRINT(ERR_DBG,
5453 "ETHTOOL_WRITE_EEPROM Err: Magic value ");
5454 DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n",
5455 eeprom->magic);
5456 return -EFAULT;
5457 }
5458
5459 while (len) {
5460 data = (u32) data_buf[cnt] & 0x000000FF;
5461 if (data) {
5462 valid = (u32) (data << 24);
5463 } else
5464 valid = data;
5465
5466 if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) {
5467 DBG_PRINT(ERR_DBG,
5468 "ETHTOOL_WRITE_EEPROM Err: Cannot ");
5469 DBG_PRINT(ERR_DBG,
5470 "write into the specified offset\n");
5471 return -EFAULT;
5472 }
5473 cnt++;
5474 len--;
5475 }
5476
5477 return 0;
5478}
5479
5480/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005481 * s2io_register_test - reads and writes into all clock domains.
5482 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 * s2io_nic structure.
5484 * @data : variable that returns the result of each of the test conducted b
5485 * by the driver.
5486 * Description:
5487 * Read and write into all clock domains. The NIC has 3 clock domains,
5488 * see that registers in all the three regions are accessible.
5489 * Return value:
5490 * 0 on success.
5491 */
5492
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005493static int s2io_register_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005495 struct XENA_dev_config __iomem *bar0 = sp->bar0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005496 u64 val64 = 0, exp_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 int fail = 0;
5498
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005499 val64 = readq(&bar0->pif_rd_swapper_fb);
5500 if (val64 != 0x123456789abcdefULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 fail = 1;
5502 DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n");
5503 }
5504
5505 val64 = readq(&bar0->rmac_pause_cfg);
5506 if (val64 != 0xc000ffff00000000ULL) {
5507 fail = 1;
5508 DBG_PRINT(INFO_DBG, "Read Test level 2 fails\n");
5509 }
5510
5511 val64 = readq(&bar0->rx_queue_cfg);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005512 if (sp->device_type == XFRAME_II_DEVICE)
5513 exp_val = 0x0404040404040404ULL;
5514 else
5515 exp_val = 0x0808080808080808ULL;
5516 if (val64 != exp_val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 fail = 1;
5518 DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n");
5519 }
5520
5521 val64 = readq(&bar0->xgxs_efifo_cfg);
5522 if (val64 != 0x000000001923141EULL) {
5523 fail = 1;
5524 DBG_PRINT(INFO_DBG, "Read Test level 4 fails\n");
5525 }
5526
5527 val64 = 0x5A5A5A5A5A5A5A5AULL;
5528 writeq(val64, &bar0->xmsi_data);
5529 val64 = readq(&bar0->xmsi_data);
5530 if (val64 != 0x5A5A5A5A5A5A5A5AULL) {
5531 fail = 1;
5532 DBG_PRINT(ERR_DBG, "Write Test level 1 fails\n");
5533 }
5534
5535 val64 = 0xA5A5A5A5A5A5A5A5ULL;
5536 writeq(val64, &bar0->xmsi_data);
5537 val64 = readq(&bar0->xmsi_data);
5538 if (val64 != 0xA5A5A5A5A5A5A5A5ULL) {
5539 fail = 1;
5540 DBG_PRINT(ERR_DBG, "Write Test level 2 fails\n");
5541 }
5542
5543 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005544 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545}
5546
5547/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005548 * s2io_eeprom_test - to verify that EEprom in the xena can be programmed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 * @sp : private member of the device structure, which is a pointer to the
5550 * s2io_nic structure.
5551 * @data:variable that returns the result of each of the test conducted by
5552 * the driver.
5553 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005554 * Verify that EEPROM in the xena can be programmed using I2C_CONTROL
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 * register.
5556 * Return value:
5557 * 0 on success.
5558 */
5559
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005560static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561{
5562 int fail = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005563 u64 ret_data, org_4F0, org_7F0;
5564 u8 saved_4F0 = 0, saved_7F0 = 0;
5565 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566
5567 /* Test Write Error at offset 0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005568 /* Note that SPI interface allows write access to all areas
5569 * of EEPROM. Hence doing all negative testing only for Xframe I.
5570 */
5571 if (sp->device_type == XFRAME_I_DEVICE)
5572 if (!write_eeprom(sp, 0, 0, 3))
5573 fail = 1;
5574
5575 /* Save current values at offsets 0x4F0 and 0x7F0 */
5576 if (!read_eeprom(sp, 0x4F0, &org_4F0))
5577 saved_4F0 = 1;
5578 if (!read_eeprom(sp, 0x7F0, &org_7F0))
5579 saved_7F0 = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580
5581 /* Test Write at offset 4f0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005582 if (write_eeprom(sp, 0x4F0, 0x012345, 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 fail = 1;
5584 if (read_eeprom(sp, 0x4F0, &ret_data))
5585 fail = 1;
5586
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005587 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005588 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. "
5589 "Data written %llx Data read %llx\n",
5590 dev->name, (unsigned long long)0x12345,
5591 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594
5595 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005596 write_eeprom(sp, 0x4F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597
5598 /* Test Write Request Error at offset 0x7c */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005599 if (sp->device_type == XFRAME_I_DEVICE)
5600 if (!write_eeprom(sp, 0x07C, 0, 3))
5601 fail = 1;
5602
5603 /* Test Write Request at offset 0x7f0 */
5604 if (write_eeprom(sp, 0x7F0, 0x012345, 3))
5605 fail = 1;
5606 if (read_eeprom(sp, 0x7F0, &ret_data))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 fail = 1;
5608
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005609 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005610 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. "
5611 "Data written %llx Data read %llx\n",
5612 dev->name, (unsigned long long)0x12345,
5613 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616
5617 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005618 write_eeprom(sp, 0x7F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005620 if (sp->device_type == XFRAME_I_DEVICE) {
5621 /* Test Write Error at offset 0x80 */
5622 if (!write_eeprom(sp, 0x080, 0, 3))
5623 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005625 /* Test Write Error at offset 0xfc */
5626 if (!write_eeprom(sp, 0x0FC, 0, 3))
5627 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005629 /* Test Write Error at offset 0x100 */
5630 if (!write_eeprom(sp, 0x100, 0, 3))
5631 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005633 /* Test Write Error at offset 4ec */
5634 if (!write_eeprom(sp, 0x4EC, 0, 3))
5635 fail = 1;
5636 }
5637
5638 /* Restore values at offsets 0x4F0 and 0x7F0 */
5639 if (saved_4F0)
5640 write_eeprom(sp, 0x4F0, org_4F0, 3);
5641 if (saved_7F0)
5642 write_eeprom(sp, 0x7F0, org_7F0, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643
5644 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005645 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646}
5647
5648/**
5649 * s2io_bist_test - invokes the MemBist test of the card .
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005650 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005652 * @data:variable that returns the result of each of the test conducted by
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 * the driver.
5654 * Description:
5655 * This invokes the MemBist test of the card. We give around
5656 * 2 secs time for the Test to complete. If it's still not complete
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005657 * within this peiod, we consider that the test failed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 * Return value:
5659 * 0 on success and -1 on failure.
5660 */
5661
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005662static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663{
5664 u8 bist = 0;
5665 int cnt = 0, ret = -1;
5666
5667 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5668 bist |= PCI_BIST_START;
5669 pci_write_config_word(sp->pdev, PCI_BIST, bist);
5670
5671 while (cnt < 20) {
5672 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5673 if (!(bist & PCI_BIST_START)) {
5674 *data = (bist & PCI_BIST_CODE_MASK);
5675 ret = 0;
5676 break;
5677 }
5678 msleep(100);
5679 cnt++;
5680 }
5681
5682 return ret;
5683}
5684
5685/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005686 * s2io-link_test - verifies the link state of the nic
5687 * @sp ; private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 * s2io_nic structure.
5689 * @data: variable that returns the result of each of the test conducted by
5690 * the driver.
5691 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005692 * The function verifies the link state of the NIC and updates the input
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693 * argument 'data' appropriately.
5694 * Return value:
5695 * 0 on success.
5696 */
5697
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005698static int s2io_link_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005700 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005701 u64 val64;
5702
5703 val64 = readq(&bar0->adapter_status);
Ananda Rajuc92ca042006-04-21 19:18:03 -04005704 if(!(LINK_IS_UP(val64)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705 *data = 1;
Ananda Rajuc92ca042006-04-21 19:18:03 -04005706 else
5707 *data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708
Ananda Rajub41477f2006-07-24 19:52:49 -04005709 return *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710}
5711
5712/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005713 * s2io_rldram_test - offline test for access to the RldRam chip on the NIC
5714 * @sp - private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005716 * @data - variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717 * conducted by the driver.
5718 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005719 * This is one of the offline test that tests the read and write
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720 * access to the RldRam chip on the NIC.
5721 * Return value:
5722 * 0 on success.
5723 */
5724
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005725static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005727 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728 u64 val64;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005729 int cnt, iteration = 0, test_fail = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730
5731 val64 = readq(&bar0->adapter_control);
5732 val64 &= ~ADAPTER_ECC_EN;
5733 writeq(val64, &bar0->adapter_control);
5734
5735 val64 = readq(&bar0->mc_rldram_test_ctrl);
5736 val64 |= MC_RLDRAM_TEST_MODE;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005737 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738
5739 val64 = readq(&bar0->mc_rldram_mrs);
5740 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE;
5741 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5742
5743 val64 |= MC_RLDRAM_MRS_ENABLE;
5744 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5745
5746 while (iteration < 2) {
5747 val64 = 0x55555555aaaa0000ULL;
5748 if (iteration == 1) {
5749 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5750 }
5751 writeq(val64, &bar0->mc_rldram_test_d0);
5752
5753 val64 = 0xaaaa5a5555550000ULL;
5754 if (iteration == 1) {
5755 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5756 }
5757 writeq(val64, &bar0->mc_rldram_test_d1);
5758
5759 val64 = 0x55aaaaaaaa5a0000ULL;
5760 if (iteration == 1) {
5761 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5762 }
5763 writeq(val64, &bar0->mc_rldram_test_d2);
5764
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005765 val64 = (u64) (0x0000003ffffe0100ULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766 writeq(val64, &bar0->mc_rldram_test_add);
5767
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005768 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE |
5769 MC_RLDRAM_TEST_GO;
5770 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771
5772 for (cnt = 0; cnt < 5; cnt++) {
5773 val64 = readq(&bar0->mc_rldram_test_ctrl);
5774 if (val64 & MC_RLDRAM_TEST_DONE)
5775 break;
5776 msleep(200);
5777 }
5778
5779 if (cnt == 5)
5780 break;
5781
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005782 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO;
5783 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784
5785 for (cnt = 0; cnt < 5; cnt++) {
5786 val64 = readq(&bar0->mc_rldram_test_ctrl);
5787 if (val64 & MC_RLDRAM_TEST_DONE)
5788 break;
5789 msleep(500);
5790 }
5791
5792 if (cnt == 5)
5793 break;
5794
5795 val64 = readq(&bar0->mc_rldram_test_ctrl);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005796 if (!(val64 & MC_RLDRAM_TEST_PASS))
5797 test_fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798
5799 iteration++;
5800 }
5801
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005802 *data = test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005803
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005804 /* Bring the adapter out of test mode */
5805 SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF);
5806
5807 return test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005808}
5809
5810/**
5811 * s2io_ethtool_test - conducts 6 tsets to determine the health of card.
5812 * @sp : private member of the device structure, which is a pointer to the
5813 * s2io_nic structure.
5814 * @ethtest : pointer to a ethtool command specific structure that will be
5815 * returned to the user.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005816 * @data : variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817 * conducted by the driver.
5818 * Description:
5819 * This function conducts 6 tests ( 4 offline and 2 online) to determine
5820 * the health of the card.
5821 * Return value:
5822 * void
5823 */
5824
5825static void s2io_ethtool_test(struct net_device *dev,
5826 struct ethtool_test *ethtest,
5827 uint64_t * data)
5828{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005829 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830 int orig_state = netif_running(sp->dev);
5831
5832 if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
5833 /* Offline Tests. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005834 if (orig_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835 s2io_close(sp->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836
5837 if (s2io_register_test(sp, &data[0]))
5838 ethtest->flags |= ETH_TEST_FL_FAILED;
5839
5840 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841
5842 if (s2io_rldram_test(sp, &data[3]))
5843 ethtest->flags |= ETH_TEST_FL_FAILED;
5844
5845 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846
5847 if (s2io_eeprom_test(sp, &data[1]))
5848 ethtest->flags |= ETH_TEST_FL_FAILED;
5849
5850 if (s2io_bist_test(sp, &data[4]))
5851 ethtest->flags |= ETH_TEST_FL_FAILED;
5852
5853 if (orig_state)
5854 s2io_open(sp->dev);
5855
5856 data[2] = 0;
5857 } else {
5858 /* Online Tests. */
5859 if (!orig_state) {
5860 DBG_PRINT(ERR_DBG,
5861 "%s: is not up, cannot run test\n",
5862 dev->name);
5863 data[0] = -1;
5864 data[1] = -1;
5865 data[2] = -1;
5866 data[3] = -1;
5867 data[4] = -1;
5868 }
5869
5870 if (s2io_link_test(sp, &data[2]))
5871 ethtest->flags |= ETH_TEST_FL_FAILED;
5872
5873 data[0] = 0;
5874 data[1] = 0;
5875 data[3] = 0;
5876 data[4] = 0;
5877 }
5878}
5879
5880static void s2io_get_ethtool_stats(struct net_device *dev,
5881 struct ethtool_stats *estats,
5882 u64 * tmp_stats)
5883{
Sivakumar Subramani8116f3c2007-09-17 13:05:35 -07005884 int i = 0, k;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05005885 struct s2io_nic *sp = dev->priv;
5886 struct stat_block *stat_info = sp->mac_control.stats_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005888 s2io_updt_stats(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005889 tmp_stats[i++] =
5890 (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32 |
5891 le32_to_cpu(stat_info->tmac_frms);
5892 tmp_stats[i++] =
5893 (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 |
5894 le32_to_cpu(stat_info->tmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005896 tmp_stats[i++] =
5897 (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 |
5898 le32_to_cpu(stat_info->tmac_mcst_frms);
5899 tmp_stats[i++] =
5900 (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 |
5901 le32_to_cpu(stat_info->tmac_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005903 tmp_stats[i++] =
5904 (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 |
5905 le32_to_cpu(stat_info->tmac_ttl_octets);
5906 tmp_stats[i++] =
5907 (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 |
5908 le32_to_cpu(stat_info->tmac_ucst_frms);
5909 tmp_stats[i++] =
5910 (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 |
5911 le32_to_cpu(stat_info->tmac_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005912 tmp_stats[i++] =
5913 (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 |
5914 le32_to_cpu(stat_info->tmac_any_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005915 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005917 tmp_stats[i++] =
5918 (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 |
5919 le32_to_cpu(stat_info->tmac_vld_ip);
5920 tmp_stats[i++] =
5921 (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 |
5922 le32_to_cpu(stat_info->tmac_drop_ip);
5923 tmp_stats[i++] =
5924 (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 |
5925 le32_to_cpu(stat_info->tmac_icmp);
5926 tmp_stats[i++] =
5927 (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 |
5928 le32_to_cpu(stat_info->tmac_rst_tcp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005930 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 |
5931 le32_to_cpu(stat_info->tmac_udp);
5932 tmp_stats[i++] =
5933 (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 |
5934 le32_to_cpu(stat_info->rmac_vld_frms);
5935 tmp_stats[i++] =
5936 (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 |
5937 le32_to_cpu(stat_info->rmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms);
5939 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005940 tmp_stats[i++] =
5941 (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 |
5942 le32_to_cpu(stat_info->rmac_vld_mcst_frms);
5943 tmp_stats[i++] =
5944 (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 |
5945 le32_to_cpu(stat_info->rmac_vld_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005947 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_out_rng_len_err_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms);
5949 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005950 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_unsup_ctrl_frms);
5951 tmp_stats[i++] =
5952 (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 |
5953 le32_to_cpu(stat_info->rmac_ttl_octets);
5954 tmp_stats[i++] =
5955 (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow)
5956 << 32 | le32_to_cpu(stat_info->rmac_accepted_ucst_frms);
5957 tmp_stats[i++] =
5958 (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow)
5959 << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005960 tmp_stats[i++] =
5961 (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 |
5962 le32_to_cpu(stat_info->rmac_discarded_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005963 tmp_stats[i++] =
5964 (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow)
5965 << 32 | le32_to_cpu(stat_info->rmac_drop_events);
5966 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets);
5967 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005968 tmp_stats[i++] =
5969 (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 |
5970 le32_to_cpu(stat_info->rmac_usized_frms);
5971 tmp_stats[i++] =
5972 (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 |
5973 le32_to_cpu(stat_info->rmac_osized_frms);
5974 tmp_stats[i++] =
5975 (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 |
5976 le32_to_cpu(stat_info->rmac_frag_frms);
5977 tmp_stats[i++] =
5978 (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 |
5979 le32_to_cpu(stat_info->rmac_jabber_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005980 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_64_frms);
5981 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms);
5982 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms);
5983 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms);
5984 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms);
5985 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms);
5986 tmp_stats[i++] =
5987 (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005988 le32_to_cpu(stat_info->rmac_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets);
5990 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005991 tmp_stats[i++] =
5992 (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005993 le32_to_cpu(stat_info->rmac_drop_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005994 tmp_stats[i++] =
5995 (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005996 le32_to_cpu(stat_info->rmac_icmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005997 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005998 tmp_stats[i++] =
5999 (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006000 le32_to_cpu(stat_info->rmac_udp);
6001 tmp_stats[i++] =
6002 (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 |
6003 le32_to_cpu(stat_info->rmac_err_drp_udp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04006004 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_err_sym);
6005 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0);
6006 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1);
6007 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2);
6008 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3);
6009 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4);
6010 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5);
6011 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6);
6012 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7);
6013 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0);
6014 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1);
6015 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2);
6016 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3);
6017 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4);
6018 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5);
6019 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6);
6020 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006021 tmp_stats[i++] =
6022 (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 |
6023 le32_to_cpu(stat_info->rmac_pause_cnt);
Ananda Rajubd1034f2006-04-21 19:20:22 -04006024 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_data_err_cnt);
6025 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006026 tmp_stats[i++] =
6027 (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 |
6028 le32_to_cpu(stat_info->rmac_accepted_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04006030 tmp_stats[i++] = le32_to_cpu(stat_info->rd_req_cnt);
6031 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_cnt);
6032 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_rtry_cnt);
6033 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_cnt);
6034 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_rd_ack_cnt);
6035 tmp_stats[i++] = le32_to_cpu(stat_info->wr_req_cnt);
6036 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_cnt);
6037 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_rtry_cnt);
6038 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_cnt);
6039 tmp_stats[i++] = le32_to_cpu(stat_info->wr_disc_cnt);
6040 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_wr_ack_cnt);
6041 tmp_stats[i++] = le32_to_cpu(stat_info->txp_wr_cnt);
6042 tmp_stats[i++] = le32_to_cpu(stat_info->txd_rd_cnt);
6043 tmp_stats[i++] = le32_to_cpu(stat_info->txd_wr_cnt);
6044 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_rd_cnt);
6045 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_wr_cnt);
6046 tmp_stats[i++] = le32_to_cpu(stat_info->txf_rd_cnt);
6047 tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt);
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -05006048
6049 /* Enhanced statistics exist only for Hercules */
6050 if(sp->device_type == XFRAME_II_DEVICE) {
6051 tmp_stats[i++] =
6052 le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms);
6053 tmp_stats[i++] =
6054 le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms);
6055 tmp_stats[i++] =
6056 le64_to_cpu(stat_info->rmac_ttl_8192_max_frms);
6057 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms);
6058 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms);
6059 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms);
6060 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms);
6061 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms);
6062 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard);
6063 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard);
6064 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard);
6065 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard);
6066 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard);
6067 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard);
6068 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard);
6069 tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt);
6070 }
6071
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006072 tmp_stats[i++] = 0;
6073 tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
6074 tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
Ananda Rajubd1034f2006-04-21 19:20:22 -04006075 tmp_stats[i++] = stat_info->sw_stat.parity_err_cnt;
6076 tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt;
6077 tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt;
6078 tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt;
Sivakumar Subramani8116f3c2007-09-17 13:05:35 -07006079 for (k = 0; k < MAX_RX_RINGS; k++)
6080 tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt[k];
Ananda Rajubd1034f2006-04-21 19:20:22 -04006081 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high;
6082 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low;
6083 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high;
6084 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_low;
6085 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_high;
6086 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_low;
6087 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_high;
6088 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_low;
6089 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_high;
6090 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_low;
6091 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_high;
6092 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_low;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006093 tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt;
6094 tmp_stats[i++] = stat_info->sw_stat.sending_both;
6095 tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts;
6096 tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts;
Andrew Mortonfe931392006-02-03 01:45:12 -08006097 if (stat_info->sw_stat.num_aggregations) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04006098 u64 tmp = stat_info->sw_stat.sum_avg_pkts_aggregated;
6099 int count = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006100 /*
Ananda Rajubd1034f2006-04-21 19:20:22 -04006101 * Since 64-bit divide does not work on all platforms,
6102 * do repeated subtraction.
6103 */
6104 while (tmp >= stat_info->sw_stat.num_aggregations) {
6105 tmp -= stat_info->sw_stat.num_aggregations;
6106 count++;
6107 }
6108 tmp_stats[i++] = count;
Andrew Mortonfe931392006-02-03 01:45:12 -08006109 }
Ananda Rajubd1034f2006-04-21 19:20:22 -04006110 else
6111 tmp_stats[i++] = 0;
Sreenivasa Honnurc53d4942007-05-10 04:18:54 -04006112 tmp_stats[i++] = stat_info->sw_stat.mem_alloc_fail_cnt;
Veena Parat491abf22007-07-23 02:37:14 -04006113 tmp_stats[i++] = stat_info->sw_stat.pci_map_fail_cnt;
Sreenivasa Honnurc53d4942007-05-10 04:18:54 -04006114 tmp_stats[i++] = stat_info->sw_stat.watchdog_timer_cnt;
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04006115 tmp_stats[i++] = stat_info->sw_stat.mem_allocated;
6116 tmp_stats[i++] = stat_info->sw_stat.mem_freed;
6117 tmp_stats[i++] = stat_info->sw_stat.link_up_cnt;
6118 tmp_stats[i++] = stat_info->sw_stat.link_down_cnt;
6119 tmp_stats[i++] = stat_info->sw_stat.link_up_time;
6120 tmp_stats[i++] = stat_info->sw_stat.link_down_time;
6121
6122 tmp_stats[i++] = stat_info->sw_stat.tx_buf_abort_cnt;
6123 tmp_stats[i++] = stat_info->sw_stat.tx_desc_abort_cnt;
6124 tmp_stats[i++] = stat_info->sw_stat.tx_parity_err_cnt;
6125 tmp_stats[i++] = stat_info->sw_stat.tx_link_loss_cnt;
6126 tmp_stats[i++] = stat_info->sw_stat.tx_list_proc_err_cnt;
6127
6128 tmp_stats[i++] = stat_info->sw_stat.rx_parity_err_cnt;
6129 tmp_stats[i++] = stat_info->sw_stat.rx_abort_cnt;
6130 tmp_stats[i++] = stat_info->sw_stat.rx_parity_abort_cnt;
6131 tmp_stats[i++] = stat_info->sw_stat.rx_rda_fail_cnt;
6132 tmp_stats[i++] = stat_info->sw_stat.rx_unkn_prot_cnt;
6133 tmp_stats[i++] = stat_info->sw_stat.rx_fcs_err_cnt;
6134 tmp_stats[i++] = stat_info->sw_stat.rx_buf_size_err_cnt;
6135 tmp_stats[i++] = stat_info->sw_stat.rx_rxd_corrupt_cnt;
6136 tmp_stats[i++] = stat_info->sw_stat.rx_unkn_err_cnt;
Sivakumar Subramani8116f3c2007-09-17 13:05:35 -07006137 tmp_stats[i++] = stat_info->sw_stat.tda_err_cnt;
6138 tmp_stats[i++] = stat_info->sw_stat.pfc_err_cnt;
6139 tmp_stats[i++] = stat_info->sw_stat.pcc_err_cnt;
6140 tmp_stats[i++] = stat_info->sw_stat.tti_err_cnt;
6141 tmp_stats[i++] = stat_info->sw_stat.tpa_err_cnt;
6142 tmp_stats[i++] = stat_info->sw_stat.sm_err_cnt;
6143 tmp_stats[i++] = stat_info->sw_stat.lso_err_cnt;
6144 tmp_stats[i++] = stat_info->sw_stat.mac_tmac_err_cnt;
6145 tmp_stats[i++] = stat_info->sw_stat.mac_rmac_err_cnt;
6146 tmp_stats[i++] = stat_info->sw_stat.xgxs_txgxs_err_cnt;
6147 tmp_stats[i++] = stat_info->sw_stat.xgxs_rxgxs_err_cnt;
6148 tmp_stats[i++] = stat_info->sw_stat.rc_err_cnt;
6149 tmp_stats[i++] = stat_info->sw_stat.prc_pcix_err_cnt;
6150 tmp_stats[i++] = stat_info->sw_stat.rpa_err_cnt;
6151 tmp_stats[i++] = stat_info->sw_stat.rda_err_cnt;
6152 tmp_stats[i++] = stat_info->sw_stat.rti_err_cnt;
6153 tmp_stats[i++] = stat_info->sw_stat.mc_err_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006154}
6155
Adrian Bunkac1f60d2005-11-06 01:46:47 +01006156static int s2io_ethtool_get_regs_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157{
6158 return (XENA_REG_SPACE);
6159}
6160
6161
Adrian Bunkac1f60d2005-11-06 01:46:47 +01006162static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006164 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006165
6166 return (sp->rx_csum);
6167}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01006168
6169static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006170{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006171 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006172
6173 if (data)
6174 sp->rx_csum = 1;
6175 else
6176 sp->rx_csum = 0;
6177
6178 return 0;
6179}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01006180
6181static int s2io_get_eeprom_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182{
6183 return (XENA_EEPROM_SPACE);
6184}
6185
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006186static int s2io_get_sset_count(struct net_device *dev, int sset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006187{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006188 struct s2io_nic *sp = dev->priv;
6189
6190 switch (sset) {
6191 case ETH_SS_TEST:
6192 return S2IO_TEST_LEN;
6193 case ETH_SS_STATS:
6194 switch(sp->device_type) {
6195 case XFRAME_I_DEVICE:
6196 return XFRAME_I_STAT_LEN;
6197 case XFRAME_II_DEVICE:
6198 return XFRAME_II_STAT_LEN;
6199 default:
6200 return 0;
6201 }
6202 default:
6203 return -EOPNOTSUPP;
6204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006205}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01006206
6207static void s2io_ethtool_get_strings(struct net_device *dev,
6208 u32 stringset, u8 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209{
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -05006210 int stat_size = 0;
6211 struct s2io_nic *sp = dev->priv;
6212
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213 switch (stringset) {
6214 case ETH_SS_TEST:
6215 memcpy(data, s2io_gstrings, S2IO_STRINGS_LEN);
6216 break;
6217 case ETH_SS_STATS:
Sivakumar Subramanifa1f0cb2007-02-24 02:03:22 -05006218 stat_size = sizeof(ethtool_xena_stats_keys);
6219 memcpy(data, &ethtool_xena_stats_keys,stat_size);
6220 if(sp->device_type == XFRAME_II_DEVICE) {
6221 memcpy(data + stat_size,
6222 &ethtool_enhanced_stats_keys,
6223 sizeof(ethtool_enhanced_stats_keys));
6224 stat_size += sizeof(ethtool_enhanced_stats_keys);
6225 }
6226
6227 memcpy(data + stat_size, &ethtool_driver_stats_keys,
6228 sizeof(ethtool_driver_stats_keys));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229 }
6230}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006231
Adrian Bunkac1f60d2005-11-06 01:46:47 +01006232static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233{
6234 if (data)
6235 dev->features |= NETIF_F_IP_CSUM;
6236 else
6237 dev->features &= ~NETIF_F_IP_CSUM;
6238
6239 return 0;
6240}
6241
Ananda Raju75c30b12006-07-24 19:55:09 -04006242static u32 s2io_ethtool_op_get_tso(struct net_device *dev)
6243{
6244 return (dev->features & NETIF_F_TSO) != 0;
6245}
6246static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data)
6247{
6248 if (data)
6249 dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
6250 else
6251 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
6252
6253 return 0;
6254}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255
Jeff Garzik7282d492006-09-13 14:30:00 -04006256static const struct ethtool_ops netdev_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257 .get_settings = s2io_ethtool_gset,
6258 .set_settings = s2io_ethtool_sset,
6259 .get_drvinfo = s2io_ethtool_gdrvinfo,
6260 .get_regs_len = s2io_ethtool_get_regs_len,
6261 .get_regs = s2io_ethtool_gregs,
6262 .get_link = ethtool_op_get_link,
6263 .get_eeprom_len = s2io_get_eeprom_len,
6264 .get_eeprom = s2io_ethtool_geeprom,
6265 .set_eeprom = s2io_ethtool_seeprom,
Sreenivasa Honnur0cec35e2007-05-10 04:06:28 -04006266 .get_ringparam = s2io_ethtool_gringparam,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006267 .get_pauseparam = s2io_ethtool_getpause_data,
6268 .set_pauseparam = s2io_ethtool_setpause_data,
6269 .get_rx_csum = s2io_ethtool_get_rx_csum,
6270 .set_rx_csum = s2io_ethtool_set_rx_csum,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271 .set_tx_csum = s2io_ethtool_op_set_tx_csum,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272 .set_sg = ethtool_op_set_sg,
Ananda Raju75c30b12006-07-24 19:55:09 -04006273 .get_tso = s2io_ethtool_op_get_tso,
6274 .set_tso = s2io_ethtool_op_set_tso,
Ananda Rajufed5ecc2005-11-14 15:25:08 -05006275 .set_ufo = ethtool_op_set_ufo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276 .self_test = s2io_ethtool_test,
6277 .get_strings = s2io_ethtool_get_strings,
6278 .phys_id = s2io_ethtool_idnic,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006279 .get_ethtool_stats = s2io_get_ethtool_stats,
6280 .get_sset_count = s2io_get_sset_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006281};
6282
6283/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006284 * s2io_ioctl - Entry point for the Ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 * @dev : Device pointer.
6286 * @ifr : An IOCTL specefic structure, that can contain a pointer to
6287 * a proprietary structure used to pass information to the driver.
6288 * @cmd : This is used to distinguish between the different commands that
6289 * can be passed to the IOCTL functions.
6290 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006291 * Currently there are no special functionality supported in IOCTL, hence
6292 * function always return EOPNOTSUPPORTED
Linus Torvalds1da177e2005-04-16 15:20:36 -07006293 */
6294
Adrian Bunkac1f60d2005-11-06 01:46:47 +01006295static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296{
6297 return -EOPNOTSUPP;
6298}
6299
6300/**
6301 * s2io_change_mtu - entry point to change MTU size for the device.
6302 * @dev : device pointer.
6303 * @new_mtu : the new MTU size for the device.
6304 * Description: A driver entry point to change MTU size for the device.
6305 * Before changing the MTU the device must be stopped.
6306 * Return value:
6307 * 0 on success and an appropriate (-)ve integer as defined in errno.h
6308 * file on failure.
6309 */
6310
Adrian Bunkac1f60d2005-11-06 01:46:47 +01006311static int s2io_change_mtu(struct net_device *dev, int new_mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006313 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314
6315 if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
6316 DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
6317 dev->name);
6318 return -EPERM;
6319 }
6320
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321 dev->mtu = new_mtu;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07006322 if (netif_running(dev)) {
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006323 s2io_card_down(sp);
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07006324 netif_stop_queue(dev);
6325 if (s2io_card_up(sp)) {
6326 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
6327 __FUNCTION__);
6328 }
6329 if (netif_queue_stopped(dev))
6330 netif_wake_queue(dev);
6331 } else { /* Device is down */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006332 struct XENA_dev_config __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07006333 u64 val64 = new_mtu;
6334
6335 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
6336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337
6338 return 0;
6339}
6340
6341/**
6342 * s2io_tasklet - Bottom half of the ISR.
6343 * @dev_adr : address of the device structure in dma_addr_t format.
6344 * Description:
6345 * This is the tasklet or the bottom half of the ISR. This is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006346 * an extension of the ISR which is scheduled by the scheduler to be run
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347 * 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 -07006348 * be pushed into the tasklet. For now the tasklet is used only to
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 * replenish the Rx buffers in the Rx buffer descriptors.
6350 * Return value:
6351 * void.
6352 */
6353
6354static void s2io_tasklet(unsigned long dev_addr)
6355{
6356 struct net_device *dev = (struct net_device *) dev_addr;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006357 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358 int i, ret;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006359 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006360 struct config_param *config;
6361
6362 mac_control = &sp->mac_control;
6363 config = &sp->config;
6364
6365 if (!TASKLET_IN_USE) {
6366 for (i = 0; i < config->rx_ring_num; i++) {
6367 ret = fill_rx_buffers(sp, i);
6368 if (ret == -ENOMEM) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08006369 DBG_PRINT(INFO_DBG, "%s: Out of ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006370 dev->name);
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04006371 DBG_PRINT(INFO_DBG, "memory in tasklet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372 break;
6373 } else if (ret == -EFILL) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08006374 DBG_PRINT(INFO_DBG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006375 "%s: Rx Ring %d is full\n",
6376 dev->name, i);
6377 break;
6378 }
6379 }
6380 clear_bit(0, (&sp->tasklet_status));
6381 }
6382}
6383
6384/**
6385 * s2io_set_link - Set the LInk status
6386 * @data: long pointer to device private structue
6387 * Description: Sets the link status for the adapter
6388 */
6389
David Howellsc4028952006-11-22 14:57:56 +00006390static void s2io_set_link(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006392 struct s2io_nic *nic = container_of(work, struct s2io_nic, set_link_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006393 struct net_device *dev = nic->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006394 struct XENA_dev_config __iomem *bar0 = nic->bar0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006395 register u64 val64;
6396 u16 subid;
6397
Francois Romieu22747d62007-02-15 23:37:50 +01006398 rtnl_lock();
6399
6400 if (!netif_running(dev))
6401 goto out_unlock;
6402
Sivakumar Subramani92b84432007-09-06 06:51:14 -04006403 if (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(nic->state))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006404 /* The card is being reset, no point doing anything */
Francois Romieu22747d62007-02-15 23:37:50 +01006405 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406 }
6407
6408 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07006409 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
6410 /*
6411 * Allow a small delay for the NICs self initiated
6412 * cleanup to complete.
6413 */
6414 msleep(100);
6415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006416
6417 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006418 if (LINK_IS_UP(val64)) {
6419 if (!(readq(&bar0->adapter_control) & ADAPTER_CNTL_EN)) {
6420 if (verify_xena_quiescence(nic)) {
6421 val64 = readq(&bar0->adapter_control);
6422 val64 |= ADAPTER_CNTL_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006423 writeq(val64, &bar0->adapter_control);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006424 if (CARDS_WITH_FAULTY_LINK_INDICATORS(
6425 nic->device_type, subid)) {
6426 val64 = readq(&bar0->gpio_control);
6427 val64 |= GPIO_CTRL_GPIO_0;
6428 writeq(val64, &bar0->gpio_control);
6429 val64 = readq(&bar0->gpio_control);
6430 } else {
6431 val64 |= ADAPTER_LED_ON;
6432 writeq(val64, &bar0->adapter_control);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07006433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006434 nic->device_enabled_once = TRUE;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006435 } else {
6436 DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
6437 DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
6438 netif_stop_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440 }
Sivakumar Subramani92c48792007-08-06 05:38:19 -04006441 val64 = readq(&bar0->adapter_control);
6442 val64 |= ADAPTER_LED_ON;
6443 writeq(val64, &bar0->adapter_control);
6444 s2io_link(nic, LINK_UP);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006445 } else {
6446 if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
6447 subid)) {
6448 val64 = readq(&bar0->gpio_control);
6449 val64 &= ~GPIO_CTRL_GPIO_0;
6450 writeq(val64, &bar0->gpio_control);
6451 val64 = readq(&bar0->gpio_control);
6452 }
Sivakumar Subramani92c48792007-08-06 05:38:19 -04006453 /* turn off LED */
6454 val64 = readq(&bar0->adapter_control);
6455 val64 = val64 &(~ADAPTER_LED_ON);
6456 writeq(val64, &bar0->adapter_control);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006457 s2io_link(nic, LINK_DOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006458 }
Sivakumar Subramani92b84432007-09-06 06:51:14 -04006459 clear_bit(__S2IO_STATE_LINK_TASK, &(nic->state));
Francois Romieu22747d62007-02-15 23:37:50 +01006460
6461out_unlock:
Sivakumar Subramanid8d70ca2007-02-24 02:04:24 -05006462 rtnl_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006463}
6464
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006465static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
6466 struct buffAdd *ba,
6467 struct sk_buff **skb, u64 *temp0, u64 *temp1,
6468 u64 *temp2, int size)
Ananda Raju5d3213c2006-04-21 19:23:26 -04006469{
6470 struct net_device *dev = sp->dev;
Veena Parat491abf22007-07-23 02:37:14 -04006471 struct swStat *stats = &sp->mac_control.stats_info->sw_stat;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006472
6473 if ((sp->rxd_mode == RXD_MODE_1) && (rxdp->Host_Control == 0)) {
Veena Parat6d517a22007-07-23 02:20:51 -04006474 struct RxD1 *rxdp1 = (struct RxD1 *)rxdp;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006475 /* allocate skb */
6476 if (*skb) {
6477 DBG_PRINT(INFO_DBG, "SKB is not NULL\n");
6478 /*
6479 * As Rx frame are not going to be processed,
6480 * using same mapped address for the Rxd
6481 * buffer pointer
6482 */
Veena Parat6d517a22007-07-23 02:20:51 -04006483 rxdp1->Buffer0_ptr = *temp0;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006484 } else {
6485 *skb = dev_alloc_skb(size);
6486 if (!(*skb)) {
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08006487 DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
Sreenivasa Honnurc53d4942007-05-10 04:18:54 -04006488 DBG_PRINT(INFO_DBG, "memory to allocate ");
6489 DBG_PRINT(INFO_DBG, "1 buf mode SKBs\n");
6490 sp->mac_control.stats_info->sw_stat. \
6491 mem_alloc_fail_cnt++;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006492 return -ENOMEM ;
6493 }
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04006494 sp->mac_control.stats_info->sw_stat.mem_allocated
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04006495 += (*skb)->truesize;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006496 /* storing the mapped addr in a temp variable
6497 * such it will be used for next rxd whose
6498 * Host Control is NULL
6499 */
Veena Parat6d517a22007-07-23 02:20:51 -04006500 rxdp1->Buffer0_ptr = *temp0 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006501 pci_map_single( sp->pdev, (*skb)->data,
6502 size - NET_IP_ALIGN,
6503 PCI_DMA_FROMDEVICE);
Veena Parat491abf22007-07-23 02:37:14 -04006504 if( (rxdp1->Buffer0_ptr == 0) ||
6505 (rxdp1->Buffer0_ptr == DMA_ERROR_CODE)) {
6506 goto memalloc_failed;
6507 }
Ananda Raju5d3213c2006-04-21 19:23:26 -04006508 rxdp->Host_Control = (unsigned long) (*skb);
6509 }
6510 } else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
Veena Parat6d517a22007-07-23 02:20:51 -04006511 struct RxD3 *rxdp3 = (struct RxD3 *)rxdp;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006512 /* Two buffer Mode */
6513 if (*skb) {
Veena Parat6d517a22007-07-23 02:20:51 -04006514 rxdp3->Buffer2_ptr = *temp2;
6515 rxdp3->Buffer0_ptr = *temp0;
6516 rxdp3->Buffer1_ptr = *temp1;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006517 } else {
6518 *skb = dev_alloc_skb(size);
David Rientjes2ceaac72006-10-30 14:19:25 -08006519 if (!(*skb)) {
Sreenivasa Honnurc53d4942007-05-10 04:18:54 -04006520 DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
6521 DBG_PRINT(INFO_DBG, "memory to allocate ");
6522 DBG_PRINT(INFO_DBG, "2 buf mode SKBs\n");
6523 sp->mac_control.stats_info->sw_stat. \
6524 mem_alloc_fail_cnt++;
David Rientjes2ceaac72006-10-30 14:19:25 -08006525 return -ENOMEM;
6526 }
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04006527 sp->mac_control.stats_info->sw_stat.mem_allocated
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04006528 += (*skb)->truesize;
Veena Parat6d517a22007-07-23 02:20:51 -04006529 rxdp3->Buffer2_ptr = *temp2 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006530 pci_map_single(sp->pdev, (*skb)->data,
6531 dev->mtu + 4,
6532 PCI_DMA_FROMDEVICE);
Veena Parat491abf22007-07-23 02:37:14 -04006533 if( (rxdp3->Buffer2_ptr == 0) ||
6534 (rxdp3->Buffer2_ptr == DMA_ERROR_CODE)) {
6535 goto memalloc_failed;
6536 }
Veena Parat6d517a22007-07-23 02:20:51 -04006537 rxdp3->Buffer0_ptr = *temp0 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006538 pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
6539 PCI_DMA_FROMDEVICE);
Veena Parat491abf22007-07-23 02:37:14 -04006540 if( (rxdp3->Buffer0_ptr == 0) ||
6541 (rxdp3->Buffer0_ptr == DMA_ERROR_CODE)) {
6542 pci_unmap_single (sp->pdev,
Al Viro3e847422007-08-02 19:21:30 +01006543 (dma_addr_t)rxdp3->Buffer2_ptr,
Veena Parat491abf22007-07-23 02:37:14 -04006544 dev->mtu + 4, PCI_DMA_FROMDEVICE);
6545 goto memalloc_failed;
6546 }
Ananda Raju5d3213c2006-04-21 19:23:26 -04006547 rxdp->Host_Control = (unsigned long) (*skb);
6548
6549 /* Buffer-1 will be dummy buffer not used */
Veena Parat6d517a22007-07-23 02:20:51 -04006550 rxdp3->Buffer1_ptr = *temp1 =
Ananda Raju5d3213c2006-04-21 19:23:26 -04006551 pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
Ananda Raju5d3213c2006-04-21 19:23:26 -04006552 PCI_DMA_FROMDEVICE);
Veena Parat491abf22007-07-23 02:37:14 -04006553 if( (rxdp3->Buffer1_ptr == 0) ||
6554 (rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
6555 pci_unmap_single (sp->pdev,
Al Viro3e847422007-08-02 19:21:30 +01006556 (dma_addr_t)rxdp3->Buffer0_ptr,
6557 BUF0_LEN, PCI_DMA_FROMDEVICE);
6558 pci_unmap_single (sp->pdev,
6559 (dma_addr_t)rxdp3->Buffer2_ptr,
Veena Parat491abf22007-07-23 02:37:14 -04006560 dev->mtu + 4, PCI_DMA_FROMDEVICE);
6561 goto memalloc_failed;
6562 }
Ananda Raju5d3213c2006-04-21 19:23:26 -04006563 }
6564 }
6565 return 0;
Veena Parat491abf22007-07-23 02:37:14 -04006566 memalloc_failed:
6567 stats->pci_map_fail_cnt++;
6568 stats->mem_freed += (*skb)->truesize;
6569 dev_kfree_skb(*skb);
6570 return -ENOMEM;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006571}
Veena Parat491abf22007-07-23 02:37:14 -04006572
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006573static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp,
6574 int size)
Ananda Raju5d3213c2006-04-21 19:23:26 -04006575{
6576 struct net_device *dev = sp->dev;
6577 if (sp->rxd_mode == RXD_MODE_1) {
6578 rxdp->Control_2 = SET_BUFFER0_SIZE_1( size - NET_IP_ALIGN);
6579 } else if (sp->rxd_mode == RXD_MODE_3B) {
6580 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
6581 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
6582 rxdp->Control_2 |= SET_BUFFER2_SIZE_3( dev->mtu + 4);
Ananda Raju5d3213c2006-04-21 19:23:26 -04006583 }
6584}
6585
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006586static int rxd_owner_bit_reset(struct s2io_nic *sp)
Ananda Raju5d3213c2006-04-21 19:23:26 -04006587{
6588 int i, j, k, blk_cnt = 0, size;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006589 struct mac_info * mac_control = &sp->mac_control;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006590 struct config_param *config = &sp->config;
6591 struct net_device *dev = sp->dev;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006592 struct RxD_t *rxdp = NULL;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006593 struct sk_buff *skb = NULL;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006594 struct buffAdd *ba = NULL;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006595 u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0;
6596
6597 /* Calculate the size based on ring mode */
6598 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
6599 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
6600 if (sp->rxd_mode == RXD_MODE_1)
6601 size += NET_IP_ALIGN;
6602 else if (sp->rxd_mode == RXD_MODE_3B)
6603 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
Ananda Raju5d3213c2006-04-21 19:23:26 -04006604
6605 for (i = 0; i < config->rx_ring_num; i++) {
6606 blk_cnt = config->rx_cfg[i].num_rxd /
6607 (rxd_count[sp->rxd_mode] +1);
6608
6609 for (j = 0; j < blk_cnt; j++) {
6610 for (k = 0; k < rxd_count[sp->rxd_mode]; k++) {
6611 rxdp = mac_control->rings[i].
6612 rx_blocks[j].rxds[k].virt_addr;
Veena Parat6d517a22007-07-23 02:20:51 -04006613 if(sp->rxd_mode == RXD_MODE_3B)
Ananda Raju5d3213c2006-04-21 19:23:26 -04006614 ba = &mac_control->rings[i].ba[j][k];
Sivakumar Subramaniac1f90d2007-02-24 02:01:31 -05006615 if (set_rxd_buffer_pointer(sp, rxdp, ba,
Ananda Raju5d3213c2006-04-21 19:23:26 -04006616 &skb,(u64 *)&temp0_64,
6617 (u64 *)&temp1_64,
Sivakumar Subramaniac1f90d2007-02-24 02:01:31 -05006618 (u64 *)&temp2_64,
6619 size) == ENOMEM) {
6620 return 0;
6621 }
Ananda Raju5d3213c2006-04-21 19:23:26 -04006622
6623 set_rxd_buffer_size(sp, rxdp, size);
6624 wmb();
6625 /* flip the Ownership bit to Hardware */
6626 rxdp->Control_1 |= RXD_OWN_XENA;
6627 }
6628 }
6629 }
6630 return 0;
6631
6632}
6633
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006634static int s2io_add_isr(struct s2io_nic * sp)
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006635{
6636 int ret = 0;
6637 struct net_device *dev = sp->dev;
6638 int err = 0;
6639
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07006640 if (sp->config.intr_type == MSI_X)
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006641 ret = s2io_enable_msi_x(sp);
6642 if (ret) {
6643 DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07006644 sp->config.intr_type = INTA;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006645 }
6646
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006647 /* Store the values of the MSIX table in the struct s2io_nic structure */
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006648 store_xmsi_data(sp);
6649
6650 /* After proper initialization of H/W, register ISR */
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07006651 if (sp->config.intr_type == MSI_X) {
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006652 int i, msix_tx_cnt=0,msix_rx_cnt=0;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006653
6654 for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
6655 if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
6656 sprintf(sp->desc[i], "%s:MSI-X-%d-TX",
6657 dev->name, i);
6658 err = request_irq(sp->entries[i].vector,
6659 s2io_msix_fifo_handle, 0, sp->desc[i],
6660 sp->s2io_entries[i].arg);
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006661 /* If either data or addr is zero print it */
6662 if(!(sp->msix_info[i].addr &&
6663 sp->msix_info[i].data)) {
6664 DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx"
6665 "Data:0x%lx\n",sp->desc[i],
6666 (unsigned long long)
6667 sp->msix_info[i].addr,
6668 (unsigned long)
6669 ntohl(sp->msix_info[i].data));
6670 } else {
6671 msix_tx_cnt++;
6672 }
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006673 } else {
6674 sprintf(sp->desc[i], "%s:MSI-X-%d-RX",
6675 dev->name, i);
6676 err = request_irq(sp->entries[i].vector,
6677 s2io_msix_ring_handle, 0, sp->desc[i],
6678 sp->s2io_entries[i].arg);
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006679 /* If either data or addr is zero print it */
6680 if(!(sp->msix_info[i].addr &&
6681 sp->msix_info[i].data)) {
6682 DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx"
6683 "Data:0x%lx\n",sp->desc[i],
6684 (unsigned long long)
6685 sp->msix_info[i].addr,
6686 (unsigned long)
6687 ntohl(sp->msix_info[i].data));
6688 } else {
6689 msix_rx_cnt++;
6690 }
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006691 }
6692 if (err) {
6693 DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
6694 "failed\n", dev->name, i);
6695 DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
6696 return -1;
6697 }
6698 sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
6699 }
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05006700 printk("MSI-X-TX %d entries enabled\n",msix_tx_cnt);
6701 printk("MSI-X-RX %d entries enabled\n",msix_rx_cnt);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006702 }
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07006703 if (sp->config.intr_type == INTA) {
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006704 err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
6705 sp->name, dev);
6706 if (err) {
6707 DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
6708 dev->name);
6709 return -1;
6710 }
6711 }
6712 return 0;
6713}
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006714static void s2io_rem_isr(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006715{
Ananda Rajuc92ca042006-04-21 19:18:03 -04006716 struct net_device *dev = sp->dev;
Sivakumar Subramanic77dd432007-08-06 05:36:28 -04006717 struct swStat *stats = &sp->mac_control.stats_info->sw_stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006718
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07006719 if (sp->config.intr_type == MSI_X) {
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006720 int i;
6721 u16 msi_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006722
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006723 for (i=1; (sp->s2io_entries[i].in_use ==
6724 MSIX_REGISTERED_SUCCESS); i++) {
6725 int vector = sp->entries[i].vector;
6726 void *arg = sp->s2io_entries[i].arg;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006727
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07006728 synchronize_irq(vector);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006729 free_irq(vector, arg);
6730 }
Sivakumar Subramanic77dd432007-08-06 05:36:28 -04006731
6732 kfree(sp->entries);
6733 stats->mem_freed +=
6734 (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
6735 kfree(sp->s2io_entries);
6736 stats->mem_freed +=
6737 (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
6738 sp->entries = NULL;
6739 sp->s2io_entries = NULL;
6740
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006741 pci_read_config_word(sp->pdev, 0x42, &msi_control);
6742 msi_control &= 0xFFFE; /* Disable MSI */
6743 pci_write_config_word(sp->pdev, 0x42, msi_control);
Ananda Rajuc92ca042006-04-21 19:18:03 -04006744
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006745 pci_disable_msix(sp->pdev);
6746 } else {
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07006747 synchronize_irq(sp->pdev->irq);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006748 free_irq(sp->pdev->irq, dev);
Ananda Rajuc92ca042006-04-21 19:18:03 -04006749 }
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006750}
6751
Linas Vepstasd796fdb2007-05-14 18:37:30 -05006752static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006753{
6754 int cnt = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006755 struct XENA_dev_config __iomem *bar0 = sp->bar0;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006756 unsigned long flags;
6757 register u64 val64 = 0;
6758
6759 del_timer_sync(&sp->alarm_timer);
6760 /* If s2io_set_link task is executing, wait till it completes. */
Sivakumar Subramani92b84432007-09-06 06:51:14 -04006761 while (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(sp->state))) {
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006762 msleep(50);
6763 }
Sivakumar Subramani92b84432007-09-06 06:51:14 -04006764 clear_bit(__S2IO_STATE_CARD_UP, &sp->state);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006765
6766 /* disable Tx and Rx traffic on the NIC */
Linas Vepstasd796fdb2007-05-14 18:37:30 -05006767 if (do_io)
6768 stop_nic(sp);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006769
6770 s2io_rem_isr(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006771
6772 /* Kill tasklet. */
6773 tasklet_kill(&sp->task);
6774
6775 /* Check if the device is Quiescent and then Reset the NIC */
Linas Vepstasd796fdb2007-05-14 18:37:30 -05006776 while(do_io) {
Ananda Raju5d3213c2006-04-21 19:23:26 -04006777 /* As per the HW requirement we need to replenish the
6778 * receive buffer to avoid the ring bump. Since there is
6779 * no intention of processing the Rx frame at this pointwe are
6780 * just settting the ownership bit of rxd in Each Rx
6781 * ring to HW and set the appropriate buffer size
6782 * based on the ring mode
6783 */
6784 rxd_owner_bit_reset(sp);
6785
Linus Torvalds1da177e2005-04-16 15:20:36 -07006786 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006787 if (verify_xena_quiescence(sp)) {
6788 if(verify_pcc_quiescent(sp, sp->device_enabled_once))
Linus Torvalds1da177e2005-04-16 15:20:36 -07006789 break;
6790 }
6791
6792 msleep(50);
6793 cnt++;
6794 if (cnt == 10) {
6795 DBG_PRINT(ERR_DBG,
6796 "s2io_close:Device not Quiescent ");
6797 DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n",
6798 (unsigned long long) val64);
6799 break;
6800 }
Linas Vepstasd796fdb2007-05-14 18:37:30 -05006801 }
6802 if (do_io)
6803 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006804
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006805 spin_lock_irqsave(&sp->tx_lock, flags);
6806 /* Free all Tx buffers */
6807 free_tx_buffers(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006808 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006809
6810 /* Free all Rx buffers */
6811 spin_lock_irqsave(&sp->rx_lock, flags);
6812 free_rx_buffers(sp);
6813 spin_unlock_irqrestore(&sp->rx_lock, flags);
6814
Sivakumar Subramani92b84432007-09-06 06:51:14 -04006815 clear_bit(__S2IO_STATE_LINK_TASK, &(sp->state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006816}
6817
Linas Vepstasd796fdb2007-05-14 18:37:30 -05006818static void s2io_card_down(struct s2io_nic * sp)
6819{
6820 do_s2io_card_down(sp, 1);
6821}
6822
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006823static int s2io_card_up(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006824{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006825 int i, ret = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006826 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006827 struct config_param *config;
6828 struct net_device *dev = (struct net_device *) sp->dev;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006829 u16 interruptible;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006830
6831 /* Initialize the H/W I/O registers */
6832 if (init_nic(sp) != 0) {
6833 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
6834 dev->name);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006835 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006836 return -ENODEV;
6837 }
6838
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006839 /*
6840 * Initializing the Rx buffers. For now we are considering only 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07006841 * Rx ring and initializing buffers into 30 Rx blocks
6842 */
6843 mac_control = &sp->mac_control;
6844 config = &sp->config;
6845
6846 for (i = 0; i < config->rx_ring_num; i++) {
6847 if ((ret = fill_rx_buffers(sp, i))) {
6848 DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
6849 dev->name);
6850 s2io_reset(sp);
6851 free_rx_buffers(sp);
6852 return -ENOMEM;
6853 }
6854 DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
6855 atomic_read(&sp->rx_bufs_left[i]));
6856 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006857 /* Maintain the state prior to the open */
6858 if (sp->promisc_flg)
6859 sp->promisc_flg = 0;
6860 if (sp->m_cast_flg) {
6861 sp->m_cast_flg = 0;
6862 sp->all_multi_pos= 0;
6863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006864
6865 /* Setting its receive mode */
6866 s2io_set_multicast(dev);
6867
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006868 if (sp->lro) {
Ananda Rajub41477f2006-07-24 19:52:49 -04006869 /* Initialize max aggregatable pkts per session based on MTU */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006870 sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
6871 /* Check if we can use(if specified) user provided value */
6872 if (lro_max_pkts < sp->lro_max_aggr_per_sess)
6873 sp->lro_max_aggr_per_sess = lro_max_pkts;
6874 }
6875
Linus Torvalds1da177e2005-04-16 15:20:36 -07006876 /* Enable Rx Traffic and interrupts on the NIC */
6877 if (start_nic(sp)) {
6878 DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006879 s2io_reset(sp);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006880 free_rx_buffers(sp);
6881 return -ENODEV;
6882 }
6883
6884 /* Add interrupt service routine */
6885 if (s2io_add_isr(sp) != 0) {
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07006886 if (sp->config.intr_type == MSI_X)
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006887 s2io_rem_isr(sp);
6888 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006889 free_rx_buffers(sp);
6890 return -ENODEV;
6891 }
6892
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07006893 S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
6894
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006895 /* Enable tasklet for the device */
6896 tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
6897
6898 /* Enable select interrupts */
Sivakumar Subramani9caab452007-09-06 06:21:54 -04006899 en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS);
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07006900 if (sp->config.intr_type != INTA)
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006901 en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
6902 else {
6903 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
Sivakumar Subramani9caab452007-09-06 06:21:54 -04006904 interruptible |= TX_PIC_INTR;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006905 en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS);
6906 }
6907
Sivakumar Subramani92b84432007-09-06 06:51:14 -04006908 set_bit(__S2IO_STATE_CARD_UP, &sp->state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006909 return 0;
6910}
6911
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006912/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006913 * s2io_restart_nic - Resets the NIC.
6914 * @data : long pointer to the device private structure
6915 * Description:
6916 * This function is scheduled to be run by the s2io_tx_watchdog
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006917 * function after 0.5 secs to reset the NIC. The idea is to reduce
Linus Torvalds1da177e2005-04-16 15:20:36 -07006918 * the run time of the watch dog routine which is run holding a
6919 * spin lock.
6920 */
6921
David Howellsc4028952006-11-22 14:57:56 +00006922static void s2io_restart_nic(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006923{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006924 struct s2io_nic *sp = container_of(work, struct s2io_nic, rst_timer_task);
David Howellsc4028952006-11-22 14:57:56 +00006925 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006926
Francois Romieu22747d62007-02-15 23:37:50 +01006927 rtnl_lock();
6928
6929 if (!netif_running(dev))
6930 goto out_unlock;
6931
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006932 s2io_card_down(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006933 if (s2io_card_up(sp)) {
6934 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
6935 dev->name);
6936 }
6937 netif_wake_queue(dev);
6938 DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
6939 dev->name);
Francois Romieu22747d62007-02-15 23:37:50 +01006940out_unlock:
6941 rtnl_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006942}
6943
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006944/**
6945 * s2io_tx_watchdog - Watchdog for transmit side.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006946 * @dev : Pointer to net device structure
6947 * Description:
6948 * This function is triggered if the Tx Queue is stopped
6949 * for a pre-defined amount of time when the Interface is still up.
6950 * If the Interface is jammed in such a situation, the hardware is
6951 * reset (by s2io_close) and restarted again (by s2io_open) to
6952 * overcome any problem that might have been caused in the hardware.
6953 * Return value:
6954 * void
6955 */
6956
6957static void s2io_tx_watchdog(struct net_device *dev)
6958{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006959 struct s2io_nic *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006960
6961 if (netif_carrier_ok(dev)) {
Sreenivasa Honnurc53d4942007-05-10 04:18:54 -04006962 sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006963 schedule_work(&sp->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04006964 sp->mac_control.stats_info->sw_stat.soft_reset_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006965 }
6966}
6967
6968/**
6969 * rx_osm_handler - To perform some OS related operations on SKB.
6970 * @sp: private member of the device structure,pointer to s2io_nic structure.
6971 * @skb : the socket buffer pointer.
6972 * @len : length of the packet
6973 * @cksum : FCS checksum of the frame.
6974 * @ring_no : the ring from which this RxD was extracted.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006975 * Description:
Ananda Rajub41477f2006-07-24 19:52:49 -04006976 * This function is called by the Rx interrupt serivce routine to perform
Linus Torvalds1da177e2005-04-16 15:20:36 -07006977 * some OS related operations on the SKB before passing it to the upper
6978 * layers. It mainly checks if the checksum is OK, if so adds it to the
6979 * SKBs cksum variable, increments the Rx packet count and passes the SKB
6980 * to the upper layer. If the checksum is wrong, it increments the Rx
6981 * packet error count, frees the SKB and returns error.
6982 * Return value:
6983 * SUCCESS on success and -1 on failure.
6984 */
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006985static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006986{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006987 struct s2io_nic *sp = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006988 struct net_device *dev = (struct net_device *) sp->dev;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006989 struct sk_buff *skb = (struct sk_buff *)
6990 ((unsigned long) rxdp->Host_Control);
6991 int ring_no = ring_data->ring_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006992 u16 l3_csum, l4_csum;
Ananda Raju863c11a2006-04-21 19:03:13 -04006993 unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05006994 struct lro *lro;
Olaf Heringf9046eb2007-06-19 22:41:10 +02006995 u8 err_mask;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006996
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006997 skb->dev = dev;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006998
Ananda Raju863c11a2006-04-21 19:03:13 -04006999 if (err) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04007000 /* Check for parity error */
7001 if (err & 0x1) {
7002 sp->mac_control.stats_info->sw_stat.parity_err_cnt++;
7003 }
Olaf Heringf9046eb2007-06-19 22:41:10 +02007004 err_mask = err >> 48;
7005 switch(err_mask) {
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04007006 case 1:
7007 sp->mac_control.stats_info->sw_stat.
7008 rx_parity_err_cnt++;
7009 break;
Ananda Rajubd1034f2006-04-21 19:20:22 -04007010
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04007011 case 2:
7012 sp->mac_control.stats_info->sw_stat.
7013 rx_abort_cnt++;
7014 break;
7015
7016 case 3:
7017 sp->mac_control.stats_info->sw_stat.
7018 rx_parity_abort_cnt++;
7019 break;
7020
7021 case 4:
7022 sp->mac_control.stats_info->sw_stat.
7023 rx_rda_fail_cnt++;
7024 break;
7025
7026 case 5:
7027 sp->mac_control.stats_info->sw_stat.
7028 rx_unkn_prot_cnt++;
7029 break;
7030
7031 case 6:
7032 sp->mac_control.stats_info->sw_stat.
7033 rx_fcs_err_cnt++;
7034 break;
7035
7036 case 7:
7037 sp->mac_control.stats_info->sw_stat.
7038 rx_buf_size_err_cnt++;
7039 break;
7040
7041 case 8:
7042 sp->mac_control.stats_info->sw_stat.
7043 rx_rxd_corrupt_cnt++;
7044 break;
7045
7046 case 15:
7047 sp->mac_control.stats_info->sw_stat.
7048 rx_unkn_err_cnt++;
7049 break;
7050 }
Ananda Raju863c11a2006-04-21 19:03:13 -04007051 /*
7052 * Drop the packet if bad transfer code. Exception being
7053 * 0x5, which could be due to unsupported IPv6 extension header.
7054 * In this case, we let stack handle the packet.
7055 * Note that in this case, since checksum will be incorrect,
7056 * stack will validate the same.
7057 */
Olaf Heringf9046eb2007-06-19 22:41:10 +02007058 if (err_mask != 0x5) {
7059 DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%x\n",
7060 dev->name, err_mask);
Ananda Raju863c11a2006-04-21 19:03:13 -04007061 sp->stats.rx_crc_errors++;
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04007062 sp->mac_control.stats_info->sw_stat.mem_freed
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04007063 += skb->truesize;
Ananda Raju863c11a2006-04-21 19:03:13 -04007064 dev_kfree_skb(skb);
7065 atomic_dec(&sp->rx_bufs_left[ring_no]);
7066 rxdp->Host_Control = 0;
7067 return 0;
7068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007069 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007070
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007071 /* Updating statistics */
Ramkrishna Vepa573608e2007-07-25 19:43:12 -07007072 sp->stats.rx_packets++;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007073 rxdp->Host_Control = 0;
Ananda Rajuda6971d2005-10-31 16:55:31 -05007074 if (sp->rxd_mode == RXD_MODE_1) {
7075 int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007076
Ananda Rajuda6971d2005-10-31 16:55:31 -05007077 sp->stats.rx_bytes += len;
7078 skb_put(skb, len);
7079
Veena Parat6d517a22007-07-23 02:20:51 -04007080 } else if (sp->rxd_mode == RXD_MODE_3B) {
Ananda Rajuda6971d2005-10-31 16:55:31 -05007081 int get_block = ring_data->rx_curr_get_info.block_index;
7082 int get_off = ring_data->rx_curr_get_info.offset;
7083 int buf0_len = RXD_GET_BUFFER0_SIZE_3(rxdp->Control_2);
7084 int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
7085 unsigned char *buff = skb_push(skb, buf0_len);
7086
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007087 struct buffAdd *ba = &ring_data->ba[get_block][get_off];
Ananda Rajuda6971d2005-10-31 16:55:31 -05007088 sp->stats.rx_bytes += buf0_len + buf2_len;
7089 memcpy(buff, ba->ba_0, buf0_len);
Veena Parat6d517a22007-07-23 02:20:51 -04007090 skb_put(skb, buf2_len);
Ananda Rajuda6971d2005-10-31 16:55:31 -05007091 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007092
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007093 if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
7094 (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007095 (sp->rx_csum)) {
7096 l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
7097 l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
7098 if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) {
7099 /*
7100 * NIC verifies if the Checksum of the received
7101 * frame is Ok or not and accordingly returns
7102 * a flag in the RxD.
7103 */
7104 skb->ip_summed = CHECKSUM_UNNECESSARY;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007105 if (sp->lro) {
7106 u32 tcp_len;
7107 u8 *tcp;
7108 int ret = 0;
7109
7110 ret = s2io_club_tcp_session(skb->data, &tcp,
7111 &tcp_len, &lro, rxdp, sp);
7112 switch (ret) {
7113 case 3: /* Begin anew */
7114 lro->parent = skb;
7115 goto aggregate;
7116 case 1: /* Aggregate */
7117 {
7118 lro_append_pkt(sp, lro,
7119 skb, tcp_len);
7120 goto aggregate;
7121 }
7122 case 4: /* Flush session */
7123 {
7124 lro_append_pkt(sp, lro,
7125 skb, tcp_len);
7126 queue_rx_frame(lro->parent);
7127 clear_lro_session(lro);
7128 sp->mac_control.stats_info->
7129 sw_stat.flush_max_pkts++;
7130 goto aggregate;
7131 }
7132 case 2: /* Flush both */
7133 lro->parent->data_len =
7134 lro->frags_len;
7135 sp->mac_control.stats_info->
7136 sw_stat.sending_both++;
7137 queue_rx_frame(lro->parent);
7138 clear_lro_session(lro);
7139 goto send_up;
7140 case 0: /* sessions exceeded */
Ananda Rajuc92ca042006-04-21 19:18:03 -04007141 case -1: /* non-TCP or not
7142 * L2 aggregatable
7143 */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007144 case 5: /*
7145 * First pkt in session not
7146 * L3/L4 aggregatable
7147 */
7148 break;
7149 default:
7150 DBG_PRINT(ERR_DBG,
7151 "%s: Samadhana!!\n",
7152 __FUNCTION__);
7153 BUG();
7154 }
7155 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007156 } else {
7157 /*
7158 * Packet with erroneous checksum, let the
7159 * upper layers deal with it.
7160 */
7161 skb->ip_summed = CHECKSUM_NONE;
7162 }
7163 } else {
7164 skb->ip_summed = CHECKSUM_NONE;
7165 }
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04007166 sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007167 if (!sp->lro) {
7168 skb->protocol = eth_type_trans(skb, dev);
Sivakumar Subramani926930b2007-02-24 01:59:39 -05007169 if ((sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2) &&
7170 vlan_strip_flag)) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007171 /* Queueing the vlan frame to the upper layer */
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007172 if (napi)
7173 vlan_hwaccel_receive_skb(skb, sp->vlgrp,
7174 RXD_GET_VLAN_TAG(rxdp->Control_2));
7175 else
7176 vlan_hwaccel_rx(skb, sp->vlgrp,
7177 RXD_GET_VLAN_TAG(rxdp->Control_2));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007178 } else {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007179 if (napi)
7180 netif_receive_skb(skb);
7181 else
7182 netif_rx(skb);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007183 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007184 } else {
7185send_up:
7186 queue_rx_frame(skb);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007187 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007188 dev->last_rx = jiffies;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007189aggregate:
Linus Torvalds1da177e2005-04-16 15:20:36 -07007190 atomic_dec(&sp->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007191 return SUCCESS;
7192}
7193
7194/**
7195 * s2io_link - stops/starts the Tx queue.
7196 * @sp : private member of the device structure, which is a pointer to the
7197 * s2io_nic structure.
7198 * @link : inidicates whether link is UP/DOWN.
7199 * Description:
7200 * This function stops/starts the Tx queue depending on whether the link
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007201 * status of the NIC is is down or up. This is called by the Alarm
7202 * interrupt handler whenever a link change interrupt comes up.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007203 * Return value:
7204 * void.
7205 */
7206
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007207static void s2io_link(struct s2io_nic * sp, int link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007208{
7209 struct net_device *dev = (struct net_device *) sp->dev;
7210
7211 if (link != sp->last_link_state) {
7212 if (link == LINK_DOWN) {
7213 DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
7214 netif_carrier_off(dev);
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04007215 if(sp->mac_control.stats_info->sw_stat.link_up_cnt)
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04007216 sp->mac_control.stats_info->sw_stat.link_up_time =
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04007217 jiffies - sp->start_time;
7218 sp->mac_control.stats_info->sw_stat.link_down_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219 } else {
7220 DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04007221 if (sp->mac_control.stats_info->sw_stat.link_down_cnt)
Sivakumar Subramani8a4bdba2007-09-18 18:14:20 -04007222 sp->mac_control.stats_info->sw_stat.link_down_time =
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04007223 jiffies - sp->start_time;
7224 sp->mac_control.stats_info->sw_stat.link_up_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007225 netif_carrier_on(dev);
7226 }
7227 }
7228 sp->last_link_state = link;
Sreenivasa Honnur491976b2007-05-10 04:22:25 -04007229 sp->start_time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007230}
7231
7232/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007233 * s2io_init_pci -Initialization of PCI and PCI-X configuration registers .
7234 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07007235 * s2io_nic structure.
7236 * Description:
7237 * This function initializes a few of the PCI and PCI-X configuration registers
7238 * with recommended values.
7239 * Return value:
7240 * void
7241 */
7242
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007243static void s2io_init_pci(struct s2io_nic * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007244{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007245 u16 pci_cmd = 0, pcix_cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007246
7247 /* Enable Data Parity Error Recovery in PCI-X command register. */
7248 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007249 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007250 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007251 (pcix_cmd | 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007252 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007253 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007254
7255 /* Set the PErr Response bit in PCI command register. */
7256 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
7257 pci_write_config_word(sp->pdev, PCI_COMMAND,
7258 (pci_cmd | PCI_COMMAND_PARITY));
7259 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007260}
7261
Ananda Raju9dc737a2006-04-21 19:05:41 -04007262static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
7263{
7264 if ( tx_fifo_num > 8) {
7265 DBG_PRINT(ERR_DBG, "s2io: Requested number of Tx fifos not "
7266 "supported\n");
7267 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Tx fifos\n");
7268 tx_fifo_num = 8;
7269 }
7270 if ( rx_ring_num > 8) {
7271 DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
7272 "supported\n");
7273 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
7274 rx_ring_num = 8;
7275 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007276 if (*dev_intr_type != INTA)
7277 napi = 0;
7278
Veena Parateccb8622007-07-23 02:23:54 -04007279 if ((*dev_intr_type != INTA) && (*dev_intr_type != MSI_X)) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04007280 DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
7281 "Defaulting to INTA\n");
7282 *dev_intr_type = INTA;
7283 }
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07007284
Ananda Raju9dc737a2006-04-21 19:05:41 -04007285 if ((*dev_intr_type == MSI_X) &&
7286 ((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
7287 (pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007288 DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. "
Ananda Raju9dc737a2006-04-21 19:05:41 -04007289 "Defaulting to INTA\n");
7290 *dev_intr_type = INTA;
7291 }
Sivakumar Subramanifb6a8252007-02-24 01:51:50 -05007292
Veena Parat6d517a22007-07-23 02:20:51 -04007293 if ((rx_ring_mode != 1) && (rx_ring_mode != 2)) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04007294 DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
Veena Parat6d517a22007-07-23 02:20:51 -04007295 DBG_PRINT(ERR_DBG, "s2io: Defaulting to 1-buffer mode\n");
7296 rx_ring_mode = 1;
Ananda Raju9dc737a2006-04-21 19:05:41 -04007297 }
7298 return SUCCESS;
7299}
7300
Linus Torvalds1da177e2005-04-16 15:20:36 -07007301/**
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05007302 * rts_ds_steer - Receive traffic steering based on IPv4 or IPv6 TOS
7303 * or Traffic class respectively.
7304 * @nic: device peivate variable
7305 * Description: The function configures the receive steering to
7306 * desired receive ring.
7307 * Return Value: SUCCESS on success and
7308 * '-1' on failure (endian settings incorrect).
7309 */
7310static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring)
7311{
7312 struct XENA_dev_config __iomem *bar0 = nic->bar0;
7313 register u64 val64 = 0;
7314
7315 if (ds_codepoint > 63)
7316 return FAILURE;
7317
7318 val64 = RTS_DS_MEM_DATA(ring);
7319 writeq(val64, &bar0->rts_ds_mem_data);
7320
7321 val64 = RTS_DS_MEM_CTRL_WE |
7322 RTS_DS_MEM_CTRL_STROBE_NEW_CMD |
7323 RTS_DS_MEM_CTRL_OFFSET(ds_codepoint);
7324
7325 writeq(val64, &bar0->rts_ds_mem_ctrl);
7326
7327 return wait_for_cmd_complete(&bar0->rts_ds_mem_ctrl,
7328 RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED,
7329 S2IO_BIT_RESET);
7330}
7331
7332/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007333 * s2io_init_nic - Initialization of the adapter .
Linus Torvalds1da177e2005-04-16 15:20:36 -07007334 * @pdev : structure containing the PCI related information of the device.
7335 * @pre: List of PCI devices supported by the driver listed in s2io_tbl.
7336 * Description:
7337 * The function initializes an adapter identified by the pci_dec structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007338 * All OS related initialization including memory and device structure and
7339 * initlaization of the device private variable is done. Also the swapper
7340 * control register is initialized to enable read and write into the I/O
Linus Torvalds1da177e2005-04-16 15:20:36 -07007341 * registers of the device.
7342 * Return value:
7343 * returns 0 on success and negative on failure.
7344 */
7345
7346static int __devinit
7347s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
7348{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007349 struct s2io_nic *sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007350 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007351 int i, j, ret;
7352 int dma_flag = FALSE;
7353 u32 mac_up, mac_down;
7354 u64 val64 = 0, tmp64 = 0;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007355 struct XENA_dev_config __iomem *bar0 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007356 u16 subid;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007357 struct mac_info *mac_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007358 struct config_param *config;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007359 int mode;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007360 u8 dev_intr_type = intr_type;
Joe Perches0795af52007-10-03 17:59:30 -07007361 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007362
Ananda Raju9dc737a2006-04-21 19:05:41 -04007363 if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
7364 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007365
7366 if ((ret = pci_enable_device(pdev))) {
7367 DBG_PRINT(ERR_DBG,
7368 "s2io_init_nic: pci_enable_device failed\n");
7369 return ret;
7370 }
7371
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04007372 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007373 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
7374 dma_flag = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007375 if (pci_set_consistent_dma_mask
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04007376 (pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007377 DBG_PRINT(ERR_DBG,
7378 "Unable to obtain 64bit DMA for \
7379 consistent allocations\n");
7380 pci_disable_device(pdev);
7381 return -ENOMEM;
7382 }
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04007383 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007384 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n");
7385 } else {
7386 pci_disable_device(pdev);
7387 return -ENOMEM;
7388 }
Veena Parateccb8622007-07-23 02:23:54 -04007389 if ((ret = pci_request_regions(pdev, s2io_driver_name))) {
7390 DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x \n", __FUNCTION__, ret);
7391 pci_disable_device(pdev);
7392 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007393 }
7394
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007395 dev = alloc_etherdev(sizeof(struct s2io_nic));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007396 if (dev == NULL) {
7397 DBG_PRINT(ERR_DBG, "Device allocation failed\n");
7398 pci_disable_device(pdev);
7399 pci_release_regions(pdev);
7400 return -ENODEV;
7401 }
7402
7403 pci_set_master(pdev);
7404 pci_set_drvdata(pdev, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007405 SET_NETDEV_DEV(dev, &pdev->dev);
7406
7407 /* Private member variable initialized to s2io NIC structure */
7408 sp = dev->priv;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007409 memset(sp, 0, sizeof(struct s2io_nic));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007410 sp->dev = dev;
7411 sp->pdev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007412 sp->high_dma_flag = dma_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007413 sp->device_enabled_once = FALSE;
Ananda Rajuda6971d2005-10-31 16:55:31 -05007414 if (rx_ring_mode == 1)
7415 sp->rxd_mode = RXD_MODE_1;
7416 if (rx_ring_mode == 2)
7417 sp->rxd_mode = RXD_MODE_3B;
Ananda Rajuda6971d2005-10-31 16:55:31 -05007418
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07007419 sp->config.intr_type = dev_intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007420
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007421 if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
7422 (pdev->device == PCI_DEVICE_ID_HERC_UNI))
7423 sp->device_type = XFRAME_II_DEVICE;
7424 else
7425 sp->device_type = XFRAME_I_DEVICE;
7426
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007427 sp->lro = lro;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007428
Linus Torvalds1da177e2005-04-16 15:20:36 -07007429 /* Initialize some PCI/PCI-X fields of the NIC. */
7430 s2io_init_pci(sp);
7431
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007432 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007433 * Setting the device configuration parameters.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007434 * Most of these parameters can be specified by the user during
7435 * module insertion as they are module loadable parameters. If
7436 * these parameters are not not specified during load time, they
Linus Torvalds1da177e2005-04-16 15:20:36 -07007437 * are initialized with default values.
7438 */
7439 mac_control = &sp->mac_control;
7440 config = &sp->config;
7441
Sivakumar Subramani596c5c92007-09-15 14:24:03 -07007442 config->napi = napi;
7443
Linus Torvalds1da177e2005-04-16 15:20:36 -07007444 /* Tx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007445 config->tx_fifo_num = tx_fifo_num;
7446 for (i = 0; i < MAX_TX_FIFOS; i++) {
7447 config->tx_cfg[i].fifo_len = tx_fifo_len[i];
7448 config->tx_cfg[i].fifo_priority = i;
7449 }
7450
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007451 /* mapping the QoS priority to the configured fifos */
7452 for (i = 0; i < MAX_TX_FIFOS; i++)
7453 config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i];
7454
Linus Torvalds1da177e2005-04-16 15:20:36 -07007455 config->tx_intr_type = TXD_INT_TYPE_UTILZ;
7456 for (i = 0; i < config->tx_fifo_num; i++) {
7457 config->tx_cfg[i].f_no_snoop =
7458 (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER);
7459 if (config->tx_cfg[i].fifo_len < 65) {
7460 config->tx_intr_type = TXD_INT_TYPE_PER_LIST;
7461 break;
7462 }
7463 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05007464 /* + 2 because one Txd for skb->data and one Txd for UFO */
7465 config->max_txds = MAX_SKB_FRAGS + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007466
7467 /* Rx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007468 config->rx_ring_num = rx_ring_num;
7469 for (i = 0; i < MAX_RX_RINGS; i++) {
7470 config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
Ananda Rajuda6971d2005-10-31 16:55:31 -05007471 (rxd_count[sp->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007472 config->rx_cfg[i].ring_priority = i;
7473 }
7474
7475 for (i = 0; i < rx_ring_num; i++) {
7476 config->rx_cfg[i].ring_org = RING_ORG_BUFF1;
7477 config->rx_cfg[i].f_no_snoop =
7478 (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER);
7479 }
7480
7481 /* Setting Mac Control parameters */
7482 mac_control->rmac_pause_time = rmac_pause_time;
7483 mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3;
7484 mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
7485
7486
7487 /* Initialize Ring buffer parameters. */
7488 for (i = 0; i < config->rx_ring_num; i++)
7489 atomic_set(&sp->rx_bufs_left[i], 0);
7490
7491 /* initialize the shared memory used by the NIC and the host */
7492 if (init_shared_mem(sp)) {
7493 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
Ananda Rajub41477f2006-07-24 19:52:49 -04007494 dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007495 ret = -ENOMEM;
7496 goto mem_alloc_failed;
7497 }
7498
7499 sp->bar0 = ioremap(pci_resource_start(pdev, 0),
7500 pci_resource_len(pdev, 0));
7501 if (!sp->bar0) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007502 DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007503 dev->name);
7504 ret = -ENOMEM;
7505 goto bar0_remap_failed;
7506 }
7507
7508 sp->bar1 = ioremap(pci_resource_start(pdev, 2),
7509 pci_resource_len(pdev, 2));
7510 if (!sp->bar1) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007511 DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007512 dev->name);
7513 ret = -ENOMEM;
7514 goto bar1_remap_failed;
7515 }
7516
7517 dev->irq = pdev->irq;
7518 dev->base_addr = (unsigned long) sp->bar0;
7519
7520 /* Initializing the BAR1 address as the start of the FIFO pointer. */
7521 for (j = 0; j < MAX_TX_FIFOS; j++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007522 mac_control->tx_FIFO_start[j] = (struct TxFIFO_element __iomem *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007523 (sp->bar1 + (j * 0x00020000));
7524 }
7525
7526 /* Driver entry points */
7527 dev->open = &s2io_open;
7528 dev->stop = &s2io_close;
7529 dev->hard_start_xmit = &s2io_xmit;
7530 dev->get_stats = &s2io_get_stats;
7531 dev->set_multicast_list = &s2io_set_multicast;
7532 dev->do_ioctl = &s2io_ioctl;
7533 dev->change_mtu = &s2io_change_mtu;
7534 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07007535 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
7536 dev->vlan_rx_register = s2io_vlan_rx_register;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007537
Linus Torvalds1da177e2005-04-16 15:20:36 -07007538 /*
7539 * will use eth_mac_addr() for dev->set_mac_address
7540 * mac address will be set every time dev->open() is called
7541 */
Stephen Hemmingerbea33482007-10-03 16:41:36 -07007542 netif_napi_add(dev, &sp->napi, s2io_poll, 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007543
Brian Haley612eff02006-06-15 14:36:36 -04007544#ifdef CONFIG_NET_POLL_CONTROLLER
7545 dev->poll_controller = s2io_netpoll;
7546#endif
7547
Linus Torvalds1da177e2005-04-16 15:20:36 -07007548 dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
7549 if (sp->high_dma_flag == TRUE)
7550 dev->features |= NETIF_F_HIGHDMA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007551 dev->features |= NETIF_F_TSO;
Herbert Xuf83ef8c2006-06-30 13:37:03 -07007552 dev->features |= NETIF_F_TSO6;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007553 if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05007554 dev->features |= NETIF_F_UFO;
7555 dev->features |= NETIF_F_HW_CSUM;
7556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007557
7558 dev->tx_timeout = &s2io_tx_watchdog;
7559 dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
David Howellsc4028952006-11-22 14:57:56 +00007560 INIT_WORK(&sp->rst_timer_task, s2io_restart_nic);
7561 INIT_WORK(&sp->set_link_task, s2io_set_link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007562
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07007563 pci_save_state(sp->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007564
7565 /* Setting swapper control on the NIC, for proper reset operation */
7566 if (s2io_set_swapper(sp)) {
7567 DBG_PRINT(ERR_DBG, "%s:swapper settings are wrong\n",
7568 dev->name);
7569 ret = -EAGAIN;
7570 goto set_swap_failed;
7571 }
7572
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007573 /* Verify if the Herc works on the slot its placed into */
7574 if (sp->device_type & XFRAME_II_DEVICE) {
7575 mode = s2io_verify_pci_mode(sp);
7576 if (mode < 0) {
7577 DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__);
7578 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
7579 ret = -EBADSLT;
7580 goto set_swap_failed;
7581 }
7582 }
7583
7584 /* Not needed for Herc */
7585 if (sp->device_type & XFRAME_I_DEVICE) {
7586 /*
7587 * Fix for all "FFs" MAC address problems observed on
7588 * Alpha platforms
7589 */
7590 fix_mac_address(sp);
7591 s2io_reset(sp);
7592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007593
7594 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007595 * MAC address initialization.
7596 * For now only one mac address will be read and used.
7597 */
7598 bar0 = sp->bar0;
7599 val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
7600 RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
7601 writeq(val64, &bar0->rmac_addr_cmd_mem);
Ananda Rajuc92ca042006-04-21 19:18:03 -04007602 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
Sivakumar Subramani9fc93a42007-02-24 01:57:32 -05007603 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007604 tmp64 = readq(&bar0->rmac_addr_data0_mem);
7605 mac_down = (u32) tmp64;
7606 mac_up = (u32) (tmp64 >> 32);
7607
Linus Torvalds1da177e2005-04-16 15:20:36 -07007608 sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up);
7609 sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8);
7610 sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16);
7611 sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_up >> 24);
7612 sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16);
7613 sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24);
7614
Linus Torvalds1da177e2005-04-16 15:20:36 -07007615 /* Set the factory defined MAC address initially */
7616 dev->addr_len = ETH_ALEN;
7617 memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
7618
Sivakumar Subramanic77dd432007-08-06 05:36:28 -04007619 /* Store the values of the MSIX table in the s2io_nic structure */
7620 store_xmsi_data(sp);
Ananda Rajub41477f2006-07-24 19:52:49 -04007621 /* reset Nic and bring it to known state */
7622 s2io_reset(sp);
7623
Linus Torvalds1da177e2005-04-16 15:20:36 -07007624 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007625 * Initialize the tasklet status and link state flags
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007626 * and the card state parameter
Linus Torvalds1da177e2005-04-16 15:20:36 -07007627 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007628 sp->tasklet_status = 0;
Sivakumar Subramani92b84432007-09-06 06:51:14 -04007629 sp->state = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007630
Linus Torvalds1da177e2005-04-16 15:20:36 -07007631 /* Initialize spinlocks */
7632 spin_lock_init(&sp->tx_lock);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007633
7634 if (!napi)
7635 spin_lock_init(&sp->put_lock);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007636 spin_lock_init(&sp->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007637
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007638 /*
7639 * SXE-002: Configure link and activity LED to init state
7640 * on driver load.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007641 */
7642 subid = sp->pdev->subsystem_device;
7643 if ((subid & 0xFF) >= 0x07) {
7644 val64 = readq(&bar0->gpio_control);
7645 val64 |= 0x0000800000000000ULL;
7646 writeq(val64, &bar0->gpio_control);
7647 val64 = 0x0411040400000000ULL;
7648 writeq(val64, (void __iomem *) bar0 + 0x2700);
7649 val64 = readq(&bar0->gpio_control);
7650 }
7651
7652 sp->rx_csum = 1; /* Rx chksum verify enabled by default */
7653
7654 if (register_netdev(dev)) {
7655 DBG_PRINT(ERR_DBG, "Device registration failed\n");
7656 ret = -ENODEV;
7657 goto register_failed;
7658 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04007659 s2io_vpd_read(sp);
Ramkrishna Vepa0c61ed52007-03-09 18:28:32 -08007660 DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n");
Ananda Rajub41477f2006-07-24 19:52:49 -04007661 DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name,
Auke Kok44c10132007-06-08 15:46:36 -07007662 sp->product_name, pdev->revision);
Ananda Rajub41477f2006-07-24 19:52:49 -04007663 DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
7664 s2io_driver_version);
Joe Perches0795af52007-10-03 17:59:30 -07007665 DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %s\n",
7666 dev->name, print_mac(mac, dev->dev_addr));
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007667 DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007668 if (sp->device_type & XFRAME_II_DEVICE) {
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07007669 mode = s2io_print_pci_mode(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007670 if (mode < 0) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04007671 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007672 ret = -EBADSLT;
Ananda Raju9dc737a2006-04-21 19:05:41 -04007673 unregister_netdev(dev);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007674 goto set_swap_failed;
7675 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007676 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04007677 switch(sp->rxd_mode) {
7678 case RXD_MODE_1:
7679 DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n",
7680 dev->name);
7681 break;
7682 case RXD_MODE_3B:
7683 DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n",
7684 dev->name);
7685 break;
Ananda Raju9dc737a2006-04-21 19:05:41 -04007686 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007687
7688 if (napi)
7689 DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
Sivakumar Subramanieaae7f72007-09-15 14:14:22 -07007690 switch(sp->config.intr_type) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04007691 case INTA:
7692 DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
7693 break;
Ananda Raju9dc737a2006-04-21 19:05:41 -04007694 case MSI_X:
7695 DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
7696 break;
7697 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007698 if (sp->lro)
7699 DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
Ananda Raju9dc737a2006-04-21 19:05:41 -04007700 dev->name);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007701 if (ufo)
7702 DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)"
7703 " enabled\n", dev->name);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007704 /* Initialize device name */
Ananda Raju9dc737a2006-04-21 19:05:41 -04007705 sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007706
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007707 /*
7708 * Make Link state as off at this point, when the Link change
7709 * interrupt comes the state will be automatically changed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07007710 * the right state.
7711 */
7712 netif_carrier_off(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007713
7714 return 0;
7715
7716 register_failed:
7717 set_swap_failed:
7718 iounmap(sp->bar1);
7719 bar1_remap_failed:
7720 iounmap(sp->bar0);
7721 bar0_remap_failed:
7722 mem_alloc_failed:
7723 free_shared_mem(sp);
7724 pci_disable_device(pdev);
Veena Parateccb8622007-07-23 02:23:54 -04007725 pci_release_regions(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007726 pci_set_drvdata(pdev, NULL);
7727 free_netdev(dev);
7728
7729 return ret;
7730}
7731
7732/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007733 * s2io_rem_nic - Free the PCI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07007734 * @pdev: structure containing the PCI related information of the device.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007735 * Description: This function is called by the Pci subsystem to release a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007736 * PCI device and free up all resource held up by the device. This could
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007737 * be in response to a Hot plug event or when the driver is to be removed
Linus Torvalds1da177e2005-04-16 15:20:36 -07007738 * from memory.
7739 */
7740
7741static void __devexit s2io_rem_nic(struct pci_dev *pdev)
7742{
7743 struct net_device *dev =
7744 (struct net_device *) pci_get_drvdata(pdev);
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007745 struct s2io_nic *sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007746
7747 if (dev == NULL) {
7748 DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
7749 return;
7750 }
7751
Francois Romieu22747d62007-02-15 23:37:50 +01007752 flush_scheduled_work();
7753
Linus Torvalds1da177e2005-04-16 15:20:36 -07007754 sp = dev->priv;
7755 unregister_netdev(dev);
7756
7757 free_shared_mem(sp);
7758 iounmap(sp->bar0);
7759 iounmap(sp->bar1);
Veena Parateccb8622007-07-23 02:23:54 -04007760 pci_release_regions(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007761 pci_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007762 free_netdev(dev);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007763 pci_disable_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007764}
7765
7766/**
7767 * s2io_starter - Entry point for the driver
7768 * Description: This function is the entry point for the driver. It verifies
7769 * the module loadable parameters and initializes PCI configuration space.
7770 */
7771
7772int __init s2io_starter(void)
7773{
Jeff Garzik29917622006-08-19 17:48:59 -04007774 return pci_register_driver(&s2io_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007775}
7776
7777/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007778 * s2io_closer - Cleanup routine for the driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07007779 * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
7780 */
7781
Sivakumar Subramani372cc592007-01-31 13:32:57 -05007782static __exit void s2io_closer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007783{
7784 pci_unregister_driver(&s2io_driver);
7785 DBG_PRINT(INIT_DBG, "cleanup done\n");
7786}
7787
7788module_init(s2io_starter);
7789module_exit(s2io_closer);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007790
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007791static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007792 struct tcphdr **tcp, struct RxD_t *rxdp)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007793{
7794 int ip_off;
7795 u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
7796
7797 if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) {
7798 DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n",
7799 __FUNCTION__);
7800 return -1;
7801 }
7802
7803 /* TODO:
7804 * By default the VLAN field in the MAC is stripped by the card, if this
7805 * feature is turned off in rx_pa_cfg register, then the ip_off field
7806 * has to be shifted by a further 2 bytes
7807 */
7808 switch (l2_type) {
7809 case 0: /* DIX type */
7810 case 4: /* DIX type with VLAN */
7811 ip_off = HEADER_ETHERNET_II_802_3_SIZE;
7812 break;
7813 /* LLC, SNAP etc are considered non-mergeable */
7814 default:
7815 return -1;
7816 }
7817
7818 *ip = (struct iphdr *)((u8 *)buffer + ip_off);
7819 ip_len = (u8)((*ip)->ihl);
7820 ip_len <<= 2;
7821 *tcp = (struct tcphdr *)((unsigned long)*ip + ip_len);
7822
7823 return 0;
7824}
7825
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007826static int check_for_socket_match(struct lro *lro, struct iphdr *ip,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007827 struct tcphdr *tcp)
7828{
7829 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7830 if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) ||
7831 (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest))
7832 return -1;
7833 return 0;
7834}
7835
7836static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
7837{
7838 return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
7839}
7840
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007841static void initiate_new_session(struct lro *lro, u8 *l2h,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007842 struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
7843{
7844 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7845 lro->l2h = l2h;
7846 lro->iph = ip;
7847 lro->tcph = tcp;
7848 lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq);
7849 lro->tcp_ack = ntohl(tcp->ack_seq);
7850 lro->sg_num = 1;
7851 lro->total_len = ntohs(ip->tot_len);
7852 lro->frags_len = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007853 /*
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007854 * check if we saw TCP timestamp. Other consistency checks have
7855 * already been done.
7856 */
7857 if (tcp->doff == 8) {
7858 u32 *ptr;
7859 ptr = (u32 *)(tcp+1);
7860 lro->saw_ts = 1;
7861 lro->cur_tsval = *(ptr+1);
7862 lro->cur_tsecr = *(ptr+2);
7863 }
7864 lro->in_use = 1;
7865}
7866
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007867static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007868{
7869 struct iphdr *ip = lro->iph;
7870 struct tcphdr *tcp = lro->tcph;
Al Virobd4f3ae2007-02-09 16:40:15 +00007871 __sum16 nchk;
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007872 struct stat_block *statinfo = sp->mac_control.stats_info;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007873 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7874
7875 /* Update L3 header */
7876 ip->tot_len = htons(lro->total_len);
7877 ip->check = 0;
7878 nchk = ip_fast_csum((u8 *)lro->iph, ip->ihl);
7879 ip->check = nchk;
7880
7881 /* Update L4 header */
7882 tcp->ack_seq = lro->tcp_ack;
7883 tcp->window = lro->window;
7884
7885 /* Update tsecr field if this session has timestamps enabled */
7886 if (lro->saw_ts) {
7887 u32 *ptr = (u32 *)(tcp + 1);
7888 *(ptr+2) = lro->cur_tsecr;
7889 }
7890
7891 /* Update counters required for calculation of
7892 * average no. of packets aggregated.
7893 */
7894 statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num;
7895 statinfo->sw_stat.num_aggregations++;
7896}
7897
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007898static void aggregate_new_rx(struct lro *lro, struct iphdr *ip,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007899 struct tcphdr *tcp, u32 l4_pyld)
7900{
7901 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7902 lro->total_len += l4_pyld;
7903 lro->frags_len += l4_pyld;
7904 lro->tcp_next_seq += l4_pyld;
7905 lro->sg_num++;
7906
7907 /* Update ack seq no. and window ad(from this pkt) in LRO object */
7908 lro->tcp_ack = tcp->ack_seq;
7909 lro->window = tcp->window;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007910
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007911 if (lro->saw_ts) {
7912 u32 *ptr;
7913 /* Update tsecr and tsval from this packet */
7914 ptr = (u32 *) (tcp + 1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007915 lro->cur_tsval = *(ptr + 1);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007916 lro->cur_tsecr = *(ptr + 2);
7917 }
7918}
7919
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007920static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007921 struct tcphdr *tcp, u32 tcp_pyld_len)
7922{
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007923 u8 *ptr;
7924
Andrew Morton79dc1902006-02-03 01:45:13 -08007925 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7926
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007927 if (!tcp_pyld_len) {
7928 /* Runt frame or a pure ack */
7929 return -1;
7930 }
7931
7932 if (ip->ihl != 5) /* IP has options */
7933 return -1;
7934
Ananda Raju75c30b12006-07-24 19:55:09 -04007935 /* If we see CE codepoint in IP header, packet is not mergeable */
7936 if (INET_ECN_is_ce(ipv4_get_dsfield(ip)))
7937 return -1;
7938
7939 /* If we see ECE or CWR flags in TCP header, packet is not mergeable */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007940 if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin ||
Ananda Raju75c30b12006-07-24 19:55:09 -04007941 tcp->ece || tcp->cwr || !tcp->ack) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007942 /*
7943 * Currently recognize only the ack control word and
7944 * any other control field being set would result in
7945 * flushing the LRO session
7946 */
7947 return -1;
7948 }
7949
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007950 /*
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007951 * Allow only one TCP timestamp option. Don't aggregate if
7952 * any other options are detected.
7953 */
7954 if (tcp->doff != 5 && tcp->doff != 8)
7955 return -1;
7956
7957 if (tcp->doff == 8) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007958 ptr = (u8 *)(tcp + 1);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007959 while (*ptr == TCPOPT_NOP)
7960 ptr++;
7961 if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP)
7962 return -1;
7963
7964 /* Ensure timestamp value increases monotonically */
7965 if (l_lro)
7966 if (l_lro->cur_tsval > *((u32 *)(ptr+2)))
7967 return -1;
7968
7969 /* timestamp echo reply should be non-zero */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007970 if (*((u32 *)(ptr+6)) == 0)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007971 return -1;
7972 }
7973
7974 return 0;
7975}
7976
7977static int
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007978s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
7979 struct RxD_t *rxdp, struct s2io_nic *sp)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007980{
7981 struct iphdr *ip;
7982 struct tcphdr *tcph;
7983 int ret = 0, i;
7984
7985 if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp,
7986 rxdp))) {
7987 DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n",
7988 ip->saddr, ip->daddr);
7989 } else {
7990 return ret;
7991 }
7992
7993 tcph = (struct tcphdr *)*tcp;
7994 *tcp_len = get_l4_pyld_length(ip, tcph);
7995 for (i=0; i<MAX_LRO_SESSIONS; i++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05007996 struct lro *l_lro = &sp->lro0_n[i];
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007997 if (l_lro->in_use) {
7998 if (check_for_socket_match(l_lro, ip, tcph))
7999 continue;
8000 /* Sock pair matched */
8001 *lro = l_lro;
8002
8003 if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) {
8004 DBG_PRINT(INFO_DBG, "%s:Out of order. expected "
8005 "0x%x, actual 0x%x\n", __FUNCTION__,
8006 (*lro)->tcp_next_seq,
8007 ntohl(tcph->seq));
8008
8009 sp->mac_control.stats_info->
8010 sw_stat.outof_sequence_pkts++;
8011 ret = 2;
8012 break;
8013 }
8014
8015 if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len))
8016 ret = 1; /* Aggregate */
8017 else
8018 ret = 2; /* Flush both */
8019 break;
8020 }
8021 }
8022
8023 if (ret == 0) {
8024 /* Before searching for available LRO objects,
8025 * check if the pkt is L3/L4 aggregatable. If not
8026 * don't create new LRO session. Just send this
8027 * packet up.
8028 */
8029 if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) {
8030 return 5;
8031 }
8032
8033 for (i=0; i<MAX_LRO_SESSIONS; i++) {
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05008034 struct lro *l_lro = &sp->lro0_n[i];
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05008035 if (!(l_lro->in_use)) {
8036 *lro = l_lro;
8037 ret = 3; /* Begin anew */
8038 break;
8039 }
8040 }
8041 }
8042
8043 if (ret == 0) { /* sessions exceeded */
8044 DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n",
8045 __FUNCTION__);
8046 *lro = NULL;
8047 return ret;
8048 }
8049
8050 switch (ret) {
8051 case 3:
8052 initiate_new_session(*lro, buffer, ip, tcph, *tcp_len);
8053 break;
8054 case 2:
8055 update_L3L4_header(sp, *lro);
8056 break;
8057 case 1:
8058 aggregate_new_rx(*lro, ip, tcph, *tcp_len);
8059 if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) {
8060 update_L3L4_header(sp, *lro);
8061 ret = 4; /* Flush the LRO */
8062 }
8063 break;
8064 default:
8065 DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n",
8066 __FUNCTION__);
8067 break;
8068 }
8069
8070 return ret;
8071}
8072
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05008073static void clear_lro_session(struct lro *lro)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05008074{
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05008075 static u16 lro_struct_size = sizeof(struct lro);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05008076
8077 memset(lro, 0, lro_struct_size);
8078}
8079
8080static void queue_rx_frame(struct sk_buff *skb)
8081{
8082 struct net_device *dev = skb->dev;
8083
8084 skb->protocol = eth_type_trans(skb, dev);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05008085 if (napi)
8086 netif_receive_skb(skb);
8087 else
8088 netif_rx(skb);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05008089}
8090
Ralf Baechle1ee6dd72007-01-31 14:09:29 -05008091static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
8092 struct sk_buff *skb,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05008093 u32 tcp_len)
8094{
Ananda Raju75c30b12006-07-24 19:55:09 -04008095 struct sk_buff *first = lro->parent;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05008096
8097 first->len += tcp_len;
8098 first->data_len = lro->frags_len;
8099 skb_pull(skb, (skb->len - tcp_len));
Ananda Raju75c30b12006-07-24 19:55:09 -04008100 if (skb_shinfo(first)->frag_list)
8101 lro->last_frag->next = skb;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05008102 else
8103 skb_shinfo(first)->frag_list = skb;
Sivakumar Subramani372cc592007-01-31 13:32:57 -05008104 first->truesize += skb->truesize;
Ananda Raju75c30b12006-07-24 19:55:09 -04008105 lro->last_frag = skb;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05008106 sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
8107 return;
8108}
Linas Vepstasd796fdb2007-05-14 18:37:30 -05008109
8110/**
8111 * s2io_io_error_detected - called when PCI error is detected
8112 * @pdev: Pointer to PCI device
Rolf Eike Beer8453d432007-07-10 11:58:02 +02008113 * @state: The current pci connection state
Linas Vepstasd796fdb2007-05-14 18:37:30 -05008114 *
8115 * This function is called after a PCI bus error affecting
8116 * this device has been detected.
8117 */
8118static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev,
8119 pci_channel_state_t state)
8120{
8121 struct net_device *netdev = pci_get_drvdata(pdev);
8122 struct s2io_nic *sp = netdev->priv;
8123
8124 netif_device_detach(netdev);
8125
8126 if (netif_running(netdev)) {
8127 /* Bring down the card, while avoiding PCI I/O */
8128 do_s2io_card_down(sp, 0);
Linas Vepstasd796fdb2007-05-14 18:37:30 -05008129 }
8130 pci_disable_device(pdev);
8131
8132 return PCI_ERS_RESULT_NEED_RESET;
8133}
8134
8135/**
8136 * s2io_io_slot_reset - called after the pci bus has been reset.
8137 * @pdev: Pointer to PCI device
8138 *
8139 * Restart the card from scratch, as if from a cold-boot.
8140 * At this point, the card has exprienced a hard reset,
8141 * followed by fixups by BIOS, and has its config space
8142 * set up identically to what it was at cold boot.
8143 */
8144static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev)
8145{
8146 struct net_device *netdev = pci_get_drvdata(pdev);
8147 struct s2io_nic *sp = netdev->priv;
8148
8149 if (pci_enable_device(pdev)) {
8150 printk(KERN_ERR "s2io: "
8151 "Cannot re-enable PCI device after reset.\n");
8152 return PCI_ERS_RESULT_DISCONNECT;
8153 }
8154
8155 pci_set_master(pdev);
8156 s2io_reset(sp);
8157
8158 return PCI_ERS_RESULT_RECOVERED;
8159}
8160
8161/**
8162 * s2io_io_resume - called when traffic can start flowing again.
8163 * @pdev: Pointer to PCI device
8164 *
8165 * This callback is called when the error recovery driver tells
8166 * us that its OK to resume normal operation.
8167 */
8168static void s2io_io_resume(struct pci_dev *pdev)
8169{
8170 struct net_device *netdev = pci_get_drvdata(pdev);
8171 struct s2io_nic *sp = netdev->priv;
8172
8173 if (netif_running(netdev)) {
8174 if (s2io_card_up(sp)) {
8175 printk(KERN_ERR "s2io: "
8176 "Can't bring device back up after reset.\n");
8177 return;
8178 }
8179
8180 if (s2io_set_mac_addr(netdev, netdev->dev_addr) == FAILURE) {
8181 s2io_card_down(sp);
8182 printk(KERN_ERR "s2io: "
8183 "Can't resetore mac addr after reset.\n");
8184 return;
8185 }
8186 }
8187
8188 netif_device_attach(netdev);
8189 netif_wake_queue(netdev);
8190}