blob: cac9fdd2e1d5bd1b6653ccac639c62865dc6565a [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
47#include <linux/config.h>
48#include <linux/module.h>
49#include <linux/types.h>
50#include <linux/errno.h>
51#include <linux/ioport.h>
52#include <linux/pci.h>
Domen Puncer1e7f0bd2005-06-26 18:22:14 -040053#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <linux/kernel.h>
55#include <linux/netdevice.h>
56#include <linux/etherdevice.h>
57#include <linux/skbuff.h>
58#include <linux/init.h>
59#include <linux/delay.h>
60#include <linux/stddef.h>
61#include <linux/ioctl.h>
62#include <linux/timex.h>
63#include <linux/sched.h>
64#include <linux/ethtool.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#include <linux/workqueue.h>
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -070066#include <linux/if_vlan.h>
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -050067#include <linux/ip.h>
68#include <linux/tcp.h>
69#include <net/tcp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#include <asm/system.h>
72#include <asm/uaccess.h>
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -070073#include <asm/io.h>
Andrew Mortonfe931392006-02-03 01:45:12 -080074#include <asm/div64.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
76/* local include */
77#include "s2io.h"
78#include "s2io-regs.h"
79
Ananda Raju5d3213c2006-04-21 19:23:26 -040080#define DRV_VERSION "2.0.14.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
374/* Module Loadable parameters. */
375static unsigned int tx_fifo_num = 1;
376static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
Ananda Raju9dc737a2006-04-21 19:05:41 -0400377 {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378static unsigned int rx_ring_num = 1;
379static unsigned int rx_ring_sz[MAX_RX_RINGS] =
Ananda Raju9dc737a2006-04-21 19:05:41 -0400380 {[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT};
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700381static unsigned int rts_frm_len[MAX_RX_RINGS] =
382 {[0 ...(MAX_RX_RINGS - 1)] = 0 };
Ananda Rajuda6971d2005-10-31 16:55:31 -0500383static unsigned int rx_ring_mode = 1;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700384static unsigned int use_continuous_tx_intrs = 1;
Ananda Raju863c11a2006-04-21 19:03:13 -0400385static unsigned int rmac_pause_time = 0x100;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386static unsigned int mc_pause_threshold_q0q3 = 187;
387static unsigned int mc_pause_threshold_q4q7 = 187;
388static unsigned int shared_splits;
389static unsigned int tmac_util_period = 5;
390static unsigned int rmac_util_period = 5;
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -0700391static unsigned int bimodal = 0;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500392static unsigned int l3l4hdr_size = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393#ifndef CONFIG_S2IO_NAPI
394static unsigned int indicate_max_pkts;
395#endif
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -0700396/* Frequency of Rx desc syncs expressed as power of 2 */
397static unsigned int rxsync_frequency = 3;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -0400398/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */
399static unsigned int intr_type = 0;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -0500400/* Large receive offload feature */
401static unsigned int lro = 0;
402/* Max pkts to be aggregated by LRO at one time. If not specified,
403 * aggregation happens until we hit max IP pkt size(64K)
404 */
405static unsigned int lro_max_pkts = 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700407/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 * S2IO device table.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700409 * This table lists all the devices that this driver supports.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 */
411static struct pci_device_id s2io_tbl[] __devinitdata = {
412 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN,
413 PCI_ANY_ID, PCI_ANY_ID},
414 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI,
415 PCI_ANY_ID, PCI_ANY_ID},
416 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700417 PCI_ANY_ID, PCI_ANY_ID},
418 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI,
419 PCI_ANY_ID, PCI_ANY_ID},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 {0,}
421};
422
423MODULE_DEVICE_TABLE(pci, s2io_tbl);
424
425static struct pci_driver s2io_driver = {
426 .name = "S2IO",
427 .id_table = s2io_tbl,
428 .probe = s2io_init_nic,
429 .remove = __devexit_p(s2io_rem_nic),
430};
431
432/* A simplifier macro used both by init and free shared_mem Fns(). */
433#define TXD_MEM_PAGE_CNT(len, per_each) ((len+per_each - 1) / per_each)
434
435/**
436 * init_shared_mem - Allocation and Initialization of Memory
437 * @nic: Device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700438 * Description: The function allocates all the memory areas shared
439 * between the NIC and the driver. This includes Tx descriptors,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 * Rx descriptors and the statistics block.
441 */
442
443static int init_shared_mem(struct s2io_nic *nic)
444{
445 u32 size;
446 void *tmp_v_addr, *tmp_v_addr_next;
447 dma_addr_t tmp_p_addr, tmp_p_addr_next;
448 RxD_block_t *pre_rxd_blk = NULL;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700449 int i, j, blk_cnt, rx_sz, tx_sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 int lst_size, lst_per_page;
451 struct net_device *dev = nic->dev;
viro@zenIV.linux.org.uk8ae418c2005-09-02 20:15:29 +0100452 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 buffAdd_t *ba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455 mac_info_t *mac_control;
456 struct config_param *config;
457
458 mac_control = &nic->mac_control;
459 config = &nic->config;
460
461
462 /* Allocation and initialization of TXDLs in FIOFs */
463 size = 0;
464 for (i = 0; i < config->tx_fifo_num; i++) {
465 size += config->tx_cfg[i].fifo_len;
466 }
467 if (size > MAX_AVAILABLE_TXDS) {
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -0700468 DBG_PRINT(ERR_DBG, "%s: Requested TxDs too high, ",
469 __FUNCTION__);
470 DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 return FAILURE;
472 }
473
474 lst_size = (sizeof(TxD_t) * config->max_txds);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700475 tx_sz = lst_size * size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 lst_per_page = PAGE_SIZE / lst_size;
477
478 for (i = 0; i < config->tx_fifo_num; i++) {
479 int fifo_len = config->tx_cfg[i].fifo_len;
480 int list_holder_size = fifo_len * sizeof(list_info_hold_t);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700481 mac_control->fifos[i].list_info = kmalloc(list_holder_size,
482 GFP_KERNEL);
483 if (!mac_control->fifos[i].list_info) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 DBG_PRINT(ERR_DBG,
485 "Malloc failed for list_info\n");
486 return -ENOMEM;
487 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700488 memset(mac_control->fifos[i].list_info, 0, list_holder_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 }
490 for (i = 0; i < config->tx_fifo_num; i++) {
491 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
492 lst_per_page);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700493 mac_control->fifos[i].tx_curr_put_info.offset = 0;
494 mac_control->fifos[i].tx_curr_put_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700496 mac_control->fifos[i].tx_curr_get_info.offset = 0;
497 mac_control->fifos[i].tx_curr_get_info.fifo_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 config->tx_cfg[i].fifo_len - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700499 mac_control->fifos[i].fifo_no = i;
500 mac_control->fifos[i].nic = nic;
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500501 mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 2;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 for (j = 0; j < page_num; j++) {
504 int k = 0;
505 dma_addr_t tmp_p;
506 void *tmp_v;
507 tmp_v = pci_alloc_consistent(nic->pdev,
508 PAGE_SIZE, &tmp_p);
509 if (!tmp_v) {
510 DBG_PRINT(ERR_DBG,
511 "pci_alloc_consistent ");
512 DBG_PRINT(ERR_DBG, "failed for TxDL\n");
513 return -ENOMEM;
514 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700515 /* If we got a zero DMA address(can happen on
516 * certain platforms like PPC), reallocate.
517 * Store virtual address of page we don't want,
518 * to be freed later.
519 */
520 if (!tmp_p) {
521 mac_control->zerodma_virt_addr = tmp_v;
522 DBG_PRINT(INIT_DBG,
523 "%s: Zero DMA address for TxDL. ", dev->name);
524 DBG_PRINT(INIT_DBG,
Andrew Morton6b4d6172005-09-12 23:21:55 -0700525 "Virtual address %p\n", tmp_v);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700526 tmp_v = pci_alloc_consistent(nic->pdev,
527 PAGE_SIZE, &tmp_p);
528 if (!tmp_v) {
529 DBG_PRINT(ERR_DBG,
530 "pci_alloc_consistent ");
531 DBG_PRINT(ERR_DBG, "failed for TxDL\n");
532 return -ENOMEM;
533 }
534 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 while (k < lst_per_page) {
536 int l = (j * lst_per_page) + k;
537 if (l == config->tx_cfg[i].fifo_len)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700538 break;
539 mac_control->fifos[i].list_info[l].list_virt_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 tmp_v + (k * lst_size);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700541 mac_control->fifos[i].list_info[l].list_phy_addr =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 tmp_p + (k * lst_size);
543 k++;
544 }
545 }
546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500548 nic->ufo_in_band_v = kmalloc((sizeof(u64) * size), GFP_KERNEL);
549 if (!nic->ufo_in_band_v)
550 return -ENOMEM;
551
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 /* Allocation and initialization of RXDs in Rings */
553 size = 0;
554 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -0500555 if (config->rx_cfg[i].num_rxd %
556 (rxd_count[nic->rxd_mode] + 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 DBG_PRINT(ERR_DBG, "%s: RxD count of ", dev->name);
558 DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ",
559 i);
560 DBG_PRINT(ERR_DBG, "RxDs per Block");
561 return FAILURE;
562 }
563 size += config->rx_cfg[i].num_rxd;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700564 mac_control->rings[i].block_count =
Ananda Rajuda6971d2005-10-31 16:55:31 -0500565 config->rx_cfg[i].num_rxd /
566 (rxd_count[nic->rxd_mode] + 1 );
567 mac_control->rings[i].pkt_cnt = config->rx_cfg[i].num_rxd -
568 mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500570 if (nic->rxd_mode == RXD_MODE_1)
571 size = (size * (sizeof(RxD1_t)));
572 else
573 size = (size * (sizeof(RxD3_t)));
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700574 rx_sz = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
576 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700577 mac_control->rings[i].rx_curr_get_info.block_index = 0;
578 mac_control->rings[i].rx_curr_get_info.offset = 0;
579 mac_control->rings[i].rx_curr_get_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700581 mac_control->rings[i].rx_curr_put_info.block_index = 0;
582 mac_control->rings[i].rx_curr_put_info.offset = 0;
583 mac_control->rings[i].rx_curr_put_info.ring_len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 config->rx_cfg[i].num_rxd - 1;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700585 mac_control->rings[i].nic = nic;
586 mac_control->rings[i].ring_no = i;
587
Ananda Rajuda6971d2005-10-31 16:55:31 -0500588 blk_cnt = config->rx_cfg[i].num_rxd /
589 (rxd_count[nic->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 /* Allocating all the Rx blocks */
591 for (j = 0; j < blk_cnt; j++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -0500592 rx_block_info_t *rx_blocks;
593 int l;
594
595 rx_blocks = &mac_control->rings[i].rx_blocks[j];
596 size = SIZE_OF_BLOCK; //size is always page size
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 tmp_v_addr = pci_alloc_consistent(nic->pdev, size,
598 &tmp_p_addr);
599 if (tmp_v_addr == NULL) {
600 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700601 * In case of failure, free_shared_mem()
602 * is called, which should free any
603 * memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 * failure happened.
605 */
Ananda Rajuda6971d2005-10-31 16:55:31 -0500606 rx_blocks->block_virt_addr = tmp_v_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 return -ENOMEM;
608 }
609 memset(tmp_v_addr, 0, size);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500610 rx_blocks->block_virt_addr = tmp_v_addr;
611 rx_blocks->block_dma_addr = tmp_p_addr;
612 rx_blocks->rxds = kmalloc(sizeof(rxd_info_t)*
613 rxd_count[nic->rxd_mode],
614 GFP_KERNEL);
615 for (l=0; l<rxd_count[nic->rxd_mode];l++) {
616 rx_blocks->rxds[l].virt_addr =
617 rx_blocks->block_virt_addr +
618 (rxd_size[nic->rxd_mode] * l);
619 rx_blocks->rxds[l].dma_addr =
620 rx_blocks->block_dma_addr +
621 (rxd_size[nic->rxd_mode] * l);
622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
624 /* Interlinking all Rx Blocks */
625 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700626 tmp_v_addr =
627 mac_control->rings[i].rx_blocks[j].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 tmp_v_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700629 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 blk_cnt].block_virt_addr;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700631 tmp_p_addr =
632 mac_control->rings[i].rx_blocks[j].block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 tmp_p_addr_next =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700634 mac_control->rings[i].rx_blocks[(j + 1) %
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 blk_cnt].block_dma_addr;
636
637 pre_rxd_blk = (RxD_block_t *) tmp_v_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 pre_rxd_blk->reserved_2_pNext_RxD_block =
639 (unsigned long) tmp_v_addr_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 pre_rxd_blk->pNext_RxD_Blk_physical =
641 (u64) tmp_p_addr_next;
642 }
643 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500644 if (nic->rxd_mode >= RXD_MODE_3A) {
645 /*
646 * Allocation of Storages for buffer addresses in 2BUFF mode
647 * and the buffers as well.
648 */
649 for (i = 0; i < config->rx_ring_num; i++) {
650 blk_cnt = config->rx_cfg[i].num_rxd /
651 (rxd_count[nic->rxd_mode]+ 1);
652 mac_control->rings[i].ba =
653 kmalloc((sizeof(buffAdd_t *) * blk_cnt),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 GFP_KERNEL);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500655 if (!mac_control->rings[i].ba)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 return -ENOMEM;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500657 for (j = 0; j < blk_cnt; j++) {
658 int k = 0;
659 mac_control->rings[i].ba[j] =
660 kmalloc((sizeof(buffAdd_t) *
661 (rxd_count[nic->rxd_mode] + 1)),
662 GFP_KERNEL);
663 if (!mac_control->rings[i].ba[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 return -ENOMEM;
Ananda Rajuda6971d2005-10-31 16:55:31 -0500665 while (k != rxd_count[nic->rxd_mode]) {
666 ba = &mac_control->rings[i].ba[j][k];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Ananda Rajuda6971d2005-10-31 16:55:31 -0500668 ba->ba_0_org = (void *) kmalloc
669 (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
670 if (!ba->ba_0_org)
671 return -ENOMEM;
672 tmp = (unsigned long)ba->ba_0_org;
673 tmp += ALIGN_SIZE;
674 tmp &= ~((unsigned long) ALIGN_SIZE);
675 ba->ba_0 = (void *) tmp;
676
677 ba->ba_1_org = (void *) kmalloc
678 (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
679 if (!ba->ba_1_org)
680 return -ENOMEM;
681 tmp = (unsigned long) ba->ba_1_org;
682 tmp += ALIGN_SIZE;
683 tmp &= ~((unsigned long) ALIGN_SIZE);
684 ba->ba_1 = (void *) tmp;
685 k++;
686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
688 }
689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
691 /* Allocation and initialization of Statistics block */
692 size = sizeof(StatInfo_t);
693 mac_control->stats_mem = pci_alloc_consistent
694 (nic->pdev, size, &mac_control->stats_mem_phy);
695
696 if (!mac_control->stats_mem) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700697 /*
698 * In case of failure, free_shared_mem() is called, which
699 * should free any memory that was alloced till the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 * failure happened.
701 */
702 return -ENOMEM;
703 }
704 mac_control->stats_mem_sz = size;
705
706 tmp_v_addr = mac_control->stats_mem;
707 mac_control->stats_info = (StatInfo_t *) tmp_v_addr;
708 memset(tmp_v_addr, 0, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name,
710 (unsigned long long) tmp_p_addr);
711
712 return SUCCESS;
713}
714
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700715/**
716 * free_shared_mem - Free the allocated Memory
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 * @nic: Device private variable.
718 * Description: This function is to free all memory locations allocated by
719 * the init_shared_mem() function and return it to the kernel.
720 */
721
722static void free_shared_mem(struct s2io_nic *nic)
723{
724 int i, j, blk_cnt, size;
725 void *tmp_v_addr;
726 dma_addr_t tmp_p_addr;
727 mac_info_t *mac_control;
728 struct config_param *config;
729 int lst_size, lst_per_page;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700730 struct net_device *dev = nic->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
732 if (!nic)
733 return;
734
735 mac_control = &nic->mac_control;
736 config = &nic->config;
737
738 lst_size = (sizeof(TxD_t) * config->max_txds);
739 lst_per_page = PAGE_SIZE / lst_size;
740
741 for (i = 0; i < config->tx_fifo_num; i++) {
742 int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
743 lst_per_page);
744 for (j = 0; j < page_num; j++) {
745 int mem_blks = (j * lst_per_page);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700746 if (!mac_control->fifos[i].list_info)
747 return;
748 if (!mac_control->fifos[i].list_info[mem_blks].
749 list_virt_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 break;
751 pci_free_consistent(nic->pdev, PAGE_SIZE,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700752 mac_control->fifos[i].
753 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 list_virt_addr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700755 mac_control->fifos[i].
756 list_info[mem_blks].
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 list_phy_addr);
758 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700759 /* If we got a zero DMA address during allocation,
760 * free the page now
761 */
762 if (mac_control->zerodma_virt_addr) {
763 pci_free_consistent(nic->pdev, PAGE_SIZE,
764 mac_control->zerodma_virt_addr,
765 (dma_addr_t)0);
766 DBG_PRINT(INIT_DBG,
Andrew Morton6b4d6172005-09-12 23:21:55 -0700767 "%s: Freeing TxDL with zero DMA addr. ",
768 dev->name);
769 DBG_PRINT(INIT_DBG, "Virtual address %p\n",
770 mac_control->zerodma_virt_addr);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -0700771 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700772 kfree(mac_control->fifos[i].list_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 }
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 size = SIZE_OF_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700777 blk_cnt = mac_control->rings[i].block_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 for (j = 0; j < blk_cnt; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700779 tmp_v_addr = mac_control->rings[i].rx_blocks[j].
780 block_virt_addr;
781 tmp_p_addr = mac_control->rings[i].rx_blocks[j].
782 block_dma_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 if (tmp_v_addr == NULL)
784 break;
785 pci_free_consistent(nic->pdev, size,
786 tmp_v_addr, tmp_p_addr);
Ananda Rajuda6971d2005-10-31 16:55:31 -0500787 kfree(mac_control->rings[i].rx_blocks[j].rxds);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 }
789 }
790
Ananda Rajuda6971d2005-10-31 16:55:31 -0500791 if (nic->rxd_mode >= RXD_MODE_3A) {
792 /* Freeing buffer storage addresses in 2BUFF mode. */
793 for (i = 0; i < config->rx_ring_num; i++) {
794 blk_cnt = config->rx_cfg[i].num_rxd /
795 (rxd_count[nic->rxd_mode] + 1);
796 for (j = 0; j < blk_cnt; j++) {
797 int k = 0;
798 if (!mac_control->rings[i].ba[j])
799 continue;
800 while (k != rxd_count[nic->rxd_mode]) {
801 buffAdd_t *ba =
802 &mac_control->rings[i].ba[j][k];
803 kfree(ba->ba_0_org);
804 kfree(ba->ba_1_org);
805 k++;
806 }
807 kfree(mac_control->rings[i].ba[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 }
Ananda Rajuda6971d2005-10-31 16:55:31 -0500809 kfree(mac_control->rings[i].ba);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 if (mac_control->stats_mem) {
814 pci_free_consistent(nic->pdev,
815 mac_control->stats_mem_sz,
816 mac_control->stats_mem,
817 mac_control->stats_mem_phy);
818 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -0500819 if (nic->ufo_in_band_v)
820 kfree(nic->ufo_in_band_v);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821}
822
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700823/**
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700824 * s2io_verify_pci_mode -
825 */
826
827static int s2io_verify_pci_mode(nic_t *nic)
828{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +0100829 XENA_dev_config_t __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700830 register u64 val64 = 0;
831 int mode;
832
833 val64 = readq(&bar0->pci_mode);
834 mode = (u8)GET_PCI_MODE(val64);
835
836 if ( val64 & PCI_MODE_UNKNOWN_MODE)
837 return -1; /* Unknown PCI mode */
838 return mode;
839}
840
Ananda Rajuc92ca042006-04-21 19:18:03 -0400841#define NEC_VENID 0x1033
842#define NEC_DEVID 0x0125
843static int s2io_on_nec_bridge(struct pci_dev *s2io_pdev)
844{
845 struct pci_dev *tdev = NULL;
846 while ((tdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, tdev)) != NULL) {
847 if ((tdev->vendor == NEC_VENID) && (tdev->device == NEC_DEVID)){
848 if (tdev->bus == s2io_pdev->bus->parent)
849 return 1;
850 }
851 }
852 return 0;
853}
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700854
Adrian Bunk7b32a312006-05-16 17:30:50 +0200855static int bus_speed[8] = {33, 133, 133, 200, 266, 133, 200, 266};
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700856/**
857 * s2io_print_pci_mode -
858 */
859static int s2io_print_pci_mode(nic_t *nic)
860{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +0100861 XENA_dev_config_t __iomem *bar0 = nic->bar0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700862 register u64 val64 = 0;
863 int mode;
864 struct config_param *config = &nic->config;
865
866 val64 = readq(&bar0->pci_mode);
867 mode = (u8)GET_PCI_MODE(val64);
868
869 if ( val64 & PCI_MODE_UNKNOWN_MODE)
870 return -1; /* Unknown PCI mode */
871
Ananda Rajuc92ca042006-04-21 19:18:03 -0400872 config->bus_speed = bus_speed[mode];
873
874 if (s2io_on_nec_bridge(nic->pdev)) {
875 DBG_PRINT(ERR_DBG, "%s: Device is on PCI-E bus\n",
876 nic->dev->name);
877 return mode;
878 }
879
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700880 if (val64 & PCI_MODE_32_BITS) {
881 DBG_PRINT(ERR_DBG, "%s: Device is on 32 bit ", nic->dev->name);
882 } else {
883 DBG_PRINT(ERR_DBG, "%s: Device is on 64 bit ", nic->dev->name);
884 }
885
886 switch(mode) {
887 case PCI_MODE_PCI_33:
888 DBG_PRINT(ERR_DBG, "33MHz PCI bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700889 break;
890 case PCI_MODE_PCI_66:
891 DBG_PRINT(ERR_DBG, "66MHz PCI bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700892 break;
893 case PCI_MODE_PCIX_M1_66:
894 DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700895 break;
896 case PCI_MODE_PCIX_M1_100:
897 DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700898 break;
899 case PCI_MODE_PCIX_M1_133:
900 DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700901 break;
902 case PCI_MODE_PCIX_M2_66:
903 DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700904 break;
905 case PCI_MODE_PCIX_M2_100:
906 DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700907 break;
908 case PCI_MODE_PCIX_M2_133:
909 DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700910 break;
911 default:
912 return -1; /* Unsupported bus speed */
913 }
914
915 return mode;
916}
917
918/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700919 * init_nic - Initialization of hardware
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 * @nic: device peivate variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700921 * Description: The function sequentially configures every block
922 * of the H/W from their reset values.
923 * Return Value: SUCCESS on success and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 * '-1' on failure (endian settings incorrect).
925 */
926
927static int init_nic(struct s2io_nic *nic)
928{
929 XENA_dev_config_t __iomem *bar0 = nic->bar0;
930 struct net_device *dev = nic->dev;
931 register u64 val64 = 0;
932 void __iomem *add;
933 u32 time;
934 int i, j;
935 mac_info_t *mac_control;
936 struct config_param *config;
Ananda Rajuc92ca042006-04-21 19:18:03 -0400937 int dtx_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 unsigned long long mem_share;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700939 int mem_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
941 mac_control = &nic->mac_control;
942 config = &nic->config;
943
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -0700944 /* to set the swapper controle on the card */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700945 if(s2io_set_swapper(nic)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n");
947 return -1;
948 }
949
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700950 /*
951 * Herc requires EOI to be removed from reset before XGXS, so..
952 */
953 if (nic->device_type & XFRAME_II_DEVICE) {
954 val64 = 0xA500000000ULL;
955 writeq(val64, &bar0->sw_reset);
956 msleep(500);
957 val64 = readq(&bar0->sw_reset);
958 }
959
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 /* Remove XGXS from reset state */
961 val64 = 0;
962 writeq(val64, &bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 msleep(500);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -0700964 val64 = readq(&bar0->sw_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
966 /* Enable Receiving broadcasts */
967 add = &bar0->mac_cfg;
968 val64 = readq(&bar0->mac_cfg);
969 val64 |= MAC_RMAC_BCAST_ENABLE;
970 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
971 writel((u32) val64, add);
972 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
973 writel((u32) (val64 >> 32), (add + 4));
974
975 /* Read registers in all blocks */
976 val64 = readq(&bar0->mac_int_mask);
977 val64 = readq(&bar0->mc_int_mask);
978 val64 = readq(&bar0->xgxs_int_mask);
979
980 /* Set MTU */
981 val64 = dev->mtu;
982 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
983
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700984 if (nic->device_type & XFRAME_II_DEVICE) {
985 while (herc_act_dtx_cfg[dtx_cnt] != END_SIGN) {
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -0700986 SPECIAL_REG_WRITE(herc_act_dtx_cfg[dtx_cnt],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 &bar0->dtx_control, UF);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700988 if (dtx_cnt & 0x1)
989 msleep(1); /* Necessary!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 dtx_cnt++;
991 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -0700992 } else {
Ananda Rajuc92ca042006-04-21 19:18:03 -0400993 while (xena_dtx_cfg[dtx_cnt] != END_SIGN) {
994 SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt],
995 &bar0->dtx_control, UF);
996 val64 = readq(&bar0->dtx_control);
997 dtx_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 }
999 }
1000
1001 /* Tx DMA Initialization */
1002 val64 = 0;
1003 writeq(val64, &bar0->tx_fifo_partition_0);
1004 writeq(val64, &bar0->tx_fifo_partition_1);
1005 writeq(val64, &bar0->tx_fifo_partition_2);
1006 writeq(val64, &bar0->tx_fifo_partition_3);
1007
1008
1009 for (i = 0, j = 0; i < config->tx_fifo_num; i++) {
1010 val64 |=
1011 vBIT(config->tx_cfg[i].fifo_len - 1, ((i * 32) + 19),
1012 13) | vBIT(config->tx_cfg[i].fifo_priority,
1013 ((i * 32) + 5), 3);
1014
1015 if (i == (config->tx_fifo_num - 1)) {
1016 if (i % 2 == 0)
1017 i++;
1018 }
1019
1020 switch (i) {
1021 case 1:
1022 writeq(val64, &bar0->tx_fifo_partition_0);
1023 val64 = 0;
1024 break;
1025 case 3:
1026 writeq(val64, &bar0->tx_fifo_partition_1);
1027 val64 = 0;
1028 break;
1029 case 5:
1030 writeq(val64, &bar0->tx_fifo_partition_2);
1031 val64 = 0;
1032 break;
1033 case 7:
1034 writeq(val64, &bar0->tx_fifo_partition_3);
1035 break;
1036 }
1037 }
1038
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001039 /*
1040 * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug
1041 * SXE-008 TRANSMIT DMA ARBITRATION ISSUE.
1042 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001043 if ((nic->device_type == XFRAME_I_DEVICE) &&
1044 (get_xena_rev_id(nic->pdev) < 4))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001045 writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable);
1046
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 val64 = readq(&bar0->tx_fifo_partition_0);
1048 DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n",
1049 &bar0->tx_fifo_partition_0, (unsigned long long) val64);
1050
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001051 /*
1052 * Initialization of Tx_PA_CONFIG register to ignore packet
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 * integrity checking.
1054 */
1055 val64 = readq(&bar0->tx_pa_cfg);
1056 val64 |= TX_PA_CFG_IGNORE_FRM_ERR | TX_PA_CFG_IGNORE_SNAP_OUI |
1057 TX_PA_CFG_IGNORE_LLC_CTRL | TX_PA_CFG_IGNORE_L2_ERR;
1058 writeq(val64, &bar0->tx_pa_cfg);
1059
1060 /* Rx DMA intialization. */
1061 val64 = 0;
1062 for (i = 0; i < config->rx_ring_num; i++) {
1063 val64 |=
1064 vBIT(config->rx_cfg[i].ring_priority, (5 + (i * 8)),
1065 3);
1066 }
1067 writeq(val64, &bar0->rx_queue_priority);
1068
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001069 /*
1070 * Allocating equal share of memory to all the
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 * configured Rings.
1072 */
1073 val64 = 0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001074 if (nic->device_type & XFRAME_II_DEVICE)
1075 mem_size = 32;
1076 else
1077 mem_size = 64;
1078
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 for (i = 0; i < config->rx_ring_num; i++) {
1080 switch (i) {
1081 case 0:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001082 mem_share = (mem_size / config->rx_ring_num +
1083 mem_size % config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 val64 |= RX_QUEUE_CFG_Q0_SZ(mem_share);
1085 continue;
1086 case 1:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001087 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 val64 |= RX_QUEUE_CFG_Q1_SZ(mem_share);
1089 continue;
1090 case 2:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001091 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 val64 |= RX_QUEUE_CFG_Q2_SZ(mem_share);
1093 continue;
1094 case 3:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001095 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 val64 |= RX_QUEUE_CFG_Q3_SZ(mem_share);
1097 continue;
1098 case 4:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001099 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 val64 |= RX_QUEUE_CFG_Q4_SZ(mem_share);
1101 continue;
1102 case 5:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001103 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 val64 |= RX_QUEUE_CFG_Q5_SZ(mem_share);
1105 continue;
1106 case 6:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001107 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 val64 |= RX_QUEUE_CFG_Q6_SZ(mem_share);
1109 continue;
1110 case 7:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001111 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 val64 |= RX_QUEUE_CFG_Q7_SZ(mem_share);
1113 continue;
1114 }
1115 }
1116 writeq(val64, &bar0->rx_queue_cfg);
1117
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001118 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001119 * Filling Tx round robin registers
1120 * as per the number of FIFOs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 */
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001122 switch (config->tx_fifo_num) {
1123 case 1:
1124 val64 = 0x0000000000000000ULL;
1125 writeq(val64, &bar0->tx_w_round_robin_0);
1126 writeq(val64, &bar0->tx_w_round_robin_1);
1127 writeq(val64, &bar0->tx_w_round_robin_2);
1128 writeq(val64, &bar0->tx_w_round_robin_3);
1129 writeq(val64, &bar0->tx_w_round_robin_4);
1130 break;
1131 case 2:
1132 val64 = 0x0000010000010000ULL;
1133 writeq(val64, &bar0->tx_w_round_robin_0);
1134 val64 = 0x0100000100000100ULL;
1135 writeq(val64, &bar0->tx_w_round_robin_1);
1136 val64 = 0x0001000001000001ULL;
1137 writeq(val64, &bar0->tx_w_round_robin_2);
1138 val64 = 0x0000010000010000ULL;
1139 writeq(val64, &bar0->tx_w_round_robin_3);
1140 val64 = 0x0100000000000000ULL;
1141 writeq(val64, &bar0->tx_w_round_robin_4);
1142 break;
1143 case 3:
1144 val64 = 0x0001000102000001ULL;
1145 writeq(val64, &bar0->tx_w_round_robin_0);
1146 val64 = 0x0001020000010001ULL;
1147 writeq(val64, &bar0->tx_w_round_robin_1);
1148 val64 = 0x0200000100010200ULL;
1149 writeq(val64, &bar0->tx_w_round_robin_2);
1150 val64 = 0x0001000102000001ULL;
1151 writeq(val64, &bar0->tx_w_round_robin_3);
1152 val64 = 0x0001020000000000ULL;
1153 writeq(val64, &bar0->tx_w_round_robin_4);
1154 break;
1155 case 4:
1156 val64 = 0x0001020300010200ULL;
1157 writeq(val64, &bar0->tx_w_round_robin_0);
1158 val64 = 0x0100000102030001ULL;
1159 writeq(val64, &bar0->tx_w_round_robin_1);
1160 val64 = 0x0200010000010203ULL;
1161 writeq(val64, &bar0->tx_w_round_robin_2);
1162 val64 = 0x0001020001000001ULL;
1163 writeq(val64, &bar0->tx_w_round_robin_3);
1164 val64 = 0x0203000100000000ULL;
1165 writeq(val64, &bar0->tx_w_round_robin_4);
1166 break;
1167 case 5:
1168 val64 = 0x0001000203000102ULL;
1169 writeq(val64, &bar0->tx_w_round_robin_0);
1170 val64 = 0x0001020001030004ULL;
1171 writeq(val64, &bar0->tx_w_round_robin_1);
1172 val64 = 0x0001000203000102ULL;
1173 writeq(val64, &bar0->tx_w_round_robin_2);
1174 val64 = 0x0001020001030004ULL;
1175 writeq(val64, &bar0->tx_w_round_robin_3);
1176 val64 = 0x0001000000000000ULL;
1177 writeq(val64, &bar0->tx_w_round_robin_4);
1178 break;
1179 case 6:
1180 val64 = 0x0001020304000102ULL;
1181 writeq(val64, &bar0->tx_w_round_robin_0);
1182 val64 = 0x0304050001020001ULL;
1183 writeq(val64, &bar0->tx_w_round_robin_1);
1184 val64 = 0x0203000100000102ULL;
1185 writeq(val64, &bar0->tx_w_round_robin_2);
1186 val64 = 0x0304000102030405ULL;
1187 writeq(val64, &bar0->tx_w_round_robin_3);
1188 val64 = 0x0001000200000000ULL;
1189 writeq(val64, &bar0->tx_w_round_robin_4);
1190 break;
1191 case 7:
1192 val64 = 0x0001020001020300ULL;
1193 writeq(val64, &bar0->tx_w_round_robin_0);
1194 val64 = 0x0102030400010203ULL;
1195 writeq(val64, &bar0->tx_w_round_robin_1);
1196 val64 = 0x0405060001020001ULL;
1197 writeq(val64, &bar0->tx_w_round_robin_2);
1198 val64 = 0x0304050000010200ULL;
1199 writeq(val64, &bar0->tx_w_round_robin_3);
1200 val64 = 0x0102030000000000ULL;
1201 writeq(val64, &bar0->tx_w_round_robin_4);
1202 break;
1203 case 8:
1204 val64 = 0x0001020300040105ULL;
1205 writeq(val64, &bar0->tx_w_round_robin_0);
1206 val64 = 0x0200030106000204ULL;
1207 writeq(val64, &bar0->tx_w_round_robin_1);
1208 val64 = 0x0103000502010007ULL;
1209 writeq(val64, &bar0->tx_w_round_robin_2);
1210 val64 = 0x0304010002060500ULL;
1211 writeq(val64, &bar0->tx_w_round_robin_3);
1212 val64 = 0x0103020400000000ULL;
1213 writeq(val64, &bar0->tx_w_round_robin_4);
1214 break;
1215 }
1216
Ananda Raju5d3213c2006-04-21 19:23:26 -04001217 /* Enable Tx FIFO partition 0. */
1218 val64 = readq(&bar0->tx_fifo_partition_0);
1219 val64 |= (TX_FIFO_PARTITION_EN);
1220 writeq(val64, &bar0->tx_fifo_partition_0);
1221
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001222 /* Filling the Rx round robin registers as per the
1223 * number of Rings and steering based on QoS.
1224 */
1225 switch (config->rx_ring_num) {
1226 case 1:
1227 val64 = 0x8080808080808080ULL;
1228 writeq(val64, &bar0->rts_qos_steering);
1229 break;
1230 case 2:
1231 val64 = 0x0000010000010000ULL;
1232 writeq(val64, &bar0->rx_w_round_robin_0);
1233 val64 = 0x0100000100000100ULL;
1234 writeq(val64, &bar0->rx_w_round_robin_1);
1235 val64 = 0x0001000001000001ULL;
1236 writeq(val64, &bar0->rx_w_round_robin_2);
1237 val64 = 0x0000010000010000ULL;
1238 writeq(val64, &bar0->rx_w_round_robin_3);
1239 val64 = 0x0100000000000000ULL;
1240 writeq(val64, &bar0->rx_w_round_robin_4);
1241
1242 val64 = 0x8080808040404040ULL;
1243 writeq(val64, &bar0->rts_qos_steering);
1244 break;
1245 case 3:
1246 val64 = 0x0001000102000001ULL;
1247 writeq(val64, &bar0->rx_w_round_robin_0);
1248 val64 = 0x0001020000010001ULL;
1249 writeq(val64, &bar0->rx_w_round_robin_1);
1250 val64 = 0x0200000100010200ULL;
1251 writeq(val64, &bar0->rx_w_round_robin_2);
1252 val64 = 0x0001000102000001ULL;
1253 writeq(val64, &bar0->rx_w_round_robin_3);
1254 val64 = 0x0001020000000000ULL;
1255 writeq(val64, &bar0->rx_w_round_robin_4);
1256
1257 val64 = 0x8080804040402020ULL;
1258 writeq(val64, &bar0->rts_qos_steering);
1259 break;
1260 case 4:
1261 val64 = 0x0001020300010200ULL;
1262 writeq(val64, &bar0->rx_w_round_robin_0);
1263 val64 = 0x0100000102030001ULL;
1264 writeq(val64, &bar0->rx_w_round_robin_1);
1265 val64 = 0x0200010000010203ULL;
1266 writeq(val64, &bar0->rx_w_round_robin_2);
1267 val64 = 0x0001020001000001ULL;
1268 writeq(val64, &bar0->rx_w_round_robin_3);
1269 val64 = 0x0203000100000000ULL;
1270 writeq(val64, &bar0->rx_w_round_robin_4);
1271
1272 val64 = 0x8080404020201010ULL;
1273 writeq(val64, &bar0->rts_qos_steering);
1274 break;
1275 case 5:
1276 val64 = 0x0001000203000102ULL;
1277 writeq(val64, &bar0->rx_w_round_robin_0);
1278 val64 = 0x0001020001030004ULL;
1279 writeq(val64, &bar0->rx_w_round_robin_1);
1280 val64 = 0x0001000203000102ULL;
1281 writeq(val64, &bar0->rx_w_round_robin_2);
1282 val64 = 0x0001020001030004ULL;
1283 writeq(val64, &bar0->rx_w_round_robin_3);
1284 val64 = 0x0001000000000000ULL;
1285 writeq(val64, &bar0->rx_w_round_robin_4);
1286
1287 val64 = 0x8080404020201008ULL;
1288 writeq(val64, &bar0->rts_qos_steering);
1289 break;
1290 case 6:
1291 val64 = 0x0001020304000102ULL;
1292 writeq(val64, &bar0->rx_w_round_robin_0);
1293 val64 = 0x0304050001020001ULL;
1294 writeq(val64, &bar0->rx_w_round_robin_1);
1295 val64 = 0x0203000100000102ULL;
1296 writeq(val64, &bar0->rx_w_round_robin_2);
1297 val64 = 0x0304000102030405ULL;
1298 writeq(val64, &bar0->rx_w_round_robin_3);
1299 val64 = 0x0001000200000000ULL;
1300 writeq(val64, &bar0->rx_w_round_robin_4);
1301
1302 val64 = 0x8080404020100804ULL;
1303 writeq(val64, &bar0->rts_qos_steering);
1304 break;
1305 case 7:
1306 val64 = 0x0001020001020300ULL;
1307 writeq(val64, &bar0->rx_w_round_robin_0);
1308 val64 = 0x0102030400010203ULL;
1309 writeq(val64, &bar0->rx_w_round_robin_1);
1310 val64 = 0x0405060001020001ULL;
1311 writeq(val64, &bar0->rx_w_round_robin_2);
1312 val64 = 0x0304050000010200ULL;
1313 writeq(val64, &bar0->rx_w_round_robin_3);
1314 val64 = 0x0102030000000000ULL;
1315 writeq(val64, &bar0->rx_w_round_robin_4);
1316
1317 val64 = 0x8080402010080402ULL;
1318 writeq(val64, &bar0->rts_qos_steering);
1319 break;
1320 case 8:
1321 val64 = 0x0001020300040105ULL;
1322 writeq(val64, &bar0->rx_w_round_robin_0);
1323 val64 = 0x0200030106000204ULL;
1324 writeq(val64, &bar0->rx_w_round_robin_1);
1325 val64 = 0x0103000502010007ULL;
1326 writeq(val64, &bar0->rx_w_round_robin_2);
1327 val64 = 0x0304010002060500ULL;
1328 writeq(val64, &bar0->rx_w_round_robin_3);
1329 val64 = 0x0103020400000000ULL;
1330 writeq(val64, &bar0->rx_w_round_robin_4);
1331
1332 val64 = 0x8040201008040201ULL;
1333 writeq(val64, &bar0->rts_qos_steering);
1334 break;
1335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
1337 /* UDP Fix */
1338 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001339 for (i = 0; i < 8; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 writeq(val64, &bar0->rts_frm_len_n[i]);
1341
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001342 /* Set the default rts frame length for the rings configured */
1343 val64 = MAC_RTS_FRM_LEN_SET(dev->mtu+22);
1344 for (i = 0 ; i < config->rx_ring_num ; i++)
1345 writeq(val64, &bar0->rts_frm_len_n[i]);
1346
1347 /* Set the frame length for the configured rings
1348 * desired by the user
1349 */
1350 for (i = 0; i < config->rx_ring_num; i++) {
1351 /* If rts_frm_len[i] == 0 then it is assumed that user not
1352 * specified frame length steering.
1353 * If the user provides the frame length then program
1354 * the rts_frm_len register for those values or else
1355 * leave it as it is.
1356 */
1357 if (rts_frm_len[i] != 0) {
1358 writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]),
1359 &bar0->rts_frm_len_n[i]);
1360 }
1361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001363 /* Program statistics memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 writeq(mac_control->stats_mem_phy, &bar0->stat_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001366 if (nic->device_type == XFRAME_II_DEVICE) {
1367 val64 = STAT_BC(0x320);
1368 writeq(val64, &bar0->stat_byte_cnt);
1369 }
1370
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001371 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 * Initializing the sampling rate for the device to calculate the
1373 * bandwidth utilization.
1374 */
1375 val64 = MAC_TX_LINK_UTIL_VAL(tmac_util_period) |
1376 MAC_RX_LINK_UTIL_VAL(rmac_util_period);
1377 writeq(val64, &bar0->mac_link_util);
1378
1379
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001380 /*
1381 * Initializing the Transmit and Receive Traffic Interrupt
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 * Scheme.
1383 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001384 /*
1385 * TTI Initialization. Default Tx timer gets us about
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 * 250 interrupts per sec. Continuous interrupts are enabled
1387 * by default.
1388 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001389 if (nic->device_type == XFRAME_II_DEVICE) {
1390 int count = (nic->config.bus_speed * 125)/2;
1391 val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count);
1392 } else {
1393
1394 val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078);
1395 }
1396 val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 TTI_DATA1_MEM_TX_URNG_B(0x10) |
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001398 TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001399 if (use_continuous_tx_intrs)
1400 val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 writeq(val64, &bar0->tti_data1_mem);
1402
1403 val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
1404 TTI_DATA2_MEM_TX_UFC_B(0x20) |
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001405 TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 writeq(val64, &bar0->tti_data2_mem);
1407
1408 val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
1409 writeq(val64, &bar0->tti_command_mem);
1410
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001411 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 * Once the operation completes, the Strobe bit of the command
1413 * register will be reset. We poll for this particular condition
1414 * We wait for a maximum of 500ms for the operation to complete,
1415 * if it's not complete by then we return error.
1416 */
1417 time = 0;
1418 while (TRUE) {
1419 val64 = readq(&bar0->tti_command_mem);
1420 if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
1421 break;
1422 }
1423 if (time > 10) {
1424 DBG_PRINT(ERR_DBG, "%s: TTI init Failed\n",
1425 dev->name);
1426 return -1;
1427 }
1428 msleep(50);
1429 time++;
1430 }
1431
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001432 if (nic->config.bimodal) {
1433 int k = 0;
1434 for (k = 0; k < config->rx_ring_num; k++) {
1435 val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
1436 val64 |= TTI_CMD_MEM_OFFSET(0x38+k);
1437 writeq(val64, &bar0->tti_command_mem);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001438
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001439 /*
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001440 * Once the operation completes, the Strobe bit of the command
1441 * register will be reset. We poll for this particular condition
1442 * We wait for a maximum of 500ms for the operation to complete,
1443 * if it's not complete by then we return error.
1444 */
1445 time = 0;
1446 while (TRUE) {
1447 val64 = readq(&bar0->tti_command_mem);
1448 if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
1449 break;
1450 }
1451 if (time > 10) {
1452 DBG_PRINT(ERR_DBG,
1453 "%s: TTI init Failed\n",
1454 dev->name);
1455 return -1;
1456 }
1457 time++;
1458 msleep(50);
1459 }
1460 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001461 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001463 /* RTI Initialization */
1464 if (nic->device_type == XFRAME_II_DEVICE) {
1465 /*
1466 * Programmed to generate Apprx 500 Intrs per
1467 * second
1468 */
1469 int count = (nic->config.bus_speed * 125)/4;
1470 val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
1471 } else {
1472 val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 }
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001474 val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
1475 RTI_DATA1_MEM_RX_URNG_B(0x10) |
1476 RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
1477
1478 writeq(val64, &bar0->rti_data1_mem);
1479
1480 val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04001481 RTI_DATA2_MEM_RX_UFC_B(0x2) ;
1482 if (nic->intr_type == MSI_X)
1483 val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
1484 RTI_DATA2_MEM_RX_UFC_D(0x40));
1485 else
1486 val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \
1487 RTI_DATA2_MEM_RX_UFC_D(0x80));
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001488 writeq(val64, &bar0->rti_data2_mem);
1489
1490 for (i = 0; i < config->rx_ring_num; i++) {
1491 val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD
1492 | RTI_CMD_MEM_OFFSET(i);
1493 writeq(val64, &bar0->rti_command_mem);
1494
1495 /*
1496 * Once the operation completes, the Strobe bit of the
1497 * command register will be reset. We poll for this
1498 * particular condition. We wait for a maximum of 500ms
1499 * for the operation to complete, if it's not complete
1500 * by then we return error.
1501 */
1502 time = 0;
1503 while (TRUE) {
1504 val64 = readq(&bar0->rti_command_mem);
1505 if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) {
1506 break;
1507 }
1508 if (time > 10) {
1509 DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
1510 dev->name);
1511 return -1;
1512 }
1513 time++;
1514 msleep(50);
1515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 }
1518
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001519 /*
1520 * Initializing proper values as Pause threshold into all
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 * the 8 Queues on Rx side.
1522 */
1523 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q0q3);
1524 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7);
1525
1526 /* Disable RMAC PAD STRIPPING */
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01001527 add = &bar0->mac_cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 val64 = readq(&bar0->mac_cfg);
1529 val64 &= ~(MAC_CFG_RMAC_STRIP_PAD);
1530 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1531 writel((u32) (val64), add);
1532 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1533 writel((u32) (val64 >> 32), (add + 4));
1534 val64 = readq(&bar0->mac_cfg);
1535
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05001536 /* Enable FCS stripping by adapter */
1537 add = &bar0->mac_cfg;
1538 val64 = readq(&bar0->mac_cfg);
1539 val64 |= MAC_CFG_RMAC_STRIP_FCS;
1540 if (nic->device_type == XFRAME_II_DEVICE)
1541 writeq(val64, &bar0->mac_cfg);
1542 else {
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 }
1548
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001549 /*
1550 * Set the time value to be inserted in the pause frame
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 * generated by xena.
1552 */
1553 val64 = readq(&bar0->rmac_pause_cfg);
1554 val64 &= ~(RMAC_PAUSE_HG_PTIME(0xffff));
1555 val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time);
1556 writeq(val64, &bar0->rmac_pause_cfg);
1557
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001558 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 * Set the Threshold Limit for Generating the pause frame
1560 * If the amount of data in any Queue exceeds ratio of
1561 * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256
1562 * pause frame is generated
1563 */
1564 val64 = 0;
1565 for (i = 0; i < 4; i++) {
1566 val64 |=
1567 (((u64) 0xFF00 | nic->mac_control.
1568 mc_pause_threshold_q0q3)
1569 << (i * 2 * 8));
1570 }
1571 writeq(val64, &bar0->mc_pause_thresh_q0q3);
1572
1573 val64 = 0;
1574 for (i = 0; i < 4; i++) {
1575 val64 |=
1576 (((u64) 0xFF00 | nic->mac_control.
1577 mc_pause_threshold_q4q7)
1578 << (i * 2 * 8));
1579 }
1580 writeq(val64, &bar0->mc_pause_thresh_q4q7);
1581
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001582 /*
1583 * TxDMA will stop Read request if the number of read split has
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 * exceeded the limit pointed by shared_splits
1585 */
1586 val64 = readq(&bar0->pic_control);
1587 val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits);
1588 writeq(val64, &bar0->pic_control);
1589
Ananda Raju863c11a2006-04-21 19:03:13 -04001590 if (nic->config.bus_speed == 266) {
1591 writeq(TXREQTO_VAL(0x7f) | TXREQTO_EN, &bar0->txreqtimeout);
1592 writeq(0x0, &bar0->read_retry_delay);
1593 writeq(0x0, &bar0->write_retry_delay);
1594 }
1595
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001596 /*
1597 * Programming the Herc to split every write transaction
1598 * that does not start on an ADB to reduce disconnects.
1599 */
1600 if (nic->device_type == XFRAME_II_DEVICE) {
Ananda Raju863c11a2006-04-21 19:03:13 -04001601 val64 = EXT_REQ_EN | MISC_LINK_STABILITY_PRD(3);
1602 writeq(val64, &bar0->misc_control);
1603 val64 = readq(&bar0->pic_control2);
1604 val64 &= ~(BIT(13)|BIT(14)|BIT(15));
1605 writeq(val64, &bar0->pic_control2);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001606 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04001607 if (strstr(nic->product_name, "CX4")) {
1608 val64 = TMAC_AVG_IPG(0x17);
1609 writeq(val64, &bar0->tmac_avg_ipg);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001610 }
1611
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 return SUCCESS;
1613}
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001614#define LINK_UP_DOWN_INTERRUPT 1
1615#define MAC_RMAC_ERR_TIMER 2
1616
Adrian Bunkac1f60d2005-11-06 01:46:47 +01001617static int s2io_link_fault_indication(nic_t *nic)
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001618{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04001619 if (nic->intr_type != INTA)
1620 return MAC_RMAC_ERR_TIMER;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001621 if (nic->device_type == XFRAME_II_DEVICE)
1622 return LINK_UP_DOWN_INTERRUPT;
1623 else
1624 return MAC_RMAC_ERR_TIMER;
1625}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001627/**
1628 * en_dis_able_nic_intrs - Enable or Disable the interrupts
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 * @nic: device private variable,
1630 * @mask: A mask indicating which Intr block must be modified and,
1631 * @flag: A flag indicating whether to enable or disable the Intrs.
1632 * Description: This function will either disable or enable the interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001633 * depending on the flag argument. The mask argument can be used to
1634 * enable/disable any Intr block.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 * Return Value: NONE.
1636 */
1637
1638static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
1639{
1640 XENA_dev_config_t __iomem *bar0 = nic->bar0;
1641 register u64 val64 = 0, temp64 = 0;
1642
1643 /* Top level interrupt classification */
1644 /* PIC Interrupts */
1645 if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
1646 /* Enable PIC Intrs in the general intr mask register */
1647 val64 = TXPIC_INT_M | PIC_RX_INT_M;
1648 if (flag == ENABLE_INTRS) {
1649 temp64 = readq(&bar0->general_int_mask);
1650 temp64 &= ~((u64) val64);
1651 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001652 /*
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001653 * If Hercules adapter enable GPIO otherwise
1654 * disabled all PCIX, Flash, MDIO, IIC and GPIO
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001655 * interrupts for now.
1656 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07001658 if (s2io_link_fault_indication(nic) ==
1659 LINK_UP_DOWN_INTERRUPT ) {
1660 temp64 = readq(&bar0->pic_int_mask);
1661 temp64 &= ~((u64) PIC_INT_GPIO);
1662 writeq(temp64, &bar0->pic_int_mask);
1663 temp64 = readq(&bar0->gpio_int_mask);
1664 temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP);
1665 writeq(temp64, &bar0->gpio_int_mask);
1666 } else {
1667 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
1668 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001669 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 * No MSI Support is available presently, so TTI and
1671 * RTI interrupts are also disabled.
1672 */
1673 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001674 /*
1675 * Disable PIC Intrs in the general
1676 * intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 */
1678 writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
1679 temp64 = readq(&bar0->general_int_mask);
1680 val64 |= temp64;
1681 writeq(val64, &bar0->general_int_mask);
1682 }
1683 }
1684
1685 /* DMA Interrupts */
1686 /* Enabling/Disabling Tx DMA interrupts */
1687 if (mask & TX_DMA_INTR) {
1688 /* Enable TxDMA Intrs in the general intr mask register */
1689 val64 = TXDMA_INT_M;
1690 if (flag == ENABLE_INTRS) {
1691 temp64 = readq(&bar0->general_int_mask);
1692 temp64 &= ~((u64) val64);
1693 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001694 /*
1695 * Keep all interrupts other than PFC interrupt
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 * and PCC interrupt disabled in DMA level.
1697 */
1698 val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M |
1699 TXDMA_PCC_INT_M);
1700 writeq(val64, &bar0->txdma_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001701 /*
1702 * Enable only the MISC error 1 interrupt in PFC block
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 */
1704 val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1);
1705 writeq(val64, &bar0->pfc_err_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001706 /*
1707 * Enable only the FB_ECC error interrupt in PCC block
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 */
1709 val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR);
1710 writeq(val64, &bar0->pcc_err_mask);
1711 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001712 /*
1713 * Disable TxDMA Intrs in the general intr mask
1714 * register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 */
1716 writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask);
1717 writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask);
1718 temp64 = readq(&bar0->general_int_mask);
1719 val64 |= temp64;
1720 writeq(val64, &bar0->general_int_mask);
1721 }
1722 }
1723
1724 /* Enabling/Disabling Rx DMA interrupts */
1725 if (mask & RX_DMA_INTR) {
1726 /* Enable RxDMA Intrs in the general intr mask register */
1727 val64 = RXDMA_INT_M;
1728 if (flag == ENABLE_INTRS) {
1729 temp64 = readq(&bar0->general_int_mask);
1730 temp64 &= ~((u64) val64);
1731 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001732 /*
1733 * All RxDMA block interrupts are disabled for now
1734 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 */
1736 writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
1737 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001738 /*
1739 * Disable RxDMA Intrs in the general intr mask
1740 * register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 */
1742 writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
1743 temp64 = readq(&bar0->general_int_mask);
1744 val64 |= temp64;
1745 writeq(val64, &bar0->general_int_mask);
1746 }
1747 }
1748
1749 /* MAC Interrupts */
1750 /* Enabling/Disabling MAC interrupts */
1751 if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
1752 val64 = TXMAC_INT_M | RXMAC_INT_M;
1753 if (flag == ENABLE_INTRS) {
1754 temp64 = readq(&bar0->general_int_mask);
1755 temp64 &= ~((u64) val64);
1756 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001757 /*
1758 * All MAC block error interrupts are disabled for now
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 * TODO
1760 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001762 /*
1763 * Disable MAC Intrs in the general intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 */
1765 writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask);
1766 writeq(DISABLE_ALL_INTRS,
1767 &bar0->mac_rmac_err_mask);
1768
1769 temp64 = readq(&bar0->general_int_mask);
1770 val64 |= temp64;
1771 writeq(val64, &bar0->general_int_mask);
1772 }
1773 }
1774
1775 /* XGXS Interrupts */
1776 if (mask & (TX_XGXS_INTR | RX_XGXS_INTR)) {
1777 val64 = TXXGXS_INT_M | RXXGXS_INT_M;
1778 if (flag == ENABLE_INTRS) {
1779 temp64 = readq(&bar0->general_int_mask);
1780 temp64 &= ~((u64) val64);
1781 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001782 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 * All XGXS block error interrupts are disabled for now
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001784 * TODO
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 */
1786 writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
1787 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001788 /*
1789 * Disable MC Intrs in the general intr mask register
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 */
1791 writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
1792 temp64 = readq(&bar0->general_int_mask);
1793 val64 |= temp64;
1794 writeq(val64, &bar0->general_int_mask);
1795 }
1796 }
1797
1798 /* Memory Controller(MC) interrupts */
1799 if (mask & MC_INTR) {
1800 val64 = MC_INT_M;
1801 if (flag == ENABLE_INTRS) {
1802 temp64 = readq(&bar0->general_int_mask);
1803 temp64 &= ~((u64) val64);
1804 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001805 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001806 * Enable all MC Intrs.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 */
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001808 writeq(0x0, &bar0->mc_int_mask);
1809 writeq(0x0, &bar0->mc_err_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 } else if (flag == DISABLE_INTRS) {
1811 /*
1812 * Disable MC Intrs in the general intr mask register
1813 */
1814 writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask);
1815 temp64 = readq(&bar0->general_int_mask);
1816 val64 |= temp64;
1817 writeq(val64, &bar0->general_int_mask);
1818 }
1819 }
1820
1821
1822 /* Tx traffic interrupts */
1823 if (mask & TX_TRAFFIC_INTR) {
1824 val64 = TXTRAFFIC_INT_M;
1825 if (flag == ENABLE_INTRS) {
1826 temp64 = readq(&bar0->general_int_mask);
1827 temp64 &= ~((u64) val64);
1828 writeq(temp64, &bar0->general_int_mask);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001829 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 * Enable all the Tx side interrupts
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001831 * writing 0 Enables all 64 TX interrupt levels
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 */
1833 writeq(0x0, &bar0->tx_traffic_mask);
1834 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001835 /*
1836 * Disable Tx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 * register.
1838 */
1839 writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask);
1840 temp64 = readq(&bar0->general_int_mask);
1841 val64 |= temp64;
1842 writeq(val64, &bar0->general_int_mask);
1843 }
1844 }
1845
1846 /* Rx traffic interrupts */
1847 if (mask & RX_TRAFFIC_INTR) {
1848 val64 = RXTRAFFIC_INT_M;
1849 if (flag == ENABLE_INTRS) {
1850 temp64 = readq(&bar0->general_int_mask);
1851 temp64 &= ~((u64) val64);
1852 writeq(temp64, &bar0->general_int_mask);
1853 /* writing 0 Enables all 8 RX interrupt levels */
1854 writeq(0x0, &bar0->rx_traffic_mask);
1855 } else if (flag == DISABLE_INTRS) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001856 /*
1857 * Disable Rx Traffic Intrs in the general intr mask
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 * register.
1859 */
1860 writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask);
1861 temp64 = readq(&bar0->general_int_mask);
1862 val64 |= temp64;
1863 writeq(val64, &bar0->general_int_mask);
1864 }
1865 }
1866}
1867
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001868static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001869{
1870 int ret = 0;
1871
1872 if (flag == FALSE) {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001873 if ((!herc && (rev_id >= 4)) || herc) {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001874 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) &&
1875 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1876 ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
1877 ret = 1;
1878 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001879 }else {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001880 if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
1881 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1882 ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
1883 ret = 1;
1884 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001885 }
1886 } else {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001887 if ((!herc && (rev_id >= 4)) || herc) {
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001888 if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
1889 ADAPTER_STATUS_RMAC_PCC_IDLE) &&
1890 (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
1891 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1892 ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
1893 ret = 1;
1894 }
1895 } else {
1896 if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
1897 ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
1898 (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
1899 ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
1900 ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
1901 ret = 1;
1902 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001903 }
1904 }
1905
1906 return ret;
1907}
1908/**
1909 * verify_xena_quiescence - Checks whether the H/W is ready
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 * @val64 : Value read from adapter status register.
1911 * @flag : indicates if the adapter enable bit was ever written once
1912 * before.
1913 * Description: Returns whether the H/W is ready to go or not. Depending
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001914 * on whether adapter enable bit was written or not the comparison
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 * differs and the calling function passes the input argument flag to
1916 * indicate this.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001917 * Return: 1 If xena is quiescence
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 * 0 If Xena is not quiescence
1919 */
1920
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001921static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922{
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001923 int ret = 0, herc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 u64 tmp64 = ~((u64) val64);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001925 int rev_id = get_xena_rev_id(sp->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001927 herc = (sp->device_type == XFRAME_II_DEVICE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 if (!
1929 (tmp64 &
1930 (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY |
1931 ADAPTER_STATUS_PFC_READY | ADAPTER_STATUS_TMAC_BUF_EMPTY |
1932 ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY |
1933 ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK |
1934 ADAPTER_STATUS_P_PLL_LOCK))) {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001935 ret = check_prc_pcc_state(val64, flag, rev_id, herc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 }
1937
1938 return ret;
1939}
1940
1941/**
1942 * fix_mac_address - Fix for Mac addr problem on Alpha platforms
1943 * @sp: Pointer to device specifc structure
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001944 * Description :
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 * New procedure to clear mac address reading problems on Alpha platforms
1946 *
1947 */
1948
Adrian Bunkac1f60d2005-11-06 01:46:47 +01001949static void fix_mac_address(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950{
1951 XENA_dev_config_t __iomem *bar0 = sp->bar0;
1952 u64 val64;
1953 int i = 0;
1954
1955 while (fix_mac[i] != END_SIGN) {
1956 writeq(fix_mac[i++], &bar0->gpio_control);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001957 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 val64 = readq(&bar0->gpio_control);
1959 }
1960}
1961
1962/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001963 * start_nic - Turns the device on
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001965 * Description:
1966 * This function actually turns the device on. Before this function is
1967 * called,all Registers are configured from their reset states
1968 * and shared memory is allocated but the NIC is still quiescent. On
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 * calling this function, the device interrupts are cleared and the NIC is
1970 * literally switched on by writing into the adapter control register.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001971 * Return Value:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 * SUCCESS on success and -1 on failure.
1973 */
1974
1975static int start_nic(struct s2io_nic *nic)
1976{
1977 XENA_dev_config_t __iomem *bar0 = nic->bar0;
1978 struct net_device *dev = nic->dev;
1979 register u64 val64 = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001980 u16 interruptible;
1981 u16 subid, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 mac_info_t *mac_control;
1983 struct config_param *config;
1984
1985 mac_control = &nic->mac_control;
1986 config = &nic->config;
1987
1988 /* PRC Initialization and configuration */
1989 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001990 writeq((u64) mac_control->rings[i].rx_blocks[0].block_dma_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 &bar0->prc_rxd0_n[i]);
1992
1993 val64 = readq(&bar0->prc_ctrl_n[i]);
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07001994 if (nic->config.bimodal)
1995 val64 |= PRC_CTRL_BIMODAL_INTERRUPT;
Ananda Rajuda6971d2005-10-31 16:55:31 -05001996 if (nic->rxd_mode == RXD_MODE_1)
1997 val64 |= PRC_CTRL_RC_ENABLED;
1998 else
1999 val64 |= PRC_CTRL_RC_ENABLED | PRC_CTRL_RING_MODE_3;
Ananda Raju863c11a2006-04-21 19:03:13 -04002000 if (nic->device_type == XFRAME_II_DEVICE)
2001 val64 |= PRC_CTRL_GROUP_READS;
2002 val64 &= ~PRC_CTRL_RXD_BACKOFF_INTERVAL(0xFFFFFF);
2003 val64 |= PRC_CTRL_RXD_BACKOFF_INTERVAL(0x1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 writeq(val64, &bar0->prc_ctrl_n[i]);
2005 }
2006
Ananda Rajuda6971d2005-10-31 16:55:31 -05002007 if (nic->rxd_mode == RXD_MODE_3B) {
2008 /* Enabling 2 buffer mode by writing into Rx_pa_cfg reg. */
2009 val64 = readq(&bar0->rx_pa_cfg);
2010 val64 |= RX_PA_CFG_IGNORE_L2_ERR;
2011 writeq(val64, &bar0->rx_pa_cfg);
2012 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002014 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 * Enabling MC-RLDRAM. After enabling the device, we timeout
2016 * for around 100ms, which is approximately the time required
2017 * for the device to be ready for operation.
2018 */
2019 val64 = readq(&bar0->mc_rldram_mrs);
2020 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE | MC_RLDRAM_MRS_ENABLE;
2021 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
2022 val64 = readq(&bar0->mc_rldram_mrs);
2023
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002024 msleep(100); /* Delay by around 100 ms. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025
2026 /* Enabling ECC Protection. */
2027 val64 = readq(&bar0->adapter_control);
2028 val64 &= ~ADAPTER_ECC_EN;
2029 writeq(val64, &bar0->adapter_control);
2030
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002031 /*
2032 * Clearing any possible Link state change interrupts that
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 * could have popped up just before Enabling the card.
2034 */
2035 val64 = readq(&bar0->mac_rmac_err_reg);
2036 if (val64)
2037 writeq(val64, &bar0->mac_rmac_err_reg);
2038
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002039 /*
2040 * Verify if the device is ready to be enabled, if so enable
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 * it.
2042 */
2043 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002044 if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name);
2046 DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n",
2047 (unsigned long long) val64);
2048 return FAILURE;
2049 }
2050
2051 /* Enable select interrupts */
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04002052 if (nic->intr_type != INTA)
2053 en_dis_able_nic_intrs(nic, ENA_ALL_INTRS, DISABLE_INTRS);
2054 else {
2055 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
2056 interruptible |= TX_PIC_INTR | RX_PIC_INTR;
2057 interruptible |= TX_MAC_INTR | RX_MAC_INTR;
2058 en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS);
2059 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002061 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 * With some switches, link might be already up at this point.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002063 * Because of this weird behavior, when we enable laser,
2064 * we may not get link. We need to handle this. We cannot
2065 * figure out which switch is misbehaving. So we are forced to
2066 * make a global change.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 */
2068
2069 /* Enabling Laser. */
2070 val64 = readq(&bar0->adapter_control);
2071 val64 |= ADAPTER_EOI_TX_ON;
2072 writeq(val64, &bar0->adapter_control);
2073
Ananda Rajuc92ca042006-04-21 19:18:03 -04002074 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
2075 /*
2076 * Dont see link state interrupts initally on some switches,
2077 * so directly scheduling the link state task here.
2078 */
2079 schedule_work(&nic->set_link_task);
2080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 /* SXE-002: Initialize link and activity LED */
2082 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07002083 if (((subid & 0xFF) >= 0x07) &&
2084 (nic->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 val64 = readq(&bar0->gpio_control);
2086 val64 |= 0x0000800000000000ULL;
2087 writeq(val64, &bar0->gpio_control);
2088 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01002089 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 }
2091
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 return SUCCESS;
2093}
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002094/**
2095 * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb
2096 */
2097static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, int get_off)
2098{
2099 nic_t *nic = fifo_data->nic;
2100 struct sk_buff *skb;
2101 TxD_t *txds;
2102 u16 j, frg_cnt;
2103
2104 txds = txdlp;
Andrew Morton26b76252005-12-14 19:25:23 -08002105 if (txds->Host_Control == (u64)(long)nic->ufo_in_band_v) {
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002106 pci_unmap_single(nic->pdev, (dma_addr_t)
2107 txds->Buffer_Pointer, sizeof(u64),
2108 PCI_DMA_TODEVICE);
2109 txds++;
2110 }
2111
2112 skb = (struct sk_buff *) ((unsigned long)
2113 txds->Host_Control);
2114 if (!skb) {
2115 memset(txdlp, 0, (sizeof(TxD_t) * fifo_data->max_txds));
2116 return NULL;
2117 }
2118 pci_unmap_single(nic->pdev, (dma_addr_t)
2119 txds->Buffer_Pointer,
2120 skb->len - skb->data_len,
2121 PCI_DMA_TODEVICE);
2122 frg_cnt = skb_shinfo(skb)->nr_frags;
2123 if (frg_cnt) {
2124 txds++;
2125 for (j = 0; j < frg_cnt; j++, txds++) {
2126 skb_frag_t *frag = &skb_shinfo(skb)->frags[j];
2127 if (!txds->Buffer_Pointer)
2128 break;
2129 pci_unmap_page(nic->pdev, (dma_addr_t)
2130 txds->Buffer_Pointer,
2131 frag->size, PCI_DMA_TODEVICE);
2132 }
2133 }
2134 txdlp->Host_Control = 0;
2135 return(skb);
2136}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002138/**
2139 * free_tx_buffers - Free all queued Tx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 * @nic : device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002141 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 * Free all queued Tx buffers.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002143 * Return Value: void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144*/
2145
2146static void free_tx_buffers(struct s2io_nic *nic)
2147{
2148 struct net_device *dev = nic->dev;
2149 struct sk_buff *skb;
2150 TxD_t *txdp;
2151 int i, j;
2152 mac_info_t *mac_control;
2153 struct config_param *config;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002154 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155
2156 mac_control = &nic->mac_control;
2157 config = &nic->config;
2158
2159 for (i = 0; i < config->tx_fifo_num; i++) {
2160 for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002161 txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 list_virt_addr;
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002163 skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
2164 if (skb) {
2165 dev_kfree_skb(skb);
2166 cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 }
2169 DBG_PRINT(INTR_DBG,
2170 "%s:forcibly freeing %d skbs on FIFO%d\n",
2171 dev->name, cnt, i);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002172 mac_control->fifos[i].tx_curr_get_info.offset = 0;
2173 mac_control->fifos[i].tx_curr_put_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 }
2175}
2176
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002177/**
2178 * stop_nic - To stop the nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 * @nic ; device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002180 * Description:
2181 * This function does exactly the opposite of what the start_nic()
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 * function does. This function is called to stop the device.
2183 * Return Value:
2184 * void.
2185 */
2186
2187static void stop_nic(struct s2io_nic *nic)
2188{
2189 XENA_dev_config_t __iomem *bar0 = nic->bar0;
2190 register u64 val64 = 0;
Ananda Raju5d3213c2006-04-21 19:23:26 -04002191 u16 interruptible;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 mac_info_t *mac_control;
2193 struct config_param *config;
2194
2195 mac_control = &nic->mac_control;
2196 config = &nic->config;
2197
2198 /* Disable all interrupts */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07002199 interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07002200 interruptible |= TX_PIC_INTR | RX_PIC_INTR;
2201 interruptible |= TX_MAC_INTR | RX_MAC_INTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
2203
Ananda Raju5d3213c2006-04-21 19:23:26 -04002204 /* Clearing Adapter_En bit of ADAPTER_CONTROL Register */
2205 val64 = readq(&bar0->adapter_control);
2206 val64 &= ~(ADAPTER_CNTL_EN);
2207 writeq(val64, &bar0->adapter_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208}
2209
Adrian Bunk26df54b2006-01-14 03:09:40 +01002210static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
Ananda Rajuda6971d2005-10-31 16:55:31 -05002211{
2212 struct net_device *dev = nic->dev;
2213 struct sk_buff *frag_list;
Jeff Garzik50eb8002005-11-05 23:40:46 -05002214 void *tmp;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002215
2216 /* Buffer-1 receives L3/L4 headers */
2217 ((RxD3_t*)rxdp)->Buffer1_ptr = pci_map_single
2218 (nic->pdev, skb->data, l3l4hdr_size + 4,
2219 PCI_DMA_FROMDEVICE);
2220
2221 /* skb_shinfo(skb)->frag_list will have L4 data payload */
2222 skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE);
2223 if (skb_shinfo(skb)->frag_list == NULL) {
2224 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
2225 return -ENOMEM ;
2226 }
2227 frag_list = skb_shinfo(skb)->frag_list;
2228 frag_list->next = NULL;
Jeff Garzik50eb8002005-11-05 23:40:46 -05002229 tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
2230 frag_list->data = tmp;
2231 frag_list->tail = tmp;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002232
2233 /* Buffer-2 receives L4 data payload */
2234 ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
2235 frag_list->data, dev->mtu,
2236 PCI_DMA_FROMDEVICE);
2237 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
2238 rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
2239
2240 return SUCCESS;
2241}
2242
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002243/**
2244 * fill_rx_buffers - Allocates the Rx side skbs
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002246 * @ring_no: ring number
2247 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 * The function allocates Rx side skbs and puts the physical
2249 * address of these buffers into the RxD buffer pointers, so that the NIC
2250 * can DMA the received frame into these locations.
2251 * The NIC supports 3 receive modes, viz
2252 * 1. single buffer,
2253 * 2. three buffer and
2254 * 3. Five buffer modes.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002255 * Each mode defines how many fragments the received frame will be split
2256 * up into by the NIC. The frame is split into L3 header, L4 Header,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 * L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself
2258 * is split into 3 fragments. As of now only single buffer mode is
2259 * supported.
2260 * Return Value:
2261 * SUCCESS on success or an appropriate -ve value on failure.
2262 */
2263
Adrian Bunkac1f60d2005-11-06 01:46:47 +01002264static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265{
2266 struct net_device *dev = nic->dev;
2267 struct sk_buff *skb;
2268 RxD_t *rxdp;
2269 int off, off1, size, block_no, block_no1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 u32 alloc_tab = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002271 u32 alloc_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 mac_info_t *mac_control;
2273 struct config_param *config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002274 u64 tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 buffAdd_t *ba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276#ifndef CONFIG_S2IO_NAPI
2277 unsigned long flags;
2278#endif
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002279 RxD_t *first_rxdp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280
2281 mac_control = &nic->mac_control;
2282 config = &nic->config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002283 alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
2284 atomic_read(&nic->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285
Ananda Raju5d3213c2006-04-21 19:23:26 -04002286 block_no1 = mac_control->rings[ring_no].rx_curr_get_info.block_index;
Ananda Raju863c11a2006-04-21 19:03:13 -04002287 off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 while (alloc_tab < alloc_cnt) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002289 block_no = mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 block_index;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002291 off = mac_control->rings[ring_no].rx_curr_put_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
Ananda Rajuda6971d2005-10-31 16:55:31 -05002293 rxdp = mac_control->rings[ring_no].
2294 rx_blocks[block_no].rxds[off].virt_addr;
2295
2296 if ((block_no == block_no1) && (off == off1) &&
2297 (rxdp->Host_Control)) {
2298 DBG_PRINT(INTR_DBG, "%s: Get and Put",
2299 dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 DBG_PRINT(INTR_DBG, " info equated\n");
2301 goto end;
2302 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002303 if (off && (off == rxd_count[nic->rxd_mode])) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002304 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 block_index++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002306 if (mac_control->rings[ring_no].rx_curr_put_info.
2307 block_index == mac_control->rings[ring_no].
2308 block_count)
2309 mac_control->rings[ring_no].rx_curr_put_info.
2310 block_index = 0;
2311 block_no = mac_control->rings[ring_no].
2312 rx_curr_put_info.block_index;
2313 if (off == rxd_count[nic->rxd_mode])
2314 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002315 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002316 offset = off;
2317 rxdp = mac_control->rings[ring_no].
2318 rx_blocks[block_no].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
2320 dev->name, rxdp);
2321 }
2322#ifndef CONFIG_S2IO_NAPI
2323 spin_lock_irqsave(&nic->put_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002324 mac_control->rings[ring_no].put_pos =
Ananda Rajuda6971d2005-10-31 16:55:31 -05002325 (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 spin_unlock_irqrestore(&nic->put_lock, flags);
2327#endif
Ananda Rajuda6971d2005-10-31 16:55:31 -05002328 if ((rxdp->Control_1 & RXD_OWN_XENA) &&
2329 ((nic->rxd_mode >= RXD_MODE_3A) &&
2330 (rxdp->Control_2 & BIT(0)))) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002331 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002332 offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 goto end;
2334 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002335 /* calculate size of skb based on ring mode */
2336 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
2337 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
2338 if (nic->rxd_mode == RXD_MODE_1)
2339 size += NET_IP_ALIGN;
2340 else if (nic->rxd_mode == RXD_MODE_3B)
2341 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
2342 else
2343 size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
Ananda Rajuda6971d2005-10-31 16:55:31 -05002345 /* allocate skb */
2346 skb = dev_alloc_skb(size);
2347 if(!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
2349 DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002350 if (first_rxdp) {
2351 wmb();
2352 first_rxdp->Control_1 |= RXD_OWN_XENA;
2353 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002354 return -ENOMEM ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002356 if (nic->rxd_mode == RXD_MODE_1) {
2357 /* 1 buffer mode - normal operation mode */
2358 memset(rxdp, 0, sizeof(RxD1_t));
2359 skb_reserve(skb, NET_IP_ALIGN);
2360 ((RxD1_t*)rxdp)->Buffer0_ptr = pci_map_single
Ananda Raju863c11a2006-04-21 19:03:13 -04002361 (nic->pdev, skb->data, size - NET_IP_ALIGN,
2362 PCI_DMA_FROMDEVICE);
2363 rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002364
2365 } else if (nic->rxd_mode >= RXD_MODE_3A) {
2366 /*
2367 * 2 or 3 buffer mode -
2368 * Both 2 buffer mode and 3 buffer mode provides 128
2369 * byte aligned receive buffers.
2370 *
2371 * 3 buffer mode provides header separation where in
2372 * skb->data will have L3/L4 headers where as
2373 * skb_shinfo(skb)->frag_list will have the L4 data
2374 * payload
2375 */
2376
2377 memset(rxdp, 0, sizeof(RxD3_t));
2378 ba = &mac_control->rings[ring_no].ba[block_no][off];
2379 skb_reserve(skb, BUF0_LEN);
2380 tmp = (u64)(unsigned long) skb->data;
2381 tmp += ALIGN_SIZE;
2382 tmp &= ~ALIGN_SIZE;
2383 skb->data = (void *) (unsigned long)tmp;
2384 skb->tail = (void *) (unsigned long)tmp;
2385
2386 ((RxD3_t*)rxdp)->Buffer0_ptr =
2387 pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
2388 PCI_DMA_FROMDEVICE);
2389 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
2390 if (nic->rxd_mode == RXD_MODE_3B) {
2391 /* Two buffer mode */
2392
2393 /*
2394 * Buffer2 will have L3/L4 header plus
2395 * L4 payload
2396 */
2397 ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single
2398 (nic->pdev, skb->data, dev->mtu + 4,
2399 PCI_DMA_FROMDEVICE);
2400
2401 /* Buffer-1 will be dummy buffer not used */
2402 ((RxD3_t*)rxdp)->Buffer1_ptr =
2403 pci_map_single(nic->pdev, ba->ba_1, BUF1_LEN,
2404 PCI_DMA_FROMDEVICE);
2405 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
2406 rxdp->Control_2 |= SET_BUFFER2_SIZE_3
2407 (dev->mtu + 4);
2408 } else {
2409 /* 3 buffer mode */
2410 if (fill_rxd_3buf(nic, rxdp, skb) == -ENOMEM) {
2411 dev_kfree_skb_irq(skb);
2412 if (first_rxdp) {
2413 wmb();
2414 first_rxdp->Control_1 |=
2415 RXD_OWN_XENA;
2416 }
2417 return -ENOMEM ;
2418 }
2419 }
2420 rxdp->Control_2 |= BIT(0);
2421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 rxdp->Host_Control = (unsigned long) (skb);
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002423 if (alloc_tab & ((1 << rxsync_frequency) - 1))
2424 rxdp->Control_1 |= RXD_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 off++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002426 if (off == (rxd_count[nic->rxd_mode] + 1))
2427 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002428 mac_control->rings[ring_no].rx_curr_put_info.offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002430 rxdp->Control_2 |= SET_RXD_MARKER;
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002431 if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
2432 if (first_rxdp) {
2433 wmb();
2434 first_rxdp->Control_1 |= RXD_OWN_XENA;
2435 }
2436 first_rxdp = rxdp;
2437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 atomic_inc(&nic->rx_bufs_left[ring_no]);
2439 alloc_tab++;
2440 }
2441
2442 end:
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002443 /* Transfer ownership of first descriptor to adapter just before
2444 * exiting. Before that, use memory barrier so that ownership
2445 * and other fields are seen by adapter correctly.
2446 */
2447 if (first_rxdp) {
2448 wmb();
2449 first_rxdp->Control_1 |= RXD_OWN_XENA;
2450 }
2451
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 return SUCCESS;
2453}
2454
Ananda Rajuda6971d2005-10-31 16:55:31 -05002455static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
2456{
2457 struct net_device *dev = sp->dev;
2458 int j;
2459 struct sk_buff *skb;
2460 RxD_t *rxdp;
2461 mac_info_t *mac_control;
2462 buffAdd_t *ba;
2463
2464 mac_control = &sp->mac_control;
2465 for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
2466 rxdp = mac_control->rings[ring_no].
2467 rx_blocks[blk].rxds[j].virt_addr;
2468 skb = (struct sk_buff *)
2469 ((unsigned long) rxdp->Host_Control);
2470 if (!skb) {
2471 continue;
2472 }
2473 if (sp->rxd_mode == RXD_MODE_1) {
2474 pci_unmap_single(sp->pdev, (dma_addr_t)
2475 ((RxD1_t*)rxdp)->Buffer0_ptr,
2476 dev->mtu +
2477 HEADER_ETHERNET_II_802_3_SIZE
2478 + HEADER_802_2_SIZE +
2479 HEADER_SNAP_SIZE,
2480 PCI_DMA_FROMDEVICE);
2481 memset(rxdp, 0, sizeof(RxD1_t));
2482 } else if(sp->rxd_mode == RXD_MODE_3B) {
2483 ba = &mac_control->rings[ring_no].
2484 ba[blk][j];
2485 pci_unmap_single(sp->pdev, (dma_addr_t)
2486 ((RxD3_t*)rxdp)->Buffer0_ptr,
2487 BUF0_LEN,
2488 PCI_DMA_FROMDEVICE);
2489 pci_unmap_single(sp->pdev, (dma_addr_t)
2490 ((RxD3_t*)rxdp)->Buffer1_ptr,
2491 BUF1_LEN,
2492 PCI_DMA_FROMDEVICE);
2493 pci_unmap_single(sp->pdev, (dma_addr_t)
2494 ((RxD3_t*)rxdp)->Buffer2_ptr,
2495 dev->mtu + 4,
2496 PCI_DMA_FROMDEVICE);
2497 memset(rxdp, 0, sizeof(RxD3_t));
2498 } else {
2499 pci_unmap_single(sp->pdev, (dma_addr_t)
2500 ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
2501 PCI_DMA_FROMDEVICE);
2502 pci_unmap_single(sp->pdev, (dma_addr_t)
2503 ((RxD3_t*)rxdp)->Buffer1_ptr,
2504 l3l4hdr_size + 4,
2505 PCI_DMA_FROMDEVICE);
2506 pci_unmap_single(sp->pdev, (dma_addr_t)
2507 ((RxD3_t*)rxdp)->Buffer2_ptr, dev->mtu,
2508 PCI_DMA_FROMDEVICE);
2509 memset(rxdp, 0, sizeof(RxD3_t));
2510 }
2511 dev_kfree_skb(skb);
2512 atomic_dec(&sp->rx_bufs_left[ring_no]);
2513 }
2514}
2515
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002517 * free_rx_buffers - Frees all Rx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 * @sp: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002519 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 * This function will free all Rx buffers allocated by host.
2521 * Return Value:
2522 * NONE.
2523 */
2524
2525static void free_rx_buffers(struct s2io_nic *sp)
2526{
2527 struct net_device *dev = sp->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002528 int i, blk = 0, buf_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 mac_info_t *mac_control;
2530 struct config_param *config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
2532 mac_control = &sp->mac_control;
2533 config = &sp->config;
2534
2535 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -05002536 for (blk = 0; blk < rx_ring_sz[i]; blk++)
2537 free_rxd_blk(sp,i,blk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002539 mac_control->rings[i].rx_curr_put_info.block_index = 0;
2540 mac_control->rings[i].rx_curr_get_info.block_index = 0;
2541 mac_control->rings[i].rx_curr_put_info.offset = 0;
2542 mac_control->rings[i].rx_curr_get_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 atomic_set(&sp->rx_bufs_left[i], 0);
2544 DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
2545 dev->name, buf_cnt, i);
2546 }
2547}
2548
2549/**
2550 * s2io_poll - Rx interrupt handler for NAPI support
2551 * @dev : pointer to the device structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002552 * @budget : The number of packets that were budgeted to be processed
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 * during one pass through the 'Poll" function.
2554 * Description:
2555 * Comes into picture only if NAPI support has been incorporated. It does
2556 * the same thing that rx_intr_handler does, but not in a interrupt context
2557 * also It will process only a given number of packets.
2558 * Return value:
2559 * 0 on success and 1 if there are No Rx packets to be processed.
2560 */
2561
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002562#if defined(CONFIG_S2IO_NAPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563static int s2io_poll(struct net_device *dev, int *budget)
2564{
2565 nic_t *nic = dev->priv;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002566 int pkt_cnt = 0, org_pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 mac_info_t *mac_control;
2568 struct config_param *config;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01002569 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ananda Raju863c11a2006-04-21 19:03:13 -04002570 u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002571 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002573 atomic_inc(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 mac_control = &nic->mac_control;
2575 config = &nic->config;
2576
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002577 nic->pkts_to_process = *budget;
2578 if (nic->pkts_to_process > dev->quota)
2579 nic->pkts_to_process = dev->quota;
2580 org_pkts_to_process = nic->pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 writeq(val64, &bar0->rx_traffic_int);
Ananda Raju863c11a2006-04-21 19:03:13 -04002583 val64 = readl(&bar0->rx_traffic_int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584
2585 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002586 rx_intr_handler(&mac_control->rings[i]);
2587 pkt_cnt = org_pkts_to_process - nic->pkts_to_process;
2588 if (!nic->pkts_to_process) {
2589 /* Quota for the current iteration has been met */
2590 goto no_rx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 }
2593 if (!pkt_cnt)
2594 pkt_cnt = 1;
2595
2596 dev->quota -= pkt_cnt;
2597 *budget -= pkt_cnt;
2598 netif_rx_complete(dev);
2599
2600 for (i = 0; i < config->rx_ring_num; i++) {
2601 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2602 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2603 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2604 break;
2605 }
2606 }
2607 /* Re enable the Rx interrupts. */
Ananda Rajuc92ca042006-04-21 19:18:03 -04002608 writeq(0x0, &bar0->rx_traffic_mask);
2609 val64 = readl(&bar0->rx_traffic_mask);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002610 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 return 0;
2612
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002613no_rx:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 dev->quota -= pkt_cnt;
2615 *budget -= pkt_cnt;
2616
2617 for (i = 0; i < config->rx_ring_num; i++) {
2618 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2619 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2620 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2621 break;
2622 }
2623 }
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002624 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 return 1;
2626}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002627#endif
2628
2629/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 * rx_intr_handler - Rx interrupt handler
2631 * @nic: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002632 * Description:
2633 * If the interrupt is because of a received frame or if the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 * receive ring contains fresh as yet un-processed frames,this function is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002635 * called. It picks out the RxD at which place the last Rx processing had
2636 * stopped and sends the skb to the OSM's Rx handler and then increments
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 * the offset.
2638 * Return Value:
2639 * NONE.
2640 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002641static void rx_intr_handler(ring_info_t *ring_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002643 nic_t *nic = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 struct net_device *dev = (struct net_device *) nic->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002645 int get_block, put_block, put_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 rx_curr_get_info_t get_info, put_info;
2647 RxD_t *rxdp;
2648 struct sk_buff *skb;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002649#ifndef CONFIG_S2IO_NAPI
2650 int pkt_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651#endif
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002652 int i;
2653
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002654 spin_lock(&nic->rx_lock);
2655 if (atomic_read(&nic->card_state) == CARD_DOWN) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002656 DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002657 __FUNCTION__, dev->name);
2658 spin_unlock(&nic->rx_lock);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002659 return;
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002660 }
2661
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002662 get_info = ring_data->rx_curr_get_info;
2663 get_block = get_info.block_index;
2664 put_info = ring_data->rx_curr_put_info;
2665 put_block = put_info.block_index;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002666 rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002667#ifndef CONFIG_S2IO_NAPI
2668 spin_lock(&nic->put_lock);
2669 put_offset = ring_data->put_pos;
2670 spin_unlock(&nic->put_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671#else
Ananda Rajuda6971d2005-10-31 16:55:31 -05002672 put_offset = (put_block * (rxd_count[nic->rxd_mode] + 1)) +
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002673 put_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674#endif
Ananda Rajuda6971d2005-10-31 16:55:31 -05002675 while (RXD_IS_UP2DT(rxdp)) {
2676 /* If your are next to put index then it's FIFO full condition */
2677 if ((get_block == put_block) &&
2678 (get_info.offset + 1) == put_info.offset) {
2679 DBG_PRINT(ERR_DBG, "%s: Ring Full\n",dev->name);
2680 break;
2681 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002682 skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
2683 if (skb == NULL) {
2684 DBG_PRINT(ERR_DBG, "%s: The skb is ",
2685 dev->name);
2686 DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002687 spin_unlock(&nic->rx_lock);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002688 return;
2689 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002690 if (nic->rxd_mode == RXD_MODE_1) {
2691 pci_unmap_single(nic->pdev, (dma_addr_t)
2692 ((RxD1_t*)rxdp)->Buffer0_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002693 dev->mtu +
2694 HEADER_ETHERNET_II_802_3_SIZE +
2695 HEADER_802_2_SIZE +
2696 HEADER_SNAP_SIZE,
2697 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002698 } else if (nic->rxd_mode == RXD_MODE_3B) {
2699 pci_unmap_single(nic->pdev, (dma_addr_t)
2700 ((RxD3_t*)rxdp)->Buffer0_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002701 BUF0_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002702 pci_unmap_single(nic->pdev, (dma_addr_t)
2703 ((RxD3_t*)rxdp)->Buffer1_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002704 BUF1_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002705 pci_unmap_single(nic->pdev, (dma_addr_t)
2706 ((RxD3_t*)rxdp)->Buffer2_ptr,
2707 dev->mtu + 4,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002708 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002709 } else {
2710 pci_unmap_single(nic->pdev, (dma_addr_t)
2711 ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
2712 PCI_DMA_FROMDEVICE);
2713 pci_unmap_single(nic->pdev, (dma_addr_t)
2714 ((RxD3_t*)rxdp)->Buffer1_ptr,
2715 l3l4hdr_size + 4,
2716 PCI_DMA_FROMDEVICE);
2717 pci_unmap_single(nic->pdev, (dma_addr_t)
2718 ((RxD3_t*)rxdp)->Buffer2_ptr,
2719 dev->mtu, PCI_DMA_FROMDEVICE);
2720 }
Ananda Raju863c11a2006-04-21 19:03:13 -04002721 prefetch(skb->data);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002722 rx_osm_handler(ring_data, rxdp);
2723 get_info.offset++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002724 ring_data->rx_curr_get_info.offset = get_info.offset;
2725 rxdp = ring_data->rx_blocks[get_block].
2726 rxds[get_info.offset].virt_addr;
2727 if (get_info.offset == rxd_count[nic->rxd_mode]) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002728 get_info.offset = 0;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002729 ring_data->rx_curr_get_info.offset = get_info.offset;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002730 get_block++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002731 if (get_block == ring_data->block_count)
2732 get_block = 0;
2733 ring_data->rx_curr_get_info.block_index = get_block;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002734 rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
2735 }
2736
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002737#ifdef CONFIG_S2IO_NAPI
2738 nic->pkts_to_process -= 1;
2739 if (!nic->pkts_to_process)
2740 break;
2741#else
2742 pkt_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
2744 break;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002745#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002747 if (nic->lro) {
2748 /* Clear all LRO sessions before exiting */
2749 for (i=0; i<MAX_LRO_SESSIONS; i++) {
2750 lro_t *lro = &nic->lro0_n[i];
2751 if (lro->in_use) {
2752 update_L3L4_header(nic, lro);
2753 queue_rx_frame(lro->parent);
2754 clear_lro_session(lro);
2755 }
2756 }
2757 }
2758
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002759 spin_unlock(&nic->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002761
2762/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 * tx_intr_handler - Transmit interrupt handler
2764 * @nic : device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002765 * Description:
2766 * If an interrupt was raised to indicate DMA complete of the
2767 * Tx packet, this function is called. It identifies the last TxD
2768 * whose buffer was freed and frees all skbs whose data have already
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 * DMA'ed into the NICs internal memory.
2770 * Return Value:
2771 * NONE
2772 */
2773
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002774static void tx_intr_handler(fifo_info_t *fifo_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002776 nic_t *nic = fifo_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 struct net_device *dev = (struct net_device *) nic->dev;
2778 tx_curr_get_info_t get_info, put_info;
2779 struct sk_buff *skb;
2780 TxD_t *txdlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002782 get_info = fifo_data->tx_curr_get_info;
2783 put_info = fifo_data->tx_curr_put_info;
2784 txdlp = (TxD_t *) fifo_data->list_info[get_info.offset].
2785 list_virt_addr;
2786 while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
2787 (get_info.offset != put_info.offset) &&
2788 (txdlp->Host_Control)) {
2789 /* Check for TxD errors */
2790 if (txdlp->Control_1 & TXD_T_CODE) {
2791 unsigned long long err;
2792 err = txdlp->Control_1 & TXD_T_CODE;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002793 if (err & 0x1) {
2794 nic->mac_control.stats_info->sw_stat.
2795 parity_err_cnt++;
2796 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002797 if ((err >> 48) == 0xA) {
2798 DBG_PRINT(TX_DBG, "TxD returned due \
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04002799to loss of link\n");
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002800 }
2801 else {
2802 DBG_PRINT(ERR_DBG, "***TxD error \
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04002803%llx\n", err);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002804 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002806
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002807 skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002808 if (skb == NULL) {
2809 DBG_PRINT(ERR_DBG, "%s: Null skb ",
2810 __FUNCTION__);
2811 DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
2812 return;
2813 }
2814
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002815 /* Updating the statistics block */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002816 nic->stats.tx_bytes += skb->len;
2817 dev_kfree_skb_irq(skb);
2818
2819 get_info.offset++;
Ananda Raju863c11a2006-04-21 19:03:13 -04002820 if (get_info.offset == get_info.fifo_len + 1)
2821 get_info.offset = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002822 txdlp = (TxD_t *) fifo_data->list_info
2823 [get_info.offset].list_virt_addr;
2824 fifo_data->tx_curr_get_info.offset =
2825 get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 }
2827
2828 spin_lock(&nic->tx_lock);
2829 if (netif_queue_stopped(dev))
2830 netif_wake_queue(dev);
2831 spin_unlock(&nic->tx_lock);
2832}
2833
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002834/**
Ananda Rajubd1034f2006-04-21 19:20:22 -04002835 * s2io_mdio_write - Function to write in to MDIO registers
2836 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
2837 * @addr : address value
2838 * @value : data value
2839 * @dev : pointer to net_device structure
2840 * Description:
2841 * This function is used to write values to the MDIO registers
2842 * NONE
2843 */
2844static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
2845{
2846 u64 val64 = 0x0;
2847 nic_t *sp = dev->priv;
2848 XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
2849
2850 //address transaction
2851 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2852 | MDIO_MMD_DEV_ADDR(mmd_type)
2853 | MDIO_MMS_PRT_ADDR(0x0);
2854 writeq(val64, &bar0->mdio_control);
2855 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2856 writeq(val64, &bar0->mdio_control);
2857 udelay(100);
2858
2859 //Data transaction
2860 val64 = 0x0;
2861 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2862 | MDIO_MMD_DEV_ADDR(mmd_type)
2863 | MDIO_MMS_PRT_ADDR(0x0)
2864 | MDIO_MDIO_DATA(value)
2865 | MDIO_OP(MDIO_OP_WRITE_TRANS);
2866 writeq(val64, &bar0->mdio_control);
2867 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2868 writeq(val64, &bar0->mdio_control);
2869 udelay(100);
2870
2871 val64 = 0x0;
2872 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2873 | MDIO_MMD_DEV_ADDR(mmd_type)
2874 | MDIO_MMS_PRT_ADDR(0x0)
2875 | MDIO_OP(MDIO_OP_READ_TRANS);
2876 writeq(val64, &bar0->mdio_control);
2877 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2878 writeq(val64, &bar0->mdio_control);
2879 udelay(100);
2880
2881}
2882
2883/**
2884 * s2io_mdio_read - Function to write in to MDIO registers
2885 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
2886 * @addr : address value
2887 * @dev : pointer to net_device structure
2888 * Description:
2889 * This function is used to read values to the MDIO registers
2890 * NONE
2891 */
2892static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
2893{
2894 u64 val64 = 0x0;
2895 u64 rval64 = 0x0;
2896 nic_t *sp = dev->priv;
2897 XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
2898
2899 /* address transaction */
2900 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2901 | MDIO_MMD_DEV_ADDR(mmd_type)
2902 | MDIO_MMS_PRT_ADDR(0x0);
2903 writeq(val64, &bar0->mdio_control);
2904 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2905 writeq(val64, &bar0->mdio_control);
2906 udelay(100);
2907
2908 /* Data transaction */
2909 val64 = 0x0;
2910 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2911 | MDIO_MMD_DEV_ADDR(mmd_type)
2912 | MDIO_MMS_PRT_ADDR(0x0)
2913 | MDIO_OP(MDIO_OP_READ_TRANS);
2914 writeq(val64, &bar0->mdio_control);
2915 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2916 writeq(val64, &bar0->mdio_control);
2917 udelay(100);
2918
2919 /* Read the value from regs */
2920 rval64 = readq(&bar0->mdio_control);
2921 rval64 = rval64 & 0xFFFF0000;
2922 rval64 = rval64 >> 16;
2923 return rval64;
2924}
2925/**
2926 * s2io_chk_xpak_counter - Function to check the status of the xpak counters
2927 * @counter : couter value to be updated
2928 * @flag : flag to indicate the status
2929 * @type : counter type
2930 * Description:
2931 * This function is to check the status of the xpak counters value
2932 * NONE
2933 */
2934
2935static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, u16 flag, u16 type)
2936{
2937 u64 mask = 0x3;
2938 u64 val64;
2939 int i;
2940 for(i = 0; i <index; i++)
2941 mask = mask << 0x2;
2942
2943 if(flag > 0)
2944 {
2945 *counter = *counter + 1;
2946 val64 = *regs_stat & mask;
2947 val64 = val64 >> (index * 0x2);
2948 val64 = val64 + 1;
2949 if(val64 == 3)
2950 {
2951 switch(type)
2952 {
2953 case 1:
2954 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
2955 "service. Excessive temperatures may "
2956 "result in premature transceiver "
2957 "failure \n");
2958 break;
2959 case 2:
2960 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
2961 "service Excessive bias currents may "
2962 "indicate imminent laser diode "
2963 "failure \n");
2964 break;
2965 case 3:
2966 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
2967 "service Excessive laser output "
2968 "power may saturate far-end "
2969 "receiver\n");
2970 break;
2971 default:
2972 DBG_PRINT(ERR_DBG, "Incorrect XPAK Alarm "
2973 "type \n");
2974 }
2975 val64 = 0x0;
2976 }
2977 val64 = val64 << (index * 0x2);
2978 *regs_stat = (*regs_stat & (~mask)) | (val64);
2979
2980 } else {
2981 *regs_stat = *regs_stat & (~mask);
2982 }
2983}
2984
2985/**
2986 * s2io_updt_xpak_counter - Function to update the xpak counters
2987 * @dev : pointer to net_device struct
2988 * Description:
2989 * This function is to upate the status of the xpak counters value
2990 * NONE
2991 */
2992static void s2io_updt_xpak_counter(struct net_device *dev)
2993{
2994 u16 flag = 0x0;
2995 u16 type = 0x0;
2996 u16 val16 = 0x0;
2997 u64 val64 = 0x0;
2998 u64 addr = 0x0;
2999
3000 nic_t *sp = dev->priv;
3001 StatInfo_t *stat_info = sp->mac_control.stats_info;
3002
3003 /* Check the communication with the MDIO slave */
3004 addr = 0x0000;
3005 val64 = 0x0;
3006 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3007 if((val64 == 0xFFFF) || (val64 == 0x0000))
3008 {
3009 DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - "
3010 "Returned %llx\n", (unsigned long long)val64);
3011 return;
3012 }
3013
3014 /* Check for the expecte value of 2040 at PMA address 0x0000 */
3015 if(val64 != 0x2040)
3016 {
3017 DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - ");
3018 DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x2040\n",
3019 (unsigned long long)val64);
3020 return;
3021 }
3022
3023 /* Loading the DOM register to MDIO register */
3024 addr = 0xA100;
3025 s2io_mdio_write(MDIO_MMD_PMA_DEV_ADDR, addr, val16, dev);
3026 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3027
3028 /* Reading the Alarm flags */
3029 addr = 0xA070;
3030 val64 = 0x0;
3031 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3032
3033 flag = CHECKBIT(val64, 0x7);
3034 type = 1;
3035 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_transceiver_temp_high,
3036 &stat_info->xpak_stat.xpak_regs_stat,
3037 0x0, flag, type);
3038
3039 if(CHECKBIT(val64, 0x6))
3040 stat_info->xpak_stat.alarm_transceiver_temp_low++;
3041
3042 flag = CHECKBIT(val64, 0x3);
3043 type = 2;
3044 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_bias_current_high,
3045 &stat_info->xpak_stat.xpak_regs_stat,
3046 0x2, flag, type);
3047
3048 if(CHECKBIT(val64, 0x2))
3049 stat_info->xpak_stat.alarm_laser_bias_current_low++;
3050
3051 flag = CHECKBIT(val64, 0x1);
3052 type = 3;
3053 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_output_power_high,
3054 &stat_info->xpak_stat.xpak_regs_stat,
3055 0x4, flag, type);
3056
3057 if(CHECKBIT(val64, 0x0))
3058 stat_info->xpak_stat.alarm_laser_output_power_low++;
3059
3060 /* Reading the Warning flags */
3061 addr = 0xA074;
3062 val64 = 0x0;
3063 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3064
3065 if(CHECKBIT(val64, 0x7))
3066 stat_info->xpak_stat.warn_transceiver_temp_high++;
3067
3068 if(CHECKBIT(val64, 0x6))
3069 stat_info->xpak_stat.warn_transceiver_temp_low++;
3070
3071 if(CHECKBIT(val64, 0x3))
3072 stat_info->xpak_stat.warn_laser_bias_current_high++;
3073
3074 if(CHECKBIT(val64, 0x2))
3075 stat_info->xpak_stat.warn_laser_bias_current_low++;
3076
3077 if(CHECKBIT(val64, 0x1))
3078 stat_info->xpak_stat.warn_laser_output_power_high++;
3079
3080 if(CHECKBIT(val64, 0x0))
3081 stat_info->xpak_stat.warn_laser_output_power_low++;
3082}
3083
3084/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 * alarm_intr_handler - Alarm Interrrupt handler
3086 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003087 * Description: If the interrupt was neither because of Rx packet or Tx
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 * complete, this function is called. If the interrupt was to indicate
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003089 * a loss of link, the OSM link status handler is invoked for any other
3090 * alarm interrupt the block that raised the interrupt is displayed
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 * and a H/W reset is issued.
3092 * Return Value:
3093 * NONE
3094*/
3095
3096static void alarm_intr_handler(struct s2io_nic *nic)
3097{
3098 struct net_device *dev = (struct net_device *) nic->dev;
3099 XENA_dev_config_t __iomem *bar0 = nic->bar0;
3100 register u64 val64 = 0, err_reg = 0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003101 u64 cnt;
3102 int i;
3103 nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
3104 /* Handling the XPAK counters update */
3105 if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
3106 /* waiting for an hour */
3107 nic->mac_control.stats_info->xpak_stat.xpak_timer_count++;
3108 } else {
3109 s2io_updt_xpak_counter(dev);
3110 /* reset the count to zero */
3111 nic->mac_control.stats_info->xpak_stat.xpak_timer_count = 0;
3112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113
3114 /* Handling link status change error Intr */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07003115 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
3116 err_reg = readq(&bar0->mac_rmac_err_reg);
3117 writeq(err_reg, &bar0->mac_rmac_err_reg);
3118 if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
3119 schedule_work(&nic->set_link_task);
3120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 }
3122
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003123 /* Handling Ecc errors */
3124 val64 = readq(&bar0->mc_err_reg);
3125 writeq(val64, &bar0->mc_err_reg);
3126 if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
3127 if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003128 nic->mac_control.stats_info->sw_stat.
3129 double_ecc_errs++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003130 DBG_PRINT(INIT_DBG, "%s: Device indicates ",
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003131 dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003132 DBG_PRINT(INIT_DBG, "double ECC error!!\n");
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003133 if (nic->device_type != XFRAME_II_DEVICE) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003134 /* Reset XframeI only if critical error */
3135 if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
3136 MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
3137 netif_stop_queue(dev);
3138 schedule_work(&nic->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04003139 nic->mac_control.stats_info->sw_stat.
3140 soft_reset_cnt++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003141 }
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003142 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003143 } else {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003144 nic->mac_control.stats_info->sw_stat.
3145 single_ecc_errs++;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003146 }
3147 }
3148
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 /* In case of a serious error, the device will be Reset. */
3150 val64 = readq(&bar0->serr_source);
3151 if (val64 & SERR_SOURCE_ANY) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04003152 nic->mac_control.stats_info->sw_stat.serious_err_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003154 DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
3155 (unsigned long long)val64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 netif_stop_queue(dev);
3157 schedule_work(&nic->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04003158 nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 }
3160
3161 /*
3162 * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
3163 * Error occurs, the adapter will be recycled by disabling the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003164 * adapter enable bit and enabling it again after the device
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 * becomes Quiescent.
3166 */
3167 val64 = readq(&bar0->pcc_err_reg);
3168 writeq(val64, &bar0->pcc_err_reg);
3169 if (val64 & PCC_FB_ECC_DB_ERR) {
3170 u64 ac = readq(&bar0->adapter_control);
3171 ac &= ~(ADAPTER_CNTL_EN);
3172 writeq(ac, &bar0->adapter_control);
3173 ac = readq(&bar0->adapter_control);
3174 schedule_work(&nic->set_link_task);
3175 }
Ananda Rajubd1034f2006-04-21 19:20:22 -04003176 /* Check for data parity error */
3177 val64 = readq(&bar0->pic_int_status);
3178 if (val64 & PIC_INT_GPIO) {
3179 val64 = readq(&bar0->gpio_int_reg);
3180 if (val64 & GPIO_INT_REG_DP_ERR_INT) {
3181 nic->mac_control.stats_info->sw_stat.parity_err_cnt++;
3182 schedule_work(&nic->rst_timer_task);
3183 nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
3184 }
3185 }
3186
3187 /* Check for ring full counter */
3188 if (nic->device_type & XFRAME_II_DEVICE) {
3189 val64 = readq(&bar0->ring_bump_counter1);
3190 for (i=0; i<4; i++) {
3191 cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
3192 cnt >>= 64 - ((i+1)*16);
3193 nic->mac_control.stats_info->sw_stat.ring_full_cnt
3194 += cnt;
3195 }
3196
3197 val64 = readq(&bar0->ring_bump_counter2);
3198 for (i=0; i<4; i++) {
3199 cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
3200 cnt >>= 64 - ((i+1)*16);
3201 nic->mac_control.stats_info->sw_stat.ring_full_cnt
3202 += cnt;
3203 }
3204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205
3206 /* Other type of interrupts are not being handled now, TODO */
3207}
3208
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003209/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 * wait_for_cmd_complete - waits for a command to complete.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003211 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003213 * Description: Function that waits for a command to Write into RMAC
3214 * ADDR DATA registers to be completed and returns either success or
3215 * error depending on whether the command was complete or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 * Return value:
3217 * SUCCESS on success and FAILURE on failure.
3218 */
3219
Ananda Rajuc92ca042006-04-21 19:18:03 -04003220static int wait_for_cmd_complete(void *addr, u64 busy_bit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 int ret = FAILURE, cnt = 0;
3223 u64 val64;
3224
3225 while (TRUE) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04003226 val64 = readq(addr);
3227 if (!(val64 & busy_bit)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 ret = SUCCESS;
3229 break;
3230 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003231
3232 if(in_interrupt())
3233 mdelay(50);
3234 else
3235 msleep(50);
3236
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 if (cnt++ > 10)
3238 break;
3239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 return ret;
3241}
3242
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003243/**
3244 * s2io_reset - Resets the card.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 * @sp : private member of the device structure.
3246 * Description: Function to Reset the card. This function then also
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003247 * restores the previously saved PCI configuration space registers as
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 * the card reset also resets the configuration space.
3249 * Return value:
3250 * void.
3251 */
3252
Adrian Bunk26df54b2006-01-14 03:09:40 +01003253static void s2io_reset(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254{
3255 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3256 u64 val64;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003257 u16 subid, pci_cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003259 /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003260 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003261
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 val64 = SW_RESET_ALL;
3263 writeq(val64, &bar0->sw_reset);
3264
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003265 /*
3266 * At this stage, if the PCI write is indeed completed, the
3267 * card is reset and so is the PCI Config space of the device.
3268 * So a read cannot be issued at this stage on any of the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 * registers to ensure the write into "sw_reset" register
3270 * has gone through.
3271 * Question: Is there any system call that will explicitly force
3272 * all the write commands still pending on the bus to be pushed
3273 * through?
3274 * As of now I'am just giving a 250ms delay and hoping that the
3275 * PCI write to sw_reset register is done by this time.
3276 */
3277 msleep(250);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003278 if (strstr(sp->product_name, "CX4")) {
3279 msleep(750);
3280 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003282 /* Restore the PCI state saved during initialization. */
3283 pci_restore_state(sp->pdev);
3284 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003285 pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 s2io_init_pci(sp);
3287
3288 msleep(250);
3289
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003290 /* Set swapper to enable I/O register access */
3291 s2io_set_swapper(sp);
3292
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003293 /* Restore the MSIX table entries from local variables */
3294 restore_xmsi_data(sp);
3295
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003296 /* Clear certain PCI/PCI-X fields after reset */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003297 if (sp->device_type == XFRAME_II_DEVICE) {
3298 /* Clear parity err detect bit */
3299 pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003300
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003301 /* Clearing PCIX Ecc status register */
3302 pci_write_config_dword(sp->pdev, 0x68, 0x7C);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003303
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003304 /* Clearing PCI_STATUS error reflected here */
3305 writeq(BIT(62), &bar0->txpic_int_reg);
3306 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003307
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003308 /* Reset device statistics maintained by OS */
3309 memset(&sp->stats, 0, sizeof (struct net_device_stats));
3310
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 /* SXE-002: Configure link and activity LED to turn it off */
3312 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003313 if (((subid & 0xFF) >= 0x07) &&
3314 (sp->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 val64 = readq(&bar0->gpio_control);
3316 val64 |= 0x0000800000000000ULL;
3317 writeq(val64, &bar0->gpio_control);
3318 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01003319 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 }
3321
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003322 /*
3323 * Clear spurious ECC interrupts that would have occured on
3324 * XFRAME II cards after reset.
3325 */
3326 if (sp->device_type == XFRAME_II_DEVICE) {
3327 val64 = readq(&bar0->pcc_err_reg);
3328 writeq(val64, &bar0->pcc_err_reg);
3329 }
3330
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 sp->device_enabled_once = FALSE;
3332}
3333
3334/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003335 * s2io_set_swapper - to set the swapper controle on the card
3336 * @sp : private member of the device structure,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 * pointer to the s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003338 * Description: Function to set the swapper control on the card
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 * correctly depending on the 'endianness' of the system.
3340 * Return value:
3341 * SUCCESS on success and FAILURE on failure.
3342 */
3343
Adrian Bunk26df54b2006-01-14 03:09:40 +01003344static int s2io_set_swapper(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345{
3346 struct net_device *dev = sp->dev;
3347 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3348 u64 val64, valt, valr;
3349
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003350 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 * Set proper endian settings and verify the same by reading
3352 * the PIF Feed-back register.
3353 */
3354
3355 val64 = readq(&bar0->pif_rd_swapper_fb);
3356 if (val64 != 0x0123456789ABCDEFULL) {
3357 int i = 0;
3358 u64 value[] = { 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */
3359 0x8100008181000081ULL, /* FE=1, SE=0 */
3360 0x4200004242000042ULL, /* FE=0, SE=1 */
3361 0}; /* FE=0, SE=0 */
3362
3363 while(i<4) {
3364 writeq(value[i], &bar0->swapper_ctrl);
3365 val64 = readq(&bar0->pif_rd_swapper_fb);
3366 if (val64 == 0x0123456789ABCDEFULL)
3367 break;
3368 i++;
3369 }
3370 if (i == 4) {
3371 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3372 dev->name);
3373 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3374 (unsigned long long) val64);
3375 return FAILURE;
3376 }
3377 valr = value[i];
3378 } else {
3379 valr = readq(&bar0->swapper_ctrl);
3380 }
3381
3382 valt = 0x0123456789ABCDEFULL;
3383 writeq(valt, &bar0->xmsi_address);
3384 val64 = readq(&bar0->xmsi_address);
3385
3386 if(val64 != valt) {
3387 int i = 0;
3388 u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */
3389 0x0081810000818100ULL, /* FE=1, SE=0 */
3390 0x0042420000424200ULL, /* FE=0, SE=1 */
3391 0}; /* FE=0, SE=0 */
3392
3393 while(i<4) {
3394 writeq((value[i] | valr), &bar0->swapper_ctrl);
3395 writeq(valt, &bar0->xmsi_address);
3396 val64 = readq(&bar0->xmsi_address);
3397 if(val64 == valt)
3398 break;
3399 i++;
3400 }
3401 if(i == 4) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003402 unsigned long long x = val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr ");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003404 DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 return FAILURE;
3406 }
3407 }
3408 val64 = readq(&bar0->swapper_ctrl);
3409 val64 &= 0xFFFF000000000000ULL;
3410
3411#ifdef __BIG_ENDIAN
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003412 /*
3413 * The device by default set to a big endian format, so a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 * big endian driver need not set anything.
3415 */
3416 val64 |= (SWAPPER_CTRL_TXP_FE |
3417 SWAPPER_CTRL_TXP_SE |
3418 SWAPPER_CTRL_TXD_R_FE |
3419 SWAPPER_CTRL_TXD_W_FE |
3420 SWAPPER_CTRL_TXF_R_FE |
3421 SWAPPER_CTRL_RXD_R_FE |
3422 SWAPPER_CTRL_RXD_W_FE |
3423 SWAPPER_CTRL_RXF_W_FE |
3424 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Andrew Morton92383342005-10-16 00:11:29 -07003426 if (sp->intr_type == INTA)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003427 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 writeq(val64, &bar0->swapper_ctrl);
3429#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003430 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 * Initially we enable all bits to make it accessible by the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003432 * driver, then we selectively enable only those bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 * we want to set.
3434 */
3435 val64 |= (SWAPPER_CTRL_TXP_FE |
3436 SWAPPER_CTRL_TXP_SE |
3437 SWAPPER_CTRL_TXD_R_FE |
3438 SWAPPER_CTRL_TXD_R_SE |
3439 SWAPPER_CTRL_TXD_W_FE |
3440 SWAPPER_CTRL_TXD_W_SE |
3441 SWAPPER_CTRL_TXF_R_FE |
3442 SWAPPER_CTRL_RXD_R_FE |
3443 SWAPPER_CTRL_RXD_R_SE |
3444 SWAPPER_CTRL_RXD_W_FE |
3445 SWAPPER_CTRL_RXD_W_SE |
3446 SWAPPER_CTRL_RXF_W_FE |
3447 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003449 if (sp->intr_type == INTA)
3450 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 writeq(val64, &bar0->swapper_ctrl);
3452#endif
3453 val64 = readq(&bar0->swapper_ctrl);
3454
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003455 /*
3456 * Verifying if endian settings are accurate by reading a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 * feedback register.
3458 */
3459 val64 = readq(&bar0->pif_rd_swapper_fb);
3460 if (val64 != 0x0123456789ABCDEFULL) {
3461 /* Endian settings are incorrect, calls for another dekko. */
3462 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3463 dev->name);
3464 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3465 (unsigned long long) val64);
3466 return FAILURE;
3467 }
3468
3469 return SUCCESS;
3470}
3471
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003472static int wait_for_msix_trans(nic_t *nic, int i)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003473{
Al Viro37eb47e2005-12-15 09:17:29 +00003474 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003475 u64 val64;
3476 int ret = 0, cnt = 0;
3477
3478 do {
3479 val64 = readq(&bar0->xmsi_access);
3480 if (!(val64 & BIT(15)))
3481 break;
3482 mdelay(1);
3483 cnt++;
3484 } while(cnt < 5);
3485 if (cnt == 5) {
3486 DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i);
3487 ret = 1;
3488 }
3489
3490 return ret;
3491}
3492
Adrian Bunk26df54b2006-01-14 03:09:40 +01003493static void restore_xmsi_data(nic_t *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003494{
Al Viro37eb47e2005-12-15 09:17:29 +00003495 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003496 u64 val64;
3497 int i;
3498
Ananda Rajuc92ca042006-04-21 19:18:03 -04003499 for (i=0; i< nic->avail_msix_vectors; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003500 writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
3501 writeq(nic->msix_info[i].data, &bar0->xmsi_data);
3502 val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
3503 writeq(val64, &bar0->xmsi_access);
3504 if (wait_for_msix_trans(nic, i)) {
3505 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3506 continue;
3507 }
3508 }
3509}
3510
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003511static void store_xmsi_data(nic_t *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003512{
Al Viro37eb47e2005-12-15 09:17:29 +00003513 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003514 u64 val64, addr, data;
3515 int i;
3516
3517 /* Store and display */
Ananda Rajuc92ca042006-04-21 19:18:03 -04003518 for (i=0; i< nic->avail_msix_vectors; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003519 val64 = (BIT(15) | vBIT(i, 26, 6));
3520 writeq(val64, &bar0->xmsi_access);
3521 if (wait_for_msix_trans(nic, i)) {
3522 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3523 continue;
3524 }
3525 addr = readq(&bar0->xmsi_address);
3526 data = readq(&bar0->xmsi_data);
3527 if (addr && data) {
3528 nic->msix_info[i].addr = addr;
3529 nic->msix_info[i].data = data;
3530 }
3531 }
3532}
3533
3534int s2io_enable_msi(nic_t *nic)
3535{
Al Viro37eb47e2005-12-15 09:17:29 +00003536 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003537 u16 msi_ctrl, msg_val;
3538 struct config_param *config = &nic->config;
3539 struct net_device *dev = nic->dev;
3540 u64 val64, tx_mat, rx_mat;
3541 int i, err;
3542
3543 val64 = readq(&bar0->pic_control);
3544 val64 &= ~BIT(1);
3545 writeq(val64, &bar0->pic_control);
3546
3547 err = pci_enable_msi(nic->pdev);
3548 if (err) {
3549 DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n",
3550 nic->dev->name);
3551 return err;
3552 }
3553
3554 /*
3555 * Enable MSI and use MSI-1 in stead of the standard MSI-0
3556 * for interrupt handling.
3557 */
3558 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3559 msg_val ^= 0x1;
3560 pci_write_config_word(nic->pdev, 0x4c, msg_val);
3561 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3562
3563 pci_read_config_word(nic->pdev, 0x42, &msi_ctrl);
3564 msi_ctrl |= 0x10;
3565 pci_write_config_word(nic->pdev, 0x42, msi_ctrl);
3566
3567 /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */
3568 tx_mat = readq(&bar0->tx_mat0_n[0]);
3569 for (i=0; i<config->tx_fifo_num; i++) {
3570 tx_mat |= TX_MAT_SET(i, 1);
3571 }
3572 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3573
3574 rx_mat = readq(&bar0->rx_mat);
3575 for (i=0; i<config->rx_ring_num; i++) {
3576 rx_mat |= RX_MAT_SET(i, 1);
3577 }
3578 writeq(rx_mat, &bar0->rx_mat);
3579
3580 dev->irq = nic->pdev->irq;
3581 return 0;
3582}
3583
Adrian Bunk26df54b2006-01-14 03:09:40 +01003584static int s2io_enable_msi_x(nic_t *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003585{
Al Viro37eb47e2005-12-15 09:17:29 +00003586 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003587 u64 tx_mat, rx_mat;
3588 u16 msi_control; /* Temp variable */
3589 int ret, i, j, msix_indx = 1;
3590
3591 nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
3592 GFP_KERNEL);
3593 if (nic->entries == NULL) {
3594 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3595 return -ENOMEM;
3596 }
3597 memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
3598
3599 nic->s2io_entries =
3600 kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
3601 GFP_KERNEL);
3602 if (nic->s2io_entries == NULL) {
3603 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3604 kfree(nic->entries);
3605 return -ENOMEM;
3606 }
3607 memset(nic->s2io_entries, 0,
3608 MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
3609
3610 for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
3611 nic->entries[i].entry = i;
3612 nic->s2io_entries[i].entry = i;
3613 nic->s2io_entries[i].arg = NULL;
3614 nic->s2io_entries[i].in_use = 0;
3615 }
3616
3617 tx_mat = readq(&bar0->tx_mat0_n[0]);
3618 for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) {
3619 tx_mat |= TX_MAT_SET(i, msix_indx);
3620 nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i];
3621 nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE;
3622 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3623 }
3624 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3625
3626 if (!nic->config.bimodal) {
3627 rx_mat = readq(&bar0->rx_mat);
3628 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3629 rx_mat |= RX_MAT_SET(j, msix_indx);
3630 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3631 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3632 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3633 }
3634 writeq(rx_mat, &bar0->rx_mat);
3635 } else {
3636 tx_mat = readq(&bar0->tx_mat0_n[7]);
3637 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3638 tx_mat |= TX_MAT_SET(i, msix_indx);
3639 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3640 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3641 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3642 }
3643 writeq(tx_mat, &bar0->tx_mat0_n[7]);
3644 }
3645
Ananda Rajuc92ca042006-04-21 19:18:03 -04003646 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003647 ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003648 /* We fail init if error or we get less vectors than min required */
3649 if (ret >= (nic->config.tx_fifo_num + nic->config.rx_ring_num + 1)) {
3650 nic->avail_msix_vectors = ret;
3651 ret = pci_enable_msix(nic->pdev, nic->entries, ret);
3652 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003653 if (ret) {
3654 DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
3655 kfree(nic->entries);
3656 kfree(nic->s2io_entries);
3657 nic->entries = NULL;
3658 nic->s2io_entries = NULL;
Ananda Rajuc92ca042006-04-21 19:18:03 -04003659 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003660 return -ENOMEM;
3661 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003662 if (!nic->avail_msix_vectors)
3663 nic->avail_msix_vectors = MAX_REQUESTED_MSI_X;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003664
3665 /*
3666 * To enable MSI-X, MSI also needs to be enabled, due to a bug
3667 * in the herc NIC. (Temp change, needs to be removed later)
3668 */
3669 pci_read_config_word(nic->pdev, 0x42, &msi_control);
3670 msi_control |= 0x1; /* Enable MSI */
3671 pci_write_config_word(nic->pdev, 0x42, msi_control);
3672
3673 return 0;
3674}
3675
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676/* ********************************************************* *
3677 * Functions defined below concern the OS part of the driver *
3678 * ********************************************************* */
3679
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003680/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 * s2io_open - open entry point of the driver
3682 * @dev : pointer to the device structure.
3683 * Description:
3684 * This function is the open entry point of the driver. It mainly calls a
3685 * function to allocate Rx buffers and inserts them into the buffer
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003686 * descriptors and then enables the Rx part of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 * Return value:
3688 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3689 * file on failure.
3690 */
3691
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003692static int s2io_open(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693{
3694 nic_t *sp = dev->priv;
3695 int err = 0;
3696
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003697 /*
3698 * Make sure you have link off by default every time
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 * Nic is initialized
3700 */
3701 netif_carrier_off(dev);
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003702 sp->last_link_state = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703
3704 /* Initialize H/W and enable interrupts */
Ananda Rajuc92ca042006-04-21 19:18:03 -04003705 err = s2io_card_up(sp);
3706 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
3708 dev->name);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003709 if (err == -ENODEV)
3710 goto hw_init_failed;
3711 else
3712 goto hw_enable_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 }
3714
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003715 /* Store the values of the MSIX table in the nic_t structure */
3716 store_xmsi_data(sp);
3717
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 /* After proper initialization of H/W, register ISR */
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003719 if (sp->intr_type == MSI) {
3720 err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
3721 SA_SHIRQ, sp->name, dev);
3722 if (err) {
3723 DBG_PRINT(ERR_DBG, "%s: MSI registration \
3724failed\n", dev->name);
3725 goto isr_registration_failed;
3726 }
3727 }
3728 if (sp->intr_type == MSI_X) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04003729 int i;
3730
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003731 for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
3732 if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
3733 sprintf(sp->desc1, "%s:MSI-X-%d-TX",
3734 dev->name, i);
3735 err = request_irq(sp->entries[i].vector,
3736 s2io_msix_fifo_handle, 0, sp->desc1,
3737 sp->s2io_entries[i].arg);
3738 DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1,
Andrew Morton26b76252005-12-14 19:25:23 -08003739 (unsigned long long)sp->msix_info[i].addr);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003740 } else {
3741 sprintf(sp->desc2, "%s:MSI-X-%d-RX",
3742 dev->name, i);
3743 err = request_irq(sp->entries[i].vector,
3744 s2io_msix_ring_handle, 0, sp->desc2,
3745 sp->s2io_entries[i].arg);
3746 DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2,
Andrew Morton26b76252005-12-14 19:25:23 -08003747 (unsigned long long)sp->msix_info[i].addr);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003748 }
3749 if (err) {
3750 DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \
3751failed\n", dev->name, i);
3752 DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
3753 goto isr_registration_failed;
3754 }
3755 sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
3756 }
3757 }
3758 if (sp->intr_type == INTA) {
3759 err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ,
3760 sp->name, dev);
3761 if (err) {
3762 DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
3763 dev->name);
3764 goto isr_registration_failed;
3765 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 }
3767
3768 if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
3769 DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003770 err = -ENODEV;
3771 goto setting_mac_address_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 }
3773
3774 netif_start_queue(dev);
3775 return 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003776
3777setting_mac_address_failed:
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003778 if (sp->intr_type != MSI_X)
3779 free_irq(sp->pdev->irq, dev);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003780isr_registration_failed:
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07003781 del_timer_sync(&sp->alarm_timer);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003782 if (sp->intr_type == MSI_X) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04003783 int i;
3784 u16 msi_control; /* Temp variable */
Ananda Rajubd1034f2006-04-21 19:20:22 -04003785
Ananda Rajuc92ca042006-04-21 19:18:03 -04003786 for (i=1; (sp->s2io_entries[i].in_use ==
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003787 MSIX_REGISTERED_SUCCESS); i++) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04003788 int vector = sp->entries[i].vector;
3789 void *arg = sp->s2io_entries[i].arg;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003790
Ananda Rajuc92ca042006-04-21 19:18:03 -04003791 free_irq(vector, arg);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003792 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003793 pci_disable_msix(sp->pdev);
3794
3795 /* Temp */
3796 pci_read_config_word(sp->pdev, 0x42, &msi_control);
3797 msi_control &= 0xFFFE; /* Disable MSI */
3798 pci_write_config_word(sp->pdev, 0x42, msi_control);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003799 }
3800 else if (sp->intr_type == MSI)
3801 pci_disable_msi(sp->pdev);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003802hw_enable_failed:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003803 s2io_reset(sp);
3804hw_init_failed:
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003805 if (sp->intr_type == MSI_X) {
3806 if (sp->entries)
3807 kfree(sp->entries);
3808 if (sp->s2io_entries)
3809 kfree(sp->s2io_entries);
3810 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003811 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812}
3813
3814/**
3815 * s2io_close -close entry point of the driver
3816 * @dev : device pointer.
3817 * Description:
3818 * This is the stop entry point of the driver. It needs to undo exactly
3819 * whatever was done by the open entry point,thus it's usually referred to
3820 * as the close function.Among other things this function mainly stops the
3821 * Rx side of the NIC and frees all the Rx buffers in the Rx rings.
3822 * Return value:
3823 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3824 * file on failure.
3825 */
3826
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003827static int s2io_close(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828{
3829 nic_t *sp = dev->priv;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003830
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 flush_scheduled_work();
3832 netif_stop_queue(dev);
3833 /* Reset card, kill tasklet and free Tx and Rx buffers. */
Ananda Rajuc92ca042006-04-21 19:18:03 -04003834 s2io_card_down(sp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 sp->device_close_flag = TRUE; /* Device is shut down. */
3837 return 0;
3838}
3839
3840/**
3841 * s2io_xmit - Tx entry point of te driver
3842 * @skb : the socket buffer containing the Tx data.
3843 * @dev : device pointer.
3844 * Description :
3845 * This function is the Tx entry point of the driver. S2IO NIC supports
3846 * certain protocol assist features on Tx side, namely CSO, S/G, LSO.
3847 * NOTE: when device cant queue the pkt,just the trans_start variable will
3848 * not be upadted.
3849 * Return value:
3850 * 0 on success & 1 on failure.
3851 */
3852
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003853static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854{
3855 nic_t *sp = dev->priv;
3856 u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
3857 register u64 val64;
3858 TxD_t *txdp;
3859 TxFIFO_element_t __iomem *tx_fifo;
3860 unsigned long flags;
3861#ifdef NETIF_F_TSO
3862 int mss;
3863#endif
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003864 u16 vlan_tag = 0;
3865 int vlan_priority = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 mac_info_t *mac_control;
3867 struct config_param *config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868
3869 mac_control = &sp->mac_control;
3870 config = &sp->config;
3871
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003872 DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 spin_lock_irqsave(&sp->tx_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 if (atomic_read(&sp->card_state) == CARD_DOWN) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003875 DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 dev->name);
3877 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003878 dev_kfree_skb(skb);
3879 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 }
3881
3882 queue = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003884 /* Get Fifo number to Transmit based on vlan priority */
3885 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3886 vlan_tag = vlan_tx_tag_get(skb);
3887 vlan_priority = vlan_tag >> 13;
3888 queue = config->fifo_mapping[vlan_priority];
3889 }
3890
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003891 put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
3892 get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
3893 txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off].
3894 list_virt_addr;
3895
3896 queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04003898 if (txdp->Host_Control ||
3899 ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003900 DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 netif_stop_queue(dev);
3902 dev_kfree_skb(skb);
3903 spin_unlock_irqrestore(&sp->tx_lock, flags);
3904 return 0;
3905 }
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003906
3907 /* A buffer with no data will be dropped */
3908 if (!skb->len) {
3909 DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
3910 dev_kfree_skb(skb);
3911 spin_unlock_irqrestore(&sp->tx_lock, flags);
3912 return 0;
3913 }
3914
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003915 txdp->Control_1 = 0;
3916 txdp->Control_2 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917#ifdef NETIF_F_TSO
3918 mss = skb_shinfo(skb)->tso_size;
3919 if (mss) {
3920 txdp->Control_1 |= TXD_TCP_LSO_EN;
3921 txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
3922 }
3923#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 if (skb->ip_summed == CHECKSUM_HW) {
3925 txdp->Control_2 |=
3926 (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
3927 TXD_TX_CKO_UDP_EN);
3928 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003929 txdp->Control_1 |= TXD_GATHER_CODE_FIRST;
3930 txdp->Control_1 |= TXD_LIST_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 txdp->Control_2 |= config->tx_intr_type;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07003932
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003933 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3934 txdp->Control_2 |= TXD_VLAN_ENABLE;
3935 txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
3936 }
3937
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003938 frg_len = skb->len - skb->data_len;
3939 if (skb_shinfo(skb)->ufo_size) {
3940 int ufo_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003942 ufo_size = skb_shinfo(skb)->ufo_size;
3943 ufo_size &= ~7;
3944 txdp->Control_1 |= TXD_UFO_EN;
3945 txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
3946 txdp->Control_1 |= TXD_BUFFER0_SIZE(8);
3947#ifdef __BIG_ENDIAN
3948 sp->ufo_in_band_v[put_off] =
3949 (u64)skb_shinfo(skb)->ip6_frag_id;
3950#else
3951 sp->ufo_in_band_v[put_off] =
3952 (u64)skb_shinfo(skb)->ip6_frag_id << 32;
3953#endif
3954 txdp->Host_Control = (unsigned long)sp->ufo_in_band_v;
3955 txdp->Buffer_Pointer = pci_map_single(sp->pdev,
3956 sp->ufo_in_band_v,
3957 sizeof(u64), PCI_DMA_TODEVICE);
3958 txdp++;
3959 txdp->Control_1 = 0;
3960 txdp->Control_2 = 0;
3961 }
3962
3963 txdp->Buffer_Pointer = pci_map_single
3964 (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
3965 txdp->Host_Control = (unsigned long) skb;
3966 txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
3967
3968 if (skb_shinfo(skb)->ufo_size)
3969 txdp->Control_1 |= TXD_UFO_EN;
3970
3971 frg_cnt = skb_shinfo(skb)->nr_frags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 /* For fragmented SKB. */
3973 for (i = 0; i < frg_cnt; i++) {
3974 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003975 /* A '0' length fragment will be ignored */
3976 if (!frag->size)
3977 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 txdp++;
3979 txdp->Buffer_Pointer = (u64) pci_map_page
3980 (sp->pdev, frag->page, frag->page_offset,
3981 frag->size, PCI_DMA_TODEVICE);
Ananda Rajuefd51b52006-01-19 14:11:54 -05003982 txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003983 if (skb_shinfo(skb)->ufo_size)
3984 txdp->Control_1 |= TXD_UFO_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 }
3986 txdp->Control_1 |= TXD_GATHER_CODE_LAST;
3987
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003988 if (skb_shinfo(skb)->ufo_size)
3989 frg_cnt++; /* as Txd0 was used for inband header */
3990
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 tx_fifo = mac_control->tx_FIFO_start[queue];
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003992 val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 writeq(val64, &tx_fifo->TxDL_Pointer);
3994
3995 val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
3996 TX_FIFO_LAST_LIST);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003997
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998#ifdef NETIF_F_TSO
3999 if (mss)
4000 val64 |= TX_FIFO_SPECIAL_FUNC;
4001#endif
Ananda Rajufed5ecc2005-11-14 15:25:08 -05004002 if (skb_shinfo(skb)->ufo_size)
4003 val64 |= TX_FIFO_SPECIAL_FUNC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 writeq(val64, &tx_fifo->List_Control);
4005
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07004006 mmiowb();
4007
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 put_off++;
Ananda Raju863c11a2006-04-21 19:03:13 -04004009 if (put_off == mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1)
4010 put_off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004011 mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012
4013 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04004014 if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04004015 sp->mac_control.stats_info->sw_stat.fifo_full_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 DBG_PRINT(TX_DBG,
4017 "No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
4018 put_off, get_off);
4019 netif_stop_queue(dev);
4020 }
4021
4022 dev->trans_start = jiffies;
4023 spin_unlock_irqrestore(&sp->tx_lock, flags);
4024
4025 return 0;
4026}
4027
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07004028static void
4029s2io_alarm_handle(unsigned long data)
4030{
4031 nic_t *sp = (nic_t *)data;
4032
4033 alarm_intr_handler(sp);
4034 mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
4035}
4036
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004037static irqreturn_t
4038s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs)
4039{
4040 struct net_device *dev = (struct net_device *) dev_id;
4041 nic_t *sp = dev->priv;
4042 int i;
4043 int ret;
4044 mac_info_t *mac_control;
4045 struct config_param *config;
4046
4047 atomic_inc(&sp->isr_cnt);
4048 mac_control = &sp->mac_control;
4049 config = &sp->config;
4050 DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__);
4051
4052 /* If Intr is because of Rx Traffic */
4053 for (i = 0; i < config->rx_ring_num; i++)
4054 rx_intr_handler(&mac_control->rings[i]);
4055
4056 /* If Intr is because of Tx Traffic */
4057 for (i = 0; i < config->tx_fifo_num; i++)
4058 tx_intr_handler(&mac_control->fifos[i]);
4059
4060 /*
4061 * If the Rx buffer count is below the panic threshold then
4062 * reallocate the buffers from the interrupt handler itself,
4063 * else schedule a tasklet to reallocate the buffers.
4064 */
4065 for (i = 0; i < config->rx_ring_num; i++) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004066 if (!sp->lro) {
4067 int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
4068 int level = rx_buffer_level(sp, rxb_size, i);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004069
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004070 if ((level == PANIC) && (!TASKLET_IN_USE)) {
4071 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ",
4072 dev->name);
4073 DBG_PRINT(INTR_DBG, "PANIC levels\n");
4074 if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
4075 DBG_PRINT(ERR_DBG, "%s:Out of memory",
4076 dev->name);
4077 DBG_PRINT(ERR_DBG, " in ISR!!\n");
4078 clear_bit(0, (&sp->tasklet_status));
4079 atomic_dec(&sp->isr_cnt);
4080 return IRQ_HANDLED;
4081 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004082 clear_bit(0, (&sp->tasklet_status));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004083 } else if (level == LOW) {
4084 tasklet_schedule(&sp->task);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004085 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004086 }
4087 else if (fill_rx_buffers(sp, i) == -ENOMEM) {
4088 DBG_PRINT(ERR_DBG, "%s:Out of memory",
4089 dev->name);
4090 DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
4091 break;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004092 }
4093 }
4094
4095 atomic_dec(&sp->isr_cnt);
4096 return IRQ_HANDLED;
4097}
4098
4099static irqreturn_t
4100s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs)
4101{
4102 ring_info_t *ring = (ring_info_t *)dev_id;
4103 nic_t *sp = ring->nic;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004104 struct net_device *dev = (struct net_device *) dev_id;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004105 int rxb_size, level, rng_n;
4106
4107 atomic_inc(&sp->isr_cnt);
4108 rx_intr_handler(ring);
4109
4110 rng_n = ring->ring_no;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004111 if (!sp->lro) {
4112 rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
4113 level = rx_buffer_level(sp, rxb_size, rng_n);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004114
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004115 if ((level == PANIC) && (!TASKLET_IN_USE)) {
4116 int ret;
4117 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
4118 DBG_PRINT(INTR_DBG, "PANIC levels\n");
4119 if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
4120 DBG_PRINT(ERR_DBG, "Out of memory in %s",
4121 __FUNCTION__);
4122 clear_bit(0, (&sp->tasklet_status));
4123 return IRQ_HANDLED;
4124 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004125 clear_bit(0, (&sp->tasklet_status));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004126 } else if (level == LOW) {
4127 tasklet_schedule(&sp->task);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004128 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004129 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004130 else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
4131 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
4132 DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
4133 }
4134
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004135 atomic_dec(&sp->isr_cnt);
4136
4137 return IRQ_HANDLED;
4138}
4139
4140static irqreturn_t
4141s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs)
4142{
4143 fifo_info_t *fifo = (fifo_info_t *)dev_id;
4144 nic_t *sp = fifo->nic;
4145
4146 atomic_inc(&sp->isr_cnt);
4147 tx_intr_handler(fifo);
4148 atomic_dec(&sp->isr_cnt);
4149 return IRQ_HANDLED;
4150}
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004151static void s2io_txpic_intr_handle(nic_t *sp)
4152{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01004153 XENA_dev_config_t __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004154 u64 val64;
4155
4156 val64 = readq(&bar0->pic_int_status);
4157 if (val64 & PIC_INT_GPIO) {
4158 val64 = readq(&bar0->gpio_int_reg);
4159 if ((val64 & GPIO_INT_REG_LINK_DOWN) &&
4160 (val64 & GPIO_INT_REG_LINK_UP)) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04004161 /*
4162 * This is unstable state so clear both up/down
4163 * interrupt and adapter to re-evaluate the link state.
4164 */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004165 val64 |= GPIO_INT_REG_LINK_DOWN;
4166 val64 |= GPIO_INT_REG_LINK_UP;
4167 writeq(val64, &bar0->gpio_int_reg);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004168 val64 = readq(&bar0->gpio_int_mask);
4169 val64 &= ~(GPIO_INT_MASK_LINK_UP |
4170 GPIO_INT_MASK_LINK_DOWN);
4171 writeq(val64, &bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004172 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04004173 else if (val64 & GPIO_INT_REG_LINK_UP) {
4174 val64 = readq(&bar0->adapter_status);
4175 if (verify_xena_quiescence(sp, val64,
4176 sp->device_enabled_once)) {
4177 /* Enable Adapter */
4178 val64 = readq(&bar0->adapter_control);
4179 val64 |= ADAPTER_CNTL_EN;
4180 writeq(val64, &bar0->adapter_control);
4181 val64 |= ADAPTER_LED_ON;
4182 writeq(val64, &bar0->adapter_control);
4183 if (!sp->device_enabled_once)
4184 sp->device_enabled_once = 1;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004185
Ananda Rajuc92ca042006-04-21 19:18:03 -04004186 s2io_link(sp, LINK_UP);
4187 /*
4188 * unmask link down interrupt and mask link-up
4189 * intr
4190 */
4191 val64 = readq(&bar0->gpio_int_mask);
4192 val64 &= ~GPIO_INT_MASK_LINK_DOWN;
4193 val64 |= GPIO_INT_MASK_LINK_UP;
4194 writeq(val64, &bar0->gpio_int_mask);
4195
4196 }
4197 }else if (val64 & GPIO_INT_REG_LINK_DOWN) {
4198 val64 = readq(&bar0->adapter_status);
4199 if (verify_xena_quiescence(sp, val64,
4200 sp->device_enabled_once)) {
4201 s2io_link(sp, LINK_DOWN);
4202 /* Link is down so unmaks link up interrupt */
4203 val64 = readq(&bar0->gpio_int_mask);
4204 val64 &= ~GPIO_INT_MASK_LINK_UP;
4205 val64 |= GPIO_INT_MASK_LINK_DOWN;
4206 writeq(val64, &bar0->gpio_int_mask);
4207 }
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004208 }
4209 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04004210 val64 = readq(&bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004211}
4212
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213/**
4214 * s2io_isr - ISR handler of the device .
4215 * @irq: the irq of the device.
4216 * @dev_id: a void pointer to the dev structure of the NIC.
4217 * @pt_regs: pointer to the registers pushed on the stack.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004218 * Description: This function is the ISR handler of the device. It
4219 * identifies the reason for the interrupt and calls the relevant
4220 * service routines. As a contongency measure, this ISR allocates the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221 * recv buffers, if their numbers are below the panic value which is
4222 * presently set to 25% of the original number of rcv buffers allocated.
4223 * Return value:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004224 * IRQ_HANDLED: will be returned if IRQ was handled by this routine
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 * IRQ_NONE: will be returned if interrupt is not from our device
4226 */
4227static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
4228{
4229 struct net_device *dev = (struct net_device *) dev_id;
4230 nic_t *sp = dev->priv;
4231 XENA_dev_config_t __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004232 int i;
Ananda Raju5d3213c2006-04-21 19:23:26 -04004233 u64 reason = 0, val64, org_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 mac_info_t *mac_control;
4235 struct config_param *config;
4236
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004237 atomic_inc(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 mac_control = &sp->mac_control;
4239 config = &sp->config;
4240
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004241 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 * Identify the cause for interrupt and call the appropriate
4243 * interrupt handler. Causes for the interrupt could be;
4244 * 1. Rx of packet.
4245 * 2. Tx complete.
4246 * 3. Link down.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004247 * 4. Error in any functional blocks of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248 */
4249 reason = readq(&bar0->general_int_status);
4250
4251 if (!reason) {
4252 /* The interrupt was not raised by Xena. */
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004253 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 return IRQ_NONE;
4255 }
4256
Ananda Raju863c11a2006-04-21 19:03:13 -04004257 val64 = 0xFFFFFFFFFFFFFFFFULL;
Ananda Raju5d3213c2006-04-21 19:23:26 -04004258 /* Store current mask before masking all interrupts */
4259 org_mask = readq(&bar0->general_int_mask);
4260 writeq(val64, &bar0->general_int_mask);
4261
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262#ifdef CONFIG_S2IO_NAPI
4263 if (reason & GEN_INTR_RXTRAFFIC) {
4264 if (netif_rx_schedule_prep(dev)) {
Ananda Raju863c11a2006-04-21 19:03:13 -04004265 writeq(val64, &bar0->rx_traffic_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 __netif_rx_schedule(dev);
4267 }
4268 }
4269#else
Ananda Raju863c11a2006-04-21 19:03:13 -04004270 /*
4271 * Rx handler is called by default, without checking for the
4272 * cause of interrupt.
4273 * rx_traffic_int reg is an R1 register, writing all 1's
4274 * will ensure that the actual interrupt causing bit get's
4275 * cleared and hence a read can be avoided.
4276 */
4277 writeq(val64, &bar0->rx_traffic_int);
4278 for (i = 0; i < config->rx_ring_num; i++) {
4279 rx_intr_handler(&mac_control->rings[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 }
4281#endif
4282
Ananda Raju863c11a2006-04-21 19:03:13 -04004283 /*
4284 * tx_traffic_int reg is an R1 register, writing all 1's
4285 * will ensure that the actual interrupt causing bit get's
4286 * cleared and hence a read can be avoided.
4287 */
4288 writeq(val64, &bar0->tx_traffic_int);
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -07004289
Ananda Raju863c11a2006-04-21 19:03:13 -04004290 for (i = 0; i < config->tx_fifo_num; i++)
4291 tx_intr_handler(&mac_control->fifos[i]);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004292
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004293 if (reason & GEN_INTR_TXPIC)
4294 s2io_txpic_intr_handle(sp);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004295 /*
4296 * If the Rx buffer count is below the panic threshold then
4297 * reallocate the buffers from the interrupt handler itself,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 * else schedule a tasklet to reallocate the buffers.
4299 */
4300#ifndef CONFIG_S2IO_NAPI
4301 for (i = 0; i < config->rx_ring_num; i++) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004302 if (!sp->lro) {
4303 int ret;
4304 int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
4305 int level = rx_buffer_level(sp, rxb_size, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004307 if ((level == PANIC) && (!TASKLET_IN_USE)) {
4308 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ",
4309 dev->name);
4310 DBG_PRINT(INTR_DBG, "PANIC levels\n");
4311 if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
4312 DBG_PRINT(ERR_DBG, "%s:Out of memory",
4313 dev->name);
4314 DBG_PRINT(ERR_DBG, " in ISR!!\n");
4315 clear_bit(0, (&sp->tasklet_status));
4316 atomic_dec(&sp->isr_cnt);
Ananda Raju5d3213c2006-04-21 19:23:26 -04004317 writeq(org_mask, &bar0->general_int_mask);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004318 return IRQ_HANDLED;
4319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 clear_bit(0, (&sp->tasklet_status));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004321 } else if (level == LOW) {
4322 tasklet_schedule(&sp->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004324 }
4325 else if (fill_rx_buffers(sp, i) == -ENOMEM) {
4326 DBG_PRINT(ERR_DBG, "%s:Out of memory",
4327 dev->name);
4328 DBG_PRINT(ERR_DBG, " in Rx intr!!\n");
4329 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 }
4331 }
4332#endif
Ananda Raju5d3213c2006-04-21 19:23:26 -04004333 writeq(org_mask, &bar0->general_int_mask);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004334 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 return IRQ_HANDLED;
4336}
4337
4338/**
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004339 * s2io_updt_stats -
4340 */
4341static void s2io_updt_stats(nic_t *sp)
4342{
4343 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4344 u64 val64;
4345 int cnt = 0;
4346
4347 if (atomic_read(&sp->card_state) == CARD_UP) {
4348 /* Apprx 30us on a 133 MHz bus */
4349 val64 = SET_UPDT_CLICKS(10) |
4350 STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
4351 writeq(val64, &bar0->stat_cfg);
4352 do {
4353 udelay(100);
4354 val64 = readq(&bar0->stat_cfg);
4355 if (!(val64 & BIT(0)))
4356 break;
4357 cnt++;
4358 if (cnt == 5)
4359 break; /* Updt failed */
4360 } while(1);
4361 }
4362}
4363
4364/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004365 * s2io_get_stats - Updates the device statistics structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 * @dev : pointer to the device structure.
4367 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004368 * This function updates the device statistics structure in the s2io_nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 * structure and returns a pointer to the same.
4370 * Return value:
4371 * pointer to the updated net_device_stats structure.
4372 */
4373
Adrian Bunkac1f60d2005-11-06 01:46:47 +01004374static struct net_device_stats *s2io_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375{
4376 nic_t *sp = dev->priv;
4377 mac_info_t *mac_control;
4378 struct config_param *config;
4379
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004380
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 mac_control = &sp->mac_control;
4382 config = &sp->config;
4383
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004384 /* Configure Stats for immediate updt */
4385 s2io_updt_stats(sp);
4386
4387 sp->stats.tx_packets =
4388 le32_to_cpu(mac_control->stats_info->tmac_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004389 sp->stats.tx_errors =
4390 le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
4391 sp->stats.rx_errors =
4392 le32_to_cpu(mac_control->stats_info->rmac_drop_frms);
4393 sp->stats.multicast =
4394 le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395 sp->stats.rx_length_errors =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004396 le32_to_cpu(mac_control->stats_info->rmac_long_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397
4398 return (&sp->stats);
4399}
4400
4401/**
4402 * s2io_set_multicast - entry point for multicast address enable/disable.
4403 * @dev : pointer to the device structure
4404 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004405 * This function is a driver entry point which gets called by the kernel
4406 * whenever multicast addresses must be enabled/disabled. This also gets
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 * called to set/reset promiscuous mode. Depending on the deivce flag, we
4408 * determine, if multicast address must be enabled or if promiscuous mode
4409 * is to be disabled etc.
4410 * Return value:
4411 * void.
4412 */
4413
4414static void s2io_set_multicast(struct net_device *dev)
4415{
4416 int i, j, prev_cnt;
4417 struct dev_mc_list *mclist;
4418 nic_t *sp = dev->priv;
4419 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4420 u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
4421 0xfeffffffffffULL;
4422 u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
4423 void __iomem *add;
4424
4425 if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) {
4426 /* Enable all Multicast addresses */
4427 writeq(RMAC_ADDR_DATA0_MEM_ADDR(multi_mac),
4428 &bar0->rmac_addr_data0_mem);
4429 writeq(RMAC_ADDR_DATA1_MEM_MASK(mask),
4430 &bar0->rmac_addr_data1_mem);
4431 val64 = RMAC_ADDR_CMD_MEM_WE |
4432 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4433 RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
4434 writeq(val64, &bar0->rmac_addr_cmd_mem);
4435 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004436 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4437 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438
4439 sp->m_cast_flg = 1;
4440 sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
4441 } else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) {
4442 /* Disable all Multicast addresses */
4443 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4444 &bar0->rmac_addr_data0_mem);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07004445 writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0),
4446 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 val64 = RMAC_ADDR_CMD_MEM_WE |
4448 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4449 RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos);
4450 writeq(val64, &bar0->rmac_addr_cmd_mem);
4451 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004452 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4453 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454
4455 sp->m_cast_flg = 0;
4456 sp->all_multi_pos = 0;
4457 }
4458
4459 if ((dev->flags & IFF_PROMISC) && (!sp->promisc_flg)) {
4460 /* Put the NIC into promiscuous mode */
4461 add = &bar0->mac_cfg;
4462 val64 = readq(&bar0->mac_cfg);
4463 val64 |= MAC_CFG_RMAC_PROM_ENABLE;
4464
4465 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4466 writel((u32) val64, add);
4467 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4468 writel((u32) (val64 >> 32), (add + 4));
4469
4470 val64 = readq(&bar0->mac_cfg);
4471 sp->promisc_flg = 1;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004472 DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 dev->name);
4474 } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) {
4475 /* Remove the NIC from promiscuous mode */
4476 add = &bar0->mac_cfg;
4477 val64 = readq(&bar0->mac_cfg);
4478 val64 &= ~MAC_CFG_RMAC_PROM_ENABLE;
4479
4480 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4481 writel((u32) val64, add);
4482 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4483 writel((u32) (val64 >> 32), (add + 4));
4484
4485 val64 = readq(&bar0->mac_cfg);
4486 sp->promisc_flg = 0;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004487 DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 dev->name);
4489 }
4490
4491 /* Update individual M_CAST address list */
4492 if ((!sp->m_cast_flg) && dev->mc_count) {
4493 if (dev->mc_count >
4494 (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) {
4495 DBG_PRINT(ERR_DBG, "%s: No more Rx filters ",
4496 dev->name);
4497 DBG_PRINT(ERR_DBG, "can be added, please enable ");
4498 DBG_PRINT(ERR_DBG, "ALL_MULTI instead\n");
4499 return;
4500 }
4501
4502 prev_cnt = sp->mc_addr_count;
4503 sp->mc_addr_count = dev->mc_count;
4504
4505 /* Clear out the previous list of Mc in the H/W. */
4506 for (i = 0; i < prev_cnt; i++) {
4507 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4508 &bar0->rmac_addr_data0_mem);
4509 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004510 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 val64 = RMAC_ADDR_CMD_MEM_WE |
4512 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4513 RMAC_ADDR_CMD_MEM_OFFSET
4514 (MAC_MC_ADDR_START_OFFSET + i);
4515 writeq(val64, &bar0->rmac_addr_cmd_mem);
4516
4517 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004518 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4519 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 DBG_PRINT(ERR_DBG, "%s: Adding ",
4521 dev->name);
4522 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4523 return;
4524 }
4525 }
4526
4527 /* Create the new Rx filter list and update the same in H/W. */
4528 for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
4529 i++, mclist = mclist->next) {
4530 memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr,
4531 ETH_ALEN);
Jeff Garzika7a80d52006-03-04 12:06:51 -05004532 mac_addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 for (j = 0; j < ETH_ALEN; j++) {
4534 mac_addr |= mclist->dmi_addr[j];
4535 mac_addr <<= 8;
4536 }
4537 mac_addr >>= 8;
4538 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4539 &bar0->rmac_addr_data0_mem);
4540 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004541 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 val64 = RMAC_ADDR_CMD_MEM_WE |
4543 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4544 RMAC_ADDR_CMD_MEM_OFFSET
4545 (i + MAC_MC_ADDR_START_OFFSET);
4546 writeq(val64, &bar0->rmac_addr_cmd_mem);
4547
4548 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004549 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4550 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 DBG_PRINT(ERR_DBG, "%s: Adding ",
4552 dev->name);
4553 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4554 return;
4555 }
4556 }
4557 }
4558}
4559
4560/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004561 * s2io_set_mac_addr - Programs the Xframe mac address
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 * @dev : pointer to the device structure.
4563 * @addr: a uchar pointer to the new mac address which is to be set.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004564 * Description : This procedure will program the Xframe to receive
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 * frames with new Mac Address
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004566 * Return value: SUCCESS on success and an appropriate (-)ve integer
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 * as defined in errno.h file on failure.
4568 */
4569
Adrian Bunk26df54b2006-01-14 03:09:40 +01004570static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571{
4572 nic_t *sp = dev->priv;
4573 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4574 register u64 val64, mac_addr = 0;
4575 int i;
4576
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004577 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 * Set the new MAC address as the new unicast filter and reflect this
4579 * change on the device address registered with the OS. It will be
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004580 * at offset 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 */
4582 for (i = 0; i < ETH_ALEN; i++) {
4583 mac_addr <<= 8;
4584 mac_addr |= addr[i];
4585 }
4586
4587 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4588 &bar0->rmac_addr_data0_mem);
4589
4590 val64 =
4591 RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4592 RMAC_ADDR_CMD_MEM_OFFSET(0);
4593 writeq(val64, &bar0->rmac_addr_cmd_mem);
4594 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004595 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4596 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
4598 return FAILURE;
4599 }
4600
4601 return SUCCESS;
4602}
4603
4604/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004605 * s2io_ethtool_sset - Sets different link parameters.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606 * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure.
4607 * @info: pointer to the structure with parameters given by ethtool to set
4608 * link information.
4609 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004610 * The function sets different link parameters provided by the user onto
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 * the NIC.
4612 * Return value:
4613 * 0 on success.
4614*/
4615
4616static int s2io_ethtool_sset(struct net_device *dev,
4617 struct ethtool_cmd *info)
4618{
4619 nic_t *sp = dev->priv;
4620 if ((info->autoneg == AUTONEG_ENABLE) ||
4621 (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
4622 return -EINVAL;
4623 else {
4624 s2io_close(sp->dev);
4625 s2io_open(sp->dev);
4626 }
4627
4628 return 0;
4629}
4630
4631/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004632 * s2io_ethtol_gset - Return link specific information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 * @sp : private member of the device structure, pointer to the
4634 * s2io_nic structure.
4635 * @info : pointer to the structure with parameters given by ethtool
4636 * to return link information.
4637 * Description:
4638 * Returns link specific information like speed, duplex etc.. to ethtool.
4639 * Return value :
4640 * return 0 on success.
4641 */
4642
4643static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
4644{
4645 nic_t *sp = dev->priv;
4646 info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4647 info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4648 info->port = PORT_FIBRE;
4649 /* info->transceiver?? TODO */
4650
4651 if (netif_carrier_ok(sp->dev)) {
4652 info->speed = 10000;
4653 info->duplex = DUPLEX_FULL;
4654 } else {
4655 info->speed = -1;
4656 info->duplex = -1;
4657 }
4658
4659 info->autoneg = AUTONEG_DISABLE;
4660 return 0;
4661}
4662
4663/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004664 * s2io_ethtool_gdrvinfo - Returns driver specific information.
4665 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 * s2io_nic structure.
4667 * @info : pointer to the structure with parameters given by ethtool to
4668 * return driver information.
4669 * Description:
4670 * Returns driver specefic information like name, version etc.. to ethtool.
4671 * Return value:
4672 * void
4673 */
4674
4675static void s2io_ethtool_gdrvinfo(struct net_device *dev,
4676 struct ethtool_drvinfo *info)
4677{
4678 nic_t *sp = dev->priv;
4679
John W. Linvilledbc23092005-09-28 17:50:51 -04004680 strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
4681 strncpy(info->version, s2io_driver_version, sizeof(info->version));
4682 strncpy(info->fw_version, "", sizeof(info->fw_version));
4683 strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 info->regdump_len = XENA_REG_SPACE;
4685 info->eedump_len = XENA_EEPROM_SPACE;
4686 info->testinfo_len = S2IO_TEST_LEN;
4687 info->n_stats = S2IO_STAT_LEN;
4688}
4689
4690/**
4691 * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004692 * @sp: private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004694 * @regs : pointer to the structure with parameters given by ethtool for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695 * dumping the registers.
4696 * @reg_space: The input argumnet into which all the registers are dumped.
4697 * Description:
4698 * Dumps the entire register space of xFrame NIC into the user given
4699 * buffer area.
4700 * Return value :
4701 * void .
4702*/
4703
4704static void s2io_ethtool_gregs(struct net_device *dev,
4705 struct ethtool_regs *regs, void *space)
4706{
4707 int i;
4708 u64 reg;
4709 u8 *reg_space = (u8 *) space;
4710 nic_t *sp = dev->priv;
4711
4712 regs->len = XENA_REG_SPACE;
4713 regs->version = sp->pdev->subsystem_device;
4714
4715 for (i = 0; i < regs->len; i += 8) {
4716 reg = readq(sp->bar0 + i);
4717 memcpy((reg_space + i), &reg, 8);
4718 }
4719}
4720
4721/**
4722 * s2io_phy_id - timer function that alternates adapter LED.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004723 * @data : address of the private member of the device structure, which
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 * is a pointer to the s2io_nic structure, provided as an u32.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004725 * Description: This is actually the timer function that alternates the
4726 * adapter LED bit of the adapter control bit to set/reset every time on
4727 * invocation. The timer is set for 1/2 a second, hence tha NIC blinks
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728 * once every second.
4729*/
4730static void s2io_phy_id(unsigned long data)
4731{
4732 nic_t *sp = (nic_t *) data;
4733 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4734 u64 val64 = 0;
4735 u16 subid;
4736
4737 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004738 if ((sp->device_type == XFRAME_II_DEVICE) ||
4739 ((subid & 0xFF) >= 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 val64 = readq(&bar0->gpio_control);
4741 val64 ^= GPIO_CTRL_GPIO_0;
4742 writeq(val64, &bar0->gpio_control);
4743 } else {
4744 val64 = readq(&bar0->adapter_control);
4745 val64 ^= ADAPTER_LED_ON;
4746 writeq(val64, &bar0->adapter_control);
4747 }
4748
4749 mod_timer(&sp->id_timer, jiffies + HZ / 2);
4750}
4751
4752/**
4753 * s2io_ethtool_idnic - To physically identify the nic on the system.
4754 * @sp : private member of the device structure, which is a pointer to the
4755 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004756 * @id : pointer to the structure with identification parameters given by
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 * ethtool.
4758 * Description: Used to physically identify the NIC on the system.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004759 * The Link LED will blink for a time specified by the user for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 * identification.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004761 * NOTE: The Link has to be Up to be able to blink the LED. Hence
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 * identification is possible only if it's link is up.
4763 * Return value:
4764 * int , returns 0 on success
4765 */
4766
4767static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
4768{
4769 u64 val64 = 0, last_gpio_ctrl_val;
4770 nic_t *sp = dev->priv;
4771 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4772 u16 subid;
4773
4774 subid = sp->pdev->subsystem_device;
4775 last_gpio_ctrl_val = readq(&bar0->gpio_control);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004776 if ((sp->device_type == XFRAME_I_DEVICE) &&
4777 ((subid & 0xFF) < 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 val64 = readq(&bar0->adapter_control);
4779 if (!(val64 & ADAPTER_CNTL_EN)) {
4780 printk(KERN_ERR
4781 "Adapter Link down, cannot blink LED\n");
4782 return -EFAULT;
4783 }
4784 }
4785 if (sp->id_timer.function == NULL) {
4786 init_timer(&sp->id_timer);
4787 sp->id_timer.function = s2io_phy_id;
4788 sp->id_timer.data = (unsigned long) sp;
4789 }
4790 mod_timer(&sp->id_timer, jiffies);
4791 if (data)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004792 msleep_interruptible(data * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004794 msleep_interruptible(MAX_FLICKER_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 del_timer_sync(&sp->id_timer);
4796
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004797 if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 writeq(last_gpio_ctrl_val, &bar0->gpio_control);
4799 last_gpio_ctrl_val = readq(&bar0->gpio_control);
4800 }
4801
4802 return 0;
4803}
4804
4805/**
4806 * s2io_ethtool_getpause_data -Pause frame frame generation and reception.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004807 * @sp : private member of the device structure, which is a pointer to the
4808 * s2io_nic structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 * @ep : pointer to the structure with pause parameters given by ethtool.
4810 * Description:
4811 * Returns the Pause frame generation and reception capability of the NIC.
4812 * Return value:
4813 * void
4814 */
4815static void s2io_ethtool_getpause_data(struct net_device *dev,
4816 struct ethtool_pauseparam *ep)
4817{
4818 u64 val64;
4819 nic_t *sp = dev->priv;
4820 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4821
4822 val64 = readq(&bar0->rmac_pause_cfg);
4823 if (val64 & RMAC_PAUSE_GEN_ENABLE)
4824 ep->tx_pause = TRUE;
4825 if (val64 & RMAC_PAUSE_RX_ENABLE)
4826 ep->rx_pause = TRUE;
4827 ep->autoneg = FALSE;
4828}
4829
4830/**
4831 * s2io_ethtool_setpause_data - set/reset pause frame generation.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004832 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 * s2io_nic structure.
4834 * @ep : pointer to the structure with pause parameters given by ethtool.
4835 * Description:
4836 * It can be used to set or reset Pause frame generation or reception
4837 * support of the NIC.
4838 * Return value:
4839 * int, returns 0 on Success
4840 */
4841
4842static int s2io_ethtool_setpause_data(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004843 struct ethtool_pauseparam *ep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844{
4845 u64 val64;
4846 nic_t *sp = dev->priv;
4847 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4848
4849 val64 = readq(&bar0->rmac_pause_cfg);
4850 if (ep->tx_pause)
4851 val64 |= RMAC_PAUSE_GEN_ENABLE;
4852 else
4853 val64 &= ~RMAC_PAUSE_GEN_ENABLE;
4854 if (ep->rx_pause)
4855 val64 |= RMAC_PAUSE_RX_ENABLE;
4856 else
4857 val64 &= ~RMAC_PAUSE_RX_ENABLE;
4858 writeq(val64, &bar0->rmac_pause_cfg);
4859 return 0;
4860}
4861
4862/**
4863 * read_eeprom - reads 4 bytes of data from user given offset.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004864 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 * s2io_nic structure.
4866 * @off : offset at which the data must be written
4867 * @data : Its an output parameter where the data read at the given
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004868 * offset is stored.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004870 * Will read 4 bytes of data from the user given offset and return the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 * read data.
4872 * NOTE: Will allow to read only part of the EEPROM visible through the
4873 * I2C bus.
4874 * Return value:
4875 * -1 on failure and 0 on success.
4876 */
4877
4878#define S2IO_DEV_ID 5
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004879static int read_eeprom(nic_t * sp, int off, u64 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880{
4881 int ret = -1;
4882 u32 exit_cnt = 0;
4883 u64 val64;
4884 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4885
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004886 if (sp->device_type == XFRAME_I_DEVICE) {
4887 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4888 I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ |
4889 I2C_CONTROL_CNTL_START;
4890 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004892 while (exit_cnt < 5) {
4893 val64 = readq(&bar0->i2c_control);
4894 if (I2C_CONTROL_CNTL_END(val64)) {
4895 *data = I2C_CONTROL_GET_DATA(val64);
4896 ret = 0;
4897 break;
4898 }
4899 msleep(50);
4900 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 }
4903
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004904 if (sp->device_type == XFRAME_II_DEVICE) {
4905 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
4906 SPI_CONTROL_BYTECNT(0x3) |
4907 SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off);
4908 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4909 val64 |= SPI_CONTROL_REQ;
4910 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4911 while (exit_cnt < 5) {
4912 val64 = readq(&bar0->spi_control);
4913 if (val64 & SPI_CONTROL_NACK) {
4914 ret = 1;
4915 break;
4916 } else if (val64 & SPI_CONTROL_DONE) {
4917 *data = readq(&bar0->spi_data);
4918 *data &= 0xffffff;
4919 ret = 0;
4920 break;
4921 }
4922 msleep(50);
4923 exit_cnt++;
4924 }
4925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 return ret;
4927}
4928
4929/**
4930 * write_eeprom - actually writes the relevant part of the data value.
4931 * @sp : private member of the device structure, which is a pointer to the
4932 * s2io_nic structure.
4933 * @off : offset at which the data must be written
4934 * @data : The data that is to be written
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004935 * @cnt : Number of bytes of the data that are actually to be written into
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 * the Eeprom. (max of 3)
4937 * Description:
4938 * Actually writes the relevant part of the data value into the Eeprom
4939 * through the I2C bus.
4940 * Return value:
4941 * 0 on success, -1 on failure.
4942 */
4943
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004944static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945{
4946 int exit_cnt = 0, ret = -1;
4947 u64 val64;
4948 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4949
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004950 if (sp->device_type == XFRAME_I_DEVICE) {
4951 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4952 I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) |
4953 I2C_CONTROL_CNTL_START;
4954 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004956 while (exit_cnt < 5) {
4957 val64 = readq(&bar0->i2c_control);
4958 if (I2C_CONTROL_CNTL_END(val64)) {
4959 if (!(val64 & I2C_CONTROL_NACK))
4960 ret = 0;
4961 break;
4962 }
4963 msleep(50);
4964 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966 }
4967
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004968 if (sp->device_type == XFRAME_II_DEVICE) {
4969 int write_cnt = (cnt == 8) ? 0 : cnt;
4970 writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data);
4971
4972 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
4973 SPI_CONTROL_BYTECNT(write_cnt) |
4974 SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off);
4975 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4976 val64 |= SPI_CONTROL_REQ;
4977 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4978 while (exit_cnt < 5) {
4979 val64 = readq(&bar0->spi_control);
4980 if (val64 & SPI_CONTROL_NACK) {
4981 ret = 1;
4982 break;
4983 } else if (val64 & SPI_CONTROL_DONE) {
4984 ret = 0;
4985 break;
4986 }
4987 msleep(50);
4988 exit_cnt++;
4989 }
4990 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 return ret;
4992}
Ananda Raju9dc737a2006-04-21 19:05:41 -04004993static void s2io_vpd_read(nic_t *nic)
4994{
4995 u8 vpd_data[256],data;
4996 int i=0, cnt, fail = 0;
4997 int vpd_addr = 0x80;
4998
4999 if (nic->device_type == XFRAME_II_DEVICE) {
5000 strcpy(nic->product_name, "Xframe II 10GbE network adapter");
5001 vpd_addr = 0x80;
5002 }
5003 else {
5004 strcpy(nic->product_name, "Xframe I 10GbE network adapter");
5005 vpd_addr = 0x50;
5006 }
5007
5008 for (i = 0; i < 256; i +=4 ) {
5009 pci_write_config_byte(nic->pdev, (vpd_addr + 2), i);
5010 pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data);
5011 pci_write_config_byte(nic->pdev, (vpd_addr + 3), 0);
5012 for (cnt = 0; cnt <5; cnt++) {
5013 msleep(2);
5014 pci_read_config_byte(nic->pdev, (vpd_addr + 3), &data);
5015 if (data == 0x80)
5016 break;
5017 }
5018 if (cnt >= 5) {
5019 DBG_PRINT(ERR_DBG, "Read of VPD data failed\n");
5020 fail = 1;
5021 break;
5022 }
5023 pci_read_config_dword(nic->pdev, (vpd_addr + 4),
5024 (u32 *)&vpd_data[i]);
5025 }
5026 if ((!fail) && (vpd_data[1] < VPD_PRODUCT_NAME_LEN)) {
5027 memset(nic->product_name, 0, vpd_data[1]);
5028 memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
5029 }
5030}
5031
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032/**
5033 * s2io_ethtool_geeprom - reads the value stored in the Eeprom.
5034 * @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 -07005035 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036 * containing all relevant information.
5037 * @data_buf : user defined value to be written into Eeprom.
5038 * Description: Reads the values stored in the Eeprom at given offset
5039 * for a given length. Stores these values int the input argument data
5040 * buffer 'data_buf' and returns these to the caller (ethtool.)
5041 * Return value:
5042 * int 0 on success
5043 */
5044
5045static int s2io_ethtool_geeprom(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005046 struct ethtool_eeprom *eeprom, u8 * data_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047{
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005048 u32 i, valid;
5049 u64 data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 nic_t *sp = dev->priv;
5051
5052 eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
5053
5054 if ((eeprom->offset + eeprom->len) > (XENA_EEPROM_SPACE))
5055 eeprom->len = XENA_EEPROM_SPACE - eeprom->offset;
5056
5057 for (i = 0; i < eeprom->len; i += 4) {
5058 if (read_eeprom(sp, (eeprom->offset + i), &data)) {
5059 DBG_PRINT(ERR_DBG, "Read of EEPROM failed\n");
5060 return -EFAULT;
5061 }
5062 valid = INV(data);
5063 memcpy((data_buf + i), &valid, 4);
5064 }
5065 return 0;
5066}
5067
5068/**
5069 * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom
5070 * @sp : private member of the device structure, which is a pointer to the
5071 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005072 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 * containing all relevant information.
5074 * @data_buf ; user defined value to be written into Eeprom.
5075 * Description:
5076 * Tries to write the user provided value in the Eeprom, at the offset
5077 * given by the user.
5078 * Return value:
5079 * 0 on success, -EFAULT on failure.
5080 */
5081
5082static int s2io_ethtool_seeprom(struct net_device *dev,
5083 struct ethtool_eeprom *eeprom,
5084 u8 * data_buf)
5085{
5086 int len = eeprom->len, cnt = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005087 u64 valid = 0, data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 nic_t *sp = dev->priv;
5089
5090 if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
5091 DBG_PRINT(ERR_DBG,
5092 "ETHTOOL_WRITE_EEPROM Err: Magic value ");
5093 DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n",
5094 eeprom->magic);
5095 return -EFAULT;
5096 }
5097
5098 while (len) {
5099 data = (u32) data_buf[cnt] & 0x000000FF;
5100 if (data) {
5101 valid = (u32) (data << 24);
5102 } else
5103 valid = data;
5104
5105 if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) {
5106 DBG_PRINT(ERR_DBG,
5107 "ETHTOOL_WRITE_EEPROM Err: Cannot ");
5108 DBG_PRINT(ERR_DBG,
5109 "write into the specified offset\n");
5110 return -EFAULT;
5111 }
5112 cnt++;
5113 len--;
5114 }
5115
5116 return 0;
5117}
5118
5119/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005120 * s2io_register_test - reads and writes into all clock domains.
5121 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122 * s2io_nic structure.
5123 * @data : variable that returns the result of each of the test conducted b
5124 * by the driver.
5125 * Description:
5126 * Read and write into all clock domains. The NIC has 3 clock domains,
5127 * see that registers in all the three regions are accessible.
5128 * Return value:
5129 * 0 on success.
5130 */
5131
5132static int s2io_register_test(nic_t * sp, uint64_t * data)
5133{
5134 XENA_dev_config_t __iomem *bar0 = sp->bar0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005135 u64 val64 = 0, exp_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136 int fail = 0;
5137
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005138 val64 = readq(&bar0->pif_rd_swapper_fb);
5139 if (val64 != 0x123456789abcdefULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 fail = 1;
5141 DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n");
5142 }
5143
5144 val64 = readq(&bar0->rmac_pause_cfg);
5145 if (val64 != 0xc000ffff00000000ULL) {
5146 fail = 1;
5147 DBG_PRINT(INFO_DBG, "Read Test level 2 fails\n");
5148 }
5149
5150 val64 = readq(&bar0->rx_queue_cfg);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005151 if (sp->device_type == XFRAME_II_DEVICE)
5152 exp_val = 0x0404040404040404ULL;
5153 else
5154 exp_val = 0x0808080808080808ULL;
5155 if (val64 != exp_val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 fail = 1;
5157 DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n");
5158 }
5159
5160 val64 = readq(&bar0->xgxs_efifo_cfg);
5161 if (val64 != 0x000000001923141EULL) {
5162 fail = 1;
5163 DBG_PRINT(INFO_DBG, "Read Test level 4 fails\n");
5164 }
5165
5166 val64 = 0x5A5A5A5A5A5A5A5AULL;
5167 writeq(val64, &bar0->xmsi_data);
5168 val64 = readq(&bar0->xmsi_data);
5169 if (val64 != 0x5A5A5A5A5A5A5A5AULL) {
5170 fail = 1;
5171 DBG_PRINT(ERR_DBG, "Write Test level 1 fails\n");
5172 }
5173
5174 val64 = 0xA5A5A5A5A5A5A5A5ULL;
5175 writeq(val64, &bar0->xmsi_data);
5176 val64 = readq(&bar0->xmsi_data);
5177 if (val64 != 0xA5A5A5A5A5A5A5A5ULL) {
5178 fail = 1;
5179 DBG_PRINT(ERR_DBG, "Write Test level 2 fails\n");
5180 }
5181
5182 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005183 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184}
5185
5186/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005187 * s2io_eeprom_test - to verify that EEprom in the xena can be programmed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 * @sp : private member of the device structure, which is a pointer to the
5189 * s2io_nic structure.
5190 * @data:variable that returns the result of each of the test conducted by
5191 * the driver.
5192 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005193 * Verify that EEPROM in the xena can be programmed using I2C_CONTROL
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 * register.
5195 * Return value:
5196 * 0 on success.
5197 */
5198
5199static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
5200{
5201 int fail = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005202 u64 ret_data, org_4F0, org_7F0;
5203 u8 saved_4F0 = 0, saved_7F0 = 0;
5204 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205
5206 /* Test Write Error at offset 0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005207 /* Note that SPI interface allows write access to all areas
5208 * of EEPROM. Hence doing all negative testing only for Xframe I.
5209 */
5210 if (sp->device_type == XFRAME_I_DEVICE)
5211 if (!write_eeprom(sp, 0, 0, 3))
5212 fail = 1;
5213
5214 /* Save current values at offsets 0x4F0 and 0x7F0 */
5215 if (!read_eeprom(sp, 0x4F0, &org_4F0))
5216 saved_4F0 = 1;
5217 if (!read_eeprom(sp, 0x7F0, &org_7F0))
5218 saved_7F0 = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219
5220 /* Test Write at offset 4f0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005221 if (write_eeprom(sp, 0x4F0, 0x012345, 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 fail = 1;
5223 if (read_eeprom(sp, 0x4F0, &ret_data))
5224 fail = 1;
5225
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005226 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005227 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. "
5228 "Data written %llx Data read %llx\n",
5229 dev->name, (unsigned long long)0x12345,
5230 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233
5234 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005235 write_eeprom(sp, 0x4F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236
5237 /* Test Write Request Error at offset 0x7c */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005238 if (sp->device_type == XFRAME_I_DEVICE)
5239 if (!write_eeprom(sp, 0x07C, 0, 3))
5240 fail = 1;
5241
5242 /* Test Write Request at offset 0x7f0 */
5243 if (write_eeprom(sp, 0x7F0, 0x012345, 3))
5244 fail = 1;
5245 if (read_eeprom(sp, 0x7F0, &ret_data))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246 fail = 1;
5247
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005248 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005249 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. "
5250 "Data written %llx Data read %llx\n",
5251 dev->name, (unsigned long long)0x12345,
5252 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005254 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255
5256 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005257 write_eeprom(sp, 0x7F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005259 if (sp->device_type == XFRAME_I_DEVICE) {
5260 /* Test Write Error at offset 0x80 */
5261 if (!write_eeprom(sp, 0x080, 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 0xfc */
5265 if (!write_eeprom(sp, 0x0FC, 0, 3))
5266 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005268 /* Test Write Error at offset 0x100 */
5269 if (!write_eeprom(sp, 0x100, 0, 3))
5270 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005272 /* Test Write Error at offset 4ec */
5273 if (!write_eeprom(sp, 0x4EC, 0, 3))
5274 fail = 1;
5275 }
5276
5277 /* Restore values at offsets 0x4F0 and 0x7F0 */
5278 if (saved_4F0)
5279 write_eeprom(sp, 0x4F0, org_4F0, 3);
5280 if (saved_7F0)
5281 write_eeprom(sp, 0x7F0, org_7F0, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282
5283 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005284 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285}
5286
5287/**
5288 * s2io_bist_test - invokes the MemBist test of the card .
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005289 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005291 * @data:variable that returns the result of each of the test conducted by
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 * the driver.
5293 * Description:
5294 * This invokes the MemBist test of the card. We give around
5295 * 2 secs time for the Test to complete. If it's still not complete
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005296 * within this peiod, we consider that the test failed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 * Return value:
5298 * 0 on success and -1 on failure.
5299 */
5300
5301static int s2io_bist_test(nic_t * sp, uint64_t * data)
5302{
5303 u8 bist = 0;
5304 int cnt = 0, ret = -1;
5305
5306 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5307 bist |= PCI_BIST_START;
5308 pci_write_config_word(sp->pdev, PCI_BIST, bist);
5309
5310 while (cnt < 20) {
5311 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5312 if (!(bist & PCI_BIST_START)) {
5313 *data = (bist & PCI_BIST_CODE_MASK);
5314 ret = 0;
5315 break;
5316 }
5317 msleep(100);
5318 cnt++;
5319 }
5320
5321 return ret;
5322}
5323
5324/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005325 * s2io-link_test - verifies the link state of the nic
5326 * @sp ; private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327 * s2io_nic structure.
5328 * @data: variable that returns the result of each of the test conducted by
5329 * the driver.
5330 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005331 * The function verifies the link state of the NIC and updates the input
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332 * argument 'data' appropriately.
5333 * Return value:
5334 * 0 on success.
5335 */
5336
5337static int s2io_link_test(nic_t * sp, uint64_t * data)
5338{
5339 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5340 u64 val64;
5341
5342 val64 = readq(&bar0->adapter_status);
Ananda Rajuc92ca042006-04-21 19:18:03 -04005343 if(!(LINK_IS_UP(val64)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344 *data = 1;
Ananda Rajuc92ca042006-04-21 19:18:03 -04005345 else
5346 *data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347
5348 return 0;
5349}
5350
5351/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005352 * s2io_rldram_test - offline test for access to the RldRam chip on the NIC
5353 * @sp - private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005355 * @data - variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 * conducted by the driver.
5357 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005358 * This is one of the offline test that tests the read and write
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 * access to the RldRam chip on the NIC.
5360 * Return value:
5361 * 0 on success.
5362 */
5363
5364static int s2io_rldram_test(nic_t * sp, uint64_t * data)
5365{
5366 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5367 u64 val64;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005368 int cnt, iteration = 0, test_fail = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369
5370 val64 = readq(&bar0->adapter_control);
5371 val64 &= ~ADAPTER_ECC_EN;
5372 writeq(val64, &bar0->adapter_control);
5373
5374 val64 = readq(&bar0->mc_rldram_test_ctrl);
5375 val64 |= MC_RLDRAM_TEST_MODE;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005376 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377
5378 val64 = readq(&bar0->mc_rldram_mrs);
5379 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE;
5380 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5381
5382 val64 |= MC_RLDRAM_MRS_ENABLE;
5383 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5384
5385 while (iteration < 2) {
5386 val64 = 0x55555555aaaa0000ULL;
5387 if (iteration == 1) {
5388 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5389 }
5390 writeq(val64, &bar0->mc_rldram_test_d0);
5391
5392 val64 = 0xaaaa5a5555550000ULL;
5393 if (iteration == 1) {
5394 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5395 }
5396 writeq(val64, &bar0->mc_rldram_test_d1);
5397
5398 val64 = 0x55aaaaaaaa5a0000ULL;
5399 if (iteration == 1) {
5400 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5401 }
5402 writeq(val64, &bar0->mc_rldram_test_d2);
5403
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005404 val64 = (u64) (0x0000003ffffe0100ULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405 writeq(val64, &bar0->mc_rldram_test_add);
5406
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005407 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE |
5408 MC_RLDRAM_TEST_GO;
5409 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410
5411 for (cnt = 0; cnt < 5; cnt++) {
5412 val64 = readq(&bar0->mc_rldram_test_ctrl);
5413 if (val64 & MC_RLDRAM_TEST_DONE)
5414 break;
5415 msleep(200);
5416 }
5417
5418 if (cnt == 5)
5419 break;
5420
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005421 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO;
5422 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423
5424 for (cnt = 0; cnt < 5; cnt++) {
5425 val64 = readq(&bar0->mc_rldram_test_ctrl);
5426 if (val64 & MC_RLDRAM_TEST_DONE)
5427 break;
5428 msleep(500);
5429 }
5430
5431 if (cnt == 5)
5432 break;
5433
5434 val64 = readq(&bar0->mc_rldram_test_ctrl);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005435 if (!(val64 & MC_RLDRAM_TEST_PASS))
5436 test_fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437
5438 iteration++;
5439 }
5440
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005441 *data = test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005443 /* Bring the adapter out of test mode */
5444 SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF);
5445
5446 return test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447}
5448
5449/**
5450 * s2io_ethtool_test - conducts 6 tsets to determine the health of card.
5451 * @sp : private member of the device structure, which is a pointer to the
5452 * s2io_nic structure.
5453 * @ethtest : pointer to a ethtool command specific structure that will be
5454 * returned to the user.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005455 * @data : variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 * conducted by the driver.
5457 * Description:
5458 * This function conducts 6 tests ( 4 offline and 2 online) to determine
5459 * the health of the card.
5460 * Return value:
5461 * void
5462 */
5463
5464static void s2io_ethtool_test(struct net_device *dev,
5465 struct ethtool_test *ethtest,
5466 uint64_t * data)
5467{
5468 nic_t *sp = dev->priv;
5469 int orig_state = netif_running(sp->dev);
5470
5471 if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
5472 /* Offline Tests. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005473 if (orig_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 s2io_close(sp->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475
5476 if (s2io_register_test(sp, &data[0]))
5477 ethtest->flags |= ETH_TEST_FL_FAILED;
5478
5479 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480
5481 if (s2io_rldram_test(sp, &data[3]))
5482 ethtest->flags |= ETH_TEST_FL_FAILED;
5483
5484 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485
5486 if (s2io_eeprom_test(sp, &data[1]))
5487 ethtest->flags |= ETH_TEST_FL_FAILED;
5488
5489 if (s2io_bist_test(sp, &data[4]))
5490 ethtest->flags |= ETH_TEST_FL_FAILED;
5491
5492 if (orig_state)
5493 s2io_open(sp->dev);
5494
5495 data[2] = 0;
5496 } else {
5497 /* Online Tests. */
5498 if (!orig_state) {
5499 DBG_PRINT(ERR_DBG,
5500 "%s: is not up, cannot run test\n",
5501 dev->name);
5502 data[0] = -1;
5503 data[1] = -1;
5504 data[2] = -1;
5505 data[3] = -1;
5506 data[4] = -1;
5507 }
5508
5509 if (s2io_link_test(sp, &data[2]))
5510 ethtest->flags |= ETH_TEST_FL_FAILED;
5511
5512 data[0] = 0;
5513 data[1] = 0;
5514 data[3] = 0;
5515 data[4] = 0;
5516 }
5517}
5518
5519static void s2io_get_ethtool_stats(struct net_device *dev,
5520 struct ethtool_stats *estats,
5521 u64 * tmp_stats)
5522{
5523 int i = 0;
5524 nic_t *sp = dev->priv;
5525 StatInfo_t *stat_info = sp->mac_control.stats_info;
5526
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005527 s2io_updt_stats(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005528 tmp_stats[i++] =
5529 (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32 |
5530 le32_to_cpu(stat_info->tmac_frms);
5531 tmp_stats[i++] =
5532 (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 |
5533 le32_to_cpu(stat_info->tmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005535 tmp_stats[i++] =
5536 (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 |
5537 le32_to_cpu(stat_info->tmac_mcst_frms);
5538 tmp_stats[i++] =
5539 (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 |
5540 le32_to_cpu(stat_info->tmac_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005542 tmp_stats[i++] =
5543 (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 |
5544 le32_to_cpu(stat_info->tmac_ttl_octets);
5545 tmp_stats[i++] =
5546 (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 |
5547 le32_to_cpu(stat_info->tmac_ucst_frms);
5548 tmp_stats[i++] =
5549 (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 |
5550 le32_to_cpu(stat_info->tmac_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005551 tmp_stats[i++] =
5552 (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 |
5553 le32_to_cpu(stat_info->tmac_any_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005554 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005556 tmp_stats[i++] =
5557 (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 |
5558 le32_to_cpu(stat_info->tmac_vld_ip);
5559 tmp_stats[i++] =
5560 (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 |
5561 le32_to_cpu(stat_info->tmac_drop_ip);
5562 tmp_stats[i++] =
5563 (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 |
5564 le32_to_cpu(stat_info->tmac_icmp);
5565 tmp_stats[i++] =
5566 (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 |
5567 le32_to_cpu(stat_info->tmac_rst_tcp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005569 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 |
5570 le32_to_cpu(stat_info->tmac_udp);
5571 tmp_stats[i++] =
5572 (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 |
5573 le32_to_cpu(stat_info->rmac_vld_frms);
5574 tmp_stats[i++] =
5575 (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 |
5576 le32_to_cpu(stat_info->rmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms);
5578 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005579 tmp_stats[i++] =
5580 (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 |
5581 le32_to_cpu(stat_info->rmac_vld_mcst_frms);
5582 tmp_stats[i++] =
5583 (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 |
5584 le32_to_cpu(stat_info->rmac_vld_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005586 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_out_rng_len_err_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms);
5588 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005589 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_unsup_ctrl_frms);
5590 tmp_stats[i++] =
5591 (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 |
5592 le32_to_cpu(stat_info->rmac_ttl_octets);
5593 tmp_stats[i++] =
5594 (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow)
5595 << 32 | le32_to_cpu(stat_info->rmac_accepted_ucst_frms);
5596 tmp_stats[i++] =
5597 (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow)
5598 << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005599 tmp_stats[i++] =
5600 (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 |
5601 le32_to_cpu(stat_info->rmac_discarded_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005602 tmp_stats[i++] =
5603 (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow)
5604 << 32 | le32_to_cpu(stat_info->rmac_drop_events);
5605 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets);
5606 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005607 tmp_stats[i++] =
5608 (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 |
5609 le32_to_cpu(stat_info->rmac_usized_frms);
5610 tmp_stats[i++] =
5611 (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 |
5612 le32_to_cpu(stat_info->rmac_osized_frms);
5613 tmp_stats[i++] =
5614 (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 |
5615 le32_to_cpu(stat_info->rmac_frag_frms);
5616 tmp_stats[i++] =
5617 (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 |
5618 le32_to_cpu(stat_info->rmac_jabber_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005619 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_64_frms);
5620 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms);
5621 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms);
5622 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms);
5623 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms);
5624 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms);
5625 tmp_stats[i++] =
5626 (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005627 le32_to_cpu(stat_info->rmac_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets);
5629 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005630 tmp_stats[i++] =
5631 (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005632 le32_to_cpu(stat_info->rmac_drop_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005633 tmp_stats[i++] =
5634 (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005635 le32_to_cpu(stat_info->rmac_icmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005637 tmp_stats[i++] =
5638 (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005639 le32_to_cpu(stat_info->rmac_udp);
5640 tmp_stats[i++] =
5641 (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 |
5642 le32_to_cpu(stat_info->rmac_err_drp_udp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005643 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_err_sym);
5644 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0);
5645 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1);
5646 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2);
5647 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3);
5648 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4);
5649 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5);
5650 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6);
5651 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7);
5652 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0);
5653 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1);
5654 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2);
5655 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3);
5656 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4);
5657 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5);
5658 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6);
5659 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005660 tmp_stats[i++] =
5661 (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 |
5662 le32_to_cpu(stat_info->rmac_pause_cnt);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005663 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_data_err_cnt);
5664 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005665 tmp_stats[i++] =
5666 (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 |
5667 le32_to_cpu(stat_info->rmac_accepted_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005669 tmp_stats[i++] = le32_to_cpu(stat_info->rd_req_cnt);
5670 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_cnt);
5671 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_rtry_cnt);
5672 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_cnt);
5673 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_rd_ack_cnt);
5674 tmp_stats[i++] = le32_to_cpu(stat_info->wr_req_cnt);
5675 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_cnt);
5676 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_rtry_cnt);
5677 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_cnt);
5678 tmp_stats[i++] = le32_to_cpu(stat_info->wr_disc_cnt);
5679 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_wr_ack_cnt);
5680 tmp_stats[i++] = le32_to_cpu(stat_info->txp_wr_cnt);
5681 tmp_stats[i++] = le32_to_cpu(stat_info->txd_rd_cnt);
5682 tmp_stats[i++] = le32_to_cpu(stat_info->txd_wr_cnt);
5683 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_rd_cnt);
5684 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_wr_cnt);
5685 tmp_stats[i++] = le32_to_cpu(stat_info->txf_rd_cnt);
5686 tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt);
5687 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms);
5688 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms);
5689 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_8192_max_frms);
5690 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms);
5691 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms);
5692 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms);
5693 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms);
5694 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms);
5695 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard);
5696 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard);
5697 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard);
5698 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard);
5699 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard);
5700 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard);
5701 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard);
5702 tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005703 tmp_stats[i++] = 0;
5704 tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
5705 tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
Ananda Rajubd1034f2006-04-21 19:20:22 -04005706 tmp_stats[i++] = stat_info->sw_stat.parity_err_cnt;
5707 tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt;
5708 tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt;
5709 tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt;
5710 tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt;
5711 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high;
5712 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low;
5713 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high;
5714 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_low;
5715 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_high;
5716 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_low;
5717 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_high;
5718 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_low;
5719 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_high;
5720 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_low;
5721 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_high;
5722 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_low;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005723 tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt;
5724 tmp_stats[i++] = stat_info->sw_stat.sending_both;
5725 tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts;
5726 tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts;
Andrew Mortonfe931392006-02-03 01:45:12 -08005727 if (stat_info->sw_stat.num_aggregations) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04005728 u64 tmp = stat_info->sw_stat.sum_avg_pkts_aggregated;
5729 int count = 0;
5730 /*
5731 * Since 64-bit divide does not work on all platforms,
5732 * do repeated subtraction.
5733 */
5734 while (tmp >= stat_info->sw_stat.num_aggregations) {
5735 tmp -= stat_info->sw_stat.num_aggregations;
5736 count++;
5737 }
5738 tmp_stats[i++] = count;
Andrew Mortonfe931392006-02-03 01:45:12 -08005739 }
Ananda Rajubd1034f2006-04-21 19:20:22 -04005740 else
5741 tmp_stats[i++] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742}
5743
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005744static int s2io_ethtool_get_regs_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745{
5746 return (XENA_REG_SPACE);
5747}
5748
5749
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005750static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005751{
5752 nic_t *sp = dev->priv;
5753
5754 return (sp->rx_csum);
5755}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005756
5757static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758{
5759 nic_t *sp = dev->priv;
5760
5761 if (data)
5762 sp->rx_csum = 1;
5763 else
5764 sp->rx_csum = 0;
5765
5766 return 0;
5767}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005768
5769static int s2io_get_eeprom_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770{
5771 return (XENA_EEPROM_SPACE);
5772}
5773
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005774static int s2io_ethtool_self_test_count(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775{
5776 return (S2IO_TEST_LEN);
5777}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005778
5779static void s2io_ethtool_get_strings(struct net_device *dev,
5780 u32 stringset, u8 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781{
5782 switch (stringset) {
5783 case ETH_SS_TEST:
5784 memcpy(data, s2io_gstrings, S2IO_STRINGS_LEN);
5785 break;
5786 case ETH_SS_STATS:
5787 memcpy(data, &ethtool_stats_keys,
5788 sizeof(ethtool_stats_keys));
5789 }
5790}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791static int s2io_ethtool_get_stats_count(struct net_device *dev)
5792{
5793 return (S2IO_STAT_LEN);
5794}
5795
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005796static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797{
5798 if (data)
5799 dev->features |= NETIF_F_IP_CSUM;
5800 else
5801 dev->features &= ~NETIF_F_IP_CSUM;
5802
5803 return 0;
5804}
5805
5806
5807static struct ethtool_ops netdev_ethtool_ops = {
5808 .get_settings = s2io_ethtool_gset,
5809 .set_settings = s2io_ethtool_sset,
5810 .get_drvinfo = s2io_ethtool_gdrvinfo,
5811 .get_regs_len = s2io_ethtool_get_regs_len,
5812 .get_regs = s2io_ethtool_gregs,
5813 .get_link = ethtool_op_get_link,
5814 .get_eeprom_len = s2io_get_eeprom_len,
5815 .get_eeprom = s2io_ethtool_geeprom,
5816 .set_eeprom = s2io_ethtool_seeprom,
5817 .get_pauseparam = s2io_ethtool_getpause_data,
5818 .set_pauseparam = s2io_ethtool_setpause_data,
5819 .get_rx_csum = s2io_ethtool_get_rx_csum,
5820 .set_rx_csum = s2io_ethtool_set_rx_csum,
5821 .get_tx_csum = ethtool_op_get_tx_csum,
5822 .set_tx_csum = s2io_ethtool_op_set_tx_csum,
5823 .get_sg = ethtool_op_get_sg,
5824 .set_sg = ethtool_op_set_sg,
5825#ifdef NETIF_F_TSO
5826 .get_tso = ethtool_op_get_tso,
5827 .set_tso = ethtool_op_set_tso,
5828#endif
Ananda Rajufed5ecc2005-11-14 15:25:08 -05005829 .get_ufo = ethtool_op_get_ufo,
5830 .set_ufo = ethtool_op_set_ufo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831 .self_test_count = s2io_ethtool_self_test_count,
5832 .self_test = s2io_ethtool_test,
5833 .get_strings = s2io_ethtool_get_strings,
5834 .phys_id = s2io_ethtool_idnic,
5835 .get_stats_count = s2io_ethtool_get_stats_count,
5836 .get_ethtool_stats = s2io_get_ethtool_stats
5837};
5838
5839/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005840 * s2io_ioctl - Entry point for the Ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841 * @dev : Device pointer.
5842 * @ifr : An IOCTL specefic structure, that can contain a pointer to
5843 * a proprietary structure used to pass information to the driver.
5844 * @cmd : This is used to distinguish between the different commands that
5845 * can be passed to the IOCTL functions.
5846 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005847 * Currently there are no special functionality supported in IOCTL, hence
5848 * function always return EOPNOTSUPPORTED
Linus Torvalds1da177e2005-04-16 15:20:36 -07005849 */
5850
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005851static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005852{
5853 return -EOPNOTSUPP;
5854}
5855
5856/**
5857 * s2io_change_mtu - entry point to change MTU size for the device.
5858 * @dev : device pointer.
5859 * @new_mtu : the new MTU size for the device.
5860 * Description: A driver entry point to change MTU size for the device.
5861 * Before changing the MTU the device must be stopped.
5862 * Return value:
5863 * 0 on success and an appropriate (-)ve integer as defined in errno.h
5864 * file on failure.
5865 */
5866
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005867static int s2io_change_mtu(struct net_device *dev, int new_mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868{
5869 nic_t *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870
5871 if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
5872 DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
5873 dev->name);
5874 return -EPERM;
5875 }
5876
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877 dev->mtu = new_mtu;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005878 if (netif_running(dev)) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04005879 s2io_card_down(sp, 0);
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005880 netif_stop_queue(dev);
5881 if (s2io_card_up(sp)) {
5882 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
5883 __FUNCTION__);
5884 }
5885 if (netif_queue_stopped(dev))
5886 netif_wake_queue(dev);
5887 } else { /* Device is down */
5888 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5889 u64 val64 = new_mtu;
5890
5891 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
5892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893
5894 return 0;
5895}
5896
5897/**
5898 * s2io_tasklet - Bottom half of the ISR.
5899 * @dev_adr : address of the device structure in dma_addr_t format.
5900 * Description:
5901 * This is the tasklet or the bottom half of the ISR. This is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005902 * an extension of the ISR which is scheduled by the scheduler to be run
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903 * 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 -07005904 * be pushed into the tasklet. For now the tasklet is used only to
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905 * replenish the Rx buffers in the Rx buffer descriptors.
5906 * Return value:
5907 * void.
5908 */
5909
5910static void s2io_tasklet(unsigned long dev_addr)
5911{
5912 struct net_device *dev = (struct net_device *) dev_addr;
5913 nic_t *sp = dev->priv;
5914 int i, ret;
5915 mac_info_t *mac_control;
5916 struct config_param *config;
5917
5918 mac_control = &sp->mac_control;
5919 config = &sp->config;
5920
5921 if (!TASKLET_IN_USE) {
5922 for (i = 0; i < config->rx_ring_num; i++) {
5923 ret = fill_rx_buffers(sp, i);
5924 if (ret == -ENOMEM) {
5925 DBG_PRINT(ERR_DBG, "%s: Out of ",
5926 dev->name);
5927 DBG_PRINT(ERR_DBG, "memory in tasklet\n");
5928 break;
5929 } else if (ret == -EFILL) {
5930 DBG_PRINT(ERR_DBG,
5931 "%s: Rx Ring %d is full\n",
5932 dev->name, i);
5933 break;
5934 }
5935 }
5936 clear_bit(0, (&sp->tasklet_status));
5937 }
5938}
5939
5940/**
5941 * s2io_set_link - Set the LInk status
5942 * @data: long pointer to device private structue
5943 * Description: Sets the link status for the adapter
5944 */
5945
5946static void s2io_set_link(unsigned long data)
5947{
5948 nic_t *nic = (nic_t *) data;
5949 struct net_device *dev = nic->dev;
5950 XENA_dev_config_t __iomem *bar0 = nic->bar0;
5951 register u64 val64;
5952 u16 subid;
5953
5954 if (test_and_set_bit(0, &(nic->link_state))) {
5955 /* The card is being reset, no point doing anything */
5956 return;
5957 }
5958
5959 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07005960 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
5961 /*
5962 * Allow a small delay for the NICs self initiated
5963 * cleanup to complete.
5964 */
5965 msleep(100);
5966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967
5968 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005969 if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970 if (LINK_IS_UP(val64)) {
5971 val64 = readq(&bar0->adapter_control);
5972 val64 |= ADAPTER_CNTL_EN;
5973 writeq(val64, &bar0->adapter_control);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005974 if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
5975 subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976 val64 = readq(&bar0->gpio_control);
5977 val64 |= GPIO_CTRL_GPIO_0;
5978 writeq(val64, &bar0->gpio_control);
5979 val64 = readq(&bar0->gpio_control);
5980 } else {
5981 val64 |= ADAPTER_LED_ON;
5982 writeq(val64, &bar0->adapter_control);
5983 }
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07005984 if (s2io_link_fault_indication(nic) ==
5985 MAC_RMAC_ERR_TIMER) {
5986 val64 = readq(&bar0->adapter_status);
5987 if (!LINK_IS_UP(val64)) {
5988 DBG_PRINT(ERR_DBG, "%s:", dev->name);
5989 DBG_PRINT(ERR_DBG, " Link down");
5990 DBG_PRINT(ERR_DBG, "after ");
5991 DBG_PRINT(ERR_DBG, "enabling ");
5992 DBG_PRINT(ERR_DBG, "device \n");
5993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994 }
5995 if (nic->device_enabled_once == FALSE) {
5996 nic->device_enabled_once = TRUE;
5997 }
5998 s2io_link(nic, LINK_UP);
5999 } else {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006000 if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
6001 subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002 val64 = readq(&bar0->gpio_control);
6003 val64 &= ~GPIO_CTRL_GPIO_0;
6004 writeq(val64, &bar0->gpio_control);
6005 val64 = readq(&bar0->gpio_control);
6006 }
6007 s2io_link(nic, LINK_DOWN);
6008 }
6009 } else { /* NIC is not Quiescent. */
6010 DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
6011 DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
6012 netif_stop_queue(dev);
6013 }
6014 clear_bit(0, &(nic->link_state));
6015}
6016
Ananda Raju5d3213c2006-04-21 19:23:26 -04006017static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
6018 struct sk_buff **skb, u64 *temp0, u64 *temp1,
6019 u64 *temp2, int size)
6020{
6021 struct net_device *dev = sp->dev;
6022 struct sk_buff *frag_list;
6023
6024 if ((sp->rxd_mode == RXD_MODE_1) && (rxdp->Host_Control == 0)) {
6025 /* allocate skb */
6026 if (*skb) {
6027 DBG_PRINT(INFO_DBG, "SKB is not NULL\n");
6028 /*
6029 * As Rx frame are not going to be processed,
6030 * using same mapped address for the Rxd
6031 * buffer pointer
6032 */
6033 ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0;
6034 } else {
6035 *skb = dev_alloc_skb(size);
6036 if (!(*skb)) {
6037 DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
6038 DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
6039 return -ENOMEM ;
6040 }
6041 /* storing the mapped addr in a temp variable
6042 * such it will be used for next rxd whose
6043 * Host Control is NULL
6044 */
6045 ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0 =
6046 pci_map_single( sp->pdev, (*skb)->data,
6047 size - NET_IP_ALIGN,
6048 PCI_DMA_FROMDEVICE);
6049 rxdp->Host_Control = (unsigned long) (*skb);
6050 }
6051 } else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
6052 /* Two buffer Mode */
6053 if (*skb) {
6054 ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
6055 ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
6056 ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
6057 } else {
6058 *skb = dev_alloc_skb(size);
6059 ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
6060 pci_map_single(sp->pdev, (*skb)->data,
6061 dev->mtu + 4,
6062 PCI_DMA_FROMDEVICE);
6063 ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
6064 pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
6065 PCI_DMA_FROMDEVICE);
6066 rxdp->Host_Control = (unsigned long) (*skb);
6067
6068 /* Buffer-1 will be dummy buffer not used */
6069 ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
6070 pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
6071 PCI_DMA_FROMDEVICE);
6072 }
6073 } else if ((rxdp->Host_Control == 0)) {
6074 /* Three buffer mode */
6075 if (*skb) {
6076 ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
6077 ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
6078 ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
6079 } else {
6080 *skb = dev_alloc_skb(size);
6081
6082 ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
6083 pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
6084 PCI_DMA_FROMDEVICE);
6085 /* Buffer-1 receives L3/L4 headers */
6086 ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
6087 pci_map_single( sp->pdev, (*skb)->data,
6088 l3l4hdr_size + 4,
6089 PCI_DMA_FROMDEVICE);
6090 /*
6091 * skb_shinfo(skb)->frag_list will have L4
6092 * data payload
6093 */
6094 skb_shinfo(*skb)->frag_list = dev_alloc_skb(dev->mtu +
6095 ALIGN_SIZE);
6096 if (skb_shinfo(*skb)->frag_list == NULL) {
6097 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb \
6098 failed\n ", dev->name);
6099 return -ENOMEM ;
6100 }
6101 frag_list = skb_shinfo(*skb)->frag_list;
6102 frag_list->next = NULL;
6103 /*
6104 * Buffer-2 receives L4 data payload
6105 */
6106 ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
6107 pci_map_single( sp->pdev, frag_list->data,
6108 dev->mtu, PCI_DMA_FROMDEVICE);
6109 }
6110 }
6111 return 0;
6112}
6113static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size)
6114{
6115 struct net_device *dev = sp->dev;
6116 if (sp->rxd_mode == RXD_MODE_1) {
6117 rxdp->Control_2 = SET_BUFFER0_SIZE_1( size - NET_IP_ALIGN);
6118 } else if (sp->rxd_mode == RXD_MODE_3B) {
6119 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
6120 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
6121 rxdp->Control_2 |= SET_BUFFER2_SIZE_3( dev->mtu + 4);
6122 } else {
6123 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
6124 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
6125 rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
6126 }
6127}
6128
6129static int rxd_owner_bit_reset(nic_t *sp)
6130{
6131 int i, j, k, blk_cnt = 0, size;
6132 mac_info_t * mac_control = &sp->mac_control;
6133 struct config_param *config = &sp->config;
6134 struct net_device *dev = sp->dev;
6135 RxD_t *rxdp = NULL;
6136 struct sk_buff *skb = NULL;
6137 buffAdd_t *ba = NULL;
6138 u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0;
6139
6140 /* Calculate the size based on ring mode */
6141 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
6142 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
6143 if (sp->rxd_mode == RXD_MODE_1)
6144 size += NET_IP_ALIGN;
6145 else if (sp->rxd_mode == RXD_MODE_3B)
6146 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
6147 else
6148 size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
6149
6150 for (i = 0; i < config->rx_ring_num; i++) {
6151 blk_cnt = config->rx_cfg[i].num_rxd /
6152 (rxd_count[sp->rxd_mode] +1);
6153
6154 for (j = 0; j < blk_cnt; j++) {
6155 for (k = 0; k < rxd_count[sp->rxd_mode]; k++) {
6156 rxdp = mac_control->rings[i].
6157 rx_blocks[j].rxds[k].virt_addr;
6158 if(sp->rxd_mode >= RXD_MODE_3A)
6159 ba = &mac_control->rings[i].ba[j][k];
6160 set_rxd_buffer_pointer(sp, rxdp, ba,
6161 &skb,(u64 *)&temp0_64,
6162 (u64 *)&temp1_64,
6163 (u64 *)&temp2_64, size);
6164
6165 set_rxd_buffer_size(sp, rxdp, size);
6166 wmb();
6167 /* flip the Ownership bit to Hardware */
6168 rxdp->Control_1 |= RXD_OWN_XENA;
6169 }
6170 }
6171 }
6172 return 0;
6173
6174}
6175
Ananda Rajuc92ca042006-04-21 19:18:03 -04006176static void s2io_card_down(nic_t * sp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006177{
6178 int cnt = 0;
6179 XENA_dev_config_t __iomem *bar0 = sp->bar0;
6180 unsigned long flags;
6181 register u64 val64 = 0;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006182 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006183
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07006184 del_timer_sync(&sp->alarm_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185 /* If s2io_set_link task is executing, wait till it completes. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006186 while (test_and_set_bit(0, &(sp->link_state))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006187 msleep(50);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189 atomic_set(&sp->card_state, CARD_DOWN);
6190
6191 /* disable Tx and Rx traffic on the NIC */
6192 stop_nic(sp);
Ananda Rajuc92ca042006-04-21 19:18:03 -04006193 if (flag) {
6194 if (sp->intr_type == MSI_X) {
6195 int i;
6196 u16 msi_control;
6197
6198 for (i=1; (sp->s2io_entries[i].in_use ==
6199 MSIX_REGISTERED_SUCCESS); i++) {
6200 int vector = sp->entries[i].vector;
6201 void *arg = sp->s2io_entries[i].arg;
6202
6203 free_irq(vector, arg);
6204 }
6205 pci_read_config_word(sp->pdev, 0x42, &msi_control);
6206 msi_control &= 0xFFFE; /* Disable MSI */
6207 pci_write_config_word(sp->pdev, 0x42, msi_control);
6208 pci_disable_msix(sp->pdev);
6209 } else {
6210 free_irq(sp->pdev->irq, dev);
6211 if (sp->intr_type == MSI)
6212 pci_disable_msi(sp->pdev);
6213 }
6214 }
6215 /* Waiting till all Interrupt handlers are complete */
6216 cnt = 0;
6217 do {
6218 msleep(10);
6219 if (!atomic_read(&sp->isr_cnt))
6220 break;
6221 cnt++;
6222 } while(cnt < 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223
6224 /* Kill tasklet. */
6225 tasklet_kill(&sp->task);
6226
6227 /* Check if the device is Quiescent and then Reset the NIC */
6228 do {
Ananda Raju5d3213c2006-04-21 19:23:26 -04006229 /* As per the HW requirement we need to replenish the
6230 * receive buffer to avoid the ring bump. Since there is
6231 * no intention of processing the Rx frame at this pointwe are
6232 * just settting the ownership bit of rxd in Each Rx
6233 * ring to HW and set the appropriate buffer size
6234 * based on the ring mode
6235 */
6236 rxd_owner_bit_reset(sp);
6237
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006239 if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240 break;
6241 }
6242
6243 msleep(50);
6244 cnt++;
6245 if (cnt == 10) {
6246 DBG_PRINT(ERR_DBG,
6247 "s2io_close:Device not Quiescent ");
6248 DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n",
6249 (unsigned long long) val64);
6250 break;
6251 }
6252 } while (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253 s2io_reset(sp);
6254
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006255 spin_lock_irqsave(&sp->tx_lock, flags);
6256 /* Free all Tx buffers */
6257 free_tx_buffers(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006259
6260 /* Free all Rx buffers */
6261 spin_lock_irqsave(&sp->rx_lock, flags);
6262 free_rx_buffers(sp);
6263 spin_unlock_irqrestore(&sp->rx_lock, flags);
6264
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265 clear_bit(0, &(sp->link_state));
6266}
6267
6268static int s2io_card_up(nic_t * sp)
6269{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006270 int i, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271 mac_info_t *mac_control;
6272 struct config_param *config;
6273 struct net_device *dev = (struct net_device *) sp->dev;
6274
6275 /* Initialize the H/W I/O registers */
6276 if (init_nic(sp) != 0) {
6277 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
6278 dev->name);
6279 return -ENODEV;
6280 }
6281
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006282 if (sp->intr_type == MSI)
6283 ret = s2io_enable_msi(sp);
6284 else if (sp->intr_type == MSI_X)
6285 ret = s2io_enable_msi_x(sp);
6286 if (ret) {
6287 DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
6288 sp->intr_type = INTA;
6289 }
6290
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006291 /*
6292 * Initializing the Rx buffers. For now we are considering only 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07006293 * Rx ring and initializing buffers into 30 Rx blocks
6294 */
6295 mac_control = &sp->mac_control;
6296 config = &sp->config;
6297
6298 for (i = 0; i < config->rx_ring_num; i++) {
6299 if ((ret = fill_rx_buffers(sp, i))) {
6300 DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
6301 dev->name);
6302 s2io_reset(sp);
6303 free_rx_buffers(sp);
6304 return -ENOMEM;
6305 }
6306 DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
6307 atomic_read(&sp->rx_bufs_left[i]));
6308 }
6309
6310 /* Setting its receive mode */
6311 s2io_set_multicast(dev);
6312
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006313 if (sp->lro) {
6314 /* Initialize max aggregatable pkts based on MTU */
6315 sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
6316 /* Check if we can use(if specified) user provided value */
6317 if (lro_max_pkts < sp->lro_max_aggr_per_sess)
6318 sp->lro_max_aggr_per_sess = lro_max_pkts;
6319 }
6320
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321 /* Enable tasklet for the device */
6322 tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
6323
6324 /* Enable Rx Traffic and interrupts on the NIC */
6325 if (start_nic(sp)) {
6326 DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
6327 tasklet_kill(&sp->task);
6328 s2io_reset(sp);
6329 free_irq(dev->irq, dev);
6330 free_rx_buffers(sp);
6331 return -ENODEV;
6332 }
6333
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07006334 S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
6335
Linus Torvalds1da177e2005-04-16 15:20:36 -07006336 atomic_set(&sp->card_state, CARD_UP);
6337 return 0;
6338}
6339
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006340/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341 * s2io_restart_nic - Resets the NIC.
6342 * @data : long pointer to the device private structure
6343 * Description:
6344 * This function is scheduled to be run by the s2io_tx_watchdog
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006345 * function after 0.5 secs to reset the NIC. The idea is to reduce
Linus Torvalds1da177e2005-04-16 15:20:36 -07006346 * the run time of the watch dog routine which is run holding a
6347 * spin lock.
6348 */
6349
6350static void s2io_restart_nic(unsigned long data)
6351{
6352 struct net_device *dev = (struct net_device *) data;
6353 nic_t *sp = dev->priv;
6354
Ananda Rajuc92ca042006-04-21 19:18:03 -04006355 s2io_card_down(sp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006356 if (s2io_card_up(sp)) {
6357 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
6358 dev->name);
6359 }
6360 netif_wake_queue(dev);
6361 DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
6362 dev->name);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006363
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364}
6365
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006366/**
6367 * s2io_tx_watchdog - Watchdog for transmit side.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 * @dev : Pointer to net device structure
6369 * Description:
6370 * This function is triggered if the Tx Queue is stopped
6371 * for a pre-defined amount of time when the Interface is still up.
6372 * If the Interface is jammed in such a situation, the hardware is
6373 * reset (by s2io_close) and restarted again (by s2io_open) to
6374 * overcome any problem that might have been caused in the hardware.
6375 * Return value:
6376 * void
6377 */
6378
6379static void s2io_tx_watchdog(struct net_device *dev)
6380{
6381 nic_t *sp = dev->priv;
6382
6383 if (netif_carrier_ok(dev)) {
6384 schedule_work(&sp->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04006385 sp->mac_control.stats_info->sw_stat.soft_reset_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386 }
6387}
6388
6389/**
6390 * rx_osm_handler - To perform some OS related operations on SKB.
6391 * @sp: private member of the device structure,pointer to s2io_nic structure.
6392 * @skb : the socket buffer pointer.
6393 * @len : length of the packet
6394 * @cksum : FCS checksum of the frame.
6395 * @ring_no : the ring from which this RxD was extracted.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006396 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397 * This function is called by the Tx interrupt serivce routine to perform
6398 * some OS related operations on the SKB before passing it to the upper
6399 * layers. It mainly checks if the checksum is OK, if so adds it to the
6400 * SKBs cksum variable, increments the Rx packet count and passes the SKB
6401 * to the upper layer. If the checksum is wrong, it increments the Rx
6402 * packet error count, frees the SKB and returns error.
6403 * Return value:
6404 * SUCCESS on success and -1 on failure.
6405 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006406static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006407{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006408 nic_t *sp = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006409 struct net_device *dev = (struct net_device *) sp->dev;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006410 struct sk_buff *skb = (struct sk_buff *)
6411 ((unsigned long) rxdp->Host_Control);
6412 int ring_no = ring_data->ring_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413 u16 l3_csum, l4_csum;
Ananda Raju863c11a2006-04-21 19:03:13 -04006414 unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006415 lro_t *lro;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006416
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006417 skb->dev = dev;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006418
Ananda Raju863c11a2006-04-21 19:03:13 -04006419 if (err) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04006420 /* Check for parity error */
6421 if (err & 0x1) {
6422 sp->mac_control.stats_info->sw_stat.parity_err_cnt++;
6423 }
6424
Ananda Raju863c11a2006-04-21 19:03:13 -04006425 /*
6426 * Drop the packet if bad transfer code. Exception being
6427 * 0x5, which could be due to unsupported IPv6 extension header.
6428 * In this case, we let stack handle the packet.
6429 * Note that in this case, since checksum will be incorrect,
6430 * stack will validate the same.
6431 */
6432 if (err && ((err >> 48) != 0x5)) {
6433 DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
6434 dev->name, err);
6435 sp->stats.rx_crc_errors++;
6436 dev_kfree_skb(skb);
6437 atomic_dec(&sp->rx_bufs_left[ring_no]);
6438 rxdp->Host_Control = 0;
6439 return 0;
6440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006441 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006443 /* Updating statistics */
6444 rxdp->Host_Control = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006445 sp->rx_pkt_count++;
6446 sp->stats.rx_packets++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006447 if (sp->rxd_mode == RXD_MODE_1) {
6448 int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449
Ananda Rajuda6971d2005-10-31 16:55:31 -05006450 sp->stats.rx_bytes += len;
6451 skb_put(skb, len);
6452
6453 } else if (sp->rxd_mode >= RXD_MODE_3A) {
6454 int get_block = ring_data->rx_curr_get_info.block_index;
6455 int get_off = ring_data->rx_curr_get_info.offset;
6456 int buf0_len = RXD_GET_BUFFER0_SIZE_3(rxdp->Control_2);
6457 int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
6458 unsigned char *buff = skb_push(skb, buf0_len);
6459
6460 buffAdd_t *ba = &ring_data->ba[get_block][get_off];
6461 sp->stats.rx_bytes += buf0_len + buf2_len;
6462 memcpy(buff, ba->ba_0, buf0_len);
6463
6464 if (sp->rxd_mode == RXD_MODE_3A) {
6465 int buf1_len = RXD_GET_BUFFER1_SIZE_3(rxdp->Control_2);
6466
6467 skb_put(skb, buf1_len);
6468 skb->len += buf2_len;
6469 skb->data_len += buf2_len;
6470 skb->truesize += buf2_len;
6471 skb_put(skb_shinfo(skb)->frag_list, buf2_len);
6472 sp->stats.rx_bytes += buf1_len;
6473
6474 } else
6475 skb_put(skb, buf2_len);
6476 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006477
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006478 if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
6479 (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006480 (sp->rx_csum)) {
6481 l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
6482 l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
6483 if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) {
6484 /*
6485 * NIC verifies if the Checksum of the received
6486 * frame is Ok or not and accordingly returns
6487 * a flag in the RxD.
6488 */
6489 skb->ip_summed = CHECKSUM_UNNECESSARY;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006490 if (sp->lro) {
6491 u32 tcp_len;
6492 u8 *tcp;
6493 int ret = 0;
6494
6495 ret = s2io_club_tcp_session(skb->data, &tcp,
6496 &tcp_len, &lro, rxdp, sp);
6497 switch (ret) {
6498 case 3: /* Begin anew */
6499 lro->parent = skb;
6500 goto aggregate;
6501 case 1: /* Aggregate */
6502 {
6503 lro_append_pkt(sp, lro,
6504 skb, tcp_len);
6505 goto aggregate;
6506 }
6507 case 4: /* Flush session */
6508 {
6509 lro_append_pkt(sp, lro,
6510 skb, tcp_len);
6511 queue_rx_frame(lro->parent);
6512 clear_lro_session(lro);
6513 sp->mac_control.stats_info->
6514 sw_stat.flush_max_pkts++;
6515 goto aggregate;
6516 }
6517 case 2: /* Flush both */
6518 lro->parent->data_len =
6519 lro->frags_len;
6520 sp->mac_control.stats_info->
6521 sw_stat.sending_both++;
6522 queue_rx_frame(lro->parent);
6523 clear_lro_session(lro);
6524 goto send_up;
6525 case 0: /* sessions exceeded */
Ananda Rajuc92ca042006-04-21 19:18:03 -04006526 case -1: /* non-TCP or not
6527 * L2 aggregatable
6528 */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006529 case 5: /*
6530 * First pkt in session not
6531 * L3/L4 aggregatable
6532 */
6533 break;
6534 default:
6535 DBG_PRINT(ERR_DBG,
6536 "%s: Samadhana!!\n",
6537 __FUNCTION__);
6538 BUG();
6539 }
6540 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006541 } else {
6542 /*
6543 * Packet with erroneous checksum, let the
6544 * upper layers deal with it.
6545 */
6546 skb->ip_summed = CHECKSUM_NONE;
6547 }
6548 } else {
6549 skb->ip_summed = CHECKSUM_NONE;
6550 }
6551
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006552 if (!sp->lro) {
6553 skb->protocol = eth_type_trans(skb, dev);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006554#ifdef CONFIG_S2IO_NAPI
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006555 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
6556 /* Queueing the vlan frame to the upper layer */
6557 vlan_hwaccel_receive_skb(skb, sp->vlgrp,
6558 RXD_GET_VLAN_TAG(rxdp->Control_2));
6559 } else {
6560 netif_receive_skb(skb);
6561 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006562#else
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006563 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
6564 /* Queueing the vlan frame to the upper layer */
6565 vlan_hwaccel_rx(skb, sp->vlgrp,
6566 RXD_GET_VLAN_TAG(rxdp->Control_2));
6567 } else {
6568 netif_rx(skb);
6569 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006570#endif
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006571 } else {
6572send_up:
6573 queue_rx_frame(skb);
6574 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006575 dev->last_rx = jiffies;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006576aggregate:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006577 atomic_dec(&sp->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006578 return SUCCESS;
6579}
6580
6581/**
6582 * s2io_link - stops/starts the Tx queue.
6583 * @sp : private member of the device structure, which is a pointer to the
6584 * s2io_nic structure.
6585 * @link : inidicates whether link is UP/DOWN.
6586 * Description:
6587 * This function stops/starts the Tx queue depending on whether the link
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006588 * status of the NIC is is down or up. This is called by the Alarm
6589 * interrupt handler whenever a link change interrupt comes up.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006590 * Return value:
6591 * void.
6592 */
6593
Adrian Bunk26df54b2006-01-14 03:09:40 +01006594static void s2io_link(nic_t * sp, int link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006595{
6596 struct net_device *dev = (struct net_device *) sp->dev;
6597
6598 if (link != sp->last_link_state) {
6599 if (link == LINK_DOWN) {
6600 DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
6601 netif_carrier_off(dev);
6602 } else {
6603 DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
6604 netif_carrier_on(dev);
6605 }
6606 }
6607 sp->last_link_state = link;
6608}
6609
6610/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006611 * get_xena_rev_id - to identify revision ID of xena.
6612 * @pdev : PCI Dev structure
6613 * Description:
6614 * Function to identify the Revision ID of xena.
6615 * Return value:
6616 * returns the revision ID of the device.
6617 */
6618
Adrian Bunk26df54b2006-01-14 03:09:40 +01006619static int get_xena_rev_id(struct pci_dev *pdev)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006620{
6621 u8 id = 0;
6622 int ret;
6623 ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id);
6624 return id;
6625}
6626
6627/**
6628 * s2io_init_pci -Initialization of PCI and PCI-X configuration registers .
6629 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07006630 * s2io_nic structure.
6631 * Description:
6632 * This function initializes a few of the PCI and PCI-X configuration registers
6633 * with recommended values.
6634 * Return value:
6635 * void
6636 */
6637
6638static void s2io_init_pci(nic_t * sp)
6639{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006640 u16 pci_cmd = 0, pcix_cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006641
6642 /* Enable Data Parity Error Recovery in PCI-X command register. */
6643 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006644 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006645 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006646 (pcix_cmd | 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006647 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006648 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006649
6650 /* Set the PErr Response bit in PCI command register. */
6651 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
6652 pci_write_config_word(sp->pdev, PCI_COMMAND,
6653 (pci_cmd | PCI_COMMAND_PARITY));
6654 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006655}
6656
6657MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
6658MODULE_LICENSE("GPL");
John Linville6c1792f2005-10-04 07:51:45 -04006659MODULE_VERSION(DRV_VERSION);
6660
Linus Torvalds1da177e2005-04-16 15:20:36 -07006661module_param(tx_fifo_num, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006662module_param(rx_ring_num, int, 0);
Ananda Rajuda6971d2005-10-31 16:55:31 -05006663module_param(rx_ring_mode, int, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006664module_param_array(tx_fifo_len, uint, NULL, 0);
6665module_param_array(rx_ring_sz, uint, NULL, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006666module_param_array(rts_frm_len, uint, NULL, 0);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07006667module_param(use_continuous_tx_intrs, int, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006668module_param(rmac_pause_time, int, 0);
6669module_param(mc_pause_threshold_q0q3, int, 0);
6670module_param(mc_pause_threshold_q4q7, int, 0);
6671module_param(shared_splits, int, 0);
6672module_param(tmac_util_period, int, 0);
6673module_param(rmac_util_period, int, 0);
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07006674module_param(bimodal, bool, 0);
Ananda Rajuda6971d2005-10-31 16:55:31 -05006675module_param(l3l4hdr_size, int , 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006676#ifndef CONFIG_S2IO_NAPI
6677module_param(indicate_max_pkts, int, 0);
6678#endif
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07006679module_param(rxsync_frequency, int, 0);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006680module_param(intr_type, int, 0);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006681module_param(lro, int, 0);
6682module_param(lro_max_pkts, int, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006683
Ananda Raju9dc737a2006-04-21 19:05:41 -04006684static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
6685{
6686 if ( tx_fifo_num > 8) {
6687 DBG_PRINT(ERR_DBG, "s2io: Requested number of Tx fifos not "
6688 "supported\n");
6689 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Tx fifos\n");
6690 tx_fifo_num = 8;
6691 }
6692 if ( rx_ring_num > 8) {
6693 DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
6694 "supported\n");
6695 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
6696 rx_ring_num = 8;
6697 }
6698#ifdef CONFIG_S2IO_NAPI
6699 if (*dev_intr_type != INTA) {
6700 DBG_PRINT(ERR_DBG, "s2io: NAPI cannot be enabled when "
6701 "MSI/MSI-X is enabled. Defaulting to INTA\n");
6702 *dev_intr_type = INTA;
6703 }
6704#endif
6705#ifndef CONFIG_PCI_MSI
6706 if (*dev_intr_type != INTA) {
6707 DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
6708 "MSI/MSI-X. Defaulting to INTA\n");
6709 *dev_intr_type = INTA;
6710 }
6711#else
6712 if (*dev_intr_type > MSI_X) {
6713 DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
6714 "Defaulting to INTA\n");
6715 *dev_intr_type = INTA;
6716 }
6717#endif
6718 if ((*dev_intr_type == MSI_X) &&
6719 ((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
6720 (pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
6721 DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. "
6722 "Defaulting to INTA\n");
6723 *dev_intr_type = INTA;
6724 }
6725 if (rx_ring_mode > 3) {
6726 DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
6727 DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
6728 rx_ring_mode = 3;
6729 }
6730 return SUCCESS;
6731}
6732
Linus Torvalds1da177e2005-04-16 15:20:36 -07006733/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006734 * s2io_init_nic - Initialization of the adapter .
Linus Torvalds1da177e2005-04-16 15:20:36 -07006735 * @pdev : structure containing the PCI related information of the device.
6736 * @pre: List of PCI devices supported by the driver listed in s2io_tbl.
6737 * Description:
6738 * The function initializes an adapter identified by the pci_dec structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006739 * All OS related initialization including memory and device structure and
6740 * initlaization of the device private variable is done. Also the swapper
6741 * control register is initialized to enable read and write into the I/O
Linus Torvalds1da177e2005-04-16 15:20:36 -07006742 * registers of the device.
6743 * Return value:
6744 * returns 0 on success and negative on failure.
6745 */
6746
6747static int __devinit
6748s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
6749{
6750 nic_t *sp;
6751 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006752 int i, j, ret;
6753 int dma_flag = FALSE;
6754 u32 mac_up, mac_down;
6755 u64 val64 = 0, tmp64 = 0;
6756 XENA_dev_config_t __iomem *bar0 = NULL;
6757 u16 subid;
6758 mac_info_t *mac_control;
6759 struct config_param *config;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006760 int mode;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006761 u8 dev_intr_type = intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006762
Ananda Raju9dc737a2006-04-21 19:05:41 -04006763 if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
6764 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006765
6766 if ((ret = pci_enable_device(pdev))) {
6767 DBG_PRINT(ERR_DBG,
6768 "s2io_init_nic: pci_enable_device failed\n");
6769 return ret;
6770 }
6771
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006772 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006773 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
6774 dma_flag = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006775 if (pci_set_consistent_dma_mask
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006776 (pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006777 DBG_PRINT(ERR_DBG,
6778 "Unable to obtain 64bit DMA for \
6779 consistent allocations\n");
6780 pci_disable_device(pdev);
6781 return -ENOMEM;
6782 }
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006783 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006784 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n");
6785 } else {
6786 pci_disable_device(pdev);
6787 return -ENOMEM;
6788 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006789 if (dev_intr_type != MSI_X) {
6790 if (pci_request_regions(pdev, s2io_driver_name)) {
6791 DBG_PRINT(ERR_DBG, "Request Regions failed\n"),
6792 pci_disable_device(pdev);
6793 return -ENODEV;
6794 }
6795 }
6796 else {
6797 if (!(request_mem_region(pci_resource_start(pdev, 0),
6798 pci_resource_len(pdev, 0), s2io_driver_name))) {
6799 DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n");
6800 pci_disable_device(pdev);
6801 return -ENODEV;
6802 }
6803 if (!(request_mem_region(pci_resource_start(pdev, 2),
6804 pci_resource_len(pdev, 2), s2io_driver_name))) {
6805 DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n");
6806 release_mem_region(pci_resource_start(pdev, 0),
6807 pci_resource_len(pdev, 0));
6808 pci_disable_device(pdev);
6809 return -ENODEV;
6810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006811 }
6812
6813 dev = alloc_etherdev(sizeof(nic_t));
6814 if (dev == NULL) {
6815 DBG_PRINT(ERR_DBG, "Device allocation failed\n");
6816 pci_disable_device(pdev);
6817 pci_release_regions(pdev);
6818 return -ENODEV;
6819 }
6820
6821 pci_set_master(pdev);
6822 pci_set_drvdata(pdev, dev);
6823 SET_MODULE_OWNER(dev);
6824 SET_NETDEV_DEV(dev, &pdev->dev);
6825
6826 /* Private member variable initialized to s2io NIC structure */
6827 sp = dev->priv;
6828 memset(sp, 0, sizeof(nic_t));
6829 sp->dev = dev;
6830 sp->pdev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006831 sp->high_dma_flag = dma_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006832 sp->device_enabled_once = FALSE;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006833 if (rx_ring_mode == 1)
6834 sp->rxd_mode = RXD_MODE_1;
6835 if (rx_ring_mode == 2)
6836 sp->rxd_mode = RXD_MODE_3B;
6837 if (rx_ring_mode == 3)
6838 sp->rxd_mode = RXD_MODE_3A;
6839
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006840 sp->intr_type = dev_intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006841
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006842 if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
6843 (pdev->device == PCI_DEVICE_ID_HERC_UNI))
6844 sp->device_type = XFRAME_II_DEVICE;
6845 else
6846 sp->device_type = XFRAME_I_DEVICE;
6847
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006848 sp->lro = lro;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006849
Linus Torvalds1da177e2005-04-16 15:20:36 -07006850 /* Initialize some PCI/PCI-X fields of the NIC. */
6851 s2io_init_pci(sp);
6852
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006853 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006854 * Setting the device configuration parameters.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006855 * Most of these parameters can be specified by the user during
6856 * module insertion as they are module loadable parameters. If
6857 * these parameters are not not specified during load time, they
Linus Torvalds1da177e2005-04-16 15:20:36 -07006858 * are initialized with default values.
6859 */
6860 mac_control = &sp->mac_control;
6861 config = &sp->config;
6862
6863 /* Tx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006864 config->tx_fifo_num = tx_fifo_num;
6865 for (i = 0; i < MAX_TX_FIFOS; i++) {
6866 config->tx_cfg[i].fifo_len = tx_fifo_len[i];
6867 config->tx_cfg[i].fifo_priority = i;
6868 }
6869
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006870 /* mapping the QoS priority to the configured fifos */
6871 for (i = 0; i < MAX_TX_FIFOS; i++)
6872 config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i];
6873
Linus Torvalds1da177e2005-04-16 15:20:36 -07006874 config->tx_intr_type = TXD_INT_TYPE_UTILZ;
6875 for (i = 0; i < config->tx_fifo_num; i++) {
6876 config->tx_cfg[i].f_no_snoop =
6877 (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER);
6878 if (config->tx_cfg[i].fifo_len < 65) {
6879 config->tx_intr_type = TXD_INT_TYPE_PER_LIST;
6880 break;
6881 }
6882 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05006883 /* + 2 because one Txd for skb->data and one Txd for UFO */
6884 config->max_txds = MAX_SKB_FRAGS + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006885
6886 /* Rx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006887 config->rx_ring_num = rx_ring_num;
6888 for (i = 0; i < MAX_RX_RINGS; i++) {
6889 config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
Ananda Rajuda6971d2005-10-31 16:55:31 -05006890 (rxd_count[sp->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006891 config->rx_cfg[i].ring_priority = i;
6892 }
6893
6894 for (i = 0; i < rx_ring_num; i++) {
6895 config->rx_cfg[i].ring_org = RING_ORG_BUFF1;
6896 config->rx_cfg[i].f_no_snoop =
6897 (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER);
6898 }
6899
6900 /* Setting Mac Control parameters */
6901 mac_control->rmac_pause_time = rmac_pause_time;
6902 mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3;
6903 mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
6904
6905
6906 /* Initialize Ring buffer parameters. */
6907 for (i = 0; i < config->rx_ring_num; i++)
6908 atomic_set(&sp->rx_bufs_left[i], 0);
6909
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006910 /* Initialize the number of ISRs currently running */
6911 atomic_set(&sp->isr_cnt, 0);
6912
Linus Torvalds1da177e2005-04-16 15:20:36 -07006913 /* initialize the shared memory used by the NIC and the host */
6914 if (init_shared_mem(sp)) {
6915 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07006916 __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006917 ret = -ENOMEM;
6918 goto mem_alloc_failed;
6919 }
6920
6921 sp->bar0 = ioremap(pci_resource_start(pdev, 0),
6922 pci_resource_len(pdev, 0));
6923 if (!sp->bar0) {
6924 DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem1\n",
6925 dev->name);
6926 ret = -ENOMEM;
6927 goto bar0_remap_failed;
6928 }
6929
6930 sp->bar1 = ioremap(pci_resource_start(pdev, 2),
6931 pci_resource_len(pdev, 2));
6932 if (!sp->bar1) {
6933 DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem2\n",
6934 dev->name);
6935 ret = -ENOMEM;
6936 goto bar1_remap_failed;
6937 }
6938
6939 dev->irq = pdev->irq;
6940 dev->base_addr = (unsigned long) sp->bar0;
6941
6942 /* Initializing the BAR1 address as the start of the FIFO pointer. */
6943 for (j = 0; j < MAX_TX_FIFOS; j++) {
6944 mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *)
6945 (sp->bar1 + (j * 0x00020000));
6946 }
6947
6948 /* Driver entry points */
6949 dev->open = &s2io_open;
6950 dev->stop = &s2io_close;
6951 dev->hard_start_xmit = &s2io_xmit;
6952 dev->get_stats = &s2io_get_stats;
6953 dev->set_multicast_list = &s2io_set_multicast;
6954 dev->do_ioctl = &s2io_ioctl;
6955 dev->change_mtu = &s2io_change_mtu;
6956 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07006957 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6958 dev->vlan_rx_register = s2io_vlan_rx_register;
6959 dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006960
Linus Torvalds1da177e2005-04-16 15:20:36 -07006961 /*
6962 * will use eth_mac_addr() for dev->set_mac_address
6963 * mac address will be set every time dev->open() is called
6964 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006965#if defined(CONFIG_S2IO_NAPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006966 dev->poll = s2io_poll;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006967 dev->weight = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006968#endif
6969
6970 dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
6971 if (sp->high_dma_flag == TRUE)
6972 dev->features |= NETIF_F_HIGHDMA;
6973#ifdef NETIF_F_TSO
6974 dev->features |= NETIF_F_TSO;
6975#endif
Ananda Rajufed5ecc2005-11-14 15:25:08 -05006976 if (sp->device_type & XFRAME_II_DEVICE) {
6977 dev->features |= NETIF_F_UFO;
6978 dev->features |= NETIF_F_HW_CSUM;
6979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006980
6981 dev->tx_timeout = &s2io_tx_watchdog;
6982 dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
6983 INIT_WORK(&sp->rst_timer_task,
6984 (void (*)(void *)) s2io_restart_nic, dev);
6985 INIT_WORK(&sp->set_link_task,
6986 (void (*)(void *)) s2io_set_link, sp);
6987
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07006988 pci_save_state(sp->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006989
6990 /* Setting swapper control on the NIC, for proper reset operation */
6991 if (s2io_set_swapper(sp)) {
6992 DBG_PRINT(ERR_DBG, "%s:swapper settings are wrong\n",
6993 dev->name);
6994 ret = -EAGAIN;
6995 goto set_swap_failed;
6996 }
6997
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006998 /* Verify if the Herc works on the slot its placed into */
6999 if (sp->device_type & XFRAME_II_DEVICE) {
7000 mode = s2io_verify_pci_mode(sp);
7001 if (mode < 0) {
7002 DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__);
7003 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
7004 ret = -EBADSLT;
7005 goto set_swap_failed;
7006 }
7007 }
7008
7009 /* Not needed for Herc */
7010 if (sp->device_type & XFRAME_I_DEVICE) {
7011 /*
7012 * Fix for all "FFs" MAC address problems observed on
7013 * Alpha platforms
7014 */
7015 fix_mac_address(sp);
7016 s2io_reset(sp);
7017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007018
7019 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007020 * MAC address initialization.
7021 * For now only one mac address will be read and used.
7022 */
7023 bar0 = sp->bar0;
7024 val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
7025 RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
7026 writeq(val64, &bar0->rmac_addr_cmd_mem);
Ananda Rajuc92ca042006-04-21 19:18:03 -04007027 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
7028 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007029 tmp64 = readq(&bar0->rmac_addr_data0_mem);
7030 mac_down = (u32) tmp64;
7031 mac_up = (u32) (tmp64 >> 32);
7032
7033 memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
7034
7035 sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up);
7036 sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8);
7037 sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16);
7038 sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_up >> 24);
7039 sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16);
7040 sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24);
7041
Linus Torvalds1da177e2005-04-16 15:20:36 -07007042 /* Set the factory defined MAC address initially */
7043 dev->addr_len = ETH_ALEN;
7044 memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
7045
7046 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007047 * Initialize the tasklet status and link state flags
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007048 * and the card state parameter
Linus Torvalds1da177e2005-04-16 15:20:36 -07007049 */
7050 atomic_set(&(sp->card_state), 0);
7051 sp->tasklet_status = 0;
7052 sp->link_state = 0;
7053
Linus Torvalds1da177e2005-04-16 15:20:36 -07007054 /* Initialize spinlocks */
7055 spin_lock_init(&sp->tx_lock);
7056#ifndef CONFIG_S2IO_NAPI
7057 spin_lock_init(&sp->put_lock);
7058#endif
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007059 spin_lock_init(&sp->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007060
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007061 /*
7062 * SXE-002: Configure link and activity LED to init state
7063 * on driver load.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007064 */
7065 subid = sp->pdev->subsystem_device;
7066 if ((subid & 0xFF) >= 0x07) {
7067 val64 = readq(&bar0->gpio_control);
7068 val64 |= 0x0000800000000000ULL;
7069 writeq(val64, &bar0->gpio_control);
7070 val64 = 0x0411040400000000ULL;
7071 writeq(val64, (void __iomem *) bar0 + 0x2700);
7072 val64 = readq(&bar0->gpio_control);
7073 }
7074
7075 sp->rx_csum = 1; /* Rx chksum verify enabled by default */
7076
7077 if (register_netdev(dev)) {
7078 DBG_PRINT(ERR_DBG, "Device registration failed\n");
7079 ret = -ENODEV;
7080 goto register_failed;
7081 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04007082 s2io_vpd_read(sp);
7083 DBG_PRINT(ERR_DBG, "%s: Neterion %s",dev->name, sp->product_name);
7084 DBG_PRINT(ERR_DBG, "(rev %d), Driver version %s\n",
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007085 get_xena_rev_id(sp->pdev),
7086 s2io_driver_version);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007087 DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n");
7088 DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
7089 "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007090 sp->def_mac_addr[0].mac_addr[0],
7091 sp->def_mac_addr[0].mac_addr[1],
7092 sp->def_mac_addr[0].mac_addr[2],
7093 sp->def_mac_addr[0].mac_addr[3],
7094 sp->def_mac_addr[0].mac_addr[4],
7095 sp->def_mac_addr[0].mac_addr[5]);
Ananda Raju9dc737a2006-04-21 19:05:41 -04007096 if (sp->device_type & XFRAME_II_DEVICE) {
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07007097 mode = s2io_print_pci_mode(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007098 if (mode < 0) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04007099 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007100 ret = -EBADSLT;
Ananda Raju9dc737a2006-04-21 19:05:41 -04007101 unregister_netdev(dev);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007102 goto set_swap_failed;
7103 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07007104 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04007105 switch(sp->rxd_mode) {
7106 case RXD_MODE_1:
7107 DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n",
7108 dev->name);
7109 break;
7110 case RXD_MODE_3B:
7111 DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n",
7112 dev->name);
7113 break;
7114 case RXD_MODE_3A:
7115 DBG_PRINT(ERR_DBG, "%s: 3-Buffer receive mode enabled\n",
7116 dev->name);
7117 break;
7118 }
7119#ifdef CONFIG_S2IO_NAPI
7120 DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
7121#endif
7122 switch(sp->intr_type) {
7123 case INTA:
7124 DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
7125 break;
7126 case MSI:
7127 DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI\n", dev->name);
7128 break;
7129 case MSI_X:
7130 DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
7131 break;
7132 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007133 if (sp->lro)
7134 DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
Ananda Raju9dc737a2006-04-21 19:05:41 -04007135 dev->name);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007136
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007137 /* Initialize device name */
Ananda Raju9dc737a2006-04-21 19:05:41 -04007138 sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07007139
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07007140 /* Initialize bimodal Interrupts */
7141 sp->config.bimodal = bimodal;
7142 if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) {
7143 sp->config.bimodal = 0;
7144 DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n",
7145 dev->name);
7146 }
7147
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007148 /*
7149 * Make Link state as off at this point, when the Link change
7150 * interrupt comes the state will be automatically changed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07007151 * the right state.
7152 */
7153 netif_carrier_off(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007154
7155 return 0;
7156
7157 register_failed:
7158 set_swap_failed:
7159 iounmap(sp->bar1);
7160 bar1_remap_failed:
7161 iounmap(sp->bar0);
7162 bar0_remap_failed:
7163 mem_alloc_failed:
7164 free_shared_mem(sp);
7165 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007166 if (dev_intr_type != MSI_X)
7167 pci_release_regions(pdev);
7168 else {
7169 release_mem_region(pci_resource_start(pdev, 0),
7170 pci_resource_len(pdev, 0));
7171 release_mem_region(pci_resource_start(pdev, 2),
7172 pci_resource_len(pdev, 2));
7173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007174 pci_set_drvdata(pdev, NULL);
7175 free_netdev(dev);
7176
7177 return ret;
7178}
7179
7180/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007181 * s2io_rem_nic - Free the PCI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07007182 * @pdev: structure containing the PCI related information of the device.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007183 * Description: This function is called by the Pci subsystem to release a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007184 * PCI device and free up all resource held up by the device. This could
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007185 * be in response to a Hot plug event or when the driver is to be removed
Linus Torvalds1da177e2005-04-16 15:20:36 -07007186 * from memory.
7187 */
7188
7189static void __devexit s2io_rem_nic(struct pci_dev *pdev)
7190{
7191 struct net_device *dev =
7192 (struct net_device *) pci_get_drvdata(pdev);
7193 nic_t *sp;
7194
7195 if (dev == NULL) {
7196 DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
7197 return;
7198 }
7199
7200 sp = dev->priv;
7201 unregister_netdev(dev);
7202
7203 free_shared_mem(sp);
7204 iounmap(sp->bar0);
7205 iounmap(sp->bar1);
7206 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007207 if (sp->intr_type != MSI_X)
7208 pci_release_regions(pdev);
7209 else {
7210 release_mem_region(pci_resource_start(pdev, 0),
7211 pci_resource_len(pdev, 0));
7212 release_mem_region(pci_resource_start(pdev, 2),
7213 pci_resource_len(pdev, 2));
7214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007215 pci_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007216 free_netdev(dev);
7217}
7218
7219/**
7220 * s2io_starter - Entry point for the driver
7221 * Description: This function is the entry point for the driver. It verifies
7222 * the module loadable parameters and initializes PCI configuration space.
7223 */
7224
7225int __init s2io_starter(void)
7226{
7227 return pci_module_init(&s2io_driver);
7228}
7229
7230/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007231 * s2io_closer - Cleanup routine for the driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07007232 * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
7233 */
7234
Adrian Bunk26df54b2006-01-14 03:09:40 +01007235static void s2io_closer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007236{
7237 pci_unregister_driver(&s2io_driver);
7238 DBG_PRINT(INIT_DBG, "cleanup done\n");
7239}
7240
7241module_init(s2io_starter);
7242module_exit(s2io_closer);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007243
7244static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
7245 struct tcphdr **tcp, RxD_t *rxdp)
7246{
7247 int ip_off;
7248 u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
7249
7250 if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) {
7251 DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n",
7252 __FUNCTION__);
7253 return -1;
7254 }
7255
7256 /* TODO:
7257 * By default the VLAN field in the MAC is stripped by the card, if this
7258 * feature is turned off in rx_pa_cfg register, then the ip_off field
7259 * has to be shifted by a further 2 bytes
7260 */
7261 switch (l2_type) {
7262 case 0: /* DIX type */
7263 case 4: /* DIX type with VLAN */
7264 ip_off = HEADER_ETHERNET_II_802_3_SIZE;
7265 break;
7266 /* LLC, SNAP etc are considered non-mergeable */
7267 default:
7268 return -1;
7269 }
7270
7271 *ip = (struct iphdr *)((u8 *)buffer + ip_off);
7272 ip_len = (u8)((*ip)->ihl);
7273 ip_len <<= 2;
7274 *tcp = (struct tcphdr *)((unsigned long)*ip + ip_len);
7275
7276 return 0;
7277}
7278
7279static int check_for_socket_match(lro_t *lro, struct iphdr *ip,
7280 struct tcphdr *tcp)
7281{
7282 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7283 if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) ||
7284 (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest))
7285 return -1;
7286 return 0;
7287}
7288
7289static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
7290{
7291 return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
7292}
7293
7294static void initiate_new_session(lro_t *lro, u8 *l2h,
7295 struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
7296{
7297 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7298 lro->l2h = l2h;
7299 lro->iph = ip;
7300 lro->tcph = tcp;
7301 lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq);
7302 lro->tcp_ack = ntohl(tcp->ack_seq);
7303 lro->sg_num = 1;
7304 lro->total_len = ntohs(ip->tot_len);
7305 lro->frags_len = 0;
7306 /*
7307 * check if we saw TCP timestamp. Other consistency checks have
7308 * already been done.
7309 */
7310 if (tcp->doff == 8) {
7311 u32 *ptr;
7312 ptr = (u32 *)(tcp+1);
7313 lro->saw_ts = 1;
7314 lro->cur_tsval = *(ptr+1);
7315 lro->cur_tsecr = *(ptr+2);
7316 }
7317 lro->in_use = 1;
7318}
7319
7320static void update_L3L4_header(nic_t *sp, lro_t *lro)
7321{
7322 struct iphdr *ip = lro->iph;
7323 struct tcphdr *tcp = lro->tcph;
7324 u16 nchk;
7325 StatInfo_t *statinfo = sp->mac_control.stats_info;
7326 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7327
7328 /* Update L3 header */
7329 ip->tot_len = htons(lro->total_len);
7330 ip->check = 0;
7331 nchk = ip_fast_csum((u8 *)lro->iph, ip->ihl);
7332 ip->check = nchk;
7333
7334 /* Update L4 header */
7335 tcp->ack_seq = lro->tcp_ack;
7336 tcp->window = lro->window;
7337
7338 /* Update tsecr field if this session has timestamps enabled */
7339 if (lro->saw_ts) {
7340 u32 *ptr = (u32 *)(tcp + 1);
7341 *(ptr+2) = lro->cur_tsecr;
7342 }
7343
7344 /* Update counters required for calculation of
7345 * average no. of packets aggregated.
7346 */
7347 statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num;
7348 statinfo->sw_stat.num_aggregations++;
7349}
7350
7351static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
7352 struct tcphdr *tcp, u32 l4_pyld)
7353{
7354 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7355 lro->total_len += l4_pyld;
7356 lro->frags_len += l4_pyld;
7357 lro->tcp_next_seq += l4_pyld;
7358 lro->sg_num++;
7359
7360 /* Update ack seq no. and window ad(from this pkt) in LRO object */
7361 lro->tcp_ack = tcp->ack_seq;
7362 lro->window = tcp->window;
7363
7364 if (lro->saw_ts) {
7365 u32 *ptr;
7366 /* Update tsecr and tsval from this packet */
7367 ptr = (u32 *) (tcp + 1);
7368 lro->cur_tsval = *(ptr + 1);
7369 lro->cur_tsecr = *(ptr + 2);
7370 }
7371}
7372
7373static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
7374 struct tcphdr *tcp, u32 tcp_pyld_len)
7375{
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007376 u8 *ptr;
7377
Andrew Morton79dc1902006-02-03 01:45:13 -08007378 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7379
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007380 if (!tcp_pyld_len) {
7381 /* Runt frame or a pure ack */
7382 return -1;
7383 }
7384
7385 if (ip->ihl != 5) /* IP has options */
7386 return -1;
7387
7388 if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin ||
7389 !tcp->ack) {
7390 /*
7391 * Currently recognize only the ack control word and
7392 * any other control field being set would result in
7393 * flushing the LRO session
7394 */
7395 return -1;
7396 }
7397
7398 /*
7399 * Allow only one TCP timestamp option. Don't aggregate if
7400 * any other options are detected.
7401 */
7402 if (tcp->doff != 5 && tcp->doff != 8)
7403 return -1;
7404
7405 if (tcp->doff == 8) {
7406 ptr = (u8 *)(tcp + 1);
7407 while (*ptr == TCPOPT_NOP)
7408 ptr++;
7409 if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP)
7410 return -1;
7411
7412 /* Ensure timestamp value increases monotonically */
7413 if (l_lro)
7414 if (l_lro->cur_tsval > *((u32 *)(ptr+2)))
7415 return -1;
7416
7417 /* timestamp echo reply should be non-zero */
7418 if (*((u32 *)(ptr+6)) == 0)
7419 return -1;
7420 }
7421
7422 return 0;
7423}
7424
7425static int
7426s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
7427 RxD_t *rxdp, nic_t *sp)
7428{
7429 struct iphdr *ip;
7430 struct tcphdr *tcph;
7431 int ret = 0, i;
7432
7433 if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp,
7434 rxdp))) {
7435 DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n",
7436 ip->saddr, ip->daddr);
7437 } else {
7438 return ret;
7439 }
7440
7441 tcph = (struct tcphdr *)*tcp;
7442 *tcp_len = get_l4_pyld_length(ip, tcph);
7443 for (i=0; i<MAX_LRO_SESSIONS; i++) {
7444 lro_t *l_lro = &sp->lro0_n[i];
7445 if (l_lro->in_use) {
7446 if (check_for_socket_match(l_lro, ip, tcph))
7447 continue;
7448 /* Sock pair matched */
7449 *lro = l_lro;
7450
7451 if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) {
7452 DBG_PRINT(INFO_DBG, "%s:Out of order. expected "
7453 "0x%x, actual 0x%x\n", __FUNCTION__,
7454 (*lro)->tcp_next_seq,
7455 ntohl(tcph->seq));
7456
7457 sp->mac_control.stats_info->
7458 sw_stat.outof_sequence_pkts++;
7459 ret = 2;
7460 break;
7461 }
7462
7463 if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len))
7464 ret = 1; /* Aggregate */
7465 else
7466 ret = 2; /* Flush both */
7467 break;
7468 }
7469 }
7470
7471 if (ret == 0) {
7472 /* Before searching for available LRO objects,
7473 * check if the pkt is L3/L4 aggregatable. If not
7474 * don't create new LRO session. Just send this
7475 * packet up.
7476 */
7477 if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) {
7478 return 5;
7479 }
7480
7481 for (i=0; i<MAX_LRO_SESSIONS; i++) {
7482 lro_t *l_lro = &sp->lro0_n[i];
7483 if (!(l_lro->in_use)) {
7484 *lro = l_lro;
7485 ret = 3; /* Begin anew */
7486 break;
7487 }
7488 }
7489 }
7490
7491 if (ret == 0) { /* sessions exceeded */
7492 DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n",
7493 __FUNCTION__);
7494 *lro = NULL;
7495 return ret;
7496 }
7497
7498 switch (ret) {
7499 case 3:
7500 initiate_new_session(*lro, buffer, ip, tcph, *tcp_len);
7501 break;
7502 case 2:
7503 update_L3L4_header(sp, *lro);
7504 break;
7505 case 1:
7506 aggregate_new_rx(*lro, ip, tcph, *tcp_len);
7507 if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) {
7508 update_L3L4_header(sp, *lro);
7509 ret = 4; /* Flush the LRO */
7510 }
7511 break;
7512 default:
7513 DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n",
7514 __FUNCTION__);
7515 break;
7516 }
7517
7518 return ret;
7519}
7520
7521static void clear_lro_session(lro_t *lro)
7522{
7523 static u16 lro_struct_size = sizeof(lro_t);
7524
7525 memset(lro, 0, lro_struct_size);
7526}
7527
7528static void queue_rx_frame(struct sk_buff *skb)
7529{
7530 struct net_device *dev = skb->dev;
7531
7532 skb->protocol = eth_type_trans(skb, dev);
7533#ifdef CONFIG_S2IO_NAPI
7534 netif_receive_skb(skb);
7535#else
7536 netif_rx(skb);
7537#endif
7538}
7539
7540static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
7541 u32 tcp_len)
7542{
7543 struct sk_buff *tmp, *first = lro->parent;
7544
7545 first->len += tcp_len;
7546 first->data_len = lro->frags_len;
7547 skb_pull(skb, (skb->len - tcp_len));
7548 if ((tmp = skb_shinfo(first)->frag_list)) {
7549 while (tmp->next)
7550 tmp = tmp->next;
7551 tmp->next = skb;
7552 }
7553 else
7554 skb_shinfo(first)->frag_list = skb;
7555 sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
7556 return;
7557}