blob: 350723bd5eb813ceb59de73342faaa73b7588ceb [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;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700462 int i, j, blk_cnt, rx_sz, tx_sz;
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);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700487 tx_sz = lst_size * size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 lst_per_page = PAGE_SIZE / lst_size;
489
490 for (i = 0; i < config->tx_fifo_num; i++) {
491 int fifo_len = config->tx_cfg[i].fifo_len;
492 int list_holder_size = fifo_len * sizeof(list_info_hold_t);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700493 mac_control->fifos[i].list_info = kmalloc(list_holder_size,
494 GFP_KERNEL);
495 if (!mac_control->fifos[i].list_info) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 DBG_PRINT(ERR_DBG,
497 "Malloc failed for list_info\n");
498 return -ENOMEM;
499 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700500 memset(mac_control->fifos[i].list_info, 0, list_holder_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 }
502 for (i = 0; i < config->tx_fifo_num; i++) {
503 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
504 lst_per_page);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700505 mac_control->fifos[i].tx_curr_put_info.offset = 0;
506 mac_control->fifos[i].tx_curr_put_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700508 mac_control->fifos[i].tx_curr_get_info.offset = 0;
509 mac_control->fifos[i].tx_curr_get_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700511 mac_control->fifos[i].fifo_no = i;
512 mac_control->fifos[i].nic = nic;
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500513 mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 2;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 for (j = 0; j < page_num; j++) {
516 int k = 0;
517 dma_addr_t tmp_p;
518 void *tmp_v;
519 tmp_v = pci_alloc_consistent(nic->pdev,
520 PAGE_SIZE, &tmp_p);
521 if (!tmp_v) {
522 DBG_PRINT(ERR_DBG,
523 "pci_alloc_consistent ");
524 DBG_PRINT(ERR_DBG, "failed for TxDL\n");
525 return -ENOMEM;
526 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700527 /* If we got a zero DMA address(can happen on
528 * certain platforms like PPC), reallocate.
529 * Store virtual address of page we don't want,
530 * to be freed later.
531 */
532 if (!tmp_p) {
533 mac_control->zerodma_virt_addr = tmp_v;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400534 DBG_PRINT(INIT_DBG,
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700535 "%s: Zero DMA address for TxDL. ", dev->name);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400536 DBG_PRINT(INIT_DBG,
Andrew Morton6b4d6172005-09-12 23:21:55 -0700537 "Virtual address %p\n", tmp_v);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700538 tmp_v = pci_alloc_consistent(nic->pdev,
539 PAGE_SIZE, &tmp_p);
540 if (!tmp_v) {
541 DBG_PRINT(ERR_DBG,
542 "pci_alloc_consistent ");
543 DBG_PRINT(ERR_DBG, "failed for TxDL\n");
544 return -ENOMEM;
545 }
546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 while (k < lst_per_page) {
548 int l = (j * lst_per_page) + k;
549 if (l == config->tx_cfg[i].fifo_len)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700550 break;
551 mac_control->fifos[i].list_info[l].list_virt_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 tmp_v + (k * lst_size);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700553 mac_control->fifos[i].list_info[l].list_phy_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 tmp_p + (k * lst_size);
555 k++;
556 }
557 }
558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
Al Viro43842472007-01-23 12:25:08 +0000560 nic->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL);
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500561 if (!nic->ufo_in_band_v)
562 return -ENOMEM;
563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 /* Allocation and initialization of RXDs in Rings */
565 size = 0;
566 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -0500567 if (config->rx_cfg[i].num_rxd %
568 (rxd_count[nic->rxd_mode] + 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 DBG_PRINT(ERR_DBG, "%s: RxD count of ", dev->name);
570 DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ",
571 i);
572 DBG_PRINT(ERR_DBG, "RxDs per Block");
573 return FAILURE;
574 }
575 size += config->rx_cfg[i].num_rxd;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700576 mac_control->rings[i].block_count =
Ananda Rajuda6971d2005-10-31 16:55:31 -0500577 config->rx_cfg[i].num_rxd /
578 (rxd_count[nic->rxd_mode] + 1 );
579 mac_control->rings[i].pkt_cnt = config->rx_cfg[i].num_rxd -
580 mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500582 if (nic->rxd_mode == RXD_MODE_1)
583 size = (size * (sizeof(RxD1_t)));
584 else
585 size = (size * (sizeof(RxD3_t)));
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700586 rx_sz = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
588 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700589 mac_control->rings[i].rx_curr_get_info.block_index = 0;
590 mac_control->rings[i].rx_curr_get_info.offset = 0;
591 mac_control->rings[i].rx_curr_get_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700593 mac_control->rings[i].rx_curr_put_info.block_index = 0;
594 mac_control->rings[i].rx_curr_put_info.offset = 0;
595 mac_control->rings[i].rx_curr_put_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700597 mac_control->rings[i].nic = nic;
598 mac_control->rings[i].ring_no = i;
599
Ananda Rajuda6971d2005-10-31 16:55:31 -0500600 blk_cnt = config->rx_cfg[i].num_rxd /
601 (rxd_count[nic->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 /* Allocating all the Rx blocks */
603 for (j = 0; j < blk_cnt; j++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -0500604 rx_block_info_t *rx_blocks;
605 int l;
606
607 rx_blocks = &mac_control->rings[i].rx_blocks[j];
608 size = SIZE_OF_BLOCK; //size is always page size
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 tmp_v_addr = pci_alloc_consistent(nic->pdev, size,
610 &tmp_p_addr);
611 if (tmp_v_addr == NULL) {
612 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700613 * In case of failure, free_shared_mem()
614 * is called, which should free any
615 * memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 * failure happened.
617 */
Ananda Rajuda6971d2005-10-31 16:55:31 -0500618 rx_blocks->block_virt_addr = tmp_v_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 return -ENOMEM;
620 }
621 memset(tmp_v_addr, 0, size);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500622 rx_blocks->block_virt_addr = tmp_v_addr;
623 rx_blocks->block_dma_addr = tmp_p_addr;
624 rx_blocks->rxds = kmalloc(sizeof(rxd_info_t)*
625 rxd_count[nic->rxd_mode],
626 GFP_KERNEL);
627 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;
2262 frag_list->next = NULL;
Jeff Garzik50eb8002005-11-05 23:40:46 -05002263 tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
2264 frag_list->data = tmp;
2265 frag_list->tail = tmp;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002266
2267 /* Buffer-2 receives L4 data payload */
2268 ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
2269 frag_list->data, dev->mtu,
2270 PCI_DMA_FROMDEVICE);
2271 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
2272 rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
2273
2274 return SUCCESS;
2275}
2276
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002277/**
2278 * fill_rx_buffers - Allocates the Rx side skbs
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002280 * @ring_no: ring number
2281 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 * The function allocates Rx side skbs and puts the physical
2283 * address of these buffers into the RxD buffer pointers, so that the NIC
2284 * can DMA the received frame into these locations.
2285 * The NIC supports 3 receive modes, viz
2286 * 1. single buffer,
2287 * 2. three buffer and
2288 * 3. Five buffer modes.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002289 * Each mode defines how many fragments the received frame will be split
2290 * up into by the NIC. The frame is split into L3 header, L4 Header,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 * L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself
2292 * is split into 3 fragments. As of now only single buffer mode is
2293 * supported.
2294 * Return Value:
2295 * SUCCESS on success or an appropriate -ve value on failure.
2296 */
2297
Adrian Bunkac1f60d2005-11-06 01:46:47 +01002298static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299{
2300 struct net_device *dev = nic->dev;
2301 struct sk_buff *skb;
2302 RxD_t *rxdp;
2303 int off, off1, size, block_no, block_no1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 u32 alloc_tab = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002305 u32 alloc_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 mac_info_t *mac_control;
2307 struct config_param *config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002308 u64 tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 buffAdd_t *ba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 unsigned long flags;
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002311 RxD_t *first_rxdp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312
2313 mac_control = &nic->mac_control;
2314 config = &nic->config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002315 alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
2316 atomic_read(&nic->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
Ananda Raju5d3213c2006-04-21 19:23:26 -04002318 block_no1 = mac_control->rings[ring_no].rx_curr_get_info.block_index;
Ananda Raju863c11a2006-04-21 19:03:13 -04002319 off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 while (alloc_tab < alloc_cnt) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002321 block_no = mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 block_index;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002323 off = mac_control->rings[ring_no].rx_curr_put_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324
Ananda Rajuda6971d2005-10-31 16:55:31 -05002325 rxdp = mac_control->rings[ring_no].
2326 rx_blocks[block_no].rxds[off].virt_addr;
2327
2328 if ((block_no == block_no1) && (off == off1) &&
2329 (rxdp->Host_Control)) {
2330 DBG_PRINT(INTR_DBG, "%s: Get and Put",
2331 dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 DBG_PRINT(INTR_DBG, " info equated\n");
2333 goto end;
2334 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002335 if (off && (off == rxd_count[nic->rxd_mode])) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002336 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 block_index++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002338 if (mac_control->rings[ring_no].rx_curr_put_info.
2339 block_index == mac_control->rings[ring_no].
2340 block_count)
2341 mac_control->rings[ring_no].rx_curr_put_info.
2342 block_index = 0;
2343 block_no = mac_control->rings[ring_no].
2344 rx_curr_put_info.block_index;
2345 if (off == rxd_count[nic->rxd_mode])
2346 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002347 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002348 offset = off;
2349 rxdp = mac_control->rings[ring_no].
2350 rx_blocks[block_no].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
2352 dev->name, rxdp);
2353 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002354 if(!napi) {
2355 spin_lock_irqsave(&nic->put_lock, flags);
2356 mac_control->rings[ring_no].put_pos =
2357 (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
2358 spin_unlock_irqrestore(&nic->put_lock, flags);
2359 } else {
2360 mac_control->rings[ring_no].put_pos =
2361 (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
2362 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002363 if ((rxdp->Control_1 & RXD_OWN_XENA) &&
2364 ((nic->rxd_mode >= RXD_MODE_3A) &&
2365 (rxdp->Control_2 & BIT(0)))) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002366 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002367 offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 goto end;
2369 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002370 /* calculate size of skb based on ring mode */
2371 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
2372 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
2373 if (nic->rxd_mode == RXD_MODE_1)
2374 size += NET_IP_ALIGN;
2375 else if (nic->rxd_mode == RXD_MODE_3B)
2376 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
2377 else
2378 size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379
Ananda Rajuda6971d2005-10-31 16:55:31 -05002380 /* allocate skb */
2381 skb = dev_alloc_skb(size);
2382 if(!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
2384 DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002385 if (first_rxdp) {
2386 wmb();
2387 first_rxdp->Control_1 |= RXD_OWN_XENA;
2388 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002389 return -ENOMEM ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002391 if (nic->rxd_mode == RXD_MODE_1) {
2392 /* 1 buffer mode - normal operation mode */
2393 memset(rxdp, 0, sizeof(RxD1_t));
2394 skb_reserve(skb, NET_IP_ALIGN);
2395 ((RxD1_t*)rxdp)->Buffer0_ptr = pci_map_single
Ananda Raju863c11a2006-04-21 19:03:13 -04002396 (nic->pdev, skb->data, size - NET_IP_ALIGN,
2397 PCI_DMA_FROMDEVICE);
2398 rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002399
2400 } else if (nic->rxd_mode >= RXD_MODE_3A) {
2401 /*
2402 * 2 or 3 buffer mode -
2403 * Both 2 buffer mode and 3 buffer mode provides 128
2404 * byte aligned receive buffers.
2405 *
2406 * 3 buffer mode provides header separation where in
2407 * skb->data will have L3/L4 headers where as
2408 * skb_shinfo(skb)->frag_list will have the L4 data
2409 * payload
2410 */
2411
2412 memset(rxdp, 0, sizeof(RxD3_t));
2413 ba = &mac_control->rings[ring_no].ba[block_no][off];
2414 skb_reserve(skb, BUF0_LEN);
2415 tmp = (u64)(unsigned long) skb->data;
2416 tmp += ALIGN_SIZE;
2417 tmp &= ~ALIGN_SIZE;
2418 skb->data = (void *) (unsigned long)tmp;
2419 skb->tail = (void *) (unsigned long)tmp;
2420
Ananda Raju75c30b12006-07-24 19:55:09 -04002421 if (!(((RxD3_t*)rxdp)->Buffer0_ptr))
2422 ((RxD3_t*)rxdp)->Buffer0_ptr =
2423 pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002424 PCI_DMA_FROMDEVICE);
Ananda Raju75c30b12006-07-24 19:55:09 -04002425 else
2426 pci_dma_sync_single_for_device(nic->pdev,
2427 (dma_addr_t) ((RxD3_t*)rxdp)->Buffer0_ptr,
2428 BUF0_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002429 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
2430 if (nic->rxd_mode == RXD_MODE_3B) {
2431 /* Two buffer mode */
2432
2433 /*
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002434 * Buffer2 will have L3/L4 header plus
Ananda Rajuda6971d2005-10-31 16:55:31 -05002435 * L4 payload
2436 */
2437 ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single
2438 (nic->pdev, skb->data, dev->mtu + 4,
2439 PCI_DMA_FROMDEVICE);
2440
Ananda Raju75c30b12006-07-24 19:55:09 -04002441 /* Buffer-1 will be dummy buffer. Not used */
2442 if (!(((RxD3_t*)rxdp)->Buffer1_ptr)) {
2443 ((RxD3_t*)rxdp)->Buffer1_ptr =
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002444 pci_map_single(nic->pdev,
Ananda Raju75c30b12006-07-24 19:55:09 -04002445 ba->ba_1, BUF1_LEN,
2446 PCI_DMA_FROMDEVICE);
2447 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002448 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
2449 rxdp->Control_2 |= SET_BUFFER2_SIZE_3
2450 (dev->mtu + 4);
2451 } else {
2452 /* 3 buffer mode */
2453 if (fill_rxd_3buf(nic, rxdp, skb) == -ENOMEM) {
2454 dev_kfree_skb_irq(skb);
2455 if (first_rxdp) {
2456 wmb();
2457 first_rxdp->Control_1 |=
2458 RXD_OWN_XENA;
2459 }
2460 return -ENOMEM ;
2461 }
2462 }
2463 rxdp->Control_2 |= BIT(0);
2464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 rxdp->Host_Control = (unsigned long) (skb);
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002466 if (alloc_tab & ((1 << rxsync_frequency) - 1))
2467 rxdp->Control_1 |= RXD_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 off++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002469 if (off == (rxd_count[nic->rxd_mode] + 1))
2470 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002471 mac_control->rings[ring_no].rx_curr_put_info.offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002473 rxdp->Control_2 |= SET_RXD_MARKER;
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002474 if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
2475 if (first_rxdp) {
2476 wmb();
2477 first_rxdp->Control_1 |= RXD_OWN_XENA;
2478 }
2479 first_rxdp = rxdp;
2480 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 atomic_inc(&nic->rx_bufs_left[ring_no]);
2482 alloc_tab++;
2483 }
2484
2485 end:
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002486 /* Transfer ownership of first descriptor to adapter just before
2487 * exiting. Before that, use memory barrier so that ownership
2488 * and other fields are seen by adapter correctly.
2489 */
2490 if (first_rxdp) {
2491 wmb();
2492 first_rxdp->Control_1 |= RXD_OWN_XENA;
2493 }
2494
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 return SUCCESS;
2496}
2497
Ananda Rajuda6971d2005-10-31 16:55:31 -05002498static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
2499{
2500 struct net_device *dev = sp->dev;
2501 int j;
2502 struct sk_buff *skb;
2503 RxD_t *rxdp;
2504 mac_info_t *mac_control;
2505 buffAdd_t *ba;
2506
2507 mac_control = &sp->mac_control;
2508 for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
2509 rxdp = mac_control->rings[ring_no].
2510 rx_blocks[blk].rxds[j].virt_addr;
2511 skb = (struct sk_buff *)
2512 ((unsigned long) rxdp->Host_Control);
2513 if (!skb) {
2514 continue;
2515 }
2516 if (sp->rxd_mode == RXD_MODE_1) {
2517 pci_unmap_single(sp->pdev, (dma_addr_t)
2518 ((RxD1_t*)rxdp)->Buffer0_ptr,
2519 dev->mtu +
2520 HEADER_ETHERNET_II_802_3_SIZE
2521 + HEADER_802_2_SIZE +
2522 HEADER_SNAP_SIZE,
2523 PCI_DMA_FROMDEVICE);
2524 memset(rxdp, 0, sizeof(RxD1_t));
2525 } else if(sp->rxd_mode == RXD_MODE_3B) {
2526 ba = &mac_control->rings[ring_no].
2527 ba[blk][j];
2528 pci_unmap_single(sp->pdev, (dma_addr_t)
2529 ((RxD3_t*)rxdp)->Buffer0_ptr,
2530 BUF0_LEN,
2531 PCI_DMA_FROMDEVICE);
2532 pci_unmap_single(sp->pdev, (dma_addr_t)
2533 ((RxD3_t*)rxdp)->Buffer1_ptr,
2534 BUF1_LEN,
2535 PCI_DMA_FROMDEVICE);
2536 pci_unmap_single(sp->pdev, (dma_addr_t)
2537 ((RxD3_t*)rxdp)->Buffer2_ptr,
2538 dev->mtu + 4,
2539 PCI_DMA_FROMDEVICE);
2540 memset(rxdp, 0, sizeof(RxD3_t));
2541 } else {
2542 pci_unmap_single(sp->pdev, (dma_addr_t)
2543 ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
2544 PCI_DMA_FROMDEVICE);
2545 pci_unmap_single(sp->pdev, (dma_addr_t)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002546 ((RxD3_t*)rxdp)->Buffer1_ptr,
Ananda Rajuda6971d2005-10-31 16:55:31 -05002547 l3l4hdr_size + 4,
2548 PCI_DMA_FROMDEVICE);
2549 pci_unmap_single(sp->pdev, (dma_addr_t)
2550 ((RxD3_t*)rxdp)->Buffer2_ptr, dev->mtu,
2551 PCI_DMA_FROMDEVICE);
2552 memset(rxdp, 0, sizeof(RxD3_t));
2553 }
2554 dev_kfree_skb(skb);
2555 atomic_dec(&sp->rx_bufs_left[ring_no]);
2556 }
2557}
2558
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002560 * free_rx_buffers - Frees all Rx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 * @sp: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002562 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 * This function will free all Rx buffers allocated by host.
2564 * Return Value:
2565 * NONE.
2566 */
2567
2568static void free_rx_buffers(struct s2io_nic *sp)
2569{
2570 struct net_device *dev = sp->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002571 int i, blk = 0, buf_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 mac_info_t *mac_control;
2573 struct config_param *config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574
2575 mac_control = &sp->mac_control;
2576 config = &sp->config;
2577
2578 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -05002579 for (blk = 0; blk < rx_ring_sz[i]; blk++)
2580 free_rxd_blk(sp,i,blk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002582 mac_control->rings[i].rx_curr_put_info.block_index = 0;
2583 mac_control->rings[i].rx_curr_get_info.block_index = 0;
2584 mac_control->rings[i].rx_curr_put_info.offset = 0;
2585 mac_control->rings[i].rx_curr_get_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 atomic_set(&sp->rx_bufs_left[i], 0);
2587 DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
2588 dev->name, buf_cnt, i);
2589 }
2590}
2591
2592/**
2593 * s2io_poll - Rx interrupt handler for NAPI support
2594 * @dev : pointer to the device structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002595 * @budget : The number of packets that were budgeted to be processed
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 * during one pass through the 'Poll" function.
2597 * Description:
2598 * Comes into picture only if NAPI support has been incorporated. It does
2599 * the same thing that rx_intr_handler does, but not in a interrupt context
2600 * also It will process only a given number of packets.
2601 * Return value:
2602 * 0 on success and 1 if there are No Rx packets to be processed.
2603 */
2604
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605static int s2io_poll(struct net_device *dev, int *budget)
2606{
2607 nic_t *nic = dev->priv;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002608 int pkt_cnt = 0, org_pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 mac_info_t *mac_control;
2610 struct config_param *config;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01002611 XENA_dev_config_t __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002612 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002614 atomic_inc(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 mac_control = &nic->mac_control;
2616 config = &nic->config;
2617
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002618 nic->pkts_to_process = *budget;
2619 if (nic->pkts_to_process > dev->quota)
2620 nic->pkts_to_process = dev->quota;
2621 org_pkts_to_process = nic->pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002623 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
2624 readl(&bar0->rx_traffic_int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
2626 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002627 rx_intr_handler(&mac_control->rings[i]);
2628 pkt_cnt = org_pkts_to_process - nic->pkts_to_process;
2629 if (!nic->pkts_to_process) {
2630 /* Quota for the current iteration has been met */
2631 goto no_rx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 }
2634 if (!pkt_cnt)
2635 pkt_cnt = 1;
2636
2637 dev->quota -= pkt_cnt;
2638 *budget -= pkt_cnt;
2639 netif_rx_complete(dev);
2640
2641 for (i = 0; i < config->rx_ring_num; i++) {
2642 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2643 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2644 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2645 break;
2646 }
2647 }
2648 /* Re enable the Rx interrupts. */
Ananda Rajuc92ca042006-04-21 19:18:03 -04002649 writeq(0x0, &bar0->rx_traffic_mask);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002650 readl(&bar0->rx_traffic_mask);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002651 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 return 0;
2653
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002654no_rx:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 dev->quota -= pkt_cnt;
2656 *budget -= pkt_cnt;
2657
2658 for (i = 0; i < config->rx_ring_num; i++) {
2659 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2660 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2661 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2662 break;
2663 }
2664 }
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002665 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 return 1;
2667}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002668
Ananda Rajub41477f2006-07-24 19:52:49 -04002669#ifdef CONFIG_NET_POLL_CONTROLLER
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002670/**
Ananda Rajub41477f2006-07-24 19:52:49 -04002671 * s2io_netpoll - netpoll event handler entry point
Brian Haley612eff02006-06-15 14:36:36 -04002672 * @dev : pointer to the device structure.
2673 * Description:
Ananda Rajub41477f2006-07-24 19:52:49 -04002674 * This function will be called by upper layer to check for events on the
2675 * interface in situations where interrupts are disabled. It is used for
2676 * specific in-kernel networking tasks, such as remote consoles and kernel
2677 * debugging over the network (example netdump in RedHat).
Brian Haley612eff02006-06-15 14:36:36 -04002678 */
Brian Haley612eff02006-06-15 14:36:36 -04002679static void s2io_netpoll(struct net_device *dev)
2680{
2681 nic_t *nic = dev->priv;
2682 mac_info_t *mac_control;
2683 struct config_param *config;
2684 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ananda Rajub41477f2006-07-24 19:52:49 -04002685 u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
Brian Haley612eff02006-06-15 14:36:36 -04002686 int i;
2687
2688 disable_irq(dev->irq);
2689
2690 atomic_inc(&nic->isr_cnt);
2691 mac_control = &nic->mac_control;
2692 config = &nic->config;
2693
Brian Haley612eff02006-06-15 14:36:36 -04002694 writeq(val64, &bar0->rx_traffic_int);
Ananda Rajub41477f2006-07-24 19:52:49 -04002695 writeq(val64, &bar0->tx_traffic_int);
Brian Haley612eff02006-06-15 14:36:36 -04002696
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002697 /* we need to free up the transmitted skbufs or else netpoll will
Ananda Rajub41477f2006-07-24 19:52:49 -04002698 * run out of skbs and will fail and eventually netpoll application such
2699 * as netdump will fail.
2700 */
2701 for (i = 0; i < config->tx_fifo_num; i++)
2702 tx_intr_handler(&mac_control->fifos[i]);
2703
2704 /* check for received packet and indicate up to network */
Brian Haley612eff02006-06-15 14:36:36 -04002705 for (i = 0; i < config->rx_ring_num; i++)
2706 rx_intr_handler(&mac_control->rings[i]);
2707
2708 for (i = 0; i < config->rx_ring_num; i++) {
2709 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2710 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2711 DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n");
2712 break;
2713 }
2714 }
2715 atomic_dec(&nic->isr_cnt);
2716 enable_irq(dev->irq);
2717 return;
2718}
2719#endif
2720
2721/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 * rx_intr_handler - Rx interrupt handler
2723 * @nic: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002724 * Description:
2725 * If the interrupt is because of a received frame or if the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 * receive ring contains fresh as yet un-processed frames,this function is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002727 * called. It picks out the RxD at which place the last Rx processing had
2728 * stopped and sends the skb to the OSM's Rx handler and then increments
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 * the offset.
2730 * Return Value:
2731 * NONE.
2732 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002733static void rx_intr_handler(ring_info_t *ring_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002735 nic_t *nic = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 struct net_device *dev = (struct net_device *) nic->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002737 int get_block, put_block, put_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 rx_curr_get_info_t get_info, put_info;
2739 RxD_t *rxdp;
2740 struct sk_buff *skb;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002741 int pkt_cnt = 0;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002742 int i;
2743
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002744 spin_lock(&nic->rx_lock);
2745 if (atomic_read(&nic->card_state) == CARD_DOWN) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002746 DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002747 __FUNCTION__, dev->name);
2748 spin_unlock(&nic->rx_lock);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002749 return;
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002750 }
2751
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002752 get_info = ring_data->rx_curr_get_info;
2753 get_block = get_info.block_index;
2754 put_info = ring_data->rx_curr_put_info;
2755 put_block = put_info.block_index;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002756 rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002757 if (!napi) {
2758 spin_lock(&nic->put_lock);
2759 put_offset = ring_data->put_pos;
2760 spin_unlock(&nic->put_lock);
2761 } else
2762 put_offset = ring_data->put_pos;
2763
Ananda Rajuda6971d2005-10-31 16:55:31 -05002764 while (RXD_IS_UP2DT(rxdp)) {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002765 /*
2766 * If your are next to put index then it's
2767 * FIFO full condition
2768 */
Ananda Rajuda6971d2005-10-31 16:55:31 -05002769 if ((get_block == put_block) &&
2770 (get_info.offset + 1) == put_info.offset) {
Ananda Raju75c30b12006-07-24 19:55:09 -04002771 DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002772 break;
2773 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002774 skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
2775 if (skb == NULL) {
2776 DBG_PRINT(ERR_DBG, "%s: The skb is ",
2777 dev->name);
2778 DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002779 spin_unlock(&nic->rx_lock);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002780 return;
2781 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002782 if (nic->rxd_mode == RXD_MODE_1) {
2783 pci_unmap_single(nic->pdev, (dma_addr_t)
2784 ((RxD1_t*)rxdp)->Buffer0_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002785 dev->mtu +
2786 HEADER_ETHERNET_II_802_3_SIZE +
2787 HEADER_802_2_SIZE +
2788 HEADER_SNAP_SIZE,
2789 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002790 } else if (nic->rxd_mode == RXD_MODE_3B) {
Ananda Raju75c30b12006-07-24 19:55:09 -04002791 pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
Ananda Rajuda6971d2005-10-31 16:55:31 -05002792 ((RxD3_t*)rxdp)->Buffer0_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002793 BUF0_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002794 pci_unmap_single(nic->pdev, (dma_addr_t)
Ananda Rajuda6971d2005-10-31 16:55:31 -05002795 ((RxD3_t*)rxdp)->Buffer2_ptr,
2796 dev->mtu + 4,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002797 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002798 } else {
Ananda Raju75c30b12006-07-24 19:55:09 -04002799 pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
Ananda Rajuda6971d2005-10-31 16:55:31 -05002800 ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
2801 PCI_DMA_FROMDEVICE);
2802 pci_unmap_single(nic->pdev, (dma_addr_t)
2803 ((RxD3_t*)rxdp)->Buffer1_ptr,
2804 l3l4hdr_size + 4,
2805 PCI_DMA_FROMDEVICE);
2806 pci_unmap_single(nic->pdev, (dma_addr_t)
2807 ((RxD3_t*)rxdp)->Buffer2_ptr,
2808 dev->mtu, PCI_DMA_FROMDEVICE);
2809 }
Ananda Raju863c11a2006-04-21 19:03:13 -04002810 prefetch(skb->data);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002811 rx_osm_handler(ring_data, rxdp);
2812 get_info.offset++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002813 ring_data->rx_curr_get_info.offset = get_info.offset;
2814 rxdp = ring_data->rx_blocks[get_block].
2815 rxds[get_info.offset].virt_addr;
2816 if (get_info.offset == rxd_count[nic->rxd_mode]) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002817 get_info.offset = 0;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002818 ring_data->rx_curr_get_info.offset = get_info.offset;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002819 get_block++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002820 if (get_block == ring_data->block_count)
2821 get_block = 0;
2822 ring_data->rx_curr_get_info.block_index = get_block;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002823 rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
2824 }
2825
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002826 nic->pkts_to_process -= 1;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05002827 if ((napi) && (!nic->pkts_to_process))
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002828 break;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002829 pkt_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
2831 break;
2832 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002833 if (nic->lro) {
2834 /* Clear all LRO sessions before exiting */
2835 for (i=0; i<MAX_LRO_SESSIONS; i++) {
2836 lro_t *lro = &nic->lro0_n[i];
2837 if (lro->in_use) {
2838 update_L3L4_header(nic, lro);
2839 queue_rx_frame(lro->parent);
2840 clear_lro_session(lro);
2841 }
2842 }
2843 }
2844
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002845 spin_unlock(&nic->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002847
2848/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 * tx_intr_handler - Transmit interrupt handler
2850 * @nic : device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002851 * Description:
2852 * If an interrupt was raised to indicate DMA complete of the
2853 * Tx packet, this function is called. It identifies the last TxD
2854 * whose buffer was freed and frees all skbs whose data have already
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 * DMA'ed into the NICs internal memory.
2856 * Return Value:
2857 * NONE
2858 */
2859
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002860static void tx_intr_handler(fifo_info_t *fifo_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002862 nic_t *nic = fifo_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 struct net_device *dev = (struct net_device *) nic->dev;
2864 tx_curr_get_info_t get_info, put_info;
2865 struct sk_buff *skb;
2866 TxD_t *txdlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002868 get_info = fifo_data->tx_curr_get_info;
2869 put_info = fifo_data->tx_curr_put_info;
2870 txdlp = (TxD_t *) fifo_data->list_info[get_info.offset].
2871 list_virt_addr;
2872 while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
2873 (get_info.offset != put_info.offset) &&
2874 (txdlp->Host_Control)) {
2875 /* Check for TxD errors */
2876 if (txdlp->Control_1 & TXD_T_CODE) {
2877 unsigned long long err;
2878 err = txdlp->Control_1 & TXD_T_CODE;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002879 if (err & 0x1) {
2880 nic->mac_control.stats_info->sw_stat.
2881 parity_err_cnt++;
2882 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002883 if ((err >> 48) == 0xA) {
2884 DBG_PRINT(TX_DBG, "TxD returned due \
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002885 to loss of link\n");
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002886 }
2887 else {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05002888 DBG_PRINT(ERR_DBG, "***TxD error %llx\n", err);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002891
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002892 skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002893 if (skb == NULL) {
2894 DBG_PRINT(ERR_DBG, "%s: Null skb ",
2895 __FUNCTION__);
2896 DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
2897 return;
2898 }
2899
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002900 /* Updating the statistics block */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002901 nic->stats.tx_bytes += skb->len;
2902 dev_kfree_skb_irq(skb);
2903
2904 get_info.offset++;
Ananda Raju863c11a2006-04-21 19:03:13 -04002905 if (get_info.offset == get_info.fifo_len + 1)
2906 get_info.offset = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002907 txdlp = (TxD_t *) fifo_data->list_info
2908 [get_info.offset].list_virt_addr;
2909 fifo_data->tx_curr_get_info.offset =
2910 get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 }
2912
2913 spin_lock(&nic->tx_lock);
2914 if (netif_queue_stopped(dev))
2915 netif_wake_queue(dev);
2916 spin_unlock(&nic->tx_lock);
2917}
2918
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002919/**
Ananda Rajubd1034f2006-04-21 19:20:22 -04002920 * s2io_mdio_write - Function to write in to MDIO registers
2921 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
2922 * @addr : address value
2923 * @value : data value
2924 * @dev : pointer to net_device structure
2925 * Description:
2926 * This function is used to write values to the MDIO registers
2927 * NONE
2928 */
2929static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
2930{
2931 u64 val64 = 0x0;
2932 nic_t *sp = dev->priv;
Al Virocc3afe62006-09-23 01:33:40 +01002933 XENA_dev_config_t __iomem *bar0 = sp->bar0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002934
2935 //address transaction
2936 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2937 | MDIO_MMD_DEV_ADDR(mmd_type)
2938 | MDIO_MMS_PRT_ADDR(0x0);
2939 writeq(val64, &bar0->mdio_control);
2940 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2941 writeq(val64, &bar0->mdio_control);
2942 udelay(100);
2943
2944 //Data transaction
2945 val64 = 0x0;
2946 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2947 | MDIO_MMD_DEV_ADDR(mmd_type)
2948 | MDIO_MMS_PRT_ADDR(0x0)
2949 | MDIO_MDIO_DATA(value)
2950 | MDIO_OP(MDIO_OP_WRITE_TRANS);
2951 writeq(val64, &bar0->mdio_control);
2952 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2953 writeq(val64, &bar0->mdio_control);
2954 udelay(100);
2955
2956 val64 = 0x0;
2957 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2958 | MDIO_MMD_DEV_ADDR(mmd_type)
2959 | MDIO_MMS_PRT_ADDR(0x0)
2960 | MDIO_OP(MDIO_OP_READ_TRANS);
2961 writeq(val64, &bar0->mdio_control);
2962 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2963 writeq(val64, &bar0->mdio_control);
2964 udelay(100);
2965
2966}
2967
2968/**
2969 * s2io_mdio_read - Function to write in to MDIO registers
2970 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
2971 * @addr : address value
2972 * @dev : pointer to net_device structure
2973 * Description:
2974 * This function is used to read values to the MDIO registers
2975 * NONE
2976 */
2977static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
2978{
2979 u64 val64 = 0x0;
2980 u64 rval64 = 0x0;
2981 nic_t *sp = dev->priv;
Al Virocc3afe62006-09-23 01:33:40 +01002982 XENA_dev_config_t __iomem *bar0 = sp->bar0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002983
2984 /* address transaction */
2985 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2986 | MDIO_MMD_DEV_ADDR(mmd_type)
2987 | MDIO_MMS_PRT_ADDR(0x0);
2988 writeq(val64, &bar0->mdio_control);
2989 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2990 writeq(val64, &bar0->mdio_control);
2991 udelay(100);
2992
2993 /* Data transaction */
2994 val64 = 0x0;
2995 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2996 | MDIO_MMD_DEV_ADDR(mmd_type)
2997 | MDIO_MMS_PRT_ADDR(0x0)
2998 | MDIO_OP(MDIO_OP_READ_TRANS);
2999 writeq(val64, &bar0->mdio_control);
3000 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
3001 writeq(val64, &bar0->mdio_control);
3002 udelay(100);
3003
3004 /* Read the value from regs */
3005 rval64 = readq(&bar0->mdio_control);
3006 rval64 = rval64 & 0xFFFF0000;
3007 rval64 = rval64 >> 16;
3008 return rval64;
3009}
3010/**
3011 * s2io_chk_xpak_counter - Function to check the status of the xpak counters
3012 * @counter : couter value to be updated
3013 * @flag : flag to indicate the status
3014 * @type : counter type
3015 * Description:
3016 * This function is to check the status of the xpak counters value
3017 * NONE
3018 */
3019
3020static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, u16 flag, u16 type)
3021{
3022 u64 mask = 0x3;
3023 u64 val64;
3024 int i;
3025 for(i = 0; i <index; i++)
3026 mask = mask << 0x2;
3027
3028 if(flag > 0)
3029 {
3030 *counter = *counter + 1;
3031 val64 = *regs_stat & mask;
3032 val64 = val64 >> (index * 0x2);
3033 val64 = val64 + 1;
3034 if(val64 == 3)
3035 {
3036 switch(type)
3037 {
3038 case 1:
3039 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
3040 "service. Excessive temperatures may "
3041 "result in premature transceiver "
3042 "failure \n");
3043 break;
3044 case 2:
3045 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
3046 "service Excessive bias currents may "
3047 "indicate imminent laser diode "
3048 "failure \n");
3049 break;
3050 case 3:
3051 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
3052 "service Excessive laser output "
3053 "power may saturate far-end "
3054 "receiver\n");
3055 break;
3056 default:
3057 DBG_PRINT(ERR_DBG, "Incorrect XPAK Alarm "
3058 "type \n");
3059 }
3060 val64 = 0x0;
3061 }
3062 val64 = val64 << (index * 0x2);
3063 *regs_stat = (*regs_stat & (~mask)) | (val64);
3064
3065 } else {
3066 *regs_stat = *regs_stat & (~mask);
3067 }
3068}
3069
3070/**
3071 * s2io_updt_xpak_counter - Function to update the xpak counters
3072 * @dev : pointer to net_device struct
3073 * Description:
3074 * This function is to upate the status of the xpak counters value
3075 * NONE
3076 */
3077static void s2io_updt_xpak_counter(struct net_device *dev)
3078{
3079 u16 flag = 0x0;
3080 u16 type = 0x0;
3081 u16 val16 = 0x0;
3082 u64 val64 = 0x0;
3083 u64 addr = 0x0;
3084
3085 nic_t *sp = dev->priv;
3086 StatInfo_t *stat_info = sp->mac_control.stats_info;
3087
3088 /* Check the communication with the MDIO slave */
3089 addr = 0x0000;
3090 val64 = 0x0;
3091 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3092 if((val64 == 0xFFFF) || (val64 == 0x0000))
3093 {
3094 DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - "
3095 "Returned %llx\n", (unsigned long long)val64);
3096 return;
3097 }
3098
3099 /* Check for the expecte value of 2040 at PMA address 0x0000 */
3100 if(val64 != 0x2040)
3101 {
3102 DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - ");
3103 DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x2040\n",
3104 (unsigned long long)val64);
3105 return;
3106 }
3107
3108 /* Loading the DOM register to MDIO register */
3109 addr = 0xA100;
3110 s2io_mdio_write(MDIO_MMD_PMA_DEV_ADDR, addr, val16, dev);
3111 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3112
3113 /* Reading the Alarm flags */
3114 addr = 0xA070;
3115 val64 = 0x0;
3116 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3117
3118 flag = CHECKBIT(val64, 0x7);
3119 type = 1;
3120 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_transceiver_temp_high,
3121 &stat_info->xpak_stat.xpak_regs_stat,
3122 0x0, flag, type);
3123
3124 if(CHECKBIT(val64, 0x6))
3125 stat_info->xpak_stat.alarm_transceiver_temp_low++;
3126
3127 flag = CHECKBIT(val64, 0x3);
3128 type = 2;
3129 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_bias_current_high,
3130 &stat_info->xpak_stat.xpak_regs_stat,
3131 0x2, flag, type);
3132
3133 if(CHECKBIT(val64, 0x2))
3134 stat_info->xpak_stat.alarm_laser_bias_current_low++;
3135
3136 flag = CHECKBIT(val64, 0x1);
3137 type = 3;
3138 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_output_power_high,
3139 &stat_info->xpak_stat.xpak_regs_stat,
3140 0x4, flag, type);
3141
3142 if(CHECKBIT(val64, 0x0))
3143 stat_info->xpak_stat.alarm_laser_output_power_low++;
3144
3145 /* Reading the Warning flags */
3146 addr = 0xA074;
3147 val64 = 0x0;
3148 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3149
3150 if(CHECKBIT(val64, 0x7))
3151 stat_info->xpak_stat.warn_transceiver_temp_high++;
3152
3153 if(CHECKBIT(val64, 0x6))
3154 stat_info->xpak_stat.warn_transceiver_temp_low++;
3155
3156 if(CHECKBIT(val64, 0x3))
3157 stat_info->xpak_stat.warn_laser_bias_current_high++;
3158
3159 if(CHECKBIT(val64, 0x2))
3160 stat_info->xpak_stat.warn_laser_bias_current_low++;
3161
3162 if(CHECKBIT(val64, 0x1))
3163 stat_info->xpak_stat.warn_laser_output_power_high++;
3164
3165 if(CHECKBIT(val64, 0x0))
3166 stat_info->xpak_stat.warn_laser_output_power_low++;
3167}
3168
3169/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 * alarm_intr_handler - Alarm Interrrupt handler
3171 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003172 * Description: If the interrupt was neither because of Rx packet or Tx
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 * complete, this function is called. If the interrupt was to indicate
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003174 * a loss of link, the OSM link status handler is invoked for any other
3175 * alarm interrupt the block that raised the interrupt is displayed
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 * and a H/W reset is issued.
3177 * Return Value:
3178 * NONE
3179*/
3180
3181static void alarm_intr_handler(struct s2io_nic *nic)
3182{
3183 struct net_device *dev = (struct net_device *) nic->dev;
3184 XENA_dev_config_t __iomem *bar0 = nic->bar0;
3185 register u64 val64 = 0, err_reg = 0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003186 u64 cnt;
3187 int i;
3188 nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
3189 /* Handling the XPAK counters update */
3190 if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
3191 /* waiting for an hour */
3192 nic->mac_control.stats_info->xpak_stat.xpak_timer_count++;
3193 } else {
3194 s2io_updt_xpak_counter(dev);
3195 /* reset the count to zero */
3196 nic->mac_control.stats_info->xpak_stat.xpak_timer_count = 0;
3197 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198
3199 /* Handling link status change error Intr */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07003200 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
3201 err_reg = readq(&bar0->mac_rmac_err_reg);
3202 writeq(err_reg, &bar0->mac_rmac_err_reg);
3203 if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
3204 schedule_work(&nic->set_link_task);
3205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 }
3207
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003208 /* Handling Ecc errors */
3209 val64 = readq(&bar0->mc_err_reg);
3210 writeq(val64, &bar0->mc_err_reg);
3211 if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
3212 if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003213 nic->mac_control.stats_info->sw_stat.
3214 double_ecc_errs++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003215 DBG_PRINT(INIT_DBG, "%s: Device indicates ",
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003216 dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003217 DBG_PRINT(INIT_DBG, "double ECC error!!\n");
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003218 if (nic->device_type != XFRAME_II_DEVICE) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003219 /* Reset XframeI only if critical error */
3220 if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
3221 MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
3222 netif_stop_queue(dev);
3223 schedule_work(&nic->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04003224 nic->mac_control.stats_info->sw_stat.
3225 soft_reset_cnt++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003226 }
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003227 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003228 } else {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003229 nic->mac_control.stats_info->sw_stat.
3230 single_ecc_errs++;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003231 }
3232 }
3233
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 /* In case of a serious error, the device will be Reset. */
3235 val64 = readq(&bar0->serr_source);
3236 if (val64 & SERR_SOURCE_ANY) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04003237 nic->mac_control.stats_info->sw_stat.serious_err_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003239 DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003240 (unsigned long long)val64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 netif_stop_queue(dev);
3242 schedule_work(&nic->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04003243 nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 }
3245
3246 /*
3247 * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
3248 * Error occurs, the adapter will be recycled by disabling the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003249 * adapter enable bit and enabling it again after the device
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 * becomes Quiescent.
3251 */
3252 val64 = readq(&bar0->pcc_err_reg);
3253 writeq(val64, &bar0->pcc_err_reg);
3254 if (val64 & PCC_FB_ECC_DB_ERR) {
3255 u64 ac = readq(&bar0->adapter_control);
3256 ac &= ~(ADAPTER_CNTL_EN);
3257 writeq(ac, &bar0->adapter_control);
3258 ac = readq(&bar0->adapter_control);
3259 schedule_work(&nic->set_link_task);
3260 }
Ananda Rajubd1034f2006-04-21 19:20:22 -04003261 /* Check for data parity error */
3262 val64 = readq(&bar0->pic_int_status);
3263 if (val64 & PIC_INT_GPIO) {
3264 val64 = readq(&bar0->gpio_int_reg);
3265 if (val64 & GPIO_INT_REG_DP_ERR_INT) {
3266 nic->mac_control.stats_info->sw_stat.parity_err_cnt++;
3267 schedule_work(&nic->rst_timer_task);
3268 nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
3269 }
3270 }
3271
3272 /* Check for ring full counter */
3273 if (nic->device_type & XFRAME_II_DEVICE) {
3274 val64 = readq(&bar0->ring_bump_counter1);
3275 for (i=0; i<4; i++) {
3276 cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
3277 cnt >>= 64 - ((i+1)*16);
3278 nic->mac_control.stats_info->sw_stat.ring_full_cnt
3279 += cnt;
3280 }
3281
3282 val64 = readq(&bar0->ring_bump_counter2);
3283 for (i=0; i<4; i++) {
3284 cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
3285 cnt >>= 64 - ((i+1)*16);
3286 nic->mac_control.stats_info->sw_stat.ring_full_cnt
3287 += cnt;
3288 }
3289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290
3291 /* Other type of interrupts are not being handled now, TODO */
3292}
3293
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003294/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 * wait_for_cmd_complete - waits for a command to complete.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003296 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003298 * Description: Function that waits for a command to Write into RMAC
3299 * ADDR DATA registers to be completed and returns either success or
3300 * error depending on whether the command was complete or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 * Return value:
3302 * SUCCESS on success and FAILURE on failure.
3303 */
3304
Al Virocc3afe62006-09-23 01:33:40 +01003305static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 int ret = FAILURE, cnt = 0;
3308 u64 val64;
3309
3310 while (TRUE) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04003311 val64 = readq(addr);
3312 if (!(val64 & busy_bit)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 ret = SUCCESS;
3314 break;
3315 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003316
3317 if(in_interrupt())
3318 mdelay(50);
3319 else
3320 msleep(50);
3321
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 if (cnt++ > 10)
3323 break;
3324 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 return ret;
3326}
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003327/*
3328 * check_pci_device_id - Checks if the device id is supported
3329 * @id : device id
3330 * Description: Function to check if the pci device id is supported by driver.
3331 * Return value: Actual device id if supported else PCI_ANY_ID
3332 */
3333static u16 check_pci_device_id(u16 id)
3334{
3335 switch (id) {
3336 case PCI_DEVICE_ID_HERC_WIN:
3337 case PCI_DEVICE_ID_HERC_UNI:
3338 return XFRAME_II_DEVICE;
3339 case PCI_DEVICE_ID_S2IO_UNI:
3340 case PCI_DEVICE_ID_S2IO_WIN:
3341 return XFRAME_I_DEVICE;
3342 default:
3343 return PCI_ANY_ID;
3344 }
3345}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003347/**
3348 * s2io_reset - Resets the card.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 * @sp : private member of the device structure.
3350 * Description: Function to Reset the card. This function then also
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003351 * restores the previously saved PCI configuration space registers as
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 * the card reset also resets the configuration space.
3353 * Return value:
3354 * void.
3355 */
3356
Adrian Bunk26df54b2006-01-14 03:09:40 +01003357static void s2io_reset(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358{
3359 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3360 u64 val64;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003361 u16 subid, pci_cmd;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003362 int i;
3363 u16 val16;
3364 DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
3365 __FUNCTION__, sp->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003367 /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003368 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003369
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003370 if (sp->device_type == XFRAME_II_DEVICE) {
3371 int ret;
3372 ret = pci_set_power_state(sp->pdev, 3);
3373 if (!ret)
3374 ret = pci_set_power_state(sp->pdev, 0);
3375 else {
3376 DBG_PRINT(ERR_DBG,"%s PME based SW_Reset failed!\n",
3377 __FUNCTION__);
3378 goto old_way;
3379 }
3380 msleep(20);
3381 goto new_way;
3382 }
3383old_way:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 val64 = SW_RESET_ALL;
3385 writeq(val64, &bar0->sw_reset);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003386new_way:
Ananda Rajuc92ca042006-04-21 19:18:03 -04003387 if (strstr(sp->product_name, "CX4")) {
3388 msleep(750);
3389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 msleep(250);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05003391 for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) {
3392
3393 /* Restore the PCI state saved during initialization. */
3394 pci_restore_state(sp->pdev);
3395 pci_read_config_word(sp->pdev, 0x2, &val16);
3396 if (check_pci_device_id(val16) != (u16)PCI_ANY_ID)
3397 break;
3398 msleep(200);
3399 }
3400
3401 if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) {
3402 DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__);
3403 }
3404
3405 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd);
3406
3407 s2io_init_pci(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003409 /* Set swapper to enable I/O register access */
3410 s2io_set_swapper(sp);
3411
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003412 /* Restore the MSIX table entries from local variables */
3413 restore_xmsi_data(sp);
3414
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003415 /* Clear certain PCI/PCI-X fields after reset */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003416 if (sp->device_type == XFRAME_II_DEVICE) {
Ananda Rajub41477f2006-07-24 19:52:49 -04003417 /* Clear "detected parity error" bit */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003418 pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003419
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003420 /* Clearing PCIX Ecc status register */
3421 pci_write_config_dword(sp->pdev, 0x68, 0x7C);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003422
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003423 /* Clearing PCI_STATUS error reflected here */
3424 writeq(BIT(62), &bar0->txpic_int_reg);
3425 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003426
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003427 /* Reset device statistics maintained by OS */
3428 memset(&sp->stats, 0, sizeof (struct net_device_stats));
3429
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 /* SXE-002: Configure link and activity LED to turn it off */
3431 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003432 if (((subid & 0xFF) >= 0x07) &&
3433 (sp->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 val64 = readq(&bar0->gpio_control);
3435 val64 |= 0x0000800000000000ULL;
3436 writeq(val64, &bar0->gpio_control);
3437 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01003438 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 }
3440
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003441 /*
3442 * Clear spurious ECC interrupts that would have occured on
3443 * XFRAME II cards after reset.
3444 */
3445 if (sp->device_type == XFRAME_II_DEVICE) {
3446 val64 = readq(&bar0->pcc_err_reg);
3447 writeq(val64, &bar0->pcc_err_reg);
3448 }
3449
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 sp->device_enabled_once = FALSE;
3451}
3452
3453/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003454 * s2io_set_swapper - to set the swapper controle on the card
3455 * @sp : private member of the device structure,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 * pointer to the s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003457 * Description: Function to set the swapper control on the card
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 * correctly depending on the 'endianness' of the system.
3459 * Return value:
3460 * SUCCESS on success and FAILURE on failure.
3461 */
3462
Adrian Bunk26df54b2006-01-14 03:09:40 +01003463static int s2io_set_swapper(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464{
3465 struct net_device *dev = sp->dev;
3466 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3467 u64 val64, valt, valr;
3468
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003469 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 * Set proper endian settings and verify the same by reading
3471 * the PIF Feed-back register.
3472 */
3473
3474 val64 = readq(&bar0->pif_rd_swapper_fb);
3475 if (val64 != 0x0123456789ABCDEFULL) {
3476 int i = 0;
3477 u64 value[] = { 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */
3478 0x8100008181000081ULL, /* FE=1, SE=0 */
3479 0x4200004242000042ULL, /* FE=0, SE=1 */
3480 0}; /* FE=0, SE=0 */
3481
3482 while(i<4) {
3483 writeq(value[i], &bar0->swapper_ctrl);
3484 val64 = readq(&bar0->pif_rd_swapper_fb);
3485 if (val64 == 0x0123456789ABCDEFULL)
3486 break;
3487 i++;
3488 }
3489 if (i == 4) {
3490 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3491 dev->name);
3492 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3493 (unsigned long long) val64);
3494 return FAILURE;
3495 }
3496 valr = value[i];
3497 } else {
3498 valr = readq(&bar0->swapper_ctrl);
3499 }
3500
3501 valt = 0x0123456789ABCDEFULL;
3502 writeq(valt, &bar0->xmsi_address);
3503 val64 = readq(&bar0->xmsi_address);
3504
3505 if(val64 != valt) {
3506 int i = 0;
3507 u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */
3508 0x0081810000818100ULL, /* FE=1, SE=0 */
3509 0x0042420000424200ULL, /* FE=0, SE=1 */
3510 0}; /* FE=0, SE=0 */
3511
3512 while(i<4) {
3513 writeq((value[i] | valr), &bar0->swapper_ctrl);
3514 writeq(valt, &bar0->xmsi_address);
3515 val64 = readq(&bar0->xmsi_address);
3516 if(val64 == valt)
3517 break;
3518 i++;
3519 }
3520 if(i == 4) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003521 unsigned long long x = val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr ");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003523 DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 return FAILURE;
3525 }
3526 }
3527 val64 = readq(&bar0->swapper_ctrl);
3528 val64 &= 0xFFFF000000000000ULL;
3529
3530#ifdef __BIG_ENDIAN
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003531 /*
3532 * The device by default set to a big endian format, so a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 * big endian driver need not set anything.
3534 */
3535 val64 |= (SWAPPER_CTRL_TXP_FE |
3536 SWAPPER_CTRL_TXP_SE |
3537 SWAPPER_CTRL_TXD_R_FE |
3538 SWAPPER_CTRL_TXD_W_FE |
3539 SWAPPER_CTRL_TXF_R_FE |
3540 SWAPPER_CTRL_RXD_R_FE |
3541 SWAPPER_CTRL_RXD_W_FE |
3542 SWAPPER_CTRL_RXF_W_FE |
3543 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Andrew Morton92383342005-10-16 00:11:29 -07003545 if (sp->intr_type == INTA)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003546 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 writeq(val64, &bar0->swapper_ctrl);
3548#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003549 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 * Initially we enable all bits to make it accessible by the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003551 * driver, then we selectively enable only those bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 * we want to set.
3553 */
3554 val64 |= (SWAPPER_CTRL_TXP_FE |
3555 SWAPPER_CTRL_TXP_SE |
3556 SWAPPER_CTRL_TXD_R_FE |
3557 SWAPPER_CTRL_TXD_R_SE |
3558 SWAPPER_CTRL_TXD_W_FE |
3559 SWAPPER_CTRL_TXD_W_SE |
3560 SWAPPER_CTRL_TXF_R_FE |
3561 SWAPPER_CTRL_RXD_R_FE |
3562 SWAPPER_CTRL_RXD_R_SE |
3563 SWAPPER_CTRL_RXD_W_FE |
3564 SWAPPER_CTRL_RXD_W_SE |
3565 SWAPPER_CTRL_RXF_W_FE |
3566 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003568 if (sp->intr_type == INTA)
3569 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 writeq(val64, &bar0->swapper_ctrl);
3571#endif
3572 val64 = readq(&bar0->swapper_ctrl);
3573
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003574 /*
3575 * Verifying if endian settings are accurate by reading a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 * feedback register.
3577 */
3578 val64 = readq(&bar0->pif_rd_swapper_fb);
3579 if (val64 != 0x0123456789ABCDEFULL) {
3580 /* Endian settings are incorrect, calls for another dekko. */
3581 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3582 dev->name);
3583 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3584 (unsigned long long) val64);
3585 return FAILURE;
3586 }
3587
3588 return SUCCESS;
3589}
3590
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003591static int wait_for_msix_trans(nic_t *nic, int i)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003592{
Al Viro37eb47e2005-12-15 09:17:29 +00003593 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003594 u64 val64;
3595 int ret = 0, cnt = 0;
3596
3597 do {
3598 val64 = readq(&bar0->xmsi_access);
3599 if (!(val64 & BIT(15)))
3600 break;
3601 mdelay(1);
3602 cnt++;
3603 } while(cnt < 5);
3604 if (cnt == 5) {
3605 DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i);
3606 ret = 1;
3607 }
3608
3609 return ret;
3610}
3611
Adrian Bunk26df54b2006-01-14 03:09:40 +01003612static void restore_xmsi_data(nic_t *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003613{
Al Viro37eb47e2005-12-15 09:17:29 +00003614 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003615 u64 val64;
3616 int i;
3617
Ananda Raju75c30b12006-07-24 19:55:09 -04003618 for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003619 writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
3620 writeq(nic->msix_info[i].data, &bar0->xmsi_data);
3621 val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
3622 writeq(val64, &bar0->xmsi_access);
3623 if (wait_for_msix_trans(nic, i)) {
3624 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3625 continue;
3626 }
3627 }
3628}
3629
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003630static void store_xmsi_data(nic_t *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003631{
Al Viro37eb47e2005-12-15 09:17:29 +00003632 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003633 u64 val64, addr, data;
3634 int i;
3635
3636 /* Store and display */
Ananda Raju75c30b12006-07-24 19:55:09 -04003637 for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003638 val64 = (BIT(15) | vBIT(i, 26, 6));
3639 writeq(val64, &bar0->xmsi_access);
3640 if (wait_for_msix_trans(nic, i)) {
3641 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3642 continue;
3643 }
3644 addr = readq(&bar0->xmsi_address);
3645 data = readq(&bar0->xmsi_data);
3646 if (addr && data) {
3647 nic->msix_info[i].addr = addr;
3648 nic->msix_info[i].data = data;
3649 }
3650 }
3651}
3652
3653int s2io_enable_msi(nic_t *nic)
3654{
Al Viro37eb47e2005-12-15 09:17:29 +00003655 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003656 u16 msi_ctrl, msg_val;
3657 struct config_param *config = &nic->config;
3658 struct net_device *dev = nic->dev;
3659 u64 val64, tx_mat, rx_mat;
3660 int i, err;
3661
3662 val64 = readq(&bar0->pic_control);
3663 val64 &= ~BIT(1);
3664 writeq(val64, &bar0->pic_control);
3665
3666 err = pci_enable_msi(nic->pdev);
3667 if (err) {
3668 DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n",
3669 nic->dev->name);
3670 return err;
3671 }
3672
3673 /*
3674 * Enable MSI and use MSI-1 in stead of the standard MSI-0
3675 * for interrupt handling.
3676 */
3677 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3678 msg_val ^= 0x1;
3679 pci_write_config_word(nic->pdev, 0x4c, msg_val);
3680 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3681
3682 pci_read_config_word(nic->pdev, 0x42, &msi_ctrl);
3683 msi_ctrl |= 0x10;
3684 pci_write_config_word(nic->pdev, 0x42, msi_ctrl);
3685
3686 /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */
3687 tx_mat = readq(&bar0->tx_mat0_n[0]);
3688 for (i=0; i<config->tx_fifo_num; i++) {
3689 tx_mat |= TX_MAT_SET(i, 1);
3690 }
3691 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3692
3693 rx_mat = readq(&bar0->rx_mat);
3694 for (i=0; i<config->rx_ring_num; i++) {
3695 rx_mat |= RX_MAT_SET(i, 1);
3696 }
3697 writeq(rx_mat, &bar0->rx_mat);
3698
3699 dev->irq = nic->pdev->irq;
3700 return 0;
3701}
3702
Adrian Bunk26df54b2006-01-14 03:09:40 +01003703static int s2io_enable_msi_x(nic_t *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003704{
Al Viro37eb47e2005-12-15 09:17:29 +00003705 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003706 u64 tx_mat, rx_mat;
3707 u16 msi_control; /* Temp variable */
3708 int ret, i, j, msix_indx = 1;
3709
3710 nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
3711 GFP_KERNEL);
3712 if (nic->entries == NULL) {
3713 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3714 return -ENOMEM;
3715 }
3716 memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
3717
3718 nic->s2io_entries =
3719 kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
3720 GFP_KERNEL);
3721 if (nic->s2io_entries == NULL) {
3722 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3723 kfree(nic->entries);
3724 return -ENOMEM;
3725 }
3726 memset(nic->s2io_entries, 0,
3727 MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
3728
3729 for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
3730 nic->entries[i].entry = i;
3731 nic->s2io_entries[i].entry = i;
3732 nic->s2io_entries[i].arg = NULL;
3733 nic->s2io_entries[i].in_use = 0;
3734 }
3735
3736 tx_mat = readq(&bar0->tx_mat0_n[0]);
3737 for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) {
3738 tx_mat |= TX_MAT_SET(i, msix_indx);
3739 nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i];
3740 nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE;
3741 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3742 }
3743 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3744
3745 if (!nic->config.bimodal) {
3746 rx_mat = readq(&bar0->rx_mat);
3747 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3748 rx_mat |= RX_MAT_SET(j, msix_indx);
3749 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3750 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3751 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3752 }
3753 writeq(rx_mat, &bar0->rx_mat);
3754 } else {
3755 tx_mat = readq(&bar0->tx_mat0_n[7]);
3756 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3757 tx_mat |= TX_MAT_SET(i, msix_indx);
3758 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3759 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3760 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3761 }
3762 writeq(tx_mat, &bar0->tx_mat0_n[7]);
3763 }
3764
Ananda Rajuc92ca042006-04-21 19:18:03 -04003765 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003766 ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003767 /* We fail init if error or we get less vectors than min required */
3768 if (ret >= (nic->config.tx_fifo_num + nic->config.rx_ring_num + 1)) {
3769 nic->avail_msix_vectors = ret;
3770 ret = pci_enable_msix(nic->pdev, nic->entries, ret);
3771 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003772 if (ret) {
3773 DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
3774 kfree(nic->entries);
3775 kfree(nic->s2io_entries);
3776 nic->entries = NULL;
3777 nic->s2io_entries = NULL;
Ananda Rajuc92ca042006-04-21 19:18:03 -04003778 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003779 return -ENOMEM;
3780 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003781 if (!nic->avail_msix_vectors)
3782 nic->avail_msix_vectors = MAX_REQUESTED_MSI_X;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003783
3784 /*
3785 * To enable MSI-X, MSI also needs to be enabled, due to a bug
3786 * in the herc NIC. (Temp change, needs to be removed later)
3787 */
3788 pci_read_config_word(nic->pdev, 0x42, &msi_control);
3789 msi_control |= 0x1; /* Enable MSI */
3790 pci_write_config_word(nic->pdev, 0x42, msi_control);
3791
3792 return 0;
3793}
3794
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795/* ********************************************************* *
3796 * Functions defined below concern the OS part of the driver *
3797 * ********************************************************* */
3798
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003799/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 * s2io_open - open entry point of the driver
3801 * @dev : pointer to the device structure.
3802 * Description:
3803 * This function is the open entry point of the driver. It mainly calls a
3804 * function to allocate Rx buffers and inserts them into the buffer
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003805 * descriptors and then enables the Rx part of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 * Return value:
3807 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3808 * file on failure.
3809 */
3810
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003811static int s2io_open(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812{
3813 nic_t *sp = dev->priv;
3814 int err = 0;
3815
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003816 /*
3817 * Make sure you have link off by default every time
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 * Nic is initialized
3819 */
3820 netif_carrier_off(dev);
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003821 sp->last_link_state = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822
3823 /* Initialize H/W and enable interrupts */
Ananda Rajuc92ca042006-04-21 19:18:03 -04003824 err = s2io_card_up(sp);
3825 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
3827 dev->name);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003828 goto hw_init_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 }
3830
3831 if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
3832 DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003833 s2io_card_down(sp);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003834 err = -ENODEV;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003835 goto hw_init_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 }
3837
3838 netif_start_queue(dev);
3839 return 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003840
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003841hw_init_failed:
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003842 if (sp->intr_type == MSI_X) {
3843 if (sp->entries)
3844 kfree(sp->entries);
3845 if (sp->s2io_entries)
3846 kfree(sp->s2io_entries);
3847 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003848 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849}
3850
3851/**
3852 * s2io_close -close entry point of the driver
3853 * @dev : device pointer.
3854 * Description:
3855 * This is the stop entry point of the driver. It needs to undo exactly
3856 * whatever was done by the open entry point,thus it's usually referred to
3857 * as the close function.Among other things this function mainly stops the
3858 * Rx side of the NIC and frees all the Rx buffers in the Rx rings.
3859 * Return value:
3860 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3861 * file on failure.
3862 */
3863
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003864static int s2io_close(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865{
3866 nic_t *sp = dev->priv;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003867
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 flush_scheduled_work();
3869 netif_stop_queue(dev);
3870 /* Reset card, kill tasklet and free Tx and Rx buffers. */
Ananda Rajue6a8fee2006-07-06 23:58:23 -07003871 s2io_card_down(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 sp->device_close_flag = TRUE; /* Device is shut down. */
3874 return 0;
3875}
3876
3877/**
3878 * s2io_xmit - Tx entry point of te driver
3879 * @skb : the socket buffer containing the Tx data.
3880 * @dev : device pointer.
3881 * Description :
3882 * This function is the Tx entry point of the driver. S2IO NIC supports
3883 * certain protocol assist features on Tx side, namely CSO, S/G, LSO.
3884 * NOTE: when device cant queue the pkt,just the trans_start variable will
3885 * not be upadted.
3886 * Return value:
3887 * 0 on success & 1 on failure.
3888 */
3889
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003890static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891{
3892 nic_t *sp = dev->priv;
3893 u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
3894 register u64 val64;
3895 TxD_t *txdp;
3896 TxFIFO_element_t __iomem *tx_fifo;
3897 unsigned long flags;
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003898 u16 vlan_tag = 0;
3899 int vlan_priority = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 mac_info_t *mac_control;
3901 struct config_param *config;
Ananda Raju75c30b12006-07-24 19:55:09 -04003902 int offload_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903
3904 mac_control = &sp->mac_control;
3905 config = &sp->config;
3906
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003907 DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 spin_lock_irqsave(&sp->tx_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 if (atomic_read(&sp->card_state) == CARD_DOWN) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003910 DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 dev->name);
3912 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003913 dev_kfree_skb(skb);
3914 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 }
3916
3917 queue = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003919 /* Get Fifo number to Transmit based on vlan priority */
3920 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3921 vlan_tag = vlan_tx_tag_get(skb);
3922 vlan_priority = vlan_tag >> 13;
3923 queue = config->fifo_mapping[vlan_priority];
3924 }
3925
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003926 put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
3927 get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
3928 txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off].
3929 list_virt_addr;
3930
3931 queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04003933 if (txdp->Host_Control ||
3934 ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003935 DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 netif_stop_queue(dev);
3937 dev_kfree_skb(skb);
3938 spin_unlock_irqrestore(&sp->tx_lock, flags);
3939 return 0;
3940 }
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003941
3942 /* A buffer with no data will be dropped */
3943 if (!skb->len) {
3944 DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
3945 dev_kfree_skb(skb);
3946 spin_unlock_irqrestore(&sp->tx_lock, flags);
3947 return 0;
3948 }
3949
Ananda Raju75c30b12006-07-24 19:55:09 -04003950 offload_type = s2io_offload_type(skb);
Ananda Raju75c30b12006-07-24 19:55:09 -04003951 if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 txdp->Control_1 |= TXD_TCP_LSO_EN;
Ananda Raju75c30b12006-07-24 19:55:09 -04003953 txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 }
Patrick McHardy84fa7932006-08-29 16:44:56 -07003955 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 txdp->Control_2 |=
3957 (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
3958 TXD_TX_CKO_UDP_EN);
3959 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003960 txdp->Control_1 |= TXD_GATHER_CODE_FIRST;
3961 txdp->Control_1 |= TXD_LIST_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 txdp->Control_2 |= config->tx_intr_type;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07003963
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003964 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3965 txdp->Control_2 |= TXD_VLAN_ENABLE;
3966 txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
3967 }
3968
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003969 frg_len = skb->len - skb->data_len;
Ananda Raju75c30b12006-07-24 19:55:09 -04003970 if (offload_type == SKB_GSO_UDP) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003971 int ufo_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972
Ananda Raju75c30b12006-07-24 19:55:09 -04003973 ufo_size = s2io_udp_mss(skb);
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003974 ufo_size &= ~7;
3975 txdp->Control_1 |= TXD_UFO_EN;
3976 txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
3977 txdp->Control_1 |= TXD_BUFFER0_SIZE(8);
3978#ifdef __BIG_ENDIAN
3979 sp->ufo_in_band_v[put_off] =
3980 (u64)skb_shinfo(skb)->ip6_frag_id;
3981#else
3982 sp->ufo_in_band_v[put_off] =
3983 (u64)skb_shinfo(skb)->ip6_frag_id << 32;
3984#endif
3985 txdp->Host_Control = (unsigned long)sp->ufo_in_band_v;
3986 txdp->Buffer_Pointer = pci_map_single(sp->pdev,
3987 sp->ufo_in_band_v,
3988 sizeof(u64), PCI_DMA_TODEVICE);
3989 txdp++;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003990 }
3991
3992 txdp->Buffer_Pointer = pci_map_single
3993 (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
3994 txdp->Host_Control = (unsigned long) skb;
3995 txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
Ananda Raju75c30b12006-07-24 19:55:09 -04003996 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003997 txdp->Control_1 |= TXD_UFO_EN;
3998
3999 frg_cnt = skb_shinfo(skb)->nr_frags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 /* For fragmented SKB. */
4001 for (i = 0; i < frg_cnt; i++) {
4002 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07004003 /* A '0' length fragment will be ignored */
4004 if (!frag->size)
4005 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 txdp++;
4007 txdp->Buffer_Pointer = (u64) pci_map_page
4008 (sp->pdev, frag->page, frag->page_offset,
4009 frag->size, PCI_DMA_TODEVICE);
Ananda Rajuefd51b52006-01-19 14:11:54 -05004010 txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
Ananda Raju75c30b12006-07-24 19:55:09 -04004011 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05004012 txdp->Control_1 |= TXD_UFO_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 }
4014 txdp->Control_1 |= TXD_GATHER_CODE_LAST;
4015
Ananda Raju75c30b12006-07-24 19:55:09 -04004016 if (offload_type == SKB_GSO_UDP)
Ananda Rajufed5ecc2005-11-14 15:25:08 -05004017 frg_cnt++; /* as Txd0 was used for inband header */
4018
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 tx_fifo = mac_control->tx_FIFO_start[queue];
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004020 val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021 writeq(val64, &tx_fifo->TxDL_Pointer);
4022
4023 val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
4024 TX_FIFO_LAST_LIST);
Ananda Raju75c30b12006-07-24 19:55:09 -04004025 if (offload_type)
4026 val64 |= TX_FIFO_SPECIAL_FUNC;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004027
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 writeq(val64, &tx_fifo->List_Control);
4029
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07004030 mmiowb();
4031
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 put_off++;
Ananda Raju863c11a2006-04-21 19:03:13 -04004033 if (put_off == mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1)
4034 put_off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004035 mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036
4037 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04004038 if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04004039 sp->mac_control.stats_info->sw_stat.fifo_full_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 DBG_PRINT(TX_DBG,
4041 "No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
4042 put_off, get_off);
4043 netif_stop_queue(dev);
4044 }
4045
4046 dev->trans_start = jiffies;
4047 spin_unlock_irqrestore(&sp->tx_lock, flags);
4048
4049 return 0;
4050}
4051
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07004052static void
4053s2io_alarm_handle(unsigned long data)
4054{
4055 nic_t *sp = (nic_t *)data;
4056
4057 alarm_intr_handler(sp);
4058 mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
4059}
4060
Ananda Raju75c30b12006-07-24 19:55:09 -04004061static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
4062{
4063 int rxb_size, level;
4064
4065 if (!sp->lro) {
4066 rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
4067 level = rx_buffer_level(sp, rxb_size, rng_n);
4068
4069 if ((level == PANIC) && (!TASKLET_IN_USE)) {
4070 int ret;
4071 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
4072 DBG_PRINT(INTR_DBG, "PANIC levels\n");
4073 if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
4074 DBG_PRINT(ERR_DBG, "Out of memory in %s",
4075 __FUNCTION__);
4076 clear_bit(0, (&sp->tasklet_status));
4077 return -1;
4078 }
4079 clear_bit(0, (&sp->tasklet_status));
4080 } else if (level == LOW)
4081 tasklet_schedule(&sp->task);
4082
4083 } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
4084 DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name);
4085 DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
4086 }
4087 return 0;
4088}
4089
David Howells7d12e782006-10-05 14:55:46 +01004090static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004091{
4092 struct net_device *dev = (struct net_device *) dev_id;
4093 nic_t *sp = dev->priv;
4094 int i;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004095 mac_info_t *mac_control;
4096 struct config_param *config;
4097
4098 atomic_inc(&sp->isr_cnt);
4099 mac_control = &sp->mac_control;
4100 config = &sp->config;
4101 DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__);
4102
4103 /* If Intr is because of Rx Traffic */
4104 for (i = 0; i < config->rx_ring_num; i++)
4105 rx_intr_handler(&mac_control->rings[i]);
4106
4107 /* If Intr is because of Tx Traffic */
4108 for (i = 0; i < config->tx_fifo_num; i++)
4109 tx_intr_handler(&mac_control->fifos[i]);
4110
4111 /*
4112 * If the Rx buffer count is below the panic threshold then
4113 * reallocate the buffers from the interrupt handler itself,
4114 * else schedule a tasklet to reallocate the buffers.
4115 */
Ananda Raju75c30b12006-07-24 19:55:09 -04004116 for (i = 0; i < config->rx_ring_num; i++)
4117 s2io_chk_rx_buffers(sp, i);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004118
4119 atomic_dec(&sp->isr_cnt);
4120 return IRQ_HANDLED;
4121}
4122
David Howells7d12e782006-10-05 14:55:46 +01004123static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004124{
4125 ring_info_t *ring = (ring_info_t *)dev_id;
4126 nic_t *sp = ring->nic;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004127
4128 atomic_inc(&sp->isr_cnt);
Ananda Raju75c30b12006-07-24 19:55:09 -04004129
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004130 rx_intr_handler(ring);
Ananda Raju75c30b12006-07-24 19:55:09 -04004131 s2io_chk_rx_buffers(sp, ring->ring_no);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004132
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004133 atomic_dec(&sp->isr_cnt);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004134 return IRQ_HANDLED;
4135}
4136
David Howells7d12e782006-10-05 14:55:46 +01004137static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004138{
4139 fifo_info_t *fifo = (fifo_info_t *)dev_id;
4140 nic_t *sp = fifo->nic;
4141
4142 atomic_inc(&sp->isr_cnt);
4143 tx_intr_handler(fifo);
4144 atomic_dec(&sp->isr_cnt);
4145 return IRQ_HANDLED;
4146}
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004147static void s2io_txpic_intr_handle(nic_t *sp)
4148{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01004149 XENA_dev_config_t __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004150 u64 val64;
4151
4152 val64 = readq(&bar0->pic_int_status);
4153 if (val64 & PIC_INT_GPIO) {
4154 val64 = readq(&bar0->gpio_int_reg);
4155 if ((val64 & GPIO_INT_REG_LINK_DOWN) &&
4156 (val64 & GPIO_INT_REG_LINK_UP)) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04004157 /*
4158 * This is unstable state so clear both up/down
4159 * interrupt and adapter to re-evaluate the link state.
4160 */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004161 val64 |= GPIO_INT_REG_LINK_DOWN;
4162 val64 |= GPIO_INT_REG_LINK_UP;
4163 writeq(val64, &bar0->gpio_int_reg);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004164 val64 = readq(&bar0->gpio_int_mask);
4165 val64 &= ~(GPIO_INT_MASK_LINK_UP |
4166 GPIO_INT_MASK_LINK_DOWN);
4167 writeq(val64, &bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004168 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04004169 else if (val64 & GPIO_INT_REG_LINK_UP) {
4170 val64 = readq(&bar0->adapter_status);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004171 /* Enable Adapter */
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004172 val64 = readq(&bar0->adapter_control);
4173 val64 |= ADAPTER_CNTL_EN;
4174 writeq(val64, &bar0->adapter_control);
4175 val64 |= ADAPTER_LED_ON;
4176 writeq(val64, &bar0->adapter_control);
4177 if (!sp->device_enabled_once)
4178 sp->device_enabled_once = 1;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004179
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004180 s2io_link(sp, LINK_UP);
4181 /*
4182 * unmask link down interrupt and mask link-up
4183 * intr
4184 */
4185 val64 = readq(&bar0->gpio_int_mask);
4186 val64 &= ~GPIO_INT_MASK_LINK_DOWN;
4187 val64 |= GPIO_INT_MASK_LINK_UP;
4188 writeq(val64, &bar0->gpio_int_mask);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004189
Ananda Rajuc92ca042006-04-21 19:18:03 -04004190 }else if (val64 & GPIO_INT_REG_LINK_DOWN) {
4191 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004192 s2io_link(sp, LINK_DOWN);
4193 /* Link is down so unmaks link up interrupt */
4194 val64 = readq(&bar0->gpio_int_mask);
4195 val64 &= ~GPIO_INT_MASK_LINK_UP;
4196 val64 |= GPIO_INT_MASK_LINK_DOWN;
4197 writeq(val64, &bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004198 }
4199 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04004200 val64 = readq(&bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004201}
4202
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203/**
4204 * s2io_isr - ISR handler of the device .
4205 * @irq: the irq of the device.
4206 * @dev_id: a void pointer to the dev structure of the NIC.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004207 * Description: This function is the ISR handler of the device. It
4208 * identifies the reason for the interrupt and calls the relevant
4209 * service routines. As a contongency measure, this ISR allocates the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 * recv buffers, if their numbers are below the panic value which is
4211 * presently set to 25% of the original number of rcv buffers allocated.
4212 * Return value:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004213 * IRQ_HANDLED: will be returned if IRQ was handled by this routine
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 * IRQ_NONE: will be returned if interrupt is not from our device
4215 */
David Howells7d12e782006-10-05 14:55:46 +01004216static irqreturn_t s2io_isr(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217{
4218 struct net_device *dev = (struct net_device *) dev_id;
4219 nic_t *sp = dev->priv;
4220 XENA_dev_config_t __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004221 int i;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004222 u64 reason = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 mac_info_t *mac_control;
4224 struct config_param *config;
4225
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004226 atomic_inc(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 mac_control = &sp->mac_control;
4228 config = &sp->config;
4229
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004230 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 * Identify the cause for interrupt and call the appropriate
4232 * interrupt handler. Causes for the interrupt could be;
4233 * 1. Rx of packet.
4234 * 2. Tx complete.
4235 * 3. Link down.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004236 * 4. Error in any functional blocks of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 */
4238 reason = readq(&bar0->general_int_status);
4239
4240 if (!reason) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004241 /* The interrupt was not raised by us. */
4242 atomic_dec(&sp->isr_cnt);
4243 return IRQ_NONE;
4244 }
4245 else if (unlikely(reason == S2IO_MINUS_ONE) ) {
4246 /* Disable device and get out */
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004247 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248 return IRQ_NONE;
4249 }
4250
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004251 if (napi) {
4252 if (reason & GEN_INTR_RXTRAFFIC) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004253 if ( likely ( netif_rx_schedule_prep(dev)) ) {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004254 __netif_rx_schedule(dev);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004255 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004256 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004257 else
4258 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004259 }
4260 } else {
4261 /*
4262 * Rx handler is called by default, without checking for the
4263 * cause of interrupt.
4264 * rx_traffic_int reg is an R1 register, writing all 1's
4265 * will ensure that the actual interrupt causing bit get's
4266 * cleared and hence a read can be avoided.
4267 */
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004268 if (reason & GEN_INTR_RXTRAFFIC)
4269 writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
4270
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004271 for (i = 0; i < config->rx_ring_num; i++) {
4272 rx_intr_handler(&mac_control->rings[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 }
4274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275
Ananda Raju863c11a2006-04-21 19:03:13 -04004276 /*
4277 * tx_traffic_int reg is an R1 register, writing all 1's
4278 * will ensure that the actual interrupt causing bit get's
4279 * cleared and hence a read can be avoided.
4280 */
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004281 if (reason & GEN_INTR_TXTRAFFIC)
4282 writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -07004283
Ananda Raju863c11a2006-04-21 19:03:13 -04004284 for (i = 0; i < config->tx_fifo_num; i++)
4285 tx_intr_handler(&mac_control->fifos[i]);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004286
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004287 if (reason & GEN_INTR_TXPIC)
4288 s2io_txpic_intr_handle(sp);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004289 /*
4290 * If the Rx buffer count is below the panic threshold then
4291 * reallocate the buffers from the interrupt handler itself,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 * else schedule a tasklet to reallocate the buffers.
4293 */
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05004294 if (!napi) {
4295 for (i = 0; i < config->rx_ring_num; i++)
4296 s2io_chk_rx_buffers(sp, i);
4297 }
4298
4299 writeq(0, &bar0->general_int_mask);
4300 readl(&bar0->general_int_status);
4301
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004302 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 return IRQ_HANDLED;
4304}
4305
4306/**
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004307 * s2io_updt_stats -
4308 */
4309static void s2io_updt_stats(nic_t *sp)
4310{
4311 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4312 u64 val64;
4313 int cnt = 0;
4314
4315 if (atomic_read(&sp->card_state) == CARD_UP) {
4316 /* Apprx 30us on a 133 MHz bus */
4317 val64 = SET_UPDT_CLICKS(10) |
4318 STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
4319 writeq(val64, &bar0->stat_cfg);
4320 do {
4321 udelay(100);
4322 val64 = readq(&bar0->stat_cfg);
4323 if (!(val64 & BIT(0)))
4324 break;
4325 cnt++;
4326 if (cnt == 5)
4327 break; /* Updt failed */
4328 } while(1);
Ananda Raju75c30b12006-07-24 19:55:09 -04004329 } else {
4330 memset(sp->mac_control.stats_info, 0, sizeof(StatInfo_t));
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004331 }
4332}
4333
4334/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004335 * s2io_get_stats - Updates the device statistics structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 * @dev : pointer to the device structure.
4337 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004338 * This function updates the device statistics structure in the s2io_nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 * structure and returns a pointer to the same.
4340 * Return value:
4341 * pointer to the updated net_device_stats structure.
4342 */
4343
Adrian Bunkac1f60d2005-11-06 01:46:47 +01004344static struct net_device_stats *s2io_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345{
4346 nic_t *sp = dev->priv;
4347 mac_info_t *mac_control;
4348 struct config_param *config;
4349
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004350
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 mac_control = &sp->mac_control;
4352 config = &sp->config;
4353
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004354 /* Configure Stats for immediate updt */
4355 s2io_updt_stats(sp);
4356
4357 sp->stats.tx_packets =
4358 le32_to_cpu(mac_control->stats_info->tmac_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004359 sp->stats.tx_errors =
4360 le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
4361 sp->stats.rx_errors =
Al Viroee705db2006-09-23 01:28:17 +01004362 le64_to_cpu(mac_control->stats_info->rmac_drop_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004363 sp->stats.multicast =
4364 le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 sp->stats.rx_length_errors =
Al Viroee705db2006-09-23 01:28:17 +01004366 le64_to_cpu(mac_control->stats_info->rmac_long_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367
4368 return (&sp->stats);
4369}
4370
4371/**
4372 * s2io_set_multicast - entry point for multicast address enable/disable.
4373 * @dev : pointer to the device structure
4374 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004375 * This function is a driver entry point which gets called by the kernel
4376 * whenever multicast addresses must be enabled/disabled. This also gets
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 * called to set/reset promiscuous mode. Depending on the deivce flag, we
4378 * determine, if multicast address must be enabled or if promiscuous mode
4379 * is to be disabled etc.
4380 * Return value:
4381 * void.
4382 */
4383
4384static void s2io_set_multicast(struct net_device *dev)
4385{
4386 int i, j, prev_cnt;
4387 struct dev_mc_list *mclist;
4388 nic_t *sp = dev->priv;
4389 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4390 u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
4391 0xfeffffffffffULL;
4392 u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
4393 void __iomem *add;
4394
4395 if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) {
4396 /* Enable all Multicast addresses */
4397 writeq(RMAC_ADDR_DATA0_MEM_ADDR(multi_mac),
4398 &bar0->rmac_addr_data0_mem);
4399 writeq(RMAC_ADDR_DATA1_MEM_MASK(mask),
4400 &bar0->rmac_addr_data1_mem);
4401 val64 = RMAC_ADDR_CMD_MEM_WE |
4402 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4403 RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
4404 writeq(val64, &bar0->rmac_addr_cmd_mem);
4405 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004406 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4407 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408
4409 sp->m_cast_flg = 1;
4410 sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
4411 } else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) {
4412 /* Disable all Multicast addresses */
4413 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4414 &bar0->rmac_addr_data0_mem);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07004415 writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0),
4416 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 val64 = RMAC_ADDR_CMD_MEM_WE |
4418 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4419 RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos);
4420 writeq(val64, &bar0->rmac_addr_cmd_mem);
4421 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004422 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4423 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424
4425 sp->m_cast_flg = 0;
4426 sp->all_multi_pos = 0;
4427 }
4428
4429 if ((dev->flags & IFF_PROMISC) && (!sp->promisc_flg)) {
4430 /* Put the NIC into promiscuous mode */
4431 add = &bar0->mac_cfg;
4432 val64 = readq(&bar0->mac_cfg);
4433 val64 |= MAC_CFG_RMAC_PROM_ENABLE;
4434
4435 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4436 writel((u32) val64, add);
4437 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4438 writel((u32) (val64 >> 32), (add + 4));
4439
4440 val64 = readq(&bar0->mac_cfg);
4441 sp->promisc_flg = 1;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004442 DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 dev->name);
4444 } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) {
4445 /* Remove the NIC from promiscuous mode */
4446 add = &bar0->mac_cfg;
4447 val64 = readq(&bar0->mac_cfg);
4448 val64 &= ~MAC_CFG_RMAC_PROM_ENABLE;
4449
4450 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4451 writel((u32) val64, add);
4452 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4453 writel((u32) (val64 >> 32), (add + 4));
4454
4455 val64 = readq(&bar0->mac_cfg);
4456 sp->promisc_flg = 0;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004457 DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 dev->name);
4459 }
4460
4461 /* Update individual M_CAST address list */
4462 if ((!sp->m_cast_flg) && dev->mc_count) {
4463 if (dev->mc_count >
4464 (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) {
4465 DBG_PRINT(ERR_DBG, "%s: No more Rx filters ",
4466 dev->name);
4467 DBG_PRINT(ERR_DBG, "can be added, please enable ");
4468 DBG_PRINT(ERR_DBG, "ALL_MULTI instead\n");
4469 return;
4470 }
4471
4472 prev_cnt = sp->mc_addr_count;
4473 sp->mc_addr_count = dev->mc_count;
4474
4475 /* Clear out the previous list of Mc in the H/W. */
4476 for (i = 0; i < prev_cnt; i++) {
4477 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4478 &bar0->rmac_addr_data0_mem);
4479 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004480 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 val64 = RMAC_ADDR_CMD_MEM_WE |
4482 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4483 RMAC_ADDR_CMD_MEM_OFFSET
4484 (MAC_MC_ADDR_START_OFFSET + i);
4485 writeq(val64, &bar0->rmac_addr_cmd_mem);
4486
4487 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004488 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4489 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 DBG_PRINT(ERR_DBG, "%s: Adding ",
4491 dev->name);
4492 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4493 return;
4494 }
4495 }
4496
4497 /* Create the new Rx filter list and update the same in H/W. */
4498 for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
4499 i++, mclist = mclist->next) {
4500 memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr,
4501 ETH_ALEN);
Jeff Garzika7a80d52006-03-04 12:06:51 -05004502 mac_addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 for (j = 0; j < ETH_ALEN; j++) {
4504 mac_addr |= mclist->dmi_addr[j];
4505 mac_addr <<= 8;
4506 }
4507 mac_addr >>= 8;
4508 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4509 &bar0->rmac_addr_data0_mem);
4510 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004511 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 val64 = RMAC_ADDR_CMD_MEM_WE |
4513 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4514 RMAC_ADDR_CMD_MEM_OFFSET
4515 (i + MAC_MC_ADDR_START_OFFSET);
4516 writeq(val64, &bar0->rmac_addr_cmd_mem);
4517
4518 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004519 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4520 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521 DBG_PRINT(ERR_DBG, "%s: Adding ",
4522 dev->name);
4523 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4524 return;
4525 }
4526 }
4527 }
4528}
4529
4530/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004531 * s2io_set_mac_addr - Programs the Xframe mac address
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 * @dev : pointer to the device structure.
4533 * @addr: a uchar pointer to the new mac address which is to be set.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004534 * Description : This procedure will program the Xframe to receive
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 * frames with new Mac Address
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004536 * Return value: SUCCESS on success and an appropriate (-)ve integer
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 * as defined in errno.h file on failure.
4538 */
4539
Adrian Bunk26df54b2006-01-14 03:09:40 +01004540static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541{
4542 nic_t *sp = dev->priv;
4543 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4544 register u64 val64, mac_addr = 0;
4545 int i;
4546
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004547 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 * Set the new MAC address as the new unicast filter and reflect this
4549 * change on the device address registered with the OS. It will be
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004550 * at offset 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 */
4552 for (i = 0; i < ETH_ALEN; i++) {
4553 mac_addr <<= 8;
4554 mac_addr |= addr[i];
4555 }
4556
4557 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4558 &bar0->rmac_addr_data0_mem);
4559
4560 val64 =
4561 RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4562 RMAC_ADDR_CMD_MEM_OFFSET(0);
4563 writeq(val64, &bar0->rmac_addr_cmd_mem);
4564 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004565 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4566 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
4568 return FAILURE;
4569 }
4570
4571 return SUCCESS;
4572}
4573
4574/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004575 * s2io_ethtool_sset - Sets different link parameters.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure.
4577 * @info: pointer to the structure with parameters given by ethtool to set
4578 * link information.
4579 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004580 * The function sets different link parameters provided by the user onto
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 * the NIC.
4582 * Return value:
4583 * 0 on success.
4584*/
4585
4586static int s2io_ethtool_sset(struct net_device *dev,
4587 struct ethtool_cmd *info)
4588{
4589 nic_t *sp = dev->priv;
4590 if ((info->autoneg == AUTONEG_ENABLE) ||
4591 (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
4592 return -EINVAL;
4593 else {
4594 s2io_close(sp->dev);
4595 s2io_open(sp->dev);
4596 }
4597
4598 return 0;
4599}
4600
4601/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004602 * s2io_ethtol_gset - Return link specific information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 * @sp : private member of the device structure, pointer to the
4604 * s2io_nic structure.
4605 * @info : pointer to the structure with parameters given by ethtool
4606 * to return link information.
4607 * Description:
4608 * Returns link specific information like speed, duplex etc.. to ethtool.
4609 * Return value :
4610 * return 0 on success.
4611 */
4612
4613static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
4614{
4615 nic_t *sp = dev->priv;
4616 info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4617 info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4618 info->port = PORT_FIBRE;
4619 /* info->transceiver?? TODO */
4620
4621 if (netif_carrier_ok(sp->dev)) {
4622 info->speed = 10000;
4623 info->duplex = DUPLEX_FULL;
4624 } else {
4625 info->speed = -1;
4626 info->duplex = -1;
4627 }
4628
4629 info->autoneg = AUTONEG_DISABLE;
4630 return 0;
4631}
4632
4633/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004634 * s2io_ethtool_gdrvinfo - Returns driver specific information.
4635 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 * s2io_nic structure.
4637 * @info : pointer to the structure with parameters given by ethtool to
4638 * return driver information.
4639 * Description:
4640 * Returns driver specefic information like name, version etc.. to ethtool.
4641 * Return value:
4642 * void
4643 */
4644
4645static void s2io_ethtool_gdrvinfo(struct net_device *dev,
4646 struct ethtool_drvinfo *info)
4647{
4648 nic_t *sp = dev->priv;
4649
John W. Linvilledbc23092005-09-28 17:50:51 -04004650 strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
4651 strncpy(info->version, s2io_driver_version, sizeof(info->version));
4652 strncpy(info->fw_version, "", sizeof(info->fw_version));
4653 strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 info->regdump_len = XENA_REG_SPACE;
4655 info->eedump_len = XENA_EEPROM_SPACE;
4656 info->testinfo_len = S2IO_TEST_LEN;
4657 info->n_stats = S2IO_STAT_LEN;
4658}
4659
4660/**
4661 * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004662 * @sp: private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004664 * @regs : pointer to the structure with parameters given by ethtool for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 * dumping the registers.
4666 * @reg_space: The input argumnet into which all the registers are dumped.
4667 * Description:
4668 * Dumps the entire register space of xFrame NIC into the user given
4669 * buffer area.
4670 * Return value :
4671 * void .
4672*/
4673
4674static void s2io_ethtool_gregs(struct net_device *dev,
4675 struct ethtool_regs *regs, void *space)
4676{
4677 int i;
4678 u64 reg;
4679 u8 *reg_space = (u8 *) space;
4680 nic_t *sp = dev->priv;
4681
4682 regs->len = XENA_REG_SPACE;
4683 regs->version = sp->pdev->subsystem_device;
4684
4685 for (i = 0; i < regs->len; i += 8) {
4686 reg = readq(sp->bar0 + i);
4687 memcpy((reg_space + i), &reg, 8);
4688 }
4689}
4690
4691/**
4692 * s2io_phy_id - timer function that alternates adapter LED.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004693 * @data : address of the private member of the device structure, which
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 * is a pointer to the s2io_nic structure, provided as an u32.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004695 * Description: This is actually the timer function that alternates the
4696 * adapter LED bit of the adapter control bit to set/reset every time on
4697 * invocation. The timer is set for 1/2 a second, hence tha NIC blinks
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 * once every second.
4699*/
4700static void s2io_phy_id(unsigned long data)
4701{
4702 nic_t *sp = (nic_t *) data;
4703 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4704 u64 val64 = 0;
4705 u16 subid;
4706
4707 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004708 if ((sp->device_type == XFRAME_II_DEVICE) ||
4709 ((subid & 0xFF) >= 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 val64 = readq(&bar0->gpio_control);
4711 val64 ^= GPIO_CTRL_GPIO_0;
4712 writeq(val64, &bar0->gpio_control);
4713 } else {
4714 val64 = readq(&bar0->adapter_control);
4715 val64 ^= ADAPTER_LED_ON;
4716 writeq(val64, &bar0->adapter_control);
4717 }
4718
4719 mod_timer(&sp->id_timer, jiffies + HZ / 2);
4720}
4721
4722/**
4723 * s2io_ethtool_idnic - To physically identify the nic on the system.
4724 * @sp : private member of the device structure, which is a pointer to the
4725 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004726 * @id : pointer to the structure with identification parameters given by
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 * ethtool.
4728 * Description: Used to physically identify the NIC on the system.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004729 * The Link LED will blink for a time specified by the user for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 * identification.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004731 * NOTE: The Link has to be Up to be able to blink the LED. Hence
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 * identification is possible only if it's link is up.
4733 * Return value:
4734 * int , returns 0 on success
4735 */
4736
4737static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
4738{
4739 u64 val64 = 0, last_gpio_ctrl_val;
4740 nic_t *sp = dev->priv;
4741 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4742 u16 subid;
4743
4744 subid = sp->pdev->subsystem_device;
4745 last_gpio_ctrl_val = readq(&bar0->gpio_control);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004746 if ((sp->device_type == XFRAME_I_DEVICE) &&
4747 ((subid & 0xFF) < 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 val64 = readq(&bar0->adapter_control);
4749 if (!(val64 & ADAPTER_CNTL_EN)) {
4750 printk(KERN_ERR
4751 "Adapter Link down, cannot blink LED\n");
4752 return -EFAULT;
4753 }
4754 }
4755 if (sp->id_timer.function == NULL) {
4756 init_timer(&sp->id_timer);
4757 sp->id_timer.function = s2io_phy_id;
4758 sp->id_timer.data = (unsigned long) sp;
4759 }
4760 mod_timer(&sp->id_timer, jiffies);
4761 if (data)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004762 msleep_interruptible(data * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004764 msleep_interruptible(MAX_FLICKER_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 del_timer_sync(&sp->id_timer);
4766
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004767 if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 writeq(last_gpio_ctrl_val, &bar0->gpio_control);
4769 last_gpio_ctrl_val = readq(&bar0->gpio_control);
4770 }
4771
4772 return 0;
4773}
4774
4775/**
4776 * s2io_ethtool_getpause_data -Pause frame frame generation and reception.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004777 * @sp : private member of the device structure, which is a pointer to the
4778 * s2io_nic structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 * @ep : pointer to the structure with pause parameters given by ethtool.
4780 * Description:
4781 * Returns the Pause frame generation and reception capability of the NIC.
4782 * Return value:
4783 * void
4784 */
4785static void s2io_ethtool_getpause_data(struct net_device *dev,
4786 struct ethtool_pauseparam *ep)
4787{
4788 u64 val64;
4789 nic_t *sp = dev->priv;
4790 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4791
4792 val64 = readq(&bar0->rmac_pause_cfg);
4793 if (val64 & RMAC_PAUSE_GEN_ENABLE)
4794 ep->tx_pause = TRUE;
4795 if (val64 & RMAC_PAUSE_RX_ENABLE)
4796 ep->rx_pause = TRUE;
4797 ep->autoneg = FALSE;
4798}
4799
4800/**
4801 * s2io_ethtool_setpause_data - set/reset pause frame generation.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004802 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 * s2io_nic structure.
4804 * @ep : pointer to the structure with pause parameters given by ethtool.
4805 * Description:
4806 * It can be used to set or reset Pause frame generation or reception
4807 * support of the NIC.
4808 * Return value:
4809 * int, returns 0 on Success
4810 */
4811
4812static int s2io_ethtool_setpause_data(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004813 struct ethtool_pauseparam *ep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814{
4815 u64 val64;
4816 nic_t *sp = dev->priv;
4817 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4818
4819 val64 = readq(&bar0->rmac_pause_cfg);
4820 if (ep->tx_pause)
4821 val64 |= RMAC_PAUSE_GEN_ENABLE;
4822 else
4823 val64 &= ~RMAC_PAUSE_GEN_ENABLE;
4824 if (ep->rx_pause)
4825 val64 |= RMAC_PAUSE_RX_ENABLE;
4826 else
4827 val64 &= ~RMAC_PAUSE_RX_ENABLE;
4828 writeq(val64, &bar0->rmac_pause_cfg);
4829 return 0;
4830}
4831
4832/**
4833 * read_eeprom - reads 4 bytes of data from user given offset.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004834 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 * s2io_nic structure.
4836 * @off : offset at which the data must be written
4837 * @data : Its an output parameter where the data read at the given
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004838 * offset is stored.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004840 * Will read 4 bytes of data from the user given offset and return the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 * read data.
4842 * NOTE: Will allow to read only part of the EEPROM visible through the
4843 * I2C bus.
4844 * Return value:
4845 * -1 on failure and 0 on success.
4846 */
4847
4848#define S2IO_DEV_ID 5
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004849static int read_eeprom(nic_t * sp, int off, u64 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850{
4851 int ret = -1;
4852 u32 exit_cnt = 0;
4853 u64 val64;
4854 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4855
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004856 if (sp->device_type == XFRAME_I_DEVICE) {
4857 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4858 I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ |
4859 I2C_CONTROL_CNTL_START;
4860 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004862 while (exit_cnt < 5) {
4863 val64 = readq(&bar0->i2c_control);
4864 if (I2C_CONTROL_CNTL_END(val64)) {
4865 *data = I2C_CONTROL_GET_DATA(val64);
4866 ret = 0;
4867 break;
4868 }
4869 msleep(50);
4870 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 }
4873
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004874 if (sp->device_type == XFRAME_II_DEVICE) {
4875 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004876 SPI_CONTROL_BYTECNT(0x3) |
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004877 SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off);
4878 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4879 val64 |= SPI_CONTROL_REQ;
4880 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4881 while (exit_cnt < 5) {
4882 val64 = readq(&bar0->spi_control);
4883 if (val64 & SPI_CONTROL_NACK) {
4884 ret = 1;
4885 break;
4886 } else if (val64 & SPI_CONTROL_DONE) {
4887 *data = readq(&bar0->spi_data);
4888 *data &= 0xffffff;
4889 ret = 0;
4890 break;
4891 }
4892 msleep(50);
4893 exit_cnt++;
4894 }
4895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 return ret;
4897}
4898
4899/**
4900 * write_eeprom - actually writes the relevant part of the data value.
4901 * @sp : private member of the device structure, which is a pointer to the
4902 * s2io_nic structure.
4903 * @off : offset at which the data must be written
4904 * @data : The data that is to be written
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004905 * @cnt : Number of bytes of the data that are actually to be written into
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 * the Eeprom. (max of 3)
4907 * Description:
4908 * Actually writes the relevant part of the data value into the Eeprom
4909 * through the I2C bus.
4910 * Return value:
4911 * 0 on success, -1 on failure.
4912 */
4913
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004914static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915{
4916 int exit_cnt = 0, ret = -1;
4917 u64 val64;
4918 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4919
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004920 if (sp->device_type == XFRAME_I_DEVICE) {
4921 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4922 I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) |
4923 I2C_CONTROL_CNTL_START;
4924 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004926 while (exit_cnt < 5) {
4927 val64 = readq(&bar0->i2c_control);
4928 if (I2C_CONTROL_CNTL_END(val64)) {
4929 if (!(val64 & I2C_CONTROL_NACK))
4930 ret = 0;
4931 break;
4932 }
4933 msleep(50);
4934 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 }
4937
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004938 if (sp->device_type == XFRAME_II_DEVICE) {
4939 int write_cnt = (cnt == 8) ? 0 : cnt;
4940 writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data);
4941
4942 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004943 SPI_CONTROL_BYTECNT(write_cnt) |
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004944 SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off);
4945 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4946 val64 |= SPI_CONTROL_REQ;
4947 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4948 while (exit_cnt < 5) {
4949 val64 = readq(&bar0->spi_control);
4950 if (val64 & SPI_CONTROL_NACK) {
4951 ret = 1;
4952 break;
4953 } else if (val64 & SPI_CONTROL_DONE) {
4954 ret = 0;
4955 break;
4956 }
4957 msleep(50);
4958 exit_cnt++;
4959 }
4960 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 return ret;
4962}
Ananda Raju9dc737a2006-04-21 19:05:41 -04004963static void s2io_vpd_read(nic_t *nic)
4964{
Ananda Rajub41477f2006-07-24 19:52:49 -04004965 u8 *vpd_data;
4966 u8 data;
Ananda Raju9dc737a2006-04-21 19:05:41 -04004967 int i=0, cnt, fail = 0;
4968 int vpd_addr = 0x80;
4969
4970 if (nic->device_type == XFRAME_II_DEVICE) {
4971 strcpy(nic->product_name, "Xframe II 10GbE network adapter");
4972 vpd_addr = 0x80;
4973 }
4974 else {
4975 strcpy(nic->product_name, "Xframe I 10GbE network adapter");
4976 vpd_addr = 0x50;
4977 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05004978 strcpy(nic->serial_num, "NOT AVAILABLE");
Ananda Raju9dc737a2006-04-21 19:05:41 -04004979
Ananda Rajub41477f2006-07-24 19:52:49 -04004980 vpd_data = kmalloc(256, GFP_KERNEL);
4981 if (!vpd_data)
4982 return;
4983
Ananda Raju9dc737a2006-04-21 19:05:41 -04004984 for (i = 0; i < 256; i +=4 ) {
4985 pci_write_config_byte(nic->pdev, (vpd_addr + 2), i);
4986 pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data);
4987 pci_write_config_byte(nic->pdev, (vpd_addr + 3), 0);
4988 for (cnt = 0; cnt <5; cnt++) {
4989 msleep(2);
4990 pci_read_config_byte(nic->pdev, (vpd_addr + 3), &data);
4991 if (data == 0x80)
4992 break;
4993 }
4994 if (cnt >= 5) {
4995 DBG_PRINT(ERR_DBG, "Read of VPD data failed\n");
4996 fail = 1;
4997 break;
4998 }
4999 pci_read_config_dword(nic->pdev, (vpd_addr + 4),
5000 (u32 *)&vpd_data[i]);
5001 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05005002
5003 if(!fail) {
5004 /* read serial number of adapter */
5005 for (cnt = 0; cnt < 256; cnt++) {
5006 if ((vpd_data[cnt] == 'S') &&
5007 (vpd_data[cnt+1] == 'N') &&
5008 (vpd_data[cnt+2] < VPD_STRING_LEN)) {
5009 memset(nic->serial_num, 0, VPD_STRING_LEN);
5010 memcpy(nic->serial_num, &vpd_data[cnt + 3],
5011 vpd_data[cnt+2]);
5012 break;
5013 }
5014 }
5015 }
5016
5017 if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04005018 memset(nic->product_name, 0, vpd_data[1]);
5019 memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
5020 }
Ananda Rajub41477f2006-07-24 19:52:49 -04005021 kfree(vpd_data);
Ananda Raju9dc737a2006-04-21 19:05:41 -04005022}
5023
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024/**
5025 * s2io_ethtool_geeprom - reads the value stored in the Eeprom.
5026 * @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 -07005027 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 * containing all relevant information.
5029 * @data_buf : user defined value to be written into Eeprom.
5030 * Description: Reads the values stored in the Eeprom at given offset
5031 * for a given length. Stores these values int the input argument data
5032 * buffer 'data_buf' and returns these to the caller (ethtool.)
5033 * Return value:
5034 * int 0 on success
5035 */
5036
5037static int s2io_ethtool_geeprom(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005038 struct ethtool_eeprom *eeprom, u8 * data_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039{
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005040 u32 i, valid;
5041 u64 data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042 nic_t *sp = dev->priv;
5043
5044 eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
5045
5046 if ((eeprom->offset + eeprom->len) > (XENA_EEPROM_SPACE))
5047 eeprom->len = XENA_EEPROM_SPACE - eeprom->offset;
5048
5049 for (i = 0; i < eeprom->len; i += 4) {
5050 if (read_eeprom(sp, (eeprom->offset + i), &data)) {
5051 DBG_PRINT(ERR_DBG, "Read of EEPROM failed\n");
5052 return -EFAULT;
5053 }
5054 valid = INV(data);
5055 memcpy((data_buf + i), &valid, 4);
5056 }
5057 return 0;
5058}
5059
5060/**
5061 * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom
5062 * @sp : private member of the device structure, which is a pointer to the
5063 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005064 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 * containing all relevant information.
5066 * @data_buf ; user defined value to be written into Eeprom.
5067 * Description:
5068 * Tries to write the user provided value in the Eeprom, at the offset
5069 * given by the user.
5070 * Return value:
5071 * 0 on success, -EFAULT on failure.
5072 */
5073
5074static int s2io_ethtool_seeprom(struct net_device *dev,
5075 struct ethtool_eeprom *eeprom,
5076 u8 * data_buf)
5077{
5078 int len = eeprom->len, cnt = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005079 u64 valid = 0, data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 nic_t *sp = dev->priv;
5081
5082 if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
5083 DBG_PRINT(ERR_DBG,
5084 "ETHTOOL_WRITE_EEPROM Err: Magic value ");
5085 DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n",
5086 eeprom->magic);
5087 return -EFAULT;
5088 }
5089
5090 while (len) {
5091 data = (u32) data_buf[cnt] & 0x000000FF;
5092 if (data) {
5093 valid = (u32) (data << 24);
5094 } else
5095 valid = data;
5096
5097 if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) {
5098 DBG_PRINT(ERR_DBG,
5099 "ETHTOOL_WRITE_EEPROM Err: Cannot ");
5100 DBG_PRINT(ERR_DBG,
5101 "write into the specified offset\n");
5102 return -EFAULT;
5103 }
5104 cnt++;
5105 len--;
5106 }
5107
5108 return 0;
5109}
5110
5111/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005112 * s2io_register_test - reads and writes into all clock domains.
5113 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 * s2io_nic structure.
5115 * @data : variable that returns the result of each of the test conducted b
5116 * by the driver.
5117 * Description:
5118 * Read and write into all clock domains. The NIC has 3 clock domains,
5119 * see that registers in all the three regions are accessible.
5120 * Return value:
5121 * 0 on success.
5122 */
5123
5124static int s2io_register_test(nic_t * sp, uint64_t * data)
5125{
5126 XENA_dev_config_t __iomem *bar0 = sp->bar0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005127 u64 val64 = 0, exp_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 int fail = 0;
5129
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005130 val64 = readq(&bar0->pif_rd_swapper_fb);
5131 if (val64 != 0x123456789abcdefULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 fail = 1;
5133 DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n");
5134 }
5135
5136 val64 = readq(&bar0->rmac_pause_cfg);
5137 if (val64 != 0xc000ffff00000000ULL) {
5138 fail = 1;
5139 DBG_PRINT(INFO_DBG, "Read Test level 2 fails\n");
5140 }
5141
5142 val64 = readq(&bar0->rx_queue_cfg);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005143 if (sp->device_type == XFRAME_II_DEVICE)
5144 exp_val = 0x0404040404040404ULL;
5145 else
5146 exp_val = 0x0808080808080808ULL;
5147 if (val64 != exp_val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 fail = 1;
5149 DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n");
5150 }
5151
5152 val64 = readq(&bar0->xgxs_efifo_cfg);
5153 if (val64 != 0x000000001923141EULL) {
5154 fail = 1;
5155 DBG_PRINT(INFO_DBG, "Read Test level 4 fails\n");
5156 }
5157
5158 val64 = 0x5A5A5A5A5A5A5A5AULL;
5159 writeq(val64, &bar0->xmsi_data);
5160 val64 = readq(&bar0->xmsi_data);
5161 if (val64 != 0x5A5A5A5A5A5A5A5AULL) {
5162 fail = 1;
5163 DBG_PRINT(ERR_DBG, "Write Test level 1 fails\n");
5164 }
5165
5166 val64 = 0xA5A5A5A5A5A5A5A5ULL;
5167 writeq(val64, &bar0->xmsi_data);
5168 val64 = readq(&bar0->xmsi_data);
5169 if (val64 != 0xA5A5A5A5A5A5A5A5ULL) {
5170 fail = 1;
5171 DBG_PRINT(ERR_DBG, "Write Test level 2 fails\n");
5172 }
5173
5174 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005175 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176}
5177
5178/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005179 * s2io_eeprom_test - to verify that EEprom in the xena can be programmed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 * @sp : private member of the device structure, which is a pointer to the
5181 * s2io_nic structure.
5182 * @data:variable that returns the result of each of the test conducted by
5183 * the driver.
5184 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005185 * Verify that EEPROM in the xena can be programmed using I2C_CONTROL
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 * register.
5187 * Return value:
5188 * 0 on success.
5189 */
5190
5191static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
5192{
5193 int fail = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005194 u64 ret_data, org_4F0, org_7F0;
5195 u8 saved_4F0 = 0, saved_7F0 = 0;
5196 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197
5198 /* Test Write Error at offset 0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005199 /* Note that SPI interface allows write access to all areas
5200 * of EEPROM. Hence doing all negative testing only for Xframe I.
5201 */
5202 if (sp->device_type == XFRAME_I_DEVICE)
5203 if (!write_eeprom(sp, 0, 0, 3))
5204 fail = 1;
5205
5206 /* Save current values at offsets 0x4F0 and 0x7F0 */
5207 if (!read_eeprom(sp, 0x4F0, &org_4F0))
5208 saved_4F0 = 1;
5209 if (!read_eeprom(sp, 0x7F0, &org_7F0))
5210 saved_7F0 = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211
5212 /* Test Write at offset 4f0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005213 if (write_eeprom(sp, 0x4F0, 0x012345, 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 fail = 1;
5215 if (read_eeprom(sp, 0x4F0, &ret_data))
5216 fail = 1;
5217
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005218 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005219 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. "
5220 "Data written %llx Data read %llx\n",
5221 dev->name, (unsigned long long)0x12345,
5222 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225
5226 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005227 write_eeprom(sp, 0x4F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228
5229 /* Test Write Request Error at offset 0x7c */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005230 if (sp->device_type == XFRAME_I_DEVICE)
5231 if (!write_eeprom(sp, 0x07C, 0, 3))
5232 fail = 1;
5233
5234 /* Test Write Request at offset 0x7f0 */
5235 if (write_eeprom(sp, 0x7F0, 0x012345, 3))
5236 fail = 1;
5237 if (read_eeprom(sp, 0x7F0, &ret_data))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238 fail = 1;
5239
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005240 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005241 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. "
5242 "Data written %llx Data read %llx\n",
5243 dev->name, (unsigned long long)0x12345,
5244 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247
5248 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005249 write_eeprom(sp, 0x7F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005251 if (sp->device_type == XFRAME_I_DEVICE) {
5252 /* Test Write Error at offset 0x80 */
5253 if (!write_eeprom(sp, 0x080, 0, 3))
5254 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005256 /* Test Write Error at offset 0xfc */
5257 if (!write_eeprom(sp, 0x0FC, 0, 3))
5258 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005260 /* Test Write Error at offset 0x100 */
5261 if (!write_eeprom(sp, 0x100, 0, 3))
5262 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005264 /* Test Write Error at offset 4ec */
5265 if (!write_eeprom(sp, 0x4EC, 0, 3))
5266 fail = 1;
5267 }
5268
5269 /* Restore values at offsets 0x4F0 and 0x7F0 */
5270 if (saved_4F0)
5271 write_eeprom(sp, 0x4F0, org_4F0, 3);
5272 if (saved_7F0)
5273 write_eeprom(sp, 0x7F0, org_7F0, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274
5275 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005276 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277}
5278
5279/**
5280 * s2io_bist_test - invokes the MemBist test of the card .
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005281 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005283 * @data:variable that returns the result of each of the test conducted by
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284 * the driver.
5285 * Description:
5286 * This invokes the MemBist test of the card. We give around
5287 * 2 secs time for the Test to complete. If it's still not complete
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005288 * within this peiod, we consider that the test failed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 * Return value:
5290 * 0 on success and -1 on failure.
5291 */
5292
5293static int s2io_bist_test(nic_t * sp, uint64_t * data)
5294{
5295 u8 bist = 0;
5296 int cnt = 0, ret = -1;
5297
5298 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5299 bist |= PCI_BIST_START;
5300 pci_write_config_word(sp->pdev, PCI_BIST, bist);
5301
5302 while (cnt < 20) {
5303 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5304 if (!(bist & PCI_BIST_START)) {
5305 *data = (bist & PCI_BIST_CODE_MASK);
5306 ret = 0;
5307 break;
5308 }
5309 msleep(100);
5310 cnt++;
5311 }
5312
5313 return ret;
5314}
5315
5316/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005317 * s2io-link_test - verifies the link state of the nic
5318 * @sp ; private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319 * s2io_nic structure.
5320 * @data: variable that returns the result of each of the test conducted by
5321 * the driver.
5322 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005323 * The function verifies the link state of the NIC and updates the input
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 * argument 'data' appropriately.
5325 * Return value:
5326 * 0 on success.
5327 */
5328
5329static int s2io_link_test(nic_t * sp, uint64_t * data)
5330{
5331 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5332 u64 val64;
5333
5334 val64 = readq(&bar0->adapter_status);
Ananda Rajuc92ca042006-04-21 19:18:03 -04005335 if(!(LINK_IS_UP(val64)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336 *data = 1;
Ananda Rajuc92ca042006-04-21 19:18:03 -04005337 else
5338 *data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005339
Ananda Rajub41477f2006-07-24 19:52:49 -04005340 return *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341}
5342
5343/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005344 * s2io_rldram_test - offline test for access to the RldRam chip on the NIC
5345 * @sp - private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005347 * @data - variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348 * conducted by the driver.
5349 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005350 * This is one of the offline test that tests the read and write
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 * access to the RldRam chip on the NIC.
5352 * Return value:
5353 * 0 on success.
5354 */
5355
5356static int s2io_rldram_test(nic_t * sp, uint64_t * data)
5357{
5358 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5359 u64 val64;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005360 int cnt, iteration = 0, test_fail = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361
5362 val64 = readq(&bar0->adapter_control);
5363 val64 &= ~ADAPTER_ECC_EN;
5364 writeq(val64, &bar0->adapter_control);
5365
5366 val64 = readq(&bar0->mc_rldram_test_ctrl);
5367 val64 |= MC_RLDRAM_TEST_MODE;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005368 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369
5370 val64 = readq(&bar0->mc_rldram_mrs);
5371 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE;
5372 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5373
5374 val64 |= MC_RLDRAM_MRS_ENABLE;
5375 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5376
5377 while (iteration < 2) {
5378 val64 = 0x55555555aaaa0000ULL;
5379 if (iteration == 1) {
5380 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5381 }
5382 writeq(val64, &bar0->mc_rldram_test_d0);
5383
5384 val64 = 0xaaaa5a5555550000ULL;
5385 if (iteration == 1) {
5386 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5387 }
5388 writeq(val64, &bar0->mc_rldram_test_d1);
5389
5390 val64 = 0x55aaaaaaaa5a0000ULL;
5391 if (iteration == 1) {
5392 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5393 }
5394 writeq(val64, &bar0->mc_rldram_test_d2);
5395
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005396 val64 = (u64) (0x0000003ffffe0100ULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 writeq(val64, &bar0->mc_rldram_test_add);
5398
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005399 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE |
5400 MC_RLDRAM_TEST_GO;
5401 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402
5403 for (cnt = 0; cnt < 5; cnt++) {
5404 val64 = readq(&bar0->mc_rldram_test_ctrl);
5405 if (val64 & MC_RLDRAM_TEST_DONE)
5406 break;
5407 msleep(200);
5408 }
5409
5410 if (cnt == 5)
5411 break;
5412
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005413 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO;
5414 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415
5416 for (cnt = 0; cnt < 5; cnt++) {
5417 val64 = readq(&bar0->mc_rldram_test_ctrl);
5418 if (val64 & MC_RLDRAM_TEST_DONE)
5419 break;
5420 msleep(500);
5421 }
5422
5423 if (cnt == 5)
5424 break;
5425
5426 val64 = readq(&bar0->mc_rldram_test_ctrl);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005427 if (!(val64 & MC_RLDRAM_TEST_PASS))
5428 test_fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429
5430 iteration++;
5431 }
5432
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005433 *data = test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005435 /* Bring the adapter out of test mode */
5436 SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF);
5437
5438 return test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439}
5440
5441/**
5442 * s2io_ethtool_test - conducts 6 tsets to determine the health of card.
5443 * @sp : private member of the device structure, which is a pointer to the
5444 * s2io_nic structure.
5445 * @ethtest : pointer to a ethtool command specific structure that will be
5446 * returned to the user.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005447 * @data : variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 * conducted by the driver.
5449 * Description:
5450 * This function conducts 6 tests ( 4 offline and 2 online) to determine
5451 * the health of the card.
5452 * Return value:
5453 * void
5454 */
5455
5456static void s2io_ethtool_test(struct net_device *dev,
5457 struct ethtool_test *ethtest,
5458 uint64_t * data)
5459{
5460 nic_t *sp = dev->priv;
5461 int orig_state = netif_running(sp->dev);
5462
5463 if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
5464 /* Offline Tests. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005465 if (orig_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466 s2io_close(sp->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467
5468 if (s2io_register_test(sp, &data[0]))
5469 ethtest->flags |= ETH_TEST_FL_FAILED;
5470
5471 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472
5473 if (s2io_rldram_test(sp, &data[3]))
5474 ethtest->flags |= ETH_TEST_FL_FAILED;
5475
5476 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477
5478 if (s2io_eeprom_test(sp, &data[1]))
5479 ethtest->flags |= ETH_TEST_FL_FAILED;
5480
5481 if (s2io_bist_test(sp, &data[4]))
5482 ethtest->flags |= ETH_TEST_FL_FAILED;
5483
5484 if (orig_state)
5485 s2io_open(sp->dev);
5486
5487 data[2] = 0;
5488 } else {
5489 /* Online Tests. */
5490 if (!orig_state) {
5491 DBG_PRINT(ERR_DBG,
5492 "%s: is not up, cannot run test\n",
5493 dev->name);
5494 data[0] = -1;
5495 data[1] = -1;
5496 data[2] = -1;
5497 data[3] = -1;
5498 data[4] = -1;
5499 }
5500
5501 if (s2io_link_test(sp, &data[2]))
5502 ethtest->flags |= ETH_TEST_FL_FAILED;
5503
5504 data[0] = 0;
5505 data[1] = 0;
5506 data[3] = 0;
5507 data[4] = 0;
5508 }
5509}
5510
5511static void s2io_get_ethtool_stats(struct net_device *dev,
5512 struct ethtool_stats *estats,
5513 u64 * tmp_stats)
5514{
5515 int i = 0;
5516 nic_t *sp = dev->priv;
5517 StatInfo_t *stat_info = sp->mac_control.stats_info;
5518
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005519 s2io_updt_stats(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005520 tmp_stats[i++] =
5521 (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32 |
5522 le32_to_cpu(stat_info->tmac_frms);
5523 tmp_stats[i++] =
5524 (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 |
5525 le32_to_cpu(stat_info->tmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005527 tmp_stats[i++] =
5528 (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 |
5529 le32_to_cpu(stat_info->tmac_mcst_frms);
5530 tmp_stats[i++] =
5531 (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 |
5532 le32_to_cpu(stat_info->tmac_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005534 tmp_stats[i++] =
5535 (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 |
5536 le32_to_cpu(stat_info->tmac_ttl_octets);
5537 tmp_stats[i++] =
5538 (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 |
5539 le32_to_cpu(stat_info->tmac_ucst_frms);
5540 tmp_stats[i++] =
5541 (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 |
5542 le32_to_cpu(stat_info->tmac_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005543 tmp_stats[i++] =
5544 (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 |
5545 le32_to_cpu(stat_info->tmac_any_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005546 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005548 tmp_stats[i++] =
5549 (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 |
5550 le32_to_cpu(stat_info->tmac_vld_ip);
5551 tmp_stats[i++] =
5552 (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 |
5553 le32_to_cpu(stat_info->tmac_drop_ip);
5554 tmp_stats[i++] =
5555 (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 |
5556 le32_to_cpu(stat_info->tmac_icmp);
5557 tmp_stats[i++] =
5558 (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 |
5559 le32_to_cpu(stat_info->tmac_rst_tcp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005561 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 |
5562 le32_to_cpu(stat_info->tmac_udp);
5563 tmp_stats[i++] =
5564 (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 |
5565 le32_to_cpu(stat_info->rmac_vld_frms);
5566 tmp_stats[i++] =
5567 (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 |
5568 le32_to_cpu(stat_info->rmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms);
5570 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005571 tmp_stats[i++] =
5572 (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 |
5573 le32_to_cpu(stat_info->rmac_vld_mcst_frms);
5574 tmp_stats[i++] =
5575 (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 |
5576 le32_to_cpu(stat_info->rmac_vld_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005578 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_out_rng_len_err_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms);
5580 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005581 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_unsup_ctrl_frms);
5582 tmp_stats[i++] =
5583 (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 |
5584 le32_to_cpu(stat_info->rmac_ttl_octets);
5585 tmp_stats[i++] =
5586 (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow)
5587 << 32 | le32_to_cpu(stat_info->rmac_accepted_ucst_frms);
5588 tmp_stats[i++] =
5589 (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow)
5590 << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005591 tmp_stats[i++] =
5592 (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 |
5593 le32_to_cpu(stat_info->rmac_discarded_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005594 tmp_stats[i++] =
5595 (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow)
5596 << 32 | le32_to_cpu(stat_info->rmac_drop_events);
5597 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets);
5598 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005599 tmp_stats[i++] =
5600 (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 |
5601 le32_to_cpu(stat_info->rmac_usized_frms);
5602 tmp_stats[i++] =
5603 (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 |
5604 le32_to_cpu(stat_info->rmac_osized_frms);
5605 tmp_stats[i++] =
5606 (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 |
5607 le32_to_cpu(stat_info->rmac_frag_frms);
5608 tmp_stats[i++] =
5609 (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 |
5610 le32_to_cpu(stat_info->rmac_jabber_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005611 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_64_frms);
5612 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms);
5613 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms);
5614 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms);
5615 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms);
5616 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms);
5617 tmp_stats[i++] =
5618 (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005619 le32_to_cpu(stat_info->rmac_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets);
5621 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005622 tmp_stats[i++] =
5623 (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005624 le32_to_cpu(stat_info->rmac_drop_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005625 tmp_stats[i++] =
5626 (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005627 le32_to_cpu(stat_info->rmac_icmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005629 tmp_stats[i++] =
5630 (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005631 le32_to_cpu(stat_info->rmac_udp);
5632 tmp_stats[i++] =
5633 (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 |
5634 le32_to_cpu(stat_info->rmac_err_drp_udp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005635 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_err_sym);
5636 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0);
5637 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1);
5638 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2);
5639 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3);
5640 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4);
5641 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5);
5642 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6);
5643 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7);
5644 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0);
5645 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1);
5646 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2);
5647 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3);
5648 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4);
5649 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5);
5650 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6);
5651 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005652 tmp_stats[i++] =
5653 (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 |
5654 le32_to_cpu(stat_info->rmac_pause_cnt);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005655 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_data_err_cnt);
5656 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005657 tmp_stats[i++] =
5658 (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 |
5659 le32_to_cpu(stat_info->rmac_accepted_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005661 tmp_stats[i++] = le32_to_cpu(stat_info->rd_req_cnt);
5662 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_cnt);
5663 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_rtry_cnt);
5664 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_cnt);
5665 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_rd_ack_cnt);
5666 tmp_stats[i++] = le32_to_cpu(stat_info->wr_req_cnt);
5667 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_cnt);
5668 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_rtry_cnt);
5669 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_cnt);
5670 tmp_stats[i++] = le32_to_cpu(stat_info->wr_disc_cnt);
5671 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_wr_ack_cnt);
5672 tmp_stats[i++] = le32_to_cpu(stat_info->txp_wr_cnt);
5673 tmp_stats[i++] = le32_to_cpu(stat_info->txd_rd_cnt);
5674 tmp_stats[i++] = le32_to_cpu(stat_info->txd_wr_cnt);
5675 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_rd_cnt);
5676 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_wr_cnt);
5677 tmp_stats[i++] = le32_to_cpu(stat_info->txf_rd_cnt);
5678 tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt);
5679 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms);
5680 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms);
5681 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_8192_max_frms);
5682 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms);
5683 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms);
5684 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms);
5685 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms);
5686 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms);
5687 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard);
5688 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard);
5689 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard);
5690 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard);
5691 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard);
5692 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard);
5693 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard);
5694 tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005695 tmp_stats[i++] = 0;
5696 tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
5697 tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
Ananda Rajubd1034f2006-04-21 19:20:22 -04005698 tmp_stats[i++] = stat_info->sw_stat.parity_err_cnt;
5699 tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt;
5700 tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt;
5701 tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt;
5702 tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt;
5703 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high;
5704 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low;
5705 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high;
5706 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_low;
5707 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_high;
5708 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_low;
5709 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_high;
5710 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_low;
5711 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_high;
5712 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_low;
5713 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_high;
5714 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_low;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005715 tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt;
5716 tmp_stats[i++] = stat_info->sw_stat.sending_both;
5717 tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts;
5718 tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts;
Andrew Mortonfe931392006-02-03 01:45:12 -08005719 if (stat_info->sw_stat.num_aggregations) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04005720 u64 tmp = stat_info->sw_stat.sum_avg_pkts_aggregated;
5721 int count = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005722 /*
Ananda Rajubd1034f2006-04-21 19:20:22 -04005723 * Since 64-bit divide does not work on all platforms,
5724 * do repeated subtraction.
5725 */
5726 while (tmp >= stat_info->sw_stat.num_aggregations) {
5727 tmp -= stat_info->sw_stat.num_aggregations;
5728 count++;
5729 }
5730 tmp_stats[i++] = count;
Andrew Mortonfe931392006-02-03 01:45:12 -08005731 }
Ananda Rajubd1034f2006-04-21 19:20:22 -04005732 else
5733 tmp_stats[i++] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734}
5735
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005736static int s2io_ethtool_get_regs_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737{
5738 return (XENA_REG_SPACE);
5739}
5740
5741
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005742static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743{
5744 nic_t *sp = dev->priv;
5745
5746 return (sp->rx_csum);
5747}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005748
5749static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750{
5751 nic_t *sp = dev->priv;
5752
5753 if (data)
5754 sp->rx_csum = 1;
5755 else
5756 sp->rx_csum = 0;
5757
5758 return 0;
5759}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005760
5761static int s2io_get_eeprom_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762{
5763 return (XENA_EEPROM_SPACE);
5764}
5765
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005766static int s2io_ethtool_self_test_count(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767{
5768 return (S2IO_TEST_LEN);
5769}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005770
5771static void s2io_ethtool_get_strings(struct net_device *dev,
5772 u32 stringset, u8 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773{
5774 switch (stringset) {
5775 case ETH_SS_TEST:
5776 memcpy(data, s2io_gstrings, S2IO_STRINGS_LEN);
5777 break;
5778 case ETH_SS_STATS:
5779 memcpy(data, &ethtool_stats_keys,
5780 sizeof(ethtool_stats_keys));
5781 }
5782}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783static int s2io_ethtool_get_stats_count(struct net_device *dev)
5784{
5785 return (S2IO_STAT_LEN);
5786}
5787
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005788static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789{
5790 if (data)
5791 dev->features |= NETIF_F_IP_CSUM;
5792 else
5793 dev->features &= ~NETIF_F_IP_CSUM;
5794
5795 return 0;
5796}
5797
Ananda Raju75c30b12006-07-24 19:55:09 -04005798static u32 s2io_ethtool_op_get_tso(struct net_device *dev)
5799{
5800 return (dev->features & NETIF_F_TSO) != 0;
5801}
5802static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data)
5803{
5804 if (data)
5805 dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
5806 else
5807 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
5808
5809 return 0;
5810}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811
Jeff Garzik7282d492006-09-13 14:30:00 -04005812static const struct ethtool_ops netdev_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813 .get_settings = s2io_ethtool_gset,
5814 .set_settings = s2io_ethtool_sset,
5815 .get_drvinfo = s2io_ethtool_gdrvinfo,
5816 .get_regs_len = s2io_ethtool_get_regs_len,
5817 .get_regs = s2io_ethtool_gregs,
5818 .get_link = ethtool_op_get_link,
5819 .get_eeprom_len = s2io_get_eeprom_len,
5820 .get_eeprom = s2io_ethtool_geeprom,
5821 .set_eeprom = s2io_ethtool_seeprom,
5822 .get_pauseparam = s2io_ethtool_getpause_data,
5823 .set_pauseparam = s2io_ethtool_setpause_data,
5824 .get_rx_csum = s2io_ethtool_get_rx_csum,
5825 .set_rx_csum = s2io_ethtool_set_rx_csum,
5826 .get_tx_csum = ethtool_op_get_tx_csum,
5827 .set_tx_csum = s2io_ethtool_op_set_tx_csum,
5828 .get_sg = ethtool_op_get_sg,
5829 .set_sg = ethtool_op_set_sg,
Ananda Raju75c30b12006-07-24 19:55:09 -04005830 .get_tso = s2io_ethtool_op_get_tso,
5831 .set_tso = s2io_ethtool_op_set_tso,
Ananda Rajufed5ecc2005-11-14 15:25:08 -05005832 .get_ufo = ethtool_op_get_ufo,
5833 .set_ufo = ethtool_op_set_ufo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005834 .self_test_count = s2io_ethtool_self_test_count,
5835 .self_test = s2io_ethtool_test,
5836 .get_strings = s2io_ethtool_get_strings,
5837 .phys_id = s2io_ethtool_idnic,
5838 .get_stats_count = s2io_ethtool_get_stats_count,
5839 .get_ethtool_stats = s2io_get_ethtool_stats
5840};
5841
5842/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005843 * s2io_ioctl - Entry point for the Ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844 * @dev : Device pointer.
5845 * @ifr : An IOCTL specefic structure, that can contain a pointer to
5846 * a proprietary structure used to pass information to the driver.
5847 * @cmd : This is used to distinguish between the different commands that
5848 * can be passed to the IOCTL functions.
5849 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005850 * Currently there are no special functionality supported in IOCTL, hence
5851 * function always return EOPNOTSUPPORTED
Linus Torvalds1da177e2005-04-16 15:20:36 -07005852 */
5853
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005854static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005855{
5856 return -EOPNOTSUPP;
5857}
5858
5859/**
5860 * s2io_change_mtu - entry point to change MTU size for the device.
5861 * @dev : device pointer.
5862 * @new_mtu : the new MTU size for the device.
5863 * Description: A driver entry point to change MTU size for the device.
5864 * Before changing the MTU the device must be stopped.
5865 * Return value:
5866 * 0 on success and an appropriate (-)ve integer as defined in errno.h
5867 * file on failure.
5868 */
5869
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005870static int s2io_change_mtu(struct net_device *dev, int new_mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871{
5872 nic_t *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873
5874 if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
5875 DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
5876 dev->name);
5877 return -EPERM;
5878 }
5879
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 dev->mtu = new_mtu;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005881 if (netif_running(dev)) {
Ananda Rajue6a8fee2006-07-06 23:58:23 -07005882 s2io_card_down(sp);
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005883 netif_stop_queue(dev);
5884 if (s2io_card_up(sp)) {
5885 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
5886 __FUNCTION__);
5887 }
5888 if (netif_queue_stopped(dev))
5889 netif_wake_queue(dev);
5890 } else { /* Device is down */
5891 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5892 u64 val64 = new_mtu;
5893
5894 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
5895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896
5897 return 0;
5898}
5899
5900/**
5901 * s2io_tasklet - Bottom half of the ISR.
5902 * @dev_adr : address of the device structure in dma_addr_t format.
5903 * Description:
5904 * This is the tasklet or the bottom half of the ISR. This is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005905 * an extension of the ISR which is scheduled by the scheduler to be run
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906 * 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 -07005907 * be pushed into the tasklet. For now the tasklet is used only to
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908 * replenish the Rx buffers in the Rx buffer descriptors.
5909 * Return value:
5910 * void.
5911 */
5912
5913static void s2io_tasklet(unsigned long dev_addr)
5914{
5915 struct net_device *dev = (struct net_device *) dev_addr;
5916 nic_t *sp = dev->priv;
5917 int i, ret;
5918 mac_info_t *mac_control;
5919 struct config_param *config;
5920
5921 mac_control = &sp->mac_control;
5922 config = &sp->config;
5923
5924 if (!TASKLET_IN_USE) {
5925 for (i = 0; i < config->rx_ring_num; i++) {
5926 ret = fill_rx_buffers(sp, i);
5927 if (ret == -ENOMEM) {
5928 DBG_PRINT(ERR_DBG, "%s: Out of ",
5929 dev->name);
5930 DBG_PRINT(ERR_DBG, "memory in tasklet\n");
5931 break;
5932 } else if (ret == -EFILL) {
5933 DBG_PRINT(ERR_DBG,
5934 "%s: Rx Ring %d is full\n",
5935 dev->name, i);
5936 break;
5937 }
5938 }
5939 clear_bit(0, (&sp->tasklet_status));
5940 }
5941}
5942
5943/**
5944 * s2io_set_link - Set the LInk status
5945 * @data: long pointer to device private structue
5946 * Description: Sets the link status for the adapter
5947 */
5948
David Howellsc4028952006-11-22 14:57:56 +00005949static void s2io_set_link(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950{
David Howellsc4028952006-11-22 14:57:56 +00005951 nic_t *nic = container_of(work, nic_t, set_link_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952 struct net_device *dev = nic->dev;
5953 XENA_dev_config_t __iomem *bar0 = nic->bar0;
5954 register u64 val64;
5955 u16 subid;
5956
5957 if (test_and_set_bit(0, &(nic->link_state))) {
5958 /* The card is being reset, no point doing anything */
5959 return;
5960 }
5961
5962 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07005963 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
5964 /*
5965 * Allow a small delay for the NICs self initiated
5966 * cleanup to complete.
5967 */
5968 msleep(100);
5969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970
5971 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05005972 if (LINK_IS_UP(val64)) {
5973 if (!(readq(&bar0->adapter_control) & ADAPTER_CNTL_EN)) {
5974 if (verify_xena_quiescence(nic)) {
5975 val64 = readq(&bar0->adapter_control);
5976 val64 |= ADAPTER_CNTL_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 writeq(val64, &bar0->adapter_control);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05005978 if (CARDS_WITH_FAULTY_LINK_INDICATORS(
5979 nic->device_type, subid)) {
5980 val64 = readq(&bar0->gpio_control);
5981 val64 |= GPIO_CTRL_GPIO_0;
5982 writeq(val64, &bar0->gpio_control);
5983 val64 = readq(&bar0->gpio_control);
5984 } else {
5985 val64 |= ADAPTER_LED_ON;
5986 writeq(val64, &bar0->adapter_control);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07005987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988 nic->device_enabled_once = TRUE;
Sivakumar Subramani19a60522007-01-31 13:30:49 -05005989 } else {
5990 DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
5991 DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
5992 netif_stop_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05005995 val64 = readq(&bar0->adapter_status);
5996 if (!LINK_IS_UP(val64)) {
5997 DBG_PRINT(ERR_DBG, "%s:", dev->name);
5998 DBG_PRINT(ERR_DBG, " Link down after enabling ");
5999 DBG_PRINT(ERR_DBG, "device \n");
6000 } else
6001 s2io_link(nic, LINK_UP);
6002 } else {
6003 if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
6004 subid)) {
6005 val64 = readq(&bar0->gpio_control);
6006 val64 &= ~GPIO_CTRL_GPIO_0;
6007 writeq(val64, &bar0->gpio_control);
6008 val64 = readq(&bar0->gpio_control);
6009 }
6010 s2io_link(nic, LINK_DOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011 }
6012 clear_bit(0, &(nic->link_state));
6013}
6014
Ananda Raju5d3213c2006-04-21 19:23:26 -04006015static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
6016 struct sk_buff **skb, u64 *temp0, u64 *temp1,
6017 u64 *temp2, int size)
6018{
6019 struct net_device *dev = sp->dev;
6020 struct sk_buff *frag_list;
6021
6022 if ((sp->rxd_mode == RXD_MODE_1) && (rxdp->Host_Control == 0)) {
6023 /* allocate skb */
6024 if (*skb) {
6025 DBG_PRINT(INFO_DBG, "SKB is not NULL\n");
6026 /*
6027 * As Rx frame are not going to be processed,
6028 * using same mapped address for the Rxd
6029 * buffer pointer
6030 */
6031 ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0;
6032 } else {
6033 *skb = dev_alloc_skb(size);
6034 if (!(*skb)) {
6035 DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
6036 DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
6037 return -ENOMEM ;
6038 }
6039 /* storing the mapped addr in a temp variable
6040 * such it will be used for next rxd whose
6041 * Host Control is NULL
6042 */
6043 ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0 =
6044 pci_map_single( sp->pdev, (*skb)->data,
6045 size - NET_IP_ALIGN,
6046 PCI_DMA_FROMDEVICE);
6047 rxdp->Host_Control = (unsigned long) (*skb);
6048 }
6049 } else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
6050 /* Two buffer Mode */
6051 if (*skb) {
6052 ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
6053 ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
6054 ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
6055 } else {
6056 *skb = dev_alloc_skb(size);
David Rientjes2ceaac72006-10-30 14:19:25 -08006057 if (!(*skb)) {
6058 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006059 dev->name);
David Rientjes2ceaac72006-10-30 14:19:25 -08006060 return -ENOMEM;
6061 }
Ananda Raju5d3213c2006-04-21 19:23:26 -04006062 ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
6063 pci_map_single(sp->pdev, (*skb)->data,
6064 dev->mtu + 4,
6065 PCI_DMA_FROMDEVICE);
6066 ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
6067 pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
6068 PCI_DMA_FROMDEVICE);
6069 rxdp->Host_Control = (unsigned long) (*skb);
6070
6071 /* Buffer-1 will be dummy buffer not used */
6072 ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
6073 pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
6074 PCI_DMA_FROMDEVICE);
6075 }
6076 } else if ((rxdp->Host_Control == 0)) {
6077 /* Three buffer mode */
6078 if (*skb) {
6079 ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
6080 ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
6081 ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
6082 } else {
6083 *skb = dev_alloc_skb(size);
David Rientjes2ceaac72006-10-30 14:19:25 -08006084 if (!(*skb)) {
6085 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
6086 dev->name);
6087 return -ENOMEM;
6088 }
Ananda Raju5d3213c2006-04-21 19:23:26 -04006089 ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
6090 pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
6091 PCI_DMA_FROMDEVICE);
6092 /* Buffer-1 receives L3/L4 headers */
6093 ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
6094 pci_map_single( sp->pdev, (*skb)->data,
6095 l3l4hdr_size + 4,
6096 PCI_DMA_FROMDEVICE);
6097 /*
6098 * skb_shinfo(skb)->frag_list will have L4
6099 * data payload
6100 */
6101 skb_shinfo(*skb)->frag_list = dev_alloc_skb(dev->mtu +
6102 ALIGN_SIZE);
6103 if (skb_shinfo(*skb)->frag_list == NULL) {
6104 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb \
6105 failed\n ", dev->name);
6106 return -ENOMEM ;
6107 }
6108 frag_list = skb_shinfo(*skb)->frag_list;
6109 frag_list->next = NULL;
6110 /*
6111 * Buffer-2 receives L4 data payload
6112 */
6113 ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
6114 pci_map_single( sp->pdev, frag_list->data,
6115 dev->mtu, PCI_DMA_FROMDEVICE);
6116 }
6117 }
6118 return 0;
6119}
6120static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size)
6121{
6122 struct net_device *dev = sp->dev;
6123 if (sp->rxd_mode == RXD_MODE_1) {
6124 rxdp->Control_2 = SET_BUFFER0_SIZE_1( size - NET_IP_ALIGN);
6125 } else if (sp->rxd_mode == RXD_MODE_3B) {
6126 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
6127 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
6128 rxdp->Control_2 |= SET_BUFFER2_SIZE_3( dev->mtu + 4);
6129 } else {
6130 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
6131 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
6132 rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
6133 }
6134}
6135
6136static int rxd_owner_bit_reset(nic_t *sp)
6137{
6138 int i, j, k, blk_cnt = 0, size;
6139 mac_info_t * mac_control = &sp->mac_control;
6140 struct config_param *config = &sp->config;
6141 struct net_device *dev = sp->dev;
6142 RxD_t *rxdp = NULL;
6143 struct sk_buff *skb = NULL;
6144 buffAdd_t *ba = NULL;
6145 u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0;
6146
6147 /* Calculate the size based on ring mode */
6148 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
6149 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
6150 if (sp->rxd_mode == RXD_MODE_1)
6151 size += NET_IP_ALIGN;
6152 else if (sp->rxd_mode == RXD_MODE_3B)
6153 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
6154 else
6155 size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
6156
6157 for (i = 0; i < config->rx_ring_num; i++) {
6158 blk_cnt = config->rx_cfg[i].num_rxd /
6159 (rxd_count[sp->rxd_mode] +1);
6160
6161 for (j = 0; j < blk_cnt; j++) {
6162 for (k = 0; k < rxd_count[sp->rxd_mode]; k++) {
6163 rxdp = mac_control->rings[i].
6164 rx_blocks[j].rxds[k].virt_addr;
6165 if(sp->rxd_mode >= RXD_MODE_3A)
6166 ba = &mac_control->rings[i].ba[j][k];
6167 set_rxd_buffer_pointer(sp, rxdp, ba,
6168 &skb,(u64 *)&temp0_64,
6169 (u64 *)&temp1_64,
6170 (u64 *)&temp2_64, size);
6171
6172 set_rxd_buffer_size(sp, rxdp, size);
6173 wmb();
6174 /* flip the Ownership bit to Hardware */
6175 rxdp->Control_1 |= RXD_OWN_XENA;
6176 }
6177 }
6178 }
6179 return 0;
6180
6181}
6182
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006183static int s2io_add_isr(nic_t * sp)
6184{
6185 int ret = 0;
6186 struct net_device *dev = sp->dev;
6187 int err = 0;
6188
6189 if (sp->intr_type == MSI)
6190 ret = s2io_enable_msi(sp);
6191 else if (sp->intr_type == MSI_X)
6192 ret = s2io_enable_msi_x(sp);
6193 if (ret) {
6194 DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
6195 sp->intr_type = INTA;
6196 }
6197
6198 /* Store the values of the MSIX table in the nic_t structure */
6199 store_xmsi_data(sp);
6200
6201 /* After proper initialization of H/W, register ISR */
6202 if (sp->intr_type == MSI) {
6203 err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
6204 IRQF_SHARED, sp->name, dev);
6205 if (err) {
6206 pci_disable_msi(sp->pdev);
6207 DBG_PRINT(ERR_DBG, "%s: MSI registration failed\n",
6208 dev->name);
6209 return -1;
6210 }
6211 }
6212 if (sp->intr_type == MSI_X) {
6213 int i;
6214
6215 for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
6216 if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
6217 sprintf(sp->desc[i], "%s:MSI-X-%d-TX",
6218 dev->name, i);
6219 err = request_irq(sp->entries[i].vector,
6220 s2io_msix_fifo_handle, 0, sp->desc[i],
6221 sp->s2io_entries[i].arg);
6222 DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
6223 (unsigned long long)sp->msix_info[i].addr);
6224 } else {
6225 sprintf(sp->desc[i], "%s:MSI-X-%d-RX",
6226 dev->name, i);
6227 err = request_irq(sp->entries[i].vector,
6228 s2io_msix_ring_handle, 0, sp->desc[i],
6229 sp->s2io_entries[i].arg);
6230 DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
6231 (unsigned long long)sp->msix_info[i].addr);
6232 }
6233 if (err) {
6234 DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
6235 "failed\n", dev->name, i);
6236 DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
6237 return -1;
6238 }
6239 sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
6240 }
6241 }
6242 if (sp->intr_type == INTA) {
6243 err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
6244 sp->name, dev);
6245 if (err) {
6246 DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
6247 dev->name);
6248 return -1;
6249 }
6250 }
6251 return 0;
6252}
6253static void s2io_rem_isr(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254{
6255 int cnt = 0;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006256 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006258 if (sp->intr_type == MSI_X) {
6259 int i;
6260 u16 msi_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006262 for (i=1; (sp->s2io_entries[i].in_use ==
6263 MSIX_REGISTERED_SUCCESS); i++) {
6264 int vector = sp->entries[i].vector;
6265 void *arg = sp->s2io_entries[i].arg;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006266
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006267 free_irq(vector, arg);
6268 }
6269 pci_read_config_word(sp->pdev, 0x42, &msi_control);
6270 msi_control &= 0xFFFE; /* Disable MSI */
6271 pci_write_config_word(sp->pdev, 0x42, msi_control);
Ananda Rajuc92ca042006-04-21 19:18:03 -04006272
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006273 pci_disable_msix(sp->pdev);
6274 } else {
6275 free_irq(sp->pdev->irq, dev);
6276 if (sp->intr_type == MSI) {
6277 u16 val;
6278
6279 pci_disable_msi(sp->pdev);
6280 pci_read_config_word(sp->pdev, 0x4c, &val);
6281 val ^= 0x1;
6282 pci_write_config_word(sp->pdev, 0x4c, val);
Ananda Rajuc92ca042006-04-21 19:18:03 -04006283 }
6284 }
6285 /* Waiting till all Interrupt handlers are complete */
6286 cnt = 0;
6287 do {
6288 msleep(10);
6289 if (!atomic_read(&sp->isr_cnt))
6290 break;
6291 cnt++;
6292 } while(cnt < 5);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006293}
6294
6295static void s2io_card_down(nic_t * sp)
6296{
6297 int cnt = 0;
6298 XENA_dev_config_t __iomem *bar0 = sp->bar0;
6299 unsigned long flags;
6300 register u64 val64 = 0;
6301
6302 del_timer_sync(&sp->alarm_timer);
6303 /* If s2io_set_link task is executing, wait till it completes. */
6304 while (test_and_set_bit(0, &(sp->link_state))) {
6305 msleep(50);
6306 }
6307 atomic_set(&sp->card_state, CARD_DOWN);
6308
6309 /* disable Tx and Rx traffic on the NIC */
6310 stop_nic(sp);
6311
6312 s2io_rem_isr(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006313
6314 /* Kill tasklet. */
6315 tasklet_kill(&sp->task);
6316
6317 /* Check if the device is Quiescent and then Reset the NIC */
6318 do {
Ananda Raju5d3213c2006-04-21 19:23:26 -04006319 /* As per the HW requirement we need to replenish the
6320 * receive buffer to avoid the ring bump. Since there is
6321 * no intention of processing the Rx frame at this pointwe are
6322 * just settting the ownership bit of rxd in Each Rx
6323 * ring to HW and set the appropriate buffer size
6324 * based on the ring mode
6325 */
6326 rxd_owner_bit_reset(sp);
6327
Linus Torvalds1da177e2005-04-16 15:20:36 -07006328 val64 = readq(&bar0->adapter_status);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006329 if (verify_xena_quiescence(sp)) {
6330 if(verify_pcc_quiescent(sp, sp->device_enabled_once))
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331 break;
6332 }
6333
6334 msleep(50);
6335 cnt++;
6336 if (cnt == 10) {
6337 DBG_PRINT(ERR_DBG,
6338 "s2io_close:Device not Quiescent ");
6339 DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n",
6340 (unsigned long long) val64);
6341 break;
6342 }
6343 } while (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344 s2io_reset(sp);
6345
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006346 spin_lock_irqsave(&sp->tx_lock, flags);
6347 /* Free all Tx buffers */
6348 free_tx_buffers(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006350
6351 /* Free all Rx buffers */
6352 spin_lock_irqsave(&sp->rx_lock, flags);
6353 free_rx_buffers(sp);
6354 spin_unlock_irqrestore(&sp->rx_lock, flags);
6355
Linus Torvalds1da177e2005-04-16 15:20:36 -07006356 clear_bit(0, &(sp->link_state));
6357}
6358
6359static int s2io_card_up(nic_t * sp)
6360{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006361 int i, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006362 mac_info_t *mac_control;
6363 struct config_param *config;
6364 struct net_device *dev = (struct net_device *) sp->dev;
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006365 u16 interruptible;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006366
6367 /* Initialize the H/W I/O registers */
6368 if (init_nic(sp) != 0) {
6369 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
6370 dev->name);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006371 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372 return -ENODEV;
6373 }
6374
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006375 /*
6376 * Initializing the Rx buffers. For now we are considering only 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377 * Rx ring and initializing buffers into 30 Rx blocks
6378 */
6379 mac_control = &sp->mac_control;
6380 config = &sp->config;
6381
6382 for (i = 0; i < config->rx_ring_num; i++) {
6383 if ((ret = fill_rx_buffers(sp, i))) {
6384 DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
6385 dev->name);
6386 s2io_reset(sp);
6387 free_rx_buffers(sp);
6388 return -ENOMEM;
6389 }
6390 DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
6391 atomic_read(&sp->rx_bufs_left[i]));
6392 }
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006393 /* Maintain the state prior to the open */
6394 if (sp->promisc_flg)
6395 sp->promisc_flg = 0;
6396 if (sp->m_cast_flg) {
6397 sp->m_cast_flg = 0;
6398 sp->all_multi_pos= 0;
6399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006400
6401 /* Setting its receive mode */
6402 s2io_set_multicast(dev);
6403
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006404 if (sp->lro) {
Ananda Rajub41477f2006-07-24 19:52:49 -04006405 /* Initialize max aggregatable pkts per session based on MTU */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006406 sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
6407 /* Check if we can use(if specified) user provided value */
6408 if (lro_max_pkts < sp->lro_max_aggr_per_sess)
6409 sp->lro_max_aggr_per_sess = lro_max_pkts;
6410 }
6411
Linus Torvalds1da177e2005-04-16 15:20:36 -07006412 /* Enable Rx Traffic and interrupts on the NIC */
6413 if (start_nic(sp)) {
6414 DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006415 s2io_reset(sp);
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006416 free_rx_buffers(sp);
6417 return -ENODEV;
6418 }
6419
6420 /* Add interrupt service routine */
6421 if (s2io_add_isr(sp) != 0) {
6422 if (sp->intr_type == MSI_X)
6423 s2io_rem_isr(sp);
6424 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006425 free_rx_buffers(sp);
6426 return -ENODEV;
6427 }
6428
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07006429 S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
6430
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006431 /* Enable tasklet for the device */
6432 tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
6433
6434 /* Enable select interrupts */
6435 if (sp->intr_type != INTA)
6436 en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
6437 else {
6438 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
6439 interruptible |= TX_PIC_INTR | RX_PIC_INTR;
6440 interruptible |= TX_MAC_INTR | RX_MAC_INTR;
6441 en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS);
6442 }
6443
6444
Linus Torvalds1da177e2005-04-16 15:20:36 -07006445 atomic_set(&sp->card_state, CARD_UP);
6446 return 0;
6447}
6448
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006449/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450 * s2io_restart_nic - Resets the NIC.
6451 * @data : long pointer to the device private structure
6452 * Description:
6453 * This function is scheduled to be run by the s2io_tx_watchdog
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006454 * function after 0.5 secs to reset the NIC. The idea is to reduce
Linus Torvalds1da177e2005-04-16 15:20:36 -07006455 * the run time of the watch dog routine which is run holding a
6456 * spin lock.
6457 */
6458
David Howellsc4028952006-11-22 14:57:56 +00006459static void s2io_restart_nic(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006460{
David Howellsc4028952006-11-22 14:57:56 +00006461 nic_t *sp = container_of(work, nic_t, rst_timer_task);
6462 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006463
Ananda Rajue6a8fee2006-07-06 23:58:23 -07006464 s2io_card_down(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006465 if (s2io_card_up(sp)) {
6466 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
6467 dev->name);
6468 }
6469 netif_wake_queue(dev);
6470 DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
6471 dev->name);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006472
Linus Torvalds1da177e2005-04-16 15:20:36 -07006473}
6474
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006475/**
6476 * s2io_tx_watchdog - Watchdog for transmit side.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006477 * @dev : Pointer to net device structure
6478 * Description:
6479 * This function is triggered if the Tx Queue is stopped
6480 * for a pre-defined amount of time when the Interface is still up.
6481 * If the Interface is jammed in such a situation, the hardware is
6482 * reset (by s2io_close) and restarted again (by s2io_open) to
6483 * overcome any problem that might have been caused in the hardware.
6484 * Return value:
6485 * void
6486 */
6487
6488static void s2io_tx_watchdog(struct net_device *dev)
6489{
6490 nic_t *sp = dev->priv;
6491
6492 if (netif_carrier_ok(dev)) {
6493 schedule_work(&sp->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04006494 sp->mac_control.stats_info->sw_stat.soft_reset_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006495 }
6496}
6497
6498/**
6499 * rx_osm_handler - To perform some OS related operations on SKB.
6500 * @sp: private member of the device structure,pointer to s2io_nic structure.
6501 * @skb : the socket buffer pointer.
6502 * @len : length of the packet
6503 * @cksum : FCS checksum of the frame.
6504 * @ring_no : the ring from which this RxD was extracted.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006505 * Description:
Ananda Rajub41477f2006-07-24 19:52:49 -04006506 * This function is called by the Rx interrupt serivce routine to perform
Linus Torvalds1da177e2005-04-16 15:20:36 -07006507 * some OS related operations on the SKB before passing it to the upper
6508 * layers. It mainly checks if the checksum is OK, if so adds it to the
6509 * SKBs cksum variable, increments the Rx packet count and passes the SKB
6510 * to the upper layer. If the checksum is wrong, it increments the Rx
6511 * packet error count, frees the SKB and returns error.
6512 * Return value:
6513 * SUCCESS on success and -1 on failure.
6514 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006515static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006516{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006517 nic_t *sp = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006518 struct net_device *dev = (struct net_device *) sp->dev;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006519 struct sk_buff *skb = (struct sk_buff *)
6520 ((unsigned long) rxdp->Host_Control);
6521 int ring_no = ring_data->ring_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006522 u16 l3_csum, l4_csum;
Ananda Raju863c11a2006-04-21 19:03:13 -04006523 unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006524 lro_t *lro;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006525
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006526 skb->dev = dev;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006527
Ananda Raju863c11a2006-04-21 19:03:13 -04006528 if (err) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04006529 /* Check for parity error */
6530 if (err & 0x1) {
6531 sp->mac_control.stats_info->sw_stat.parity_err_cnt++;
6532 }
6533
Ananda Raju863c11a2006-04-21 19:03:13 -04006534 /*
6535 * Drop the packet if bad transfer code. Exception being
6536 * 0x5, which could be due to unsupported IPv6 extension header.
6537 * In this case, we let stack handle the packet.
6538 * Note that in this case, since checksum will be incorrect,
6539 * stack will validate the same.
6540 */
6541 if (err && ((err >> 48) != 0x5)) {
6542 DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
6543 dev->name, err);
6544 sp->stats.rx_crc_errors++;
6545 dev_kfree_skb(skb);
6546 atomic_dec(&sp->rx_bufs_left[ring_no]);
6547 rxdp->Host_Control = 0;
6548 return 0;
6549 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006550 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006551
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006552 /* Updating statistics */
6553 rxdp->Host_Control = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006554 sp->rx_pkt_count++;
6555 sp->stats.rx_packets++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006556 if (sp->rxd_mode == RXD_MODE_1) {
6557 int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006558
Ananda Rajuda6971d2005-10-31 16:55:31 -05006559 sp->stats.rx_bytes += len;
6560 skb_put(skb, len);
6561
6562 } else if (sp->rxd_mode >= RXD_MODE_3A) {
6563 int get_block = ring_data->rx_curr_get_info.block_index;
6564 int get_off = ring_data->rx_curr_get_info.offset;
6565 int buf0_len = RXD_GET_BUFFER0_SIZE_3(rxdp->Control_2);
6566 int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
6567 unsigned char *buff = skb_push(skb, buf0_len);
6568
6569 buffAdd_t *ba = &ring_data->ba[get_block][get_off];
6570 sp->stats.rx_bytes += buf0_len + buf2_len;
6571 memcpy(buff, ba->ba_0, buf0_len);
6572
6573 if (sp->rxd_mode == RXD_MODE_3A) {
6574 int buf1_len = RXD_GET_BUFFER1_SIZE_3(rxdp->Control_2);
6575
6576 skb_put(skb, buf1_len);
6577 skb->len += buf2_len;
6578 skb->data_len += buf2_len;
6579 skb->truesize += buf2_len;
6580 skb_put(skb_shinfo(skb)->frag_list, buf2_len);
6581 sp->stats.rx_bytes += buf1_len;
6582
6583 } else
6584 skb_put(skb, buf2_len);
6585 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006586
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006587 if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
6588 (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006589 (sp->rx_csum)) {
6590 l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
6591 l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
6592 if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) {
6593 /*
6594 * NIC verifies if the Checksum of the received
6595 * frame is Ok or not and accordingly returns
6596 * a flag in the RxD.
6597 */
6598 skb->ip_summed = CHECKSUM_UNNECESSARY;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006599 if (sp->lro) {
6600 u32 tcp_len;
6601 u8 *tcp;
6602 int ret = 0;
6603
6604 ret = s2io_club_tcp_session(skb->data, &tcp,
6605 &tcp_len, &lro, rxdp, sp);
6606 switch (ret) {
6607 case 3: /* Begin anew */
6608 lro->parent = skb;
6609 goto aggregate;
6610 case 1: /* Aggregate */
6611 {
6612 lro_append_pkt(sp, lro,
6613 skb, tcp_len);
6614 goto aggregate;
6615 }
6616 case 4: /* Flush session */
6617 {
6618 lro_append_pkt(sp, lro,
6619 skb, tcp_len);
6620 queue_rx_frame(lro->parent);
6621 clear_lro_session(lro);
6622 sp->mac_control.stats_info->
6623 sw_stat.flush_max_pkts++;
6624 goto aggregate;
6625 }
6626 case 2: /* Flush both */
6627 lro->parent->data_len =
6628 lro->frags_len;
6629 sp->mac_control.stats_info->
6630 sw_stat.sending_both++;
6631 queue_rx_frame(lro->parent);
6632 clear_lro_session(lro);
6633 goto send_up;
6634 case 0: /* sessions exceeded */
Ananda Rajuc92ca042006-04-21 19:18:03 -04006635 case -1: /* non-TCP or not
6636 * L2 aggregatable
6637 */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006638 case 5: /*
6639 * First pkt in session not
6640 * L3/L4 aggregatable
6641 */
6642 break;
6643 default:
6644 DBG_PRINT(ERR_DBG,
6645 "%s: Samadhana!!\n",
6646 __FUNCTION__);
6647 BUG();
6648 }
6649 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006650 } else {
6651 /*
6652 * Packet with erroneous checksum, let the
6653 * upper layers deal with it.
6654 */
6655 skb->ip_summed = CHECKSUM_NONE;
6656 }
6657 } else {
6658 skb->ip_summed = CHECKSUM_NONE;
6659 }
6660
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006661 if (!sp->lro) {
6662 skb->protocol = eth_type_trans(skb, dev);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006663 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
6664 /* Queueing the vlan frame to the upper layer */
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05006665 if (napi)
6666 vlan_hwaccel_receive_skb(skb, sp->vlgrp,
6667 RXD_GET_VLAN_TAG(rxdp->Control_2));
6668 else
6669 vlan_hwaccel_rx(skb, sp->vlgrp,
6670 RXD_GET_VLAN_TAG(rxdp->Control_2));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006671 } else {
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05006672 if (napi)
6673 netif_receive_skb(skb);
6674 else
6675 netif_rx(skb);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006676 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006677 } else {
6678send_up:
6679 queue_rx_frame(skb);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006680 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006681 dev->last_rx = jiffies;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006682aggregate:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006683 atomic_dec(&sp->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006684 return SUCCESS;
6685}
6686
6687/**
6688 * s2io_link - stops/starts the Tx queue.
6689 * @sp : private member of the device structure, which is a pointer to the
6690 * s2io_nic structure.
6691 * @link : inidicates whether link is UP/DOWN.
6692 * Description:
6693 * This function stops/starts the Tx queue depending on whether the link
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006694 * status of the NIC is is down or up. This is called by the Alarm
6695 * interrupt handler whenever a link change interrupt comes up.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006696 * Return value:
6697 * void.
6698 */
6699
Adrian Bunk26df54b2006-01-14 03:09:40 +01006700static void s2io_link(nic_t * sp, int link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006701{
6702 struct net_device *dev = (struct net_device *) sp->dev;
6703
6704 if (link != sp->last_link_state) {
6705 if (link == LINK_DOWN) {
6706 DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
6707 netif_carrier_off(dev);
6708 } else {
6709 DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
6710 netif_carrier_on(dev);
6711 }
6712 }
6713 sp->last_link_state = link;
6714}
6715
6716/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006717 * get_xena_rev_id - to identify revision ID of xena.
6718 * @pdev : PCI Dev structure
6719 * Description:
6720 * Function to identify the Revision ID of xena.
6721 * Return value:
6722 * returns the revision ID of the device.
6723 */
6724
Adrian Bunk26df54b2006-01-14 03:09:40 +01006725static int get_xena_rev_id(struct pci_dev *pdev)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006726{
6727 u8 id = 0;
6728 int ret;
6729 ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id);
6730 return id;
6731}
6732
6733/**
6734 * s2io_init_pci -Initialization of PCI and PCI-X configuration registers .
6735 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07006736 * s2io_nic structure.
6737 * Description:
6738 * This function initializes a few of the PCI and PCI-X configuration registers
6739 * with recommended values.
6740 * Return value:
6741 * void
6742 */
6743
6744static void s2io_init_pci(nic_t * sp)
6745{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006746 u16 pci_cmd = 0, pcix_cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747
6748 /* Enable Data Parity Error Recovery in PCI-X command register. */
6749 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006750 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006751 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006752 (pcix_cmd | 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006753 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006754 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006755
6756 /* Set the PErr Response bit in PCI command register. */
6757 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
6758 pci_write_config_word(sp->pdev, PCI_COMMAND,
6759 (pci_cmd | PCI_COMMAND_PARITY));
6760 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006761}
6762
Ananda Raju9dc737a2006-04-21 19:05:41 -04006763static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
6764{
6765 if ( tx_fifo_num > 8) {
6766 DBG_PRINT(ERR_DBG, "s2io: Requested number of Tx fifos not "
6767 "supported\n");
6768 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Tx fifos\n");
6769 tx_fifo_num = 8;
6770 }
6771 if ( rx_ring_num > 8) {
6772 DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
6773 "supported\n");
6774 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
6775 rx_ring_num = 8;
6776 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05006777 if (*dev_intr_type != INTA)
6778 napi = 0;
6779
Ananda Raju9dc737a2006-04-21 19:05:41 -04006780#ifndef CONFIG_PCI_MSI
6781 if (*dev_intr_type != INTA) {
6782 DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
6783 "MSI/MSI-X. Defaulting to INTA\n");
6784 *dev_intr_type = INTA;
6785 }
6786#else
6787 if (*dev_intr_type > MSI_X) {
6788 DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
6789 "Defaulting to INTA\n");
6790 *dev_intr_type = INTA;
6791 }
6792#endif
6793 if ((*dev_intr_type == MSI_X) &&
6794 ((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
6795 (pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006796 DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. "
Ananda Raju9dc737a2006-04-21 19:05:41 -04006797 "Defaulting to INTA\n");
6798 *dev_intr_type = INTA;
6799 }
6800 if (rx_ring_mode > 3) {
6801 DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
6802 DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
6803 rx_ring_mode = 3;
6804 }
6805 return SUCCESS;
6806}
6807
Linus Torvalds1da177e2005-04-16 15:20:36 -07006808/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006809 * s2io_init_nic - Initialization of the adapter .
Linus Torvalds1da177e2005-04-16 15:20:36 -07006810 * @pdev : structure containing the PCI related information of the device.
6811 * @pre: List of PCI devices supported by the driver listed in s2io_tbl.
6812 * Description:
6813 * The function initializes an adapter identified by the pci_dec structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006814 * All OS related initialization including memory and device structure and
6815 * initlaization of the device private variable is done. Also the swapper
6816 * control register is initialized to enable read and write into the I/O
Linus Torvalds1da177e2005-04-16 15:20:36 -07006817 * registers of the device.
6818 * Return value:
6819 * returns 0 on success and negative on failure.
6820 */
6821
6822static int __devinit
6823s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
6824{
6825 nic_t *sp;
6826 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006827 int i, j, ret;
6828 int dma_flag = FALSE;
6829 u32 mac_up, mac_down;
6830 u64 val64 = 0, tmp64 = 0;
6831 XENA_dev_config_t __iomem *bar0 = NULL;
6832 u16 subid;
6833 mac_info_t *mac_control;
6834 struct config_param *config;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006835 int mode;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006836 u8 dev_intr_type = intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006837
Ananda Raju9dc737a2006-04-21 19:05:41 -04006838 if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
6839 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006840
6841 if ((ret = pci_enable_device(pdev))) {
6842 DBG_PRINT(ERR_DBG,
6843 "s2io_init_nic: pci_enable_device failed\n");
6844 return ret;
6845 }
6846
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006847 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006848 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
6849 dma_flag = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006850 if (pci_set_consistent_dma_mask
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006851 (pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006852 DBG_PRINT(ERR_DBG,
6853 "Unable to obtain 64bit DMA for \
6854 consistent allocations\n");
6855 pci_disable_device(pdev);
6856 return -ENOMEM;
6857 }
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006858 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006859 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n");
6860 } else {
6861 pci_disable_device(pdev);
6862 return -ENOMEM;
6863 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006864 if (dev_intr_type != MSI_X) {
6865 if (pci_request_regions(pdev, s2io_driver_name)) {
Ananda Rajub41477f2006-07-24 19:52:49 -04006866 DBG_PRINT(ERR_DBG, "Request Regions failed\n");
6867 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006868 return -ENODEV;
6869 }
6870 }
6871 else {
6872 if (!(request_mem_region(pci_resource_start(pdev, 0),
6873 pci_resource_len(pdev, 0), s2io_driver_name))) {
6874 DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n");
6875 pci_disable_device(pdev);
6876 return -ENODEV;
6877 }
6878 if (!(request_mem_region(pci_resource_start(pdev, 2),
6879 pci_resource_len(pdev, 2), s2io_driver_name))) {
6880 DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n");
6881 release_mem_region(pci_resource_start(pdev, 0),
6882 pci_resource_len(pdev, 0));
6883 pci_disable_device(pdev);
6884 return -ENODEV;
6885 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006886 }
6887
6888 dev = alloc_etherdev(sizeof(nic_t));
6889 if (dev == NULL) {
6890 DBG_PRINT(ERR_DBG, "Device allocation failed\n");
6891 pci_disable_device(pdev);
6892 pci_release_regions(pdev);
6893 return -ENODEV;
6894 }
6895
6896 pci_set_master(pdev);
6897 pci_set_drvdata(pdev, dev);
6898 SET_MODULE_OWNER(dev);
6899 SET_NETDEV_DEV(dev, &pdev->dev);
6900
6901 /* Private member variable initialized to s2io NIC structure */
6902 sp = dev->priv;
6903 memset(sp, 0, sizeof(nic_t));
6904 sp->dev = dev;
6905 sp->pdev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006906 sp->high_dma_flag = dma_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006907 sp->device_enabled_once = FALSE;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006908 if (rx_ring_mode == 1)
6909 sp->rxd_mode = RXD_MODE_1;
6910 if (rx_ring_mode == 2)
6911 sp->rxd_mode = RXD_MODE_3B;
6912 if (rx_ring_mode == 3)
6913 sp->rxd_mode = RXD_MODE_3A;
6914
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006915 sp->intr_type = dev_intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006916
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006917 if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
6918 (pdev->device == PCI_DEVICE_ID_HERC_UNI))
6919 sp->device_type = XFRAME_II_DEVICE;
6920 else
6921 sp->device_type = XFRAME_I_DEVICE;
6922
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006923 sp->lro = lro;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006924
Linus Torvalds1da177e2005-04-16 15:20:36 -07006925 /* Initialize some PCI/PCI-X fields of the NIC. */
6926 s2io_init_pci(sp);
6927
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006928 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006929 * Setting the device configuration parameters.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006930 * Most of these parameters can be specified by the user during
6931 * module insertion as they are module loadable parameters. If
6932 * these parameters are not not specified during load time, they
Linus Torvalds1da177e2005-04-16 15:20:36 -07006933 * are initialized with default values.
6934 */
6935 mac_control = &sp->mac_control;
6936 config = &sp->config;
6937
6938 /* Tx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006939 config->tx_fifo_num = tx_fifo_num;
6940 for (i = 0; i < MAX_TX_FIFOS; i++) {
6941 config->tx_cfg[i].fifo_len = tx_fifo_len[i];
6942 config->tx_cfg[i].fifo_priority = i;
6943 }
6944
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006945 /* mapping the QoS priority to the configured fifos */
6946 for (i = 0; i < MAX_TX_FIFOS; i++)
6947 config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i];
6948
Linus Torvalds1da177e2005-04-16 15:20:36 -07006949 config->tx_intr_type = TXD_INT_TYPE_UTILZ;
6950 for (i = 0; i < config->tx_fifo_num; i++) {
6951 config->tx_cfg[i].f_no_snoop =
6952 (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER);
6953 if (config->tx_cfg[i].fifo_len < 65) {
6954 config->tx_intr_type = TXD_INT_TYPE_PER_LIST;
6955 break;
6956 }
6957 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05006958 /* + 2 because one Txd for skb->data and one Txd for UFO */
6959 config->max_txds = MAX_SKB_FRAGS + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006960
6961 /* Rx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006962 config->rx_ring_num = rx_ring_num;
6963 for (i = 0; i < MAX_RX_RINGS; i++) {
6964 config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
Ananda Rajuda6971d2005-10-31 16:55:31 -05006965 (rxd_count[sp->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006966 config->rx_cfg[i].ring_priority = i;
6967 }
6968
6969 for (i = 0; i < rx_ring_num; i++) {
6970 config->rx_cfg[i].ring_org = RING_ORG_BUFF1;
6971 config->rx_cfg[i].f_no_snoop =
6972 (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER);
6973 }
6974
6975 /* Setting Mac Control parameters */
6976 mac_control->rmac_pause_time = rmac_pause_time;
6977 mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3;
6978 mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
6979
6980
6981 /* Initialize Ring buffer parameters. */
6982 for (i = 0; i < config->rx_ring_num; i++)
6983 atomic_set(&sp->rx_bufs_left[i], 0);
6984
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006985 /* Initialize the number of ISRs currently running */
6986 atomic_set(&sp->isr_cnt, 0);
6987
Linus Torvalds1da177e2005-04-16 15:20:36 -07006988 /* initialize the shared memory used by the NIC and the host */
6989 if (init_shared_mem(sp)) {
6990 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
Ananda Rajub41477f2006-07-24 19:52:49 -04006991 dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006992 ret = -ENOMEM;
6993 goto mem_alloc_failed;
6994 }
6995
6996 sp->bar0 = ioremap(pci_resource_start(pdev, 0),
6997 pci_resource_len(pdev, 0));
6998 if (!sp->bar0) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05006999 DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007000 dev->name);
7001 ret = -ENOMEM;
7002 goto bar0_remap_failed;
7003 }
7004
7005 sp->bar1 = ioremap(pci_resource_start(pdev, 2),
7006 pci_resource_len(pdev, 2));
7007 if (!sp->bar1) {
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007008 DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007009 dev->name);
7010 ret = -ENOMEM;
7011 goto bar1_remap_failed;
7012 }
7013
7014 dev->irq = pdev->irq;
7015 dev->base_addr = (unsigned long) sp->bar0;
7016
7017 /* Initializing the BAR1 address as the start of the FIFO pointer. */
7018 for (j = 0; j < MAX_TX_FIFOS; j++) {
7019 mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *)
7020 (sp->bar1 + (j * 0x00020000));
7021 }
7022
7023 /* Driver entry points */
7024 dev->open = &s2io_open;
7025 dev->stop = &s2io_close;
7026 dev->hard_start_xmit = &s2io_xmit;
7027 dev->get_stats = &s2io_get_stats;
7028 dev->set_multicast_list = &s2io_set_multicast;
7029 dev->do_ioctl = &s2io_ioctl;
7030 dev->change_mtu = &s2io_change_mtu;
7031 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07007032 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
7033 dev->vlan_rx_register = s2io_vlan_rx_register;
7034 dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007035
Linus Torvalds1da177e2005-04-16 15:20:36 -07007036 /*
7037 * will use eth_mac_addr() for dev->set_mac_address
7038 * mac address will be set every time dev->open() is called
7039 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007040 dev->poll = s2io_poll;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007041 dev->weight = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007042
Brian Haley612eff02006-06-15 14:36:36 -04007043#ifdef CONFIG_NET_POLL_CONTROLLER
7044 dev->poll_controller = s2io_netpoll;
7045#endif
7046
Linus Torvalds1da177e2005-04-16 15:20:36 -07007047 dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
7048 if (sp->high_dma_flag == TRUE)
7049 dev->features |= NETIF_F_HIGHDMA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007050 dev->features |= NETIF_F_TSO;
Herbert Xuf83ef8c2006-06-30 13:37:03 -07007051 dev->features |= NETIF_F_TSO6;
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007052 if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05007053 dev->features |= NETIF_F_UFO;
7054 dev->features |= NETIF_F_HW_CSUM;
7055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007056
7057 dev->tx_timeout = &s2io_tx_watchdog;
7058 dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
David Howellsc4028952006-11-22 14:57:56 +00007059 INIT_WORK(&sp->rst_timer_task, s2io_restart_nic);
7060 INIT_WORK(&sp->set_link_task, s2io_set_link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007061
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07007062 pci_save_state(sp->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007063
7064 /* Setting swapper control on the NIC, for proper reset operation */
7065 if (s2io_set_swapper(sp)) {
7066 DBG_PRINT(ERR_DBG, "%s:swapper settings are wrong\n",
7067 dev->name);
7068 ret = -EAGAIN;
7069 goto set_swap_failed;
7070 }
7071
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007072 /* Verify if the Herc works on the slot its placed into */
7073 if (sp->device_type & XFRAME_II_DEVICE) {
7074 mode = s2io_verify_pci_mode(sp);
7075 if (mode < 0) {
7076 DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__);
7077 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
7078 ret = -EBADSLT;
7079 goto set_swap_failed;
7080 }
7081 }
7082
7083 /* Not needed for Herc */
7084 if (sp->device_type & XFRAME_I_DEVICE) {
7085 /*
7086 * Fix for all "FFs" MAC address problems observed on
7087 * Alpha platforms
7088 */
7089 fix_mac_address(sp);
7090 s2io_reset(sp);
7091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007092
7093 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007094 * MAC address initialization.
7095 * For now only one mac address will be read and used.
7096 */
7097 bar0 = sp->bar0;
7098 val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
7099 RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
7100 writeq(val64, &bar0->rmac_addr_cmd_mem);
Ananda Rajuc92ca042006-04-21 19:18:03 -04007101 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
7102 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007103 tmp64 = readq(&bar0->rmac_addr_data0_mem);
7104 mac_down = (u32) tmp64;
7105 mac_up = (u32) (tmp64 >> 32);
7106
7107 memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
7108
7109 sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up);
7110 sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8);
7111 sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16);
7112 sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_up >> 24);
7113 sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16);
7114 sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24);
7115
Linus Torvalds1da177e2005-04-16 15:20:36 -07007116 /* Set the factory defined MAC address initially */
7117 dev->addr_len = ETH_ALEN;
7118 memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
7119
Ananda Rajub41477f2006-07-24 19:52:49 -04007120 /* reset Nic and bring it to known state */
7121 s2io_reset(sp);
7122
Linus Torvalds1da177e2005-04-16 15:20:36 -07007123 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007124 * Initialize the tasklet status and link state flags
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007125 * and the card state parameter
Linus Torvalds1da177e2005-04-16 15:20:36 -07007126 */
7127 atomic_set(&(sp->card_state), 0);
7128 sp->tasklet_status = 0;
7129 sp->link_state = 0;
7130
Linus Torvalds1da177e2005-04-16 15:20:36 -07007131 /* Initialize spinlocks */
7132 spin_lock_init(&sp->tx_lock);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007133
7134 if (!napi)
7135 spin_lock_init(&sp->put_lock);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007136 spin_lock_init(&sp->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007137
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007138 /*
7139 * SXE-002: Configure link and activity LED to init state
7140 * on driver load.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007141 */
7142 subid = sp->pdev->subsystem_device;
7143 if ((subid & 0xFF) >= 0x07) {
7144 val64 = readq(&bar0->gpio_control);
7145 val64 |= 0x0000800000000000ULL;
7146 writeq(val64, &bar0->gpio_control);
7147 val64 = 0x0411040400000000ULL;
7148 writeq(val64, (void __iomem *) bar0 + 0x2700);
7149 val64 = readq(&bar0->gpio_control);
7150 }
7151
7152 sp->rx_csum = 1; /* Rx chksum verify enabled by default */
7153
7154 if (register_netdev(dev)) {
7155 DBG_PRINT(ERR_DBG, "Device registration failed\n");
7156 ret = -ENODEV;
7157 goto register_failed;
7158 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04007159 s2io_vpd_read(sp);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007160 DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n");
Ananda Rajub41477f2006-07-24 19:52:49 -04007161 DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name,
7162 sp->product_name, get_xena_rev_id(sp->pdev));
7163 DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
7164 s2io_driver_version);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007165 DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007166 "%02x:%02x:%02x:%02x:%02x:%02x", dev->name,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007167 sp->def_mac_addr[0].mac_addr[0],
7168 sp->def_mac_addr[0].mac_addr[1],
7169 sp->def_mac_addr[0].mac_addr[2],
7170 sp->def_mac_addr[0].mac_addr[3],
7171 sp->def_mac_addr[0].mac_addr[4],
7172 sp->def_mac_addr[0].mac_addr[5]);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007173 DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007174 if (sp->device_type & XFRAME_II_DEVICE) {
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07007175 mode = s2io_print_pci_mode(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007176 if (mode < 0) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04007177 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007178 ret = -EBADSLT;
Ananda Raju9dc737a2006-04-21 19:05:41 -04007179 unregister_netdev(dev);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007180 goto set_swap_failed;
7181 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007182 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04007183 switch(sp->rxd_mode) {
7184 case RXD_MODE_1:
7185 DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n",
7186 dev->name);
7187 break;
7188 case RXD_MODE_3B:
7189 DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n",
7190 dev->name);
7191 break;
7192 case RXD_MODE_3A:
7193 DBG_PRINT(ERR_DBG, "%s: 3-Buffer receive mode enabled\n",
7194 dev->name);
7195 break;
7196 }
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007197
7198 if (napi)
7199 DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007200 switch(sp->intr_type) {
7201 case INTA:
7202 DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
7203 break;
7204 case MSI:
7205 DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI\n", dev->name);
7206 break;
7207 case MSI_X:
7208 DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
7209 break;
7210 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007211 if (sp->lro)
7212 DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
Ananda Raju9dc737a2006-04-21 19:05:41 -04007213 dev->name);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007214 if (ufo)
7215 DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)"
7216 " enabled\n", dev->name);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007217 /* Initialize device name */
Ananda Raju9dc737a2006-04-21 19:05:41 -04007218 sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007219
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07007220 /* Initialize bimodal Interrupts */
7221 sp->config.bimodal = bimodal;
7222 if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) {
7223 sp->config.bimodal = 0;
7224 DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n",
7225 dev->name);
7226 }
7227
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007228 /*
7229 * Make Link state as off at this point, when the Link change
7230 * interrupt comes the state will be automatically changed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07007231 * the right state.
7232 */
7233 netif_carrier_off(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007234
7235 return 0;
7236
7237 register_failed:
7238 set_swap_failed:
7239 iounmap(sp->bar1);
7240 bar1_remap_failed:
7241 iounmap(sp->bar0);
7242 bar0_remap_failed:
7243 mem_alloc_failed:
7244 free_shared_mem(sp);
7245 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007246 if (dev_intr_type != MSI_X)
7247 pci_release_regions(pdev);
7248 else {
7249 release_mem_region(pci_resource_start(pdev, 0),
7250 pci_resource_len(pdev, 0));
7251 release_mem_region(pci_resource_start(pdev, 2),
7252 pci_resource_len(pdev, 2));
7253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007254 pci_set_drvdata(pdev, NULL);
7255 free_netdev(dev);
7256
7257 return ret;
7258}
7259
7260/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007261 * s2io_rem_nic - Free the PCI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07007262 * @pdev: structure containing the PCI related information of the device.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007263 * Description: This function is called by the Pci subsystem to release a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007264 * PCI device and free up all resource held up by the device. This could
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007265 * be in response to a Hot plug event or when the driver is to be removed
Linus Torvalds1da177e2005-04-16 15:20:36 -07007266 * from memory.
7267 */
7268
7269static void __devexit s2io_rem_nic(struct pci_dev *pdev)
7270{
7271 struct net_device *dev =
7272 (struct net_device *) pci_get_drvdata(pdev);
7273 nic_t *sp;
7274
7275 if (dev == NULL) {
7276 DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
7277 return;
7278 }
7279
7280 sp = dev->priv;
7281 unregister_netdev(dev);
7282
7283 free_shared_mem(sp);
7284 iounmap(sp->bar0);
7285 iounmap(sp->bar1);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007286 if (sp->intr_type != MSI_X)
7287 pci_release_regions(pdev);
7288 else {
7289 release_mem_region(pci_resource_start(pdev, 0),
7290 pci_resource_len(pdev, 0));
7291 release_mem_region(pci_resource_start(pdev, 2),
7292 pci_resource_len(pdev, 2));
7293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007294 pci_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007295 free_netdev(dev);
Sivakumar Subramani19a60522007-01-31 13:30:49 -05007296 pci_disable_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007297}
7298
7299/**
7300 * s2io_starter - Entry point for the driver
7301 * Description: This function is the entry point for the driver. It verifies
7302 * the module loadable parameters and initializes PCI configuration space.
7303 */
7304
7305int __init s2io_starter(void)
7306{
Jeff Garzik29917622006-08-19 17:48:59 -04007307 return pci_register_driver(&s2io_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007308}
7309
7310/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007311 * s2io_closer - Cleanup routine for the driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07007312 * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
7313 */
7314
Adrian Bunk26df54b2006-01-14 03:09:40 +01007315static void s2io_closer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007316{
7317 pci_unregister_driver(&s2io_driver);
7318 DBG_PRINT(INIT_DBG, "cleanup done\n");
7319}
7320
7321module_init(s2io_starter);
7322module_exit(s2io_closer);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007323
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007324static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007325 struct tcphdr **tcp, RxD_t *rxdp)
7326{
7327 int ip_off;
7328 u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
7329
7330 if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) {
7331 DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n",
7332 __FUNCTION__);
7333 return -1;
7334 }
7335
7336 /* TODO:
7337 * By default the VLAN field in the MAC is stripped by the card, if this
7338 * feature is turned off in rx_pa_cfg register, then the ip_off field
7339 * has to be shifted by a further 2 bytes
7340 */
7341 switch (l2_type) {
7342 case 0: /* DIX type */
7343 case 4: /* DIX type with VLAN */
7344 ip_off = HEADER_ETHERNET_II_802_3_SIZE;
7345 break;
7346 /* LLC, SNAP etc are considered non-mergeable */
7347 default:
7348 return -1;
7349 }
7350
7351 *ip = (struct iphdr *)((u8 *)buffer + ip_off);
7352 ip_len = (u8)((*ip)->ihl);
7353 ip_len <<= 2;
7354 *tcp = (struct tcphdr *)((unsigned long)*ip + ip_len);
7355
7356 return 0;
7357}
7358
7359static int check_for_socket_match(lro_t *lro, struct iphdr *ip,
7360 struct tcphdr *tcp)
7361{
7362 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7363 if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) ||
7364 (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest))
7365 return -1;
7366 return 0;
7367}
7368
7369static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
7370{
7371 return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
7372}
7373
7374static void initiate_new_session(lro_t *lro, u8 *l2h,
7375 struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
7376{
7377 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7378 lro->l2h = l2h;
7379 lro->iph = ip;
7380 lro->tcph = tcp;
7381 lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq);
7382 lro->tcp_ack = ntohl(tcp->ack_seq);
7383 lro->sg_num = 1;
7384 lro->total_len = ntohs(ip->tot_len);
7385 lro->frags_len = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007386 /*
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007387 * check if we saw TCP timestamp. Other consistency checks have
7388 * already been done.
7389 */
7390 if (tcp->doff == 8) {
7391 u32 *ptr;
7392 ptr = (u32 *)(tcp+1);
7393 lro->saw_ts = 1;
7394 lro->cur_tsval = *(ptr+1);
7395 lro->cur_tsecr = *(ptr+2);
7396 }
7397 lro->in_use = 1;
7398}
7399
7400static void update_L3L4_header(nic_t *sp, lro_t *lro)
7401{
7402 struct iphdr *ip = lro->iph;
7403 struct tcphdr *tcp = lro->tcph;
7404 u16 nchk;
7405 StatInfo_t *statinfo = sp->mac_control.stats_info;
7406 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7407
7408 /* Update L3 header */
7409 ip->tot_len = htons(lro->total_len);
7410 ip->check = 0;
7411 nchk = ip_fast_csum((u8 *)lro->iph, ip->ihl);
7412 ip->check = nchk;
7413
7414 /* Update L4 header */
7415 tcp->ack_seq = lro->tcp_ack;
7416 tcp->window = lro->window;
7417
7418 /* Update tsecr field if this session has timestamps enabled */
7419 if (lro->saw_ts) {
7420 u32 *ptr = (u32 *)(tcp + 1);
7421 *(ptr+2) = lro->cur_tsecr;
7422 }
7423
7424 /* Update counters required for calculation of
7425 * average no. of packets aggregated.
7426 */
7427 statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num;
7428 statinfo->sw_stat.num_aggregations++;
7429}
7430
7431static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
7432 struct tcphdr *tcp, u32 l4_pyld)
7433{
7434 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7435 lro->total_len += l4_pyld;
7436 lro->frags_len += l4_pyld;
7437 lro->tcp_next_seq += l4_pyld;
7438 lro->sg_num++;
7439
7440 /* Update ack seq no. and window ad(from this pkt) in LRO object */
7441 lro->tcp_ack = tcp->ack_seq;
7442 lro->window = tcp->window;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007443
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007444 if (lro->saw_ts) {
7445 u32 *ptr;
7446 /* Update tsecr and tsval from this packet */
7447 ptr = (u32 *) (tcp + 1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007448 lro->cur_tsval = *(ptr + 1);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007449 lro->cur_tsecr = *(ptr + 2);
7450 }
7451}
7452
7453static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
7454 struct tcphdr *tcp, u32 tcp_pyld_len)
7455{
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007456 u8 *ptr;
7457
Andrew Morton79dc1902006-02-03 01:45:13 -08007458 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7459
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007460 if (!tcp_pyld_len) {
7461 /* Runt frame or a pure ack */
7462 return -1;
7463 }
7464
7465 if (ip->ihl != 5) /* IP has options */
7466 return -1;
7467
Ananda Raju75c30b12006-07-24 19:55:09 -04007468 /* If we see CE codepoint in IP header, packet is not mergeable */
7469 if (INET_ECN_is_ce(ipv4_get_dsfield(ip)))
7470 return -1;
7471
7472 /* If we see ECE or CWR flags in TCP header, packet is not mergeable */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007473 if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin ||
Ananda Raju75c30b12006-07-24 19:55:09 -04007474 tcp->ece || tcp->cwr || !tcp->ack) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007475 /*
7476 * Currently recognize only the ack control word and
7477 * any other control field being set would result in
7478 * flushing the LRO session
7479 */
7480 return -1;
7481 }
7482
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007483 /*
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007484 * Allow only one TCP timestamp option. Don't aggregate if
7485 * any other options are detected.
7486 */
7487 if (tcp->doff != 5 && tcp->doff != 8)
7488 return -1;
7489
7490 if (tcp->doff == 8) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007491 ptr = (u8 *)(tcp + 1);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007492 while (*ptr == TCPOPT_NOP)
7493 ptr++;
7494 if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP)
7495 return -1;
7496
7497 /* Ensure timestamp value increases monotonically */
7498 if (l_lro)
7499 if (l_lro->cur_tsval > *((u32 *)(ptr+2)))
7500 return -1;
7501
7502 /* timestamp echo reply should be non-zero */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007503 if (*((u32 *)(ptr+6)) == 0)
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007504 return -1;
7505 }
7506
7507 return 0;
7508}
7509
7510static int
7511s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
7512 RxD_t *rxdp, nic_t *sp)
7513{
7514 struct iphdr *ip;
7515 struct tcphdr *tcph;
7516 int ret = 0, i;
7517
7518 if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp,
7519 rxdp))) {
7520 DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n",
7521 ip->saddr, ip->daddr);
7522 } else {
7523 return ret;
7524 }
7525
7526 tcph = (struct tcphdr *)*tcp;
7527 *tcp_len = get_l4_pyld_length(ip, tcph);
7528 for (i=0; i<MAX_LRO_SESSIONS; i++) {
7529 lro_t *l_lro = &sp->lro0_n[i];
7530 if (l_lro->in_use) {
7531 if (check_for_socket_match(l_lro, ip, tcph))
7532 continue;
7533 /* Sock pair matched */
7534 *lro = l_lro;
7535
7536 if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) {
7537 DBG_PRINT(INFO_DBG, "%s:Out of order. expected "
7538 "0x%x, actual 0x%x\n", __FUNCTION__,
7539 (*lro)->tcp_next_seq,
7540 ntohl(tcph->seq));
7541
7542 sp->mac_control.stats_info->
7543 sw_stat.outof_sequence_pkts++;
7544 ret = 2;
7545 break;
7546 }
7547
7548 if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len))
7549 ret = 1; /* Aggregate */
7550 else
7551 ret = 2; /* Flush both */
7552 break;
7553 }
7554 }
7555
7556 if (ret == 0) {
7557 /* Before searching for available LRO objects,
7558 * check if the pkt is L3/L4 aggregatable. If not
7559 * don't create new LRO session. Just send this
7560 * packet up.
7561 */
7562 if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) {
7563 return 5;
7564 }
7565
7566 for (i=0; i<MAX_LRO_SESSIONS; i++) {
7567 lro_t *l_lro = &sp->lro0_n[i];
7568 if (!(l_lro->in_use)) {
7569 *lro = l_lro;
7570 ret = 3; /* Begin anew */
7571 break;
7572 }
7573 }
7574 }
7575
7576 if (ret == 0) { /* sessions exceeded */
7577 DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n",
7578 __FUNCTION__);
7579 *lro = NULL;
7580 return ret;
7581 }
7582
7583 switch (ret) {
7584 case 3:
7585 initiate_new_session(*lro, buffer, ip, tcph, *tcp_len);
7586 break;
7587 case 2:
7588 update_L3L4_header(sp, *lro);
7589 break;
7590 case 1:
7591 aggregate_new_rx(*lro, ip, tcph, *tcp_len);
7592 if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) {
7593 update_L3L4_header(sp, *lro);
7594 ret = 4; /* Flush the LRO */
7595 }
7596 break;
7597 default:
7598 DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n",
7599 __FUNCTION__);
7600 break;
7601 }
7602
7603 return ret;
7604}
7605
7606static void clear_lro_session(lro_t *lro)
7607{
7608 static u16 lro_struct_size = sizeof(lro_t);
7609
7610 memset(lro, 0, lro_struct_size);
7611}
7612
7613static void queue_rx_frame(struct sk_buff *skb)
7614{
7615 struct net_device *dev = skb->dev;
7616
7617 skb->protocol = eth_type_trans(skb, dev);
Sivakumar Subramanidb874e62007-01-31 13:28:08 -05007618 if (napi)
7619 netif_receive_skb(skb);
7620 else
7621 netif_rx(skb);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007622}
7623
7624static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
7625 u32 tcp_len)
7626{
Ananda Raju75c30b12006-07-24 19:55:09 -04007627 struct sk_buff *first = lro->parent;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007628
7629 first->len += tcp_len;
7630 first->data_len = lro->frags_len;
7631 skb_pull(skb, (skb->len - tcp_len));
Ananda Raju75c30b12006-07-24 19:55:09 -04007632 if (skb_shinfo(first)->frag_list)
7633 lro->last_frag->next = skb;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007634 else
7635 skb_shinfo(first)->frag_list = skb;
Ananda Raju75c30b12006-07-24 19:55:09 -04007636 lro->last_frag = skb;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007637 sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
7638 return;
7639}