blob: ae79c4cfefcc2071fd28195f8906b894e7fd2e5e [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
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -050080#define DRV_VERSION "2.0.11.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
Ananda Rajuc92ca042006-04-21 19:18:03 -0400855int 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
1039 /* Enable Tx FIFO partition 0. */
1040 val64 = readq(&bar0->tx_fifo_partition_0);
1041 val64 |= BIT(0); /* To enable the FIFO partition. */
1042 writeq(val64, &bar0->tx_fifo_partition_0);
1043
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001044 /*
1045 * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug
1046 * SXE-008 TRANSMIT DMA ARBITRATION ISSUE.
1047 */
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001048 if ((nic->device_type == XFRAME_I_DEVICE) &&
1049 (get_xena_rev_id(nic->pdev) < 4))
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001050 writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable);
1051
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 val64 = readq(&bar0->tx_fifo_partition_0);
1053 DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n",
1054 &bar0->tx_fifo_partition_0, (unsigned long long) val64);
1055
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001056 /*
1057 * Initialization of Tx_PA_CONFIG register to ignore packet
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 * integrity checking.
1059 */
1060 val64 = readq(&bar0->tx_pa_cfg);
1061 val64 |= TX_PA_CFG_IGNORE_FRM_ERR | TX_PA_CFG_IGNORE_SNAP_OUI |
1062 TX_PA_CFG_IGNORE_LLC_CTRL | TX_PA_CFG_IGNORE_L2_ERR;
1063 writeq(val64, &bar0->tx_pa_cfg);
1064
1065 /* Rx DMA intialization. */
1066 val64 = 0;
1067 for (i = 0; i < config->rx_ring_num; i++) {
1068 val64 |=
1069 vBIT(config->rx_cfg[i].ring_priority, (5 + (i * 8)),
1070 3);
1071 }
1072 writeq(val64, &bar0->rx_queue_priority);
1073
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001074 /*
1075 * Allocating equal share of memory to all the
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 * configured Rings.
1077 */
1078 val64 = 0;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07001079 if (nic->device_type & XFRAME_II_DEVICE)
1080 mem_size = 32;
1081 else
1082 mem_size = 64;
1083
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 for (i = 0; i < config->rx_ring_num; i++) {
1085 switch (i) {
1086 case 0:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001087 mem_share = (mem_size / config->rx_ring_num +
1088 mem_size % config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 val64 |= RX_QUEUE_CFG_Q0_SZ(mem_share);
1090 continue;
1091 case 1:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001092 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 val64 |= RX_QUEUE_CFG_Q1_SZ(mem_share);
1094 continue;
1095 case 2:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001096 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 val64 |= RX_QUEUE_CFG_Q2_SZ(mem_share);
1098 continue;
1099 case 3:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001100 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 val64 |= RX_QUEUE_CFG_Q3_SZ(mem_share);
1102 continue;
1103 case 4:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001104 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 val64 |= RX_QUEUE_CFG_Q4_SZ(mem_share);
1106 continue;
1107 case 5:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001108 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 val64 |= RX_QUEUE_CFG_Q5_SZ(mem_share);
1110 continue;
1111 case 6:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001112 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 val64 |= RX_QUEUE_CFG_Q6_SZ(mem_share);
1114 continue;
1115 case 7:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001116 mem_share = (mem_size / config->rx_ring_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 val64 |= RX_QUEUE_CFG_Q7_SZ(mem_share);
1118 continue;
1119 }
1120 }
1121 writeq(val64, &bar0->rx_queue_cfg);
1122
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07001123 /*
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001124 * Filling Tx round robin registers
1125 * as per the number of FIFOs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 */
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07001127 switch (config->tx_fifo_num) {
1128 case 1:
1129 val64 = 0x0000000000000000ULL;
1130 writeq(val64, &bar0->tx_w_round_robin_0);
1131 writeq(val64, &bar0->tx_w_round_robin_1);
1132 writeq(val64, &bar0->tx_w_round_robin_2);
1133 writeq(val64, &bar0->tx_w_round_robin_3);
1134 writeq(val64, &bar0->tx_w_round_robin_4);
1135 break;
1136 case 2:
1137 val64 = 0x0000010000010000ULL;
1138 writeq(val64, &bar0->tx_w_round_robin_0);
1139 val64 = 0x0100000100000100ULL;
1140 writeq(val64, &bar0->tx_w_round_robin_1);
1141 val64 = 0x0001000001000001ULL;
1142 writeq(val64, &bar0->tx_w_round_robin_2);
1143 val64 = 0x0000010000010000ULL;
1144 writeq(val64, &bar0->tx_w_round_robin_3);
1145 val64 = 0x0100000000000000ULL;
1146 writeq(val64, &bar0->tx_w_round_robin_4);
1147 break;
1148 case 3:
1149 val64 = 0x0001000102000001ULL;
1150 writeq(val64, &bar0->tx_w_round_robin_0);
1151 val64 = 0x0001020000010001ULL;
1152 writeq(val64, &bar0->tx_w_round_robin_1);
1153 val64 = 0x0200000100010200ULL;
1154 writeq(val64, &bar0->tx_w_round_robin_2);
1155 val64 = 0x0001000102000001ULL;
1156 writeq(val64, &bar0->tx_w_round_robin_3);
1157 val64 = 0x0001020000000000ULL;
1158 writeq(val64, &bar0->tx_w_round_robin_4);
1159 break;
1160 case 4:
1161 val64 = 0x0001020300010200ULL;
1162 writeq(val64, &bar0->tx_w_round_robin_0);
1163 val64 = 0x0100000102030001ULL;
1164 writeq(val64, &bar0->tx_w_round_robin_1);
1165 val64 = 0x0200010000010203ULL;
1166 writeq(val64, &bar0->tx_w_round_robin_2);
1167 val64 = 0x0001020001000001ULL;
1168 writeq(val64, &bar0->tx_w_round_robin_3);
1169 val64 = 0x0203000100000000ULL;
1170 writeq(val64, &bar0->tx_w_round_robin_4);
1171 break;
1172 case 5:
1173 val64 = 0x0001000203000102ULL;
1174 writeq(val64, &bar0->tx_w_round_robin_0);
1175 val64 = 0x0001020001030004ULL;
1176 writeq(val64, &bar0->tx_w_round_robin_1);
1177 val64 = 0x0001000203000102ULL;
1178 writeq(val64, &bar0->tx_w_round_robin_2);
1179 val64 = 0x0001020001030004ULL;
1180 writeq(val64, &bar0->tx_w_round_robin_3);
1181 val64 = 0x0001000000000000ULL;
1182 writeq(val64, &bar0->tx_w_round_robin_4);
1183 break;
1184 case 6:
1185 val64 = 0x0001020304000102ULL;
1186 writeq(val64, &bar0->tx_w_round_robin_0);
1187 val64 = 0x0304050001020001ULL;
1188 writeq(val64, &bar0->tx_w_round_robin_1);
1189 val64 = 0x0203000100000102ULL;
1190 writeq(val64, &bar0->tx_w_round_robin_2);
1191 val64 = 0x0304000102030405ULL;
1192 writeq(val64, &bar0->tx_w_round_robin_3);
1193 val64 = 0x0001000200000000ULL;
1194 writeq(val64, &bar0->tx_w_round_robin_4);
1195 break;
1196 case 7:
1197 val64 = 0x0001020001020300ULL;
1198 writeq(val64, &bar0->tx_w_round_robin_0);
1199 val64 = 0x0102030400010203ULL;
1200 writeq(val64, &bar0->tx_w_round_robin_1);
1201 val64 = 0x0405060001020001ULL;
1202 writeq(val64, &bar0->tx_w_round_robin_2);
1203 val64 = 0x0304050000010200ULL;
1204 writeq(val64, &bar0->tx_w_round_robin_3);
1205 val64 = 0x0102030000000000ULL;
1206 writeq(val64, &bar0->tx_w_round_robin_4);
1207 break;
1208 case 8:
1209 val64 = 0x0001020300040105ULL;
1210 writeq(val64, &bar0->tx_w_round_robin_0);
1211 val64 = 0x0200030106000204ULL;
1212 writeq(val64, &bar0->tx_w_round_robin_1);
1213 val64 = 0x0103000502010007ULL;
1214 writeq(val64, &bar0->tx_w_round_robin_2);
1215 val64 = 0x0304010002060500ULL;
1216 writeq(val64, &bar0->tx_w_round_robin_3);
1217 val64 = 0x0103020400000000ULL;
1218 writeq(val64, &bar0->tx_w_round_robin_4);
1219 break;
1220 }
1221
1222 /* 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;
2191 u16 interruptible, i;
2192 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
2204 /* Disable PRCs */
2205 for (i = 0; i < config->rx_ring_num; i++) {
2206 val64 = readq(&bar0->prc_ctrl_n[i]);
2207 val64 &= ~((u64) PRC_CTRL_RC_ENABLED);
2208 writeq(val64, &bar0->prc_ctrl_n[i]);
2209 }
2210}
2211
Adrian Bunk26df54b2006-01-14 03:09:40 +01002212static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
Ananda Rajuda6971d2005-10-31 16:55:31 -05002213{
2214 struct net_device *dev = nic->dev;
2215 struct sk_buff *frag_list;
Jeff Garzik50eb8002005-11-05 23:40:46 -05002216 void *tmp;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002217
2218 /* Buffer-1 receives L3/L4 headers */
2219 ((RxD3_t*)rxdp)->Buffer1_ptr = pci_map_single
2220 (nic->pdev, skb->data, l3l4hdr_size + 4,
2221 PCI_DMA_FROMDEVICE);
2222
2223 /* skb_shinfo(skb)->frag_list will have L4 data payload */
2224 skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE);
2225 if (skb_shinfo(skb)->frag_list == NULL) {
2226 DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
2227 return -ENOMEM ;
2228 }
2229 frag_list = skb_shinfo(skb)->frag_list;
2230 frag_list->next = NULL;
Jeff Garzik50eb8002005-11-05 23:40:46 -05002231 tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
2232 frag_list->data = tmp;
2233 frag_list->tail = tmp;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002234
2235 /* Buffer-2 receives L4 data payload */
2236 ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
2237 frag_list->data, dev->mtu,
2238 PCI_DMA_FROMDEVICE);
2239 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
2240 rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
2241
2242 return SUCCESS;
2243}
2244
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002245/**
2246 * fill_rx_buffers - Allocates the Rx side skbs
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002248 * @ring_no: ring number
2249 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 * The function allocates Rx side skbs and puts the physical
2251 * address of these buffers into the RxD buffer pointers, so that the NIC
2252 * can DMA the received frame into these locations.
2253 * The NIC supports 3 receive modes, viz
2254 * 1. single buffer,
2255 * 2. three buffer and
2256 * 3. Five buffer modes.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002257 * Each mode defines how many fragments the received frame will be split
2258 * up into by the NIC. The frame is split into L3 header, L4 Header,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 * L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself
2260 * is split into 3 fragments. As of now only single buffer mode is
2261 * supported.
2262 * Return Value:
2263 * SUCCESS on success or an appropriate -ve value on failure.
2264 */
2265
Adrian Bunkac1f60d2005-11-06 01:46:47 +01002266static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267{
2268 struct net_device *dev = nic->dev;
2269 struct sk_buff *skb;
2270 RxD_t *rxdp;
2271 int off, off1, size, block_no, block_no1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 u32 alloc_tab = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002273 u32 alloc_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 mac_info_t *mac_control;
2275 struct config_param *config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002276 u64 tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 buffAdd_t *ba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278#ifndef CONFIG_S2IO_NAPI
2279 unsigned long flags;
2280#endif
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002281 RxD_t *first_rxdp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282
2283 mac_control = &nic->mac_control;
2284 config = &nic->config;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002285 alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
2286 atomic_read(&nic->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287
Ananda Rajubd1034f2006-04-21 19:20:22 -04002288 block_no1 = mac_control->rings[ring_no].rx_curr_get_info.block_index;
Ananda Raju863c11a2006-04-21 19:03:13 -04002289 off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 while (alloc_tab < alloc_cnt) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002291 block_no = mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 block_index;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002293 off = mac_control->rings[ring_no].rx_curr_put_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294
Ananda Rajuda6971d2005-10-31 16:55:31 -05002295 rxdp = mac_control->rings[ring_no].
2296 rx_blocks[block_no].rxds[off].virt_addr;
2297
2298 if ((block_no == block_no1) && (off == off1) &&
2299 (rxdp->Host_Control)) {
2300 DBG_PRINT(INTR_DBG, "%s: Get and Put",
2301 dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 DBG_PRINT(INTR_DBG, " info equated\n");
2303 goto end;
2304 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002305 if (off && (off == rxd_count[nic->rxd_mode])) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002306 mac_control->rings[ring_no].rx_curr_put_info.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 block_index++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002308 if (mac_control->rings[ring_no].rx_curr_put_info.
2309 block_index == mac_control->rings[ring_no].
2310 block_count)
2311 mac_control->rings[ring_no].rx_curr_put_info.
2312 block_index = 0;
2313 block_no = mac_control->rings[ring_no].
2314 rx_curr_put_info.block_index;
2315 if (off == rxd_count[nic->rxd_mode])
2316 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002317 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002318 offset = off;
2319 rxdp = mac_control->rings[ring_no].
2320 rx_blocks[block_no].block_virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
2322 dev->name, rxdp);
2323 }
2324#ifndef CONFIG_S2IO_NAPI
2325 spin_lock_irqsave(&nic->put_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002326 mac_control->rings[ring_no].put_pos =
Ananda Rajuda6971d2005-10-31 16:55:31 -05002327 (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 spin_unlock_irqrestore(&nic->put_lock, flags);
2329#endif
Ananda Rajuda6971d2005-10-31 16:55:31 -05002330 if ((rxdp->Control_1 & RXD_OWN_XENA) &&
2331 ((nic->rxd_mode >= RXD_MODE_3A) &&
2332 (rxdp->Control_2 & BIT(0)))) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002333 mac_control->rings[ring_no].rx_curr_put_info.
Ananda Rajuda6971d2005-10-31 16:55:31 -05002334 offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 goto end;
2336 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002337 /* calculate size of skb based on ring mode */
2338 size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
2339 HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
2340 if (nic->rxd_mode == RXD_MODE_1)
2341 size += NET_IP_ALIGN;
2342 else if (nic->rxd_mode == RXD_MODE_3B)
2343 size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
2344 else
2345 size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346
Ananda Rajuda6971d2005-10-31 16:55:31 -05002347 /* allocate skb */
2348 skb = dev_alloc_skb(size);
2349 if(!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
2351 DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002352 if (first_rxdp) {
2353 wmb();
2354 first_rxdp->Control_1 |= RXD_OWN_XENA;
2355 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002356 return -ENOMEM ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002358 if (nic->rxd_mode == RXD_MODE_1) {
2359 /* 1 buffer mode - normal operation mode */
2360 memset(rxdp, 0, sizeof(RxD1_t));
2361 skb_reserve(skb, NET_IP_ALIGN);
2362 ((RxD1_t*)rxdp)->Buffer0_ptr = pci_map_single
Ananda Raju863c11a2006-04-21 19:03:13 -04002363 (nic->pdev, skb->data, size - NET_IP_ALIGN,
2364 PCI_DMA_FROMDEVICE);
2365 rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002366
2367 } else if (nic->rxd_mode >= RXD_MODE_3A) {
2368 /*
2369 * 2 or 3 buffer mode -
2370 * Both 2 buffer mode and 3 buffer mode provides 128
2371 * byte aligned receive buffers.
2372 *
2373 * 3 buffer mode provides header separation where in
2374 * skb->data will have L3/L4 headers where as
2375 * skb_shinfo(skb)->frag_list will have the L4 data
2376 * payload
2377 */
2378
2379 memset(rxdp, 0, sizeof(RxD3_t));
2380 ba = &mac_control->rings[ring_no].ba[block_no][off];
2381 skb_reserve(skb, BUF0_LEN);
2382 tmp = (u64)(unsigned long) skb->data;
2383 tmp += ALIGN_SIZE;
2384 tmp &= ~ALIGN_SIZE;
2385 skb->data = (void *) (unsigned long)tmp;
2386 skb->tail = (void *) (unsigned long)tmp;
2387
2388 ((RxD3_t*)rxdp)->Buffer0_ptr =
2389 pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
2390 PCI_DMA_FROMDEVICE);
2391 rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
2392 if (nic->rxd_mode == RXD_MODE_3B) {
2393 /* Two buffer mode */
2394
2395 /*
2396 * Buffer2 will have L3/L4 header plus
2397 * L4 payload
2398 */
2399 ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single
2400 (nic->pdev, skb->data, dev->mtu + 4,
2401 PCI_DMA_FROMDEVICE);
2402
2403 /* Buffer-1 will be dummy buffer not used */
2404 ((RxD3_t*)rxdp)->Buffer1_ptr =
2405 pci_map_single(nic->pdev, ba->ba_1, BUF1_LEN,
2406 PCI_DMA_FROMDEVICE);
2407 rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
2408 rxdp->Control_2 |= SET_BUFFER2_SIZE_3
2409 (dev->mtu + 4);
2410 } else {
2411 /* 3 buffer mode */
2412 if (fill_rxd_3buf(nic, rxdp, skb) == -ENOMEM) {
2413 dev_kfree_skb_irq(skb);
2414 if (first_rxdp) {
2415 wmb();
2416 first_rxdp->Control_1 |=
2417 RXD_OWN_XENA;
2418 }
2419 return -ENOMEM ;
2420 }
2421 }
2422 rxdp->Control_2 |= BIT(0);
2423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 rxdp->Host_Control = (unsigned long) (skb);
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002425 if (alloc_tab & ((1 << rxsync_frequency) - 1))
2426 rxdp->Control_1 |= RXD_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 off++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002428 if (off == (rxd_count[nic->rxd_mode] + 1))
2429 off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002430 mac_control->rings[ring_no].rx_curr_put_info.offset = off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07002432 rxdp->Control_2 |= SET_RXD_MARKER;
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002433 if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
2434 if (first_rxdp) {
2435 wmb();
2436 first_rxdp->Control_1 |= RXD_OWN_XENA;
2437 }
2438 first_rxdp = rxdp;
2439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 atomic_inc(&nic->rx_bufs_left[ring_no]);
2441 alloc_tab++;
2442 }
2443
2444 end:
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07002445 /* Transfer ownership of first descriptor to adapter just before
2446 * exiting. Before that, use memory barrier so that ownership
2447 * and other fields are seen by adapter correctly.
2448 */
2449 if (first_rxdp) {
2450 wmb();
2451 first_rxdp->Control_1 |= RXD_OWN_XENA;
2452 }
2453
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 return SUCCESS;
2455}
2456
Ananda Rajuda6971d2005-10-31 16:55:31 -05002457static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
2458{
2459 struct net_device *dev = sp->dev;
2460 int j;
2461 struct sk_buff *skb;
2462 RxD_t *rxdp;
2463 mac_info_t *mac_control;
2464 buffAdd_t *ba;
2465
2466 mac_control = &sp->mac_control;
2467 for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
2468 rxdp = mac_control->rings[ring_no].
2469 rx_blocks[blk].rxds[j].virt_addr;
2470 skb = (struct sk_buff *)
2471 ((unsigned long) rxdp->Host_Control);
2472 if (!skb) {
2473 continue;
2474 }
2475 if (sp->rxd_mode == RXD_MODE_1) {
2476 pci_unmap_single(sp->pdev, (dma_addr_t)
2477 ((RxD1_t*)rxdp)->Buffer0_ptr,
2478 dev->mtu +
2479 HEADER_ETHERNET_II_802_3_SIZE
2480 + HEADER_802_2_SIZE +
2481 HEADER_SNAP_SIZE,
2482 PCI_DMA_FROMDEVICE);
2483 memset(rxdp, 0, sizeof(RxD1_t));
2484 } else if(sp->rxd_mode == RXD_MODE_3B) {
2485 ba = &mac_control->rings[ring_no].
2486 ba[blk][j];
2487 pci_unmap_single(sp->pdev, (dma_addr_t)
2488 ((RxD3_t*)rxdp)->Buffer0_ptr,
2489 BUF0_LEN,
2490 PCI_DMA_FROMDEVICE);
2491 pci_unmap_single(sp->pdev, (dma_addr_t)
2492 ((RxD3_t*)rxdp)->Buffer1_ptr,
2493 BUF1_LEN,
2494 PCI_DMA_FROMDEVICE);
2495 pci_unmap_single(sp->pdev, (dma_addr_t)
2496 ((RxD3_t*)rxdp)->Buffer2_ptr,
2497 dev->mtu + 4,
2498 PCI_DMA_FROMDEVICE);
2499 memset(rxdp, 0, sizeof(RxD3_t));
2500 } else {
2501 pci_unmap_single(sp->pdev, (dma_addr_t)
2502 ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
2503 PCI_DMA_FROMDEVICE);
2504 pci_unmap_single(sp->pdev, (dma_addr_t)
2505 ((RxD3_t*)rxdp)->Buffer1_ptr,
2506 l3l4hdr_size + 4,
2507 PCI_DMA_FROMDEVICE);
2508 pci_unmap_single(sp->pdev, (dma_addr_t)
2509 ((RxD3_t*)rxdp)->Buffer2_ptr, dev->mtu,
2510 PCI_DMA_FROMDEVICE);
2511 memset(rxdp, 0, sizeof(RxD3_t));
2512 }
2513 dev_kfree_skb(skb);
2514 atomic_dec(&sp->rx_bufs_left[ring_no]);
2515 }
2516}
2517
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002519 * free_rx_buffers - Frees all Rx buffers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 * @sp: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002521 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 * This function will free all Rx buffers allocated by host.
2523 * Return Value:
2524 * NONE.
2525 */
2526
2527static void free_rx_buffers(struct s2io_nic *sp)
2528{
2529 struct net_device *dev = sp->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002530 int i, blk = 0, buf_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 mac_info_t *mac_control;
2532 struct config_param *config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533
2534 mac_control = &sp->mac_control;
2535 config = &sp->config;
2536
2537 for (i = 0; i < config->rx_ring_num; i++) {
Ananda Rajuda6971d2005-10-31 16:55:31 -05002538 for (blk = 0; blk < rx_ring_sz[i]; blk++)
2539 free_rxd_blk(sp,i,blk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002541 mac_control->rings[i].rx_curr_put_info.block_index = 0;
2542 mac_control->rings[i].rx_curr_get_info.block_index = 0;
2543 mac_control->rings[i].rx_curr_put_info.offset = 0;
2544 mac_control->rings[i].rx_curr_get_info.offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 atomic_set(&sp->rx_bufs_left[i], 0);
2546 DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
2547 dev->name, buf_cnt, i);
2548 }
2549}
2550
2551/**
2552 * s2io_poll - Rx interrupt handler for NAPI support
2553 * @dev : pointer to the device structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002554 * @budget : The number of packets that were budgeted to be processed
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 * during one pass through the 'Poll" function.
2556 * Description:
2557 * Comes into picture only if NAPI support has been incorporated. It does
2558 * the same thing that rx_intr_handler does, but not in a interrupt context
2559 * also It will process only a given number of packets.
2560 * Return value:
2561 * 0 on success and 1 if there are No Rx packets to be processed.
2562 */
2563
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002564#if defined(CONFIG_S2IO_NAPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565static int s2io_poll(struct net_device *dev, int *budget)
2566{
2567 nic_t *nic = dev->priv;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002568 int pkt_cnt = 0, org_pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 mac_info_t *mac_control;
2570 struct config_param *config;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01002571 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ananda Raju863c11a2006-04-21 19:03:13 -04002572 u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002573 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002575 atomic_inc(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 mac_control = &nic->mac_control;
2577 config = &nic->config;
2578
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002579 nic->pkts_to_process = *budget;
2580 if (nic->pkts_to_process > dev->quota)
2581 nic->pkts_to_process = dev->quota;
2582 org_pkts_to_process = nic->pkts_to_process;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 writeq(val64, &bar0->rx_traffic_int);
Ananda Raju863c11a2006-04-21 19:03:13 -04002585 val64 = readl(&bar0->rx_traffic_int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
2587 for (i = 0; i < config->rx_ring_num; i++) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002588 rx_intr_handler(&mac_control->rings[i]);
2589 pkt_cnt = org_pkts_to_process - nic->pkts_to_process;
2590 if (!nic->pkts_to_process) {
2591 /* Quota for the current iteration has been met */
2592 goto no_rx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 }
2595 if (!pkt_cnt)
2596 pkt_cnt = 1;
2597
2598 dev->quota -= pkt_cnt;
2599 *budget -= pkt_cnt;
2600 netif_rx_complete(dev);
2601
2602 for (i = 0; i < config->rx_ring_num; i++) {
2603 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2604 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2605 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2606 break;
2607 }
2608 }
2609 /* Re enable the Rx interrupts. */
Ananda Rajuc92ca042006-04-21 19:18:03 -04002610 writeq(0x0, &bar0->rx_traffic_mask);
2611 val64 = readl(&bar0->rx_traffic_mask);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002612 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 return 0;
2614
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002615no_rx:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 dev->quota -= pkt_cnt;
2617 *budget -= pkt_cnt;
2618
2619 for (i = 0; i < config->rx_ring_num; i++) {
2620 if (fill_rx_buffers(nic, i) == -ENOMEM) {
2621 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
2622 DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
2623 break;
2624 }
2625 }
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002626 atomic_dec(&nic->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 return 1;
2628}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002629#endif
2630
2631/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 * rx_intr_handler - Rx interrupt handler
2633 * @nic: device private variable.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002634 * Description:
2635 * If the interrupt is because of a received frame or if the
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 * receive ring contains fresh as yet un-processed frames,this function is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002637 * called. It picks out the RxD at which place the last Rx processing had
2638 * stopped and sends the skb to the OSM's Rx handler and then increments
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 * the offset.
2640 * Return Value:
2641 * NONE.
2642 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002643static void rx_intr_handler(ring_info_t *ring_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002645 nic_t *nic = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 struct net_device *dev = (struct net_device *) nic->dev;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002647 int get_block, put_block, put_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 rx_curr_get_info_t get_info, put_info;
2649 RxD_t *rxdp;
2650 struct sk_buff *skb;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002651#ifndef CONFIG_S2IO_NAPI
2652 int pkt_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653#endif
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002654 int i;
2655
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002656 spin_lock(&nic->rx_lock);
2657 if (atomic_read(&nic->card_state) == CARD_DOWN) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002658 DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002659 __FUNCTION__, dev->name);
2660 spin_unlock(&nic->rx_lock);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002661 return;
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002662 }
2663
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002664 get_info = ring_data->rx_curr_get_info;
2665 get_block = get_info.block_index;
2666 put_info = ring_data->rx_curr_put_info;
2667 put_block = put_info.block_index;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002668 rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002669#ifndef CONFIG_S2IO_NAPI
2670 spin_lock(&nic->put_lock);
2671 put_offset = ring_data->put_pos;
2672 spin_unlock(&nic->put_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673#else
Ananda Rajuda6971d2005-10-31 16:55:31 -05002674 put_offset = (put_block * (rxd_count[nic->rxd_mode] + 1)) +
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002675 put_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676#endif
Ananda Rajuda6971d2005-10-31 16:55:31 -05002677 while (RXD_IS_UP2DT(rxdp)) {
2678 /* If your are next to put index then it's FIFO full condition */
2679 if ((get_block == put_block) &&
2680 (get_info.offset + 1) == put_info.offset) {
2681 DBG_PRINT(ERR_DBG, "%s: Ring Full\n",dev->name);
2682 break;
2683 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002684 skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
2685 if (skb == NULL) {
2686 DBG_PRINT(ERR_DBG, "%s: The skb is ",
2687 dev->name);
2688 DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002689 spin_unlock(&nic->rx_lock);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002690 return;
2691 }
Ananda Rajuda6971d2005-10-31 16:55:31 -05002692 if (nic->rxd_mode == RXD_MODE_1) {
2693 pci_unmap_single(nic->pdev, (dma_addr_t)
2694 ((RxD1_t*)rxdp)->Buffer0_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002695 dev->mtu +
2696 HEADER_ETHERNET_II_802_3_SIZE +
2697 HEADER_802_2_SIZE +
2698 HEADER_SNAP_SIZE,
2699 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002700 } else if (nic->rxd_mode == RXD_MODE_3B) {
2701 pci_unmap_single(nic->pdev, (dma_addr_t)
2702 ((RxD3_t*)rxdp)->Buffer0_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002703 BUF0_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002704 pci_unmap_single(nic->pdev, (dma_addr_t)
2705 ((RxD3_t*)rxdp)->Buffer1_ptr,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002706 BUF1_LEN, PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002707 pci_unmap_single(nic->pdev, (dma_addr_t)
2708 ((RxD3_t*)rxdp)->Buffer2_ptr,
2709 dev->mtu + 4,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002710 PCI_DMA_FROMDEVICE);
Ananda Rajuda6971d2005-10-31 16:55:31 -05002711 } else {
2712 pci_unmap_single(nic->pdev, (dma_addr_t)
2713 ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
2714 PCI_DMA_FROMDEVICE);
2715 pci_unmap_single(nic->pdev, (dma_addr_t)
2716 ((RxD3_t*)rxdp)->Buffer1_ptr,
2717 l3l4hdr_size + 4,
2718 PCI_DMA_FROMDEVICE);
2719 pci_unmap_single(nic->pdev, (dma_addr_t)
2720 ((RxD3_t*)rxdp)->Buffer2_ptr,
2721 dev->mtu, PCI_DMA_FROMDEVICE);
2722 }
Ananda Raju863c11a2006-04-21 19:03:13 -04002723 prefetch(skb->data);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002724 rx_osm_handler(ring_data, rxdp);
2725 get_info.offset++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002726 ring_data->rx_curr_get_info.offset = get_info.offset;
2727 rxdp = ring_data->rx_blocks[get_block].
2728 rxds[get_info.offset].virt_addr;
2729 if (get_info.offset == rxd_count[nic->rxd_mode]) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002730 get_info.offset = 0;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002731 ring_data->rx_curr_get_info.offset = get_info.offset;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002732 get_block++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05002733 if (get_block == ring_data->block_count)
2734 get_block = 0;
2735 ring_data->rx_curr_get_info.block_index = get_block;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002736 rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
2737 }
2738
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002739#ifdef CONFIG_S2IO_NAPI
2740 nic->pkts_to_process -= 1;
2741 if (!nic->pkts_to_process)
2742 break;
2743#else
2744 pkt_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
2746 break;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002747#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05002749 if (nic->lro) {
2750 /* Clear all LRO sessions before exiting */
2751 for (i=0; i<MAX_LRO_SESSIONS; i++) {
2752 lro_t *lro = &nic->lro0_n[i];
2753 if (lro->in_use) {
2754 update_L3L4_header(nic, lro);
2755 queue_rx_frame(lro->parent);
2756 clear_lro_session(lro);
2757 }
2758 }
2759 }
2760
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07002761 spin_unlock(&nic->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762}
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002763
2764/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 * tx_intr_handler - Transmit interrupt handler
2766 * @nic : device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002767 * Description:
2768 * If an interrupt was raised to indicate DMA complete of the
2769 * Tx packet, this function is called. It identifies the last TxD
2770 * whose buffer was freed and frees all skbs whose data have already
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 * DMA'ed into the NICs internal memory.
2772 * Return Value:
2773 * NONE
2774 */
2775
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002776static void tx_intr_handler(fifo_info_t *fifo_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002778 nic_t *nic = fifo_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 struct net_device *dev = (struct net_device *) nic->dev;
2780 tx_curr_get_info_t get_info, put_info;
2781 struct sk_buff *skb;
2782 TxD_t *txdlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002784 get_info = fifo_data->tx_curr_get_info;
2785 put_info = fifo_data->tx_curr_put_info;
2786 txdlp = (TxD_t *) fifo_data->list_info[get_info.offset].
2787 list_virt_addr;
2788 while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
2789 (get_info.offset != put_info.offset) &&
2790 (txdlp->Host_Control)) {
2791 /* Check for TxD errors */
2792 if (txdlp->Control_1 & TXD_T_CODE) {
2793 unsigned long long err;
2794 err = txdlp->Control_1 & TXD_T_CODE;
Ananda Rajubd1034f2006-04-21 19:20:22 -04002795 if (err & 0x1) {
2796 nic->mac_control.stats_info->sw_stat.
2797 parity_err_cnt++;
2798 }
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002799 if ((err >> 48) == 0xA) {
2800 DBG_PRINT(TX_DBG, "TxD returned due \
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04002801to loss of link\n");
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002802 }
2803 else {
2804 DBG_PRINT(ERR_DBG, "***TxD error \
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04002805%llx\n", err);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07002806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002808
Ananda Rajufed5ecc2005-11-14 15:25:08 -05002809 skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002810 if (skb == NULL) {
2811 DBG_PRINT(ERR_DBG, "%s: Null skb ",
2812 __FUNCTION__);
2813 DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
2814 return;
2815 }
2816
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002817 /* Updating the statistics block */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002818 nic->stats.tx_bytes += skb->len;
2819 dev_kfree_skb_irq(skb);
2820
2821 get_info.offset++;
Ananda Raju863c11a2006-04-21 19:03:13 -04002822 if (get_info.offset == get_info.fifo_len + 1)
2823 get_info.offset = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002824 txdlp = (TxD_t *) fifo_data->list_info
2825 [get_info.offset].list_virt_addr;
2826 fifo_data->tx_curr_get_info.offset =
2827 get_info.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 }
2829
2830 spin_lock(&nic->tx_lock);
2831 if (netif_queue_stopped(dev))
2832 netif_wake_queue(dev);
2833 spin_unlock(&nic->tx_lock);
2834}
2835
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07002836/**
Ananda Rajubd1034f2006-04-21 19:20:22 -04002837 * s2io_mdio_write - Function to write in to MDIO registers
2838 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
2839 * @addr : address value
2840 * @value : data value
2841 * @dev : pointer to net_device structure
2842 * Description:
2843 * This function is used to write values to the MDIO registers
2844 * NONE
2845 */
2846static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
2847{
2848 u64 val64 = 0x0;
2849 nic_t *sp = dev->priv;
2850 XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
2851
2852 //address transaction
2853 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2854 | MDIO_MMD_DEV_ADDR(mmd_type)
2855 | MDIO_MMS_PRT_ADDR(0x0);
2856 writeq(val64, &bar0->mdio_control);
2857 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2858 writeq(val64, &bar0->mdio_control);
2859 udelay(100);
2860
2861 //Data transaction
2862 val64 = 0x0;
2863 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2864 | MDIO_MMD_DEV_ADDR(mmd_type)
2865 | MDIO_MMS_PRT_ADDR(0x0)
2866 | MDIO_MDIO_DATA(value)
2867 | MDIO_OP(MDIO_OP_WRITE_TRANS);
2868 writeq(val64, &bar0->mdio_control);
2869 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2870 writeq(val64, &bar0->mdio_control);
2871 udelay(100);
2872
2873 val64 = 0x0;
2874 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2875 | MDIO_MMD_DEV_ADDR(mmd_type)
2876 | MDIO_MMS_PRT_ADDR(0x0)
2877 | MDIO_OP(MDIO_OP_READ_TRANS);
2878 writeq(val64, &bar0->mdio_control);
2879 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2880 writeq(val64, &bar0->mdio_control);
2881 udelay(100);
2882
2883}
2884
2885/**
2886 * s2io_mdio_read - Function to write in to MDIO registers
2887 * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
2888 * @addr : address value
2889 * @dev : pointer to net_device structure
2890 * Description:
2891 * This function is used to read values to the MDIO registers
2892 * NONE
2893 */
2894static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
2895{
2896 u64 val64 = 0x0;
2897 u64 rval64 = 0x0;
2898 nic_t *sp = dev->priv;
2899 XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
2900
2901 /* address transaction */
2902 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2903 | MDIO_MMD_DEV_ADDR(mmd_type)
2904 | MDIO_MMS_PRT_ADDR(0x0);
2905 writeq(val64, &bar0->mdio_control);
2906 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2907 writeq(val64, &bar0->mdio_control);
2908 udelay(100);
2909
2910 /* Data transaction */
2911 val64 = 0x0;
2912 val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
2913 | MDIO_MMD_DEV_ADDR(mmd_type)
2914 | MDIO_MMS_PRT_ADDR(0x0)
2915 | MDIO_OP(MDIO_OP_READ_TRANS);
2916 writeq(val64, &bar0->mdio_control);
2917 val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
2918 writeq(val64, &bar0->mdio_control);
2919 udelay(100);
2920
2921 /* Read the value from regs */
2922 rval64 = readq(&bar0->mdio_control);
2923 rval64 = rval64 & 0xFFFF0000;
2924 rval64 = rval64 >> 16;
2925 return rval64;
2926}
2927/**
2928 * s2io_chk_xpak_counter - Function to check the status of the xpak counters
2929 * @counter : couter value to be updated
2930 * @flag : flag to indicate the status
2931 * @type : counter type
2932 * Description:
2933 * This function is to check the status of the xpak counters value
2934 * NONE
2935 */
2936
2937static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, u16 flag, u16 type)
2938{
2939 u64 mask = 0x3;
2940 u64 val64;
2941 int i;
2942 for(i = 0; i <index; i++)
2943 mask = mask << 0x2;
2944
2945 if(flag > 0)
2946 {
2947 *counter = *counter + 1;
2948 val64 = *regs_stat & mask;
2949 val64 = val64 >> (index * 0x2);
2950 val64 = val64 + 1;
2951 if(val64 == 3)
2952 {
2953 switch(type)
2954 {
2955 case 1:
2956 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
2957 "service. Excessive temperatures may "
2958 "result in premature transceiver "
2959 "failure \n");
2960 break;
2961 case 2:
2962 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
2963 "service Excessive bias currents may "
2964 "indicate imminent laser diode "
2965 "failure \n");
2966 break;
2967 case 3:
2968 DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
2969 "service Excessive laser output "
2970 "power may saturate far-end "
2971 "receiver\n");
2972 break;
2973 default:
2974 DBG_PRINT(ERR_DBG, "Incorrect XPAK Alarm "
2975 "type \n");
2976 }
2977 val64 = 0x0;
2978 }
2979 val64 = val64 << (index * 0x2);
2980 *regs_stat = (*regs_stat & (~mask)) | (val64);
2981
2982 } else {
2983 *regs_stat = *regs_stat & (~mask);
2984 }
2985}
2986
2987/**
2988 * s2io_updt_xpak_counter - Function to update the xpak counters
2989 * @dev : pointer to net_device struct
2990 * Description:
2991 * This function is to upate the status of the xpak counters value
2992 * NONE
2993 */
2994static void s2io_updt_xpak_counter(struct net_device *dev)
2995{
2996 u16 flag = 0x0;
2997 u16 type = 0x0;
2998 u16 val16 = 0x0;
2999 u64 val64 = 0x0;
3000 u64 addr = 0x0;
3001
3002 nic_t *sp = dev->priv;
3003 StatInfo_t *stat_info = sp->mac_control.stats_info;
3004
3005 /* Check the communication with the MDIO slave */
3006 addr = 0x0000;
3007 val64 = 0x0;
3008 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3009 if((val64 == 0xFFFF) || (val64 == 0x0000))
3010 {
3011 DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - "
3012 "Returned %llx\n", (unsigned long long)val64);
3013 return;
3014 }
3015
3016 /* Check for the expecte value of 2040 at PMA address 0x0000 */
3017 if(val64 != 0x2040)
3018 {
3019 DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - ");
3020 DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x2040\n",
3021 (unsigned long long)val64);
3022 return;
3023 }
3024
3025 /* Loading the DOM register to MDIO register */
3026 addr = 0xA100;
3027 s2io_mdio_write(MDIO_MMD_PMA_DEV_ADDR, addr, val16, dev);
3028 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3029
3030 /* Reading the Alarm flags */
3031 addr = 0xA070;
3032 val64 = 0x0;
3033 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3034
3035 flag = CHECKBIT(val64, 0x7);
3036 type = 1;
3037 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_transceiver_temp_high,
3038 &stat_info->xpak_stat.xpak_regs_stat,
3039 0x0, flag, type);
3040
3041 if(CHECKBIT(val64, 0x6))
3042 stat_info->xpak_stat.alarm_transceiver_temp_low++;
3043
3044 flag = CHECKBIT(val64, 0x3);
3045 type = 2;
3046 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_bias_current_high,
3047 &stat_info->xpak_stat.xpak_regs_stat,
3048 0x2, flag, type);
3049
3050 if(CHECKBIT(val64, 0x2))
3051 stat_info->xpak_stat.alarm_laser_bias_current_low++;
3052
3053 flag = CHECKBIT(val64, 0x1);
3054 type = 3;
3055 s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_output_power_high,
3056 &stat_info->xpak_stat.xpak_regs_stat,
3057 0x4, flag, type);
3058
3059 if(CHECKBIT(val64, 0x0))
3060 stat_info->xpak_stat.alarm_laser_output_power_low++;
3061
3062 /* Reading the Warning flags */
3063 addr = 0xA074;
3064 val64 = 0x0;
3065 val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
3066
3067 if(CHECKBIT(val64, 0x7))
3068 stat_info->xpak_stat.warn_transceiver_temp_high++;
3069
3070 if(CHECKBIT(val64, 0x6))
3071 stat_info->xpak_stat.warn_transceiver_temp_low++;
3072
3073 if(CHECKBIT(val64, 0x3))
3074 stat_info->xpak_stat.warn_laser_bias_current_high++;
3075
3076 if(CHECKBIT(val64, 0x2))
3077 stat_info->xpak_stat.warn_laser_bias_current_low++;
3078
3079 if(CHECKBIT(val64, 0x1))
3080 stat_info->xpak_stat.warn_laser_output_power_high++;
3081
3082 if(CHECKBIT(val64, 0x0))
3083 stat_info->xpak_stat.warn_laser_output_power_low++;
3084}
3085
3086/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 * alarm_intr_handler - Alarm Interrrupt handler
3088 * @nic: device private variable
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003089 * Description: If the interrupt was neither because of Rx packet or Tx
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 * complete, this function is called. If the interrupt was to indicate
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003091 * a loss of link, the OSM link status handler is invoked for any other
3092 * alarm interrupt the block that raised the interrupt is displayed
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 * and a H/W reset is issued.
3094 * Return Value:
3095 * NONE
3096*/
3097
3098static void alarm_intr_handler(struct s2io_nic *nic)
3099{
3100 struct net_device *dev = (struct net_device *) nic->dev;
3101 XENA_dev_config_t __iomem *bar0 = nic->bar0;
3102 register u64 val64 = 0, err_reg = 0;
Ananda Rajubd1034f2006-04-21 19:20:22 -04003103 u64 cnt;
3104 int i;
3105 nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
3106 /* Handling the XPAK counters update */
3107 if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
3108 /* waiting for an hour */
3109 nic->mac_control.stats_info->xpak_stat.xpak_timer_count++;
3110 } else {
3111 s2io_updt_xpak_counter(dev);
3112 /* reset the count to zero */
3113 nic->mac_control.stats_info->xpak_stat.xpak_timer_count = 0;
3114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115
3116 /* Handling link status change error Intr */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07003117 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
3118 err_reg = readq(&bar0->mac_rmac_err_reg);
3119 writeq(err_reg, &bar0->mac_rmac_err_reg);
3120 if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
3121 schedule_work(&nic->set_link_task);
3122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 }
3124
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003125 /* Handling Ecc errors */
3126 val64 = readq(&bar0->mc_err_reg);
3127 writeq(val64, &bar0->mc_err_reg);
3128 if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
3129 if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003130 nic->mac_control.stats_info->sw_stat.
3131 double_ecc_errs++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003132 DBG_PRINT(INIT_DBG, "%s: Device indicates ",
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003133 dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003134 DBG_PRINT(INIT_DBG, "double ECC error!!\n");
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003135 if (nic->device_type != XFRAME_II_DEVICE) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003136 /* Reset XframeI only if critical error */
3137 if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
3138 MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
3139 netif_stop_queue(dev);
3140 schedule_work(&nic->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04003141 nic->mac_control.stats_info->sw_stat.
3142 soft_reset_cnt++;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003143 }
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003144 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003145 } else {
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07003146 nic->mac_control.stats_info->sw_stat.
3147 single_ecc_errs++;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003148 }
3149 }
3150
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 /* In case of a serious error, the device will be Reset. */
3152 val64 = readq(&bar0->serr_source);
3153 if (val64 & SERR_SOURCE_ANY) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04003154 nic->mac_control.stats_info->sw_stat.serious_err_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003156 DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
3157 (unsigned long long)val64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 netif_stop_queue(dev);
3159 schedule_work(&nic->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04003160 nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 }
3162
3163 /*
3164 * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
3165 * Error occurs, the adapter will be recycled by disabling the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003166 * adapter enable bit and enabling it again after the device
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 * becomes Quiescent.
3168 */
3169 val64 = readq(&bar0->pcc_err_reg);
3170 writeq(val64, &bar0->pcc_err_reg);
3171 if (val64 & PCC_FB_ECC_DB_ERR) {
3172 u64 ac = readq(&bar0->adapter_control);
3173 ac &= ~(ADAPTER_CNTL_EN);
3174 writeq(ac, &bar0->adapter_control);
3175 ac = readq(&bar0->adapter_control);
3176 schedule_work(&nic->set_link_task);
3177 }
Ananda Rajubd1034f2006-04-21 19:20:22 -04003178 /* Check for data parity error */
3179 val64 = readq(&bar0->pic_int_status);
3180 if (val64 & PIC_INT_GPIO) {
3181 val64 = readq(&bar0->gpio_int_reg);
3182 if (val64 & GPIO_INT_REG_DP_ERR_INT) {
3183 nic->mac_control.stats_info->sw_stat.parity_err_cnt++;
3184 schedule_work(&nic->rst_timer_task);
3185 nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
3186 }
3187 }
3188
3189 /* Check for ring full counter */
3190 if (nic->device_type & XFRAME_II_DEVICE) {
3191 val64 = readq(&bar0->ring_bump_counter1);
3192 for (i=0; i<4; i++) {
3193 cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
3194 cnt >>= 64 - ((i+1)*16);
3195 nic->mac_control.stats_info->sw_stat.ring_full_cnt
3196 += cnt;
3197 }
3198
3199 val64 = readq(&bar0->ring_bump_counter2);
3200 for (i=0; i<4; i++) {
3201 cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
3202 cnt >>= 64 - ((i+1)*16);
3203 nic->mac_control.stats_info->sw_stat.ring_full_cnt
3204 += cnt;
3205 }
3206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207
3208 /* Other type of interrupts are not being handled now, TODO */
3209}
3210
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003211/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 * wait_for_cmd_complete - waits for a command to complete.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003213 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003215 * Description: Function that waits for a command to Write into RMAC
3216 * ADDR DATA registers to be completed and returns either success or
3217 * error depending on whether the command was complete or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 * Return value:
3219 * SUCCESS on success and FAILURE on failure.
3220 */
3221
Ananda Rajuc92ca042006-04-21 19:18:03 -04003222static int wait_for_cmd_complete(void *addr, u64 busy_bit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 int ret = FAILURE, cnt = 0;
3225 u64 val64;
3226
3227 while (TRUE) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04003228 val64 = readq(addr);
3229 if (!(val64 & busy_bit)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 ret = SUCCESS;
3231 break;
3232 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003233
3234 if(in_interrupt())
3235 mdelay(50);
3236 else
3237 msleep(50);
3238
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 if (cnt++ > 10)
3240 break;
3241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 return ret;
3243}
3244
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003245/**
3246 * s2io_reset - Resets the card.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 * @sp : private member of the device structure.
3248 * Description: Function to Reset the card. This function then also
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003249 * restores the previously saved PCI configuration space registers as
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 * the card reset also resets the configuration space.
3251 * Return value:
3252 * void.
3253 */
3254
Adrian Bunk26df54b2006-01-14 03:09:40 +01003255static void s2io_reset(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256{
3257 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3258 u64 val64;
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003259 u16 subid, pci_cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003261 /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003262 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003263
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 val64 = SW_RESET_ALL;
3265 writeq(val64, &bar0->sw_reset);
3266
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003267 /*
3268 * At this stage, if the PCI write is indeed completed, the
3269 * card is reset and so is the PCI Config space of the device.
3270 * So a read cannot be issued at this stage on any of the
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 * registers to ensure the write into "sw_reset" register
3272 * has gone through.
3273 * Question: Is there any system call that will explicitly force
3274 * all the write commands still pending on the bus to be pushed
3275 * through?
3276 * As of now I'am just giving a 250ms delay and hoping that the
3277 * PCI write to sw_reset register is done by this time.
3278 */
3279 msleep(250);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003280 if (strstr(sp->product_name, "CX4")) {
3281 msleep(750);
3282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07003284 /* Restore the PCI state saved during initialization. */
3285 pci_restore_state(sp->pdev);
3286 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003287 pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 s2io_init_pci(sp);
3289
3290 msleep(250);
3291
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003292 /* Set swapper to enable I/O register access */
3293 s2io_set_swapper(sp);
3294
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003295 /* Restore the MSIX table entries from local variables */
3296 restore_xmsi_data(sp);
3297
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003298 /* Clear certain PCI/PCI-X fields after reset */
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003299 if (sp->device_type == XFRAME_II_DEVICE) {
3300 /* Clear parity err detect bit */
3301 pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003302
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003303 /* Clearing PCIX Ecc status register */
3304 pci_write_config_dword(sp->pdev, 0x68, 0x7C);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003305
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07003306 /* Clearing PCI_STATUS error reflected here */
3307 writeq(BIT(62), &bar0->txpic_int_reg);
3308 }
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07003309
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003310 /* Reset device statistics maintained by OS */
3311 memset(&sp->stats, 0, sizeof (struct net_device_stats));
3312
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 /* SXE-002: Configure link and activity LED to turn it off */
3314 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003315 if (((subid & 0xFF) >= 0x07) &&
3316 (sp->device_type == XFRAME_I_DEVICE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 val64 = readq(&bar0->gpio_control);
3318 val64 |= 0x0000800000000000ULL;
3319 writeq(val64, &bar0->gpio_control);
3320 val64 = 0x0411040400000000ULL;
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01003321 writeq(val64, (void __iomem *)bar0 + 0x2700);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 }
3323
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07003324 /*
3325 * Clear spurious ECC interrupts that would have occured on
3326 * XFRAME II cards after reset.
3327 */
3328 if (sp->device_type == XFRAME_II_DEVICE) {
3329 val64 = readq(&bar0->pcc_err_reg);
3330 writeq(val64, &bar0->pcc_err_reg);
3331 }
3332
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 sp->device_enabled_once = FALSE;
3334}
3335
3336/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003337 * s2io_set_swapper - to set the swapper controle on the card
3338 * @sp : private member of the device structure,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 * pointer to the s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003340 * Description: Function to set the swapper control on the card
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 * correctly depending on the 'endianness' of the system.
3342 * Return value:
3343 * SUCCESS on success and FAILURE on failure.
3344 */
3345
Adrian Bunk26df54b2006-01-14 03:09:40 +01003346static int s2io_set_swapper(nic_t * sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347{
3348 struct net_device *dev = sp->dev;
3349 XENA_dev_config_t __iomem *bar0 = sp->bar0;
3350 u64 val64, valt, valr;
3351
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003352 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 * Set proper endian settings and verify the same by reading
3354 * the PIF Feed-back register.
3355 */
3356
3357 val64 = readq(&bar0->pif_rd_swapper_fb);
3358 if (val64 != 0x0123456789ABCDEFULL) {
3359 int i = 0;
3360 u64 value[] = { 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */
3361 0x8100008181000081ULL, /* FE=1, SE=0 */
3362 0x4200004242000042ULL, /* FE=0, SE=1 */
3363 0}; /* FE=0, SE=0 */
3364
3365 while(i<4) {
3366 writeq(value[i], &bar0->swapper_ctrl);
3367 val64 = readq(&bar0->pif_rd_swapper_fb);
3368 if (val64 == 0x0123456789ABCDEFULL)
3369 break;
3370 i++;
3371 }
3372 if (i == 4) {
3373 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3374 dev->name);
3375 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3376 (unsigned long long) val64);
3377 return FAILURE;
3378 }
3379 valr = value[i];
3380 } else {
3381 valr = readq(&bar0->swapper_ctrl);
3382 }
3383
3384 valt = 0x0123456789ABCDEFULL;
3385 writeq(valt, &bar0->xmsi_address);
3386 val64 = readq(&bar0->xmsi_address);
3387
3388 if(val64 != valt) {
3389 int i = 0;
3390 u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */
3391 0x0081810000818100ULL, /* FE=1, SE=0 */
3392 0x0042420000424200ULL, /* FE=0, SE=1 */
3393 0}; /* FE=0, SE=0 */
3394
3395 while(i<4) {
3396 writeq((value[i] | valr), &bar0->swapper_ctrl);
3397 writeq(valt, &bar0->xmsi_address);
3398 val64 = readq(&bar0->xmsi_address);
3399 if(val64 == valt)
3400 break;
3401 i++;
3402 }
3403 if(i == 4) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003404 unsigned long long x = val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr ");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003406 DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 return FAILURE;
3408 }
3409 }
3410 val64 = readq(&bar0->swapper_ctrl);
3411 val64 &= 0xFFFF000000000000ULL;
3412
3413#ifdef __BIG_ENDIAN
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003414 /*
3415 * The device by default set to a big endian format, so a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 * big endian driver need not set anything.
3417 */
3418 val64 |= (SWAPPER_CTRL_TXP_FE |
3419 SWAPPER_CTRL_TXP_SE |
3420 SWAPPER_CTRL_TXD_R_FE |
3421 SWAPPER_CTRL_TXD_W_FE |
3422 SWAPPER_CTRL_TXF_R_FE |
3423 SWAPPER_CTRL_RXD_R_FE |
3424 SWAPPER_CTRL_RXD_W_FE |
3425 SWAPPER_CTRL_RXF_W_FE |
3426 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Andrew Morton92383342005-10-16 00:11:29 -07003428 if (sp->intr_type == INTA)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003429 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 writeq(val64, &bar0->swapper_ctrl);
3431#else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003432 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 * Initially we enable all bits to make it accessible by the
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003434 * driver, then we selectively enable only those bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 * we want to set.
3436 */
3437 val64 |= (SWAPPER_CTRL_TXP_FE |
3438 SWAPPER_CTRL_TXP_SE |
3439 SWAPPER_CTRL_TXD_R_FE |
3440 SWAPPER_CTRL_TXD_R_SE |
3441 SWAPPER_CTRL_TXD_W_FE |
3442 SWAPPER_CTRL_TXD_W_SE |
3443 SWAPPER_CTRL_TXF_R_FE |
3444 SWAPPER_CTRL_RXD_R_FE |
3445 SWAPPER_CTRL_RXD_R_SE |
3446 SWAPPER_CTRL_RXD_W_FE |
3447 SWAPPER_CTRL_RXD_W_SE |
3448 SWAPPER_CTRL_RXF_W_FE |
3449 SWAPPER_CTRL_XMSI_FE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003451 if (sp->intr_type == INTA)
3452 val64 |= SWAPPER_CTRL_XMSI_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 writeq(val64, &bar0->swapper_ctrl);
3454#endif
3455 val64 = readq(&bar0->swapper_ctrl);
3456
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003457 /*
3458 * Verifying if endian settings are accurate by reading a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 * feedback register.
3460 */
3461 val64 = readq(&bar0->pif_rd_swapper_fb);
3462 if (val64 != 0x0123456789ABCDEFULL) {
3463 /* Endian settings are incorrect, calls for another dekko. */
3464 DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ",
3465 dev->name);
3466 DBG_PRINT(ERR_DBG, "feedback read %llx\n",
3467 (unsigned long long) val64);
3468 return FAILURE;
3469 }
3470
3471 return SUCCESS;
3472}
3473
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003474static int wait_for_msix_trans(nic_t *nic, int i)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003475{
Al Viro37eb47e2005-12-15 09:17:29 +00003476 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003477 u64 val64;
3478 int ret = 0, cnt = 0;
3479
3480 do {
3481 val64 = readq(&bar0->xmsi_access);
3482 if (!(val64 & BIT(15)))
3483 break;
3484 mdelay(1);
3485 cnt++;
3486 } while(cnt < 5);
3487 if (cnt == 5) {
3488 DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i);
3489 ret = 1;
3490 }
3491
3492 return ret;
3493}
3494
Adrian Bunk26df54b2006-01-14 03:09:40 +01003495static void restore_xmsi_data(nic_t *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003496{
Al Viro37eb47e2005-12-15 09:17:29 +00003497 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003498 u64 val64;
3499 int i;
3500
Ananda Rajuc92ca042006-04-21 19:18:03 -04003501 for (i=0; i< nic->avail_msix_vectors; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003502 writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
3503 writeq(nic->msix_info[i].data, &bar0->xmsi_data);
3504 val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
3505 writeq(val64, &bar0->xmsi_access);
3506 if (wait_for_msix_trans(nic, i)) {
3507 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3508 continue;
3509 }
3510 }
3511}
3512
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003513static void store_xmsi_data(nic_t *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003514{
Al Viro37eb47e2005-12-15 09:17:29 +00003515 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003516 u64 val64, addr, data;
3517 int i;
3518
3519 /* Store and display */
Ananda Rajuc92ca042006-04-21 19:18:03 -04003520 for (i=0; i< nic->avail_msix_vectors; i++) {
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003521 val64 = (BIT(15) | vBIT(i, 26, 6));
3522 writeq(val64, &bar0->xmsi_access);
3523 if (wait_for_msix_trans(nic, i)) {
3524 DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
3525 continue;
3526 }
3527 addr = readq(&bar0->xmsi_address);
3528 data = readq(&bar0->xmsi_data);
3529 if (addr && data) {
3530 nic->msix_info[i].addr = addr;
3531 nic->msix_info[i].data = data;
3532 }
3533 }
3534}
3535
3536int s2io_enable_msi(nic_t *nic)
3537{
Al Viro37eb47e2005-12-15 09:17:29 +00003538 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003539 u16 msi_ctrl, msg_val;
3540 struct config_param *config = &nic->config;
3541 struct net_device *dev = nic->dev;
3542 u64 val64, tx_mat, rx_mat;
3543 int i, err;
3544
3545 val64 = readq(&bar0->pic_control);
3546 val64 &= ~BIT(1);
3547 writeq(val64, &bar0->pic_control);
3548
3549 err = pci_enable_msi(nic->pdev);
3550 if (err) {
3551 DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n",
3552 nic->dev->name);
3553 return err;
3554 }
3555
3556 /*
3557 * Enable MSI and use MSI-1 in stead of the standard MSI-0
3558 * for interrupt handling.
3559 */
3560 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3561 msg_val ^= 0x1;
3562 pci_write_config_word(nic->pdev, 0x4c, msg_val);
3563 pci_read_config_word(nic->pdev, 0x4c, &msg_val);
3564
3565 pci_read_config_word(nic->pdev, 0x42, &msi_ctrl);
3566 msi_ctrl |= 0x10;
3567 pci_write_config_word(nic->pdev, 0x42, msi_ctrl);
3568
3569 /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */
3570 tx_mat = readq(&bar0->tx_mat0_n[0]);
3571 for (i=0; i<config->tx_fifo_num; i++) {
3572 tx_mat |= TX_MAT_SET(i, 1);
3573 }
3574 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3575
3576 rx_mat = readq(&bar0->rx_mat);
3577 for (i=0; i<config->rx_ring_num; i++) {
3578 rx_mat |= RX_MAT_SET(i, 1);
3579 }
3580 writeq(rx_mat, &bar0->rx_mat);
3581
3582 dev->irq = nic->pdev->irq;
3583 return 0;
3584}
3585
Adrian Bunk26df54b2006-01-14 03:09:40 +01003586static int s2io_enable_msi_x(nic_t *nic)
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003587{
Al Viro37eb47e2005-12-15 09:17:29 +00003588 XENA_dev_config_t __iomem *bar0 = nic->bar0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003589 u64 tx_mat, rx_mat;
3590 u16 msi_control; /* Temp variable */
3591 int ret, i, j, msix_indx = 1;
3592
3593 nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
3594 GFP_KERNEL);
3595 if (nic->entries == NULL) {
3596 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3597 return -ENOMEM;
3598 }
3599 memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
3600
3601 nic->s2io_entries =
3602 kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
3603 GFP_KERNEL);
3604 if (nic->s2io_entries == NULL) {
3605 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
3606 kfree(nic->entries);
3607 return -ENOMEM;
3608 }
3609 memset(nic->s2io_entries, 0,
3610 MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
3611
3612 for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
3613 nic->entries[i].entry = i;
3614 nic->s2io_entries[i].entry = i;
3615 nic->s2io_entries[i].arg = NULL;
3616 nic->s2io_entries[i].in_use = 0;
3617 }
3618
3619 tx_mat = readq(&bar0->tx_mat0_n[0]);
3620 for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) {
3621 tx_mat |= TX_MAT_SET(i, msix_indx);
3622 nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i];
3623 nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE;
3624 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3625 }
3626 writeq(tx_mat, &bar0->tx_mat0_n[0]);
3627
3628 if (!nic->config.bimodal) {
3629 rx_mat = readq(&bar0->rx_mat);
3630 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3631 rx_mat |= RX_MAT_SET(j, msix_indx);
3632 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3633 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3634 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3635 }
3636 writeq(rx_mat, &bar0->rx_mat);
3637 } else {
3638 tx_mat = readq(&bar0->tx_mat0_n[7]);
3639 for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
3640 tx_mat |= TX_MAT_SET(i, msix_indx);
3641 nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
3642 nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
3643 nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
3644 }
3645 writeq(tx_mat, &bar0->tx_mat0_n[7]);
3646 }
3647
Ananda Rajuc92ca042006-04-21 19:18:03 -04003648 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003649 ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003650 /* We fail init if error or we get less vectors than min required */
3651 if (ret >= (nic->config.tx_fifo_num + nic->config.rx_ring_num + 1)) {
3652 nic->avail_msix_vectors = ret;
3653 ret = pci_enable_msix(nic->pdev, nic->entries, ret);
3654 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003655 if (ret) {
3656 DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
3657 kfree(nic->entries);
3658 kfree(nic->s2io_entries);
3659 nic->entries = NULL;
3660 nic->s2io_entries = NULL;
Ananda Rajuc92ca042006-04-21 19:18:03 -04003661 nic->avail_msix_vectors = 0;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003662 return -ENOMEM;
3663 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003664 if (!nic->avail_msix_vectors)
3665 nic->avail_msix_vectors = MAX_REQUESTED_MSI_X;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003666
3667 /*
3668 * To enable MSI-X, MSI also needs to be enabled, due to a bug
3669 * in the herc NIC. (Temp change, needs to be removed later)
3670 */
3671 pci_read_config_word(nic->pdev, 0x42, &msi_control);
3672 msi_control |= 0x1; /* Enable MSI */
3673 pci_write_config_word(nic->pdev, 0x42, msi_control);
3674
3675 return 0;
3676}
3677
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678/* ********************************************************* *
3679 * Functions defined below concern the OS part of the driver *
3680 * ********************************************************* */
3681
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003682/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 * s2io_open - open entry point of the driver
3684 * @dev : pointer to the device structure.
3685 * Description:
3686 * This function is the open entry point of the driver. It mainly calls a
3687 * function to allocate Rx buffers and inserts them into the buffer
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003688 * descriptors and then enables the Rx part of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 * Return value:
3690 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3691 * file on failure.
3692 */
3693
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003694static int s2io_open(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695{
3696 nic_t *sp = dev->priv;
3697 int err = 0;
3698
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003699 /*
3700 * Make sure you have link off by default every time
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 * Nic is initialized
3702 */
3703 netif_carrier_off(dev);
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003704 sp->last_link_state = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705
3706 /* Initialize H/W and enable interrupts */
Ananda Rajuc92ca042006-04-21 19:18:03 -04003707 err = s2io_card_up(sp);
3708 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
3710 dev->name);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003711 if (err == -ENODEV)
3712 goto hw_init_failed;
3713 else
3714 goto hw_enable_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 }
3716
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003717 /* Store the values of the MSIX table in the nic_t structure */
3718 store_xmsi_data(sp);
3719
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 /* After proper initialization of H/W, register ISR */
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003721 if (sp->intr_type == MSI) {
3722 err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
3723 SA_SHIRQ, sp->name, dev);
3724 if (err) {
3725 DBG_PRINT(ERR_DBG, "%s: MSI registration \
3726failed\n", dev->name);
3727 goto isr_registration_failed;
3728 }
3729 }
3730 if (sp->intr_type == MSI_X) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04003731 int i;
3732
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003733 for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
3734 if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
3735 sprintf(sp->desc1, "%s:MSI-X-%d-TX",
3736 dev->name, i);
3737 err = request_irq(sp->entries[i].vector,
3738 s2io_msix_fifo_handle, 0, sp->desc1,
3739 sp->s2io_entries[i].arg);
3740 DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1,
Andrew Morton26b76252005-12-14 19:25:23 -08003741 (unsigned long long)sp->msix_info[i].addr);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003742 } else {
3743 sprintf(sp->desc2, "%s:MSI-X-%d-RX",
3744 dev->name, i);
3745 err = request_irq(sp->entries[i].vector,
3746 s2io_msix_ring_handle, 0, sp->desc2,
3747 sp->s2io_entries[i].arg);
3748 DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2,
Andrew Morton26b76252005-12-14 19:25:23 -08003749 (unsigned long long)sp->msix_info[i].addr);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003750 }
3751 if (err) {
3752 DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \
3753failed\n", dev->name, i);
3754 DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
3755 goto isr_registration_failed;
3756 }
3757 sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
3758 }
3759 }
3760 if (sp->intr_type == INTA) {
3761 err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ,
3762 sp->name, dev);
3763 if (err) {
3764 DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
3765 dev->name);
3766 goto isr_registration_failed;
3767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 }
3769
3770 if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
3771 DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003772 err = -ENODEV;
3773 goto setting_mac_address_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 }
3775
3776 netif_start_queue(dev);
3777 return 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003778
3779setting_mac_address_failed:
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003780 if (sp->intr_type != MSI_X)
3781 free_irq(sp->pdev->irq, dev);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003782isr_registration_failed:
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07003783 del_timer_sync(&sp->alarm_timer);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003784 if (sp->intr_type == MSI_X) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04003785 int i;
3786 u16 msi_control; /* Temp variable */
Ananda Rajubd1034f2006-04-21 19:20:22 -04003787
Ananda Rajuc92ca042006-04-21 19:18:03 -04003788 for (i=1; (sp->s2io_entries[i].in_use ==
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003789 MSIX_REGISTERED_SUCCESS); i++) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04003790 int vector = sp->entries[i].vector;
3791 void *arg = sp->s2io_entries[i].arg;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003792
Ananda Rajuc92ca042006-04-21 19:18:03 -04003793 free_irq(vector, arg);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003794 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04003795 pci_disable_msix(sp->pdev);
3796
3797 /* Temp */
3798 pci_read_config_word(sp->pdev, 0x42, &msi_control);
3799 msi_control &= 0xFFFE; /* Disable MSI */
3800 pci_write_config_word(sp->pdev, 0x42, msi_control);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003801 }
3802 else if (sp->intr_type == MSI)
3803 pci_disable_msi(sp->pdev);
Ananda Rajuc92ca042006-04-21 19:18:03 -04003804hw_enable_failed:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003805 s2io_reset(sp);
3806hw_init_failed:
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003807 if (sp->intr_type == MSI_X) {
3808 if (sp->entries)
3809 kfree(sp->entries);
3810 if (sp->s2io_entries)
3811 kfree(sp->s2io_entries);
3812 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003813 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814}
3815
3816/**
3817 * s2io_close -close entry point of the driver
3818 * @dev : device pointer.
3819 * Description:
3820 * This is the stop entry point of the driver. It needs to undo exactly
3821 * whatever was done by the open entry point,thus it's usually referred to
3822 * as the close function.Among other things this function mainly stops the
3823 * Rx side of the NIC and frees all the Rx buffers in the Rx rings.
3824 * Return value:
3825 * 0 on success and an appropriate (-)ve integer as defined in errno.h
3826 * file on failure.
3827 */
3828
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003829static int s2io_close(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830{
3831 nic_t *sp = dev->priv;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04003832
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 flush_scheduled_work();
3834 netif_stop_queue(dev);
3835 /* Reset card, kill tasklet and free Tx and Rx buffers. */
Ananda Rajuc92ca042006-04-21 19:18:03 -04003836 s2io_card_down(sp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 sp->device_close_flag = TRUE; /* Device is shut down. */
3839 return 0;
3840}
3841
3842/**
3843 * s2io_xmit - Tx entry point of te driver
3844 * @skb : the socket buffer containing the Tx data.
3845 * @dev : device pointer.
3846 * Description :
3847 * This function is the Tx entry point of the driver. S2IO NIC supports
3848 * certain protocol assist features on Tx side, namely CSO, S/G, LSO.
3849 * NOTE: when device cant queue the pkt,just the trans_start variable will
3850 * not be upadted.
3851 * Return value:
3852 * 0 on success & 1 on failure.
3853 */
3854
Adrian Bunkac1f60d2005-11-06 01:46:47 +01003855static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856{
3857 nic_t *sp = dev->priv;
3858 u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
3859 register u64 val64;
3860 TxD_t *txdp;
3861 TxFIFO_element_t __iomem *tx_fifo;
3862 unsigned long flags;
3863#ifdef NETIF_F_TSO
3864 int mss;
3865#endif
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003866 u16 vlan_tag = 0;
3867 int vlan_priority = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 mac_info_t *mac_control;
3869 struct config_param *config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870
3871 mac_control = &sp->mac_control;
3872 config = &sp->config;
3873
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003874 DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 spin_lock_irqsave(&sp->tx_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 if (atomic_read(&sp->card_state) == CARD_DOWN) {
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003877 DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 dev->name);
3879 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003880 dev_kfree_skb(skb);
3881 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882 }
3883
3884 queue = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003886 /* Get Fifo number to Transmit based on vlan priority */
3887 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3888 vlan_tag = vlan_tx_tag_get(skb);
3889 vlan_priority = vlan_tag >> 13;
3890 queue = config->fifo_mapping[vlan_priority];
3891 }
3892
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003893 put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
3894 get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
3895 txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off].
3896 list_virt_addr;
3897
3898 queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04003900 if (txdp->Host_Control ||
3901 ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07003902 DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 netif_stop_queue(dev);
3904 dev_kfree_skb(skb);
3905 spin_unlock_irqrestore(&sp->tx_lock, flags);
3906 return 0;
3907 }
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003908
3909 /* A buffer with no data will be dropped */
3910 if (!skb->len) {
3911 DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
3912 dev_kfree_skb(skb);
3913 spin_unlock_irqrestore(&sp->tx_lock, flags);
3914 return 0;
3915 }
3916
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003917 txdp->Control_1 = 0;
3918 txdp->Control_2 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919#ifdef NETIF_F_TSO
3920 mss = skb_shinfo(skb)->tso_size;
3921 if (mss) {
3922 txdp->Control_1 |= TXD_TCP_LSO_EN;
3923 txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
3924 }
3925#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 if (skb->ip_summed == CHECKSUM_HW) {
3927 txdp->Control_2 |=
3928 (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
3929 TXD_TX_CKO_UDP_EN);
3930 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003931 txdp->Control_1 |= TXD_GATHER_CODE_FIRST;
3932 txdp->Control_1 |= TXD_LIST_OWN_XENA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 txdp->Control_2 |= config->tx_intr_type;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07003934
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07003935 if (sp->vlgrp && vlan_tx_tag_present(skb)) {
3936 txdp->Control_2 |= TXD_VLAN_ENABLE;
3937 txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
3938 }
3939
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003940 frg_len = skb->len - skb->data_len;
3941 if (skb_shinfo(skb)->ufo_size) {
3942 int ufo_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003944 ufo_size = skb_shinfo(skb)->ufo_size;
3945 ufo_size &= ~7;
3946 txdp->Control_1 |= TXD_UFO_EN;
3947 txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
3948 txdp->Control_1 |= TXD_BUFFER0_SIZE(8);
3949#ifdef __BIG_ENDIAN
3950 sp->ufo_in_band_v[put_off] =
3951 (u64)skb_shinfo(skb)->ip6_frag_id;
3952#else
3953 sp->ufo_in_band_v[put_off] =
3954 (u64)skb_shinfo(skb)->ip6_frag_id << 32;
3955#endif
3956 txdp->Host_Control = (unsigned long)sp->ufo_in_band_v;
3957 txdp->Buffer_Pointer = pci_map_single(sp->pdev,
3958 sp->ufo_in_band_v,
3959 sizeof(u64), PCI_DMA_TODEVICE);
3960 txdp++;
3961 txdp->Control_1 = 0;
3962 txdp->Control_2 = 0;
3963 }
3964
3965 txdp->Buffer_Pointer = pci_map_single
3966 (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
3967 txdp->Host_Control = (unsigned long) skb;
3968 txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
3969
3970 if (skb_shinfo(skb)->ufo_size)
3971 txdp->Control_1 |= TXD_UFO_EN;
3972
3973 frg_cnt = skb_shinfo(skb)->nr_frags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 /* For fragmented SKB. */
3975 for (i = 0; i < frg_cnt; i++) {
3976 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07003977 /* A '0' length fragment will be ignored */
3978 if (!frag->size)
3979 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 txdp++;
3981 txdp->Buffer_Pointer = (u64) pci_map_page
3982 (sp->pdev, frag->page, frag->page_offset,
3983 frag->size, PCI_DMA_TODEVICE);
Ananda Rajuefd51b52006-01-19 14:11:54 -05003984 txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003985 if (skb_shinfo(skb)->ufo_size)
3986 txdp->Control_1 |= TXD_UFO_EN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 }
3988 txdp->Control_1 |= TXD_GATHER_CODE_LAST;
3989
Ananda Rajufed5ecc2005-11-14 15:25:08 -05003990 if (skb_shinfo(skb)->ufo_size)
3991 frg_cnt++; /* as Txd0 was used for inband header */
3992
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 tx_fifo = mac_control->tx_FIFO_start[queue];
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003994 val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 writeq(val64, &tx_fifo->TxDL_Pointer);
3996
3997 val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
3998 TX_FIFO_LAST_LIST);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07003999
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000#ifdef NETIF_F_TSO
4001 if (mss)
4002 val64 |= TX_FIFO_SPECIAL_FUNC;
4003#endif
Ananda Rajufed5ecc2005-11-14 15:25:08 -05004004 if (skb_shinfo(skb)->ufo_size)
4005 val64 |= TX_FIFO_SPECIAL_FUNC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 writeq(val64, &tx_fifo->List_Control);
4007
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07004008 mmiowb();
4009
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 put_off++;
Ananda Raju863c11a2006-04-21 19:03:13 -04004011 if (put_off == mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1)
4012 put_off = 0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004013 mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014
4015 /* Avoid "put" pointer going beyond "get" pointer */
Ananda Raju863c11a2006-04-21 19:03:13 -04004016 if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04004017 sp->mac_control.stats_info->sw_stat.fifo_full_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 DBG_PRINT(TX_DBG,
4019 "No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
4020 put_off, get_off);
4021 netif_stop_queue(dev);
4022 }
4023
4024 dev->trans_start = jiffies;
4025 spin_unlock_irqrestore(&sp->tx_lock, flags);
4026
4027 return 0;
4028}
4029
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07004030static void
4031s2io_alarm_handle(unsigned long data)
4032{
4033 nic_t *sp = (nic_t *)data;
4034
4035 alarm_intr_handler(sp);
4036 mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
4037}
4038
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004039static irqreturn_t
4040s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs)
4041{
4042 struct net_device *dev = (struct net_device *) dev_id;
4043 nic_t *sp = dev->priv;
4044 int i;
4045 int ret;
4046 mac_info_t *mac_control;
4047 struct config_param *config;
4048
4049 atomic_inc(&sp->isr_cnt);
4050 mac_control = &sp->mac_control;
4051 config = &sp->config;
4052 DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__);
4053
4054 /* If Intr is because of Rx Traffic */
4055 for (i = 0; i < config->rx_ring_num; i++)
4056 rx_intr_handler(&mac_control->rings[i]);
4057
4058 /* If Intr is because of Tx Traffic */
4059 for (i = 0; i < config->tx_fifo_num; i++)
4060 tx_intr_handler(&mac_control->fifos[i]);
4061
4062 /*
4063 * If the Rx buffer count is below the panic threshold then
4064 * reallocate the buffers from the interrupt handler itself,
4065 * else schedule a tasklet to reallocate the buffers.
4066 */
4067 for (i = 0; i < config->rx_ring_num; i++) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004068 if (!sp->lro) {
4069 int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
4070 int level = rx_buffer_level(sp, rxb_size, i);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004071
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004072 if ((level == PANIC) && (!TASKLET_IN_USE)) {
4073 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ",
4074 dev->name);
4075 DBG_PRINT(INTR_DBG, "PANIC levels\n");
4076 if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
4077 DBG_PRINT(ERR_DBG, "%s:Out of memory",
4078 dev->name);
4079 DBG_PRINT(ERR_DBG, " in ISR!!\n");
4080 clear_bit(0, (&sp->tasklet_status));
4081 atomic_dec(&sp->isr_cnt);
4082 return IRQ_HANDLED;
4083 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004084 clear_bit(0, (&sp->tasklet_status));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004085 } else if (level == LOW) {
4086 tasklet_schedule(&sp->task);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004087 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004088 }
4089 else if (fill_rx_buffers(sp, i) == -ENOMEM) {
4090 DBG_PRINT(ERR_DBG, "%s:Out of memory",
4091 dev->name);
4092 DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
4093 break;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004094 }
4095 }
4096
4097 atomic_dec(&sp->isr_cnt);
4098 return IRQ_HANDLED;
4099}
4100
4101static irqreturn_t
4102s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs)
4103{
4104 ring_info_t *ring = (ring_info_t *)dev_id;
4105 nic_t *sp = ring->nic;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004106 struct net_device *dev = (struct net_device *) dev_id;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004107 int rxb_size, level, rng_n;
4108
4109 atomic_inc(&sp->isr_cnt);
4110 rx_intr_handler(ring);
4111
4112 rng_n = ring->ring_no;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004113 if (!sp->lro) {
4114 rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
4115 level = rx_buffer_level(sp, rxb_size, rng_n);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004116
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004117 if ((level == PANIC) && (!TASKLET_IN_USE)) {
4118 int ret;
4119 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
4120 DBG_PRINT(INTR_DBG, "PANIC levels\n");
4121 if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
4122 DBG_PRINT(ERR_DBG, "Out of memory in %s",
4123 __FUNCTION__);
4124 clear_bit(0, (&sp->tasklet_status));
4125 return IRQ_HANDLED;
4126 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004127 clear_bit(0, (&sp->tasklet_status));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004128 } else if (level == LOW) {
4129 tasklet_schedule(&sp->task);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004130 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004131 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004132 else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
4133 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
4134 DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
4135 }
4136
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04004137 atomic_dec(&sp->isr_cnt);
4138
4139 return IRQ_HANDLED;
4140}
4141
4142static irqreturn_t
4143s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs)
4144{
4145 fifo_info_t *fifo = (fifo_info_t *)dev_id;
4146 nic_t *sp = fifo->nic;
4147
4148 atomic_inc(&sp->isr_cnt);
4149 tx_intr_handler(fifo);
4150 atomic_dec(&sp->isr_cnt);
4151 return IRQ_HANDLED;
4152}
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004153static void s2io_txpic_intr_handle(nic_t *sp)
4154{
viro@ftp.linux.org.uk509a2672005-09-05 03:25:58 +01004155 XENA_dev_config_t __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004156 u64 val64;
4157
4158 val64 = readq(&bar0->pic_int_status);
4159 if (val64 & PIC_INT_GPIO) {
4160 val64 = readq(&bar0->gpio_int_reg);
4161 if ((val64 & GPIO_INT_REG_LINK_DOWN) &&
4162 (val64 & GPIO_INT_REG_LINK_UP)) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04004163 /*
4164 * This is unstable state so clear both up/down
4165 * interrupt and adapter to re-evaluate the link state.
4166 */
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004167 val64 |= GPIO_INT_REG_LINK_DOWN;
4168 val64 |= GPIO_INT_REG_LINK_UP;
4169 writeq(val64, &bar0->gpio_int_reg);
Ananda Rajuc92ca042006-04-21 19:18:03 -04004170 val64 = readq(&bar0->gpio_int_mask);
4171 val64 &= ~(GPIO_INT_MASK_LINK_UP |
4172 GPIO_INT_MASK_LINK_DOWN);
4173 writeq(val64, &bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004174 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04004175 else if (val64 & GPIO_INT_REG_LINK_UP) {
4176 val64 = readq(&bar0->adapter_status);
4177 if (verify_xena_quiescence(sp, val64,
4178 sp->device_enabled_once)) {
4179 /* Enable Adapter */
4180 val64 = readq(&bar0->adapter_control);
4181 val64 |= ADAPTER_CNTL_EN;
4182 writeq(val64, &bar0->adapter_control);
4183 val64 |= ADAPTER_LED_ON;
4184 writeq(val64, &bar0->adapter_control);
4185 if (!sp->device_enabled_once)
4186 sp->device_enabled_once = 1;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004187
Ananda Rajuc92ca042006-04-21 19:18:03 -04004188 s2io_link(sp, LINK_UP);
4189 /*
4190 * unmask link down interrupt and mask link-up
4191 * intr
4192 */
4193 val64 = readq(&bar0->gpio_int_mask);
4194 val64 &= ~GPIO_INT_MASK_LINK_DOWN;
4195 val64 |= GPIO_INT_MASK_LINK_UP;
4196 writeq(val64, &bar0->gpio_int_mask);
4197
4198 }
4199 }else if (val64 & GPIO_INT_REG_LINK_DOWN) {
4200 val64 = readq(&bar0->adapter_status);
4201 if (verify_xena_quiescence(sp, val64,
4202 sp->device_enabled_once)) {
4203 s2io_link(sp, LINK_DOWN);
4204 /* Link is down so unmaks link up interrupt */
4205 val64 = readq(&bar0->gpio_int_mask);
4206 val64 &= ~GPIO_INT_MASK_LINK_UP;
4207 val64 |= GPIO_INT_MASK_LINK_DOWN;
4208 writeq(val64, &bar0->gpio_int_mask);
4209 }
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004210 }
4211 }
Ananda Rajuc92ca042006-04-21 19:18:03 -04004212 val64 = readq(&bar0->gpio_int_mask);
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004213}
4214
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215/**
4216 * s2io_isr - ISR handler of the device .
4217 * @irq: the irq of the device.
4218 * @dev_id: a void pointer to the dev structure of the NIC.
4219 * @pt_regs: pointer to the registers pushed on the stack.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004220 * Description: This function is the ISR handler of the device. It
4221 * identifies the reason for the interrupt and calls the relevant
4222 * service routines. As a contongency measure, this ISR allocates the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 * recv buffers, if their numbers are below the panic value which is
4224 * presently set to 25% of the original number of rcv buffers allocated.
4225 * Return value:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004226 * IRQ_HANDLED: will be returned if IRQ was handled by this routine
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 * IRQ_NONE: will be returned if interrupt is not from our device
4228 */
4229static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
4230{
4231 struct net_device *dev = (struct net_device *) dev_id;
4232 nic_t *sp = dev->priv;
4233 XENA_dev_config_t __iomem *bar0 = sp->bar0;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004234 int i;
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -07004235 u64 reason = 0, val64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 mac_info_t *mac_control;
4237 struct config_param *config;
4238
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004239 atomic_inc(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 mac_control = &sp->mac_control;
4241 config = &sp->config;
4242
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004243 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 * Identify the cause for interrupt and call the appropriate
4245 * interrupt handler. Causes for the interrupt could be;
4246 * 1. Rx of packet.
4247 * 2. Tx complete.
4248 * 3. Link down.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004249 * 4. Error in any functional blocks of the NIC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 */
4251 reason = readq(&bar0->general_int_status);
4252
4253 if (!reason) {
4254 /* The interrupt was not raised by Xena. */
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004255 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 return IRQ_NONE;
4257 }
4258
Ananda Raju863c11a2006-04-21 19:03:13 -04004259 val64 = 0xFFFFFFFFFFFFFFFFULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260#ifdef CONFIG_S2IO_NAPI
4261 if (reason & GEN_INTR_RXTRAFFIC) {
4262 if (netif_rx_schedule_prep(dev)) {
Ananda Raju863c11a2006-04-21 19:03:13 -04004263 writeq(val64, &bar0->rx_traffic_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264 __netif_rx_schedule(dev);
4265 }
4266 }
4267#else
Ananda Raju863c11a2006-04-21 19:03:13 -04004268 /*
4269 * Rx handler is called by default, without checking for the
4270 * cause of interrupt.
4271 * rx_traffic_int reg is an R1 register, writing all 1's
4272 * will ensure that the actual interrupt causing bit get's
4273 * cleared and hence a read can be avoided.
4274 */
4275 writeq(val64, &bar0->rx_traffic_int);
4276 for (i = 0; i < config->rx_ring_num; i++) {
4277 rx_intr_handler(&mac_control->rings[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 }
4279#endif
4280
Ananda Raju863c11a2006-04-21 19:03:13 -04004281 /*
4282 * tx_traffic_int reg is an R1 register, writing all 1's
4283 * will ensure that the actual interrupt causing bit get's
4284 * cleared and hence a read can be avoided.
4285 */
4286 writeq(val64, &bar0->tx_traffic_int);
raghavendra.koushik@neterion.comfe113632005-08-03 12:32:00 -07004287
Ananda Raju863c11a2006-04-21 19:03:13 -04004288 for (i = 0; i < config->tx_fifo_num; i++)
4289 tx_intr_handler(&mac_control->fifos[i]);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004290
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07004291 if (reason & GEN_INTR_TXPIC)
4292 s2io_txpic_intr_handle(sp);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004293 /*
4294 * If the Rx buffer count is below the panic threshold then
4295 * reallocate the buffers from the interrupt handler itself,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 * else schedule a tasklet to reallocate the buffers.
4297 */
4298#ifndef CONFIG_S2IO_NAPI
4299 for (i = 0; i < config->rx_ring_num; i++) {
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004300 if (!sp->lro) {
4301 int ret;
4302 int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
4303 int level = rx_buffer_level(sp, rxb_size, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004305 if ((level == PANIC) && (!TASKLET_IN_USE)) {
4306 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ",
4307 dev->name);
4308 DBG_PRINT(INTR_DBG, "PANIC levels\n");
4309 if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
4310 DBG_PRINT(ERR_DBG, "%s:Out of memory",
4311 dev->name);
4312 DBG_PRINT(ERR_DBG, " in ISR!!\n");
4313 clear_bit(0, (&sp->tasklet_status));
4314 atomic_dec(&sp->isr_cnt);
4315 return IRQ_HANDLED;
4316 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 clear_bit(0, (&sp->tasklet_status));
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004318 } else if (level == LOW) {
4319 tasklet_schedule(&sp->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05004321 }
4322 else if (fill_rx_buffers(sp, i) == -ENOMEM) {
4323 DBG_PRINT(ERR_DBG, "%s:Out of memory",
4324 dev->name);
4325 DBG_PRINT(ERR_DBG, " in Rx intr!!\n");
4326 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327 }
4328 }
4329#endif
4330
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004331 atomic_dec(&sp->isr_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 return IRQ_HANDLED;
4333}
4334
4335/**
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004336 * s2io_updt_stats -
4337 */
4338static void s2io_updt_stats(nic_t *sp)
4339{
4340 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4341 u64 val64;
4342 int cnt = 0;
4343
4344 if (atomic_read(&sp->card_state) == CARD_UP) {
4345 /* Apprx 30us on a 133 MHz bus */
4346 val64 = SET_UPDT_CLICKS(10) |
4347 STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
4348 writeq(val64, &bar0->stat_cfg);
4349 do {
4350 udelay(100);
4351 val64 = readq(&bar0->stat_cfg);
4352 if (!(val64 & BIT(0)))
4353 break;
4354 cnt++;
4355 if (cnt == 5)
4356 break; /* Updt failed */
4357 } while(1);
4358 }
4359}
4360
4361/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004362 * s2io_get_stats - Updates the device statistics structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 * @dev : pointer to the device structure.
4364 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004365 * This function updates the device statistics structure in the s2io_nic
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 * structure and returns a pointer to the same.
4367 * Return value:
4368 * pointer to the updated net_device_stats structure.
4369 */
4370
Adrian Bunkac1f60d2005-11-06 01:46:47 +01004371static struct net_device_stats *s2io_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372{
4373 nic_t *sp = dev->priv;
4374 mac_info_t *mac_control;
4375 struct config_param *config;
4376
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004377
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 mac_control = &sp->mac_control;
4379 config = &sp->config;
4380
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07004381 /* Configure Stats for immediate updt */
4382 s2io_updt_stats(sp);
4383
4384 sp->stats.tx_packets =
4385 le32_to_cpu(mac_control->stats_info->tmac_frms);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004386 sp->stats.tx_errors =
4387 le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
4388 sp->stats.rx_errors =
4389 le32_to_cpu(mac_control->stats_info->rmac_drop_frms);
4390 sp->stats.multicast =
4391 le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 sp->stats.rx_length_errors =
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004393 le32_to_cpu(mac_control->stats_info->rmac_long_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394
4395 return (&sp->stats);
4396}
4397
4398/**
4399 * s2io_set_multicast - entry point for multicast address enable/disable.
4400 * @dev : pointer to the device structure
4401 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004402 * This function is a driver entry point which gets called by the kernel
4403 * whenever multicast addresses must be enabled/disabled. This also gets
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 * called to set/reset promiscuous mode. Depending on the deivce flag, we
4405 * determine, if multicast address must be enabled or if promiscuous mode
4406 * is to be disabled etc.
4407 * Return value:
4408 * void.
4409 */
4410
4411static void s2io_set_multicast(struct net_device *dev)
4412{
4413 int i, j, prev_cnt;
4414 struct dev_mc_list *mclist;
4415 nic_t *sp = dev->priv;
4416 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4417 u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
4418 0xfeffffffffffULL;
4419 u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
4420 void __iomem *add;
4421
4422 if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) {
4423 /* Enable all Multicast addresses */
4424 writeq(RMAC_ADDR_DATA0_MEM_ADDR(multi_mac),
4425 &bar0->rmac_addr_data0_mem);
4426 writeq(RMAC_ADDR_DATA1_MEM_MASK(mask),
4427 &bar0->rmac_addr_data1_mem);
4428 val64 = RMAC_ADDR_CMD_MEM_WE |
4429 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4430 RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
4431 writeq(val64, &bar0->rmac_addr_cmd_mem);
4432 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004433 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4434 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435
4436 sp->m_cast_flg = 1;
4437 sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
4438 } else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) {
4439 /* Disable all Multicast addresses */
4440 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4441 &bar0->rmac_addr_data0_mem);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07004442 writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0),
4443 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 val64 = RMAC_ADDR_CMD_MEM_WE |
4445 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4446 RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos);
4447 writeq(val64, &bar0->rmac_addr_cmd_mem);
4448 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004449 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4450 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451
4452 sp->m_cast_flg = 0;
4453 sp->all_multi_pos = 0;
4454 }
4455
4456 if ((dev->flags & IFF_PROMISC) && (!sp->promisc_flg)) {
4457 /* Put the NIC into promiscuous mode */
4458 add = &bar0->mac_cfg;
4459 val64 = readq(&bar0->mac_cfg);
4460 val64 |= MAC_CFG_RMAC_PROM_ENABLE;
4461
4462 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4463 writel((u32) val64, add);
4464 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4465 writel((u32) (val64 >> 32), (add + 4));
4466
4467 val64 = readq(&bar0->mac_cfg);
4468 sp->promisc_flg = 1;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004469 DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 dev->name);
4471 } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) {
4472 /* Remove the NIC from promiscuous mode */
4473 add = &bar0->mac_cfg;
4474 val64 = readq(&bar0->mac_cfg);
4475 val64 &= ~MAC_CFG_RMAC_PROM_ENABLE;
4476
4477 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4478 writel((u32) val64, add);
4479 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
4480 writel((u32) (val64 >> 32), (add + 4));
4481
4482 val64 = readq(&bar0->mac_cfg);
4483 sp->promisc_flg = 0;
ravinandan.arakali@neterion.com776bd202005-09-06 21:36:56 -07004484 DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 dev->name);
4486 }
4487
4488 /* Update individual M_CAST address list */
4489 if ((!sp->m_cast_flg) && dev->mc_count) {
4490 if (dev->mc_count >
4491 (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) {
4492 DBG_PRINT(ERR_DBG, "%s: No more Rx filters ",
4493 dev->name);
4494 DBG_PRINT(ERR_DBG, "can be added, please enable ");
4495 DBG_PRINT(ERR_DBG, "ALL_MULTI instead\n");
4496 return;
4497 }
4498
4499 prev_cnt = sp->mc_addr_count;
4500 sp->mc_addr_count = dev->mc_count;
4501
4502 /* Clear out the previous list of Mc in the H/W. */
4503 for (i = 0; i < prev_cnt; i++) {
4504 writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
4505 &bar0->rmac_addr_data0_mem);
4506 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004507 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 val64 = RMAC_ADDR_CMD_MEM_WE |
4509 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4510 RMAC_ADDR_CMD_MEM_OFFSET
4511 (MAC_MC_ADDR_START_OFFSET + i);
4512 writeq(val64, &bar0->rmac_addr_cmd_mem);
4513
4514 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004515 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4516 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 DBG_PRINT(ERR_DBG, "%s: Adding ",
4518 dev->name);
4519 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4520 return;
4521 }
4522 }
4523
4524 /* Create the new Rx filter list and update the same in H/W. */
4525 for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
4526 i++, mclist = mclist->next) {
4527 memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr,
4528 ETH_ALEN);
Jeff Garzika7a80d52006-03-04 12:06:51 -05004529 mac_addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 for (j = 0; j < ETH_ALEN; j++) {
4531 mac_addr |= mclist->dmi_addr[j];
4532 mac_addr <<= 8;
4533 }
4534 mac_addr >>= 8;
4535 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4536 &bar0->rmac_addr_data0_mem);
4537 writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004538 &bar0->rmac_addr_data1_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 val64 = RMAC_ADDR_CMD_MEM_WE |
4540 RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4541 RMAC_ADDR_CMD_MEM_OFFSET
4542 (i + MAC_MC_ADDR_START_OFFSET);
4543 writeq(val64, &bar0->rmac_addr_cmd_mem);
4544
4545 /* Wait for command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004546 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4547 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 DBG_PRINT(ERR_DBG, "%s: Adding ",
4549 dev->name);
4550 DBG_PRINT(ERR_DBG, "Multicasts failed\n");
4551 return;
4552 }
4553 }
4554 }
4555}
4556
4557/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004558 * s2io_set_mac_addr - Programs the Xframe mac address
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 * @dev : pointer to the device structure.
4560 * @addr: a uchar pointer to the new mac address which is to be set.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004561 * Description : This procedure will program the Xframe to receive
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 * frames with new Mac Address
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004563 * Return value: SUCCESS on success and an appropriate (-)ve integer
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 * as defined in errno.h file on failure.
4565 */
4566
Adrian Bunk26df54b2006-01-14 03:09:40 +01004567static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568{
4569 nic_t *sp = dev->priv;
4570 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4571 register u64 val64, mac_addr = 0;
4572 int i;
4573
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004574 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 * Set the new MAC address as the new unicast filter and reflect this
4576 * change on the device address registered with the OS. It will be
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004577 * at offset 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 */
4579 for (i = 0; i < ETH_ALEN; i++) {
4580 mac_addr <<= 8;
4581 mac_addr |= addr[i];
4582 }
4583
4584 writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
4585 &bar0->rmac_addr_data0_mem);
4586
4587 val64 =
4588 RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
4589 RMAC_ADDR_CMD_MEM_OFFSET(0);
4590 writeq(val64, &bar0->rmac_addr_cmd_mem);
4591 /* Wait till command completes */
Ananda Rajuc92ca042006-04-21 19:18:03 -04004592 if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
4593 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
4595 return FAILURE;
4596 }
4597
4598 return SUCCESS;
4599}
4600
4601/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004602 * s2io_ethtool_sset - Sets different link parameters.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure.
4604 * @info: pointer to the structure with parameters given by ethtool to set
4605 * link information.
4606 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004607 * The function sets different link parameters provided by the user onto
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608 * the NIC.
4609 * Return value:
4610 * 0 on success.
4611*/
4612
4613static int s2io_ethtool_sset(struct net_device *dev,
4614 struct ethtool_cmd *info)
4615{
4616 nic_t *sp = dev->priv;
4617 if ((info->autoneg == AUTONEG_ENABLE) ||
4618 (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
4619 return -EINVAL;
4620 else {
4621 s2io_close(sp->dev);
4622 s2io_open(sp->dev);
4623 }
4624
4625 return 0;
4626}
4627
4628/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004629 * s2io_ethtol_gset - Return link specific information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630 * @sp : private member of the device structure, pointer to the
4631 * s2io_nic structure.
4632 * @info : pointer to the structure with parameters given by ethtool
4633 * to return link information.
4634 * Description:
4635 * Returns link specific information like speed, duplex etc.. to ethtool.
4636 * Return value :
4637 * return 0 on success.
4638 */
4639
4640static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
4641{
4642 nic_t *sp = dev->priv;
4643 info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4644 info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
4645 info->port = PORT_FIBRE;
4646 /* info->transceiver?? TODO */
4647
4648 if (netif_carrier_ok(sp->dev)) {
4649 info->speed = 10000;
4650 info->duplex = DUPLEX_FULL;
4651 } else {
4652 info->speed = -1;
4653 info->duplex = -1;
4654 }
4655
4656 info->autoneg = AUTONEG_DISABLE;
4657 return 0;
4658}
4659
4660/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004661 * s2io_ethtool_gdrvinfo - Returns driver specific information.
4662 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 * s2io_nic structure.
4664 * @info : pointer to the structure with parameters given by ethtool to
4665 * return driver information.
4666 * Description:
4667 * Returns driver specefic information like name, version etc.. to ethtool.
4668 * Return value:
4669 * void
4670 */
4671
4672static void s2io_ethtool_gdrvinfo(struct net_device *dev,
4673 struct ethtool_drvinfo *info)
4674{
4675 nic_t *sp = dev->priv;
4676
John W. Linvilledbc23092005-09-28 17:50:51 -04004677 strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
4678 strncpy(info->version, s2io_driver_version, sizeof(info->version));
4679 strncpy(info->fw_version, "", sizeof(info->fw_version));
4680 strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681 info->regdump_len = XENA_REG_SPACE;
4682 info->eedump_len = XENA_EEPROM_SPACE;
4683 info->testinfo_len = S2IO_TEST_LEN;
4684 info->n_stats = S2IO_STAT_LEN;
4685}
4686
4687/**
4688 * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004689 * @sp: private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004691 * @regs : pointer to the structure with parameters given by ethtool for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692 * dumping the registers.
4693 * @reg_space: The input argumnet into which all the registers are dumped.
4694 * Description:
4695 * Dumps the entire register space of xFrame NIC into the user given
4696 * buffer area.
4697 * Return value :
4698 * void .
4699*/
4700
4701static void s2io_ethtool_gregs(struct net_device *dev,
4702 struct ethtool_regs *regs, void *space)
4703{
4704 int i;
4705 u64 reg;
4706 u8 *reg_space = (u8 *) space;
4707 nic_t *sp = dev->priv;
4708
4709 regs->len = XENA_REG_SPACE;
4710 regs->version = sp->pdev->subsystem_device;
4711
4712 for (i = 0; i < regs->len; i += 8) {
4713 reg = readq(sp->bar0 + i);
4714 memcpy((reg_space + i), &reg, 8);
4715 }
4716}
4717
4718/**
4719 * s2io_phy_id - timer function that alternates adapter LED.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004720 * @data : address of the private member of the device structure, which
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 * is a pointer to the s2io_nic structure, provided as an u32.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004722 * Description: This is actually the timer function that alternates the
4723 * adapter LED bit of the adapter control bit to set/reset every time on
4724 * invocation. The timer is set for 1/2 a second, hence tha NIC blinks
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 * once every second.
4726*/
4727static void s2io_phy_id(unsigned long data)
4728{
4729 nic_t *sp = (nic_t *) data;
4730 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4731 u64 val64 = 0;
4732 u16 subid;
4733
4734 subid = sp->pdev->subsystem_device;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004735 if ((sp->device_type == XFRAME_II_DEVICE) ||
4736 ((subid & 0xFF) >= 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 val64 = readq(&bar0->gpio_control);
4738 val64 ^= GPIO_CTRL_GPIO_0;
4739 writeq(val64, &bar0->gpio_control);
4740 } else {
4741 val64 = readq(&bar0->adapter_control);
4742 val64 ^= ADAPTER_LED_ON;
4743 writeq(val64, &bar0->adapter_control);
4744 }
4745
4746 mod_timer(&sp->id_timer, jiffies + HZ / 2);
4747}
4748
4749/**
4750 * s2io_ethtool_idnic - To physically identify the nic on the system.
4751 * @sp : private member of the device structure, which is a pointer to the
4752 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004753 * @id : pointer to the structure with identification parameters given by
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 * ethtool.
4755 * Description: Used to physically identify the NIC on the system.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004756 * The Link LED will blink for a time specified by the user for
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 * identification.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004758 * NOTE: The Link has to be Up to be able to blink the LED. Hence
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 * identification is possible only if it's link is up.
4760 * Return value:
4761 * int , returns 0 on success
4762 */
4763
4764static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
4765{
4766 u64 val64 = 0, last_gpio_ctrl_val;
4767 nic_t *sp = dev->priv;
4768 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4769 u16 subid;
4770
4771 subid = sp->pdev->subsystem_device;
4772 last_gpio_ctrl_val = readq(&bar0->gpio_control);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004773 if ((sp->device_type == XFRAME_I_DEVICE) &&
4774 ((subid & 0xFF) < 0x07)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 val64 = readq(&bar0->adapter_control);
4776 if (!(val64 & ADAPTER_CNTL_EN)) {
4777 printk(KERN_ERR
4778 "Adapter Link down, cannot blink LED\n");
4779 return -EFAULT;
4780 }
4781 }
4782 if (sp->id_timer.function == NULL) {
4783 init_timer(&sp->id_timer);
4784 sp->id_timer.function = s2io_phy_id;
4785 sp->id_timer.data = (unsigned long) sp;
4786 }
4787 mod_timer(&sp->id_timer, jiffies);
4788 if (data)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004789 msleep_interruptible(data * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 else
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004791 msleep_interruptible(MAX_FLICKER_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 del_timer_sync(&sp->id_timer);
4793
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07004794 if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 writeq(last_gpio_ctrl_val, &bar0->gpio_control);
4796 last_gpio_ctrl_val = readq(&bar0->gpio_control);
4797 }
4798
4799 return 0;
4800}
4801
4802/**
4803 * s2io_ethtool_getpause_data -Pause frame frame generation and reception.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004804 * @sp : private member of the device structure, which is a pointer to the
4805 * s2io_nic structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 * @ep : pointer to the structure with pause parameters given by ethtool.
4807 * Description:
4808 * Returns the Pause frame generation and reception capability of the NIC.
4809 * Return value:
4810 * void
4811 */
4812static void s2io_ethtool_getpause_data(struct net_device *dev,
4813 struct ethtool_pauseparam *ep)
4814{
4815 u64 val64;
4816 nic_t *sp = dev->priv;
4817 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4818
4819 val64 = readq(&bar0->rmac_pause_cfg);
4820 if (val64 & RMAC_PAUSE_GEN_ENABLE)
4821 ep->tx_pause = TRUE;
4822 if (val64 & RMAC_PAUSE_RX_ENABLE)
4823 ep->rx_pause = TRUE;
4824 ep->autoneg = FALSE;
4825}
4826
4827/**
4828 * s2io_ethtool_setpause_data - set/reset pause frame generation.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004829 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 * s2io_nic structure.
4831 * @ep : pointer to the structure with pause parameters given by ethtool.
4832 * Description:
4833 * It can be used to set or reset Pause frame generation or reception
4834 * support of the NIC.
4835 * Return value:
4836 * int, returns 0 on Success
4837 */
4838
4839static int s2io_ethtool_setpause_data(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004840 struct ethtool_pauseparam *ep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841{
4842 u64 val64;
4843 nic_t *sp = dev->priv;
4844 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4845
4846 val64 = readq(&bar0->rmac_pause_cfg);
4847 if (ep->tx_pause)
4848 val64 |= RMAC_PAUSE_GEN_ENABLE;
4849 else
4850 val64 &= ~RMAC_PAUSE_GEN_ENABLE;
4851 if (ep->rx_pause)
4852 val64 |= RMAC_PAUSE_RX_ENABLE;
4853 else
4854 val64 &= ~RMAC_PAUSE_RX_ENABLE;
4855 writeq(val64, &bar0->rmac_pause_cfg);
4856 return 0;
4857}
4858
4859/**
4860 * read_eeprom - reads 4 bytes of data from user given offset.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004861 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 * s2io_nic structure.
4863 * @off : offset at which the data must be written
4864 * @data : Its an output parameter where the data read at the given
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004865 * offset is stored.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004867 * Will read 4 bytes of data from the user given offset and return the
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 * read data.
4869 * NOTE: Will allow to read only part of the EEPROM visible through the
4870 * I2C bus.
4871 * Return value:
4872 * -1 on failure and 0 on success.
4873 */
4874
4875#define S2IO_DEV_ID 5
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004876static int read_eeprom(nic_t * sp, int off, u64 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877{
4878 int ret = -1;
4879 u32 exit_cnt = 0;
4880 u64 val64;
4881 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4882
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004883 if (sp->device_type == XFRAME_I_DEVICE) {
4884 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4885 I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ |
4886 I2C_CONTROL_CNTL_START;
4887 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004889 while (exit_cnt < 5) {
4890 val64 = readq(&bar0->i2c_control);
4891 if (I2C_CONTROL_CNTL_END(val64)) {
4892 *data = I2C_CONTROL_GET_DATA(val64);
4893 ret = 0;
4894 break;
4895 }
4896 msleep(50);
4897 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 }
4900
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004901 if (sp->device_type == XFRAME_II_DEVICE) {
4902 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
4903 SPI_CONTROL_BYTECNT(0x3) |
4904 SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off);
4905 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4906 val64 |= SPI_CONTROL_REQ;
4907 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4908 while (exit_cnt < 5) {
4909 val64 = readq(&bar0->spi_control);
4910 if (val64 & SPI_CONTROL_NACK) {
4911 ret = 1;
4912 break;
4913 } else if (val64 & SPI_CONTROL_DONE) {
4914 *data = readq(&bar0->spi_data);
4915 *data &= 0xffffff;
4916 ret = 0;
4917 break;
4918 }
4919 msleep(50);
4920 exit_cnt++;
4921 }
4922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923 return ret;
4924}
4925
4926/**
4927 * write_eeprom - actually writes the relevant part of the data value.
4928 * @sp : private member of the device structure, which is a pointer to the
4929 * s2io_nic structure.
4930 * @off : offset at which the data must be written
4931 * @data : The data that is to be written
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07004932 * @cnt : Number of bytes of the data that are actually to be written into
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933 * the Eeprom. (max of 3)
4934 * Description:
4935 * Actually writes the relevant part of the data value into the Eeprom
4936 * through the I2C bus.
4937 * Return value:
4938 * 0 on success, -1 on failure.
4939 */
4940
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004941static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942{
4943 int exit_cnt = 0, ret = -1;
4944 u64 val64;
4945 XENA_dev_config_t __iomem *bar0 = sp->bar0;
4946
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004947 if (sp->device_type == XFRAME_I_DEVICE) {
4948 val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
4949 I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) |
4950 I2C_CONTROL_CNTL_START;
4951 SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004953 while (exit_cnt < 5) {
4954 val64 = readq(&bar0->i2c_control);
4955 if (I2C_CONTROL_CNTL_END(val64)) {
4956 if (!(val64 & I2C_CONTROL_NACK))
4957 ret = 0;
4958 break;
4959 }
4960 msleep(50);
4961 exit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963 }
4964
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07004965 if (sp->device_type == XFRAME_II_DEVICE) {
4966 int write_cnt = (cnt == 8) ? 0 : cnt;
4967 writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data);
4968
4969 val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
4970 SPI_CONTROL_BYTECNT(write_cnt) |
4971 SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off);
4972 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4973 val64 |= SPI_CONTROL_REQ;
4974 SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
4975 while (exit_cnt < 5) {
4976 val64 = readq(&bar0->spi_control);
4977 if (val64 & SPI_CONTROL_NACK) {
4978 ret = 1;
4979 break;
4980 } else if (val64 & SPI_CONTROL_DONE) {
4981 ret = 0;
4982 break;
4983 }
4984 msleep(50);
4985 exit_cnt++;
4986 }
4987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 return ret;
4989}
Ananda Raju9dc737a2006-04-21 19:05:41 -04004990static void s2io_vpd_read(nic_t *nic)
4991{
4992 u8 vpd_data[256],data;
4993 int i=0, cnt, fail = 0;
4994 int vpd_addr = 0x80;
4995
4996 if (nic->device_type == XFRAME_II_DEVICE) {
4997 strcpy(nic->product_name, "Xframe II 10GbE network adapter");
4998 vpd_addr = 0x80;
4999 }
5000 else {
5001 strcpy(nic->product_name, "Xframe I 10GbE network adapter");
5002 vpd_addr = 0x50;
5003 }
5004
5005 for (i = 0; i < 256; i +=4 ) {
5006 pci_write_config_byte(nic->pdev, (vpd_addr + 2), i);
5007 pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data);
5008 pci_write_config_byte(nic->pdev, (vpd_addr + 3), 0);
5009 for (cnt = 0; cnt <5; cnt++) {
5010 msleep(2);
5011 pci_read_config_byte(nic->pdev, (vpd_addr + 3), &data);
5012 if (data == 0x80)
5013 break;
5014 }
5015 if (cnt >= 5) {
5016 DBG_PRINT(ERR_DBG, "Read of VPD data failed\n");
5017 fail = 1;
5018 break;
5019 }
5020 pci_read_config_dword(nic->pdev, (vpd_addr + 4),
5021 (u32 *)&vpd_data[i]);
5022 }
5023 if ((!fail) && (vpd_data[1] < VPD_PRODUCT_NAME_LEN)) {
5024 memset(nic->product_name, 0, vpd_data[1]);
5025 memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
5026 }
5027}
5028
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029/**
5030 * s2io_ethtool_geeprom - reads the value stored in the Eeprom.
5031 * @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 -07005032 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 * containing all relevant information.
5034 * @data_buf : user defined value to be written into Eeprom.
5035 * Description: Reads the values stored in the Eeprom at given offset
5036 * for a given length. Stores these values int the input argument data
5037 * buffer 'data_buf' and returns these to the caller (ethtool.)
5038 * Return value:
5039 * int 0 on success
5040 */
5041
5042static int s2io_ethtool_geeprom(struct net_device *dev,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005043 struct ethtool_eeprom *eeprom, u8 * data_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044{
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005045 u32 i, valid;
5046 u64 data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 nic_t *sp = dev->priv;
5048
5049 eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
5050
5051 if ((eeprom->offset + eeprom->len) > (XENA_EEPROM_SPACE))
5052 eeprom->len = XENA_EEPROM_SPACE - eeprom->offset;
5053
5054 for (i = 0; i < eeprom->len; i += 4) {
5055 if (read_eeprom(sp, (eeprom->offset + i), &data)) {
5056 DBG_PRINT(ERR_DBG, "Read of EEPROM failed\n");
5057 return -EFAULT;
5058 }
5059 valid = INV(data);
5060 memcpy((data_buf + i), &valid, 4);
5061 }
5062 return 0;
5063}
5064
5065/**
5066 * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom
5067 * @sp : private member of the device structure, which is a pointer to the
5068 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005069 * @eeprom : pointer to the user level structure provided by ethtool,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 * containing all relevant information.
5071 * @data_buf ; user defined value to be written into Eeprom.
5072 * Description:
5073 * Tries to write the user provided value in the Eeprom, at the offset
5074 * given by the user.
5075 * Return value:
5076 * 0 on success, -EFAULT on failure.
5077 */
5078
5079static int s2io_ethtool_seeprom(struct net_device *dev,
5080 struct ethtool_eeprom *eeprom,
5081 u8 * data_buf)
5082{
5083 int len = eeprom->len, cnt = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005084 u64 valid = 0, data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085 nic_t *sp = dev->priv;
5086
5087 if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
5088 DBG_PRINT(ERR_DBG,
5089 "ETHTOOL_WRITE_EEPROM Err: Magic value ");
5090 DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n",
5091 eeprom->magic);
5092 return -EFAULT;
5093 }
5094
5095 while (len) {
5096 data = (u32) data_buf[cnt] & 0x000000FF;
5097 if (data) {
5098 valid = (u32) (data << 24);
5099 } else
5100 valid = data;
5101
5102 if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) {
5103 DBG_PRINT(ERR_DBG,
5104 "ETHTOOL_WRITE_EEPROM Err: Cannot ");
5105 DBG_PRINT(ERR_DBG,
5106 "write into the specified offset\n");
5107 return -EFAULT;
5108 }
5109 cnt++;
5110 len--;
5111 }
5112
5113 return 0;
5114}
5115
5116/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005117 * s2io_register_test - reads and writes into all clock domains.
5118 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 * s2io_nic structure.
5120 * @data : variable that returns the result of each of the test conducted b
5121 * by the driver.
5122 * Description:
5123 * Read and write into all clock domains. The NIC has 3 clock domains,
5124 * see that registers in all the three regions are accessible.
5125 * Return value:
5126 * 0 on success.
5127 */
5128
5129static int s2io_register_test(nic_t * sp, uint64_t * data)
5130{
5131 XENA_dev_config_t __iomem *bar0 = sp->bar0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005132 u64 val64 = 0, exp_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 int fail = 0;
5134
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005135 val64 = readq(&bar0->pif_rd_swapper_fb);
5136 if (val64 != 0x123456789abcdefULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 fail = 1;
5138 DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n");
5139 }
5140
5141 val64 = readq(&bar0->rmac_pause_cfg);
5142 if (val64 != 0xc000ffff00000000ULL) {
5143 fail = 1;
5144 DBG_PRINT(INFO_DBG, "Read Test level 2 fails\n");
5145 }
5146
5147 val64 = readq(&bar0->rx_queue_cfg);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005148 if (sp->device_type == XFRAME_II_DEVICE)
5149 exp_val = 0x0404040404040404ULL;
5150 else
5151 exp_val = 0x0808080808080808ULL;
5152 if (val64 != exp_val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 fail = 1;
5154 DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n");
5155 }
5156
5157 val64 = readq(&bar0->xgxs_efifo_cfg);
5158 if (val64 != 0x000000001923141EULL) {
5159 fail = 1;
5160 DBG_PRINT(INFO_DBG, "Read Test level 4 fails\n");
5161 }
5162
5163 val64 = 0x5A5A5A5A5A5A5A5AULL;
5164 writeq(val64, &bar0->xmsi_data);
5165 val64 = readq(&bar0->xmsi_data);
5166 if (val64 != 0x5A5A5A5A5A5A5A5AULL) {
5167 fail = 1;
5168 DBG_PRINT(ERR_DBG, "Write Test level 1 fails\n");
5169 }
5170
5171 val64 = 0xA5A5A5A5A5A5A5A5ULL;
5172 writeq(val64, &bar0->xmsi_data);
5173 val64 = readq(&bar0->xmsi_data);
5174 if (val64 != 0xA5A5A5A5A5A5A5A5ULL) {
5175 fail = 1;
5176 DBG_PRINT(ERR_DBG, "Write Test level 2 fails\n");
5177 }
5178
5179 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005180 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181}
5182
5183/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005184 * s2io_eeprom_test - to verify that EEprom in the xena can be programmed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 * @sp : private member of the device structure, which is a pointer to the
5186 * s2io_nic structure.
5187 * @data:variable that returns the result of each of the test conducted by
5188 * the driver.
5189 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005190 * Verify that EEPROM in the xena can be programmed using I2C_CONTROL
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 * register.
5192 * Return value:
5193 * 0 on success.
5194 */
5195
5196static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
5197{
5198 int fail = 0;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005199 u64 ret_data, org_4F0, org_7F0;
5200 u8 saved_4F0 = 0, saved_7F0 = 0;
5201 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202
5203 /* Test Write Error at offset 0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005204 /* Note that SPI interface allows write access to all areas
5205 * of EEPROM. Hence doing all negative testing only for Xframe I.
5206 */
5207 if (sp->device_type == XFRAME_I_DEVICE)
5208 if (!write_eeprom(sp, 0, 0, 3))
5209 fail = 1;
5210
5211 /* Save current values at offsets 0x4F0 and 0x7F0 */
5212 if (!read_eeprom(sp, 0x4F0, &org_4F0))
5213 saved_4F0 = 1;
5214 if (!read_eeprom(sp, 0x7F0, &org_7F0))
5215 saved_7F0 = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216
5217 /* Test Write at offset 4f0 */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005218 if (write_eeprom(sp, 0x4F0, 0x012345, 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 fail = 1;
5220 if (read_eeprom(sp, 0x4F0, &ret_data))
5221 fail = 1;
5222
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005223 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005224 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. "
5225 "Data written %llx Data read %llx\n",
5226 dev->name, (unsigned long long)0x12345,
5227 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230
5231 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005232 write_eeprom(sp, 0x4F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233
5234 /* Test Write Request Error at offset 0x7c */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005235 if (sp->device_type == XFRAME_I_DEVICE)
5236 if (!write_eeprom(sp, 0x07C, 0, 3))
5237 fail = 1;
5238
5239 /* Test Write Request at offset 0x7f0 */
5240 if (write_eeprom(sp, 0x7F0, 0x012345, 3))
5241 fail = 1;
5242 if (read_eeprom(sp, 0x7F0, &ret_data))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 fail = 1;
5244
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005245 if (ret_data != 0x012345) {
Andrew Morton26b76252005-12-14 19:25:23 -08005246 DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. "
5247 "Data written %llx Data read %llx\n",
5248 dev->name, (unsigned long long)0x12345,
5249 (unsigned long long)ret_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 fail = 1;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252
5253 /* Reset the EEPROM data go FFFF */
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005254 write_eeprom(sp, 0x7F0, 0xFFFFFF, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005256 if (sp->device_type == XFRAME_I_DEVICE) {
5257 /* Test Write Error at offset 0x80 */
5258 if (!write_eeprom(sp, 0x080, 0, 3))
5259 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005261 /* Test Write Error at offset 0xfc */
5262 if (!write_eeprom(sp, 0x0FC, 0, 3))
5263 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005265 /* Test Write Error at offset 0x100 */
5266 if (!write_eeprom(sp, 0x100, 0, 3))
5267 fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005269 /* Test Write Error at offset 4ec */
5270 if (!write_eeprom(sp, 0x4EC, 0, 3))
5271 fail = 1;
5272 }
5273
5274 /* Restore values at offsets 0x4F0 and 0x7F0 */
5275 if (saved_4F0)
5276 write_eeprom(sp, 0x4F0, org_4F0, 3);
5277 if (saved_7F0)
5278 write_eeprom(sp, 0x7F0, org_7F0, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279
5280 *data = fail;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005281 return fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282}
5283
5284/**
5285 * s2io_bist_test - invokes the MemBist test of the card .
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005286 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005288 * @data:variable that returns the result of each of the test conducted by
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 * the driver.
5290 * Description:
5291 * This invokes the MemBist test of the card. We give around
5292 * 2 secs time for the Test to complete. If it's still not complete
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005293 * within this peiod, we consider that the test failed.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294 * Return value:
5295 * 0 on success and -1 on failure.
5296 */
5297
5298static int s2io_bist_test(nic_t * sp, uint64_t * data)
5299{
5300 u8 bist = 0;
5301 int cnt = 0, ret = -1;
5302
5303 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5304 bist |= PCI_BIST_START;
5305 pci_write_config_word(sp->pdev, PCI_BIST, bist);
5306
5307 while (cnt < 20) {
5308 pci_read_config_byte(sp->pdev, PCI_BIST, &bist);
5309 if (!(bist & PCI_BIST_START)) {
5310 *data = (bist & PCI_BIST_CODE_MASK);
5311 ret = 0;
5312 break;
5313 }
5314 msleep(100);
5315 cnt++;
5316 }
5317
5318 return ret;
5319}
5320
5321/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005322 * s2io-link_test - verifies the link state of the nic
5323 * @sp ; private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 * s2io_nic structure.
5325 * @data: variable that returns the result of each of the test conducted by
5326 * the driver.
5327 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005328 * The function verifies the link state of the NIC and updates the input
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 * argument 'data' appropriately.
5330 * Return value:
5331 * 0 on success.
5332 */
5333
5334static int s2io_link_test(nic_t * sp, uint64_t * data)
5335{
5336 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5337 u64 val64;
5338
5339 val64 = readq(&bar0->adapter_status);
Ananda Rajuc92ca042006-04-21 19:18:03 -04005340 if(!(LINK_IS_UP(val64)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 *data = 1;
Ananda Rajuc92ca042006-04-21 19:18:03 -04005342 else
5343 *data = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344
5345 return 0;
5346}
5347
5348/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005349 * s2io_rldram_test - offline test for access to the RldRam chip on the NIC
5350 * @sp - private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 * s2io_nic structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005352 * @data - variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353 * conducted by the driver.
5354 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005355 * This is one of the offline test that tests the read and write
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 * access to the RldRam chip on the NIC.
5357 * Return value:
5358 * 0 on success.
5359 */
5360
5361static int s2io_rldram_test(nic_t * sp, uint64_t * data)
5362{
5363 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5364 u64 val64;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005365 int cnt, iteration = 0, test_fail = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366
5367 val64 = readq(&bar0->adapter_control);
5368 val64 &= ~ADAPTER_ECC_EN;
5369 writeq(val64, &bar0->adapter_control);
5370
5371 val64 = readq(&bar0->mc_rldram_test_ctrl);
5372 val64 |= MC_RLDRAM_TEST_MODE;
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005373 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374
5375 val64 = readq(&bar0->mc_rldram_mrs);
5376 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE;
5377 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5378
5379 val64 |= MC_RLDRAM_MRS_ENABLE;
5380 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
5381
5382 while (iteration < 2) {
5383 val64 = 0x55555555aaaa0000ULL;
5384 if (iteration == 1) {
5385 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5386 }
5387 writeq(val64, &bar0->mc_rldram_test_d0);
5388
5389 val64 = 0xaaaa5a5555550000ULL;
5390 if (iteration == 1) {
5391 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5392 }
5393 writeq(val64, &bar0->mc_rldram_test_d1);
5394
5395 val64 = 0x55aaaaaaaa5a0000ULL;
5396 if (iteration == 1) {
5397 val64 ^= 0xFFFFFFFFFFFF0000ULL;
5398 }
5399 writeq(val64, &bar0->mc_rldram_test_d2);
5400
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005401 val64 = (u64) (0x0000003ffffe0100ULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 writeq(val64, &bar0->mc_rldram_test_add);
5403
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005404 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE |
5405 MC_RLDRAM_TEST_GO;
5406 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407
5408 for (cnt = 0; cnt < 5; cnt++) {
5409 val64 = readq(&bar0->mc_rldram_test_ctrl);
5410 if (val64 & MC_RLDRAM_TEST_DONE)
5411 break;
5412 msleep(200);
5413 }
5414
5415 if (cnt == 5)
5416 break;
5417
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005418 val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO;
5419 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420
5421 for (cnt = 0; cnt < 5; cnt++) {
5422 val64 = readq(&bar0->mc_rldram_test_ctrl);
5423 if (val64 & MC_RLDRAM_TEST_DONE)
5424 break;
5425 msleep(500);
5426 }
5427
5428 if (cnt == 5)
5429 break;
5430
5431 val64 = readq(&bar0->mc_rldram_test_ctrl);
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005432 if (!(val64 & MC_RLDRAM_TEST_PASS))
5433 test_fail = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434
5435 iteration++;
5436 }
5437
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005438 *data = test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439
ravinandan.arakali@neterion.comad4ebed2005-10-17 18:26:20 -07005440 /* Bring the adapter out of test mode */
5441 SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF);
5442
5443 return test_fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444}
5445
5446/**
5447 * s2io_ethtool_test - conducts 6 tsets to determine the health of card.
5448 * @sp : private member of the device structure, which is a pointer to the
5449 * s2io_nic structure.
5450 * @ethtest : pointer to a ethtool command specific structure that will be
5451 * returned to the user.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005452 * @data : variable that returns the result of each of the test
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 * conducted by the driver.
5454 * Description:
5455 * This function conducts 6 tests ( 4 offline and 2 online) to determine
5456 * the health of the card.
5457 * Return value:
5458 * void
5459 */
5460
5461static void s2io_ethtool_test(struct net_device *dev,
5462 struct ethtool_test *ethtest,
5463 uint64_t * data)
5464{
5465 nic_t *sp = dev->priv;
5466 int orig_state = netif_running(sp->dev);
5467
5468 if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
5469 /* Offline Tests. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005470 if (orig_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471 s2io_close(sp->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472
5473 if (s2io_register_test(sp, &data[0]))
5474 ethtest->flags |= ETH_TEST_FL_FAILED;
5475
5476 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477
5478 if (s2io_rldram_test(sp, &data[3]))
5479 ethtest->flags |= ETH_TEST_FL_FAILED;
5480
5481 s2io_reset(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482
5483 if (s2io_eeprom_test(sp, &data[1]))
5484 ethtest->flags |= ETH_TEST_FL_FAILED;
5485
5486 if (s2io_bist_test(sp, &data[4]))
5487 ethtest->flags |= ETH_TEST_FL_FAILED;
5488
5489 if (orig_state)
5490 s2io_open(sp->dev);
5491
5492 data[2] = 0;
5493 } else {
5494 /* Online Tests. */
5495 if (!orig_state) {
5496 DBG_PRINT(ERR_DBG,
5497 "%s: is not up, cannot run test\n",
5498 dev->name);
5499 data[0] = -1;
5500 data[1] = -1;
5501 data[2] = -1;
5502 data[3] = -1;
5503 data[4] = -1;
5504 }
5505
5506 if (s2io_link_test(sp, &data[2]))
5507 ethtest->flags |= ETH_TEST_FL_FAILED;
5508
5509 data[0] = 0;
5510 data[1] = 0;
5511 data[3] = 0;
5512 data[4] = 0;
5513 }
5514}
5515
5516static void s2io_get_ethtool_stats(struct net_device *dev,
5517 struct ethtool_stats *estats,
5518 u64 * tmp_stats)
5519{
5520 int i = 0;
5521 nic_t *sp = dev->priv;
5522 StatInfo_t *stat_info = sp->mac_control.stats_info;
5523
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005524 s2io_updt_stats(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005525 tmp_stats[i++] =
5526 (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32 |
5527 le32_to_cpu(stat_info->tmac_frms);
5528 tmp_stats[i++] =
5529 (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 |
5530 le32_to_cpu(stat_info->tmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005532 tmp_stats[i++] =
5533 (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 |
5534 le32_to_cpu(stat_info->tmac_mcst_frms);
5535 tmp_stats[i++] =
5536 (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 |
5537 le32_to_cpu(stat_info->tmac_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005539 tmp_stats[i++] =
5540 (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 |
5541 le32_to_cpu(stat_info->tmac_ttl_octets);
5542 tmp_stats[i++] =
5543 (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 |
5544 le32_to_cpu(stat_info->tmac_ucst_frms);
5545 tmp_stats[i++] =
5546 (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 |
5547 le32_to_cpu(stat_info->tmac_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005548 tmp_stats[i++] =
5549 (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 |
5550 le32_to_cpu(stat_info->tmac_any_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005551 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005553 tmp_stats[i++] =
5554 (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 |
5555 le32_to_cpu(stat_info->tmac_vld_ip);
5556 tmp_stats[i++] =
5557 (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 |
5558 le32_to_cpu(stat_info->tmac_drop_ip);
5559 tmp_stats[i++] =
5560 (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 |
5561 le32_to_cpu(stat_info->tmac_icmp);
5562 tmp_stats[i++] =
5563 (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 |
5564 le32_to_cpu(stat_info->tmac_rst_tcp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005566 tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 |
5567 le32_to_cpu(stat_info->tmac_udp);
5568 tmp_stats[i++] =
5569 (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 |
5570 le32_to_cpu(stat_info->rmac_vld_frms);
5571 tmp_stats[i++] =
5572 (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 |
5573 le32_to_cpu(stat_info->rmac_data_octets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms);
5575 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005576 tmp_stats[i++] =
5577 (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 |
5578 le32_to_cpu(stat_info->rmac_vld_mcst_frms);
5579 tmp_stats[i++] =
5580 (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 |
5581 le32_to_cpu(stat_info->rmac_vld_bcst_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005583 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_out_rng_len_err_frms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms);
5585 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005586 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_unsup_ctrl_frms);
5587 tmp_stats[i++] =
5588 (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 |
5589 le32_to_cpu(stat_info->rmac_ttl_octets);
5590 tmp_stats[i++] =
5591 (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow)
5592 << 32 | le32_to_cpu(stat_info->rmac_accepted_ucst_frms);
5593 tmp_stats[i++] =
5594 (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow)
5595 << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005596 tmp_stats[i++] =
5597 (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 |
5598 le32_to_cpu(stat_info->rmac_discarded_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005599 tmp_stats[i++] =
5600 (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow)
5601 << 32 | le32_to_cpu(stat_info->rmac_drop_events);
5602 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets);
5603 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005604 tmp_stats[i++] =
5605 (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 |
5606 le32_to_cpu(stat_info->rmac_usized_frms);
5607 tmp_stats[i++] =
5608 (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 |
5609 le32_to_cpu(stat_info->rmac_osized_frms);
5610 tmp_stats[i++] =
5611 (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 |
5612 le32_to_cpu(stat_info->rmac_frag_frms);
5613 tmp_stats[i++] =
5614 (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 |
5615 le32_to_cpu(stat_info->rmac_jabber_frms);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005616 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_64_frms);
5617 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms);
5618 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms);
5619 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms);
5620 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms);
5621 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms);
5622 tmp_stats[i++] =
5623 (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005624 le32_to_cpu(stat_info->rmac_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets);
5626 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005627 tmp_stats[i++] =
5628 (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005629 le32_to_cpu(stat_info->rmac_drop_ip);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005630 tmp_stats[i++] =
5631 (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005632 le32_to_cpu(stat_info->rmac_icmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005634 tmp_stats[i++] =
5635 (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 |
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005636 le32_to_cpu(stat_info->rmac_udp);
5637 tmp_stats[i++] =
5638 (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 |
5639 le32_to_cpu(stat_info->rmac_err_drp_udp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005640 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_err_sym);
5641 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0);
5642 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1);
5643 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2);
5644 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3);
5645 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4);
5646 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5);
5647 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6);
5648 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7);
5649 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0);
5650 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1);
5651 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2);
5652 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3);
5653 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4);
5654 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5);
5655 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6);
5656 tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005657 tmp_stats[i++] =
5658 (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 |
5659 le32_to_cpu(stat_info->rmac_pause_cnt);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005660 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_data_err_cnt);
5661 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005662 tmp_stats[i++] =
5663 (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 |
5664 le32_to_cpu(stat_info->rmac_accepted_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp);
Ananda Rajubd1034f2006-04-21 19:20:22 -04005666 tmp_stats[i++] = le32_to_cpu(stat_info->rd_req_cnt);
5667 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_cnt);
5668 tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_rtry_cnt);
5669 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_cnt);
5670 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_rd_ack_cnt);
5671 tmp_stats[i++] = le32_to_cpu(stat_info->wr_req_cnt);
5672 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_cnt);
5673 tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_rtry_cnt);
5674 tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_cnt);
5675 tmp_stats[i++] = le32_to_cpu(stat_info->wr_disc_cnt);
5676 tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_wr_ack_cnt);
5677 tmp_stats[i++] = le32_to_cpu(stat_info->txp_wr_cnt);
5678 tmp_stats[i++] = le32_to_cpu(stat_info->txd_rd_cnt);
5679 tmp_stats[i++] = le32_to_cpu(stat_info->txd_wr_cnt);
5680 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_rd_cnt);
5681 tmp_stats[i++] = le32_to_cpu(stat_info->rxd_wr_cnt);
5682 tmp_stats[i++] = le32_to_cpu(stat_info->txf_rd_cnt);
5683 tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt);
5684 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms);
5685 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms);
5686 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_8192_max_frms);
5687 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms);
5688 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms);
5689 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms);
5690 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms);
5691 tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms);
5692 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard);
5693 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard);
5694 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard);
5695 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard);
5696 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard);
5697 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard);
5698 tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard);
5699 tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07005700 tmp_stats[i++] = 0;
5701 tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
5702 tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
Ananda Rajubd1034f2006-04-21 19:20:22 -04005703 tmp_stats[i++] = stat_info->sw_stat.parity_err_cnt;
5704 tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt;
5705 tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt;
5706 tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt;
5707 tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt;
5708 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high;
5709 tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low;
5710 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high;
5711 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_low;
5712 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_high;
5713 tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_low;
5714 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_high;
5715 tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_low;
5716 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_high;
5717 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_low;
5718 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_high;
5719 tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_low;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05005720 tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt;
5721 tmp_stats[i++] = stat_info->sw_stat.sending_both;
5722 tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts;
5723 tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts;
Andrew Mortonfe931392006-02-03 01:45:12 -08005724 if (stat_info->sw_stat.num_aggregations) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04005725 u64 tmp = stat_info->sw_stat.sum_avg_pkts_aggregated;
5726 int count = 0;
5727 /*
5728 * Since 64-bit divide does not work on all platforms,
5729 * do repeated subtraction.
5730 */
5731 while (tmp >= stat_info->sw_stat.num_aggregations) {
5732 tmp -= stat_info->sw_stat.num_aggregations;
5733 count++;
5734 }
5735 tmp_stats[i++] = count;
Andrew Mortonfe931392006-02-03 01:45:12 -08005736 }
Ananda Rajubd1034f2006-04-21 19:20:22 -04005737 else
5738 tmp_stats[i++] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739}
5740
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005741static int s2io_ethtool_get_regs_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742{
5743 return (XENA_REG_SPACE);
5744}
5745
5746
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005747static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748{
5749 nic_t *sp = dev->priv;
5750
5751 return (sp->rx_csum);
5752}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005753
5754static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755{
5756 nic_t *sp = dev->priv;
5757
5758 if (data)
5759 sp->rx_csum = 1;
5760 else
5761 sp->rx_csum = 0;
5762
5763 return 0;
5764}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005765
5766static int s2io_get_eeprom_len(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767{
5768 return (XENA_EEPROM_SPACE);
5769}
5770
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005771static int s2io_ethtool_self_test_count(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772{
5773 return (S2IO_TEST_LEN);
5774}
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005775
5776static void s2io_ethtool_get_strings(struct net_device *dev,
5777 u32 stringset, u8 * data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778{
5779 switch (stringset) {
5780 case ETH_SS_TEST:
5781 memcpy(data, s2io_gstrings, S2IO_STRINGS_LEN);
5782 break;
5783 case ETH_SS_STATS:
5784 memcpy(data, &ethtool_stats_keys,
5785 sizeof(ethtool_stats_keys));
5786 }
5787}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788static int s2io_ethtool_get_stats_count(struct net_device *dev)
5789{
5790 return (S2IO_STAT_LEN);
5791}
5792
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005793static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794{
5795 if (data)
5796 dev->features |= NETIF_F_IP_CSUM;
5797 else
5798 dev->features &= ~NETIF_F_IP_CSUM;
5799
5800 return 0;
5801}
5802
5803
5804static struct ethtool_ops netdev_ethtool_ops = {
5805 .get_settings = s2io_ethtool_gset,
5806 .set_settings = s2io_ethtool_sset,
5807 .get_drvinfo = s2io_ethtool_gdrvinfo,
5808 .get_regs_len = s2io_ethtool_get_regs_len,
5809 .get_regs = s2io_ethtool_gregs,
5810 .get_link = ethtool_op_get_link,
5811 .get_eeprom_len = s2io_get_eeprom_len,
5812 .get_eeprom = s2io_ethtool_geeprom,
5813 .set_eeprom = s2io_ethtool_seeprom,
5814 .get_pauseparam = s2io_ethtool_getpause_data,
5815 .set_pauseparam = s2io_ethtool_setpause_data,
5816 .get_rx_csum = s2io_ethtool_get_rx_csum,
5817 .set_rx_csum = s2io_ethtool_set_rx_csum,
5818 .get_tx_csum = ethtool_op_get_tx_csum,
5819 .set_tx_csum = s2io_ethtool_op_set_tx_csum,
5820 .get_sg = ethtool_op_get_sg,
5821 .set_sg = ethtool_op_set_sg,
5822#ifdef NETIF_F_TSO
5823 .get_tso = ethtool_op_get_tso,
5824 .set_tso = ethtool_op_set_tso,
5825#endif
Ananda Rajufed5ecc2005-11-14 15:25:08 -05005826 .get_ufo = ethtool_op_get_ufo,
5827 .set_ufo = ethtool_op_set_ufo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828 .self_test_count = s2io_ethtool_self_test_count,
5829 .self_test = s2io_ethtool_test,
5830 .get_strings = s2io_ethtool_get_strings,
5831 .phys_id = s2io_ethtool_idnic,
5832 .get_stats_count = s2io_ethtool_get_stats_count,
5833 .get_ethtool_stats = s2io_get_ethtool_stats
5834};
5835
5836/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005837 * s2io_ioctl - Entry point for the Ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838 * @dev : Device pointer.
5839 * @ifr : An IOCTL specefic structure, that can contain a pointer to
5840 * a proprietary structure used to pass information to the driver.
5841 * @cmd : This is used to distinguish between the different commands that
5842 * can be passed to the IOCTL functions.
5843 * Description:
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005844 * Currently there are no special functionality supported in IOCTL, hence
5845 * function always return EOPNOTSUPPORTED
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846 */
5847
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005848static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005849{
5850 return -EOPNOTSUPP;
5851}
5852
5853/**
5854 * s2io_change_mtu - entry point to change MTU size for the device.
5855 * @dev : device pointer.
5856 * @new_mtu : the new MTU size for the device.
5857 * Description: A driver entry point to change MTU size for the device.
5858 * Before changing the MTU the device must be stopped.
5859 * Return value:
5860 * 0 on success and an appropriate (-)ve integer as defined in errno.h
5861 * file on failure.
5862 */
5863
Adrian Bunkac1f60d2005-11-06 01:46:47 +01005864static int s2io_change_mtu(struct net_device *dev, int new_mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865{
5866 nic_t *sp = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867
5868 if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
5869 DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
5870 dev->name);
5871 return -EPERM;
5872 }
5873
Linus Torvalds1da177e2005-04-16 15:20:36 -07005874 dev->mtu = new_mtu;
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005875 if (netif_running(dev)) {
Ananda Rajuc92ca042006-04-21 19:18:03 -04005876 s2io_card_down(sp, 0);
raghavendra.koushik@neterion.comd8892c62005-08-03 12:33:12 -07005877 netif_stop_queue(dev);
5878 if (s2io_card_up(sp)) {
5879 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
5880 __FUNCTION__);
5881 }
5882 if (netif_queue_stopped(dev))
5883 netif_wake_queue(dev);
5884 } else { /* Device is down */
5885 XENA_dev_config_t __iomem *bar0 = sp->bar0;
5886 u64 val64 = new_mtu;
5887
5888 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
5889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890
5891 return 0;
5892}
5893
5894/**
5895 * s2io_tasklet - Bottom half of the ISR.
5896 * @dev_adr : address of the device structure in dma_addr_t format.
5897 * Description:
5898 * This is the tasklet or the bottom half of the ISR. This is
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005899 * an extension of the ISR which is scheduled by the scheduler to be run
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900 * 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 -07005901 * be pushed into the tasklet. For now the tasklet is used only to
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 * replenish the Rx buffers in the Rx buffer descriptors.
5903 * Return value:
5904 * void.
5905 */
5906
5907static void s2io_tasklet(unsigned long dev_addr)
5908{
5909 struct net_device *dev = (struct net_device *) dev_addr;
5910 nic_t *sp = dev->priv;
5911 int i, ret;
5912 mac_info_t *mac_control;
5913 struct config_param *config;
5914
5915 mac_control = &sp->mac_control;
5916 config = &sp->config;
5917
5918 if (!TASKLET_IN_USE) {
5919 for (i = 0; i < config->rx_ring_num; i++) {
5920 ret = fill_rx_buffers(sp, i);
5921 if (ret == -ENOMEM) {
5922 DBG_PRINT(ERR_DBG, "%s: Out of ",
5923 dev->name);
5924 DBG_PRINT(ERR_DBG, "memory in tasklet\n");
5925 break;
5926 } else if (ret == -EFILL) {
5927 DBG_PRINT(ERR_DBG,
5928 "%s: Rx Ring %d is full\n",
5929 dev->name, i);
5930 break;
5931 }
5932 }
5933 clear_bit(0, (&sp->tasklet_status));
5934 }
5935}
5936
5937/**
5938 * s2io_set_link - Set the LInk status
5939 * @data: long pointer to device private structue
5940 * Description: Sets the link status for the adapter
5941 */
5942
5943static void s2io_set_link(unsigned long data)
5944{
5945 nic_t *nic = (nic_t *) data;
5946 struct net_device *dev = nic->dev;
5947 XENA_dev_config_t __iomem *bar0 = nic->bar0;
5948 register u64 val64;
5949 u16 subid;
5950
5951 if (test_and_set_bit(0, &(nic->link_state))) {
5952 /* The card is being reset, no point doing anything */
5953 return;
5954 }
5955
5956 subid = nic->pdev->subsystem_device;
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07005957 if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
5958 /*
5959 * Allow a small delay for the NICs self initiated
5960 * cleanup to complete.
5961 */
5962 msleep(100);
5963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964
5965 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07005966 if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967 if (LINK_IS_UP(val64)) {
5968 val64 = readq(&bar0->adapter_control);
5969 val64 |= ADAPTER_CNTL_EN;
5970 writeq(val64, &bar0->adapter_control);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005971 if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
5972 subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973 val64 = readq(&bar0->gpio_control);
5974 val64 |= GPIO_CTRL_GPIO_0;
5975 writeq(val64, &bar0->gpio_control);
5976 val64 = readq(&bar0->gpio_control);
5977 } else {
5978 val64 |= ADAPTER_LED_ON;
5979 writeq(val64, &bar0->adapter_control);
5980 }
raghavendra.koushik@neterion.coma371a072005-08-03 12:38:59 -07005981 if (s2io_link_fault_indication(nic) ==
5982 MAC_RMAC_ERR_TIMER) {
5983 val64 = readq(&bar0->adapter_status);
5984 if (!LINK_IS_UP(val64)) {
5985 DBG_PRINT(ERR_DBG, "%s:", dev->name);
5986 DBG_PRINT(ERR_DBG, " Link down");
5987 DBG_PRINT(ERR_DBG, "after ");
5988 DBG_PRINT(ERR_DBG, "enabling ");
5989 DBG_PRINT(ERR_DBG, "device \n");
5990 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991 }
5992 if (nic->device_enabled_once == FALSE) {
5993 nic->device_enabled_once = TRUE;
5994 }
5995 s2io_link(nic, LINK_UP);
5996 } else {
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07005997 if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
5998 subid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999 val64 = readq(&bar0->gpio_control);
6000 val64 &= ~GPIO_CTRL_GPIO_0;
6001 writeq(val64, &bar0->gpio_control);
6002 val64 = readq(&bar0->gpio_control);
6003 }
6004 s2io_link(nic, LINK_DOWN);
6005 }
6006 } else { /* NIC is not Quiescent. */
6007 DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
6008 DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
6009 netif_stop_queue(dev);
6010 }
6011 clear_bit(0, &(nic->link_state));
6012}
6013
Ananda Rajuc92ca042006-04-21 19:18:03 -04006014static void s2io_card_down(nic_t * sp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006015{
6016 int cnt = 0;
6017 XENA_dev_config_t __iomem *bar0 = sp->bar0;
6018 unsigned long flags;
6019 register u64 val64 = 0;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006020 struct net_device *dev = sp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07006022 del_timer_sync(&sp->alarm_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023 /* If s2io_set_link task is executing, wait till it completes. */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006024 while (test_and_set_bit(0, &(sp->link_state))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025 msleep(50);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006026 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027 atomic_set(&sp->card_state, CARD_DOWN);
6028
6029 /* disable Tx and Rx traffic on the NIC */
6030 stop_nic(sp);
Ananda Rajuc92ca042006-04-21 19:18:03 -04006031 if (flag) {
6032 if (sp->intr_type == MSI_X) {
6033 int i;
6034 u16 msi_control;
6035
6036 for (i=1; (sp->s2io_entries[i].in_use ==
6037 MSIX_REGISTERED_SUCCESS); i++) {
6038 int vector = sp->entries[i].vector;
6039 void *arg = sp->s2io_entries[i].arg;
6040
6041 free_irq(vector, arg);
6042 }
6043 pci_read_config_word(sp->pdev, 0x42, &msi_control);
6044 msi_control &= 0xFFFE; /* Disable MSI */
6045 pci_write_config_word(sp->pdev, 0x42, msi_control);
6046 pci_disable_msix(sp->pdev);
6047 } else {
6048 free_irq(sp->pdev->irq, dev);
6049 if (sp->intr_type == MSI)
6050 pci_disable_msi(sp->pdev);
6051 }
6052 }
6053 /* Waiting till all Interrupt handlers are complete */
6054 cnt = 0;
6055 do {
6056 msleep(10);
6057 if (!atomic_read(&sp->isr_cnt))
6058 break;
6059 cnt++;
6060 } while(cnt < 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006061
6062 /* Kill tasklet. */
6063 tasklet_kill(&sp->task);
6064
6065 /* Check if the device is Quiescent and then Reset the NIC */
6066 do {
6067 val64 = readq(&bar0->adapter_status);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006068 if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069 break;
6070 }
6071
6072 msleep(50);
6073 cnt++;
6074 if (cnt == 10) {
6075 DBG_PRINT(ERR_DBG,
6076 "s2io_close:Device not Quiescent ");
6077 DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n",
6078 (unsigned long long) val64);
6079 break;
6080 }
6081 } while (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082 s2io_reset(sp);
6083
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006084 spin_lock_irqsave(&sp->tx_lock, flags);
6085 /* Free all Tx buffers */
6086 free_tx_buffers(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087 spin_unlock_irqrestore(&sp->tx_lock, flags);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006088
6089 /* Free all Rx buffers */
6090 spin_lock_irqsave(&sp->rx_lock, flags);
6091 free_rx_buffers(sp);
6092 spin_unlock_irqrestore(&sp->rx_lock, flags);
6093
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094 clear_bit(0, &(sp->link_state));
6095}
6096
6097static int s2io_card_up(nic_t * sp)
6098{
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006099 int i, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100 mac_info_t *mac_control;
6101 struct config_param *config;
6102 struct net_device *dev = (struct net_device *) sp->dev;
6103
6104 /* Initialize the H/W I/O registers */
6105 if (init_nic(sp) != 0) {
6106 DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
6107 dev->name);
6108 return -ENODEV;
6109 }
6110
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006111 if (sp->intr_type == MSI)
6112 ret = s2io_enable_msi(sp);
6113 else if (sp->intr_type == MSI_X)
6114 ret = s2io_enable_msi_x(sp);
6115 if (ret) {
6116 DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
6117 sp->intr_type = INTA;
6118 }
6119
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006120 /*
6121 * Initializing the Rx buffers. For now we are considering only 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07006122 * Rx ring and initializing buffers into 30 Rx blocks
6123 */
6124 mac_control = &sp->mac_control;
6125 config = &sp->config;
6126
6127 for (i = 0; i < config->rx_ring_num; i++) {
6128 if ((ret = fill_rx_buffers(sp, i))) {
6129 DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
6130 dev->name);
6131 s2io_reset(sp);
6132 free_rx_buffers(sp);
6133 return -ENOMEM;
6134 }
6135 DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
6136 atomic_read(&sp->rx_bufs_left[i]));
6137 }
6138
6139 /* Setting its receive mode */
6140 s2io_set_multicast(dev);
6141
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006142 if (sp->lro) {
6143 /* Initialize max aggregatable pkts based on MTU */
6144 sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
6145 /* Check if we can use(if specified) user provided value */
6146 if (lro_max_pkts < sp->lro_max_aggr_per_sess)
6147 sp->lro_max_aggr_per_sess = lro_max_pkts;
6148 }
6149
Linus Torvalds1da177e2005-04-16 15:20:36 -07006150 /* Enable tasklet for the device */
6151 tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
6152
6153 /* Enable Rx Traffic and interrupts on the NIC */
6154 if (start_nic(sp)) {
6155 DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
6156 tasklet_kill(&sp->task);
6157 s2io_reset(sp);
6158 free_irq(dev->irq, dev);
6159 free_rx_buffers(sp);
6160 return -ENODEV;
6161 }
6162
raghavendra.koushik@neterion.com25fff882005-08-03 12:34:11 -07006163 S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
6164
Linus Torvalds1da177e2005-04-16 15:20:36 -07006165 atomic_set(&sp->card_state, CARD_UP);
6166 return 0;
6167}
6168
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006169/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006170 * s2io_restart_nic - Resets the NIC.
6171 * @data : long pointer to the device private structure
6172 * Description:
6173 * This function is scheduled to be run by the s2io_tx_watchdog
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006174 * function after 0.5 secs to reset the NIC. The idea is to reduce
Linus Torvalds1da177e2005-04-16 15:20:36 -07006175 * the run time of the watch dog routine which is run holding a
6176 * spin lock.
6177 */
6178
6179static void s2io_restart_nic(unsigned long data)
6180{
6181 struct net_device *dev = (struct net_device *) data;
6182 nic_t *sp = dev->priv;
6183
Ananda Rajuc92ca042006-04-21 19:18:03 -04006184 s2io_card_down(sp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185 if (s2io_card_up(sp)) {
6186 DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
6187 dev->name);
6188 }
6189 netif_wake_queue(dev);
6190 DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
6191 dev->name);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006192
Linus Torvalds1da177e2005-04-16 15:20:36 -07006193}
6194
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006195/**
6196 * s2io_tx_watchdog - Watchdog for transmit side.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006197 * @dev : Pointer to net device structure
6198 * Description:
6199 * This function is triggered if the Tx Queue is stopped
6200 * for a pre-defined amount of time when the Interface is still up.
6201 * If the Interface is jammed in such a situation, the hardware is
6202 * reset (by s2io_close) and restarted again (by s2io_open) to
6203 * overcome any problem that might have been caused in the hardware.
6204 * Return value:
6205 * void
6206 */
6207
6208static void s2io_tx_watchdog(struct net_device *dev)
6209{
6210 nic_t *sp = dev->priv;
6211
6212 if (netif_carrier_ok(dev)) {
6213 schedule_work(&sp->rst_timer_task);
Ananda Rajubd1034f2006-04-21 19:20:22 -04006214 sp->mac_control.stats_info->sw_stat.soft_reset_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006215 }
6216}
6217
6218/**
6219 * rx_osm_handler - To perform some OS related operations on SKB.
6220 * @sp: private member of the device structure,pointer to s2io_nic structure.
6221 * @skb : the socket buffer pointer.
6222 * @len : length of the packet
6223 * @cksum : FCS checksum of the frame.
6224 * @ring_no : the ring from which this RxD was extracted.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006225 * Description:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226 * This function is called by the Tx interrupt serivce routine to perform
6227 * some OS related operations on the SKB before passing it to the upper
6228 * layers. It mainly checks if the checksum is OK, if so adds it to the
6229 * SKBs cksum variable, increments the Rx packet count and passes the SKB
6230 * to the upper layer. If the checksum is wrong, it increments the Rx
6231 * packet error count, frees the SKB and returns error.
6232 * Return value:
6233 * SUCCESS on success and -1 on failure.
6234 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006235static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006236{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006237 nic_t *sp = ring_data->nic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238 struct net_device *dev = (struct net_device *) sp->dev;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006239 struct sk_buff *skb = (struct sk_buff *)
6240 ((unsigned long) rxdp->Host_Control);
6241 int ring_no = ring_data->ring_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242 u16 l3_csum, l4_csum;
Ananda Raju863c11a2006-04-21 19:03:13 -04006243 unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006244 lro_t *lro;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006245
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006246 skb->dev = dev;
Ananda Rajuc92ca042006-04-21 19:18:03 -04006247
Ananda Raju863c11a2006-04-21 19:03:13 -04006248 if (err) {
Ananda Rajubd1034f2006-04-21 19:20:22 -04006249 /* Check for parity error */
6250 if (err & 0x1) {
6251 sp->mac_control.stats_info->sw_stat.parity_err_cnt++;
6252 }
6253
Ananda Raju863c11a2006-04-21 19:03:13 -04006254 /*
6255 * Drop the packet if bad transfer code. Exception being
6256 * 0x5, which could be due to unsupported IPv6 extension header.
6257 * In this case, we let stack handle the packet.
6258 * Note that in this case, since checksum will be incorrect,
6259 * stack will validate the same.
6260 */
6261 if (err && ((err >> 48) != 0x5)) {
6262 DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
6263 dev->name, err);
6264 sp->stats.rx_crc_errors++;
6265 dev_kfree_skb(skb);
6266 atomic_dec(&sp->rx_bufs_left[ring_no]);
6267 rxdp->Host_Control = 0;
6268 return 0;
6269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006272 /* Updating statistics */
6273 rxdp->Host_Control = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 sp->rx_pkt_count++;
6275 sp->stats.rx_packets++;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006276 if (sp->rxd_mode == RXD_MODE_1) {
6277 int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006278
Ananda Rajuda6971d2005-10-31 16:55:31 -05006279 sp->stats.rx_bytes += len;
6280 skb_put(skb, len);
6281
6282 } else if (sp->rxd_mode >= RXD_MODE_3A) {
6283 int get_block = ring_data->rx_curr_get_info.block_index;
6284 int get_off = ring_data->rx_curr_get_info.offset;
6285 int buf0_len = RXD_GET_BUFFER0_SIZE_3(rxdp->Control_2);
6286 int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
6287 unsigned char *buff = skb_push(skb, buf0_len);
6288
6289 buffAdd_t *ba = &ring_data->ba[get_block][get_off];
6290 sp->stats.rx_bytes += buf0_len + buf2_len;
6291 memcpy(buff, ba->ba_0, buf0_len);
6292
6293 if (sp->rxd_mode == RXD_MODE_3A) {
6294 int buf1_len = RXD_GET_BUFFER1_SIZE_3(rxdp->Control_2);
6295
6296 skb_put(skb, buf1_len);
6297 skb->len += buf2_len;
6298 skb->data_len += buf2_len;
6299 skb->truesize += buf2_len;
6300 skb_put(skb_shinfo(skb)->frag_list, buf2_len);
6301 sp->stats.rx_bytes += buf1_len;
6302
6303 } else
6304 skb_put(skb, buf2_len);
6305 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006306
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006307 if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
6308 (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006309 (sp->rx_csum)) {
6310 l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
6311 l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
6312 if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) {
6313 /*
6314 * NIC verifies if the Checksum of the received
6315 * frame is Ok or not and accordingly returns
6316 * a flag in the RxD.
6317 */
6318 skb->ip_summed = CHECKSUM_UNNECESSARY;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006319 if (sp->lro) {
6320 u32 tcp_len;
6321 u8 *tcp;
6322 int ret = 0;
6323
6324 ret = s2io_club_tcp_session(skb->data, &tcp,
6325 &tcp_len, &lro, rxdp, sp);
6326 switch (ret) {
6327 case 3: /* Begin anew */
6328 lro->parent = skb;
6329 goto aggregate;
6330 case 1: /* Aggregate */
6331 {
6332 lro_append_pkt(sp, lro,
6333 skb, tcp_len);
6334 goto aggregate;
6335 }
6336 case 4: /* Flush session */
6337 {
6338 lro_append_pkt(sp, lro,
6339 skb, tcp_len);
6340 queue_rx_frame(lro->parent);
6341 clear_lro_session(lro);
6342 sp->mac_control.stats_info->
6343 sw_stat.flush_max_pkts++;
6344 goto aggregate;
6345 }
6346 case 2: /* Flush both */
6347 lro->parent->data_len =
6348 lro->frags_len;
6349 sp->mac_control.stats_info->
6350 sw_stat.sending_both++;
6351 queue_rx_frame(lro->parent);
6352 clear_lro_session(lro);
6353 goto send_up;
6354 case 0: /* sessions exceeded */
Ananda Rajuc92ca042006-04-21 19:18:03 -04006355 case -1: /* non-TCP or not
6356 * L2 aggregatable
6357 */
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006358 case 5: /*
6359 * First pkt in session not
6360 * L3/L4 aggregatable
6361 */
6362 break;
6363 default:
6364 DBG_PRINT(ERR_DBG,
6365 "%s: Samadhana!!\n",
6366 __FUNCTION__);
6367 BUG();
6368 }
6369 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006370 } else {
6371 /*
6372 * Packet with erroneous checksum, let the
6373 * upper layers deal with it.
6374 */
6375 skb->ip_summed = CHECKSUM_NONE;
6376 }
6377 } else {
6378 skb->ip_summed = CHECKSUM_NONE;
6379 }
6380
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006381 if (!sp->lro) {
6382 skb->protocol = eth_type_trans(skb, dev);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006383#ifdef CONFIG_S2IO_NAPI
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006384 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
6385 /* Queueing the vlan frame to the upper layer */
6386 vlan_hwaccel_receive_skb(skb, sp->vlgrp,
6387 RXD_GET_VLAN_TAG(rxdp->Control_2));
6388 } else {
6389 netif_receive_skb(skb);
6390 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006391#else
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006392 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
6393 /* Queueing the vlan frame to the upper layer */
6394 vlan_hwaccel_rx(skb, sp->vlgrp,
6395 RXD_GET_VLAN_TAG(rxdp->Control_2));
6396 } else {
6397 netif_rx(skb);
6398 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006399#endif
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006400 } else {
6401send_up:
6402 queue_rx_frame(skb);
6403 }
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006404 dev->last_rx = jiffies;
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006405aggregate:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406 atomic_dec(&sp->rx_bufs_left[ring_no]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006407 return SUCCESS;
6408}
6409
6410/**
6411 * s2io_link - stops/starts the Tx queue.
6412 * @sp : private member of the device structure, which is a pointer to the
6413 * s2io_nic structure.
6414 * @link : inidicates whether link is UP/DOWN.
6415 * Description:
6416 * This function stops/starts the Tx queue depending on whether the link
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006417 * status of the NIC is is down or up. This is called by the Alarm
6418 * interrupt handler whenever a link change interrupt comes up.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006419 * Return value:
6420 * void.
6421 */
6422
Adrian Bunk26df54b2006-01-14 03:09:40 +01006423static void s2io_link(nic_t * sp, int link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006424{
6425 struct net_device *dev = (struct net_device *) sp->dev;
6426
6427 if (link != sp->last_link_state) {
6428 if (link == LINK_DOWN) {
6429 DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
6430 netif_carrier_off(dev);
6431 } else {
6432 DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
6433 netif_carrier_on(dev);
6434 }
6435 }
6436 sp->last_link_state = link;
6437}
6438
6439/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006440 * get_xena_rev_id - to identify revision ID of xena.
6441 * @pdev : PCI Dev structure
6442 * Description:
6443 * Function to identify the Revision ID of xena.
6444 * Return value:
6445 * returns the revision ID of the device.
6446 */
6447
Adrian Bunk26df54b2006-01-14 03:09:40 +01006448static int get_xena_rev_id(struct pci_dev *pdev)
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006449{
6450 u8 id = 0;
6451 int ret;
6452 ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id);
6453 return id;
6454}
6455
6456/**
6457 * s2io_init_pci -Initialization of PCI and PCI-X configuration registers .
6458 * @sp : private member of the device structure, which is a pointer to the
Linus Torvalds1da177e2005-04-16 15:20:36 -07006459 * s2io_nic structure.
6460 * Description:
6461 * This function initializes a few of the PCI and PCI-X configuration registers
6462 * with recommended values.
6463 * Return value:
6464 * void
6465 */
6466
6467static void s2io_init_pci(nic_t * sp)
6468{
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006469 u16 pci_cmd = 0, pcix_cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006470
6471 /* Enable Data Parity Error Recovery in PCI-X command register. */
6472 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006473 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006474 pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006475 (pcix_cmd | 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006476 pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006477 &(pcix_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006478
6479 /* Set the PErr Response bit in PCI command register. */
6480 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
6481 pci_write_config_word(sp->pdev, PCI_COMMAND,
6482 (pci_cmd | PCI_COMMAND_PARITY));
6483 pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006484}
6485
6486MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
6487MODULE_LICENSE("GPL");
John Linville6c1792f2005-10-04 07:51:45 -04006488MODULE_VERSION(DRV_VERSION);
6489
Linus Torvalds1da177e2005-04-16 15:20:36 -07006490module_param(tx_fifo_num, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491module_param(rx_ring_num, int, 0);
Ananda Rajuda6971d2005-10-31 16:55:31 -05006492module_param(rx_ring_mode, int, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006493module_param_array(tx_fifo_len, uint, NULL, 0);
6494module_param_array(rx_ring_sz, uint, NULL, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006495module_param_array(rts_frm_len, uint, NULL, 0);
raghavendra.koushik@neterion.com5e25b9d2005-08-03 12:27:09 -07006496module_param(use_continuous_tx_intrs, int, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006497module_param(rmac_pause_time, int, 0);
6498module_param(mc_pause_threshold_q0q3, int, 0);
6499module_param(mc_pause_threshold_q4q7, int, 0);
6500module_param(shared_splits, int, 0);
6501module_param(tmac_util_period, int, 0);
6502module_param(rmac_util_period, int, 0);
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07006503module_param(bimodal, bool, 0);
Ananda Rajuda6971d2005-10-31 16:55:31 -05006504module_param(l3l4hdr_size, int , 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006505#ifndef CONFIG_S2IO_NAPI
6506module_param(indicate_max_pkts, int, 0);
6507#endif
raghavendra.koushik@neterion.com303bcb42005-08-03 12:41:38 -07006508module_param(rxsync_frequency, int, 0);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006509module_param(intr_type, int, 0);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006510module_param(lro, int, 0);
6511module_param(lro_max_pkts, int, 0);
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006512
Ananda Raju9dc737a2006-04-21 19:05:41 -04006513static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
6514{
6515 if ( tx_fifo_num > 8) {
6516 DBG_PRINT(ERR_DBG, "s2io: Requested number of Tx fifos not "
6517 "supported\n");
6518 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Tx fifos\n");
6519 tx_fifo_num = 8;
6520 }
6521 if ( rx_ring_num > 8) {
6522 DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
6523 "supported\n");
6524 DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
6525 rx_ring_num = 8;
6526 }
6527#ifdef CONFIG_S2IO_NAPI
6528 if (*dev_intr_type != INTA) {
6529 DBG_PRINT(ERR_DBG, "s2io: NAPI cannot be enabled when "
6530 "MSI/MSI-X is enabled. Defaulting to INTA\n");
6531 *dev_intr_type = INTA;
6532 }
6533#endif
6534#ifndef CONFIG_PCI_MSI
6535 if (*dev_intr_type != INTA) {
6536 DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
6537 "MSI/MSI-X. Defaulting to INTA\n");
6538 *dev_intr_type = INTA;
6539 }
6540#else
6541 if (*dev_intr_type > MSI_X) {
6542 DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
6543 "Defaulting to INTA\n");
6544 *dev_intr_type = INTA;
6545 }
6546#endif
6547 if ((*dev_intr_type == MSI_X) &&
6548 ((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
6549 (pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
6550 DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. "
6551 "Defaulting to INTA\n");
6552 *dev_intr_type = INTA;
6553 }
6554 if (rx_ring_mode > 3) {
6555 DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
6556 DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
6557 rx_ring_mode = 3;
6558 }
6559 return SUCCESS;
6560}
6561
Linus Torvalds1da177e2005-04-16 15:20:36 -07006562/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006563 * s2io_init_nic - Initialization of the adapter .
Linus Torvalds1da177e2005-04-16 15:20:36 -07006564 * @pdev : structure containing the PCI related information of the device.
6565 * @pre: List of PCI devices supported by the driver listed in s2io_tbl.
6566 * Description:
6567 * The function initializes an adapter identified by the pci_dec structure.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006568 * All OS related initialization including memory and device structure and
6569 * initlaization of the device private variable is done. Also the swapper
6570 * control register is initialized to enable read and write into the I/O
Linus Torvalds1da177e2005-04-16 15:20:36 -07006571 * registers of the device.
6572 * Return value:
6573 * returns 0 on success and negative on failure.
6574 */
6575
6576static int __devinit
6577s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
6578{
6579 nic_t *sp;
6580 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006581 int i, j, ret;
6582 int dma_flag = FALSE;
6583 u32 mac_up, mac_down;
6584 u64 val64 = 0, tmp64 = 0;
6585 XENA_dev_config_t __iomem *bar0 = NULL;
6586 u16 subid;
6587 mac_info_t *mac_control;
6588 struct config_param *config;
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006589 int mode;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006590 u8 dev_intr_type = intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006591
Ananda Raju9dc737a2006-04-21 19:05:41 -04006592 if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
6593 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006594
6595 if ((ret = pci_enable_device(pdev))) {
6596 DBG_PRINT(ERR_DBG,
6597 "s2io_init_nic: pci_enable_device failed\n");
6598 return ret;
6599 }
6600
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006601 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006602 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
6603 dma_flag = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006604 if (pci_set_consistent_dma_mask
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006605 (pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006606 DBG_PRINT(ERR_DBG,
6607 "Unable to obtain 64bit DMA for \
6608 consistent allocations\n");
6609 pci_disable_device(pdev);
6610 return -ENOMEM;
6611 }
Domen Puncer1e7f0bd2005-06-26 18:22:14 -04006612 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006613 DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n");
6614 } else {
6615 pci_disable_device(pdev);
6616 return -ENOMEM;
6617 }
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006618 if (dev_intr_type != MSI_X) {
6619 if (pci_request_regions(pdev, s2io_driver_name)) {
6620 DBG_PRINT(ERR_DBG, "Request Regions failed\n"),
6621 pci_disable_device(pdev);
6622 return -ENODEV;
6623 }
6624 }
6625 else {
6626 if (!(request_mem_region(pci_resource_start(pdev, 0),
6627 pci_resource_len(pdev, 0), s2io_driver_name))) {
6628 DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n");
6629 pci_disable_device(pdev);
6630 return -ENODEV;
6631 }
6632 if (!(request_mem_region(pci_resource_start(pdev, 2),
6633 pci_resource_len(pdev, 2), s2io_driver_name))) {
6634 DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n");
6635 release_mem_region(pci_resource_start(pdev, 0),
6636 pci_resource_len(pdev, 0));
6637 pci_disable_device(pdev);
6638 return -ENODEV;
6639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006640 }
6641
6642 dev = alloc_etherdev(sizeof(nic_t));
6643 if (dev == NULL) {
6644 DBG_PRINT(ERR_DBG, "Device allocation failed\n");
6645 pci_disable_device(pdev);
6646 pci_release_regions(pdev);
6647 return -ENODEV;
6648 }
6649
6650 pci_set_master(pdev);
6651 pci_set_drvdata(pdev, dev);
6652 SET_MODULE_OWNER(dev);
6653 SET_NETDEV_DEV(dev, &pdev->dev);
6654
6655 /* Private member variable initialized to s2io NIC structure */
6656 sp = dev->priv;
6657 memset(sp, 0, sizeof(nic_t));
6658 sp->dev = dev;
6659 sp->pdev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006660 sp->high_dma_flag = dma_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006661 sp->device_enabled_once = FALSE;
Ananda Rajuda6971d2005-10-31 16:55:31 -05006662 if (rx_ring_mode == 1)
6663 sp->rxd_mode = RXD_MODE_1;
6664 if (rx_ring_mode == 2)
6665 sp->rxd_mode = RXD_MODE_3B;
6666 if (rx_ring_mode == 3)
6667 sp->rxd_mode = RXD_MODE_3A;
6668
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006669 sp->intr_type = dev_intr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006670
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006671 if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
6672 (pdev->device == PCI_DEVICE_ID_HERC_UNI))
6673 sp->device_type = XFRAME_II_DEVICE;
6674 else
6675 sp->device_type = XFRAME_I_DEVICE;
6676
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006677 sp->lro = lro;
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006678
Linus Torvalds1da177e2005-04-16 15:20:36 -07006679 /* Initialize some PCI/PCI-X fields of the NIC. */
6680 s2io_init_pci(sp);
6681
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006682 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006683 * Setting the device configuration parameters.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006684 * Most of these parameters can be specified by the user during
6685 * module insertion as they are module loadable parameters. If
6686 * these parameters are not not specified during load time, they
Linus Torvalds1da177e2005-04-16 15:20:36 -07006687 * are initialized with default values.
6688 */
6689 mac_control = &sp->mac_control;
6690 config = &sp->config;
6691
6692 /* Tx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006693 config->tx_fifo_num = tx_fifo_num;
6694 for (i = 0; i < MAX_TX_FIFOS; i++) {
6695 config->tx_cfg[i].fifo_len = tx_fifo_len[i];
6696 config->tx_cfg[i].fifo_priority = i;
6697 }
6698
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006699 /* mapping the QoS priority to the configured fifos */
6700 for (i = 0; i < MAX_TX_FIFOS; i++)
6701 config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i];
6702
Linus Torvalds1da177e2005-04-16 15:20:36 -07006703 config->tx_intr_type = TXD_INT_TYPE_UTILZ;
6704 for (i = 0; i < config->tx_fifo_num; i++) {
6705 config->tx_cfg[i].f_no_snoop =
6706 (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER);
6707 if (config->tx_cfg[i].fifo_len < 65) {
6708 config->tx_intr_type = TXD_INT_TYPE_PER_LIST;
6709 break;
6710 }
6711 }
Ananda Rajufed5ecc2005-11-14 15:25:08 -05006712 /* + 2 because one Txd for skb->data and one Txd for UFO */
6713 config->max_txds = MAX_SKB_FRAGS + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006714
6715 /* Rx side parameters. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006716 config->rx_ring_num = rx_ring_num;
6717 for (i = 0; i < MAX_RX_RINGS; i++) {
6718 config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
Ananda Rajuda6971d2005-10-31 16:55:31 -05006719 (rxd_count[sp->rxd_mode] + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006720 config->rx_cfg[i].ring_priority = i;
6721 }
6722
6723 for (i = 0; i < rx_ring_num; i++) {
6724 config->rx_cfg[i].ring_org = RING_ORG_BUFF1;
6725 config->rx_cfg[i].f_no_snoop =
6726 (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER);
6727 }
6728
6729 /* Setting Mac Control parameters */
6730 mac_control->rmac_pause_time = rmac_pause_time;
6731 mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3;
6732 mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
6733
6734
6735 /* Initialize Ring buffer parameters. */
6736 for (i = 0; i < config->rx_ring_num; i++)
6737 atomic_set(&sp->rx_bufs_left[i], 0);
6738
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006739 /* Initialize the number of ISRs currently running */
6740 atomic_set(&sp->isr_cnt, 0);
6741
Linus Torvalds1da177e2005-04-16 15:20:36 -07006742 /* initialize the shared memory used by the NIC and the host */
6743 if (init_shared_mem(sp)) {
6744 DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07006745 __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006746 ret = -ENOMEM;
6747 goto mem_alloc_failed;
6748 }
6749
6750 sp->bar0 = ioremap(pci_resource_start(pdev, 0),
6751 pci_resource_len(pdev, 0));
6752 if (!sp->bar0) {
6753 DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem1\n",
6754 dev->name);
6755 ret = -ENOMEM;
6756 goto bar0_remap_failed;
6757 }
6758
6759 sp->bar1 = ioremap(pci_resource_start(pdev, 2),
6760 pci_resource_len(pdev, 2));
6761 if (!sp->bar1) {
6762 DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem2\n",
6763 dev->name);
6764 ret = -ENOMEM;
6765 goto bar1_remap_failed;
6766 }
6767
6768 dev->irq = pdev->irq;
6769 dev->base_addr = (unsigned long) sp->bar0;
6770
6771 /* Initializing the BAR1 address as the start of the FIFO pointer. */
6772 for (j = 0; j < MAX_TX_FIFOS; j++) {
6773 mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *)
6774 (sp->bar1 + (j * 0x00020000));
6775 }
6776
6777 /* Driver entry points */
6778 dev->open = &s2io_open;
6779 dev->stop = &s2io_close;
6780 dev->hard_start_xmit = &s2io_xmit;
6781 dev->get_stats = &s2io_get_stats;
6782 dev->set_multicast_list = &s2io_set_multicast;
6783 dev->do_ioctl = &s2io_ioctl;
6784 dev->change_mtu = &s2io_change_mtu;
6785 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
raghavendra.koushik@neterion.combe3a6b02005-08-03 12:35:55 -07006786 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6787 dev->vlan_rx_register = s2io_vlan_rx_register;
6788 dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006789
Linus Torvalds1da177e2005-04-16 15:20:36 -07006790 /*
6791 * will use eth_mac_addr() for dev->set_mac_address
6792 * mac address will be set every time dev->open() is called
6793 */
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006794#if defined(CONFIG_S2IO_NAPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006795 dev->poll = s2io_poll;
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006796 dev->weight = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006797#endif
6798
6799 dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
6800 if (sp->high_dma_flag == TRUE)
6801 dev->features |= NETIF_F_HIGHDMA;
6802#ifdef NETIF_F_TSO
6803 dev->features |= NETIF_F_TSO;
6804#endif
Ananda Rajufed5ecc2005-11-14 15:25:08 -05006805 if (sp->device_type & XFRAME_II_DEVICE) {
6806 dev->features |= NETIF_F_UFO;
6807 dev->features |= NETIF_F_HW_CSUM;
6808 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006809
6810 dev->tx_timeout = &s2io_tx_watchdog;
6811 dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
6812 INIT_WORK(&sp->rst_timer_task,
6813 (void (*)(void *)) s2io_restart_nic, dev);
6814 INIT_WORK(&sp->set_link_task,
6815 (void (*)(void *)) s2io_set_link, sp);
6816
ravinandan.arakali@neterion.come960fc52005-08-12 10:15:59 -07006817 pci_save_state(sp->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006818
6819 /* Setting swapper control on the NIC, for proper reset operation */
6820 if (s2io_set_swapper(sp)) {
6821 DBG_PRINT(ERR_DBG, "%s:swapper settings are wrong\n",
6822 dev->name);
6823 ret = -EAGAIN;
6824 goto set_swap_failed;
6825 }
6826
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006827 /* Verify if the Herc works on the slot its placed into */
6828 if (sp->device_type & XFRAME_II_DEVICE) {
6829 mode = s2io_verify_pci_mode(sp);
6830 if (mode < 0) {
6831 DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__);
6832 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
6833 ret = -EBADSLT;
6834 goto set_swap_failed;
6835 }
6836 }
6837
6838 /* Not needed for Herc */
6839 if (sp->device_type & XFRAME_I_DEVICE) {
6840 /*
6841 * Fix for all "FFs" MAC address problems observed on
6842 * Alpha platforms
6843 */
6844 fix_mac_address(sp);
6845 s2io_reset(sp);
6846 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006847
6848 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006849 * MAC address initialization.
6850 * For now only one mac address will be read and used.
6851 */
6852 bar0 = sp->bar0;
6853 val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
6854 RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
6855 writeq(val64, &bar0->rmac_addr_cmd_mem);
Ananda Rajuc92ca042006-04-21 19:18:03 -04006856 wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
6857 RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006858 tmp64 = readq(&bar0->rmac_addr_data0_mem);
6859 mac_down = (u32) tmp64;
6860 mac_up = (u32) (tmp64 >> 32);
6861
6862 memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
6863
6864 sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up);
6865 sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8);
6866 sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16);
6867 sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_up >> 24);
6868 sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16);
6869 sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24);
6870
Linus Torvalds1da177e2005-04-16 15:20:36 -07006871 /* Set the factory defined MAC address initially */
6872 dev->addr_len = ETH_ALEN;
6873 memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
6874
6875 /*
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006876 * Initialize the tasklet status and link state flags
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006877 * and the card state parameter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006878 */
6879 atomic_set(&(sp->card_state), 0);
6880 sp->tasklet_status = 0;
6881 sp->link_state = 0;
6882
Linus Torvalds1da177e2005-04-16 15:20:36 -07006883 /* Initialize spinlocks */
6884 spin_lock_init(&sp->tx_lock);
6885#ifndef CONFIG_S2IO_NAPI
6886 spin_lock_init(&sp->put_lock);
6887#endif
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006888 spin_lock_init(&sp->rx_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006889
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006890 /*
6891 * SXE-002: Configure link and activity LED to init state
6892 * on driver load.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006893 */
6894 subid = sp->pdev->subsystem_device;
6895 if ((subid & 0xFF) >= 0x07) {
6896 val64 = readq(&bar0->gpio_control);
6897 val64 |= 0x0000800000000000ULL;
6898 writeq(val64, &bar0->gpio_control);
6899 val64 = 0x0411040400000000ULL;
6900 writeq(val64, (void __iomem *) bar0 + 0x2700);
6901 val64 = readq(&bar0->gpio_control);
6902 }
6903
6904 sp->rx_csum = 1; /* Rx chksum verify enabled by default */
6905
6906 if (register_netdev(dev)) {
6907 DBG_PRINT(ERR_DBG, "Device registration failed\n");
6908 ret = -ENODEV;
6909 goto register_failed;
6910 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04006911 s2io_vpd_read(sp);
6912 DBG_PRINT(ERR_DBG, "%s: Neterion %s",dev->name, sp->product_name);
6913 DBG_PRINT(ERR_DBG, "(rev %d), Driver version %s\n",
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006914 get_xena_rev_id(sp->pdev),
6915 s2io_driver_version);
Ananda Raju9dc737a2006-04-21 19:05:41 -04006916 DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n");
6917 DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
6918 "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006919 sp->def_mac_addr[0].mac_addr[0],
6920 sp->def_mac_addr[0].mac_addr[1],
6921 sp->def_mac_addr[0].mac_addr[2],
6922 sp->def_mac_addr[0].mac_addr[3],
6923 sp->def_mac_addr[0].mac_addr[4],
6924 sp->def_mac_addr[0].mac_addr[5]);
Ananda Raju9dc737a2006-04-21 19:05:41 -04006925 if (sp->device_type & XFRAME_II_DEVICE) {
raghavendra.koushik@neterion.com0b1f7eb2005-08-03 12:39:56 -07006926 mode = s2io_print_pci_mode(sp);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006927 if (mode < 0) {
Ananda Raju9dc737a2006-04-21 19:05:41 -04006928 DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006929 ret = -EBADSLT;
Ananda Raju9dc737a2006-04-21 19:05:41 -04006930 unregister_netdev(dev);
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006931 goto set_swap_failed;
6932 }
raghavendra.koushik@neterion.com541ae682005-08-03 12:36:55 -07006933 }
Ananda Raju9dc737a2006-04-21 19:05:41 -04006934 switch(sp->rxd_mode) {
6935 case RXD_MODE_1:
6936 DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n",
6937 dev->name);
6938 break;
6939 case RXD_MODE_3B:
6940 DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n",
6941 dev->name);
6942 break;
6943 case RXD_MODE_3A:
6944 DBG_PRINT(ERR_DBG, "%s: 3-Buffer receive mode enabled\n",
6945 dev->name);
6946 break;
6947 }
6948#ifdef CONFIG_S2IO_NAPI
6949 DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
6950#endif
6951 switch(sp->intr_type) {
6952 case INTA:
6953 DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
6954 break;
6955 case MSI:
6956 DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI\n", dev->name);
6957 break;
6958 case MSI_X:
6959 DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
6960 break;
6961 }
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006962 if (sp->lro)
6963 DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
Ananda Raju9dc737a2006-04-21 19:05:41 -04006964 dev->name);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05006965
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006966 /* Initialize device name */
Ananda Raju9dc737a2006-04-21 19:05:41 -04006967 sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
raghavendra.koushik@neterion.com7ba013a2005-08-03 12:29:20 -07006968
raghavendra.koushik@neterion.comb6e3f982005-08-03 12:38:01 -07006969 /* Initialize bimodal Interrupts */
6970 sp->config.bimodal = bimodal;
6971 if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) {
6972 sp->config.bimodal = 0;
6973 DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n",
6974 dev->name);
6975 }
6976
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07006977 /*
6978 * Make Link state as off at this point, when the Link change
6979 * interrupt comes the state will be automatically changed to
Linus Torvalds1da177e2005-04-16 15:20:36 -07006980 * the right state.
6981 */
6982 netif_carrier_off(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006983
6984 return 0;
6985
6986 register_failed:
6987 set_swap_failed:
6988 iounmap(sp->bar1);
6989 bar1_remap_failed:
6990 iounmap(sp->bar0);
6991 bar0_remap_failed:
6992 mem_alloc_failed:
6993 free_shared_mem(sp);
6994 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04006995 if (dev_intr_type != MSI_X)
6996 pci_release_regions(pdev);
6997 else {
6998 release_mem_region(pci_resource_start(pdev, 0),
6999 pci_resource_len(pdev, 0));
7000 release_mem_region(pci_resource_start(pdev, 2),
7001 pci_resource_len(pdev, 2));
7002 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007003 pci_set_drvdata(pdev, NULL);
7004 free_netdev(dev);
7005
7006 return ret;
7007}
7008
7009/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007010 * s2io_rem_nic - Free the PCI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07007011 * @pdev: structure containing the PCI related information of the device.
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007012 * Description: This function is called by the Pci subsystem to release a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007013 * PCI device and free up all resource held up by the device. This could
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007014 * be in response to a Hot plug event or when the driver is to be removed
Linus Torvalds1da177e2005-04-16 15:20:36 -07007015 * from memory.
7016 */
7017
7018static void __devexit s2io_rem_nic(struct pci_dev *pdev)
7019{
7020 struct net_device *dev =
7021 (struct net_device *) pci_get_drvdata(pdev);
7022 nic_t *sp;
7023
7024 if (dev == NULL) {
7025 DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
7026 return;
7027 }
7028
7029 sp = dev->priv;
7030 unregister_netdev(dev);
7031
7032 free_shared_mem(sp);
7033 iounmap(sp->bar0);
7034 iounmap(sp->bar1);
7035 pci_disable_device(pdev);
Ravinandan Arakalicc6e7c42005-10-04 06:41:24 -04007036 if (sp->intr_type != MSI_X)
7037 pci_release_regions(pdev);
7038 else {
7039 release_mem_region(pci_resource_start(pdev, 0),
7040 pci_resource_len(pdev, 0));
7041 release_mem_region(pci_resource_start(pdev, 2),
7042 pci_resource_len(pdev, 2));
7043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007044 pci_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007045 free_netdev(dev);
7046}
7047
7048/**
7049 * s2io_starter - Entry point for the driver
7050 * Description: This function is the entry point for the driver. It verifies
7051 * the module loadable parameters and initializes PCI configuration space.
7052 */
7053
7054int __init s2io_starter(void)
7055{
7056 return pci_module_init(&s2io_driver);
7057}
7058
7059/**
raghavendra.koushik@neterion.com20346722005-08-03 12:24:33 -07007060 * s2io_closer - Cleanup routine for the driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07007061 * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
7062 */
7063
Adrian Bunk26df54b2006-01-14 03:09:40 +01007064static void s2io_closer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007065{
7066 pci_unregister_driver(&s2io_driver);
7067 DBG_PRINT(INIT_DBG, "cleanup done\n");
7068}
7069
7070module_init(s2io_starter);
7071module_exit(s2io_closer);
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007072
7073static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
7074 struct tcphdr **tcp, RxD_t *rxdp)
7075{
7076 int ip_off;
7077 u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
7078
7079 if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) {
7080 DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n",
7081 __FUNCTION__);
7082 return -1;
7083 }
7084
7085 /* TODO:
7086 * By default the VLAN field in the MAC is stripped by the card, if this
7087 * feature is turned off in rx_pa_cfg register, then the ip_off field
7088 * has to be shifted by a further 2 bytes
7089 */
7090 switch (l2_type) {
7091 case 0: /* DIX type */
7092 case 4: /* DIX type with VLAN */
7093 ip_off = HEADER_ETHERNET_II_802_3_SIZE;
7094 break;
7095 /* LLC, SNAP etc are considered non-mergeable */
7096 default:
7097 return -1;
7098 }
7099
7100 *ip = (struct iphdr *)((u8 *)buffer + ip_off);
7101 ip_len = (u8)((*ip)->ihl);
7102 ip_len <<= 2;
7103 *tcp = (struct tcphdr *)((unsigned long)*ip + ip_len);
7104
7105 return 0;
7106}
7107
7108static int check_for_socket_match(lro_t *lro, struct iphdr *ip,
7109 struct tcphdr *tcp)
7110{
7111 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7112 if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) ||
7113 (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest))
7114 return -1;
7115 return 0;
7116}
7117
7118static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
7119{
7120 return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
7121}
7122
7123static void initiate_new_session(lro_t *lro, u8 *l2h,
7124 struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
7125{
7126 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7127 lro->l2h = l2h;
7128 lro->iph = ip;
7129 lro->tcph = tcp;
7130 lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq);
7131 lro->tcp_ack = ntohl(tcp->ack_seq);
7132 lro->sg_num = 1;
7133 lro->total_len = ntohs(ip->tot_len);
7134 lro->frags_len = 0;
7135 /*
7136 * check if we saw TCP timestamp. Other consistency checks have
7137 * already been done.
7138 */
7139 if (tcp->doff == 8) {
7140 u32 *ptr;
7141 ptr = (u32 *)(tcp+1);
7142 lro->saw_ts = 1;
7143 lro->cur_tsval = *(ptr+1);
7144 lro->cur_tsecr = *(ptr+2);
7145 }
7146 lro->in_use = 1;
7147}
7148
7149static void update_L3L4_header(nic_t *sp, lro_t *lro)
7150{
7151 struct iphdr *ip = lro->iph;
7152 struct tcphdr *tcp = lro->tcph;
7153 u16 nchk;
7154 StatInfo_t *statinfo = sp->mac_control.stats_info;
7155 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7156
7157 /* Update L3 header */
7158 ip->tot_len = htons(lro->total_len);
7159 ip->check = 0;
7160 nchk = ip_fast_csum((u8 *)lro->iph, ip->ihl);
7161 ip->check = nchk;
7162
7163 /* Update L4 header */
7164 tcp->ack_seq = lro->tcp_ack;
7165 tcp->window = lro->window;
7166
7167 /* Update tsecr field if this session has timestamps enabled */
7168 if (lro->saw_ts) {
7169 u32 *ptr = (u32 *)(tcp + 1);
7170 *(ptr+2) = lro->cur_tsecr;
7171 }
7172
7173 /* Update counters required for calculation of
7174 * average no. of packets aggregated.
7175 */
7176 statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num;
7177 statinfo->sw_stat.num_aggregations++;
7178}
7179
7180static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
7181 struct tcphdr *tcp, u32 l4_pyld)
7182{
7183 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7184 lro->total_len += l4_pyld;
7185 lro->frags_len += l4_pyld;
7186 lro->tcp_next_seq += l4_pyld;
7187 lro->sg_num++;
7188
7189 /* Update ack seq no. and window ad(from this pkt) in LRO object */
7190 lro->tcp_ack = tcp->ack_seq;
7191 lro->window = tcp->window;
7192
7193 if (lro->saw_ts) {
7194 u32 *ptr;
7195 /* Update tsecr and tsval from this packet */
7196 ptr = (u32 *) (tcp + 1);
7197 lro->cur_tsval = *(ptr + 1);
7198 lro->cur_tsecr = *(ptr + 2);
7199 }
7200}
7201
7202static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
7203 struct tcphdr *tcp, u32 tcp_pyld_len)
7204{
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007205 u8 *ptr;
7206
Andrew Morton79dc1902006-02-03 01:45:13 -08007207 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
7208
Ravinandan Arakali7d3d04392006-01-25 14:53:07 -05007209 if (!tcp_pyld_len) {
7210 /* Runt frame or a pure ack */
7211 return -1;
7212 }
7213
7214 if (ip->ihl != 5) /* IP has options */
7215 return -1;
7216
7217 if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin ||
7218 !tcp->ack) {
7219 /*
7220 * Currently recognize only the ack control word and
7221 * any other control field being set would result in
7222 * flushing the LRO session
7223 */
7224 return -1;
7225 }
7226
7227 /*
7228 * Allow only one TCP timestamp option. Don't aggregate if
7229 * any other options are detected.
7230 */
7231 if (tcp->doff != 5 && tcp->doff != 8)
7232 return -1;
7233
7234 if (tcp->doff == 8) {
7235 ptr = (u8 *)(tcp + 1);
7236 while (*ptr == TCPOPT_NOP)
7237 ptr++;
7238 if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP)
7239 return -1;
7240
7241 /* Ensure timestamp value increases monotonically */
7242 if (l_lro)
7243 if (l_lro->cur_tsval > *((u32 *)(ptr+2)))
7244 return -1;
7245
7246 /* timestamp echo reply should be non-zero */
7247 if (*((u32 *)(ptr+6)) == 0)
7248 return -1;
7249 }
7250
7251 return 0;
7252}
7253
7254static int
7255s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
7256 RxD_t *rxdp, nic_t *sp)
7257{
7258 struct iphdr *ip;
7259 struct tcphdr *tcph;
7260 int ret = 0, i;
7261
7262 if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp,
7263 rxdp))) {
7264 DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n",
7265 ip->saddr, ip->daddr);
7266 } else {
7267 return ret;
7268 }
7269
7270 tcph = (struct tcphdr *)*tcp;
7271 *tcp_len = get_l4_pyld_length(ip, tcph);
7272 for (i=0; i<MAX_LRO_SESSIONS; i++) {
7273 lro_t *l_lro = &sp->lro0_n[i];
7274 if (l_lro->in_use) {
7275 if (check_for_socket_match(l_lro, ip, tcph))
7276 continue;
7277 /* Sock pair matched */
7278 *lro = l_lro;
7279
7280 if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) {
7281 DBG_PRINT(INFO_DBG, "%s:Out of order. expected "
7282 "0x%x, actual 0x%x\n", __FUNCTION__,
7283 (*lro)->tcp_next_seq,
7284 ntohl(tcph->seq));
7285
7286 sp->mac_control.stats_info->
7287 sw_stat.outof_sequence_pkts++;
7288 ret = 2;
7289 break;
7290 }
7291
7292 if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len))
7293 ret = 1; /* Aggregate */
7294 else
7295 ret = 2; /* Flush both */
7296 break;
7297 }
7298 }
7299
7300 if (ret == 0) {
7301 /* Before searching for available LRO objects,
7302 * check if the pkt is L3/L4 aggregatable. If not
7303 * don't create new LRO session. Just send this
7304 * packet up.
7305 */
7306 if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) {
7307 return 5;
7308 }
7309
7310 for (i=0; i<MAX_LRO_SESSIONS; i++) {
7311 lro_t *l_lro = &sp->lro0_n[i];
7312 if (!(l_lro->in_use)) {
7313 *lro = l_lro;
7314 ret = 3; /* Begin anew */
7315 break;
7316 }
7317 }
7318 }
7319
7320 if (ret == 0) { /* sessions exceeded */
7321 DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n",
7322 __FUNCTION__);
7323 *lro = NULL;
7324 return ret;
7325 }
7326
7327 switch (ret) {
7328 case 3:
7329 initiate_new_session(*lro, buffer, ip, tcph, *tcp_len);
7330 break;
7331 case 2:
7332 update_L3L4_header(sp, *lro);
7333 break;
7334 case 1:
7335 aggregate_new_rx(*lro, ip, tcph, *tcp_len);
7336 if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) {
7337 update_L3L4_header(sp, *lro);
7338 ret = 4; /* Flush the LRO */
7339 }
7340 break;
7341 default:
7342 DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n",
7343 __FUNCTION__);
7344 break;
7345 }
7346
7347 return ret;
7348}
7349
7350static void clear_lro_session(lro_t *lro)
7351{
7352 static u16 lro_struct_size = sizeof(lro_t);
7353
7354 memset(lro, 0, lro_struct_size);
7355}
7356
7357static void queue_rx_frame(struct sk_buff *skb)
7358{
7359 struct net_device *dev = skb->dev;
7360
7361 skb->protocol = eth_type_trans(skb, dev);
7362#ifdef CONFIG_S2IO_NAPI
7363 netif_receive_skb(skb);
7364#else
7365 netif_rx(skb);
7366#endif
7367}
7368
7369static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
7370 u32 tcp_len)
7371{
7372 struct sk_buff *tmp, *first = lro->parent;
7373
7374 first->len += tcp_len;
7375 first->data_len = lro->frags_len;
7376 skb_pull(skb, (skb->len - tcp_len));
7377 if ((tmp = skb_shinfo(first)->frag_list)) {
7378 while (tmp->next)
7379 tmp = tmp->next;
7380 tmp->next = skb;
7381 }
7382 else
7383 skb_shinfo(first)->frag_list = skb;
7384 sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
7385 return;
7386}