blob: 9b9b28e85a7d272dbd690c0744a158bbb05976f0 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/************************************************************************
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002 * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Copyright(c) 2002-2005 Neterion Inc.
4
5 * This software may be used and distributed according to the terms of
6 * the GNU General Public License (GPL), incorporated herein by reference.
7 * Drivers based on or derived from this code fall under the GPL and must
8 * retain the authorship, copyright and license notice. This file is not
9 * a complete program and may only be used when the entire operating
10 * system is licensed under the GPL.
11 * See the file COPYING in this distribution for more information.
12 *
13 * Credits:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070014 * Jeff Garzik : For pointing out the improper error condition
15 * check in the s2io_xmit routine and also some
16 * issues in the Tx watch dog function. Also for
17 * patiently answering all those innumerable
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 * questions regaring the 2.6 porting issues.
19 * Stephen Hemminger : Providing proper 2.6 porting mechanism for some
20 * macros available only in 2.6 Kernel.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070021 * Francois Romieu : For pointing out all code part that were
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 * deprecated and also styling related comments.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070023 * Grant Grundler : For helping me get rid of some Architecture
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 * dependent code.
25 * Christopher Hellwig : Some more 2.6 specific issues in the driver.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070026 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 * The module loadable parameters that are supported by the driver and a brief
28 * explaination of all the variables.
Ananda Raju9dc737a2006-04-21 19:05:41 -040029 *
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070030 * rx_ring_num : This can be used to program the number of receive rings used
31 * in the driver.
Ananda Raju9dc737a2006-04-21 19:05:41 -040032 * rx_ring_sz: This defines the number of receive blocks each ring can have.
33 * This is also an array of size 8.
Ananda Rajuda6971d2005-10-31 16:55:31 -050034 * rx_ring_mode: This defines the operation mode of all 8 rings. The valid
35 * values are 1, 2 and 3.
Linus Torvalds1da177e2005-04-16 15:20:36 -070036 * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070037 * tx_fifo_len: This too is an array of 8. Each element defines the number of
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 * Tx descriptors that can be associated with each corresponding FIFO.
Ananda Raju9dc737a2006-04-21 19:05:41 -040039 * intr_type: This defines the type of interrupt. The values can be 0(INTA),
40 * 1(MSI), 2(MSI_X). Default value is '0(INTA)'
41 * lro: Specifies whether to enable Large Receive Offload (LRO) or not.
42 * Possible values '1' for enable '0' for disable. Default is '0'
43 * lro_max_pkts: This parameter defines maximum number of packets can be
44 * aggregated as a single large packet
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 ************************************************************************/
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/module.h>
48#include <linux/types.h>
49#include <linux/errno.h>
50#include <linux/ioport.h>
51#include <linux/pci.h>
Domen Puncer1e7f0bd2005-06-26 18:22:14 -040052#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <linux/kernel.h>
54#include <linux/netdevice.h>
55#include <linux/etherdevice.h>
56#include <linux/skbuff.h>
57#include <linux/init.h>
58#include <linux/delay.h>
59#include <linux/stddef.h>
60#include <linux/ioctl.h>
61#include <linux/timex.h>
62#include <linux/sched.h>
63#include <linux/ethtool.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include <linux/workqueue.h>
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -070065#include <linux/if_vlan.h>
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -050066#include <linux/ip.h>
67#include <linux/tcp.h>
68#include <net/tcp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#include <asm/system.h>
71#include <asm/uaccess.h>
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070072#include <asm/io.h>
Andrew Mortonfe931392006-02-03 01:45:12 -080073#include <asm/div64.h>
Andrew Morton330ce0d2006-08-14 23:00:14 -070074#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
76/* local include */
77#include "s2io.h"
78#include "s2io-regs.h"
79
Ananda Raju75c30b12006-07-24 19:55:09 -040080#define DRV_VERSION "2.0.15.2"
John Linville6c1792f2005-10-04 07:51:45 -040081
Linus Torvalds1da177e2005-04-16 15:20:36 -070082/* S2io Driver name & version. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070083static char s2io_driver_name[] = "Neterion";
John Linville6c1792f2005-10-04 07:51:45 -040084static char s2io_driver_version[] = DRV_VERSION;
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
Adrian Bunk26df54b2006-01-14 03:09:40 +010086static int rxd_size[4] = {32,48,48,64};
87static int rxd_count[4] = {127,85,85,63};
Ananda Rajuda6971d2005-10-31 16:55:31 -050088
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -070089static inline int RXD_IS_UP2DT(RxD_t *rxdp)
90{
91 int ret;
92
93 ret = ((!(rxdp->Control_1 & RXD_OWN_XENA)) &&
94 (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK));
95
96 return ret;
97}
98
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070099/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 * Cards with following subsystem_id have a link state indication
101 * problem, 600B, 600C, 600D, 640B, 640C and 640D.
102 * macro below identifies these cards given the subsystem_id.
103 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700104#define CARDS_WITH_FAULTY_LINK_INDICATORS(dev_type, subid) \
105 (dev_type == XFRAME_I_DEVICE) ? \
106 ((((subid >= 0x600B) && (subid <= 0x600D)) || \
107 ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0) : 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
109#define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \
110 ADAPTER_STATUS_RMAC_LOCAL_FAULT)))
111#define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status))
112#define PANIC 1
113#define LOW 2
114static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring)
115{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700116 mac_info_t *mac_control;
117
118 mac_control = &sp->mac_control;
Ananda Raju863c11a2006-04-21 19:03:13 -0400119 if (rxb_size <= rxd_count[sp->rxd_mode])
120 return PANIC;
121 else if ((mac_control->rings[ring].pkt_cnt - rxb_size) > 16)
122 return LOW;
123 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124}
125
126/* Ethtool related variables and Macros. */
127static char s2io_gstrings[][ETH_GSTRING_LEN] = {
128 "Register test\t(offline)",
129 "Eeprom test\t(offline)",
130 "Link test\t(online)",
131 "RLDRAM test\t(offline)",
132 "BIST Test\t(offline)"
133};
134
135static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
136 {"tmac_frms"},
137 {"tmac_data_octets"},
138 {"tmac_drop_frms"},
139 {"tmac_mcst_frms"},
140 {"tmac_bcst_frms"},
141 {"tmac_pause_ctrl_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400142 {"tmac_ttl_octets"},
143 {"tmac_ucst_frms"},
144 {"tmac_nucst_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 {"tmac_any_err_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400146 {"tmac_ttl_less_fb_octets"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 {"tmac_vld_ip_octets"},
148 {"tmac_vld_ip"},
149 {"tmac_drop_ip"},
150 {"tmac_icmp"},
151 {"tmac_rst_tcp"},
152 {"tmac_tcp"},
153 {"tmac_udp"},
154 {"rmac_vld_frms"},
155 {"rmac_data_octets"},
156 {"rmac_fcs_err_frms"},
157 {"rmac_drop_frms"},
158 {"rmac_vld_mcst_frms"},
159 {"rmac_vld_bcst_frms"},
160 {"rmac_in_rng_len_err_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400161 {"rmac_out_rng_len_err_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 {"rmac_long_frms"},
163 {"rmac_pause_ctrl_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400164 {"rmac_unsup_ctrl_frms"},
165 {"rmac_ttl_octets"},
166 {"rmac_accepted_ucst_frms"},
167 {"rmac_accepted_nucst_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 {"rmac_discarded_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400169 {"rmac_drop_events"},
170 {"rmac_ttl_less_fb_octets"},
171 {"rmac_ttl_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 {"rmac_usized_frms"},
173 {"rmac_osized_frms"},
174 {"rmac_frag_frms"},
175 {"rmac_jabber_frms"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400176 {"rmac_ttl_64_frms"},
177 {"rmac_ttl_65_127_frms"},
178 {"rmac_ttl_128_255_frms"},
179 {"rmac_ttl_256_511_frms"},
180 {"rmac_ttl_512_1023_frms"},
181 {"rmac_ttl_1024_1518_frms"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 {"rmac_ip"},
183 {"rmac_ip_octets"},
184 {"rmac_hdr_err_ip"},
185 {"rmac_drop_ip"},
186 {"rmac_icmp"},
187 {"rmac_tcp"},
188 {"rmac_udp"},
189 {"rmac_err_drp_udp"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400190 {"rmac_xgmii_err_sym"},
191 {"rmac_frms_q0"},
192 {"rmac_frms_q1"},
193 {"rmac_frms_q2"},
194 {"rmac_frms_q3"},
195 {"rmac_frms_q4"},
196 {"rmac_frms_q5"},
197 {"rmac_frms_q6"},
198 {"rmac_frms_q7"},
199 {"rmac_full_q0"},
200 {"rmac_full_q1"},
201 {"rmac_full_q2"},
202 {"rmac_full_q3"},
203 {"rmac_full_q4"},
204 {"rmac_full_q5"},
205 {"rmac_full_q6"},
206 {"rmac_full_q7"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 {"rmac_pause_cnt"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400208 {"rmac_xgmii_data_err_cnt"},
209 {"rmac_xgmii_ctrl_err_cnt"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 {"rmac_accepted_ip"},
211 {"rmac_err_tcp"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400212 {"rd_req_cnt"},
213 {"new_rd_req_cnt"},
214 {"new_rd_req_rtry_cnt"},
215 {"rd_rtry_cnt"},
216 {"wr_rtry_rd_ack_cnt"},
217 {"wr_req_cnt"},
218 {"new_wr_req_cnt"},
219 {"new_wr_req_rtry_cnt"},
220 {"wr_rtry_cnt"},
221 {"wr_disc_cnt"},
222 {"rd_rtry_wr_ack_cnt"},
223 {"txp_wr_cnt"},
224 {"txd_rd_cnt"},
225 {"txd_wr_cnt"},
226 {"rxd_rd_cnt"},
227 {"rxd_wr_cnt"},
228 {"txf_rd_cnt"},
229 {"rxf_wr_cnt"},
230 {"rmac_ttl_1519_4095_frms"},
231 {"rmac_ttl_4096_8191_frms"},
232 {"rmac_ttl_8192_max_frms"},
233 {"rmac_ttl_gt_max_frms"},
234 {"rmac_osized_alt_frms"},
235 {"rmac_jabber_alt_frms"},
236 {"rmac_gt_max_alt_frms"},
237 {"rmac_vlan_frms"},
238 {"rmac_len_discard"},
239 {"rmac_fcs_discard"},
240 {"rmac_pf_discard"},
241 {"rmac_da_discard"},
242 {"rmac_red_discard"},
243 {"rmac_rts_discard"},
244 {"rmac_ingm_full_discard"},
245 {"link_fault_cnt"},
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -0700246 {"\n DRIVER STATISTICS"},
247 {"single_bit_ecc_errs"},
248 {"double_bit_ecc_errs"},
Ananda Rajubd1034f2006-04-21 19:20:22 -0400249 {"parity_err_cnt"},
250 {"serious_err_cnt"},
251 {"soft_reset_cnt"},
252 {"fifo_full_cnt"},
253 {"ring_full_cnt"},
254 ("alarm_transceiver_temp_high"),
255 ("alarm_transceiver_temp_low"),
256 ("alarm_laser_bias_current_high"),
257 ("alarm_laser_bias_current_low"),
258 ("alarm_laser_output_power_high"),
259 ("alarm_laser_output_power_low"),
260 ("warn_transceiver_temp_high"),
261 ("warn_transceiver_temp_low"),
262 ("warn_laser_bias_current_high"),
263 ("warn_laser_bias_current_low"),
264 ("warn_laser_output_power_high"),
265 ("warn_laser_output_power_low"),
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -0500266 ("lro_aggregated_pkts"),
267 ("lro_flush_both_count"),
268 ("lro_out_of_sequence_pkts"),
269 ("lro_flush_due_to_max_pkts"),
270 ("lro_avg_aggr_pkts"),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271};
272
273#define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN
274#define S2IO_STAT_STRINGS_LEN S2IO_STAT_LEN * ETH_GSTRING_LEN
275
276#define S2IO_TEST_LEN sizeof(s2io_gstrings) / ETH_GSTRING_LEN
277#define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN
278
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -0700279#define S2IO_TIMER_CONF(timer, handle, arg, exp) \
280 init_timer(&timer); \
281 timer.function = handle; \
282 timer.data = (unsigned long) arg; \
283 mod_timer(&timer, (jiffies + exp)) \
284
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -0700285/* Add the vlan */
286static void s2io_vlan_rx_register(struct net_device *dev,
287 struct vlan_group *grp)
288{
289 nic_t *nic = dev->priv;
290 unsigned long flags;
291
292 spin_lock_irqsave(&nic->tx_lock, flags);
293 nic->vlgrp = grp;
294 spin_unlock_irqrestore(&nic->tx_lock, flags);
295}
296
297/* Unregister the vlan */
298static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
299{
300 nic_t *nic = dev->priv;
301 unsigned long flags;
302
303 spin_lock_irqsave(&nic->tx_lock, flags);
304 if (nic->vlgrp)
305 nic->vlgrp->vlan_devices[vid] = NULL;
306 spin_unlock_irqrestore(&nic->tx_lock, flags);
307}
308
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700309/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 * Constants to be programmed into the Xena's registers, to configure
311 * the XAUI.
312 */
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314#define END_SIGN 0x0
Arjan van de Venf71e1302006-03-03 21:33:57 -0500315static const u64 herc_act_dtx_cfg[] = {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700316 /* Set address */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700317 0x8000051536750000ULL, 0x80000515367500E0ULL,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700318 /* Write data */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700319 0x8000051536750004ULL, 0x80000515367500E4ULL,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700320 /* Set address */
321 0x80010515003F0000ULL, 0x80010515003F00E0ULL,
322 /* Write data */
323 0x80010515003F0004ULL, 0x80010515003F00E4ULL,
324 /* Set address */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -0700325 0x801205150D440000ULL, 0x801205150D4400E0ULL,
326 /* Write data */
327 0x801205150D440004ULL, 0x801205150D4400E4ULL,
328 /* Set address */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700329 0x80020515F2100000ULL, 0x80020515F21000E0ULL,
330 /* Write data */
331 0x80020515F2100004ULL, 0x80020515F21000E4ULL,
332 /* Done */
333 END_SIGN
334};
335
Arjan van de Venf71e1302006-03-03 21:33:57 -0500336static const u64 xena_dtx_cfg[] = {
Ananda Rajuc92ca042006-04-21 19:18:03 -0400337 /* Set address */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 0x8000051500000000ULL, 0x80000515000000E0ULL,
Ananda Rajuc92ca042006-04-21 19:18:03 -0400339 /* Write data */
340 0x80000515D9350004ULL, 0x80000515D93500E4ULL,
341 /* Set address */
342 0x8001051500000000ULL, 0x80010515000000E0ULL,
343 /* Write data */
344 0x80010515001E0004ULL, 0x80010515001E00E4ULL,
345 /* Set address */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 0x8002051500000000ULL, 0x80020515000000E0ULL,
Ananda Rajuc92ca042006-04-21 19:18:03 -0400347 /* Write data */
348 0x80020515F2100004ULL, 0x80020515F21000E4ULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 END_SIGN
350};
351
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700352/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 * Constants for Fixing the MacAddress problem seen mostly on
354 * Alpha machines.
355 */
Arjan van de Venf71e1302006-03-03 21:33:57 -0500356static const u64 fix_mac[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 0x0060000000000000ULL, 0x0060600000000000ULL,
358 0x0040600000000000ULL, 0x0000600000000000ULL,
359 0x0020600000000000ULL, 0x0060600000000000ULL,
360 0x0020600000000000ULL, 0x0060600000000000ULL,
361 0x0020600000000000ULL, 0x0060600000000000ULL,
362 0x0020600000000000ULL, 0x0060600000000000ULL,
363 0x0020600000000000ULL, 0x0060600000000000ULL,
364 0x0020600000000000ULL, 0x0060600000000000ULL,
365 0x0020600000000000ULL, 0x0060600000000000ULL,
366 0x0020600000000000ULL, 0x0060600000000000ULL,
367 0x0020600000000000ULL, 0x0060600000000000ULL,
368 0x0020600000000000ULL, 0x0060600000000000ULL,
369 0x0020600000000000ULL, 0x0000600000000000ULL,
370 0x0040600000000000ULL, 0x0060600000000000ULL,
371 END_SIGN
372};
373
Ananda Rajub41477f2006-07-24 19:52:49 -0400374MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
375MODULE_LICENSE("GPL");
376MODULE_VERSION(DRV_VERSION);
377
378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379/* Module Loadable parameters. */
Ananda Rajub41477f2006-07-24 19:52:49 -0400380S2IO_PARM_INT(tx_fifo_num, 1);
381S2IO_PARM_INT(rx_ring_num, 1);
382
383
384S2IO_PARM_INT(rx_ring_mode, 1);
385S2IO_PARM_INT(use_continuous_tx_intrs, 1);
386S2IO_PARM_INT(rmac_pause_time, 0x100);
387S2IO_PARM_INT(mc_pause_threshold_q0q3, 187);
388S2IO_PARM_INT(mc_pause_threshold_q4q7, 187);
389S2IO_PARM_INT(shared_splits, 0);
390S2IO_PARM_INT(tmac_util_period, 5);
391S2IO_PARM_INT(rmac_util_period, 5);
392S2IO_PARM_INT(bimodal, 0);
393S2IO_PARM_INT(l3l4hdr_size, 128);
394/* Frequency of Rx desc syncs expressed as power of 2 */
395S2IO_PARM_INT(rxsync_frequency, 3);
396/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */
397S2IO_PARM_INT(intr_type, 0);
398/* Large receive offload feature */
399S2IO_PARM_INT(lro, 0);
400/* Max pkts to be aggregated by LRO at one time. If not specified,
401 * aggregation happens until we hit max IP pkt size(64K)
402 */
403S2IO_PARM_INT(lro_max_pkts, 0xFFFF);
Ananda Rajub41477f2006-07-24 19:52:49 -0400404S2IO_PARM_INT(indicate_max_pkts, 0);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -0500405
406S2IO_PARM_INT(napi, 1);
407S2IO_PARM_INT(ufo, 0);
Ananda Rajub41477f2006-07-24 19:52:49 -0400408
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
Ananda Raju9dc737a2006-04-21 19:05:41 -0400410 {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411static unsigned int rx_ring_sz[MAX_RX_RINGS] =
Ananda Raju9dc737a2006-04-21 19:05:41 -0400412 {[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT};
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700413static unsigned int rts_frm_len[MAX_RX_RINGS] =
414 {[0 ...(MAX_RX_RINGS - 1)] = 0 };
Ananda Rajub41477f2006-07-24 19:52:49 -0400415
416module_param_array(tx_fifo_len, uint, NULL, 0);
417module_param_array(rx_ring_sz, uint, NULL, 0);
418module_param_array(rts_frm_len, uint, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700420/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 * S2IO device table.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700422 * This table lists all the devices that this driver supports.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 */
424static struct pci_device_id s2io_tbl[] __devinitdata = {
425 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN,
426 PCI_ANY_ID, PCI_ANY_ID},
427 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI,
428 PCI_ANY_ID, PCI_ANY_ID},
429 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700430 PCI_ANY_ID, PCI_ANY_ID},
431 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI,
432 PCI_ANY_ID, PCI_ANY_ID},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 {0,}
434};
435
436MODULE_DEVICE_TABLE(pci, s2io_tbl);
437
438static struct pci_driver s2io_driver = {
439 .name = "S2IO",
440 .id_table = s2io_tbl,
441 .probe = s2io_init_nic,
442 .remove = __devexit_p(s2io_rem_nic),
443};
444
445/* A simplifier macro used both by init and free shared_mem Fns(). */
446#define TXD_MEM_PAGE_CNT(len, per_each) ((len+per_each - 1) / per_each)
447
448/**
449 * init_shared_mem - Allocation and Initialization of Memory
450 * @nic: Device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700451 * Description: The function allocates all the memory areas shared
452 * between the NIC and the driver. This includes Tx descriptors,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 * Rx descriptors and the statistics block.
454 */
455
456static int init_shared_mem(struct s2io_nic *nic)
457{
458 u32 size;
459 void *tmp_v_addr, *tmp_v_addr_next;
460 dma_addr_t tmp_p_addr, tmp_p_addr_next;
461 RxD_block_t *pre_rxd_blk = NULL;
Sivakumar Subramani372cc592007-01-31 13:32:57 -0500462 int i, j, blk_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 int lst_size, lst_per_page;
464 struct net_device *dev = nic->dev;
viro@zenIV.linux.org.uk8ae418c2005-09-02 20:15:29 +0100465 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 buffAdd_t *ba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
468 mac_info_t *mac_control;
469 struct config_param *config;
470
471 mac_control = &nic->mac_control;
472 config = &nic->config;
473
474
475 /* Allocation and initialization of TXDLs in FIOFs */
476 size = 0;
477 for (i = 0; i < config->tx_fifo_num; i++) {
478 size += config->tx_cfg[i].fifo_len;
479 }
480 if (size > MAX_AVAILABLE_TXDS) {
Ananda Rajub41477f2006-07-24 19:52:49 -0400481 DBG_PRINT(ERR_DBG, "s2io: Requested TxDs too high, ");
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -0700482 DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size);
Ananda Rajub41477f2006-07-24 19:52:49 -0400483 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 }
485
486 lst_size = (sizeof(TxD_t) * config->max_txds);
487 lst_per_page = PAGE_SIZE / lst_size;
488
489 for (i = 0; i < config->tx_fifo_num; i++) {
490 int fifo_len = config->tx_cfg[i].fifo_len;
491 int list_holder_size = fifo_len * sizeof(list_info_hold_t);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700492 mac_control->fifos[i].list_info = kmalloc(list_holder_size,
493 GFP_KERNEL);
494 if (!mac_control->fifos[i].list_info) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 DBG_PRINT(ERR_DBG,
496 "Malloc failed for list_info\n");
497 return -ENOMEM;
498 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700499 memset(mac_control->fifos[i].list_info, 0, list_holder_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
501 for (i = 0; i < config->tx_fifo_num; i++) {
502 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
503 lst_per_page);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700504 mac_control->fifos[i].tx_curr_put_info.offset = 0;
505 mac_control->fifos[i].tx_curr_put_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700507 mac_control->fifos[i].tx_curr_get_info.offset = 0;
508 mac_control->fifos[i].tx_curr_get_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700510 mac_control->fifos[i].fifo_no = i;
511 mac_control->fifos[i].nic = nic;
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500512 mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 2;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700513
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 for (j = 0; j < page_num; j++) {
515 int k = 0;
516 dma_addr_t tmp_p;
517 void *tmp_v;
518 tmp_v = pci_alloc_consistent(nic->pdev,
519 PAGE_SIZE, &tmp_p);
520 if (!tmp_v) {
521 DBG_PRINT(ERR_DBG,
522 "pci_alloc_consistent ");
523 DBG_PRINT(ERR_DBG, "failed for TxDL\n");
524 return -ENOMEM;
525 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700526 /* If we got a zero DMA address(can happen on
527 * certain platforms like PPC), reallocate.
528 * Store virtual address of page we don't want,
529 * to be freed later.
530 */
531 if (!tmp_p) {
532 mac_control->zerodma_virt_addr = tmp_v;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400533 DBG_PRINT(INIT_DBG,
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700534 "%s: Zero DMA address for TxDL. ", dev->name);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400535 DBG_PRINT(INIT_DBG,
Andrew Morton6b4d6172005-09-12 23:21:55 -0700536 "Virtual address %p\n", tmp_v);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700537 tmp_v = pci_alloc_consistent(nic->pdev,
538 PAGE_SIZE, &tmp_p);
539 if (!tmp_v) {
540 DBG_PRINT(ERR_DBG,
541 "pci_alloc_consistent ");
542 DBG_PRINT(ERR_DBG, "failed for TxDL\n");
543 return -ENOMEM;
544 }
545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 while (k < lst_per_page) {
547 int l = (j * lst_per_page) + k;
548 if (l == config->tx_cfg[i].fifo_len)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700549 break;
550 mac_control->fifos[i].list_info[l].list_virt_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 tmp_v + (k * lst_size);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700552 mac_control->fifos[i].list_info[l].list_phy_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 tmp_p + (k * lst_size);
554 k++;
555 }
556 }
557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
Al Viro43842472007-01-23 12:25:08 +0000559 nic->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL);
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500560 if (!nic->ufo_in_band_v)
561 return -ENOMEM;
562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 /* Allocation and initialization of RXDs in Rings */
564 size = 0;
565 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -0500566 if (config->rx_cfg[i].num_rxd %
567 (rxd_count[nic->rxd_mode] + 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 DBG_PRINT(ERR_DBG, "%s: RxD count of ", dev->name);
569 DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ",
570 i);
571 DBG_PRINT(ERR_DBG, "RxDs per Block");
572 return FAILURE;
573 }
574 size += config->rx_cfg[i].num_rxd;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700575 mac_control->rings[i].block_count =
Ananda Rajuda6971d2005-10-31 16:55:31 -0500576 config->rx_cfg[i].num_rxd /
577 (rxd_count[nic->rxd_mode] + 1 );
578 mac_control->rings[i].pkt_cnt = config->rx_cfg[i].num_rxd -
579 mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500581 if (nic->rxd_mode == RXD_MODE_1)
582 size = (size * (sizeof(RxD1_t)));
583 else
584 size = (size * (sizeof(RxD3_t)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
586 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700587 mac_control->rings[i].rx_curr_get_info.block_index = 0;
588 mac_control->rings[i].rx_curr_get_info.offset = 0;
589 mac_control->rings[i].rx_curr_get_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700591 mac_control->rings[i].rx_curr_put_info.block_index = 0;
592 mac_control->rings[i].rx_curr_put_info.offset = 0;
593 mac_control->rings[i].rx_curr_put_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700595 mac_control->rings[i].nic = nic;
596 mac_control->rings[i].ring_no = i;
597
Ananda Rajuda6971d2005-10-31 16:55:31 -0500598 blk_cnt = config->rx_cfg[i].num_rxd /
599 (rxd_count[nic->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 /* Allocating all the Rx blocks */
601 for (j = 0; j < blk_cnt; j++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -0500602 rx_block_info_t *rx_blocks;
603 int l;
604
605 rx_blocks = &mac_control->rings[i].rx_blocks[j];
606 size = SIZE_OF_BLOCK; //size is always page size
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 tmp_v_addr = pci_alloc_consistent(nic->pdev, size,
608 &tmp_p_addr);
609 if (tmp_v_addr == NULL) {
610 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700611 * In case of failure, free_shared_mem()
612 * is called, which should free any
613 * memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 * failure happened.
615 */
Ananda Rajuda6971d2005-10-31 16:55:31 -0500616 rx_blocks->block_virt_addr = tmp_v_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 return -ENOMEM;
618 }
619 memset(tmp_v_addr, 0, size);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500620 rx_blocks->block_virt_addr = tmp_v_addr;
621 rx_blocks->block_dma_addr = tmp_p_addr;
622 rx_blocks->rxds = kmalloc(sizeof(rxd_info_t)*
623 rxd_count[nic->rxd_mode],
624 GFP_KERNEL);
Sivakumar Subramani372cc592007-01-31 13:32:57 -0500625 if (!rx_blocks->rxds)
626 return -ENOMEM;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500627 for (l=0; l<rxd_count[nic->rxd_mode];l++) {
628 rx_blocks->rxds[l].virt_addr =
629 rx_blocks->block_virt_addr +
630 (rxd_size[nic->rxd_mode] * l);
631 rx_blocks->rxds[l].dma_addr =
632 rx_blocks->block_dma_addr +
633 (rxd_size[nic->rxd_mode] * l);
634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 }
636 /* Interlinking all Rx Blocks */
637 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700638 tmp_v_addr =
639 mac_control->rings[i].rx_blocks[j].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 tmp_v_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700641 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 blk_cnt].block_virt_addr;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700643 tmp_p_addr =
644 mac_control->rings[i].rx_blocks[j].block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 tmp_p_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700646 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 blk_cnt].block_dma_addr;
648
649 pre_rxd_blk = (RxD_block_t *) tmp_v_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 pre_rxd_blk->reserved_2_pNext_RxD_block =
651 (unsigned long) tmp_v_addr_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 pre_rxd_blk->pNext_RxD_Blk_physical =
653 (u64) tmp_p_addr_next;
654 }
655 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500656 if (nic->rxd_mode >= RXD_MODE_3A) {
657 /*
658 * Allocation of Storages for buffer addresses in 2BUFF mode
659 * and the buffers as well.
660 */
661 for (i = 0; i < config->rx_ring_num; i++) {
662 blk_cnt = config->rx_cfg[i].num_rxd /
663 (rxd_count[nic->rxd_mode]+ 1);
664 mac_control->rings[i].ba =
665 kmalloc((sizeof(buffAdd_t *) * blk_cnt),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 GFP_KERNEL);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500667 if (!mac_control->rings[i].ba)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 return -ENOMEM;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500669 for (j = 0; j < blk_cnt; j++) {
670 int k = 0;
671 mac_control->rings[i].ba[j] =
672 kmalloc((sizeof(buffAdd_t) *
673 (rxd_count[nic->rxd_mode] + 1)),
674 GFP_KERNEL);
675 if (!mac_control->rings[i].ba[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 return -ENOMEM;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500677 while (k != rxd_count[nic->rxd_mode]) {
678 ba = &mac_control->rings[i].ba[j][k];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Ananda Rajuda6971d2005-10-31 16:55:31 -0500680 ba->ba_0_org = (void *) kmalloc
681 (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
682 if (!ba->ba_0_org)
683 return -ENOMEM;
684 tmp = (unsigned long)ba->ba_0_org;
685 tmp += ALIGN_SIZE;
686 tmp &= ~((unsigned long) ALIGN_SIZE);
687 ba->ba_0 = (void *) tmp;
688
689 ba->ba_1_org = (void *) kmalloc
690 (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
691 if (!ba->ba_1_org)
692 return -ENOMEM;
693 tmp = (unsigned long) ba->ba_1_org;
694 tmp += ALIGN_SIZE;
695 tmp &= ~((unsigned long) ALIGN_SIZE);
696 ba->ba_1 = (void *) tmp;
697 k++;
698 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 }
700 }
701 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
703 /* Allocation and initialization of Statistics block */
704 size = sizeof(StatInfo_t);
705 mac_control->stats_mem = pci_alloc_consistent
706 (nic->pdev, size, &mac_control->stats_mem_phy);
707
708 if (!mac_control->stats_mem) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700709 /*
710 * In case of failure, free_shared_mem() is called, which
711 * should free any memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 * failure happened.
713 */
714 return -ENOMEM;
715 }
716 mac_control->stats_mem_sz = size;
717
718 tmp_v_addr = mac_control->stats_mem;
719 mac_control->stats_info = (StatInfo_t *) tmp_v_addr;
720 memset(tmp_v_addr, 0, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name,
722 (unsigned long long) tmp_p_addr);
723
724 return SUCCESS;
725}
726
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700727/**
728 * free_shared_mem - Free the allocated Memory
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 * @nic: Device private variable.
730 * Description: This function is to free all memory locations allocated by
731 * the init_shared_mem() function and return it to the kernel.
732 */
733
734static void free_shared_mem(struct s2io_nic *nic)
735{
736 int i, j, blk_cnt, size;
737 void *tmp_v_addr;
738 dma_addr_t tmp_p_addr;
739 mac_info_t *mac_control;
740 struct config_param *config;
741 int lst_size, lst_per_page;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700742 struct net_device *dev = nic->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
744 if (!nic)
745 return;
746
747 mac_control = &nic->mac_control;
748 config = &nic->config;
749
750 lst_size = (sizeof(TxD_t) * config->max_txds);
751 lst_per_page = PAGE_SIZE / lst_size;
752
753 for (i = 0; i < config->tx_fifo_num; i++) {
754 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
755 lst_per_page);
756 for (j = 0; j < page_num; j++) {
757 int mem_blks = (j * lst_per_page);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700758 if (!mac_control->fifos[i].list_info)
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400759 return;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700760 if (!mac_control->fifos[i].list_info[mem_blks].
761 list_virt_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 break;
763 pci_free_consistent(nic->pdev, PAGE_SIZE,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700764 mac_control->fifos[i].
765 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 list_virt_addr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700767 mac_control->fifos[i].
768 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 list_phy_addr);
770 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700771 /* If we got a zero DMA address during allocation,
772 * free the page now
773 */
774 if (mac_control->zerodma_virt_addr) {
775 pci_free_consistent(nic->pdev, PAGE_SIZE,
776 mac_control->zerodma_virt_addr,
777 (dma_addr_t)0);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400778 DBG_PRINT(INIT_DBG,
Andrew Morton6b4d6172005-09-12 23:21:55 -0700779 "%s: Freeing TxDL with zero DMA addr. ",
780 dev->name);
781 DBG_PRINT(INIT_DBG, "Virtual address %p\n",
782 mac_control->zerodma_virt_addr);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700783 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700784 kfree(mac_control->fifos[i].list_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 }
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 size = SIZE_OF_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700789 blk_cnt = mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700791 tmp_v_addr = mac_control->rings[i].rx_blocks[j].
792 block_virt_addr;
793 tmp_p_addr = mac_control->rings[i].rx_blocks[j].
794 block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if (tmp_v_addr == NULL)
796 break;
797 pci_free_consistent(nic->pdev, size,
798 tmp_v_addr, tmp_p_addr);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500799 kfree(mac_control->rings[i].rx_blocks[j].rxds);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 }
801 }
802
Ananda Rajuda6971d2005-10-31 16:55:31 -0500803 if (nic->rxd_mode >= RXD_MODE_3A) {
804 /* Freeing buffer storage addresses in 2BUFF mode. */
805 for (i = 0; i < config->rx_ring_num; i++) {
806 blk_cnt = config->rx_cfg[i].num_rxd /
807 (rxd_count[nic->rxd_mode] + 1);
808 for (j = 0; j < blk_cnt; j++) {
809 int k = 0;
810 if (!mac_control->rings[i].ba[j])
811 continue;
812 while (k != rxd_count[nic->rxd_mode]) {
813 buffAdd_t *ba =
814 &mac_control->rings[i].ba[j][k];
815 kfree(ba->ba_0_org);
816 kfree(ba->ba_1_org);
817 k++;
818 }
819 kfree(mac_control->rings[i].ba[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500821 kfree(mac_control->rings[i].ba);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825 if (mac_control->stats_mem) {
826 pci_free_consistent(nic->pdev,
827 mac_control->stats_mem_sz,
828 mac_control->stats_mem,
829 mac_control->stats_mem_phy);
830 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500831 if (nic->ufo_in_band_v)
832 kfree(nic->ufo_in_band_v);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833}
834
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700835/**
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700836 * s2io_verify_pci_mode -
837 */
838
839static int s2io_verify_pci_mode(nic_t *nic)
840{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +0100841 XENA_dev_config_t __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700842 register u64 val64 = 0;
843 int mode;
844
845 val64 = readq(&bar0->pci_mode);
846 mode = (u8)GET_PCI_MODE(val64);
847
848 if ( val64 & PCI_MODE_UNKNOWN_MODE)
849 return -1; /* Unknown PCI mode */
850 return mode;
851}
852
Ananda Rajuc92ca042006-04-21 19:18:03 -0400853#define NEC_VENID 0x1033
854#define NEC_DEVID 0x0125
855static int s2io_on_nec_bridge(struct pci_dev *s2io_pdev)
856{
857 struct pci_dev *tdev = NULL;
Alan Cox26d36b62006-09-15 15:22:51 +0100858 while ((tdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, tdev)) != NULL) {
859 if (tdev->vendor == NEC_VENID && tdev->device == NEC_DEVID) {
Ananda Rajuc92ca042006-04-21 19:18:03 -0400860 if (tdev->bus == s2io_pdev->bus->parent)
Alan Cox26d36b62006-09-15 15:22:51 +0100861 pci_dev_put(tdev);
Ananda Rajuc92ca042006-04-21 19:18:03 -0400862 return 1;
863 }
864 }
865 return 0;
866}
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700867
Adrian Bunk7b32a312006-05-16 17:30:50 +0200868static int bus_speed[8] = {33, 133, 133, 200, 266, 133, 200, 266};
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700869/**
870 * s2io_print_pci_mode -
871 */
872static int s2io_print_pci_mode(nic_t *nic)
873{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +0100874 XENA_dev_config_t __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700875 register u64 val64 = 0;
876 int mode;
877 struct config_param *config = &nic->config;
878
879 val64 = readq(&bar0->pci_mode);
880 mode = (u8)GET_PCI_MODE(val64);
881
882 if ( val64 & PCI_MODE_UNKNOWN_MODE)
883 return -1; /* Unknown PCI mode */
884
Ananda Rajuc92ca042006-04-21 19:18:03 -0400885 config->bus_speed = bus_speed[mode];
886
887 if (s2io_on_nec_bridge(nic->pdev)) {
888 DBG_PRINT(ERR_DBG, "%s: Device is on PCI-E bus\n",
889 nic->dev->name);
890 return mode;
891 }
892
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700893 if (val64 & PCI_MODE_32_BITS) {
894 DBG_PRINT(ERR_DBG, "%s: Device is on 32 bit ", nic->dev->name);
895 } else {
896 DBG_PRINT(ERR_DBG, "%s: Device is on 64 bit ", nic->dev->name);
897 }
898
899 switch(mode) {
900 case PCI_MODE_PCI_33:
901 DBG_PRINT(ERR_DBG, "33MHz PCI bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700902 break;
903 case PCI_MODE_PCI_66:
904 DBG_PRINT(ERR_DBG, "66MHz PCI bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700905 break;
906 case PCI_MODE_PCIX_M1_66:
907 DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700908 break;
909 case PCI_MODE_PCIX_M1_100:
910 DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700911 break;
912 case PCI_MODE_PCIX_M1_133:
913 DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700914 break;
915 case PCI_MODE_PCIX_M2_66:
916 DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700917 break;
918 case PCI_MODE_PCIX_M2_100:
919 DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700920 break;
921 case PCI_MODE_PCIX_M2_133:
922 DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700923 break;
924 default:
925 return -1; /* Unsupported bus speed */
926 }
927
928 return mode;
929}
930
931/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700932 * init_nic - Initialization of hardware
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 * @nic: device peivate variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700934 * Description: The function sequentially configures every block
935 * of the H/W from their reset values.
936 * Return Value: SUCCESS on success and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 * '-1' on failure (endian settings incorrect).
938 */
939
940static int init_nic(struct s2io_nic *nic)
941{
942 XENA_dev_config_t __iomem *bar0 = nic->bar0;
943 struct net_device *dev = nic->dev;
944 register u64 val64 = 0;
945 void __iomem *add;
946 u32 time;
947 int i, j;
948 mac_info_t *mac_control;
949 struct config_param *config;
Ananda Rajuc92ca042006-04-21 19:18:03 -0400950 int dtx_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 unsigned long long mem_share;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700952 int mem_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 mac_control = &nic->mac_control;
955 config = &nic->config;
956
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700957 /* to set the swapper controle on the card */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700958 if(s2io_set_swapper(nic)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n");
960 return -1;
961 }
962
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700963 /*
964 * Herc requires EOI to be removed from reset before XGXS, so..
965 */
966 if (nic->device_type & XFRAME_II_DEVICE) {
967 val64 = 0xA500000000ULL;
968 writeq(val64, &bar0->sw_reset);
969 msleep(500);
970 val64 = readq(&bar0->sw_reset);
971 }
972
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 /* Remove XGXS from reset state */
974 val64 = 0;
975 writeq(val64, &bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 msleep(500);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700977 val64 = readq(&bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
979 /* Enable Receiving broadcasts */
980 add = &bar0->mac_cfg;
981 val64 = readq(&bar0->mac_cfg);
982 val64 |= MAC_RMAC_BCAST_ENABLE;
983 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
984 writel((u32) val64, add);
985 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
986 writel((u32) (val64 >> 32), (add + 4));
987
988 /* Read registers in all blocks */
989 val64 = readq(&bar0->mac_int_mask);
990 val64 = readq(&bar0->mc_int_mask);
991 val64 = readq(&bar0->xgxs_int_mask);
992
993 /* Set MTU */
994 val64 = dev->mtu;
995 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
996
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700997 if (nic->device_type & XFRAME_II_DEVICE) {
998 while (herc_act_dtx_cfg[dtx_cnt] != END_SIGN) {
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -0700999 SPECIAL_REG_WRITE(herc_act_dtx_cfg[dtx_cnt],
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 &bar0->dtx_control, UF);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001001 if (dtx_cnt & 0x1)
1002 msleep(1); /* Necessary!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 dtx_cnt++;
1004 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001005 } else {
Ananda Rajuc92ca042006-04-21 19:18:03 -04001006 while (xena_dtx_cfg[dtx_cnt] != END_SIGN) {
1007 SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt],
1008 &bar0->dtx_control, UF);
1009 val64 = readq(&bar0->dtx_control);
1010 dtx_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 }
1012 }
1013
1014 /* Tx DMA Initialization */
1015 val64 = 0;
1016 writeq(val64, &bar0->tx_fifo_partition_0);
1017 writeq(val64, &bar0->tx_fifo_partition_1);
1018 writeq(val64, &bar0->tx_fifo_partition_2);
1019 writeq(val64, &bar0->tx_fifo_partition_3);
1020
1021
1022 for (i = 0, j = 0; i < config->tx_fifo_num; i++) {
1023 val64 |=
1024 vBIT(config->tx_cfg[i].fifo_len - 1, ((i * 32) + 19),
1025 13) | vBIT(config->tx_cfg[i].fifo_priority,
1026 ((i * 32) + 5), 3);
1027
1028 if (i == (config->tx_fifo_num - 1)) {
1029 if (i % 2 == 0)
1030 i++;
1031 }
1032
1033 switch (i) {
1034 case 1:
1035 writeq(val64, &bar0->tx_fifo_partition_0);
1036 val64 = 0;
1037 break;
1038 case 3:
1039 writeq(val64, &bar0->tx_fifo_partition_1);
1040 val64 = 0;
1041 break;
1042 case 5:
1043 writeq(val64, &bar0->tx_fifo_partition_2);
1044 val64 = 0;
1045 break;
1046 case 7:
1047 writeq(val64, &bar0->tx_fifo_partition_3);
1048 break;
1049 }
1050 }
1051
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001052 /*
1053 * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug
1054 * SXE-008 TRANSMIT DMA ARBITRATION ISSUE.
1055 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001056 if ((nic->device_type == XFRAME_I_DEVICE) &&
1057 (get_xena_rev_id(nic->pdev) < 4))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001058 writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable);
1059
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 val64 = readq(&bar0->tx_fifo_partition_0);
1061 DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n",
1062 &bar0->tx_fifo_partition_0, (unsigned long long) val64);
1063
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001064 /*
1065 * Initialization of Tx_PA_CONFIG register to ignore packet
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 * integrity checking.
1067 */
1068 val64 = readq(&bar0->tx_pa_cfg);
1069 val64 |= TX_PA_CFG_IGNORE_FRM_ERR | TX_PA_CFG_IGNORE_SNAP_OUI |
1070 TX_PA_CFG_IGNORE_LLC_CTRL | TX_PA_CFG_IGNORE_L2_ERR;
1071 writeq(val64, &bar0->tx_pa_cfg);
1072
1073 /* Rx DMA intialization. */
1074 val64 = 0;
1075 for (i = 0; i < config->rx_ring_num; i++) {
1076 val64 |=
1077 vBIT(config->rx_cfg[i].ring_priority, (5 + (i * 8)),
1078 3);
1079 }
1080 writeq(val64, &bar0->rx_queue_priority);
1081
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001082 /*
1083 * Allocating equal share of memory to all the
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 * configured Rings.
1085 */
1086 val64 = 0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001087 if (nic->device_type & XFRAME_II_DEVICE)
1088 mem_size = 32;
1089 else
1090 mem_size = 64;
1091
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 for (i = 0; i < config->rx_ring_num; i++) {
1093 switch (i) {
1094 case 0:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001095 mem_share = (mem_size / config->rx_ring_num +
1096 mem_size % config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 val64 |= RX_QUEUE_CFG_Q0_SZ(mem_share);
1098 continue;
1099 case 1:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001100 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 val64 |= RX_QUEUE_CFG_Q1_SZ(mem_share);
1102 continue;
1103 case 2:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001104 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 val64 |= RX_QUEUE_CFG_Q2_SZ(mem_share);
1106 continue;
1107 case 3:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001108 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 val64 |= RX_QUEUE_CFG_Q3_SZ(mem_share);
1110 continue;
1111 case 4:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001112 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 val64 |= RX_QUEUE_CFG_Q4_SZ(mem_share);
1114 continue;
1115 case 5:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001116 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 val64 |= RX_QUEUE_CFG_Q5_SZ(mem_share);
1118 continue;
1119 case 6:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001120 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 val64 |= RX_QUEUE_CFG_Q6_SZ(mem_share);
1122 continue;
1123 case 7:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001124 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 val64 |= RX_QUEUE_CFG_Q7_SZ(mem_share);
1126 continue;
1127 }
1128 }
1129 writeq(val64, &bar0->rx_queue_cfg);
1130
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001131 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001132 * Filling Tx round robin registers
1133 * as per the number of FIFOs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 */
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001135 switch (config->tx_fifo_num) {
1136 case 1:
1137 val64 = 0x0000000000000000ULL;
1138 writeq(val64, &bar0->tx_w_round_robin_0);
1139 writeq(val64, &bar0->tx_w_round_robin_1);
1140 writeq(val64, &bar0->tx_w_round_robin_2);
1141 writeq(val64, &bar0->tx_w_round_robin_3);
1142 writeq(val64, &bar0->tx_w_round_robin_4);
1143 break;
1144 case 2:
1145 val64 = 0x0000010000010000ULL;
1146 writeq(val64, &bar0->tx_w_round_robin_0);
1147 val64 = 0x0100000100000100ULL;
1148 writeq(val64, &bar0->tx_w_round_robin_1);
1149 val64 = 0x0001000001000001ULL;
1150 writeq(val64, &bar0->tx_w_round_robin_2);
1151 val64 = 0x0000010000010000ULL;
1152 writeq(val64, &bar0->tx_w_round_robin_3);
1153 val64 = 0x0100000000000000ULL;
1154 writeq(val64, &bar0->tx_w_round_robin_4);
1155 break;
1156 case 3:
1157 val64 = 0x0001000102000001ULL;
1158 writeq(val64, &bar0->tx_w_round_robin_0);
1159 val64 = 0x0001020000010001ULL;
1160 writeq(val64, &bar0->tx_w_round_robin_1);
1161 val64 = 0x0200000100010200ULL;
1162 writeq(val64, &bar0->tx_w_round_robin_2);
1163 val64 = 0x0001000102000001ULL;
1164 writeq(val64, &bar0->tx_w_round_robin_3);
1165 val64 = 0x0001020000000000ULL;
1166 writeq(val64, &bar0->tx_w_round_robin_4);
1167 break;
1168 case 4:
1169 val64 = 0x0001020300010200ULL;
1170 writeq(val64, &bar0->tx_w_round_robin_0);
1171 val64 = 0x0100000102030001ULL;
1172 writeq(val64, &bar0->tx_w_round_robin_1);
1173 val64 = 0x0200010000010203ULL;
1174 writeq(val64, &bar0->tx_w_round_robin_2);
1175 val64 = 0x0001020001000001ULL;
1176 writeq(val64, &bar0->tx_w_round_robin_3);
1177 val64 = 0x0203000100000000ULL;
1178 writeq(val64, &bar0->tx_w_round_robin_4);
1179 break;
1180 case 5:
1181 val64 = 0x0001000203000102ULL;
1182 writeq(val64, &bar0->tx_w_round_robin_0);
1183 val64 = 0x0001020001030004ULL;
1184 writeq(val64, &bar0->tx_w_round_robin_1);
1185 val64 = 0x0001000203000102ULL;
1186 writeq(val64, &bar0->tx_w_round_robin_2);
1187 val64 = 0x0001020001030004ULL;
1188 writeq(val64, &bar0->tx_w_round_robin_3);
1189 val64 = 0x0001000000000000ULL;
1190 writeq(val64, &bar0->tx_w_round_robin_4);
1191 break;
1192 case 6:
1193 val64 = 0x0001020304000102ULL;
1194 writeq(val64, &bar0->tx_w_round_robin_0);
1195 val64 = 0x0304050001020001ULL;
1196 writeq(val64, &bar0->tx_w_round_robin_1);
1197 val64 = 0x0203000100000102ULL;
1198 writeq(val64, &bar0->tx_w_round_robin_2);
1199 val64 = 0x0304000102030405ULL;
1200 writeq(val64, &bar0->tx_w_round_robin_3);
1201 val64 = 0x0001000200000000ULL;
1202 writeq(val64, &bar0->tx_w_round_robin_4);
1203 break;
1204 case 7:
1205 val64 = 0x0001020001020300ULL;
1206 writeq(val64, &bar0->tx_w_round_robin_0);
1207 val64 = 0x0102030400010203ULL;
1208 writeq(val64, &bar0->tx_w_round_robin_1);
1209 val64 = 0x0405060001020001ULL;
1210 writeq(val64, &bar0->tx_w_round_robin_2);
1211 val64 = 0x0304050000010200ULL;
1212 writeq(val64, &bar0->tx_w_round_robin_3);
1213 val64 = 0x0102030000000000ULL;
1214 writeq(val64, &bar0->tx_w_round_robin_4);
1215 break;
1216 case 8:
1217 val64 = 0x0001020300040105ULL;
1218 writeq(val64, &bar0->tx_w_round_robin_0);
1219 val64 = 0x0200030106000204ULL;
1220 writeq(val64, &bar0->tx_w_round_robin_1);
1221 val64 = 0x0103000502010007ULL;
1222 writeq(val64, &bar0->tx_w_round_robin_2);
1223 val64 = 0x0304010002060500ULL;
1224 writeq(val64, &bar0->tx_w_round_robin_3);
1225 val64 = 0x0103020400000000ULL;
1226 writeq(val64, &bar0->tx_w_round_robin_4);
1227 break;
1228 }
1229
Ananda Rajub41477f2006-07-24 19:52:49 -04001230 /* Enable all configured Tx FIFO partitions */
Ananda Raju5d3213c2006-04-21 19:23:26 -04001231 val64 = readq(&bar0->tx_fifo_partition_0);
1232 val64 |= (TX_FIFO_PARTITION_EN);
1233 writeq(val64, &bar0->tx_fifo_partition_0);
1234
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001235 /* Filling the Rx round robin registers as per the
1236 * number of Rings and steering based on QoS.
1237 */
1238 switch (config->rx_ring_num) {
1239 case 1:
1240 val64 = 0x8080808080808080ULL;
1241 writeq(val64, &bar0->rts_qos_steering);
1242 break;
1243 case 2:
1244 val64 = 0x0000010000010000ULL;
1245 writeq(val64, &bar0->rx_w_round_robin_0);
1246 val64 = 0x0100000100000100ULL;
1247 writeq(val64, &bar0->rx_w_round_robin_1);
1248 val64 = 0x0001000001000001ULL;
1249 writeq(val64, &bar0->rx_w_round_robin_2);
1250 val64 = 0x0000010000010000ULL;
1251 writeq(val64, &bar0->rx_w_round_robin_3);
1252 val64 = 0x0100000000000000ULL;
1253 writeq(val64, &bar0->rx_w_round_robin_4);
1254
1255 val64 = 0x8080808040404040ULL;
1256 writeq(val64, &bar0->rts_qos_steering);
1257 break;
1258 case 3:
1259 val64 = 0x0001000102000001ULL;
1260 writeq(val64, &bar0->rx_w_round_robin_0);
1261 val64 = 0x0001020000010001ULL;
1262 writeq(val64, &bar0->rx_w_round_robin_1);
1263 val64 = 0x0200000100010200ULL;
1264 writeq(val64, &bar0->rx_w_round_robin_2);
1265 val64 = 0x0001000102000001ULL;
1266 writeq(val64, &bar0->rx_w_round_robin_3);
1267 val64 = 0x0001020000000000ULL;
1268 writeq(val64, &bar0->rx_w_round_robin_4);
1269
1270 val64 = 0x8080804040402020ULL;
1271 writeq(val64, &bar0->rts_qos_steering);
1272 break;
1273 case 4:
1274 val64 = 0x0001020300010200ULL;
1275 writeq(val64, &bar0->rx_w_round_robin_0);
1276 val64 = 0x0100000102030001ULL;
1277 writeq(val64, &bar0->rx_w_round_robin_1);
1278 val64 = 0x0200010000010203ULL;
1279 writeq(val64, &bar0->rx_w_round_robin_2);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001280 val64 = 0x0001020001000001ULL;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001281 writeq(val64, &bar0->rx_w_round_robin_3);
1282 val64 = 0x0203000100000000ULL;
1283 writeq(val64, &bar0->rx_w_round_robin_4);
1284
1285 val64 = 0x8080404020201010ULL;
1286 writeq(val64, &bar0->rts_qos_steering);
1287 break;
1288 case 5:
1289 val64 = 0x0001000203000102ULL;
1290 writeq(val64, &bar0->rx_w_round_robin_0);
1291 val64 = 0x0001020001030004ULL;
1292 writeq(val64, &bar0->rx_w_round_robin_1);
1293 val64 = 0x0001000203000102ULL;
1294 writeq(val64, &bar0->rx_w_round_robin_2);
1295 val64 = 0x0001020001030004ULL;
1296 writeq(val64, &bar0->rx_w_round_robin_3);
1297 val64 = 0x0001000000000000ULL;
1298 writeq(val64, &bar0->rx_w_round_robin_4);
1299
1300 val64 = 0x8080404020201008ULL;
1301 writeq(val64, &bar0->rts_qos_steering);
1302 break;
1303 case 6:
1304 val64 = 0x0001020304000102ULL;
1305 writeq(val64, &bar0->rx_w_round_robin_0);
1306 val64 = 0x0304050001020001ULL;
1307 writeq(val64, &bar0->rx_w_round_robin_1);
1308 val64 = 0x0203000100000102ULL;
1309 writeq(val64, &bar0->rx_w_round_robin_2);
1310 val64 = 0x0304000102030405ULL;
1311 writeq(val64, &bar0->rx_w_round_robin_3);
1312 val64 = 0x0001000200000000ULL;
1313 writeq(val64, &bar0->rx_w_round_robin_4);
1314
1315 val64 = 0x8080404020100804ULL;
1316 writeq(val64, &bar0->rts_qos_steering);
1317 break;
1318 case 7:
1319 val64 = 0x0001020001020300ULL;
1320 writeq(val64, &bar0->rx_w_round_robin_0);
1321 val64 = 0x0102030400010203ULL;
1322 writeq(val64, &bar0->rx_w_round_robin_1);
1323 val64 = 0x0405060001020001ULL;
1324 writeq(val64, &bar0->rx_w_round_robin_2);
1325 val64 = 0x0304050000010200ULL;
1326 writeq(val64, &bar0->rx_w_round_robin_3);
1327 val64 = 0x0102030000000000ULL;
1328 writeq(val64, &bar0->rx_w_round_robin_4);
1329
1330 val64 = 0x8080402010080402ULL;
1331 writeq(val64, &bar0->rts_qos_steering);
1332 break;
1333 case 8:
1334 val64 = 0x0001020300040105ULL;
1335 writeq(val64, &bar0->rx_w_round_robin_0);
1336 val64 = 0x0200030106000204ULL;
1337 writeq(val64, &bar0->rx_w_round_robin_1);
1338 val64 = 0x0103000502010007ULL;
1339 writeq(val64, &bar0->rx_w_round_robin_2);
1340 val64 = 0x0304010002060500ULL;
1341 writeq(val64, &bar0->rx_w_round_robin_3);
1342 val64 = 0x0103020400000000ULL;
1343 writeq(val64, &bar0->rx_w_round_robin_4);
1344
1345 val64 = 0x8040201008040201ULL;
1346 writeq(val64, &bar0->rts_qos_steering);
1347 break;
1348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
1350 /* UDP Fix */
1351 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001352 for (i = 0; i < 8; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 writeq(val64, &bar0->rts_frm_len_n[i]);
1354
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001355 /* Set the default rts frame length for the rings configured */
1356 val64 = MAC_RTS_FRM_LEN_SET(dev->mtu+22);
1357 for (i = 0 ; i < config->rx_ring_num ; i++)
1358 writeq(val64, &bar0->rts_frm_len_n[i]);
1359
1360 /* Set the frame length for the configured rings
1361 * desired by the user
1362 */
1363 for (i = 0; i < config->rx_ring_num; i++) {
1364 /* If rts_frm_len[i] == 0 then it is assumed that user not
1365 * specified frame length steering.
1366 * If the user provides the frame length then program
1367 * the rts_frm_len register for those values or else
1368 * leave it as it is.
1369 */
1370 if (rts_frm_len[i] != 0) {
1371 writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]),
1372 &bar0->rts_frm_len_n[i]);
1373 }
1374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001376 /* Program statistics memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 writeq(mac_control->stats_mem_phy, &bar0->stat_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001379 if (nic->device_type == XFRAME_II_DEVICE) {
1380 val64 = STAT_BC(0x320);
1381 writeq(val64, &bar0->stat_byte_cnt);
1382 }
1383
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001384 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 * Initializing the sampling rate for the device to calculate the
1386 * bandwidth utilization.
1387 */
1388 val64 = MAC_TX_LINK_UTIL_VAL(tmac_util_period) |
1389 MAC_RX_LINK_UTIL_VAL(rmac_util_period);
1390 writeq(val64, &bar0->mac_link_util);
1391
1392
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001393 /*
1394 * Initializing the Transmit and Receive Traffic Interrupt
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 * Scheme.
1396 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001397 /*
1398 * TTI Initialization. Default Tx timer gets us about
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 * 250 interrupts per sec. Continuous interrupts are enabled
1400 * by default.
1401 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001402 if (nic->device_type == XFRAME_II_DEVICE) {
1403 int count = (nic->config.bus_speed * 125)/2;
1404 val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count);
1405 } else {
1406
1407 val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078);
1408 }
1409 val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 TTI_DATA1_MEM_TX_URNG_B(0x10) |
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001411 TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001412 if (use_continuous_tx_intrs)
1413 val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 writeq(val64, &bar0->tti_data1_mem);
1415
1416 val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
1417 TTI_DATA2_MEM_TX_UFC_B(0x20) |
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001418 TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 writeq(val64, &bar0->tti_data2_mem);
1420
1421 val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
1422 writeq(val64, &bar0->tti_command_mem);
1423
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001424 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 * Once the operation completes, the Strobe bit of the command
1426 * register will be reset. We poll for this particular condition
1427 * We wait for a maximum of 500ms for the operation to complete,
1428 * if it's not complete by then we return error.
1429 */
1430 time = 0;
1431 while (TRUE) {
1432 val64 = readq(&bar0->tti_command_mem);
1433 if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
1434 break;
1435 }
1436 if (time > 10) {
1437 DBG_PRINT(ERR_DBG, "%s: TTI init Failed\n",
1438 dev->name);
1439 return -1;
1440 }
1441 msleep(50);
1442 time++;
1443 }
1444
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001445 if (nic->config.bimodal) {
1446 int k = 0;
1447 for (k = 0; k < config->rx_ring_num; k++) {
1448 val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
1449 val64 |= TTI_CMD_MEM_OFFSET(0x38+k);
1450 writeq(val64, &bar0->tti_command_mem);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001451
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001452 /*
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001453 * Once the operation completes, the Strobe bit of the command
1454 * register will be reset. We poll for this particular condition
1455 * We wait for a maximum of 500ms for the operation to complete,
1456 * if it's not complete by then we return error.
1457 */
1458 time = 0;
1459 while (TRUE) {
1460 val64 = readq(&bar0->tti_command_mem);
1461 if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
1462 break;
1463 }
1464 if (time > 10) {
1465 DBG_PRINT(ERR_DBG,
1466 "%s: TTI init Failed\n",
1467 dev->name);
1468 return -1;
1469 }
1470 time++;
1471 msleep(50);
1472 }
1473 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001474 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001476 /* RTI Initialization */
1477 if (nic->device_type == XFRAME_II_DEVICE) {
1478 /*
1479 * Programmed to generate Apprx 500 Intrs per
1480 * second
1481 */
1482 int count = (nic->config.bus_speed * 125)/4;
1483 val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
1484 } else {
1485 val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 }
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001487 val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
1488 RTI_DATA1_MEM_RX_URNG_B(0x10) |
1489 RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
1490
1491 writeq(val64, &bar0->rti_data1_mem);
1492
1493 val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04001494 RTI_DATA2_MEM_RX_UFC_B(0x2) ;
1495 if (nic->intr_type == MSI_X)
1496 val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
1497 RTI_DATA2_MEM_RX_UFC_D(0x40));
1498 else
1499 val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \
1500 RTI_DATA2_MEM_RX_UFC_D(0x80));
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001501 writeq(val64, &bar0->rti_data2_mem);
1502
1503 for (i = 0; i < config->rx_ring_num; i++) {
1504 val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD
1505 | RTI_CMD_MEM_OFFSET(i);
1506 writeq(val64, &bar0->rti_command_mem);
1507
1508 /*
1509 * Once the operation completes, the Strobe bit of the
1510 * command register will be reset. We poll for this
1511 * particular condition. We wait for a maximum of 500ms
1512 * for the operation to complete, if it's not complete
1513 * by then we return error.
1514 */
1515 time = 0;
1516 while (TRUE) {
1517 val64 = readq(&bar0->rti_command_mem);
1518 if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) {
1519 break;
1520 }
1521 if (time > 10) {
1522 DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
1523 dev->name);
1524 return -1;
1525 }
1526 time++;
1527 msleep(50);
1528 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 }
1531
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001532 /*
1533 * Initializing proper values as Pause threshold into all
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 * the 8 Queues on Rx side.
1535 */
1536 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q0q3);
1537 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7);
1538
1539 /* Disable RMAC PAD STRIPPING */
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01001540 add = &bar0->mac_cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 val64 = readq(&bar0->mac_cfg);
1542 val64 &= ~(MAC_CFG_RMAC_STRIP_PAD);
1543 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1544 writel((u32) (val64), add);
1545 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1546 writel((u32) (val64 >> 32), (add + 4));
1547 val64 = readq(&bar0->mac_cfg);
1548
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05001549 /* Enable FCS stripping by adapter */
1550 add = &bar0->mac_cfg;
1551 val64 = readq(&bar0->mac_cfg);
1552 val64 |= MAC_CFG_RMAC_STRIP_FCS;
1553 if (nic->device_type == XFRAME_II_DEVICE)
1554 writeq(val64, &bar0->mac_cfg);
1555 else {
1556 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1557 writel((u32) (val64), add);
1558 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1559 writel((u32) (val64 >> 32), (add + 4));
1560 }
1561
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001562 /*
1563 * Set the time value to be inserted in the pause frame
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 * generated by xena.
1565 */
1566 val64 = readq(&bar0->rmac_pause_cfg);
1567 val64 &= ~(RMAC_PAUSE_HG_PTIME(0xffff));
1568 val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time);
1569 writeq(val64, &bar0->rmac_pause_cfg);
1570
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001571 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 * Set the Threshold Limit for Generating the pause frame
1573 * If the amount of data in any Queue exceeds ratio of
1574 * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256
1575 * pause frame is generated
1576 */
1577 val64 = 0;
1578 for (i = 0; i < 4; i++) {
1579 val64 |=
1580 (((u64) 0xFF00 | nic->mac_control.
1581 mc_pause_threshold_q0q3)
1582 << (i * 2 * 8));
1583 }
1584 writeq(val64, &bar0->mc_pause_thresh_q0q3);
1585
1586 val64 = 0;
1587 for (i = 0; i < 4; i++) {
1588 val64 |=
1589 (((u64) 0xFF00 | nic->mac_control.
1590 mc_pause_threshold_q4q7)
1591 << (i * 2 * 8));
1592 }
1593 writeq(val64, &bar0->mc_pause_thresh_q4q7);
1594
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001595 /*
1596 * TxDMA will stop Read request if the number of read split has
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 * exceeded the limit pointed by shared_splits
1598 */
1599 val64 = readq(&bar0->pic_control);
1600 val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits);
1601 writeq(val64, &bar0->pic_control);
1602
Ananda Raju863c11a2006-04-21 19:03:13 -04001603 if (nic->config.bus_speed == 266) {
1604 writeq(TXREQTO_VAL(0x7f) | TXREQTO_EN, &bar0->txreqtimeout);
1605 writeq(0x0, &bar0->read_retry_delay);
1606 writeq(0x0, &bar0->write_retry_delay);
1607 }
1608
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001609 /*
1610 * Programming the Herc to split every write transaction
1611 * that does not start on an ADB to reduce disconnects.
1612 */
1613 if (nic->device_type == XFRAME_II_DEVICE) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001614 val64 = FAULT_BEHAVIOUR | EXT_REQ_EN |
1615 MISC_LINK_STABILITY_PRD(3);
Ananda Raju863c11a2006-04-21 19:03:13 -04001616 writeq(val64, &bar0->misc_control);
1617 val64 = readq(&bar0->pic_control2);
1618 val64 &= ~(BIT(13)|BIT(14)|BIT(15));
1619 writeq(val64, &bar0->pic_control2);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001620 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04001621 if (strstr(nic->product_name, "CX4")) {
1622 val64 = TMAC_AVG_IPG(0x17);
1623 writeq(val64, &bar0->tmac_avg_ipg);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001624 }
1625
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 return SUCCESS;
1627}
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001628#define LINK_UP_DOWN_INTERRUPT 1
1629#define MAC_RMAC_ERR_TIMER 2
1630
Adrian Bunkac1f60d2005-11-06 01:46:47 +01001631static int s2io_link_fault_indication(nic_t *nic)
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001632{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04001633 if (nic->intr_type != INTA)
1634 return MAC_RMAC_ERR_TIMER;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001635 if (nic->device_type == XFRAME_II_DEVICE)
1636 return LINK_UP_DOWN_INTERRUPT;
1637 else
1638 return MAC_RMAC_ERR_TIMER;
1639}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001641/**
1642 * en_dis_able_nic_intrs - Enable or Disable the interrupts
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 * @nic: device private variable,
1644 * @mask: A mask indicating which Intr block must be modified and,
1645 * @flag: A flag indicating whether to enable or disable the Intrs.
1646 * Description: This function will either disable or enable the interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001647 * depending on the flag argument. The mask argument can be used to
1648 * enable/disable any Intr block.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 * Return Value: NONE.
1650 */
1651
1652static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
1653{
1654 XENA_dev_config_t __iomem *bar0 = nic->bar0;
1655 register u64 val64 = 0, temp64 = 0;
1656
1657 /* Top level interrupt classification */
1658 /* PIC Interrupts */
1659 if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
1660 /* Enable PIC Intrs in the general intr mask register */
1661 val64 = TXPIC_INT_M | PIC_RX_INT_M;
1662 if (flag == ENABLE_INTRS) {
1663 temp64 = readq(&bar0->general_int_mask);
1664 temp64 &= ~((u64) val64);
1665 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001666 /*
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001667 * If Hercules adapter enable GPIO otherwise
Ananda Rajub41477f2006-07-24 19:52:49 -04001668 * disable all PCIX, Flash, MDIO, IIC and GPIO
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001669 * interrupts for now.
1670 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001672 if (s2io_link_fault_indication(nic) ==
1673 LINK_UP_DOWN_INTERRUPT ) {
1674 temp64 = readq(&bar0->pic_int_mask);
1675 temp64 &= ~((u64) PIC_INT_GPIO);
1676 writeq(temp64, &bar0->pic_int_mask);
1677 temp64 = readq(&bar0->gpio_int_mask);
1678 temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP);
1679 writeq(temp64, &bar0->gpio_int_mask);
1680 } else {
1681 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
1682 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001683 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 * No MSI Support is available presently, so TTI and
1685 * RTI interrupts are also disabled.
1686 */
1687 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001688 /*
1689 * Disable PIC Intrs in the general
1690 * intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 */
1692 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
1693 temp64 = readq(&bar0->general_int_mask);
1694 val64 |= temp64;
1695 writeq(val64, &bar0->general_int_mask);
1696 }
1697 }
1698
1699 /* DMA Interrupts */
1700 /* Enabling/Disabling Tx DMA interrupts */
1701 if (mask & TX_DMA_INTR) {
1702 /* Enable TxDMA Intrs in the general intr mask register */
1703 val64 = TXDMA_INT_M;
1704 if (flag == ENABLE_INTRS) {
1705 temp64 = readq(&bar0->general_int_mask);
1706 temp64 &= ~((u64) val64);
1707 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001708 /*
1709 * Keep all interrupts other than PFC interrupt
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 * and PCC interrupt disabled in DMA level.
1711 */
1712 val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M |
1713 TXDMA_PCC_INT_M);
1714 writeq(val64, &bar0->txdma_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001715 /*
1716 * Enable only the MISC error 1 interrupt in PFC block
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 */
1718 val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1);
1719 writeq(val64, &bar0->pfc_err_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001720 /*
1721 * Enable only the FB_ECC error interrupt in PCC block
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 */
1723 val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR);
1724 writeq(val64, &bar0->pcc_err_mask);
1725 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001726 /*
1727 * Disable TxDMA Intrs in the general intr mask
1728 * register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 */
1730 writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask);
1731 writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask);
1732 temp64 = readq(&bar0->general_int_mask);
1733 val64 |= temp64;
1734 writeq(val64, &bar0->general_int_mask);
1735 }
1736 }
1737
1738 /* Enabling/Disabling Rx DMA interrupts */
1739 if (mask & RX_DMA_INTR) {
1740 /* Enable RxDMA Intrs in the general intr mask register */
1741 val64 = RXDMA_INT_M;
1742 if (flag == ENABLE_INTRS) {
1743 temp64 = readq(&bar0->general_int_mask);
1744 temp64 &= ~((u64) val64);
1745 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001746 /*
1747 * All RxDMA block interrupts are disabled for now
1748 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 */
1750 writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
1751 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001752 /*
1753 * Disable RxDMA Intrs in the general intr mask
1754 * register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 */
1756 writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
1757 temp64 = readq(&bar0->general_int_mask);
1758 val64 |= temp64;
1759 writeq(val64, &bar0->general_int_mask);
1760 }
1761 }
1762
1763 /* MAC Interrupts */
1764 /* Enabling/Disabling MAC interrupts */
1765 if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
1766 val64 = TXMAC_INT_M | RXMAC_INT_M;
1767 if (flag == ENABLE_INTRS) {
1768 temp64 = readq(&bar0->general_int_mask);
1769 temp64 &= ~((u64) val64);
1770 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001771 /*
1772 * All MAC block error interrupts are disabled for now
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 * TODO
1774 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001776 /*
1777 * Disable MAC Intrs in the general intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 */
1779 writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask);
1780 writeq(DISABLE_ALL_INTRS,
1781 &bar0->mac_rmac_err_mask);
1782
1783 temp64 = readq(&bar0->general_int_mask);
1784 val64 |= temp64;
1785 writeq(val64, &bar0->general_int_mask);
1786 }
1787 }
1788
1789 /* XGXS Interrupts */
1790 if (mask & (TX_XGXS_INTR | RX_XGXS_INTR)) {
1791 val64 = TXXGXS_INT_M | RXXGXS_INT_M;
1792 if (flag == ENABLE_INTRS) {
1793 temp64 = readq(&bar0->general_int_mask);
1794 temp64 &= ~((u64) val64);
1795 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001796 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 * All XGXS block error interrupts are disabled for now
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001798 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 */
1800 writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
1801 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001802 /*
1803 * Disable MC Intrs in the general intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 */
1805 writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
1806 temp64 = readq(&bar0->general_int_mask);
1807 val64 |= temp64;
1808 writeq(val64, &bar0->general_int_mask);
1809 }
1810 }
1811
1812 /* Memory Controller(MC) interrupts */
1813 if (mask & MC_INTR) {
1814 val64 = MC_INT_M;
1815 if (flag == ENABLE_INTRS) {
1816 temp64 = readq(&bar0->general_int_mask);
1817 temp64 &= ~((u64) val64);
1818 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001819 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001820 * Enable all MC Intrs.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 */
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001822 writeq(0x0, &bar0->mc_int_mask);
1823 writeq(0x0, &bar0->mc_err_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 } else if (flag == DISABLE_INTRS) {
1825 /*
1826 * Disable MC Intrs in the general intr mask register
1827 */
1828 writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask);
1829 temp64 = readq(&bar0->general_int_mask);
1830 val64 |= temp64;
1831 writeq(val64, &bar0->general_int_mask);
1832 }
1833 }
1834
1835
1836 /* Tx traffic interrupts */
1837 if (mask & TX_TRAFFIC_INTR) {
1838 val64 = TXTRAFFIC_INT_M;
1839 if (flag == ENABLE_INTRS) {
1840 temp64 = readq(&bar0->general_int_mask);
1841 temp64 &= ~((u64) val64);
1842 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001843 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 * Enable all the Tx side interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001845 * writing 0 Enables all 64 TX interrupt levels
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 */
1847 writeq(0x0, &bar0->tx_traffic_mask);
1848 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001849 /*
1850 * Disable Tx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 * register.
1852 */
1853 writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask);
1854 temp64 = readq(&bar0->general_int_mask);
1855 val64 |= temp64;
1856 writeq(val64, &bar0->general_int_mask);
1857 }
1858 }
1859
1860 /* Rx traffic interrupts */
1861 if (mask & RX_TRAFFIC_INTR) {
1862 val64 = RXTRAFFIC_INT_M;
1863 if (flag == ENABLE_INTRS) {
1864 temp64 = readq(&bar0->general_int_mask);
1865 temp64 &= ~((u64) val64);
1866 writeq(temp64, &bar0->general_int_mask);
1867 /* writing 0 Enables all 8 RX interrupt levels */
1868 writeq(0x0, &bar0->rx_traffic_mask);
1869 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001870 /*
1871 * Disable Rx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 * register.
1873 */
1874 writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask);
1875 temp64 = readq(&bar0->general_int_mask);
1876 val64 |= temp64;
1877 writeq(val64, &bar0->general_int_mask);
1878 }
1879 }
1880}
1881
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001882/**
1883 * verify_pcc_quiescent- Checks for PCC quiescent state
1884 * Return: 1 If PCC is quiescence
1885 * 0 If PCC is not quiescence
1886 */
1887static int verify_pcc_quiescent(nic_t *sp, int flag)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001888{
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001889 int ret = 0, herc;
1890 XENA_dev_config_t __iomem *bar0 = sp->bar0;
1891 u64 val64 = readq(&bar0->adapter_status);
1892
1893 herc = (sp->device_type == XFRAME_II_DEVICE);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001894
1895 if (flag == FALSE) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001896 if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
1897 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001898 ret = 1;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001899 } else {
1900 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001901 ret = 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001902 }
1903 } else {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001904 if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001905 if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001906 ADAPTER_STATUS_RMAC_PCC_IDLE))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001907 ret = 1;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001908 } else {
1909 if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001910 ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001911 ret = 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001912 }
1913 }
1914
1915 return ret;
1916}
1917/**
1918 * verify_xena_quiescence - Checks whether the H/W is ready
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 * Description: Returns whether the H/W is ready to go or not. Depending
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001920 * on whether adapter enable bit was written or not the comparison
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 * differs and the calling function passes the input argument flag to
1922 * indicate this.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001923 * Return: 1 If xena is quiescence
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 * 0 If Xena is not quiescence
1925 */
1926
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001927static int verify_xena_quiescence(nic_t *sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928{
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001929 int mode;
1930 XENA_dev_config_t __iomem *bar0 = sp->bar0;
1931 u64 val64 = readq(&bar0->adapter_status);
1932 mode = s2io_verify_pci_mode(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001934 if (!(val64 & ADAPTER_STATUS_TDMA_READY)) {
1935 DBG_PRINT(ERR_DBG, "%s", "TDMA is not ready!");
1936 return 0;
1937 }
1938 if (!(val64 & ADAPTER_STATUS_RDMA_READY)) {
1939 DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!");
1940 return 0;
1941 }
1942 if (!(val64 & ADAPTER_STATUS_PFC_READY)) {
1943 DBG_PRINT(ERR_DBG, "%s", "PFC is not ready!");
1944 return 0;
1945 }
1946 if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) {
1947 DBG_PRINT(ERR_DBG, "%s", "TMAC BUF is not empty!");
1948 return 0;
1949 }
1950 if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) {
1951 DBG_PRINT(ERR_DBG, "%s", "PIC is not QUIESCENT!");
1952 return 0;
1953 }
1954 if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) {
1955 DBG_PRINT(ERR_DBG, "%s", "MC_DRAM is not ready!");
1956 return 0;
1957 }
1958 if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) {
1959 DBG_PRINT(ERR_DBG, "%s", "MC_QUEUES is not ready!");
1960 return 0;
1961 }
1962 if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) {
1963 DBG_PRINT(ERR_DBG, "%s", "M_PLL is not locked!");
1964 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 }
1966
Sivakumar Subramani19a60522007-01-31 13:30:49 -05001967 /*
1968 * In PCI 33 mode, the P_PLL is not used, and therefore,
1969 * the the P_PLL_LOCK bit in the adapter_status register will
1970 * not be asserted.
1971 */
1972 if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) &&
1973 sp->device_type == XFRAME_II_DEVICE && mode !=
1974 PCI_MODE_PCI_33) {
1975 DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!");
1976 return 0;
1977 }
1978 if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1979 ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
1980 DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!");
1981 return 0;
1982 }
1983 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984}
1985
1986/**
1987 * fix_mac_address - Fix for Mac addr problem on Alpha platforms
1988 * @sp: Pointer to device specifc structure
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001989 * Description :
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 * New procedure to clear mac address reading problems on Alpha platforms
1991 *
1992 */
1993
Adrian Bunkac1f60d2005-11-06 01:46:47 +01001994static void fix_mac_address(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995{
1996 XENA_dev_config_t __iomem *bar0 = sp->bar0;
1997 u64 val64;
1998 int i = 0;
1999
2000 while (fix_mac[i] != END_SIGN) {
2001 writeq(fix_mac[i++], &bar0->gpio_control);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002002 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 val64 = readq(&bar0->gpio_control);
2004 }
2005}
2006
2007/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002008 * start_nic - Turns the device on
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002010 * Description:
2011 * This function actually turns the device on. Before this function is
2012 * called,all Registers are configured from their reset states
2013 * and shared memory is allocated but the NIC is still quiescent. On
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 * calling this function, the device interrupts are cleared and the NIC is
2015 * literally switched on by writing into the adapter control register.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002016 * Return Value:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 * SUCCESS on success and -1 on failure.
2018 */
2019
2020static int start_nic(struct s2io_nic *nic)
2021{
2022 XENA_dev_config_t __iomem *bar0 = nic->bar0;
2023 struct net_device *dev = nic->dev;
2024 register u64 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002025 u16 subid, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 mac_info_t *mac_control;
2027 struct config_param *config;
2028
2029 mac_control = &nic->mac_control;
2030 config = &nic->config;
2031
2032 /* PRC Initialization and configuration */
2033 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002034 writeq((u64) mac_control->rings[i].rx_blocks[0].block_dma_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 &bar0->prc_rxd0_n[i]);
2036
2037 val64 = readq(&bar0->prc_ctrl_n[i]);
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07002038 if (nic->config.bimodal)
2039 val64 |= PRC_CTRL_BIMODAL_INTERRUPT;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002040 if (nic->rxd_mode == RXD_MODE_1)
2041 val64 |= PRC_CTRL_RC_ENABLED;
2042 else
2043 val64 |= PRC_CTRL_RC_ENABLED | PRC_CTRL_RING_MODE_3;
Ananda Raju863c11a2006-04-21 19:03:13 -04002044 if (nic->device_type == XFRAME_II_DEVICE)
2045 val64 |= PRC_CTRL_GROUP_READS;
2046 val64 &= ~PRC_CTRL_RXD_BACKOFF_INTERVAL(0xFFFFFF);
2047 val64 |= PRC_CTRL_RXD_BACKOFF_INTERVAL(0x1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 writeq(val64, &bar0->prc_ctrl_n[i]);
2049 }
2050
Ananda Rajuda6971d2005-10-31 16:55:31 -05002051 if (nic->rxd_mode == RXD_MODE_3B) {
2052 /* Enabling 2 buffer mode by writing into Rx_pa_cfg reg. */
2053 val64 = readq(&bar0->rx_pa_cfg);
2054 val64 |= RX_PA_CFG_IGNORE_L2_ERR;
2055 writeq(val64, &bar0->rx_pa_cfg);
2056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002058 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 * Enabling MC-RLDRAM. After enabling the device, we timeout
2060 * for around 100ms, which is approximately the time required
2061 * for the device to be ready for operation.
2062 */
2063 val64 = readq(&bar0->mc_rldram_mrs);
2064 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE | MC_RLDRAM_MRS_ENABLE;
2065 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
2066 val64 = readq(&bar0->mc_rldram_mrs);
2067
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002068 msleep(100); /* Delay by around 100 ms. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
2070 /* Enabling ECC Protection. */
2071 val64 = readq(&bar0->adapter_control);
2072 val64 &= ~ADAPTER_ECC_EN;
2073 writeq(val64, &bar0->adapter_control);
2074
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002075 /*
2076 * Clearing any possible Link state change interrupts that
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 * could have popped up just before Enabling the card.
2078 */
2079 val64 = readq(&bar0->mac_rmac_err_reg);
2080 if (val64)
2081 writeq(val64, &bar0->mac_rmac_err_reg);
2082
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002083 /*
2084 * Verify if the device is ready to be enabled, if so enable
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 * it.
2086 */
2087 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002088 if (!verify_xena_quiescence(nic)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name);
2090 DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n",
2091 (unsigned long long) val64);
2092 return FAILURE;
2093 }
2094
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002095 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 * With some switches, link might be already up at this point.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002097 * Because of this weird behavior, when we enable laser,
2098 * we may not get link. We need to handle this. We cannot
2099 * figure out which switch is misbehaving. So we are forced to
2100 * make a global change.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 */
2102
2103 /* Enabling Laser. */
2104 val64 = readq(&bar0->adapter_control);
2105 val64 |= ADAPTER_EOI_TX_ON;
2106 writeq(val64, &bar0->adapter_control);
2107
Ananda Rajuc92ca042006-04-21 19:18:03 -04002108 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
2109 /*
2110 * Dont see link state interrupts initally on some switches,
2111 * so directly scheduling the link state task here.
2112 */
2113 schedule_work(&nic->set_link_task);
2114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 /* SXE-002: Initialize link and activity LED */
2116 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07002117 if (((subid & 0xFF) >= 0x07) &&
2118 (nic->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 val64 = readq(&bar0->gpio_control);
2120 val64 |= 0x0000800000000000ULL;
2121 writeq(val64, &bar0->gpio_control);
2122 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01002123 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 }
2125
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 return SUCCESS;
2127}
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002128/**
2129 * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb
2130 */
2131static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, int get_off)
2132{
2133 nic_t *nic = fifo_data->nic;
2134 struct sk_buff *skb;
2135 TxD_t *txds;
2136 u16 j, frg_cnt;
2137
2138 txds = txdlp;
Andrew Morton26b76252005-12-14 19:25:23 -08002139 if (txds->Host_Control == (u64)(long)nic->ufo_in_band_v) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002140 pci_unmap_single(nic->pdev, (dma_addr_t)
2141 txds->Buffer_Pointer, sizeof(u64),
2142 PCI_DMA_TODEVICE);
2143 txds++;
2144 }
2145
2146 skb = (struct sk_buff *) ((unsigned long)
2147 txds->Host_Control);
2148 if (!skb) {
2149 memset(txdlp, 0, (sizeof(TxD_t) * fifo_data->max_txds));
2150 return NULL;
2151 }
2152 pci_unmap_single(nic->pdev, (dma_addr_t)
2153 txds->Buffer_Pointer,
2154 skb->len - skb->data_len,
2155 PCI_DMA_TODEVICE);
2156 frg_cnt = skb_shinfo(skb)->nr_frags;
2157 if (frg_cnt) {
2158 txds++;
2159 for (j = 0; j < frg_cnt; j++, txds++) {
2160 skb_frag_t *frag = &skb_shinfo(skb)->frags[j];
2161 if (!txds->Buffer_Pointer)
2162 break;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002163 pci_unmap_page(nic->pdev, (dma_addr_t)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002164 txds->Buffer_Pointer,
2165 frag->size, PCI_DMA_TODEVICE);
2166 }
2167 }
Ananda Rajub41477f2006-07-24 19:52:49 -04002168 memset(txdlp,0, (sizeof(TxD_t) * fifo_data->max_txds));
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002169 return(skb);
2170}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002172/**
2173 * free_tx_buffers - Free all queued Tx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002175 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 * Free all queued Tx buffers.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002177 * Return Value: void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178*/
2179
2180static void free_tx_buffers(struct s2io_nic *nic)
2181{
2182 struct net_device *dev = nic->dev;
2183 struct sk_buff *skb;
2184 TxD_t *txdp;
2185 int i, j;
2186 mac_info_t *mac_control;
2187 struct config_param *config;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002188 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189
2190 mac_control = &nic->mac_control;
2191 config = &nic->config;
2192
2193 for (i = 0; i < config->tx_fifo_num; i++) {
2194 for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002195 txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 list_virt_addr;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002197 skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
2198 if (skb) {
2199 dev_kfree_skb(skb);
2200 cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 }
2203 DBG_PRINT(INTR_DBG,
2204 "%s:forcibly freeing %d skbs on FIFO%d\n",
2205 dev->name, cnt, i);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002206 mac_control->fifos[i].tx_curr_get_info.offset = 0;
2207 mac_control->fifos[i].tx_curr_put_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 }
2209}
2210
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002211/**
2212 * stop_nic - To stop the nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 * @nic ; device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002214 * Description:
2215 * This function does exactly the opposite of what the start_nic()
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 * function does. This function is called to stop the device.
2217 * Return Value:
2218 * void.
2219 */
2220
2221static void stop_nic(struct s2io_nic *nic)
2222{
2223 XENA_dev_config_t __iomem *bar0 = nic->bar0;
2224 register u64 val64 = 0;
Ananda Raju5d3213c2006-04-21 19:23:26 -04002225 u16 interruptible;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 mac_info_t *mac_control;
2227 struct config_param *config;
2228
2229 mac_control = &nic->mac_control;
2230 config = &nic->config;
2231
2232 /* Disable all interrupts */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002233 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07002234 interruptible |= TX_PIC_INTR | RX_PIC_INTR;
2235 interruptible |= TX_MAC_INTR | RX_MAC_INTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
2237
Ananda Raju5d3213c2006-04-21 19:23:26 -04002238 /* Clearing Adapter_En bit of ADAPTER_CONTROL Register */
2239 val64 = readq(&bar0->adapter_control);
2240 val64 &= ~(ADAPTER_CNTL_EN);
2241 writeq(val64, &bar0->adapter_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242}
2243
Adrian Bunk26df54b2006-01-14 03:09:40 +01002244static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
Ananda Rajuda6971d2005-10-31 16:55:31 -05002245{
2246 struct net_device *dev = nic->dev;
2247 struct sk_buff *frag_list;
Jeff Garzik50eb8002005-11-05 23:40:46 -05002248 void *tmp;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002249
2250 /* Buffer-1 receives L3/L4 headers */
2251 ((RxD3_t*)rxdp)->Buffer1_ptr = pci_map_single
2252 (nic->pdev, skb->data, l3l4hdr_size + 4,
2253 PCI_DMA_FROMDEVICE);
2254
2255 /* skb_shinfo(skb)->frag_list will have L4 data payload */
2256 skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE);
2257 if (skb_shinfo(skb)->frag_list == NULL) {
2258 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
2259 return -ENOMEM ;
2260 }
2261 frag_list = skb_shinfo(skb)->frag_list;
Sivakumar Subramani372cc592007-01-31 13:32:57 -05002262 skb->truesize += frag_list->truesize;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002263 frag_list->next = NULL;
Jeff Garzik50eb8002005-11-05 23:40:46 -05002264 tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
2265 frag_list->data = tmp;
2266 frag_list->tail = tmp;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002267
2268 /* Buffer-2 receives L4 data payload */
2269 ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
2270 frag_list->data, dev->mtu,
2271 PCI_DMA_FROMDEVICE);
2272 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
2273 rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
2274
2275 return SUCCESS;
2276}
2277
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002278/**
2279 * fill_rx_buffers - Allocates the Rx side skbs
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002281 * @ring_no: ring number
2282 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 * The function allocates Rx side skbs and puts the physical
2284 * address of these buffers into the RxD buffer pointers, so that the NIC
2285 * can DMA the received frame into these locations.
2286 * The NIC supports 3 receive modes, viz
2287 * 1. single buffer,
2288 * 2. three buffer and
2289 * 3. Five buffer modes.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002290 * Each mode defines how many fragments the received frame will be split
2291 * up into by the NIC. The frame is split into L3 header, L4 Header,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 * L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself
2293 * is split into 3 fragments. As of now only single buffer mode is
2294 * supported.
2295 * Return Value:
2296 * SUCCESS on success or an appropriate -ve value on failure.
2297 */
2298
Adrian Bunkac1f60d2005-11-06 01:46:47 +01002299static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300{
2301 struct net_device *dev = nic->dev;
2302 struct sk_buff *skb;
2303 RxD_t *rxdp;
2304 int off, off1, size, block_no, block_no1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 u32 alloc_tab = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002306 u32 alloc_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 mac_info_t *mac_control;
2308 struct config_param *config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002309 u64 tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 buffAdd_t *ba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 unsigned long flags;
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002312 RxD_t *first_rxdp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
2314 mac_control = &nic->mac_control;
2315 config = &nic->config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002316 alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
2317 atomic_read(&nic->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
Ananda Raju5d3213c2006-04-21 19:23:26 -04002319 block_no1 = mac_control->rings[ring_no].rx_curr_get_info.block_index;
Ananda Raju863c11a2006-04-21 19:03:13 -04002320 off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 while (alloc_tab < alloc_cnt) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002322 block_no = mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 block_index;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002324 off = mac_control->rings[ring_no].rx_curr_put_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325
Ananda Rajuda6971d2005-10-31 16:55:31 -05002326 rxdp = mac_control->rings[ring_no].
2327 rx_blocks[block_no].rxds[off].virt_addr;
2328
2329 if ((block_no == block_no1) && (off == off1) &&
2330 (rxdp->Host_Control)) {
2331 DBG_PRINT(INTR_DBG, "%s: Get and Put",
2332 dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 DBG_PRINT(INTR_DBG, " info equated\n");
2334 goto end;
2335 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002336 if (off && (off == rxd_count[nic->rxd_mode])) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002337 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 block_index++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002339 if (mac_control->rings[ring_no].rx_curr_put_info.
2340 block_index == mac_control->rings[ring_no].
2341 block_count)
2342 mac_control->rings[ring_no].rx_curr_put_info.
2343 block_index = 0;
2344 block_no = mac_control->rings[ring_no].
2345 rx_curr_put_info.block_index;
2346 if (off == rxd_count[nic->rxd_mode])
2347 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002348 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002349 offset = off;
2350 rxdp = mac_control->rings[ring_no].
2351 rx_blocks[block_no].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
2353 dev->name, rxdp);
2354 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002355 if(!napi) {
2356 spin_lock_irqsave(&nic->put_lock, flags);
2357 mac_control->rings[ring_no].put_pos =
2358 (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
2359 spin_unlock_irqrestore(&nic->put_lock, flags);
2360 } else {
2361 mac_control->rings[ring_no].put_pos =
2362 (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
2363 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002364 if ((rxdp->Control_1 & RXD_OWN_XENA) &&
2365 ((nic->rxd_mode >= RXD_MODE_3A) &&
2366 (rxdp->Control_2 & BIT(0)))) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002367 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002368 offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 goto end;
2370 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002371 /* calculate size of skb based on ring mode */
2372 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
2373 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
2374 if (nic->rxd_mode == RXD_MODE_1)
2375 size += NET_IP_ALIGN;
2376 else if (nic->rxd_mode == RXD_MODE_3B)
2377 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
2378 else
2379 size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380
Ananda Rajuda6971d2005-10-31 16:55:31 -05002381 /* allocate skb */
2382 skb = dev_alloc_skb(size);
2383 if(!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
2385 DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002386 if (first_rxdp) {
2387 wmb();
2388 first_rxdp->Control_1 |= RXD_OWN_XENA;
2389 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002390 return -ENOMEM ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002392 if (nic->rxd_mode == RXD_MODE_1) {
2393 /* 1 buffer mode - normal operation mode */
2394 memset(rxdp, 0, sizeof(RxD1_t));
2395 skb_reserve(skb, NET_IP_ALIGN);
2396 ((RxD1_t*)rxdp)->Buffer0_ptr = pci_map_single
Ananda Raju863c11a2006-04-21 19:03:13 -04002397 (nic->pdev, skb->data, size - NET_IP_ALIGN,
2398 PCI_DMA_FROMDEVICE);
2399 rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002400
2401 } else if (nic->rxd_mode >= RXD_MODE_3A) {
2402 /*
2403 * 2 or 3 buffer mode -
2404 * Both 2 buffer mode and 3 buffer mode provides 128
2405 * byte aligned receive buffers.
2406 *
2407 * 3 buffer mode provides header separation where in
2408 * skb->data will have L3/L4 headers where as
2409 * skb_shinfo(skb)->frag_list will have the L4 data
2410 * payload
2411 */
2412
2413 memset(rxdp, 0, sizeof(RxD3_t));
2414 ba = &mac_control->rings[ring_no].ba[block_no][off];
2415 skb_reserve(skb, BUF0_LEN);
2416 tmp = (u64)(unsigned long) skb->data;
2417 tmp += ALIGN_SIZE;
2418 tmp &= ~ALIGN_SIZE;
2419 skb->data = (void *) (unsigned long)tmp;
2420 skb->tail = (void *) (unsigned long)tmp;
2421
Ananda Raju75c30b12006-07-24 19:55:09 -04002422 if (!(((RxD3_t*)rxdp)->Buffer0_ptr))
2423 ((RxD3_t*)rxdp)->Buffer0_ptr =
2424 pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002425 PCI_DMA_FROMDEVICE);
Ananda Raju75c30b12006-07-24 19:55:09 -04002426 else
2427 pci_dma_sync_single_for_device(nic->pdev,
2428 (dma_addr_t) ((RxD3_t*)rxdp)->Buffer0_ptr,
2429 BUF0_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002430 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
2431 if (nic->rxd_mode == RXD_MODE_3B) {
2432 /* Two buffer mode */
2433
2434 /*
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002435 * Buffer2 will have L3/L4 header plus
Ananda Rajuda6971d2005-10-31 16:55:31 -05002436 * L4 payload
2437 */
2438 ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single
2439 (nic->pdev, skb->data, dev->mtu + 4,
2440 PCI_DMA_FROMDEVICE);
2441
Ananda Raju75c30b12006-07-24 19:55:09 -04002442 /* Buffer-1 will be dummy buffer. Not used */
2443 if (!(((RxD3_t*)rxdp)->Buffer1_ptr)) {
2444 ((RxD3_t*)rxdp)->Buffer1_ptr =
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002445 pci_map_single(nic->pdev,
Ananda Raju75c30b12006-07-24 19:55:09 -04002446 ba->ba_1, BUF1_LEN,
2447 PCI_DMA_FROMDEVICE);
2448 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002449 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
2450 rxdp->Control_2 |= SET_BUFFER2_SIZE_3
2451 (dev->mtu + 4);
2452 } else {
2453 /* 3 buffer mode */
2454 if (fill_rxd_3buf(nic, rxdp, skb) == -ENOMEM) {
2455 dev_kfree_skb_irq(skb);
2456 if (first_rxdp) {
2457 wmb();
2458 first_rxdp->Control_1 |=
2459 RXD_OWN_XENA;
2460 }
2461 return -ENOMEM ;
2462 }
2463 }
2464 rxdp->Control_2 |= BIT(0);
2465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 rxdp->Host_Control = (unsigned long) (skb);
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002467 if (alloc_tab & ((1 << rxsync_frequency) - 1))
2468 rxdp->Control_1 |= RXD_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 off++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002470 if (off == (rxd_count[nic->rxd_mode] + 1))
2471 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002472 mac_control->rings[ring_no].rx_curr_put_info.offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002474 rxdp->Control_2 |= SET_RXD_MARKER;
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002475 if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
2476 if (first_rxdp) {
2477 wmb();
2478 first_rxdp->Control_1 |= RXD_OWN_XENA;
2479 }
2480 first_rxdp = rxdp;
2481 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 atomic_inc(&nic->rx_bufs_left[ring_no]);
2483 alloc_tab++;
2484 }
2485
2486 end:
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002487 /* Transfer ownership of first descriptor to adapter just before
2488 * exiting. Before that, use memory barrier so that ownership
2489 * and other fields are seen by adapter correctly.
2490 */
2491 if (first_rxdp) {
2492 wmb();
2493 first_rxdp->Control_1 |= RXD_OWN_XENA;
2494 }
2495
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 return SUCCESS;
2497}
2498
Ananda Rajuda6971d2005-10-31 16:55:31 -05002499static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
2500{
2501 struct net_device *dev = sp->dev;
2502 int j;
2503 struct sk_buff *skb;
2504 RxD_t *rxdp;
2505 mac_info_t *mac_control;
2506 buffAdd_t *ba;
2507
2508 mac_control = &sp->mac_control;
2509 for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
2510 rxdp = mac_control->rings[ring_no].
2511 rx_blocks[blk].rxds[j].virt_addr;
2512 skb = (struct sk_buff *)
2513 ((unsigned long) rxdp->Host_Control);
2514 if (!skb) {
2515 continue;
2516 }
2517 if (sp->rxd_mode == RXD_MODE_1) {
2518 pci_unmap_single(sp->pdev, (dma_addr_t)
2519 ((RxD1_t*)rxdp)->Buffer0_ptr,
2520 dev->mtu +
2521 HEADER_ETHERNET_II_802_3_SIZE
2522 + HEADER_802_2_SIZE +
2523 HEADER_SNAP_SIZE,
2524 PCI_DMA_FROMDEVICE);
2525 memset(rxdp, 0, sizeof(RxD1_t));
2526 } else if(sp->rxd_mode == RXD_MODE_3B) {
2527 ba = &mac_control->rings[ring_no].
2528 ba[blk][j];
2529 pci_unmap_single(sp->pdev, (dma_addr_t)
2530 ((RxD3_t*)rxdp)->Buffer0_ptr,
2531 BUF0_LEN,
2532 PCI_DMA_FROMDEVICE);
2533 pci_unmap_single(sp->pdev, (dma_addr_t)
2534 ((RxD3_t*)rxdp)->Buffer1_ptr,
2535 BUF1_LEN,
2536 PCI_DMA_FROMDEVICE);
2537 pci_unmap_single(sp->pdev, (dma_addr_t)
2538 ((RxD3_t*)rxdp)->Buffer2_ptr,
2539 dev->mtu + 4,
2540 PCI_DMA_FROMDEVICE);
2541 memset(rxdp, 0, sizeof(RxD3_t));
2542 } else {
2543 pci_unmap_single(sp->pdev, (dma_addr_t)
2544 ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
2545 PCI_DMA_FROMDEVICE);
2546 pci_unmap_single(sp->pdev, (dma_addr_t)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002547 ((RxD3_t*)rxdp)->Buffer1_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002548 l3l4hdr_size + 4,
2549 PCI_DMA_FROMDEVICE);
2550 pci_unmap_single(sp->pdev, (dma_addr_t)
2551 ((RxD3_t*)rxdp)->Buffer2_ptr, dev->mtu,
2552 PCI_DMA_FROMDEVICE);
2553 memset(rxdp, 0, sizeof(RxD3_t));
2554 }
2555 dev_kfree_skb(skb);
2556 atomic_dec(&sp->rx_bufs_left[ring_no]);
2557 }
2558}
2559
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002561 * free_rx_buffers - Frees all Rx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 * @sp: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002563 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 * This function will free all Rx buffers allocated by host.
2565 * Return Value:
2566 * NONE.
2567 */
2568
2569static void free_rx_buffers(struct s2io_nic *sp)
2570{
2571 struct net_device *dev = sp->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002572 int i, blk = 0, buf_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 mac_info_t *mac_control;
2574 struct config_param *config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575
2576 mac_control = &sp->mac_control;
2577 config = &sp->config;
2578
2579 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -05002580 for (blk = 0; blk < rx_ring_sz[i]; blk++)
2581 free_rxd_blk(sp,i,blk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002583 mac_control->rings[i].rx_curr_put_info.block_index = 0;
2584 mac_control->rings[i].rx_curr_get_info.block_index = 0;
2585 mac_control->rings[i].rx_curr_put_info.offset = 0;
2586 mac_control->rings[i].rx_curr_get_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 atomic_set(&sp->rx_bufs_left[i], 0);
2588 DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
2589 dev->name, buf_cnt, i);
2590 }
2591}
2592
2593/**
2594 * s2io_poll - Rx interrupt handler for NAPI support
2595 * @dev : pointer to the device structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002596 * @budget : The number of packets that were budgeted to be processed
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 * during one pass through the 'Poll" function.
2598 * Description:
2599 * Comes into picture only if NAPI support has been incorporated. It does
2600 * the same thing that rx_intr_handler does, but not in a interrupt context
2601 * also It will process only a given number of packets.
2602 * Return value:
2603 * 0 on success and 1 if there are No Rx packets to be processed.
2604 */
2605
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606static int s2io_poll(struct net_device *dev, int *budget)
2607{
2608 nic_t *nic = dev->priv;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002609 int pkt_cnt = 0, org_pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 mac_info_t *mac_control;
2611 struct config_param *config;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01002612 XENA_dev_config_t __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002613 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002615 atomic_inc(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 mac_control = &nic->mac_control;
2617 config = &nic->config;
2618
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002619 nic->pkts_to_process = *budget;
2620 if (nic->pkts_to_process > dev->quota)
2621 nic->pkts_to_process = dev->quota;
2622 org_pkts_to_process = nic->pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002624 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
2625 readl(&bar0->rx_traffic_int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626
2627 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002628 rx_intr_handler(&mac_control->rings[i]);
2629 pkt_cnt = org_pkts_to_process - nic->pkts_to_process;
2630 if (!nic->pkts_to_process) {
2631 /* Quota for the current iteration has been met */
2632 goto no_rx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 }
2635 if (!pkt_cnt)
2636 pkt_cnt = 1;
2637
2638 dev->quota -= pkt_cnt;
2639 *budget -= pkt_cnt;
2640 netif_rx_complete(dev);
2641
2642 for (i = 0; i < config->rx_ring_num; i++) {
2643 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2644 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2645 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2646 break;
2647 }
2648 }
2649 /* Re enable the Rx interrupts. */
Ananda Rajuc92ca042006-04-21 19:18:03 -04002650 writeq(0x0, &bar0->rx_traffic_mask);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002651 readl(&bar0->rx_traffic_mask);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002652 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 return 0;
2654
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002655no_rx:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 dev->quota -= pkt_cnt;
2657 *budget -= pkt_cnt;
2658
2659 for (i = 0; i < config->rx_ring_num; i++) {
2660 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2661 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2662 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2663 break;
2664 }
2665 }
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002666 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 return 1;
2668}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002669
Ananda Rajub41477f2006-07-24 19:52:49 -04002670#ifdef CONFIG_NET_POLL_CONTROLLER
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002671/**
Ananda Rajub41477f2006-07-24 19:52:49 -04002672 * s2io_netpoll - netpoll event handler entry point
Brian Haley612eff02006-06-15 14:36:36 -04002673 * @dev : pointer to the device structure.
2674 * Description:
Ananda Rajub41477f2006-07-24 19:52:49 -04002675 * This function will be called by upper layer to check for events on the
2676 * interface in situations where interrupts are disabled. It is used for
2677 * specific in-kernel networking tasks, such as remote consoles and kernel
2678 * debugging over the network (example netdump in RedHat).
Brian Haley612eff02006-06-15 14:36:36 -04002679 */
Brian Haley612eff02006-06-15 14:36:36 -04002680static void s2io_netpoll(struct net_device *dev)
2681{
2682 nic_t *nic = dev->priv;
2683 mac_info_t *mac_control;
2684 struct config_param *config;
2685 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ananda Rajub41477f2006-07-24 19:52:49 -04002686 u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
Brian Haley612eff02006-06-15 14:36:36 -04002687 int i;
2688
2689 disable_irq(dev->irq);
2690
2691 atomic_inc(&nic->isr_cnt);
2692 mac_control = &nic->mac_control;
2693 config = &nic->config;
2694
Brian Haley612eff02006-06-15 14:36:36 -04002695 writeq(val64, &bar0->rx_traffic_int);
Ananda Rajub41477f2006-07-24 19:52:49 -04002696 writeq(val64, &bar0->tx_traffic_int);
Brian Haley612eff02006-06-15 14:36:36 -04002697
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002698 /* we need to free up the transmitted skbufs or else netpoll will
Ananda Rajub41477f2006-07-24 19:52:49 -04002699 * run out of skbs and will fail and eventually netpoll application such
2700 * as netdump will fail.
2701 */
2702 for (i = 0; i < config->tx_fifo_num; i++)
2703 tx_intr_handler(&mac_control->fifos[i]);
2704
2705 /* check for received packet and indicate up to network */
Brian Haley612eff02006-06-15 14:36:36 -04002706 for (i = 0; i < config->rx_ring_num; i++)
2707 rx_intr_handler(&mac_control->rings[i]);
2708
2709 for (i = 0; i < config->rx_ring_num; i++) {
2710 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2711 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2712 DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n");
2713 break;
2714 }
2715 }
2716 atomic_dec(&nic->isr_cnt);
2717 enable_irq(dev->irq);
2718 return;
2719}
2720#endif
2721
2722/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 * rx_intr_handler - Rx interrupt handler
2724 * @nic: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002725 * Description:
2726 * If the interrupt is because of a received frame or if the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 * receive ring contains fresh as yet un-processed frames,this function is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002728 * called. It picks out the RxD at which place the last Rx processing had
2729 * stopped and sends the skb to the OSM's Rx handler and then increments
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 * the offset.
2731 * Return Value:
2732 * NONE.
2733 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002734static void rx_intr_handler(ring_info_t *ring_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002736 nic_t *nic = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 struct net_device *dev = (struct net_device *) nic->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002738 int get_block, put_block, put_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 rx_curr_get_info_t get_info, put_info;
2740 RxD_t *rxdp;
2741 struct sk_buff *skb;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002742 int pkt_cnt = 0;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002743 int i;
2744
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002745 spin_lock(&nic->rx_lock);
2746 if (atomic_read(&nic->card_state) == CARD_DOWN) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002747 DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002748 __FUNCTION__, dev->name);
2749 spin_unlock(&nic->rx_lock);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002750 return;
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002751 }
2752
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002753 get_info = ring_data->rx_curr_get_info;
2754 get_block = get_info.block_index;
2755 put_info = ring_data->rx_curr_put_info;
2756 put_block = put_info.block_index;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002757 rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002758 if (!napi) {
2759 spin_lock(&nic->put_lock);
2760 put_offset = ring_data->put_pos;
2761 spin_unlock(&nic->put_lock);
2762 } else
2763 put_offset = ring_data->put_pos;
2764
Ananda Rajuda6971d2005-10-31 16:55:31 -05002765 while (RXD_IS_UP2DT(rxdp)) {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002766 /*
2767 * If your are next to put index then it's
2768 * FIFO full condition
2769 */
Ananda Rajuda6971d2005-10-31 16:55:31 -05002770 if ((get_block == put_block) &&
2771 (get_info.offset + 1) == put_info.offset) {
Ananda Raju75c30b12006-07-24 19:55:09 -04002772 DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002773 break;
2774 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002775 skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
2776 if (skb == NULL) {
2777 DBG_PRINT(ERR_DBG, "%s: The skb is ",
2778 dev->name);
2779 DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002780 spin_unlock(&nic->rx_lock);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002781 return;
2782 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002783 if (nic->rxd_mode == RXD_MODE_1) {
2784 pci_unmap_single(nic->pdev, (dma_addr_t)
2785 ((RxD1_t*)rxdp)->Buffer0_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002786 dev->mtu +
2787 HEADER_ETHERNET_II_802_3_SIZE +
2788 HEADER_802_2_SIZE +
2789 HEADER_SNAP_SIZE,
2790 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002791 } else if (nic->rxd_mode == RXD_MODE_3B) {
Ananda Raju75c30b12006-07-24 19:55:09 -04002792 pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
Ananda Rajuda6971d2005-10-31 16:55:31 -05002793 ((RxD3_t*)rxdp)->Buffer0_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002794 BUF0_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002795 pci_unmap_single(nic->pdev, (dma_addr_t)
Ananda Rajuda6971d2005-10-31 16:55:31 -05002796 ((RxD3_t*)rxdp)->Buffer2_ptr,
2797 dev->mtu + 4,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002798 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002799 } else {
Ananda Raju75c30b12006-07-24 19:55:09 -04002800 pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
Ananda Rajuda6971d2005-10-31 16:55:31 -05002801 ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
2802 PCI_DMA_FROMDEVICE);
2803 pci_unmap_single(nic->pdev, (dma_addr_t)
2804 ((RxD3_t*)rxdp)->Buffer1_ptr,
2805 l3l4hdr_size + 4,
2806 PCI_DMA_FROMDEVICE);
2807 pci_unmap_single(nic->pdev, (dma_addr_t)
2808 ((RxD3_t*)rxdp)->Buffer2_ptr,
2809 dev->mtu, PCI_DMA_FROMDEVICE);
2810 }
Ananda Raju863c11a2006-04-21 19:03:13 -04002811 prefetch(skb->data);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002812 rx_osm_handler(ring_data, rxdp);
2813 get_info.offset++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002814 ring_data->rx_curr_get_info.offset = get_info.offset;
2815 rxdp = ring_data->rx_blocks[get_block].
2816 rxds[get_info.offset].virt_addr;
2817 if (get_info.offset == rxd_count[nic->rxd_mode]) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002818 get_info.offset = 0;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002819 ring_data->rx_curr_get_info.offset = get_info.offset;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002820 get_block++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002821 if (get_block == ring_data->block_count)
2822 get_block = 0;
2823 ring_data->rx_curr_get_info.block_index = get_block;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002824 rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
2825 }
2826
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002827 nic->pkts_to_process -= 1;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002828 if ((napi) && (!nic->pkts_to_process))
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002829 break;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002830 pkt_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
2832 break;
2833 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002834 if (nic->lro) {
2835 /* Clear all LRO sessions before exiting */
2836 for (i=0; i<MAX_LRO_SESSIONS; i++) {
2837 lro_t *lro = &nic->lro0_n[i];
2838 if (lro->in_use) {
2839 update_L3L4_header(nic, lro);
2840 queue_rx_frame(lro->parent);
2841 clear_lro_session(lro);
2842 }
2843 }
2844 }
2845
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002846 spin_unlock(&nic->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002848
2849/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 * tx_intr_handler - Transmit interrupt handler
2851 * @nic : device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002852 * Description:
2853 * If an interrupt was raised to indicate DMA complete of the
2854 * Tx packet, this function is called. It identifies the last TxD
2855 * whose buffer was freed and frees all skbs whose data have already
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 * DMA'ed into the NICs internal memory.
2857 * Return Value:
2858 * NONE
2859 */
2860
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002861static void tx_intr_handler(fifo_info_t *fifo_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002863 nic_t *nic = fifo_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 struct net_device *dev = (struct net_device *) nic->dev;
2865 tx_curr_get_info_t get_info, put_info;
2866 struct sk_buff *skb;
2867 TxD_t *txdlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002869 get_info = fifo_data->tx_curr_get_info;
2870 put_info = fifo_data->tx_curr_put_info;
2871 txdlp = (TxD_t *) fifo_data->list_info[get_info.offset].
2872 list_virt_addr;
2873 while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
2874 (get_info.offset != put_info.offset) &&
2875 (txdlp->Host_Control)) {
2876 /* Check for TxD errors */
2877 if (txdlp->Control_1 & TXD_T_CODE) {
2878 unsigned long long err;
2879 err = txdlp->Control_1 & TXD_T_CODE;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002880 if (err & 0x1) {
2881 nic->mac_control.stats_info->sw_stat.
2882 parity_err_cnt++;
2883 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002884 if ((err >> 48) == 0xA) {
2885 DBG_PRINT(TX_DBG, "TxD returned due \
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002886 to loss of link\n");
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002887 }
2888 else {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002889 DBG_PRINT(ERR_DBG, "***TxD error %llx\n", err);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002890 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002892
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002893 skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002894 if (skb == NULL) {
2895 DBG_PRINT(ERR_DBG, "%s: Null skb ",
2896 __FUNCTION__);
2897 DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
2898 return;
2899 }
2900
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002901 /* Updating the statistics block */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002902 nic->stats.tx_bytes += skb->len;
2903 dev_kfree_skb_irq(skb);
2904
2905 get_info.offset++;
Ananda Raju863c11a2006-04-21 19:03:13 -04002906 if (get_info.offset == get_info.fifo_len + 1)
2907 get_info.offset = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002908 txdlp = (TxD_t *) fifo_data->list_info
2909 [get_info.offset].list_virt_addr;
2910 fifo_data->tx_curr_get_info.offset =
2911 get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 }
2913
2914 spin_lock(&nic->tx_lock);
2915 if (netif_queue_stopped(dev))
2916 netif_wake_queue(dev);
2917 spin_unlock(&nic->tx_lock);
2918}
2919
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002920/**
Ananda Rajubd1034f2006-04-21 19:20:22 -04002921 * s2io_mdio_write - Function to write in to MDIO registers
2922 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
2923 * @addr : address value
2924 * @value : data value
2925 * @dev : pointer to net_device structure
2926 * Description:
2927 * This function is used to write values to the MDIO registers
2928 * NONE
2929 */
2930static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
2931{
2932 u64 val64 = 0x0;
2933 nic_t *sp = dev->priv;
Al Virocc3afe62006-09-23 01:33:40 +01002934 XENA_dev_config_t __iomem *bar0 = sp->bar0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002935
2936 //address transaction
2937 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2938 | MDIO_MMD_DEV_ADDR(mmd_type)
2939 | MDIO_MMS_PRT_ADDR(0x0);
2940 writeq(val64, &bar0->mdio_control);
2941 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2942 writeq(val64, &bar0->mdio_control);
2943 udelay(100);
2944
2945 //Data transaction
2946 val64 = 0x0;
2947 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2948 | MDIO_MMD_DEV_ADDR(mmd_type)
2949 | MDIO_MMS_PRT_ADDR(0x0)
2950 | MDIO_MDIO_DATA(value)
2951 | MDIO_OP(MDIO_OP_WRITE_TRANS);
2952 writeq(val64, &bar0->mdio_control);
2953 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2954 writeq(val64, &bar0->mdio_control);
2955 udelay(100);
2956
2957 val64 = 0x0;
2958 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2959 | MDIO_MMD_DEV_ADDR(mmd_type)
2960 | MDIO_MMS_PRT_ADDR(0x0)
2961 | MDIO_OP(MDIO_OP_READ_TRANS);
2962 writeq(val64, &bar0->mdio_control);
2963 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2964 writeq(val64, &bar0->mdio_control);
2965 udelay(100);
2966
2967}
2968
2969/**
2970 * s2io_mdio_read - Function to write in to MDIO registers
2971 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
2972 * @addr : address value
2973 * @dev : pointer to net_device structure
2974 * Description:
2975 * This function is used to read values to the MDIO registers
2976 * NONE
2977 */
2978static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
2979{
2980 u64 val64 = 0x0;
2981 u64 rval64 = 0x0;
2982 nic_t *sp = dev->priv;
Al Virocc3afe62006-09-23 01:33:40 +01002983 XENA_dev_config_t __iomem *bar0 = sp->bar0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002984
2985 /* address transaction */
2986 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2987 | MDIO_MMD_DEV_ADDR(mmd_type)
2988 | MDIO_MMS_PRT_ADDR(0x0);
2989 writeq(val64, &bar0->mdio_control);
2990 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2991 writeq(val64, &bar0->mdio_control);
2992 udelay(100);
2993
2994 /* Data transaction */
2995 val64 = 0x0;
2996 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2997 | MDIO_MMD_DEV_ADDR(mmd_type)
2998 | MDIO_MMS_PRT_ADDR(0x0)
2999 | MDIO_OP(MDIO_OP_READ_TRANS);
3000 writeq(val64, &bar0->mdio_control);
3001 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
3002 writeq(val64, &bar0->mdio_control);
3003 udelay(100);
3004
3005 /* Read the value from regs */
3006 rval64 = readq(&bar0->mdio_control);
3007 rval64 = rval64 & 0xFFFF0000;
3008 rval64 = rval64 >> 16;
3009 return rval64;
3010}
3011/**
3012 * s2io_chk_xpak_counter - Function to check the status of the xpak counters
3013 * @counter : couter value to be updated
3014 * @flag : flag to indicate the status
3015 * @type : counter type
3016 * Description:
3017 * This function is to check the status of the xpak counters value
3018 * NONE
3019 */
3020
3021static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, u16 flag, u16 type)
3022{
3023 u64 mask = 0x3;
3024 u64 val64;
3025 int i;
3026 for(i = 0; i <index; i++)
3027 mask = mask << 0x2;
3028
3029 if(flag > 0)
3030 {
3031 *counter = *counter + 1;
3032 val64 = *regs_stat & mask;
3033 val64 = val64 >> (index * 0x2);
3034 val64 = val64 + 1;
3035 if(val64 == 3)
3036 {
3037 switch(type)
3038 {
3039 case 1:
3040 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
3041 "service. Excessive temperatures may "
3042 "result in premature transceiver "
3043 "failure \n");
3044 break;
3045 case 2:
3046 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
3047 "service Excessive bias currents may "
3048 "indicate imminent laser diode "
3049 "failure \n");
3050 break;
3051 case 3:
3052 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
3053 "service Excessive laser output "
3054 "power may saturate far-end "
3055 "receiver\n");
3056 break;
3057 default:
3058 DBG_PRINT(ERR_DBG, "Incorrect XPAK Alarm "
3059 "type \n");
3060 }
3061 val64 = 0x0;
3062 }
3063 val64 = val64 << (index * 0x2);
3064 *regs_stat = (*regs_stat & (~mask)) | (val64);
3065
3066 } else {
3067 *regs_stat = *regs_stat & (~mask);
3068 }
3069}
3070
3071/**
3072 * s2io_updt_xpak_counter - Function to update the xpak counters
3073 * @dev : pointer to net_device struct
3074 * Description:
3075 * This function is to upate the status of the xpak counters value
3076 * NONE
3077 */
3078static void s2io_updt_xpak_counter(struct net_device *dev)
3079{
3080 u16 flag = 0x0;
3081 u16 type = 0x0;
3082 u16 val16 = 0x0;
3083 u64 val64 = 0x0;
3084 u64 addr = 0x0;
3085
3086 nic_t *sp = dev->priv;
3087 StatInfo_t *stat_info = sp->mac_control.stats_info;
3088
3089 /* Check the communication with the MDIO slave */
3090 addr = 0x0000;
3091 val64 = 0x0;
3092 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3093 if((val64 == 0xFFFF) || (val64 == 0x0000))
3094 {
3095 DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - "
3096 "Returned %llx\n", (unsigned long long)val64);
3097 return;
3098 }
3099
3100 /* Check for the expecte value of 2040 at PMA address 0x0000 */
3101 if(val64 != 0x2040)
3102 {
3103 DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - ");
3104 DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x2040\n",
3105 (unsigned long long)val64);
3106 return;
3107 }
3108
3109 /* Loading the DOM register to MDIO register */
3110 addr = 0xA100;
3111 s2io_mdio_write(MDIO_MMD_PMA_DEV_ADDR, addr, val16, dev);
3112 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3113
3114 /* Reading the Alarm flags */
3115 addr = 0xA070;
3116 val64 = 0x0;
3117 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3118
3119 flag = CHECKBIT(val64, 0x7);
3120 type = 1;
3121 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_transceiver_temp_high,
3122 &stat_info->xpak_stat.xpak_regs_stat,
3123 0x0, flag, type);
3124
3125 if(CHECKBIT(val64, 0x6))
3126 stat_info->xpak_stat.alarm_transceiver_temp_low++;
3127
3128 flag = CHECKBIT(val64, 0x3);
3129 type = 2;
3130 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_bias_current_high,
3131 &stat_info->xpak_stat.xpak_regs_stat,
3132 0x2, flag, type);
3133
3134 if(CHECKBIT(val64, 0x2))
3135 stat_info->xpak_stat.alarm_laser_bias_current_low++;
3136
3137 flag = CHECKBIT(val64, 0x1);
3138 type = 3;
3139 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_output_power_high,
3140 &stat_info->xpak_stat.xpak_regs_stat,
3141 0x4, flag, type);
3142
3143 if(CHECKBIT(val64, 0x0))
3144 stat_info->xpak_stat.alarm_laser_output_power_low++;
3145
3146 /* Reading the Warning flags */
3147 addr = 0xA074;
3148 val64 = 0x0;
3149 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3150
3151 if(CHECKBIT(val64, 0x7))
3152 stat_info->xpak_stat.warn_transceiver_temp_high++;
3153
3154 if(CHECKBIT(val64, 0x6))
3155 stat_info->xpak_stat.warn_transceiver_temp_low++;
3156
3157 if(CHECKBIT(val64, 0x3))
3158 stat_info->xpak_stat.warn_laser_bias_current_high++;
3159
3160 if(CHECKBIT(val64, 0x2))
3161 stat_info->xpak_stat.warn_laser_bias_current_low++;
3162
3163 if(CHECKBIT(val64, 0x1))
3164 stat_info->xpak_stat.warn_laser_output_power_high++;
3165
3166 if(CHECKBIT(val64, 0x0))
3167 stat_info->xpak_stat.warn_laser_output_power_low++;
3168}
3169
3170/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 * alarm_intr_handler - Alarm Interrrupt handler
3172 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003173 * Description: If the interrupt was neither because of Rx packet or Tx
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 * complete, this function is called. If the interrupt was to indicate
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003175 * a loss of link, the OSM link status handler is invoked for any other
3176 * alarm interrupt the block that raised the interrupt is displayed
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 * and a H/W reset is issued.
3178 * Return Value:
3179 * NONE
3180*/
3181
3182static void alarm_intr_handler(struct s2io_nic *nic)
3183{
3184 struct net_device *dev = (struct net_device *) nic->dev;
3185 XENA_dev_config_t __iomem *bar0 = nic->bar0;
3186 register u64 val64 = 0, err_reg = 0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003187 u64 cnt;
3188 int i;
Sivakumar Subramani372cc592007-01-31 13:32:57 -05003189 if (atomic_read(&nic->card_state) == CARD_DOWN)
3190 return;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003191 nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
3192 /* Handling the XPAK counters update */
3193 if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
3194 /* waiting for an hour */
3195 nic->mac_control.stats_info->xpak_stat.xpak_timer_count++;
3196 } else {
3197 s2io_updt_xpak_counter(dev);
3198 /* reset the count to zero */
3199 nic->mac_control.stats_info->xpak_stat.xpak_timer_count = 0;
3200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201
3202 /* Handling link status change error Intr */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07003203 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
3204 err_reg = readq(&bar0->mac_rmac_err_reg);
3205 writeq(err_reg, &bar0->mac_rmac_err_reg);
3206 if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
3207 schedule_work(&nic->set_link_task);
3208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 }
3210
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003211 /* Handling Ecc errors */
3212 val64 = readq(&bar0->mc_err_reg);
3213 writeq(val64, &bar0->mc_err_reg);
3214 if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
3215 if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003216 nic->mac_control.stats_info->sw_stat.
3217 double_ecc_errs++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003218 DBG_PRINT(INIT_DBG, "%s: Device indicates ",
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003219 dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003220 DBG_PRINT(INIT_DBG, "double ECC error!!\n");
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003221 if (nic->device_type != XFRAME_II_DEVICE) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003222 /* Reset XframeI only if critical error */
3223 if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
3224 MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
3225 netif_stop_queue(dev);
3226 schedule_work(&nic->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04003227 nic->mac_control.stats_info->sw_stat.
3228 soft_reset_cnt++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003229 }
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003230 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003231 } else {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003232 nic->mac_control.stats_info->sw_stat.
3233 single_ecc_errs++;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003234 }
3235 }
3236
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 /* In case of a serious error, the device will be Reset. */
3238 val64 = readq(&bar0->serr_source);
3239 if (val64 & SERR_SOURCE_ANY) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04003240 nic->mac_control.stats_info->sw_stat.serious_err_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003242 DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003243 (unsigned long long)val64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 netif_stop_queue(dev);
3245 schedule_work(&nic->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04003246 nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 }
3248
3249 /*
3250 * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
3251 * Error occurs, the adapter will be recycled by disabling the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003252 * adapter enable bit and enabling it again after the device
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 * becomes Quiescent.
3254 */
3255 val64 = readq(&bar0->pcc_err_reg);
3256 writeq(val64, &bar0->pcc_err_reg);
3257 if (val64 & PCC_FB_ECC_DB_ERR) {
3258 u64 ac = readq(&bar0->adapter_control);
3259 ac &= ~(ADAPTER_CNTL_EN);
3260 writeq(ac, &bar0->adapter_control);
3261 ac = readq(&bar0->adapter_control);
3262 schedule_work(&nic->set_link_task);
3263 }
Ananda Rajubd1034f2006-04-21 19:20:22 -04003264 /* Check for data parity error */
3265 val64 = readq(&bar0->pic_int_status);
3266 if (val64 & PIC_INT_GPIO) {
3267 val64 = readq(&bar0->gpio_int_reg);
3268 if (val64 & GPIO_INT_REG_DP_ERR_INT) {
3269 nic->mac_control.stats_info->sw_stat.parity_err_cnt++;
3270 schedule_work(&nic->rst_timer_task);
3271 nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
3272 }
3273 }
3274
3275 /* Check for ring full counter */
3276 if (nic->device_type & XFRAME_II_DEVICE) {
3277 val64 = readq(&bar0->ring_bump_counter1);
3278 for (i=0; i<4; i++) {
3279 cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
3280 cnt >>= 64 - ((i+1)*16);
3281 nic->mac_control.stats_info->sw_stat.ring_full_cnt
3282 += cnt;
3283 }
3284
3285 val64 = readq(&bar0->ring_bump_counter2);
3286 for (i=0; i<4; i++) {
3287 cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
3288 cnt >>= 64 - ((i+1)*16);
3289 nic->mac_control.stats_info->sw_stat.ring_full_cnt
3290 += cnt;
3291 }
3292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293
3294 /* Other type of interrupts are not being handled now, TODO */
3295}
3296
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003297/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 * wait_for_cmd_complete - waits for a command to complete.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003299 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003301 * Description: Function that waits for a command to Write into RMAC
3302 * ADDR DATA registers to be completed and returns either success or
3303 * error depending on whether the command was complete or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 * Return value:
3305 * SUCCESS on success and FAILURE on failure.
3306 */
3307
Al Virocc3afe62006-09-23 01:33:40 +01003308static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 int ret = FAILURE, cnt = 0;
3311 u64 val64;
3312
3313 while (TRUE) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04003314 val64 = readq(addr);
3315 if (!(val64 & busy_bit)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 ret = SUCCESS;
3317 break;
3318 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003319
3320 if(in_interrupt())
3321 mdelay(50);
3322 else
3323 msleep(50);
3324
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 if (cnt++ > 10)
3326 break;
3327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 return ret;
3329}
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003330/*
3331 * check_pci_device_id - Checks if the device id is supported
3332 * @id : device id
3333 * Description: Function to check if the pci device id is supported by driver.
3334 * Return value: Actual device id if supported else PCI_ANY_ID
3335 */
3336static u16 check_pci_device_id(u16 id)
3337{
3338 switch (id) {
3339 case PCI_DEVICE_ID_HERC_WIN:
3340 case PCI_DEVICE_ID_HERC_UNI:
3341 return XFRAME_II_DEVICE;
3342 case PCI_DEVICE_ID_S2IO_UNI:
3343 case PCI_DEVICE_ID_S2IO_WIN:
3344 return XFRAME_I_DEVICE;
3345 default:
3346 return PCI_ANY_ID;
3347 }
3348}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003350/**
3351 * s2io_reset - Resets the card.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 * @sp : private member of the device structure.
3353 * Description: Function to Reset the card. This function then also
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003354 * restores the previously saved PCI configuration space registers as
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 * the card reset also resets the configuration space.
3356 * Return value:
3357 * void.
3358 */
3359
Adrian Bunk26df54b2006-01-14 03:09:40 +01003360static void s2io_reset(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361{
3362 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3363 u64 val64;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003364 u16 subid, pci_cmd;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003365 int i;
3366 u16 val16;
3367 DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
3368 __FUNCTION__, sp->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003370 /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003371 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003372
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003373 if (sp->device_type == XFRAME_II_DEVICE) {
3374 int ret;
3375 ret = pci_set_power_state(sp->pdev, 3);
3376 if (!ret)
3377 ret = pci_set_power_state(sp->pdev, 0);
3378 else {
3379 DBG_PRINT(ERR_DBG,"%s PME based SW_Reset failed!\n",
3380 __FUNCTION__);
3381 goto old_way;
3382 }
3383 msleep(20);
3384 goto new_way;
3385 }
3386old_way:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 val64 = SW_RESET_ALL;
3388 writeq(val64, &bar0->sw_reset);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003389new_way:
Ananda Rajuc92ca042006-04-21 19:18:03 -04003390 if (strstr(sp->product_name, "CX4")) {
3391 msleep(750);
3392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 msleep(250);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003394 for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) {
3395
3396 /* Restore the PCI state saved during initialization. */
3397 pci_restore_state(sp->pdev);
3398 pci_read_config_word(sp->pdev, 0x2, &val16);
3399 if (check_pci_device_id(val16) != (u16)PCI_ANY_ID)
3400 break;
3401 msleep(200);
3402 }
3403
3404 if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) {
3405 DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__);
3406 }
3407
3408 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd);
3409
3410 s2io_init_pci(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003412 /* Set swapper to enable I/O register access */
3413 s2io_set_swapper(sp);
3414
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003415 /* Restore the MSIX table entries from local variables */
3416 restore_xmsi_data(sp);
3417
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003418 /* Clear certain PCI/PCI-X fields after reset */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003419 if (sp->device_type == XFRAME_II_DEVICE) {
Ananda Rajub41477f2006-07-24 19:52:49 -04003420 /* Clear "detected parity error" bit */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003421 pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003422
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003423 /* Clearing PCIX Ecc status register */
3424 pci_write_config_dword(sp->pdev, 0x68, 0x7C);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003425
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003426 /* Clearing PCI_STATUS error reflected here */
3427 writeq(BIT(62), &bar0->txpic_int_reg);
3428 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003429
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003430 /* Reset device statistics maintained by OS */
3431 memset(&sp->stats, 0, sizeof (struct net_device_stats));
3432
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 /* SXE-002: Configure link and activity LED to turn it off */
3434 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003435 if (((subid & 0xFF) >= 0x07) &&
3436 (sp->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 val64 = readq(&bar0->gpio_control);
3438 val64 |= 0x0000800000000000ULL;
3439 writeq(val64, &bar0->gpio_control);
3440 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01003441 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 }
3443
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003444 /*
3445 * Clear spurious ECC interrupts that would have occured on
3446 * XFRAME II cards after reset.
3447 */
3448 if (sp->device_type == XFRAME_II_DEVICE) {
3449 val64 = readq(&bar0->pcc_err_reg);
3450 writeq(val64, &bar0->pcc_err_reg);
3451 }
3452
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 sp->device_enabled_once = FALSE;
3454}
3455
3456/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003457 * s2io_set_swapper - to set the swapper controle on the card
3458 * @sp : private member of the device structure,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 * pointer to the s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003460 * Description: Function to set the swapper control on the card
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 * correctly depending on the 'endianness' of the system.
3462 * Return value:
3463 * SUCCESS on success and FAILURE on failure.
3464 */
3465
Adrian Bunk26df54b2006-01-14 03:09:40 +01003466static int s2io_set_swapper(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467{
3468 struct net_device *dev = sp->dev;
3469 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3470 u64 val64, valt, valr;
3471
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003472 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 * Set proper endian settings and verify the same by reading
3474 * the PIF Feed-back register.
3475 */
3476
3477 val64 = readq(&bar0->pif_rd_swapper_fb);
3478 if (val64 != 0x0123456789ABCDEFULL) {
3479 int i = 0;
3480 u64 value[] = { 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */
3481 0x8100008181000081ULL, /* FE=1, SE=0 */
3482 0x4200004242000042ULL, /* FE=0, SE=1 */
3483 0}; /* FE=0, SE=0 */
3484
3485 while(i<4) {
3486 writeq(value[i], &bar0->swapper_ctrl);
3487 val64 = readq(&bar0->pif_rd_swapper_fb);
3488 if (val64 == 0x0123456789ABCDEFULL)
3489 break;
3490 i++;
3491 }
3492 if (i == 4) {
3493 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3494 dev->name);
3495 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3496 (unsigned long long) val64);
3497 return FAILURE;
3498 }
3499 valr = value[i];
3500 } else {
3501 valr = readq(&bar0->swapper_ctrl);
3502 }
3503
3504 valt = 0x0123456789ABCDEFULL;
3505 writeq(valt, &bar0->xmsi_address);
3506 val64 = readq(&bar0->xmsi_address);
3507
3508 if(val64 != valt) {
3509 int i = 0;
3510 u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */
3511 0x0081810000818100ULL, /* FE=1, SE=0 */
3512 0x0042420000424200ULL, /* FE=0, SE=1 */
3513 0}; /* FE=0, SE=0 */
3514
3515 while(i<4) {
3516 writeq((value[i] | valr), &bar0->swapper_ctrl);
3517 writeq(valt, &bar0->xmsi_address);
3518 val64 = readq(&bar0->xmsi_address);
3519 if(val64 == valt)
3520 break;
3521 i++;
3522 }
3523 if(i == 4) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003524 unsigned long long x = val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr ");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003526 DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 return FAILURE;
3528 }
3529 }
3530 val64 = readq(&bar0->swapper_ctrl);
3531 val64 &= 0xFFFF000000000000ULL;
3532
3533#ifdef __BIG_ENDIAN
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003534 /*
3535 * The device by default set to a big endian format, so a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 * big endian driver need not set anything.
3537 */
3538 val64 |= (SWAPPER_CTRL_TXP_FE |
3539 SWAPPER_CTRL_TXP_SE |
3540 SWAPPER_CTRL_TXD_R_FE |
3541 SWAPPER_CTRL_TXD_W_FE |
3542 SWAPPER_CTRL_TXF_R_FE |
3543 SWAPPER_CTRL_RXD_R_FE |
3544 SWAPPER_CTRL_RXD_W_FE |
3545 SWAPPER_CTRL_RXF_W_FE |
3546 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Andrew Morton92383342005-10-16 00:11:29 -07003548 if (sp->intr_type == INTA)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003549 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 writeq(val64, &bar0->swapper_ctrl);
3551#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003552 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 * Initially we enable all bits to make it accessible by the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003554 * driver, then we selectively enable only those bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 * we want to set.
3556 */
3557 val64 |= (SWAPPER_CTRL_TXP_FE |
3558 SWAPPER_CTRL_TXP_SE |
3559 SWAPPER_CTRL_TXD_R_FE |
3560 SWAPPER_CTRL_TXD_R_SE |
3561 SWAPPER_CTRL_TXD_W_FE |
3562 SWAPPER_CTRL_TXD_W_SE |
3563 SWAPPER_CTRL_TXF_R_FE |
3564 SWAPPER_CTRL_RXD_R_FE |
3565 SWAPPER_CTRL_RXD_R_SE |
3566 SWAPPER_CTRL_RXD_W_FE |
3567 SWAPPER_CTRL_RXD_W_SE |
3568 SWAPPER_CTRL_RXF_W_FE |
3569 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003571 if (sp->intr_type == INTA)
3572 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 writeq(val64, &bar0->swapper_ctrl);
3574#endif
3575 val64 = readq(&bar0->swapper_ctrl);
3576
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003577 /*
3578 * Verifying if endian settings are accurate by reading a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 * feedback register.
3580 */
3581 val64 = readq(&bar0->pif_rd_swapper_fb);
3582 if (val64 != 0x0123456789ABCDEFULL) {
3583 /* Endian settings are incorrect, calls for another dekko. */
3584 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3585 dev->name);
3586 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3587 (unsigned long long) val64);
3588 return FAILURE;
3589 }
3590
3591 return SUCCESS;
3592}
3593
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003594static int wait_for_msix_trans(nic_t *nic, int i)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003595{
Al Viro37eb47e2005-12-15 09:17:29 +00003596 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003597 u64 val64;
3598 int ret = 0, cnt = 0;
3599
3600 do {
3601 val64 = readq(&bar0->xmsi_access);
3602 if (!(val64 & BIT(15)))
3603 break;
3604 mdelay(1);
3605 cnt++;
3606 } while(cnt < 5);
3607 if (cnt == 5) {
3608 DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i);
3609 ret = 1;
3610 }
3611
3612 return ret;
3613}
3614
Adrian Bunk26df54b2006-01-14 03:09:40 +01003615static void restore_xmsi_data(nic_t *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003616{
Al Viro37eb47e2005-12-15 09:17:29 +00003617 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003618 u64 val64;
3619 int i;
3620
Ananda Raju75c30b12006-07-24 19:55:09 -04003621 for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003622 writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
3623 writeq(nic->msix_info[i].data, &bar0->xmsi_data);
3624 val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
3625 writeq(val64, &bar0->xmsi_access);
3626 if (wait_for_msix_trans(nic, i)) {
3627 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3628 continue;
3629 }
3630 }
3631}
3632
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003633static void store_xmsi_data(nic_t *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003634{
Al Viro37eb47e2005-12-15 09:17:29 +00003635 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003636 u64 val64, addr, data;
3637 int i;
3638
3639 /* Store and display */
Ananda Raju75c30b12006-07-24 19:55:09 -04003640 for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003641 val64 = (BIT(15) | vBIT(i, 26, 6));
3642 writeq(val64, &bar0->xmsi_access);
3643 if (wait_for_msix_trans(nic, i)) {
3644 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3645 continue;
3646 }
3647 addr = readq(&bar0->xmsi_address);
3648 data = readq(&bar0->xmsi_data);
3649 if (addr && data) {
3650 nic->msix_info[i].addr = addr;
3651 nic->msix_info[i].data = data;
3652 }
3653 }
3654}
3655
3656int s2io_enable_msi(nic_t *nic)
3657{
Al Viro37eb47e2005-12-15 09:17:29 +00003658 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003659 u16 msi_ctrl, msg_val;
3660 struct config_param *config = &nic->config;
3661 struct net_device *dev = nic->dev;
3662 u64 val64, tx_mat, rx_mat;
3663 int i, err;
3664
3665 val64 = readq(&bar0->pic_control);
3666 val64 &= ~BIT(1);
3667 writeq(val64, &bar0->pic_control);
3668
3669 err = pci_enable_msi(nic->pdev);
3670 if (err) {
3671 DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n",
3672 nic->dev->name);
3673 return err;
3674 }
3675
3676 /*
3677 * Enable MSI and use MSI-1 in stead of the standard MSI-0
3678 * for interrupt handling.
3679 */
3680 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3681 msg_val ^= 0x1;
3682 pci_write_config_word(nic->pdev, 0x4c, msg_val);
3683 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3684
3685 pci_read_config_word(nic->pdev, 0x42, &msi_ctrl);
3686 msi_ctrl |= 0x10;
3687 pci_write_config_word(nic->pdev, 0x42, msi_ctrl);
3688
3689 /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */
3690 tx_mat = readq(&bar0->tx_mat0_n[0]);
3691 for (i=0; i<config->tx_fifo_num; i++) {
3692 tx_mat |= TX_MAT_SET(i, 1);
3693 }
3694 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3695
3696 rx_mat = readq(&bar0->rx_mat);
3697 for (i=0; i<config->rx_ring_num; i++) {
3698 rx_mat |= RX_MAT_SET(i, 1);
3699 }
3700 writeq(rx_mat, &bar0->rx_mat);
3701
3702 dev->irq = nic->pdev->irq;
3703 return 0;
3704}
3705
Adrian Bunk26df54b2006-01-14 03:09:40 +01003706static int s2io_enable_msi_x(nic_t *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003707{
Al Viro37eb47e2005-12-15 09:17:29 +00003708 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003709 u64 tx_mat, rx_mat;
3710 u16 msi_control; /* Temp variable */
3711 int ret, i, j, msix_indx = 1;
3712
3713 nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
3714 GFP_KERNEL);
3715 if (nic->entries == NULL) {
3716 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3717 return -ENOMEM;
3718 }
3719 memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
3720
3721 nic->s2io_entries =
3722 kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
3723 GFP_KERNEL);
3724 if (nic->s2io_entries == NULL) {
3725 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3726 kfree(nic->entries);
3727 return -ENOMEM;
3728 }
3729 memset(nic->s2io_entries, 0,
3730 MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
3731
3732 for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
3733 nic->entries[i].entry = i;
3734 nic->s2io_entries[i].entry = i;
3735 nic->s2io_entries[i].arg = NULL;
3736 nic->s2io_entries[i].in_use = 0;
3737 }
3738
3739 tx_mat = readq(&bar0->tx_mat0_n[0]);
3740 for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) {
3741 tx_mat |= TX_MAT_SET(i, msix_indx);
3742 nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i];
3743 nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE;
3744 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3745 }
3746 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3747
3748 if (!nic->config.bimodal) {
3749 rx_mat = readq(&bar0->rx_mat);
3750 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3751 rx_mat |= RX_MAT_SET(j, msix_indx);
3752 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3753 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3754 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3755 }
3756 writeq(rx_mat, &bar0->rx_mat);
3757 } else {
3758 tx_mat = readq(&bar0->tx_mat0_n[7]);
3759 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3760 tx_mat |= TX_MAT_SET(i, msix_indx);
3761 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3762 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3763 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3764 }
3765 writeq(tx_mat, &bar0->tx_mat0_n[7]);
3766 }
3767
Ananda Rajuc92ca042006-04-21 19:18:03 -04003768 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003769 ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003770 /* We fail init if error or we get less vectors than min required */
3771 if (ret >= (nic->config.tx_fifo_num + nic->config.rx_ring_num + 1)) {
3772 nic->avail_msix_vectors = ret;
3773 ret = pci_enable_msix(nic->pdev, nic->entries, ret);
3774 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003775 if (ret) {
3776 DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
3777 kfree(nic->entries);
3778 kfree(nic->s2io_entries);
3779 nic->entries = NULL;
3780 nic->s2io_entries = NULL;
Ananda Rajuc92ca042006-04-21 19:18:03 -04003781 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003782 return -ENOMEM;
3783 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003784 if (!nic->avail_msix_vectors)
3785 nic->avail_msix_vectors = MAX_REQUESTED_MSI_X;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003786
3787 /*
3788 * To enable MSI-X, MSI also needs to be enabled, due to a bug
3789 * in the herc NIC. (Temp change, needs to be removed later)
3790 */
3791 pci_read_config_word(nic->pdev, 0x42, &msi_control);
3792 msi_control |= 0x1; /* Enable MSI */
3793 pci_write_config_word(nic->pdev, 0x42, msi_control);
3794
3795 return 0;
3796}
3797
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798/* ********************************************************* *
3799 * Functions defined below concern the OS part of the driver *
3800 * ********************************************************* */
3801
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003802/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 * s2io_open - open entry point of the driver
3804 * @dev : pointer to the device structure.
3805 * Description:
3806 * This function is the open entry point of the driver. It mainly calls a
3807 * function to allocate Rx buffers and inserts them into the buffer
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003808 * descriptors and then enables the Rx part of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 * Return value:
3810 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3811 * file on failure.
3812 */
3813
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003814static int s2io_open(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815{
3816 nic_t *sp = dev->priv;
3817 int err = 0;
3818
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003819 /*
3820 * Make sure you have link off by default every time
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 * Nic is initialized
3822 */
3823 netif_carrier_off(dev);
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003824 sp->last_link_state = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825
3826 /* Initialize H/W and enable interrupts */
Ananda Rajuc92ca042006-04-21 19:18:03 -04003827 err = s2io_card_up(sp);
3828 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
3830 dev->name);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003831 goto hw_init_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 }
3833
3834 if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
3835 DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003836 s2io_card_down(sp);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003837 err = -ENODEV;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003838 goto hw_init_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 }
3840
3841 netif_start_queue(dev);
3842 return 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003843
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003844hw_init_failed:
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003845 if (sp->intr_type == MSI_X) {
3846 if (sp->entries)
3847 kfree(sp->entries);
3848 if (sp->s2io_entries)
3849 kfree(sp->s2io_entries);
3850 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003851 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852}
3853
3854/**
3855 * s2io_close -close entry point of the driver
3856 * @dev : device pointer.
3857 * Description:
3858 * This is the stop entry point of the driver. It needs to undo exactly
3859 * whatever was done by the open entry point,thus it's usually referred to
3860 * as the close function.Among other things this function mainly stops the
3861 * Rx side of the NIC and frees all the Rx buffers in the Rx rings.
3862 * Return value:
3863 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3864 * file on failure.
3865 */
3866
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003867static int s2io_close(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868{
3869 nic_t *sp = dev->priv;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003870
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 flush_scheduled_work();
3872 netif_stop_queue(dev);
3873 /* Reset card, kill tasklet and free Tx and Rx buffers. */
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003874 s2io_card_down(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 sp->device_close_flag = TRUE; /* Device is shut down. */
3877 return 0;
3878}
3879
3880/**
3881 * s2io_xmit - Tx entry point of te driver
3882 * @skb : the socket buffer containing the Tx data.
3883 * @dev : device pointer.
3884 * Description :
3885 * This function is the Tx entry point of the driver. S2IO NIC supports
3886 * certain protocol assist features on Tx side, namely CSO, S/G, LSO.
3887 * NOTE: when device cant queue the pkt,just the trans_start variable will
3888 * not be upadted.
3889 * Return value:
3890 * 0 on success & 1 on failure.
3891 */
3892
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003893static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894{
3895 nic_t *sp = dev->priv;
3896 u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
3897 register u64 val64;
3898 TxD_t *txdp;
3899 TxFIFO_element_t __iomem *tx_fifo;
3900 unsigned long flags;
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003901 u16 vlan_tag = 0;
3902 int vlan_priority = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 mac_info_t *mac_control;
3904 struct config_param *config;
Ananda Raju75c30b12006-07-24 19:55:09 -04003905 int offload_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906
3907 mac_control = &sp->mac_control;
3908 config = &sp->config;
3909
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003910 DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 spin_lock_irqsave(&sp->tx_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 if (atomic_read(&sp->card_state) == CARD_DOWN) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003913 DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 dev->name);
3915 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003916 dev_kfree_skb(skb);
3917 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 }
3919
3920 queue = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003922 /* Get Fifo number to Transmit based on vlan priority */
3923 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3924 vlan_tag = vlan_tx_tag_get(skb);
3925 vlan_priority = vlan_tag >> 13;
3926 queue = config->fifo_mapping[vlan_priority];
3927 }
3928
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003929 put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
3930 get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
3931 txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off].
3932 list_virt_addr;
3933
3934 queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04003936 if (txdp->Host_Control ||
3937 ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003938 DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 netif_stop_queue(dev);
3940 dev_kfree_skb(skb);
3941 spin_unlock_irqrestore(&sp->tx_lock, flags);
3942 return 0;
3943 }
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003944
3945 /* A buffer with no data will be dropped */
3946 if (!skb->len) {
3947 DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
3948 dev_kfree_skb(skb);
3949 spin_unlock_irqrestore(&sp->tx_lock, flags);
3950 return 0;
3951 }
3952
Ananda Raju75c30b12006-07-24 19:55:09 -04003953 offload_type = s2io_offload_type(skb);
Ananda Raju75c30b12006-07-24 19:55:09 -04003954 if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 txdp->Control_1 |= TXD_TCP_LSO_EN;
Ananda Raju75c30b12006-07-24 19:55:09 -04003956 txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 }
Patrick McHardy84fa7932006-08-29 16:44:56 -07003958 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 txdp->Control_2 |=
3960 (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
3961 TXD_TX_CKO_UDP_EN);
3962 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003963 txdp->Control_1 |= TXD_GATHER_CODE_FIRST;
3964 txdp->Control_1 |= TXD_LIST_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 txdp->Control_2 |= config->tx_intr_type;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07003966
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003967 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3968 txdp->Control_2 |= TXD_VLAN_ENABLE;
3969 txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
3970 }
3971
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003972 frg_len = skb->len - skb->data_len;
Ananda Raju75c30b12006-07-24 19:55:09 -04003973 if (offload_type == SKB_GSO_UDP) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003974 int ufo_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975
Ananda Raju75c30b12006-07-24 19:55:09 -04003976 ufo_size = s2io_udp_mss(skb);
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003977 ufo_size &= ~7;
3978 txdp->Control_1 |= TXD_UFO_EN;
3979 txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
3980 txdp->Control_1 |= TXD_BUFFER0_SIZE(8);
3981#ifdef __BIG_ENDIAN
3982 sp->ufo_in_band_v[put_off] =
3983 (u64)skb_shinfo(skb)->ip6_frag_id;
3984#else
3985 sp->ufo_in_band_v[put_off] =
3986 (u64)skb_shinfo(skb)->ip6_frag_id << 32;
3987#endif
3988 txdp->Host_Control = (unsigned long)sp->ufo_in_band_v;
3989 txdp->Buffer_Pointer = pci_map_single(sp->pdev,
3990 sp->ufo_in_band_v,
3991 sizeof(u64), PCI_DMA_TODEVICE);
3992 txdp++;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003993 }
3994
3995 txdp->Buffer_Pointer = pci_map_single
3996 (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
3997 txdp->Host_Control = (unsigned long) skb;
3998 txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
Ananda Raju75c30b12006-07-24 19:55:09 -04003999 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05004000 txdp->Control_1 |= TXD_UFO_EN;
4001
4002 frg_cnt = skb_shinfo(skb)->nr_frags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 /* For fragmented SKB. */
4004 for (i = 0; i < frg_cnt; i++) {
4005 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07004006 /* A '0' length fragment will be ignored */
4007 if (!frag->size)
4008 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 txdp++;
4010 txdp->Buffer_Pointer = (u64) pci_map_page
4011 (sp->pdev, frag->page, frag->page_offset,
4012 frag->size, PCI_DMA_TODEVICE);
Ananda Rajuefd51b52006-01-19 14:11:54 -05004013 txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
Ananda Raju75c30b12006-07-24 19:55:09 -04004014 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05004015 txdp->Control_1 |= TXD_UFO_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 }
4017 txdp->Control_1 |= TXD_GATHER_CODE_LAST;
4018
Ananda Raju75c30b12006-07-24 19:55:09 -04004019 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05004020 frg_cnt++; /* as Txd0 was used for inband header */
4021
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 tx_fifo = mac_control->tx_FIFO_start[queue];
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004023 val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 writeq(val64, &tx_fifo->TxDL_Pointer);
4025
4026 val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
4027 TX_FIFO_LAST_LIST);
Ananda Raju75c30b12006-07-24 19:55:09 -04004028 if (offload_type)
4029 val64 |= TX_FIFO_SPECIAL_FUNC;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004030
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 writeq(val64, &tx_fifo->List_Control);
4032
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07004033 mmiowb();
4034
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 put_off++;
Ananda Raju863c11a2006-04-21 19:03:13 -04004036 if (put_off == mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1)
4037 put_off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004038 mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039
4040 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04004041 if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04004042 sp->mac_control.stats_info->sw_stat.fifo_full_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 DBG_PRINT(TX_DBG,
4044 "No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
4045 put_off, get_off);
4046 netif_stop_queue(dev);
4047 }
4048
4049 dev->trans_start = jiffies;
4050 spin_unlock_irqrestore(&sp->tx_lock, flags);
4051
4052 return 0;
4053}
4054
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07004055static void
4056s2io_alarm_handle(unsigned long data)
4057{
4058 nic_t *sp = (nic_t *)data;
4059
4060 alarm_intr_handler(sp);
4061 mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
4062}
4063
Ananda Raju75c30b12006-07-24 19:55:09 -04004064static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
4065{
4066 int rxb_size, level;
4067
4068 if (!sp->lro) {
4069 rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
4070 level = rx_buffer_level(sp, rxb_size, rng_n);
4071
4072 if ((level == PANIC) && (!TASKLET_IN_USE)) {
4073 int ret;
4074 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
4075 DBG_PRINT(INTR_DBG, "PANIC levels\n");
4076 if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
4077 DBG_PRINT(ERR_DBG, "Out of memory in %s",
4078 __FUNCTION__);
4079 clear_bit(0, (&sp->tasklet_status));
4080 return -1;
4081 }
4082 clear_bit(0, (&sp->tasklet_status));
4083 } else if (level == LOW)
4084 tasklet_schedule(&sp->task);
4085
4086 } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
4087 DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name);
4088 DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
4089 }
4090 return 0;
4091}
4092
David Howells7d12e782006-10-05 14:55:46 +01004093static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004094{
4095 struct net_device *dev = (struct net_device *) dev_id;
4096 nic_t *sp = dev->priv;
4097 int i;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004098 mac_info_t *mac_control;
4099 struct config_param *config;
4100
4101 atomic_inc(&sp->isr_cnt);
4102 mac_control = &sp->mac_control;
4103 config = &sp->config;
4104 DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__);
4105
4106 /* If Intr is because of Rx Traffic */
4107 for (i = 0; i < config->rx_ring_num; i++)
4108 rx_intr_handler(&mac_control->rings[i]);
4109
4110 /* If Intr is because of Tx Traffic */
4111 for (i = 0; i < config->tx_fifo_num; i++)
4112 tx_intr_handler(&mac_control->fifos[i]);
4113
4114 /*
4115 * If the Rx buffer count is below the panic threshold then
4116 * reallocate the buffers from the interrupt handler itself,
4117 * else schedule a tasklet to reallocate the buffers.
4118 */
Ananda Raju75c30b12006-07-24 19:55:09 -04004119 for (i = 0; i < config->rx_ring_num; i++)
4120 s2io_chk_rx_buffers(sp, i);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004121
4122 atomic_dec(&sp->isr_cnt);
4123 return IRQ_HANDLED;
4124}
4125
David Howells7d12e782006-10-05 14:55:46 +01004126static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004127{
4128 ring_info_t *ring = (ring_info_t *)dev_id;
4129 nic_t *sp = ring->nic;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004130
4131 atomic_inc(&sp->isr_cnt);
Ananda Raju75c30b12006-07-24 19:55:09 -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 atomic_dec(&sp->isr_cnt);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004137 return IRQ_HANDLED;
4138}
4139
David Howells7d12e782006-10-05 14:55:46 +01004140static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004141{
4142 fifo_info_t *fifo = (fifo_info_t *)dev_id;
4143 nic_t *sp = fifo->nic;
4144
4145 atomic_inc(&sp->isr_cnt);
4146 tx_intr_handler(fifo);
4147 atomic_dec(&sp->isr_cnt);
4148 return IRQ_HANDLED;
4149}
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004150static void s2io_txpic_intr_handle(nic_t *sp)
4151{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01004152 XENA_dev_config_t __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);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004201 }
4202 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04004203 val64 = readq(&bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004204}
4205
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206/**
4207 * s2io_isr - ISR handler of the device .
4208 * @irq: the irq of the device.
4209 * @dev_id: a void pointer to the dev structure of the NIC.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004210 * Description: This function is the ISR handler of the device. It
4211 * identifies the reason for the interrupt and calls the relevant
4212 * service routines. As a contongency measure, this ISR allocates the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 * recv buffers, if their numbers are below the panic value which is
4214 * presently set to 25% of the original number of rcv buffers allocated.
4215 * Return value:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004216 * IRQ_HANDLED: will be returned if IRQ was handled by this routine
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 * IRQ_NONE: will be returned if interrupt is not from our device
4218 */
David Howells7d12e782006-10-05 14:55:46 +01004219static irqreturn_t s2io_isr(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220{
4221 struct net_device *dev = (struct net_device *) dev_id;
4222 nic_t *sp = dev->priv;
4223 XENA_dev_config_t __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004224 int i;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004225 u64 reason = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 mac_info_t *mac_control;
4227 struct config_param *config;
4228
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004229 atomic_inc(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 mac_control = &sp->mac_control;
4231 config = &sp->config;
4232
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004233 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 * Identify the cause for interrupt and call the appropriate
4235 * interrupt handler. Causes for the interrupt could be;
4236 * 1. Rx of packet.
4237 * 2. Tx complete.
4238 * 3. Link down.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004239 * 4. Error in any functional blocks of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 */
4241 reason = readq(&bar0->general_int_status);
4242
4243 if (!reason) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004244 /* The interrupt was not raised by us. */
4245 atomic_dec(&sp->isr_cnt);
4246 return IRQ_NONE;
4247 }
4248 else if (unlikely(reason == S2IO_MINUS_ONE) ) {
4249 /* Disable device and get out */
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004250 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 return IRQ_NONE;
4252 }
4253
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004254 if (napi) {
4255 if (reason & GEN_INTR_RXTRAFFIC) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004256 if ( likely ( netif_rx_schedule_prep(dev)) ) {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004257 __netif_rx_schedule(dev);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004258 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004259 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004260 else
4261 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004262 }
4263 } else {
4264 /*
4265 * Rx handler is called by default, without checking for the
4266 * cause of interrupt.
4267 * rx_traffic_int reg is an R1 register, writing all 1's
4268 * will ensure that the actual interrupt causing bit get's
4269 * cleared and hence a read can be avoided.
4270 */
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004271 if (reason & GEN_INTR_RXTRAFFIC)
4272 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
4273
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004274 for (i = 0; i < config->rx_ring_num; i++) {
4275 rx_intr_handler(&mac_control->rings[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276 }
4277 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278
Ananda Raju863c11a2006-04-21 19:03:13 -04004279 /*
4280 * tx_traffic_int reg is an R1 register, writing all 1's
4281 * will ensure that the actual interrupt causing bit get's
4282 * cleared and hence a read can be avoided.
4283 */
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004284 if (reason & GEN_INTR_TXTRAFFIC)
4285 writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -07004286
Ananda Raju863c11a2006-04-21 19:03:13 -04004287 for (i = 0; i < config->tx_fifo_num; i++)
4288 tx_intr_handler(&mac_control->fifos[i]);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004289
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004290 if (reason & GEN_INTR_TXPIC)
4291 s2io_txpic_intr_handle(sp);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004292 /*
4293 * If the Rx buffer count is below the panic threshold then
4294 * reallocate the buffers from the interrupt handler itself,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 * else schedule a tasklet to reallocate the buffers.
4296 */
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004297 if (!napi) {
4298 for (i = 0; i < config->rx_ring_num; i++)
4299 s2io_chk_rx_buffers(sp, i);
4300 }
4301
4302 writeq(0, &bar0->general_int_mask);
4303 readl(&bar0->general_int_status);
4304
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004305 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 return IRQ_HANDLED;
4307}
4308
4309/**
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004310 * s2io_updt_stats -
4311 */
4312static void s2io_updt_stats(nic_t *sp)
4313{
4314 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4315 u64 val64;
4316 int cnt = 0;
4317
4318 if (atomic_read(&sp->card_state) == CARD_UP) {
4319 /* Apprx 30us on a 133 MHz bus */
4320 val64 = SET_UPDT_CLICKS(10) |
4321 STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
4322 writeq(val64, &bar0->stat_cfg);
4323 do {
4324 udelay(100);
4325 val64 = readq(&bar0->stat_cfg);
4326 if (!(val64 & BIT(0)))
4327 break;
4328 cnt++;
4329 if (cnt == 5)
4330 break; /* Updt failed */
4331 } while(1);
Ananda Raju75c30b12006-07-24 19:55:09 -04004332 } else {
4333 memset(sp->mac_control.stats_info, 0, sizeof(StatInfo_t));
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004334 }
4335}
4336
4337/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004338 * s2io_get_stats - Updates the device statistics structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 * @dev : pointer to the device structure.
4340 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004341 * This function updates the device statistics structure in the s2io_nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 * structure and returns a pointer to the same.
4343 * Return value:
4344 * pointer to the updated net_device_stats structure.
4345 */
4346
Adrian Bunkac1f60d2005-11-06 01:46:47 +01004347static struct net_device_stats *s2io_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348{
4349 nic_t *sp = dev->priv;
4350 mac_info_t *mac_control;
4351 struct config_param *config;
4352
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004353
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 mac_control = &sp->mac_control;
4355 config = &sp->config;
4356
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004357 /* Configure Stats for immediate updt */
4358 s2io_updt_stats(sp);
4359
4360 sp->stats.tx_packets =
4361 le32_to_cpu(mac_control->stats_info->tmac_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004362 sp->stats.tx_errors =
4363 le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
4364 sp->stats.rx_errors =
Al Viroee705db2006-09-23 01:28:17 +01004365 le64_to_cpu(mac_control->stats_info->rmac_drop_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004366 sp->stats.multicast =
4367 le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 sp->stats.rx_length_errors =
Al Viroee705db2006-09-23 01:28:17 +01004369 le64_to_cpu(mac_control->stats_info->rmac_long_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370
4371 return (&sp->stats);
4372}
4373
4374/**
4375 * s2io_set_multicast - entry point for multicast address enable/disable.
4376 * @dev : pointer to the device structure
4377 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004378 * This function is a driver entry point which gets called by the kernel
4379 * whenever multicast addresses must be enabled/disabled. This also gets
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 * called to set/reset promiscuous mode. Depending on the deivce flag, we
4381 * determine, if multicast address must be enabled or if promiscuous mode
4382 * is to be disabled etc.
4383 * Return value:
4384 * void.
4385 */
4386
4387static void s2io_set_multicast(struct net_device *dev)
4388{
4389 int i, j, prev_cnt;
4390 struct dev_mc_list *mclist;
4391 nic_t *sp = dev->priv;
4392 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4393 u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
4394 0xfeffffffffffULL;
4395 u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
4396 void __iomem *add;
4397
4398 if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) {
4399 /* Enable all Multicast addresses */
4400 writeq(RMAC_ADDR_DATA0_MEM_ADDR(multi_mac),
4401 &bar0->rmac_addr_data0_mem);
4402 writeq(RMAC_ADDR_DATA1_MEM_MASK(mask),
4403 &bar0->rmac_addr_data1_mem);
4404 val64 = RMAC_ADDR_CMD_MEM_WE |
4405 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4406 RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
4407 writeq(val64, &bar0->rmac_addr_cmd_mem);
4408 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004409 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4410 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411
4412 sp->m_cast_flg = 1;
4413 sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
4414 } else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) {
4415 /* Disable all Multicast addresses */
4416 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4417 &bar0->rmac_addr_data0_mem);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07004418 writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0),
4419 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 val64 = RMAC_ADDR_CMD_MEM_WE |
4421 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4422 RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos);
4423 writeq(val64, &bar0->rmac_addr_cmd_mem);
4424 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004425 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4426 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427
4428 sp->m_cast_flg = 0;
4429 sp->all_multi_pos = 0;
4430 }
4431
4432 if ((dev->flags & IFF_PROMISC) && (!sp->promisc_flg)) {
4433 /* Put the NIC into promiscuous mode */
4434 add = &bar0->mac_cfg;
4435 val64 = readq(&bar0->mac_cfg);
4436 val64 |= MAC_CFG_RMAC_PROM_ENABLE;
4437
4438 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4439 writel((u32) val64, add);
4440 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4441 writel((u32) (val64 >> 32), (add + 4));
4442
4443 val64 = readq(&bar0->mac_cfg);
4444 sp->promisc_flg = 1;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004445 DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 dev->name);
4447 } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) {
4448 /* Remove the NIC from promiscuous mode */
4449 add = &bar0->mac_cfg;
4450 val64 = readq(&bar0->mac_cfg);
4451 val64 &= ~MAC_CFG_RMAC_PROM_ENABLE;
4452
4453 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4454 writel((u32) val64, add);
4455 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4456 writel((u32) (val64 >> 32), (add + 4));
4457
4458 val64 = readq(&bar0->mac_cfg);
4459 sp->promisc_flg = 0;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004460 DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 dev->name);
4462 }
4463
4464 /* Update individual M_CAST address list */
4465 if ((!sp->m_cast_flg) && dev->mc_count) {
4466 if (dev->mc_count >
4467 (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) {
4468 DBG_PRINT(ERR_DBG, "%s: No more Rx filters ",
4469 dev->name);
4470 DBG_PRINT(ERR_DBG, "can be added, please enable ");
4471 DBG_PRINT(ERR_DBG, "ALL_MULTI instead\n");
4472 return;
4473 }
4474
4475 prev_cnt = sp->mc_addr_count;
4476 sp->mc_addr_count = dev->mc_count;
4477
4478 /* Clear out the previous list of Mc in the H/W. */
4479 for (i = 0; i < prev_cnt; i++) {
4480 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4481 &bar0->rmac_addr_data0_mem);
4482 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004483 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 val64 = RMAC_ADDR_CMD_MEM_WE |
4485 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4486 RMAC_ADDR_CMD_MEM_OFFSET
4487 (MAC_MC_ADDR_START_OFFSET + i);
4488 writeq(val64, &bar0->rmac_addr_cmd_mem);
4489
4490 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004491 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4492 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 DBG_PRINT(ERR_DBG, "%s: Adding ",
4494 dev->name);
4495 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4496 return;
4497 }
4498 }
4499
4500 /* Create the new Rx filter list and update the same in H/W. */
4501 for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
4502 i++, mclist = mclist->next) {
4503 memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr,
4504 ETH_ALEN);
Jeff Garzika7a80d52006-03-04 12:06:51 -05004505 mac_addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 for (j = 0; j < ETH_ALEN; j++) {
4507 mac_addr |= mclist->dmi_addr[j];
4508 mac_addr <<= 8;
4509 }
4510 mac_addr >>= 8;
4511 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4512 &bar0->rmac_addr_data0_mem);
4513 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004514 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 val64 = RMAC_ADDR_CMD_MEM_WE |
4516 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4517 RMAC_ADDR_CMD_MEM_OFFSET
4518 (i + MAC_MC_ADDR_START_OFFSET);
4519 writeq(val64, &bar0->rmac_addr_cmd_mem);
4520
4521 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004522 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4523 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 DBG_PRINT(ERR_DBG, "%s: Adding ",
4525 dev->name);
4526 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4527 return;
4528 }
4529 }
4530 }
4531}
4532
4533/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004534 * s2io_set_mac_addr - Programs the Xframe mac address
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 * @dev : pointer to the device structure.
4536 * @addr: a uchar pointer to the new mac address which is to be set.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004537 * Description : This procedure will program the Xframe to receive
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538 * frames with new Mac Address
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004539 * Return value: SUCCESS on success and an appropriate (-)ve integer
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 * as defined in errno.h file on failure.
4541 */
4542
Adrian Bunk26df54b2006-01-14 03:09:40 +01004543static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544{
4545 nic_t *sp = dev->priv;
4546 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4547 register u64 val64, mac_addr = 0;
4548 int i;
4549
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004550 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 * Set the new MAC address as the new unicast filter and reflect this
4552 * change on the device address registered with the OS. It will be
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004553 * at offset 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 */
4555 for (i = 0; i < ETH_ALEN; i++) {
4556 mac_addr <<= 8;
4557 mac_addr |= addr[i];
4558 }
4559
4560 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4561 &bar0->rmac_addr_data0_mem);
4562
4563 val64 =
4564 RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4565 RMAC_ADDR_CMD_MEM_OFFSET(0);
4566 writeq(val64, &bar0->rmac_addr_cmd_mem);
4567 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004568 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4569 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
4571 return FAILURE;
4572 }
4573
4574 return SUCCESS;
4575}
4576
4577/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004578 * s2io_ethtool_sset - Sets different link parameters.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure.
4580 * @info: pointer to the structure with parameters given by ethtool to set
4581 * link information.
4582 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004583 * The function sets different link parameters provided by the user onto
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 * the NIC.
4585 * Return value:
4586 * 0 on success.
4587*/
4588
4589static int s2io_ethtool_sset(struct net_device *dev,
4590 struct ethtool_cmd *info)
4591{
4592 nic_t *sp = dev->priv;
4593 if ((info->autoneg == AUTONEG_ENABLE) ||
4594 (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
4595 return -EINVAL;
4596 else {
4597 s2io_close(sp->dev);
4598 s2io_open(sp->dev);
4599 }
4600
4601 return 0;
4602}
4603
4604/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004605 * s2io_ethtol_gset - Return link specific information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606 * @sp : private member of the device structure, pointer to the
4607 * s2io_nic structure.
4608 * @info : pointer to the structure with parameters given by ethtool
4609 * to return link information.
4610 * Description:
4611 * Returns link specific information like speed, duplex etc.. to ethtool.
4612 * Return value :
4613 * return 0 on success.
4614 */
4615
4616static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
4617{
4618 nic_t *sp = dev->priv;
4619 info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4620 info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4621 info->port = PORT_FIBRE;
4622 /* info->transceiver?? TODO */
4623
4624 if (netif_carrier_ok(sp->dev)) {
4625 info->speed = 10000;
4626 info->duplex = DUPLEX_FULL;
4627 } else {
4628 info->speed = -1;
4629 info->duplex = -1;
4630 }
4631
4632 info->autoneg = AUTONEG_DISABLE;
4633 return 0;
4634}
4635
4636/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004637 * s2io_ethtool_gdrvinfo - Returns driver specific information.
4638 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 * s2io_nic structure.
4640 * @info : pointer to the structure with parameters given by ethtool to
4641 * return driver information.
4642 * Description:
4643 * Returns driver specefic information like name, version etc.. to ethtool.
4644 * Return value:
4645 * void
4646 */
4647
4648static void s2io_ethtool_gdrvinfo(struct net_device *dev,
4649 struct ethtool_drvinfo *info)
4650{
4651 nic_t *sp = dev->priv;
4652
John W. Linvilledbc23092005-09-28 17:50:51 -04004653 strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
4654 strncpy(info->version, s2io_driver_version, sizeof(info->version));
4655 strncpy(info->fw_version, "", sizeof(info->fw_version));
4656 strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 info->regdump_len = XENA_REG_SPACE;
4658 info->eedump_len = XENA_EEPROM_SPACE;
4659 info->testinfo_len = S2IO_TEST_LEN;
4660 info->n_stats = S2IO_STAT_LEN;
4661}
4662
4663/**
4664 * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004665 * @sp: private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004667 * @regs : pointer to the structure with parameters given by ethtool for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 * dumping the registers.
4669 * @reg_space: The input argumnet into which all the registers are dumped.
4670 * Description:
4671 * Dumps the entire register space of xFrame NIC into the user given
4672 * buffer area.
4673 * Return value :
4674 * void .
4675*/
4676
4677static void s2io_ethtool_gregs(struct net_device *dev,
4678 struct ethtool_regs *regs, void *space)
4679{
4680 int i;
4681 u64 reg;
4682 u8 *reg_space = (u8 *) space;
4683 nic_t *sp = dev->priv;
4684
4685 regs->len = XENA_REG_SPACE;
4686 regs->version = sp->pdev->subsystem_device;
4687
4688 for (i = 0; i < regs->len; i += 8) {
4689 reg = readq(sp->bar0 + i);
4690 memcpy((reg_space + i), &reg, 8);
4691 }
4692}
4693
4694/**
4695 * s2io_phy_id - timer function that alternates adapter LED.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004696 * @data : address of the private member of the device structure, which
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 * is a pointer to the s2io_nic structure, provided as an u32.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004698 * Description: This is actually the timer function that alternates the
4699 * adapter LED bit of the adapter control bit to set/reset every time on
4700 * invocation. The timer is set for 1/2 a second, hence tha NIC blinks
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 * once every second.
4702*/
4703static void s2io_phy_id(unsigned long data)
4704{
4705 nic_t *sp = (nic_t *) data;
4706 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4707 u64 val64 = 0;
4708 u16 subid;
4709
4710 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004711 if ((sp->device_type == XFRAME_II_DEVICE) ||
4712 ((subid & 0xFF) >= 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 val64 = readq(&bar0->gpio_control);
4714 val64 ^= GPIO_CTRL_GPIO_0;
4715 writeq(val64, &bar0->gpio_control);
4716 } else {
4717 val64 = readq(&bar0->adapter_control);
4718 val64 ^= ADAPTER_LED_ON;
4719 writeq(val64, &bar0->adapter_control);
4720 }
4721
4722 mod_timer(&sp->id_timer, jiffies + HZ / 2);
4723}
4724
4725/**
4726 * s2io_ethtool_idnic - To physically identify the nic on the system.
4727 * @sp : private member of the device structure, which is a pointer to the
4728 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004729 * @id : pointer to the structure with identification parameters given by
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 * ethtool.
4731 * Description: Used to physically identify the NIC on the system.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004732 * The Link LED will blink for a time specified by the user for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 * identification.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004734 * NOTE: The Link has to be Up to be able to blink the LED. Hence
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 * identification is possible only if it's link is up.
4736 * Return value:
4737 * int , returns 0 on success
4738 */
4739
4740static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
4741{
4742 u64 val64 = 0, last_gpio_ctrl_val;
4743 nic_t *sp = dev->priv;
4744 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4745 u16 subid;
4746
4747 subid = sp->pdev->subsystem_device;
4748 last_gpio_ctrl_val = readq(&bar0->gpio_control);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004749 if ((sp->device_type == XFRAME_I_DEVICE) &&
4750 ((subid & 0xFF) < 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 val64 = readq(&bar0->adapter_control);
4752 if (!(val64 & ADAPTER_CNTL_EN)) {
4753 printk(KERN_ERR
4754 "Adapter Link down, cannot blink LED\n");
4755 return -EFAULT;
4756 }
4757 }
4758 if (sp->id_timer.function == NULL) {
4759 init_timer(&sp->id_timer);
4760 sp->id_timer.function = s2io_phy_id;
4761 sp->id_timer.data = (unsigned long) sp;
4762 }
4763 mod_timer(&sp->id_timer, jiffies);
4764 if (data)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004765 msleep_interruptible(data * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004767 msleep_interruptible(MAX_FLICKER_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 del_timer_sync(&sp->id_timer);
4769
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004770 if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 writeq(last_gpio_ctrl_val, &bar0->gpio_control);
4772 last_gpio_ctrl_val = readq(&bar0->gpio_control);
4773 }
4774
4775 return 0;
4776}
4777
4778/**
4779 * s2io_ethtool_getpause_data -Pause frame frame generation and reception.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004780 * @sp : private member of the device structure, which is a pointer to the
4781 * s2io_nic structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 * @ep : pointer to the structure with pause parameters given by ethtool.
4783 * Description:
4784 * Returns the Pause frame generation and reception capability of the NIC.
4785 * Return value:
4786 * void
4787 */
4788static void s2io_ethtool_getpause_data(struct net_device *dev,
4789 struct ethtool_pauseparam *ep)
4790{
4791 u64 val64;
4792 nic_t *sp = dev->priv;
4793 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4794
4795 val64 = readq(&bar0->rmac_pause_cfg);
4796 if (val64 & RMAC_PAUSE_GEN_ENABLE)
4797 ep->tx_pause = TRUE;
4798 if (val64 & RMAC_PAUSE_RX_ENABLE)
4799 ep->rx_pause = TRUE;
4800 ep->autoneg = FALSE;
4801}
4802
4803/**
4804 * s2io_ethtool_setpause_data - set/reset pause frame generation.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004805 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 * s2io_nic structure.
4807 * @ep : pointer to the structure with pause parameters given by ethtool.
4808 * Description:
4809 * It can be used to set or reset Pause frame generation or reception
4810 * support of the NIC.
4811 * Return value:
4812 * int, returns 0 on Success
4813 */
4814
4815static int s2io_ethtool_setpause_data(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004816 struct ethtool_pauseparam *ep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817{
4818 u64 val64;
4819 nic_t *sp = dev->priv;
4820 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4821
4822 val64 = readq(&bar0->rmac_pause_cfg);
4823 if (ep->tx_pause)
4824 val64 |= RMAC_PAUSE_GEN_ENABLE;
4825 else
4826 val64 &= ~RMAC_PAUSE_GEN_ENABLE;
4827 if (ep->rx_pause)
4828 val64 |= RMAC_PAUSE_RX_ENABLE;
4829 else
4830 val64 &= ~RMAC_PAUSE_RX_ENABLE;
4831 writeq(val64, &bar0->rmac_pause_cfg);
4832 return 0;
4833}
4834
4835/**
4836 * read_eeprom - reads 4 bytes of data from user given offset.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004837 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 * s2io_nic structure.
4839 * @off : offset at which the data must be written
4840 * @data : Its an output parameter where the data read at the given
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004841 * offset is stored.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004843 * Will read 4 bytes of data from the user given offset and return the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 * read data.
4845 * NOTE: Will allow to read only part of the EEPROM visible through the
4846 * I2C bus.
4847 * Return value:
4848 * -1 on failure and 0 on success.
4849 */
4850
4851#define S2IO_DEV_ID 5
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004852static int read_eeprom(nic_t * sp, int off, u64 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853{
4854 int ret = -1;
4855 u32 exit_cnt = 0;
4856 u64 val64;
4857 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4858
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004859 if (sp->device_type == XFRAME_I_DEVICE) {
4860 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4861 I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ |
4862 I2C_CONTROL_CNTL_START;
4863 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004865 while (exit_cnt < 5) {
4866 val64 = readq(&bar0->i2c_control);
4867 if (I2C_CONTROL_CNTL_END(val64)) {
4868 *data = I2C_CONTROL_GET_DATA(val64);
4869 ret = 0;
4870 break;
4871 }
4872 msleep(50);
4873 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 }
4876
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004877 if (sp->device_type == XFRAME_II_DEVICE) {
4878 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004879 SPI_CONTROL_BYTECNT(0x3) |
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004880 SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off);
4881 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4882 val64 |= SPI_CONTROL_REQ;
4883 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4884 while (exit_cnt < 5) {
4885 val64 = readq(&bar0->spi_control);
4886 if (val64 & SPI_CONTROL_NACK) {
4887 ret = 1;
4888 break;
4889 } else if (val64 & SPI_CONTROL_DONE) {
4890 *data = readq(&bar0->spi_data);
4891 *data &= 0xffffff;
4892 ret = 0;
4893 break;
4894 }
4895 msleep(50);
4896 exit_cnt++;
4897 }
4898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 return ret;
4900}
4901
4902/**
4903 * write_eeprom - actually writes the relevant part of the data value.
4904 * @sp : private member of the device structure, which is a pointer to the
4905 * s2io_nic structure.
4906 * @off : offset at which the data must be written
4907 * @data : The data that is to be written
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004908 * @cnt : Number of bytes of the data that are actually to be written into
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 * the Eeprom. (max of 3)
4910 * Description:
4911 * Actually writes the relevant part of the data value into the Eeprom
4912 * through the I2C bus.
4913 * Return value:
4914 * 0 on success, -1 on failure.
4915 */
4916
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004917static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918{
4919 int exit_cnt = 0, ret = -1;
4920 u64 val64;
4921 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4922
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004923 if (sp->device_type == XFRAME_I_DEVICE) {
4924 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4925 I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) |
4926 I2C_CONTROL_CNTL_START;
4927 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004929 while (exit_cnt < 5) {
4930 val64 = readq(&bar0->i2c_control);
4931 if (I2C_CONTROL_CNTL_END(val64)) {
4932 if (!(val64 & I2C_CONTROL_NACK))
4933 ret = 0;
4934 break;
4935 }
4936 msleep(50);
4937 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939 }
4940
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004941 if (sp->device_type == XFRAME_II_DEVICE) {
4942 int write_cnt = (cnt == 8) ? 0 : cnt;
4943 writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data);
4944
4945 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004946 SPI_CONTROL_BYTECNT(write_cnt) |
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004947 SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off);
4948 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4949 val64 |= SPI_CONTROL_REQ;
4950 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4951 while (exit_cnt < 5) {
4952 val64 = readq(&bar0->spi_control);
4953 if (val64 & SPI_CONTROL_NACK) {
4954 ret = 1;
4955 break;
4956 } else if (val64 & SPI_CONTROL_DONE) {
4957 ret = 0;
4958 break;
4959 }
4960 msleep(50);
4961 exit_cnt++;
4962 }
4963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 return ret;
4965}
Ananda Raju9dc737a2006-04-21 19:05:41 -04004966static void s2io_vpd_read(nic_t *nic)
4967{
Ananda Rajub41477f2006-07-24 19:52:49 -04004968 u8 *vpd_data;
4969 u8 data;
Ananda Raju9dc737a2006-04-21 19:05:41 -04004970 int i=0, cnt, fail = 0;
4971 int vpd_addr = 0x80;
4972
4973 if (nic->device_type == XFRAME_II_DEVICE) {
4974 strcpy(nic->product_name, "Xframe II 10GbE network adapter");
4975 vpd_addr = 0x80;
4976 }
4977 else {
4978 strcpy(nic->product_name, "Xframe I 10GbE network adapter");
4979 vpd_addr = 0x50;
4980 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004981 strcpy(nic->serial_num, "NOT AVAILABLE");
Ananda Raju9dc737a2006-04-21 19:05:41 -04004982
Ananda Rajub41477f2006-07-24 19:52:49 -04004983 vpd_data = kmalloc(256, GFP_KERNEL);
4984 if (!vpd_data)
4985 return;
4986
Ananda Raju9dc737a2006-04-21 19:05:41 -04004987 for (i = 0; i < 256; i +=4 ) {
4988 pci_write_config_byte(nic->pdev, (vpd_addr + 2), i);
4989 pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data);
4990 pci_write_config_byte(nic->pdev, (vpd_addr + 3), 0);
4991 for (cnt = 0; cnt <5; cnt++) {
4992 msleep(2);
4993 pci_read_config_byte(nic->pdev, (vpd_addr + 3), &data);
4994 if (data == 0x80)
4995 break;
4996 }
4997 if (cnt >= 5) {
4998 DBG_PRINT(ERR_DBG, "Read of VPD data failed\n");
4999 fail = 1;
5000 break;
5001 }
5002 pci_read_config_dword(nic->pdev, (vpd_addr + 4),
5003 (u32 *)&vpd_data[i]);
5004 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05005005
5006 if(!fail) {
5007 /* read serial number of adapter */
5008 for (cnt = 0; cnt < 256; cnt++) {
5009 if ((vpd_data[cnt] == 'S') &&
5010 (vpd_data[cnt+1] == 'N') &&
5011 (vpd_data[cnt+2] < VPD_STRING_LEN)) {
5012 memset(nic->serial_num, 0, VPD_STRING_LEN);
5013 memcpy(nic->serial_num, &vpd_data[cnt + 3],
5014 vpd_data[cnt+2]);
5015 break;
5016 }
5017 }
5018 }
5019
5020 if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04005021 memset(nic->product_name, 0, vpd_data[1]);
5022 memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
5023 }
Ananda Rajub41477f2006-07-24 19:52:49 -04005024 kfree(vpd_data);
Ananda Raju9dc737a2006-04-21 19:05:41 -04005025}
5026
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027/**
5028 * s2io_ethtool_geeprom - reads the value stored in the Eeprom.
5029 * @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 -07005030 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 * containing all relevant information.
5032 * @data_buf : user defined value to be written into Eeprom.
5033 * Description: Reads the values stored in the Eeprom at given offset
5034 * for a given length. Stores these values int the input argument data
5035 * buffer 'data_buf' and returns these to the caller (ethtool.)
5036 * Return value:
5037 * int 0 on success
5038 */
5039
5040static int s2io_ethtool_geeprom(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005041 struct ethtool_eeprom *eeprom, u8 * data_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042{
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005043 u32 i, valid;
5044 u64 data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045 nic_t *sp = dev->priv;
5046
5047 eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
5048
5049 if ((eeprom->offset + eeprom->len) > (XENA_EEPROM_SPACE))
5050 eeprom->len = XENA_EEPROM_SPACE - eeprom->offset;
5051
5052 for (i = 0; i < eeprom->len; i += 4) {
5053 if (read_eeprom(sp, (eeprom->offset + i), &data)) {
5054 DBG_PRINT(ERR_DBG, "Read of EEPROM failed\n");
5055 return -EFAULT;
5056 }
5057 valid = INV(data);
5058 memcpy((data_buf + i), &valid, 4);
5059 }
5060 return 0;
5061}
5062
5063/**
5064 * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom
5065 * @sp : private member of the device structure, which is a pointer to the
5066 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005067 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 * containing all relevant information.
5069 * @data_buf ; user defined value to be written into Eeprom.
5070 * Description:
5071 * Tries to write the user provided value in the Eeprom, at the offset
5072 * given by the user.
5073 * Return value:
5074 * 0 on success, -EFAULT on failure.
5075 */
5076
5077static int s2io_ethtool_seeprom(struct net_device *dev,
5078 struct ethtool_eeprom *eeprom,
5079 u8 * data_buf)
5080{
5081 int len = eeprom->len, cnt = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005082 u64 valid = 0, data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083 nic_t *sp = dev->priv;
5084
5085 if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
5086 DBG_PRINT(ERR_DBG,
5087 "ETHTOOL_WRITE_EEPROM Err: Magic value ");
5088 DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n",
5089 eeprom->magic);
5090 return -EFAULT;
5091 }
5092
5093 while (len) {
5094 data = (u32) data_buf[cnt] & 0x000000FF;
5095 if (data) {
5096 valid = (u32) (data << 24);
5097 } else
5098 valid = data;
5099
5100 if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) {
5101 DBG_PRINT(ERR_DBG,
5102 "ETHTOOL_WRITE_EEPROM Err: Cannot ");
5103 DBG_PRINT(ERR_DBG,
5104 "write into the specified offset\n");
5105 return -EFAULT;
5106 }
5107 cnt++;
5108 len--;
5109 }
5110
5111 return 0;
5112}
5113
5114/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005115 * s2io_register_test - reads and writes into all clock domains.
5116 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 * s2io_nic structure.
5118 * @data : variable that returns the result of each of the test conducted b
5119 * by the driver.
5120 * Description:
5121 * Read and write into all clock domains. The NIC has 3 clock domains,
5122 * see that registers in all the three regions are accessible.
5123 * Return value:
5124 * 0 on success.
5125 */
5126
5127static int s2io_register_test(nic_t * sp, uint64_t * data)
5128{
5129 XENA_dev_config_t __iomem *bar0 = sp->bar0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005130 u64 val64 = 0, exp_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 int fail = 0;
5132
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005133 val64 = readq(&bar0->pif_rd_swapper_fb);
5134 if (val64 != 0x123456789abcdefULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 fail = 1;
5136 DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n");
5137 }
5138
5139 val64 = readq(&bar0->rmac_pause_cfg);
5140 if (val64 != 0xc000ffff00000000ULL) {
5141 fail = 1;
5142 DBG_PRINT(INFO_DBG, "Read Test level 2 fails\n");
5143 }
5144
5145 val64 = readq(&bar0->rx_queue_cfg);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005146 if (sp->device_type == XFRAME_II_DEVICE)
5147 exp_val = 0x0404040404040404ULL;
5148 else
5149 exp_val = 0x0808080808080808ULL;
5150 if (val64 != exp_val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 fail = 1;
5152 DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n");
5153 }
5154
5155 val64 = readq(&bar0->xgxs_efifo_cfg);
5156 if (val64 != 0x000000001923141EULL) {
5157 fail = 1;
5158 DBG_PRINT(INFO_DBG, "Read Test level 4 fails\n");
5159 }
5160
5161 val64 = 0x5A5A5A5A5A5A5A5AULL;
5162 writeq(val64, &bar0->xmsi_data);
5163 val64 = readq(&bar0->xmsi_data);
5164 if (val64 != 0x5A5A5A5A5A5A5A5AULL) {
5165 fail = 1;
5166 DBG_PRINT(ERR_DBG, "Write Test level 1 fails\n");
5167 }
5168
5169 val64 = 0xA5A5A5A5A5A5A5A5ULL;
5170 writeq(val64, &bar0->xmsi_data);
5171 val64 = readq(&bar0->xmsi_data);
5172 if (val64 != 0xA5A5A5A5A5A5A5A5ULL) {
5173 fail = 1;
5174 DBG_PRINT(ERR_DBG, "Write Test level 2 fails\n");
5175 }
5176
5177 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005178 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005179}
5180
5181/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005182 * s2io_eeprom_test - to verify that EEprom in the xena can be programmed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 * @sp : private member of the device structure, which is a pointer to the
5184 * s2io_nic structure.
5185 * @data:variable that returns the result of each of the test conducted by
5186 * the driver.
5187 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005188 * Verify that EEPROM in the xena can be programmed using I2C_CONTROL
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 * register.
5190 * Return value:
5191 * 0 on success.
5192 */
5193
5194static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
5195{
5196 int fail = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005197 u64 ret_data, org_4F0, org_7F0;
5198 u8 saved_4F0 = 0, saved_7F0 = 0;
5199 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200
5201 /* Test Write Error at offset 0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005202 /* Note that SPI interface allows write access to all areas
5203 * of EEPROM. Hence doing all negative testing only for Xframe I.
5204 */
5205 if (sp->device_type == XFRAME_I_DEVICE)
5206 if (!write_eeprom(sp, 0, 0, 3))
5207 fail = 1;
5208
5209 /* Save current values at offsets 0x4F0 and 0x7F0 */
5210 if (!read_eeprom(sp, 0x4F0, &org_4F0))
5211 saved_4F0 = 1;
5212 if (!read_eeprom(sp, 0x7F0, &org_7F0))
5213 saved_7F0 = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214
5215 /* Test Write at offset 4f0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005216 if (write_eeprom(sp, 0x4F0, 0x012345, 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 fail = 1;
5218 if (read_eeprom(sp, 0x4F0, &ret_data))
5219 fail = 1;
5220
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005221 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005222 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. "
5223 "Data written %llx Data read %llx\n",
5224 dev->name, (unsigned long long)0x12345,
5225 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228
5229 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005230 write_eeprom(sp, 0x4F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231
5232 /* Test Write Request Error at offset 0x7c */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005233 if (sp->device_type == XFRAME_I_DEVICE)
5234 if (!write_eeprom(sp, 0x07C, 0, 3))
5235 fail = 1;
5236
5237 /* Test Write Request at offset 0x7f0 */
5238 if (write_eeprom(sp, 0x7F0, 0x012345, 3))
5239 fail = 1;
5240 if (read_eeprom(sp, 0x7F0, &ret_data))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241 fail = 1;
5242
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005243 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005244 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. "
5245 "Data written %llx Data read %llx\n",
5246 dev->name, (unsigned long long)0x12345,
5247 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250
5251 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005252 write_eeprom(sp, 0x7F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005254 if (sp->device_type == XFRAME_I_DEVICE) {
5255 /* Test Write Error at offset 0x80 */
5256 if (!write_eeprom(sp, 0x080, 0, 3))
5257 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005259 /* Test Write Error at offset 0xfc */
5260 if (!write_eeprom(sp, 0x0FC, 0, 3))
5261 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005263 /* Test Write Error at offset 0x100 */
5264 if (!write_eeprom(sp, 0x100, 0, 3))
5265 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005267 /* Test Write Error at offset 4ec */
5268 if (!write_eeprom(sp, 0x4EC, 0, 3))
5269 fail = 1;
5270 }
5271
5272 /* Restore values at offsets 0x4F0 and 0x7F0 */
5273 if (saved_4F0)
5274 write_eeprom(sp, 0x4F0, org_4F0, 3);
5275 if (saved_7F0)
5276 write_eeprom(sp, 0x7F0, org_7F0, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277
5278 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005279 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280}
5281
5282/**
5283 * s2io_bist_test - invokes the MemBist test of the card .
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005284 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005286 * @data:variable that returns the result of each of the test conducted by
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 * the driver.
5288 * Description:
5289 * This invokes the MemBist test of the card. We give around
5290 * 2 secs time for the Test to complete. If it's still not complete
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005291 * within this peiod, we consider that the test failed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 * Return value:
5293 * 0 on success and -1 on failure.
5294 */
5295
5296static int s2io_bist_test(nic_t * sp, uint64_t * data)
5297{
5298 u8 bist = 0;
5299 int cnt = 0, ret = -1;
5300
5301 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5302 bist |= PCI_BIST_START;
5303 pci_write_config_word(sp->pdev, PCI_BIST, bist);
5304
5305 while (cnt < 20) {
5306 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5307 if (!(bist & PCI_BIST_START)) {
5308 *data = (bist & PCI_BIST_CODE_MASK);
5309 ret = 0;
5310 break;
5311 }
5312 msleep(100);
5313 cnt++;
5314 }
5315
5316 return ret;
5317}
5318
5319/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005320 * s2io-link_test - verifies the link state of the nic
5321 * @sp ; private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322 * s2io_nic structure.
5323 * @data: variable that returns the result of each of the test conducted by
5324 * the driver.
5325 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005326 * The function verifies the link state of the NIC and updates the input
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327 * argument 'data' appropriately.
5328 * Return value:
5329 * 0 on success.
5330 */
5331
5332static int s2io_link_test(nic_t * sp, uint64_t * data)
5333{
5334 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5335 u64 val64;
5336
5337 val64 = readq(&bar0->adapter_status);
Ananda Rajuc92ca042006-04-21 19:18:03 -04005338 if(!(LINK_IS_UP(val64)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005339 *data = 1;
Ananda Rajuc92ca042006-04-21 19:18:03 -04005340 else
5341 *data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342
Ananda Rajub41477f2006-07-24 19:52:49 -04005343 return *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344}
5345
5346/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005347 * s2io_rldram_test - offline test for access to the RldRam chip on the NIC
5348 * @sp - private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005349 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005350 * @data - variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 * conducted by the driver.
5352 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005353 * This is one of the offline test that tests the read and write
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354 * access to the RldRam chip on the NIC.
5355 * Return value:
5356 * 0 on success.
5357 */
5358
5359static int s2io_rldram_test(nic_t * sp, uint64_t * data)
5360{
5361 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5362 u64 val64;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005363 int cnt, iteration = 0, test_fail = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364
5365 val64 = readq(&bar0->adapter_control);
5366 val64 &= ~ADAPTER_ECC_EN;
5367 writeq(val64, &bar0->adapter_control);
5368
5369 val64 = readq(&bar0->mc_rldram_test_ctrl);
5370 val64 |= MC_RLDRAM_TEST_MODE;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005371 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372
5373 val64 = readq(&bar0->mc_rldram_mrs);
5374 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE;
5375 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5376
5377 val64 |= MC_RLDRAM_MRS_ENABLE;
5378 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5379
5380 while (iteration < 2) {
5381 val64 = 0x55555555aaaa0000ULL;
5382 if (iteration == 1) {
5383 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5384 }
5385 writeq(val64, &bar0->mc_rldram_test_d0);
5386
5387 val64 = 0xaaaa5a5555550000ULL;
5388 if (iteration == 1) {
5389 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5390 }
5391 writeq(val64, &bar0->mc_rldram_test_d1);
5392
5393 val64 = 0x55aaaaaaaa5a0000ULL;
5394 if (iteration == 1) {
5395 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5396 }
5397 writeq(val64, &bar0->mc_rldram_test_d2);
5398
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005399 val64 = (u64) (0x0000003ffffe0100ULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400 writeq(val64, &bar0->mc_rldram_test_add);
5401
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005402 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE |
5403 MC_RLDRAM_TEST_GO;
5404 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405
5406 for (cnt = 0; cnt < 5; cnt++) {
5407 val64 = readq(&bar0->mc_rldram_test_ctrl);
5408 if (val64 & MC_RLDRAM_TEST_DONE)
5409 break;
5410 msleep(200);
5411 }
5412
5413 if (cnt == 5)
5414 break;
5415
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005416 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO;
5417 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418
5419 for (cnt = 0; cnt < 5; cnt++) {
5420 val64 = readq(&bar0->mc_rldram_test_ctrl);
5421 if (val64 & MC_RLDRAM_TEST_DONE)
5422 break;
5423 msleep(500);
5424 }
5425
5426 if (cnt == 5)
5427 break;
5428
5429 val64 = readq(&bar0->mc_rldram_test_ctrl);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005430 if (!(val64 & MC_RLDRAM_TEST_PASS))
5431 test_fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432
5433 iteration++;
5434 }
5435
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005436 *data = test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005438 /* Bring the adapter out of test mode */
5439 SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF);
5440
5441 return test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442}
5443
5444/**
5445 * s2io_ethtool_test - conducts 6 tsets to determine the health of card.
5446 * @sp : private member of the device structure, which is a pointer to the
5447 * s2io_nic structure.
5448 * @ethtest : pointer to a ethtool command specific structure that will be
5449 * returned to the user.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005450 * @data : variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 * conducted by the driver.
5452 * Description:
5453 * This function conducts 6 tests ( 4 offline and 2 online) to determine
5454 * the health of the card.
5455 * Return value:
5456 * void
5457 */
5458
5459static void s2io_ethtool_test(struct net_device *dev,
5460 struct ethtool_test *ethtest,
5461 uint64_t * data)
5462{
5463 nic_t *sp = dev->priv;
5464 int orig_state = netif_running(sp->dev);
5465
5466 if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
5467 /* Offline Tests. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005468 if (orig_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 s2io_close(sp->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470
5471 if (s2io_register_test(sp, &data[0]))
5472 ethtest->flags |= ETH_TEST_FL_FAILED;
5473
5474 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475
5476 if (s2io_rldram_test(sp, &data[3]))
5477 ethtest->flags |= ETH_TEST_FL_FAILED;
5478
5479 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480
5481 if (s2io_eeprom_test(sp, &data[1]))
5482 ethtest->flags |= ETH_TEST_FL_FAILED;
5483
5484 if (s2io_bist_test(sp, &data[4]))
5485 ethtest->flags |= ETH_TEST_FL_FAILED;
5486
5487 if (orig_state)
5488 s2io_open(sp->dev);
5489
5490 data[2] = 0;
5491 } else {
5492 /* Online Tests. */
5493 if (!orig_state) {
5494 DBG_PRINT(ERR_DBG,
5495 "%s: is not up, cannot run test\n",
5496 dev->name);
5497 data[0] = -1;
5498 data[1] = -1;
5499 data[2] = -1;
5500 data[3] = -1;
5501 data[4] = -1;
5502 }
5503
5504 if (s2io_link_test(sp, &data[2]))
5505 ethtest->flags |= ETH_TEST_FL_FAILED;
5506
5507 data[0] = 0;
5508 data[1] = 0;
5509 data[3] = 0;
5510 data[4] = 0;
5511 }
5512}
5513
5514static void s2io_get_ethtool_stats(struct net_device *dev,
5515 struct ethtool_stats *estats,
5516 u64 * tmp_stats)
5517{
5518 int i = 0;
5519 nic_t *sp = dev->priv;
5520 StatInfo_t *stat_info = sp->mac_control.stats_info;
5521
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005522 s2io_updt_stats(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005523 tmp_stats[i++] =
5524 (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32 |
5525 le32_to_cpu(stat_info->tmac_frms);
5526 tmp_stats[i++] =
5527 (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 |
5528 le32_to_cpu(stat_info->tmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005530 tmp_stats[i++] =
5531 (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 |
5532 le32_to_cpu(stat_info->tmac_mcst_frms);
5533 tmp_stats[i++] =
5534 (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 |
5535 le32_to_cpu(stat_info->tmac_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005537 tmp_stats[i++] =
5538 (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 |
5539 le32_to_cpu(stat_info->tmac_ttl_octets);
5540 tmp_stats[i++] =
5541 (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 |
5542 le32_to_cpu(stat_info->tmac_ucst_frms);
5543 tmp_stats[i++] =
5544 (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 |
5545 le32_to_cpu(stat_info->tmac_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005546 tmp_stats[i++] =
5547 (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 |
5548 le32_to_cpu(stat_info->tmac_any_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005549 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005551 tmp_stats[i++] =
5552 (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 |
5553 le32_to_cpu(stat_info->tmac_vld_ip);
5554 tmp_stats[i++] =
5555 (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 |
5556 le32_to_cpu(stat_info->tmac_drop_ip);
5557 tmp_stats[i++] =
5558 (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 |
5559 le32_to_cpu(stat_info->tmac_icmp);
5560 tmp_stats[i++] =
5561 (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 |
5562 le32_to_cpu(stat_info->tmac_rst_tcp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005564 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 |
5565 le32_to_cpu(stat_info->tmac_udp);
5566 tmp_stats[i++] =
5567 (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 |
5568 le32_to_cpu(stat_info->rmac_vld_frms);
5569 tmp_stats[i++] =
5570 (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 |
5571 le32_to_cpu(stat_info->rmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms);
5573 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005574 tmp_stats[i++] =
5575 (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 |
5576 le32_to_cpu(stat_info->rmac_vld_mcst_frms);
5577 tmp_stats[i++] =
5578 (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 |
5579 le32_to_cpu(stat_info->rmac_vld_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005581 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_out_rng_len_err_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms);
5583 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005584 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_unsup_ctrl_frms);
5585 tmp_stats[i++] =
5586 (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 |
5587 le32_to_cpu(stat_info->rmac_ttl_octets);
5588 tmp_stats[i++] =
5589 (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow)
5590 << 32 | le32_to_cpu(stat_info->rmac_accepted_ucst_frms);
5591 tmp_stats[i++] =
5592 (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow)
5593 << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005594 tmp_stats[i++] =
5595 (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 |
5596 le32_to_cpu(stat_info->rmac_discarded_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005597 tmp_stats[i++] =
5598 (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow)
5599 << 32 | le32_to_cpu(stat_info->rmac_drop_events);
5600 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets);
5601 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005602 tmp_stats[i++] =
5603 (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 |
5604 le32_to_cpu(stat_info->rmac_usized_frms);
5605 tmp_stats[i++] =
5606 (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 |
5607 le32_to_cpu(stat_info->rmac_osized_frms);
5608 tmp_stats[i++] =
5609 (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 |
5610 le32_to_cpu(stat_info->rmac_frag_frms);
5611 tmp_stats[i++] =
5612 (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 |
5613 le32_to_cpu(stat_info->rmac_jabber_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005614 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_64_frms);
5615 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms);
5616 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms);
5617 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms);
5618 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms);
5619 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms);
5620 tmp_stats[i++] =
5621 (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005622 le32_to_cpu(stat_info->rmac_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets);
5624 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005625 tmp_stats[i++] =
5626 (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005627 le32_to_cpu(stat_info->rmac_drop_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005628 tmp_stats[i++] =
5629 (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005630 le32_to_cpu(stat_info->rmac_icmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005632 tmp_stats[i++] =
5633 (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005634 le32_to_cpu(stat_info->rmac_udp);
5635 tmp_stats[i++] =
5636 (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 |
5637 le32_to_cpu(stat_info->rmac_err_drp_udp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005638 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_err_sym);
5639 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0);
5640 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1);
5641 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2);
5642 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3);
5643 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4);
5644 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5);
5645 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6);
5646 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7);
5647 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0);
5648 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1);
5649 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2);
5650 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3);
5651 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4);
5652 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5);
5653 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6);
5654 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005655 tmp_stats[i++] =
5656 (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 |
5657 le32_to_cpu(stat_info->rmac_pause_cnt);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005658 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_data_err_cnt);
5659 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005660 tmp_stats[i++] =
5661 (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 |
5662 le32_to_cpu(stat_info->rmac_accepted_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005664 tmp_stats[i++] = le32_to_cpu(stat_info->rd_req_cnt);
5665 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_cnt);
5666 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_rtry_cnt);
5667 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_cnt);
5668 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_rd_ack_cnt);
5669 tmp_stats[i++] = le32_to_cpu(stat_info->wr_req_cnt);
5670 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_cnt);
5671 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_rtry_cnt);
5672 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_cnt);
5673 tmp_stats[i++] = le32_to_cpu(stat_info->wr_disc_cnt);
5674 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_wr_ack_cnt);
5675 tmp_stats[i++] = le32_to_cpu(stat_info->txp_wr_cnt);
5676 tmp_stats[i++] = le32_to_cpu(stat_info->txd_rd_cnt);
5677 tmp_stats[i++] = le32_to_cpu(stat_info->txd_wr_cnt);
5678 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_rd_cnt);
5679 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_wr_cnt);
5680 tmp_stats[i++] = le32_to_cpu(stat_info->txf_rd_cnt);
5681 tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt);
5682 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms);
5683 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms);
5684 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_8192_max_frms);
5685 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms);
5686 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms);
5687 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms);
5688 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms);
5689 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms);
5690 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard);
5691 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard);
5692 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard);
5693 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard);
5694 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard);
5695 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard);
5696 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard);
5697 tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005698 tmp_stats[i++] = 0;
5699 tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
5700 tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
Ananda Rajubd1034f2006-04-21 19:20:22 -04005701 tmp_stats[i++] = stat_info->sw_stat.parity_err_cnt;
5702 tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt;
5703 tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt;
5704 tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt;
5705 tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt;
5706 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high;
5707 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low;
5708 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high;
5709 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_low;
5710 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_high;
5711 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_low;
5712 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_high;
5713 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_low;
5714 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_high;
5715 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_low;
5716 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_high;
5717 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_low;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005718 tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt;
5719 tmp_stats[i++] = stat_info->sw_stat.sending_both;
5720 tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts;
5721 tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts;
Andrew Mortonfe931392006-02-03 01:45:12 -08005722 if (stat_info->sw_stat.num_aggregations) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04005723 u64 tmp = stat_info->sw_stat.sum_avg_pkts_aggregated;
5724 int count = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005725 /*
Ananda Rajubd1034f2006-04-21 19:20:22 -04005726 * Since 64-bit divide does not work on all platforms,
5727 * do repeated subtraction.
5728 */
5729 while (tmp >= stat_info->sw_stat.num_aggregations) {
5730 tmp -= stat_info->sw_stat.num_aggregations;
5731 count++;
5732 }
5733 tmp_stats[i++] = count;
Andrew Mortonfe931392006-02-03 01:45:12 -08005734 }
Ananda Rajubd1034f2006-04-21 19:20:22 -04005735 else
5736 tmp_stats[i++] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737}
5738
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005739static int s2io_ethtool_get_regs_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740{
5741 return (XENA_REG_SPACE);
5742}
5743
5744
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005745static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746{
5747 nic_t *sp = dev->priv;
5748
5749 return (sp->rx_csum);
5750}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005751
5752static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753{
5754 nic_t *sp = dev->priv;
5755
5756 if (data)
5757 sp->rx_csum = 1;
5758 else
5759 sp->rx_csum = 0;
5760
5761 return 0;
5762}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005763
5764static int s2io_get_eeprom_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765{
5766 return (XENA_EEPROM_SPACE);
5767}
5768
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005769static int s2io_ethtool_self_test_count(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770{
5771 return (S2IO_TEST_LEN);
5772}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005773
5774static void s2io_ethtool_get_strings(struct net_device *dev,
5775 u32 stringset, u8 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776{
5777 switch (stringset) {
5778 case ETH_SS_TEST:
5779 memcpy(data, s2io_gstrings, S2IO_STRINGS_LEN);
5780 break;
5781 case ETH_SS_STATS:
5782 memcpy(data, &ethtool_stats_keys,
5783 sizeof(ethtool_stats_keys));
5784 }
5785}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786static int s2io_ethtool_get_stats_count(struct net_device *dev)
5787{
5788 return (S2IO_STAT_LEN);
5789}
5790
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005791static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792{
5793 if (data)
5794 dev->features |= NETIF_F_IP_CSUM;
5795 else
5796 dev->features &= ~NETIF_F_IP_CSUM;
5797
5798 return 0;
5799}
5800
Ananda Raju75c30b12006-07-24 19:55:09 -04005801static u32 s2io_ethtool_op_get_tso(struct net_device *dev)
5802{
5803 return (dev->features & NETIF_F_TSO) != 0;
5804}
5805static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data)
5806{
5807 if (data)
5808 dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
5809 else
5810 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
5811
5812 return 0;
5813}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814
Jeff Garzik7282d492006-09-13 14:30:00 -04005815static const struct ethtool_ops netdev_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005816 .get_settings = s2io_ethtool_gset,
5817 .set_settings = s2io_ethtool_sset,
5818 .get_drvinfo = s2io_ethtool_gdrvinfo,
5819 .get_regs_len = s2io_ethtool_get_regs_len,
5820 .get_regs = s2io_ethtool_gregs,
5821 .get_link = ethtool_op_get_link,
5822 .get_eeprom_len = s2io_get_eeprom_len,
5823 .get_eeprom = s2io_ethtool_geeprom,
5824 .set_eeprom = s2io_ethtool_seeprom,
5825 .get_pauseparam = s2io_ethtool_getpause_data,
5826 .set_pauseparam = s2io_ethtool_setpause_data,
5827 .get_rx_csum = s2io_ethtool_get_rx_csum,
5828 .set_rx_csum = s2io_ethtool_set_rx_csum,
5829 .get_tx_csum = ethtool_op_get_tx_csum,
5830 .set_tx_csum = s2io_ethtool_op_set_tx_csum,
5831 .get_sg = ethtool_op_get_sg,
5832 .set_sg = ethtool_op_set_sg,
Ananda Raju75c30b12006-07-24 19:55:09 -04005833 .get_tso = s2io_ethtool_op_get_tso,
5834 .set_tso = s2io_ethtool_op_set_tso,
Ananda Rajufed5ecc2005-11-14 15:25:08 -05005835 .get_ufo = ethtool_op_get_ufo,
5836 .set_ufo = ethtool_op_set_ufo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837 .self_test_count = s2io_ethtool_self_test_count,
5838 .self_test = s2io_ethtool_test,
5839 .get_strings = s2io_ethtool_get_strings,
5840 .phys_id = s2io_ethtool_idnic,
5841 .get_stats_count = s2io_ethtool_get_stats_count,
5842 .get_ethtool_stats = s2io_get_ethtool_stats
5843};
5844
5845/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005846 * s2io_ioctl - Entry point for the Ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847 * @dev : Device pointer.
5848 * @ifr : An IOCTL specefic structure, that can contain a pointer to
5849 * a proprietary structure used to pass information to the driver.
5850 * @cmd : This is used to distinguish between the different commands that
5851 * can be passed to the IOCTL functions.
5852 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005853 * Currently there are no special functionality supported in IOCTL, hence
5854 * function always return EOPNOTSUPPORTED
Linus Torvalds1da177e2005-04-16 15:20:36 -07005855 */
5856
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005857static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858{
5859 return -EOPNOTSUPP;
5860}
5861
5862/**
5863 * s2io_change_mtu - entry point to change MTU size for the device.
5864 * @dev : device pointer.
5865 * @new_mtu : the new MTU size for the device.
5866 * Description: A driver entry point to change MTU size for the device.
5867 * Before changing the MTU the device must be stopped.
5868 * Return value:
5869 * 0 on success and an appropriate (-)ve integer as defined in errno.h
5870 * file on failure.
5871 */
5872
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005873static int s2io_change_mtu(struct net_device *dev, int new_mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005874{
5875 nic_t *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876
5877 if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
5878 DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
5879 dev->name);
5880 return -EPERM;
5881 }
5882
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883 dev->mtu = new_mtu;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005884 if (netif_running(dev)) {
Ananda Rajue6a8fee2006-07-06 23:58:23 -07005885 s2io_card_down(sp);
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005886 netif_stop_queue(dev);
5887 if (s2io_card_up(sp)) {
5888 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
5889 __FUNCTION__);
5890 }
5891 if (netif_queue_stopped(dev))
5892 netif_wake_queue(dev);
5893 } else { /* Device is down */
5894 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5895 u64 val64 = new_mtu;
5896
5897 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
5898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899
5900 return 0;
5901}
5902
5903/**
5904 * s2io_tasklet - Bottom half of the ISR.
5905 * @dev_adr : address of the device structure in dma_addr_t format.
5906 * Description:
5907 * This is the tasklet or the bottom half of the ISR. This is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005908 * an extension of the ISR which is scheduled by the scheduler to be run
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909 * 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 -07005910 * be pushed into the tasklet. For now the tasklet is used only to
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911 * replenish the Rx buffers in the Rx buffer descriptors.
5912 * Return value:
5913 * void.
5914 */
5915
5916static void s2io_tasklet(unsigned long dev_addr)
5917{
5918 struct net_device *dev = (struct net_device *) dev_addr;
5919 nic_t *sp = dev->priv;
5920 int i, ret;
5921 mac_info_t *mac_control;
5922 struct config_param *config;
5923
5924 mac_control = &sp->mac_control;
5925 config = &sp->config;
5926
5927 if (!TASKLET_IN_USE) {
5928 for (i = 0; i < config->rx_ring_num; i++) {
5929 ret = fill_rx_buffers(sp, i);
5930 if (ret == -ENOMEM) {
5931 DBG_PRINT(ERR_DBG, "%s: Out of ",
5932 dev->name);
5933 DBG_PRINT(ERR_DBG, "memory in tasklet\n");
5934 break;
5935 } else if (ret == -EFILL) {
5936 DBG_PRINT(ERR_DBG,
5937 "%s: Rx Ring %d is full\n",
5938 dev->name, i);
5939 break;
5940 }
5941 }
5942 clear_bit(0, (&sp->tasklet_status));
5943 }
5944}
5945
5946/**
5947 * s2io_set_link - Set the LInk status
5948 * @data: long pointer to device private structue
5949 * Description: Sets the link status for the adapter
5950 */
5951
David Howellsc4028952006-11-22 14:57:56 +00005952static void s2io_set_link(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953{
David Howellsc4028952006-11-22 14:57:56 +00005954 nic_t *nic = container_of(work, nic_t, set_link_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955 struct net_device *dev = nic->dev;
5956 XENA_dev_config_t __iomem *bar0 = nic->bar0;
5957 register u64 val64;
5958 u16 subid;
5959
5960 if (test_and_set_bit(0, &(nic->link_state))) {
5961 /* The card is being reset, no point doing anything */
5962 return;
5963 }
5964
5965 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07005966 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
5967 /*
5968 * Allow a small delay for the NICs self initiated
5969 * cleanup to complete.
5970 */
5971 msleep(100);
5972 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973
5974 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05005975 if (LINK_IS_UP(val64)) {
5976 if (!(readq(&bar0->adapter_control) & ADAPTER_CNTL_EN)) {
5977 if (verify_xena_quiescence(nic)) {
5978 val64 = readq(&bar0->adapter_control);
5979 val64 |= ADAPTER_CNTL_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 writeq(val64, &bar0->adapter_control);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05005981 if (CARDS_WITH_FAULTY_LINK_INDICATORS(
5982 nic->device_type, subid)) {
5983 val64 = readq(&bar0->gpio_control);
5984 val64 |= GPIO_CTRL_GPIO_0;
5985 writeq(val64, &bar0->gpio_control);
5986 val64 = readq(&bar0->gpio_control);
5987 } else {
5988 val64 |= ADAPTER_LED_ON;
5989 writeq(val64, &bar0->adapter_control);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07005990 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991 nic->device_enabled_once = TRUE;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05005992 } else {
5993 DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
5994 DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
5995 netif_stop_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005996 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005997 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05005998 val64 = readq(&bar0->adapter_status);
5999 if (!LINK_IS_UP(val64)) {
6000 DBG_PRINT(ERR_DBG, "%s:", dev->name);
6001 DBG_PRINT(ERR_DBG, " Link down after enabling ");
6002 DBG_PRINT(ERR_DBG, "device \n");
6003 } else
6004 s2io_link(nic, LINK_UP);
6005 } else {
6006 if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
6007 subid)) {
6008 val64 = readq(&bar0->gpio_control);
6009 val64 &= ~GPIO_CTRL_GPIO_0;
6010 writeq(val64, &bar0->gpio_control);
6011 val64 = readq(&bar0->gpio_control);
6012 }
6013 s2io_link(nic, LINK_DOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014 }
6015 clear_bit(0, &(nic->link_state));
6016}
6017
Ananda Raju5d3213c2006-04-21 19:23:26 -04006018static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
6019 struct sk_buff **skb, u64 *temp0, u64 *temp1,
6020 u64 *temp2, int size)
6021{
6022 struct net_device *dev = sp->dev;
6023 struct sk_buff *frag_list;
6024
6025 if ((sp->rxd_mode == RXD_MODE_1) && (rxdp->Host_Control == 0)) {
6026 /* allocate skb */
6027 if (*skb) {
6028 DBG_PRINT(INFO_DBG, "SKB is not NULL\n");
6029 /*
6030 * As Rx frame are not going to be processed,
6031 * using same mapped address for the Rxd
6032 * buffer pointer
6033 */
6034 ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0;
6035 } else {
6036 *skb = dev_alloc_skb(size);
6037 if (!(*skb)) {
6038 DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
6039 DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
6040 return -ENOMEM ;
6041 }
6042 /* storing the mapped addr in a temp variable
6043 * such it will be used for next rxd whose
6044 * Host Control is NULL
6045 */
6046 ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0 =
6047 pci_map_single( sp->pdev, (*skb)->data,
6048 size - NET_IP_ALIGN,
6049 PCI_DMA_FROMDEVICE);
6050 rxdp->Host_Control = (unsigned long) (*skb);
6051 }
6052 } else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
6053 /* Two buffer Mode */
6054 if (*skb) {
6055 ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
6056 ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
6057 ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
6058 } else {
6059 *skb = dev_alloc_skb(size);
David Rientjes2ceaac72006-10-30 14:19:25 -08006060 if (!(*skb)) {
6061 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006062 dev->name);
David Rientjes2ceaac72006-10-30 14:19:25 -08006063 return -ENOMEM;
6064 }
Ananda Raju5d3213c2006-04-21 19:23:26 -04006065 ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
6066 pci_map_single(sp->pdev, (*skb)->data,
6067 dev->mtu + 4,
6068 PCI_DMA_FROMDEVICE);
6069 ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
6070 pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
6071 PCI_DMA_FROMDEVICE);
6072 rxdp->Host_Control = (unsigned long) (*skb);
6073
6074 /* Buffer-1 will be dummy buffer not used */
6075 ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
6076 pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
6077 PCI_DMA_FROMDEVICE);
6078 }
6079 } else if ((rxdp->Host_Control == 0)) {
6080 /* Three buffer mode */
6081 if (*skb) {
6082 ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
6083 ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
6084 ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
6085 } else {
6086 *skb = dev_alloc_skb(size);
David Rientjes2ceaac72006-10-30 14:19:25 -08006087 if (!(*skb)) {
6088 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
6089 dev->name);
6090 return -ENOMEM;
6091 }
Ananda Raju5d3213c2006-04-21 19:23:26 -04006092 ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
6093 pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
6094 PCI_DMA_FROMDEVICE);
6095 /* Buffer-1 receives L3/L4 headers */
6096 ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
6097 pci_map_single( sp->pdev, (*skb)->data,
6098 l3l4hdr_size + 4,
6099 PCI_DMA_FROMDEVICE);
6100 /*
6101 * skb_shinfo(skb)->frag_list will have L4
6102 * data payload
6103 */
6104 skb_shinfo(*skb)->frag_list = dev_alloc_skb(dev->mtu +
6105 ALIGN_SIZE);
6106 if (skb_shinfo(*skb)->frag_list == NULL) {
6107 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb \
6108 failed\n ", dev->name);
6109 return -ENOMEM ;
6110 }
6111 frag_list = skb_shinfo(*skb)->frag_list;
6112 frag_list->next = NULL;
6113 /*
6114 * Buffer-2 receives L4 data payload
6115 */
6116 ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
6117 pci_map_single( sp->pdev, frag_list->data,
6118 dev->mtu, PCI_DMA_FROMDEVICE);
6119 }
6120 }
6121 return 0;
6122}
6123static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size)
6124{
6125 struct net_device *dev = sp->dev;
6126 if (sp->rxd_mode == RXD_MODE_1) {
6127 rxdp->Control_2 = SET_BUFFER0_SIZE_1( size - NET_IP_ALIGN);
6128 } else if (sp->rxd_mode == RXD_MODE_3B) {
6129 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
6130 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
6131 rxdp->Control_2 |= SET_BUFFER2_SIZE_3( dev->mtu + 4);
6132 } else {
6133 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
6134 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
6135 rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
6136 }
6137}
6138
6139static int rxd_owner_bit_reset(nic_t *sp)
6140{
6141 int i, j, k, blk_cnt = 0, size;
6142 mac_info_t * mac_control = &sp->mac_control;
6143 struct config_param *config = &sp->config;
6144 struct net_device *dev = sp->dev;
6145 RxD_t *rxdp = NULL;
6146 struct sk_buff *skb = NULL;
6147 buffAdd_t *ba = NULL;
6148 u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0;
6149
6150 /* Calculate the size based on ring mode */
6151 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
6152 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
6153 if (sp->rxd_mode == RXD_MODE_1)
6154 size += NET_IP_ALIGN;
6155 else if (sp->rxd_mode == RXD_MODE_3B)
6156 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
6157 else
6158 size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
6159
6160 for (i = 0; i < config->rx_ring_num; i++) {
6161 blk_cnt = config->rx_cfg[i].num_rxd /
6162 (rxd_count[sp->rxd_mode] +1);
6163
6164 for (j = 0; j < blk_cnt; j++) {
6165 for (k = 0; k < rxd_count[sp->rxd_mode]; k++) {
6166 rxdp = mac_control->rings[i].
6167 rx_blocks[j].rxds[k].virt_addr;
6168 if(sp->rxd_mode >= RXD_MODE_3A)
6169 ba = &mac_control->rings[i].ba[j][k];
6170 set_rxd_buffer_pointer(sp, rxdp, ba,
6171 &skb,(u64 *)&temp0_64,
6172 (u64 *)&temp1_64,
6173 (u64 *)&temp2_64, size);
6174
6175 set_rxd_buffer_size(sp, rxdp, size);
6176 wmb();
6177 /* flip the Ownership bit to Hardware */
6178 rxdp->Control_1 |= RXD_OWN_XENA;
6179 }
6180 }
6181 }
6182 return 0;
6183
6184}
6185
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006186static int s2io_add_isr(nic_t * sp)
6187{
6188 int ret = 0;
6189 struct net_device *dev = sp->dev;
6190 int err = 0;
6191
6192 if (sp->intr_type == MSI)
6193 ret = s2io_enable_msi(sp);
6194 else if (sp->intr_type == MSI_X)
6195 ret = s2io_enable_msi_x(sp);
6196 if (ret) {
6197 DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
6198 sp->intr_type = INTA;
6199 }
6200
6201 /* Store the values of the MSIX table in the nic_t structure */
6202 store_xmsi_data(sp);
6203
6204 /* After proper initialization of H/W, register ISR */
6205 if (sp->intr_type == MSI) {
6206 err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
6207 IRQF_SHARED, sp->name, dev);
6208 if (err) {
6209 pci_disable_msi(sp->pdev);
6210 DBG_PRINT(ERR_DBG, "%s: MSI registration failed\n",
6211 dev->name);
6212 return -1;
6213 }
6214 }
6215 if (sp->intr_type == MSI_X) {
6216 int i;
6217
6218 for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
6219 if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
6220 sprintf(sp->desc[i], "%s:MSI-X-%d-TX",
6221 dev->name, i);
6222 err = request_irq(sp->entries[i].vector,
6223 s2io_msix_fifo_handle, 0, sp->desc[i],
6224 sp->s2io_entries[i].arg);
6225 DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
6226 (unsigned long long)sp->msix_info[i].addr);
6227 } else {
6228 sprintf(sp->desc[i], "%s:MSI-X-%d-RX",
6229 dev->name, i);
6230 err = request_irq(sp->entries[i].vector,
6231 s2io_msix_ring_handle, 0, sp->desc[i],
6232 sp->s2io_entries[i].arg);
6233 DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
6234 (unsigned long long)sp->msix_info[i].addr);
6235 }
6236 if (err) {
6237 DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
6238 "failed\n", dev->name, i);
6239 DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
6240 return -1;
6241 }
6242 sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
6243 }
6244 }
6245 if (sp->intr_type == INTA) {
6246 err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
6247 sp->name, dev);
6248 if (err) {
6249 DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
6250 dev->name);
6251 return -1;
6252 }
6253 }
6254 return 0;
6255}
6256static void s2io_rem_isr(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257{
6258 int cnt = 0;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006259 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006261 if (sp->intr_type == MSI_X) {
6262 int i;
6263 u16 msi_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006265 for (i=1; (sp->s2io_entries[i].in_use ==
6266 MSIX_REGISTERED_SUCCESS); i++) {
6267 int vector = sp->entries[i].vector;
6268 void *arg = sp->s2io_entries[i].arg;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006269
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006270 free_irq(vector, arg);
6271 }
6272 pci_read_config_word(sp->pdev, 0x42, &msi_control);
6273 msi_control &= 0xFFFE; /* Disable MSI */
6274 pci_write_config_word(sp->pdev, 0x42, msi_control);
Ananda Rajuc92ca042006-04-21 19:18:03 -04006275
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006276 pci_disable_msix(sp->pdev);
6277 } else {
6278 free_irq(sp->pdev->irq, dev);
6279 if (sp->intr_type == MSI) {
6280 u16 val;
6281
6282 pci_disable_msi(sp->pdev);
6283 pci_read_config_word(sp->pdev, 0x4c, &val);
6284 val ^= 0x1;
6285 pci_write_config_word(sp->pdev, 0x4c, val);
Ananda Rajuc92ca042006-04-21 19:18:03 -04006286 }
6287 }
6288 /* Waiting till all Interrupt handlers are complete */
6289 cnt = 0;
6290 do {
6291 msleep(10);
6292 if (!atomic_read(&sp->isr_cnt))
6293 break;
6294 cnt++;
6295 } while(cnt < 5);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006296}
6297
6298static void s2io_card_down(nic_t * sp)
6299{
6300 int cnt = 0;
6301 XENA_dev_config_t __iomem *bar0 = sp->bar0;
6302 unsigned long flags;
6303 register u64 val64 = 0;
6304
6305 del_timer_sync(&sp->alarm_timer);
6306 /* If s2io_set_link task is executing, wait till it completes. */
6307 while (test_and_set_bit(0, &(sp->link_state))) {
6308 msleep(50);
6309 }
6310 atomic_set(&sp->card_state, CARD_DOWN);
6311
6312 /* disable Tx and Rx traffic on the NIC */
6313 stop_nic(sp);
6314
6315 s2io_rem_isr(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316
6317 /* Kill tasklet. */
6318 tasklet_kill(&sp->task);
6319
6320 /* Check if the device is Quiescent and then Reset the NIC */
6321 do {
Ananda Raju5d3213c2006-04-21 19:23:26 -04006322 /* As per the HW requirement we need to replenish the
6323 * receive buffer to avoid the ring bump. Since there is
6324 * no intention of processing the Rx frame at this pointwe are
6325 * just settting the ownership bit of rxd in Each Rx
6326 * ring to HW and set the appropriate buffer size
6327 * based on the ring mode
6328 */
6329 rxd_owner_bit_reset(sp);
6330
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006332 if (verify_xena_quiescence(sp)) {
6333 if(verify_pcc_quiescent(sp, sp->device_enabled_once))
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334 break;
6335 }
6336
6337 msleep(50);
6338 cnt++;
6339 if (cnt == 10) {
6340 DBG_PRINT(ERR_DBG,
6341 "s2io_close:Device not Quiescent ");
6342 DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n",
6343 (unsigned long long) val64);
6344 break;
6345 }
6346 } while (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347 s2io_reset(sp);
6348
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006349 spin_lock_irqsave(&sp->tx_lock, flags);
6350 /* Free all Tx buffers */
6351 free_tx_buffers(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006352 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006353
6354 /* Free all Rx buffers */
6355 spin_lock_irqsave(&sp->rx_lock, flags);
6356 free_rx_buffers(sp);
6357 spin_unlock_irqrestore(&sp->rx_lock, flags);
6358
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359 clear_bit(0, &(sp->link_state));
6360}
6361
6362static int s2io_card_up(nic_t * sp)
6363{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006364 int i, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006365 mac_info_t *mac_control;
6366 struct config_param *config;
6367 struct net_device *dev = (struct net_device *) sp->dev;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006368 u16 interruptible;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369
6370 /* Initialize the H/W I/O registers */
6371 if (init_nic(sp) != 0) {
6372 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
6373 dev->name);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006374 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006375 return -ENODEV;
6376 }
6377
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006378 /*
6379 * Initializing the Rx buffers. For now we are considering only 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07006380 * Rx ring and initializing buffers into 30 Rx blocks
6381 */
6382 mac_control = &sp->mac_control;
6383 config = &sp->config;
6384
6385 for (i = 0; i < config->rx_ring_num; i++) {
6386 if ((ret = fill_rx_buffers(sp, i))) {
6387 DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
6388 dev->name);
6389 s2io_reset(sp);
6390 free_rx_buffers(sp);
6391 return -ENOMEM;
6392 }
6393 DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
6394 atomic_read(&sp->rx_bufs_left[i]));
6395 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006396 /* Maintain the state prior to the open */
6397 if (sp->promisc_flg)
6398 sp->promisc_flg = 0;
6399 if (sp->m_cast_flg) {
6400 sp->m_cast_flg = 0;
6401 sp->all_multi_pos= 0;
6402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403
6404 /* Setting its receive mode */
6405 s2io_set_multicast(dev);
6406
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006407 if (sp->lro) {
Ananda Rajub41477f2006-07-24 19:52:49 -04006408 /* Initialize max aggregatable pkts per session based on MTU */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006409 sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
6410 /* Check if we can use(if specified) user provided value */
6411 if (lro_max_pkts < sp->lro_max_aggr_per_sess)
6412 sp->lro_max_aggr_per_sess = lro_max_pkts;
6413 }
6414
Linus Torvalds1da177e2005-04-16 15:20:36 -07006415 /* Enable Rx Traffic and interrupts on the NIC */
6416 if (start_nic(sp)) {
6417 DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006418 s2io_reset(sp);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006419 free_rx_buffers(sp);
6420 return -ENODEV;
6421 }
6422
6423 /* Add interrupt service routine */
6424 if (s2io_add_isr(sp) != 0) {
6425 if (sp->intr_type == MSI_X)
6426 s2io_rem_isr(sp);
6427 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428 free_rx_buffers(sp);
6429 return -ENODEV;
6430 }
6431
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07006432 S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
6433
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006434 /* Enable tasklet for the device */
6435 tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
6436
6437 /* Enable select interrupts */
6438 if (sp->intr_type != INTA)
6439 en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
6440 else {
6441 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
6442 interruptible |= TX_PIC_INTR | RX_PIC_INTR;
6443 interruptible |= TX_MAC_INTR | RX_MAC_INTR;
6444 en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS);
6445 }
6446
6447
Linus Torvalds1da177e2005-04-16 15:20:36 -07006448 atomic_set(&sp->card_state, CARD_UP);
6449 return 0;
6450}
6451
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006452/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006453 * s2io_restart_nic - Resets the NIC.
6454 * @data : long pointer to the device private structure
6455 * Description:
6456 * This function is scheduled to be run by the s2io_tx_watchdog
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006457 * function after 0.5 secs to reset the NIC. The idea is to reduce
Linus Torvalds1da177e2005-04-16 15:20:36 -07006458 * the run time of the watch dog routine which is run holding a
6459 * spin lock.
6460 */
6461
David Howellsc4028952006-11-22 14:57:56 +00006462static void s2io_restart_nic(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006463{
David Howellsc4028952006-11-22 14:57:56 +00006464 nic_t *sp = container_of(work, nic_t, rst_timer_task);
6465 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006466
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006467 s2io_card_down(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006468 if (s2io_card_up(sp)) {
6469 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
6470 dev->name);
6471 }
6472 netif_wake_queue(dev);
6473 DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
6474 dev->name);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006475
Linus Torvalds1da177e2005-04-16 15:20:36 -07006476}
6477
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006478/**
6479 * s2io_tx_watchdog - Watchdog for transmit side.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006480 * @dev : Pointer to net device structure
6481 * Description:
6482 * This function is triggered if the Tx Queue is stopped
6483 * for a pre-defined amount of time when the Interface is still up.
6484 * If the Interface is jammed in such a situation, the hardware is
6485 * reset (by s2io_close) and restarted again (by s2io_open) to
6486 * overcome any problem that might have been caused in the hardware.
6487 * Return value:
6488 * void
6489 */
6490
6491static void s2io_tx_watchdog(struct net_device *dev)
6492{
6493 nic_t *sp = dev->priv;
6494
6495 if (netif_carrier_ok(dev)) {
6496 schedule_work(&sp->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04006497 sp->mac_control.stats_info->sw_stat.soft_reset_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006498 }
6499}
6500
6501/**
6502 * rx_osm_handler - To perform some OS related operations on SKB.
6503 * @sp: private member of the device structure,pointer to s2io_nic structure.
6504 * @skb : the socket buffer pointer.
6505 * @len : length of the packet
6506 * @cksum : FCS checksum of the frame.
6507 * @ring_no : the ring from which this RxD was extracted.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006508 * Description:
Ananda Rajub41477f2006-07-24 19:52:49 -04006509 * This function is called by the Rx interrupt serivce routine to perform
Linus Torvalds1da177e2005-04-16 15:20:36 -07006510 * some OS related operations on the SKB before passing it to the upper
6511 * layers. It mainly checks if the checksum is OK, if so adds it to the
6512 * SKBs cksum variable, increments the Rx packet count and passes the SKB
6513 * to the upper layer. If the checksum is wrong, it increments the Rx
6514 * packet error count, frees the SKB and returns error.
6515 * Return value:
6516 * SUCCESS on success and -1 on failure.
6517 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006518static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006519{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006520 nic_t *sp = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006521 struct net_device *dev = (struct net_device *) sp->dev;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006522 struct sk_buff *skb = (struct sk_buff *)
6523 ((unsigned long) rxdp->Host_Control);
6524 int ring_no = ring_data->ring_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006525 u16 l3_csum, l4_csum;
Ananda Raju863c11a2006-04-21 19:03:13 -04006526 unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006527 lro_t *lro;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006528
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006529 skb->dev = dev;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006530
Ananda Raju863c11a2006-04-21 19:03:13 -04006531 if (err) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04006532 /* Check for parity error */
6533 if (err & 0x1) {
6534 sp->mac_control.stats_info->sw_stat.parity_err_cnt++;
6535 }
6536
Ananda Raju863c11a2006-04-21 19:03:13 -04006537 /*
6538 * Drop the packet if bad transfer code. Exception being
6539 * 0x5, which could be due to unsupported IPv6 extension header.
6540 * In this case, we let stack handle the packet.
6541 * Note that in this case, since checksum will be incorrect,
6542 * stack will validate the same.
6543 */
6544 if (err && ((err >> 48) != 0x5)) {
6545 DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
6546 dev->name, err);
6547 sp->stats.rx_crc_errors++;
6548 dev_kfree_skb(skb);
6549 atomic_dec(&sp->rx_bufs_left[ring_no]);
6550 rxdp->Host_Control = 0;
6551 return 0;
6552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006554
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006555 /* Updating statistics */
6556 rxdp->Host_Control = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006557 sp->rx_pkt_count++;
6558 sp->stats.rx_packets++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006559 if (sp->rxd_mode == RXD_MODE_1) {
6560 int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006561
Ananda Rajuda6971d2005-10-31 16:55:31 -05006562 sp->stats.rx_bytes += len;
6563 skb_put(skb, len);
6564
6565 } else if (sp->rxd_mode >= RXD_MODE_3A) {
6566 int get_block = ring_data->rx_curr_get_info.block_index;
6567 int get_off = ring_data->rx_curr_get_info.offset;
6568 int buf0_len = RXD_GET_BUFFER0_SIZE_3(rxdp->Control_2);
6569 int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
6570 unsigned char *buff = skb_push(skb, buf0_len);
6571
6572 buffAdd_t *ba = &ring_data->ba[get_block][get_off];
6573 sp->stats.rx_bytes += buf0_len + buf2_len;
6574 memcpy(buff, ba->ba_0, buf0_len);
6575
6576 if (sp->rxd_mode == RXD_MODE_3A) {
6577 int buf1_len = RXD_GET_BUFFER1_SIZE_3(rxdp->Control_2);
6578
6579 skb_put(skb, buf1_len);
6580 skb->len += buf2_len;
6581 skb->data_len += buf2_len;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006582 skb_put(skb_shinfo(skb)->frag_list, buf2_len);
6583 sp->stats.rx_bytes += buf1_len;
6584
6585 } else
6586 skb_put(skb, buf2_len);
6587 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006588
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006589 if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
6590 (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006591 (sp->rx_csum)) {
6592 l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
6593 l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
6594 if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) {
6595 /*
6596 * NIC verifies if the Checksum of the received
6597 * frame is Ok or not and accordingly returns
6598 * a flag in the RxD.
6599 */
6600 skb->ip_summed = CHECKSUM_UNNECESSARY;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006601 if (sp->lro) {
6602 u32 tcp_len;
6603 u8 *tcp;
6604 int ret = 0;
6605
6606 ret = s2io_club_tcp_session(skb->data, &tcp,
6607 &tcp_len, &lro, rxdp, sp);
6608 switch (ret) {
6609 case 3: /* Begin anew */
6610 lro->parent = skb;
6611 goto aggregate;
6612 case 1: /* Aggregate */
6613 {
6614 lro_append_pkt(sp, lro,
6615 skb, tcp_len);
6616 goto aggregate;
6617 }
6618 case 4: /* Flush session */
6619 {
6620 lro_append_pkt(sp, lro,
6621 skb, tcp_len);
6622 queue_rx_frame(lro->parent);
6623 clear_lro_session(lro);
6624 sp->mac_control.stats_info->
6625 sw_stat.flush_max_pkts++;
6626 goto aggregate;
6627 }
6628 case 2: /* Flush both */
6629 lro->parent->data_len =
6630 lro->frags_len;
6631 sp->mac_control.stats_info->
6632 sw_stat.sending_both++;
6633 queue_rx_frame(lro->parent);
6634 clear_lro_session(lro);
6635 goto send_up;
6636 case 0: /* sessions exceeded */
Ananda Rajuc92ca042006-04-21 19:18:03 -04006637 case -1: /* non-TCP or not
6638 * L2 aggregatable
6639 */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006640 case 5: /*
6641 * First pkt in session not
6642 * L3/L4 aggregatable
6643 */
6644 break;
6645 default:
6646 DBG_PRINT(ERR_DBG,
6647 "%s: Samadhana!!\n",
6648 __FUNCTION__);
6649 BUG();
6650 }
6651 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006652 } else {
6653 /*
6654 * Packet with erroneous checksum, let the
6655 * upper layers deal with it.
6656 */
6657 skb->ip_summed = CHECKSUM_NONE;
6658 }
6659 } else {
6660 skb->ip_summed = CHECKSUM_NONE;
6661 }
6662
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006663 if (!sp->lro) {
6664 skb->protocol = eth_type_trans(skb, dev);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006665 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
6666 /* Queueing the vlan frame to the upper layer */
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05006667 if (napi)
6668 vlan_hwaccel_receive_skb(skb, sp->vlgrp,
6669 RXD_GET_VLAN_TAG(rxdp->Control_2));
6670 else
6671 vlan_hwaccel_rx(skb, sp->vlgrp,
6672 RXD_GET_VLAN_TAG(rxdp->Control_2));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006673 } else {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05006674 if (napi)
6675 netif_receive_skb(skb);
6676 else
6677 netif_rx(skb);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006678 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006679 } else {
6680send_up:
6681 queue_rx_frame(skb);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006682 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006683 dev->last_rx = jiffies;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006684aggregate:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006685 atomic_dec(&sp->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006686 return SUCCESS;
6687}
6688
6689/**
6690 * s2io_link - stops/starts the Tx queue.
6691 * @sp : private member of the device structure, which is a pointer to the
6692 * s2io_nic structure.
6693 * @link : inidicates whether link is UP/DOWN.
6694 * Description:
6695 * This function stops/starts the Tx queue depending on whether the link
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006696 * status of the NIC is is down or up. This is called by the Alarm
6697 * interrupt handler whenever a link change interrupt comes up.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006698 * Return value:
6699 * void.
6700 */
6701
Adrian Bunk26df54b2006-01-14 03:09:40 +01006702static void s2io_link(nic_t * sp, int link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006703{
6704 struct net_device *dev = (struct net_device *) sp->dev;
6705
6706 if (link != sp->last_link_state) {
6707 if (link == LINK_DOWN) {
6708 DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
6709 netif_carrier_off(dev);
6710 } else {
6711 DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
6712 netif_carrier_on(dev);
6713 }
6714 }
6715 sp->last_link_state = link;
6716}
6717
6718/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006719 * get_xena_rev_id - to identify revision ID of xena.
6720 * @pdev : PCI Dev structure
6721 * Description:
6722 * Function to identify the Revision ID of xena.
6723 * Return value:
6724 * returns the revision ID of the device.
6725 */
6726
Adrian Bunk26df54b2006-01-14 03:09:40 +01006727static int get_xena_rev_id(struct pci_dev *pdev)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006728{
6729 u8 id = 0;
6730 int ret;
6731 ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id);
6732 return id;
6733}
6734
6735/**
6736 * s2io_init_pci -Initialization of PCI and PCI-X configuration registers .
6737 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07006738 * s2io_nic structure.
6739 * Description:
6740 * This function initializes a few of the PCI and PCI-X configuration registers
6741 * with recommended values.
6742 * Return value:
6743 * void
6744 */
6745
6746static void s2io_init_pci(nic_t * sp)
6747{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006748 u16 pci_cmd = 0, pcix_cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006749
6750 /* Enable Data Parity Error Recovery in PCI-X command register. */
6751 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006752 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006753 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006754 (pcix_cmd | 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006755 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006756 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006757
6758 /* Set the PErr Response bit in PCI command register. */
6759 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
6760 pci_write_config_word(sp->pdev, PCI_COMMAND,
6761 (pci_cmd | PCI_COMMAND_PARITY));
6762 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006763}
6764
Ananda Raju9dc737a2006-04-21 19:05:41 -04006765static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
6766{
6767 if ( tx_fifo_num > 8) {
6768 DBG_PRINT(ERR_DBG, "s2io: Requested number of Tx fifos not "
6769 "supported\n");
6770 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Tx fifos\n");
6771 tx_fifo_num = 8;
6772 }
6773 if ( rx_ring_num > 8) {
6774 DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
6775 "supported\n");
6776 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
6777 rx_ring_num = 8;
6778 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05006779 if (*dev_intr_type != INTA)
6780 napi = 0;
6781
Ananda Raju9dc737a2006-04-21 19:05:41 -04006782#ifndef CONFIG_PCI_MSI
6783 if (*dev_intr_type != INTA) {
6784 DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
6785 "MSI/MSI-X. Defaulting to INTA\n");
6786 *dev_intr_type = INTA;
6787 }
6788#else
6789 if (*dev_intr_type > MSI_X) {
6790 DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
6791 "Defaulting to INTA\n");
6792 *dev_intr_type = INTA;
6793 }
6794#endif
6795 if ((*dev_intr_type == MSI_X) &&
6796 ((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
6797 (pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006798 DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. "
Ananda Raju9dc737a2006-04-21 19:05:41 -04006799 "Defaulting to INTA\n");
6800 *dev_intr_type = INTA;
6801 }
Sivakumar Subramani372cc592007-01-31 13:32:57 -05006802 if ( (rx_ring_num > 1) && (*dev_intr_type != INTA) )
6803 napi = 0;
Ananda Raju9dc737a2006-04-21 19:05:41 -04006804 if (rx_ring_mode > 3) {
6805 DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
6806 DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
6807 rx_ring_mode = 3;
6808 }
6809 return SUCCESS;
6810}
6811
Linus Torvalds1da177e2005-04-16 15:20:36 -07006812/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006813 * s2io_init_nic - Initialization of the adapter .
Linus Torvalds1da177e2005-04-16 15:20:36 -07006814 * @pdev : structure containing the PCI related information of the device.
6815 * @pre: List of PCI devices supported by the driver listed in s2io_tbl.
6816 * Description:
6817 * The function initializes an adapter identified by the pci_dec structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006818 * All OS related initialization including memory and device structure and
6819 * initlaization of the device private variable is done. Also the swapper
6820 * control register is initialized to enable read and write into the I/O
Linus Torvalds1da177e2005-04-16 15:20:36 -07006821 * registers of the device.
6822 * Return value:
6823 * returns 0 on success and negative on failure.
6824 */
6825
6826static int __devinit
6827s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
6828{
6829 nic_t *sp;
6830 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006831 int i, j, ret;
6832 int dma_flag = FALSE;
6833 u32 mac_up, mac_down;
6834 u64 val64 = 0, tmp64 = 0;
6835 XENA_dev_config_t __iomem *bar0 = NULL;
6836 u16 subid;
6837 mac_info_t *mac_control;
6838 struct config_param *config;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006839 int mode;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006840 u8 dev_intr_type = intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006841
Ananda Raju9dc737a2006-04-21 19:05:41 -04006842 if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
6843 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006844
6845 if ((ret = pci_enable_device(pdev))) {
6846 DBG_PRINT(ERR_DBG,
6847 "s2io_init_nic: pci_enable_device failed\n");
6848 return ret;
6849 }
6850
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006851 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006852 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
6853 dma_flag = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006854 if (pci_set_consistent_dma_mask
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006855 (pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006856 DBG_PRINT(ERR_DBG,
6857 "Unable to obtain 64bit DMA for \
6858 consistent allocations\n");
6859 pci_disable_device(pdev);
6860 return -ENOMEM;
6861 }
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006862 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006863 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n");
6864 } else {
6865 pci_disable_device(pdev);
6866 return -ENOMEM;
6867 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006868 if (dev_intr_type != MSI_X) {
6869 if (pci_request_regions(pdev, s2io_driver_name)) {
Ananda Rajub41477f2006-07-24 19:52:49 -04006870 DBG_PRINT(ERR_DBG, "Request Regions failed\n");
6871 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006872 return -ENODEV;
6873 }
6874 }
6875 else {
6876 if (!(request_mem_region(pci_resource_start(pdev, 0),
6877 pci_resource_len(pdev, 0), s2io_driver_name))) {
6878 DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n");
6879 pci_disable_device(pdev);
6880 return -ENODEV;
6881 }
6882 if (!(request_mem_region(pci_resource_start(pdev, 2),
6883 pci_resource_len(pdev, 2), s2io_driver_name))) {
6884 DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n");
6885 release_mem_region(pci_resource_start(pdev, 0),
6886 pci_resource_len(pdev, 0));
6887 pci_disable_device(pdev);
6888 return -ENODEV;
6889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006890 }
6891
6892 dev = alloc_etherdev(sizeof(nic_t));
6893 if (dev == NULL) {
6894 DBG_PRINT(ERR_DBG, "Device allocation failed\n");
6895 pci_disable_device(pdev);
6896 pci_release_regions(pdev);
6897 return -ENODEV;
6898 }
6899
6900 pci_set_master(pdev);
6901 pci_set_drvdata(pdev, dev);
6902 SET_MODULE_OWNER(dev);
6903 SET_NETDEV_DEV(dev, &pdev->dev);
6904
6905 /* Private member variable initialized to s2io NIC structure */
6906 sp = dev->priv;
6907 memset(sp, 0, sizeof(nic_t));
6908 sp->dev = dev;
6909 sp->pdev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006910 sp->high_dma_flag = dma_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006911 sp->device_enabled_once = FALSE;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006912 if (rx_ring_mode == 1)
6913 sp->rxd_mode = RXD_MODE_1;
6914 if (rx_ring_mode == 2)
6915 sp->rxd_mode = RXD_MODE_3B;
6916 if (rx_ring_mode == 3)
6917 sp->rxd_mode = RXD_MODE_3A;
6918
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006919 sp->intr_type = dev_intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006920
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006921 if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
6922 (pdev->device == PCI_DEVICE_ID_HERC_UNI))
6923 sp->device_type = XFRAME_II_DEVICE;
6924 else
6925 sp->device_type = XFRAME_I_DEVICE;
6926
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006927 sp->lro = lro;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006928
Linus Torvalds1da177e2005-04-16 15:20:36 -07006929 /* Initialize some PCI/PCI-X fields of the NIC. */
6930 s2io_init_pci(sp);
6931
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006932 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006933 * Setting the device configuration parameters.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006934 * Most of these parameters can be specified by the user during
6935 * module insertion as they are module loadable parameters. If
6936 * these parameters are not not specified during load time, they
Linus Torvalds1da177e2005-04-16 15:20:36 -07006937 * are initialized with default values.
6938 */
6939 mac_control = &sp->mac_control;
6940 config = &sp->config;
6941
6942 /* Tx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006943 config->tx_fifo_num = tx_fifo_num;
6944 for (i = 0; i < MAX_TX_FIFOS; i++) {
6945 config->tx_cfg[i].fifo_len = tx_fifo_len[i];
6946 config->tx_cfg[i].fifo_priority = i;
6947 }
6948
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006949 /* mapping the QoS priority to the configured fifos */
6950 for (i = 0; i < MAX_TX_FIFOS; i++)
6951 config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i];
6952
Linus Torvalds1da177e2005-04-16 15:20:36 -07006953 config->tx_intr_type = TXD_INT_TYPE_UTILZ;
6954 for (i = 0; i < config->tx_fifo_num; i++) {
6955 config->tx_cfg[i].f_no_snoop =
6956 (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER);
6957 if (config->tx_cfg[i].fifo_len < 65) {
6958 config->tx_intr_type = TXD_INT_TYPE_PER_LIST;
6959 break;
6960 }
6961 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05006962 /* + 2 because one Txd for skb->data and one Txd for UFO */
6963 config->max_txds = MAX_SKB_FRAGS + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006964
6965 /* Rx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006966 config->rx_ring_num = rx_ring_num;
6967 for (i = 0; i < MAX_RX_RINGS; i++) {
6968 config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
Ananda Rajuda6971d2005-10-31 16:55:31 -05006969 (rxd_count[sp->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006970 config->rx_cfg[i].ring_priority = i;
6971 }
6972
6973 for (i = 0; i < rx_ring_num; i++) {
6974 config->rx_cfg[i].ring_org = RING_ORG_BUFF1;
6975 config->rx_cfg[i].f_no_snoop =
6976 (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER);
6977 }
6978
6979 /* Setting Mac Control parameters */
6980 mac_control->rmac_pause_time = rmac_pause_time;
6981 mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3;
6982 mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
6983
6984
6985 /* Initialize Ring buffer parameters. */
6986 for (i = 0; i < config->rx_ring_num; i++)
6987 atomic_set(&sp->rx_bufs_left[i], 0);
6988
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006989 /* Initialize the number of ISRs currently running */
6990 atomic_set(&sp->isr_cnt, 0);
6991
Linus Torvalds1da177e2005-04-16 15:20:36 -07006992 /* initialize the shared memory used by the NIC and the host */
6993 if (init_shared_mem(sp)) {
6994 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
Ananda Rajub41477f2006-07-24 19:52:49 -04006995 dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006996 ret = -ENOMEM;
6997 goto mem_alloc_failed;
6998 }
6999
7000 sp->bar0 = ioremap(pci_resource_start(pdev, 0),
7001 pci_resource_len(pdev, 0));
7002 if (!sp->bar0) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007003 DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007004 dev->name);
7005 ret = -ENOMEM;
7006 goto bar0_remap_failed;
7007 }
7008
7009 sp->bar1 = ioremap(pci_resource_start(pdev, 2),
7010 pci_resource_len(pdev, 2));
7011 if (!sp->bar1) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007012 DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007013 dev->name);
7014 ret = -ENOMEM;
7015 goto bar1_remap_failed;
7016 }
7017
7018 dev->irq = pdev->irq;
7019 dev->base_addr = (unsigned long) sp->bar0;
7020
7021 /* Initializing the BAR1 address as the start of the FIFO pointer. */
7022 for (j = 0; j < MAX_TX_FIFOS; j++) {
7023 mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *)
7024 (sp->bar1 + (j * 0x00020000));
7025 }
7026
7027 /* Driver entry points */
7028 dev->open = &s2io_open;
7029 dev->stop = &s2io_close;
7030 dev->hard_start_xmit = &s2io_xmit;
7031 dev->get_stats = &s2io_get_stats;
7032 dev->set_multicast_list = &s2io_set_multicast;
7033 dev->do_ioctl = &s2io_ioctl;
7034 dev->change_mtu = &s2io_change_mtu;
7035 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07007036 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
7037 dev->vlan_rx_register = s2io_vlan_rx_register;
7038 dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007039
Linus Torvalds1da177e2005-04-16 15:20:36 -07007040 /*
7041 * will use eth_mac_addr() for dev->set_mac_address
7042 * mac address will be set every time dev->open() is called
7043 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007044 dev->poll = s2io_poll;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007045 dev->weight = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007046
Brian Haley612eff02006-06-15 14:36:36 -04007047#ifdef CONFIG_NET_POLL_CONTROLLER
7048 dev->poll_controller = s2io_netpoll;
7049#endif
7050
Linus Torvalds1da177e2005-04-16 15:20:36 -07007051 dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
7052 if (sp->high_dma_flag == TRUE)
7053 dev->features |= NETIF_F_HIGHDMA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007054 dev->features |= NETIF_F_TSO;
Herbert Xuf83ef8c2006-06-30 13:37:03 -07007055 dev->features |= NETIF_F_TSO6;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007056 if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05007057 dev->features |= NETIF_F_UFO;
7058 dev->features |= NETIF_F_HW_CSUM;
7059 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007060
7061 dev->tx_timeout = &s2io_tx_watchdog;
7062 dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
David Howellsc4028952006-11-22 14:57:56 +00007063 INIT_WORK(&sp->rst_timer_task, s2io_restart_nic);
7064 INIT_WORK(&sp->set_link_task, s2io_set_link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007065
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07007066 pci_save_state(sp->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007067
7068 /* Setting swapper control on the NIC, for proper reset operation */
7069 if (s2io_set_swapper(sp)) {
7070 DBG_PRINT(ERR_DBG, "%s:swapper settings are wrong\n",
7071 dev->name);
7072 ret = -EAGAIN;
7073 goto set_swap_failed;
7074 }
7075
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007076 /* Verify if the Herc works on the slot its placed into */
7077 if (sp->device_type & XFRAME_II_DEVICE) {
7078 mode = s2io_verify_pci_mode(sp);
7079 if (mode < 0) {
7080 DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__);
7081 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
7082 ret = -EBADSLT;
7083 goto set_swap_failed;
7084 }
7085 }
7086
7087 /* Not needed for Herc */
7088 if (sp->device_type & XFRAME_I_DEVICE) {
7089 /*
7090 * Fix for all "FFs" MAC address problems observed on
7091 * Alpha platforms
7092 */
7093 fix_mac_address(sp);
7094 s2io_reset(sp);
7095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007096
7097 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007098 * MAC address initialization.
7099 * For now only one mac address will be read and used.
7100 */
7101 bar0 = sp->bar0;
7102 val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
7103 RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
7104 writeq(val64, &bar0->rmac_addr_cmd_mem);
Ananda Rajuc92ca042006-04-21 19:18:03 -04007105 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
7106 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007107 tmp64 = readq(&bar0->rmac_addr_data0_mem);
7108 mac_down = (u32) tmp64;
7109 mac_up = (u32) (tmp64 >> 32);
7110
7111 memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
7112
7113 sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up);
7114 sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8);
7115 sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16);
7116 sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_up >> 24);
7117 sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16);
7118 sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24);
7119
Linus Torvalds1da177e2005-04-16 15:20:36 -07007120 /* Set the factory defined MAC address initially */
7121 dev->addr_len = ETH_ALEN;
7122 memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
7123
Ananda Rajub41477f2006-07-24 19:52:49 -04007124 /* reset Nic and bring it to known state */
7125 s2io_reset(sp);
7126
Linus Torvalds1da177e2005-04-16 15:20:36 -07007127 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007128 * Initialize the tasklet status and link state flags
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007129 * and the card state parameter
Linus Torvalds1da177e2005-04-16 15:20:36 -07007130 */
7131 atomic_set(&(sp->card_state), 0);
7132 sp->tasklet_status = 0;
7133 sp->link_state = 0;
7134
Linus Torvalds1da177e2005-04-16 15:20:36 -07007135 /* Initialize spinlocks */
7136 spin_lock_init(&sp->tx_lock);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007137
7138 if (!napi)
7139 spin_lock_init(&sp->put_lock);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007140 spin_lock_init(&sp->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007141
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007142 /*
7143 * SXE-002: Configure link and activity LED to init state
7144 * on driver load.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007145 */
7146 subid = sp->pdev->subsystem_device;
7147 if ((subid & 0xFF) >= 0x07) {
7148 val64 = readq(&bar0->gpio_control);
7149 val64 |= 0x0000800000000000ULL;
7150 writeq(val64, &bar0->gpio_control);
7151 val64 = 0x0411040400000000ULL;
7152 writeq(val64, (void __iomem *) bar0 + 0x2700);
7153 val64 = readq(&bar0->gpio_control);
7154 }
7155
7156 sp->rx_csum = 1; /* Rx chksum verify enabled by default */
7157
7158 if (register_netdev(dev)) {
7159 DBG_PRINT(ERR_DBG, "Device registration failed\n");
7160 ret = -ENODEV;
7161 goto register_failed;
7162 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04007163 s2io_vpd_read(sp);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007164 DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n");
Ananda Rajub41477f2006-07-24 19:52:49 -04007165 DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name,
7166 sp->product_name, get_xena_rev_id(sp->pdev));
7167 DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
7168 s2io_driver_version);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007169 DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007170 "%02x:%02x:%02x:%02x:%02x:%02x", dev->name,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007171 sp->def_mac_addr[0].mac_addr[0],
7172 sp->def_mac_addr[0].mac_addr[1],
7173 sp->def_mac_addr[0].mac_addr[2],
7174 sp->def_mac_addr[0].mac_addr[3],
7175 sp->def_mac_addr[0].mac_addr[4],
7176 sp->def_mac_addr[0].mac_addr[5]);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007177 DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007178 if (sp->device_type & XFRAME_II_DEVICE) {
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07007179 mode = s2io_print_pci_mode(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007180 if (mode < 0) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04007181 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007182 ret = -EBADSLT;
Ananda Raju9dc737a2006-04-21 19:05:41 -04007183 unregister_netdev(dev);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007184 goto set_swap_failed;
7185 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007186 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04007187 switch(sp->rxd_mode) {
7188 case RXD_MODE_1:
7189 DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n",
7190 dev->name);
7191 break;
7192 case RXD_MODE_3B:
7193 DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n",
7194 dev->name);
7195 break;
7196 case RXD_MODE_3A:
7197 DBG_PRINT(ERR_DBG, "%s: 3-Buffer receive mode enabled\n",
7198 dev->name);
7199 break;
7200 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007201
7202 if (napi)
7203 DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007204 switch(sp->intr_type) {
7205 case INTA:
7206 DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
7207 break;
7208 case MSI:
7209 DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI\n", dev->name);
7210 break;
7211 case MSI_X:
7212 DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
7213 break;
7214 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007215 if (sp->lro)
7216 DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
Ananda Raju9dc737a2006-04-21 19:05:41 -04007217 dev->name);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007218 if (ufo)
7219 DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)"
7220 " enabled\n", dev->name);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007221 /* Initialize device name */
Ananda Raju9dc737a2006-04-21 19:05:41 -04007222 sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007223
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07007224 /* Initialize bimodal Interrupts */
7225 sp->config.bimodal = bimodal;
7226 if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) {
7227 sp->config.bimodal = 0;
7228 DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n",
7229 dev->name);
7230 }
7231
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007232 /*
7233 * Make Link state as off at this point, when the Link change
7234 * interrupt comes the state will be automatically changed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07007235 * the right state.
7236 */
7237 netif_carrier_off(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007238
7239 return 0;
7240
7241 register_failed:
7242 set_swap_failed:
7243 iounmap(sp->bar1);
7244 bar1_remap_failed:
7245 iounmap(sp->bar0);
7246 bar0_remap_failed:
7247 mem_alloc_failed:
7248 free_shared_mem(sp);
7249 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007250 if (dev_intr_type != MSI_X)
7251 pci_release_regions(pdev);
7252 else {
7253 release_mem_region(pci_resource_start(pdev, 0),
7254 pci_resource_len(pdev, 0));
7255 release_mem_region(pci_resource_start(pdev, 2),
7256 pci_resource_len(pdev, 2));
7257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007258 pci_set_drvdata(pdev, NULL);
7259 free_netdev(dev);
7260
7261 return ret;
7262}
7263
7264/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007265 * s2io_rem_nic - Free the PCI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07007266 * @pdev: structure containing the PCI related information of the device.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007267 * Description: This function is called by the Pci subsystem to release a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007268 * PCI device and free up all resource held up by the device. This could
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007269 * be in response to a Hot plug event or when the driver is to be removed
Linus Torvalds1da177e2005-04-16 15:20:36 -07007270 * from memory.
7271 */
7272
7273static void __devexit s2io_rem_nic(struct pci_dev *pdev)
7274{
7275 struct net_device *dev =
7276 (struct net_device *) pci_get_drvdata(pdev);
7277 nic_t *sp;
7278
7279 if (dev == NULL) {
7280 DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
7281 return;
7282 }
7283
7284 sp = dev->priv;
7285 unregister_netdev(dev);
7286
7287 free_shared_mem(sp);
7288 iounmap(sp->bar0);
7289 iounmap(sp->bar1);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007290 if (sp->intr_type != MSI_X)
7291 pci_release_regions(pdev);
7292 else {
7293 release_mem_region(pci_resource_start(pdev, 0),
7294 pci_resource_len(pdev, 0));
7295 release_mem_region(pci_resource_start(pdev, 2),
7296 pci_resource_len(pdev, 2));
7297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007298 pci_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007299 free_netdev(dev);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007300 pci_disable_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007301}
7302
7303/**
7304 * s2io_starter - Entry point for the driver
7305 * Description: This function is the entry point for the driver. It verifies
7306 * the module loadable parameters and initializes PCI configuration space.
7307 */
7308
7309int __init s2io_starter(void)
7310{
Jeff Garzik29917622006-08-19 17:48:59 -04007311 return pci_register_driver(&s2io_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007312}
7313
7314/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007315 * s2io_closer - Cleanup routine for the driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07007316 * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
7317 */
7318
Sivakumar Subramani372cc592007-01-31 13:32:57 -05007319static __exit void s2io_closer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007320{
7321 pci_unregister_driver(&s2io_driver);
7322 DBG_PRINT(INIT_DBG, "cleanup done\n");
7323}
7324
7325module_init(s2io_starter);
7326module_exit(s2io_closer);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007327
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007328static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007329 struct tcphdr **tcp, RxD_t *rxdp)
7330{
7331 int ip_off;
7332 u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
7333
7334 if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) {
7335 DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n",
7336 __FUNCTION__);
7337 return -1;
7338 }
7339
7340 /* TODO:
7341 * By default the VLAN field in the MAC is stripped by the card, if this
7342 * feature is turned off in rx_pa_cfg register, then the ip_off field
7343 * has to be shifted by a further 2 bytes
7344 */
7345 switch (l2_type) {
7346 case 0: /* DIX type */
7347 case 4: /* DIX type with VLAN */
7348 ip_off = HEADER_ETHERNET_II_802_3_SIZE;
7349 break;
7350 /* LLC, SNAP etc are considered non-mergeable */
7351 default:
7352 return -1;
7353 }
7354
7355 *ip = (struct iphdr *)((u8 *)buffer + ip_off);
7356 ip_len = (u8)((*ip)->ihl);
7357 ip_len <<= 2;
7358 *tcp = (struct tcphdr *)((unsigned long)*ip + ip_len);
7359
7360 return 0;
7361}
7362
7363static int check_for_socket_match(lro_t *lro, struct iphdr *ip,
7364 struct tcphdr *tcp)
7365{
7366 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7367 if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) ||
7368 (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest))
7369 return -1;
7370 return 0;
7371}
7372
7373static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
7374{
7375 return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
7376}
7377
7378static void initiate_new_session(lro_t *lro, u8 *l2h,
7379 struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
7380{
7381 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7382 lro->l2h = l2h;
7383 lro->iph = ip;
7384 lro->tcph = tcp;
7385 lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq);
7386 lro->tcp_ack = ntohl(tcp->ack_seq);
7387 lro->sg_num = 1;
7388 lro->total_len = ntohs(ip->tot_len);
7389 lro->frags_len = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007390 /*
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007391 * check if we saw TCP timestamp. Other consistency checks have
7392 * already been done.
7393 */
7394 if (tcp->doff == 8) {
7395 u32 *ptr;
7396 ptr = (u32 *)(tcp+1);
7397 lro->saw_ts = 1;
7398 lro->cur_tsval = *(ptr+1);
7399 lro->cur_tsecr = *(ptr+2);
7400 }
7401 lro->in_use = 1;
7402}
7403
7404static void update_L3L4_header(nic_t *sp, lro_t *lro)
7405{
7406 struct iphdr *ip = lro->iph;
7407 struct tcphdr *tcp = lro->tcph;
7408 u16 nchk;
7409 StatInfo_t *statinfo = sp->mac_control.stats_info;
7410 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7411
7412 /* Update L3 header */
7413 ip->tot_len = htons(lro->total_len);
7414 ip->check = 0;
7415 nchk = ip_fast_csum((u8 *)lro->iph, ip->ihl);
7416 ip->check = nchk;
7417
7418 /* Update L4 header */
7419 tcp->ack_seq = lro->tcp_ack;
7420 tcp->window = lro->window;
7421
7422 /* Update tsecr field if this session has timestamps enabled */
7423 if (lro->saw_ts) {
7424 u32 *ptr = (u32 *)(tcp + 1);
7425 *(ptr+2) = lro->cur_tsecr;
7426 }
7427
7428 /* Update counters required for calculation of
7429 * average no. of packets aggregated.
7430 */
7431 statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num;
7432 statinfo->sw_stat.num_aggregations++;
7433}
7434
7435static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
7436 struct tcphdr *tcp, u32 l4_pyld)
7437{
7438 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7439 lro->total_len += l4_pyld;
7440 lro->frags_len += l4_pyld;
7441 lro->tcp_next_seq += l4_pyld;
7442 lro->sg_num++;
7443
7444 /* Update ack seq no. and window ad(from this pkt) in LRO object */
7445 lro->tcp_ack = tcp->ack_seq;
7446 lro->window = tcp->window;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007447
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007448 if (lro->saw_ts) {
7449 u32 *ptr;
7450 /* Update tsecr and tsval from this packet */
7451 ptr = (u32 *) (tcp + 1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007452 lro->cur_tsval = *(ptr + 1);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007453 lro->cur_tsecr = *(ptr + 2);
7454 }
7455}
7456
7457static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
7458 struct tcphdr *tcp, u32 tcp_pyld_len)
7459{
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007460 u8 *ptr;
7461
Andrew Morton79dc1902006-02-03 01:45:13 -08007462 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7463
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007464 if (!tcp_pyld_len) {
7465 /* Runt frame or a pure ack */
7466 return -1;
7467 }
7468
7469 if (ip->ihl != 5) /* IP has options */
7470 return -1;
7471
Ananda Raju75c30b12006-07-24 19:55:09 -04007472 /* If we see CE codepoint in IP header, packet is not mergeable */
7473 if (INET_ECN_is_ce(ipv4_get_dsfield(ip)))
7474 return -1;
7475
7476 /* If we see ECE or CWR flags in TCP header, packet is not mergeable */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007477 if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin ||
Ananda Raju75c30b12006-07-24 19:55:09 -04007478 tcp->ece || tcp->cwr || !tcp->ack) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007479 /*
7480 * Currently recognize only the ack control word and
7481 * any other control field being set would result in
7482 * flushing the LRO session
7483 */
7484 return -1;
7485 }
7486
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007487 /*
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007488 * Allow only one TCP timestamp option. Don't aggregate if
7489 * any other options are detected.
7490 */
7491 if (tcp->doff != 5 && tcp->doff != 8)
7492 return -1;
7493
7494 if (tcp->doff == 8) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007495 ptr = (u8 *)(tcp + 1);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007496 while (*ptr == TCPOPT_NOP)
7497 ptr++;
7498 if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP)
7499 return -1;
7500
7501 /* Ensure timestamp value increases monotonically */
7502 if (l_lro)
7503 if (l_lro->cur_tsval > *((u32 *)(ptr+2)))
7504 return -1;
7505
7506 /* timestamp echo reply should be non-zero */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007507 if (*((u32 *)(ptr+6)) == 0)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007508 return -1;
7509 }
7510
7511 return 0;
7512}
7513
7514static int
7515s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
7516 RxD_t *rxdp, nic_t *sp)
7517{
7518 struct iphdr *ip;
7519 struct tcphdr *tcph;
7520 int ret = 0, i;
7521
7522 if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp,
7523 rxdp))) {
7524 DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n",
7525 ip->saddr, ip->daddr);
7526 } else {
7527 return ret;
7528 }
7529
7530 tcph = (struct tcphdr *)*tcp;
7531 *tcp_len = get_l4_pyld_length(ip, tcph);
7532 for (i=0; i<MAX_LRO_SESSIONS; i++) {
7533 lro_t *l_lro = &sp->lro0_n[i];
7534 if (l_lro->in_use) {
7535 if (check_for_socket_match(l_lro, ip, tcph))
7536 continue;
7537 /* Sock pair matched */
7538 *lro = l_lro;
7539
7540 if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) {
7541 DBG_PRINT(INFO_DBG, "%s:Out of order. expected "
7542 "0x%x, actual 0x%x\n", __FUNCTION__,
7543 (*lro)->tcp_next_seq,
7544 ntohl(tcph->seq));
7545
7546 sp->mac_control.stats_info->
7547 sw_stat.outof_sequence_pkts++;
7548 ret = 2;
7549 break;
7550 }
7551
7552 if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len))
7553 ret = 1; /* Aggregate */
7554 else
7555 ret = 2; /* Flush both */
7556 break;
7557 }
7558 }
7559
7560 if (ret == 0) {
7561 /* Before searching for available LRO objects,
7562 * check if the pkt is L3/L4 aggregatable. If not
7563 * don't create new LRO session. Just send this
7564 * packet up.
7565 */
7566 if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) {
7567 return 5;
7568 }
7569
7570 for (i=0; i<MAX_LRO_SESSIONS; i++) {
7571 lro_t *l_lro = &sp->lro0_n[i];
7572 if (!(l_lro->in_use)) {
7573 *lro = l_lro;
7574 ret = 3; /* Begin anew */
7575 break;
7576 }
7577 }
7578 }
7579
7580 if (ret == 0) { /* sessions exceeded */
7581 DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n",
7582 __FUNCTION__);
7583 *lro = NULL;
7584 return ret;
7585 }
7586
7587 switch (ret) {
7588 case 3:
7589 initiate_new_session(*lro, buffer, ip, tcph, *tcp_len);
7590 break;
7591 case 2:
7592 update_L3L4_header(sp, *lro);
7593 break;
7594 case 1:
7595 aggregate_new_rx(*lro, ip, tcph, *tcp_len);
7596 if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) {
7597 update_L3L4_header(sp, *lro);
7598 ret = 4; /* Flush the LRO */
7599 }
7600 break;
7601 default:
7602 DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n",
7603 __FUNCTION__);
7604 break;
7605 }
7606
7607 return ret;
7608}
7609
7610static void clear_lro_session(lro_t *lro)
7611{
7612 static u16 lro_struct_size = sizeof(lro_t);
7613
7614 memset(lro, 0, lro_struct_size);
7615}
7616
7617static void queue_rx_frame(struct sk_buff *skb)
7618{
7619 struct net_device *dev = skb->dev;
7620
7621 skb->protocol = eth_type_trans(skb, dev);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007622 if (napi)
7623 netif_receive_skb(skb);
7624 else
7625 netif_rx(skb);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007626}
7627
7628static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
7629 u32 tcp_len)
7630{
Ananda Raju75c30b12006-07-24 19:55:09 -04007631 struct sk_buff *first = lro->parent;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007632
7633 first->len += tcp_len;
7634 first->data_len = lro->frags_len;
7635 skb_pull(skb, (skb->len - tcp_len));
Ananda Raju75c30b12006-07-24 19:55:09 -04007636 if (skb_shinfo(first)->frag_list)
7637 lro->last_frag->next = skb;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007638 else
7639 skb_shinfo(first)->frag_list = skb;
Sivakumar Subramani372cc592007-01-31 13:32:57 -05007640 first->truesize += skb->truesize;
Ananda Raju75c30b12006-07-24 19:55:09 -04007641 lro->last_frag = skb;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007642 sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
7643 return;
7644}