* Possible values '1' for enable , '0' for disable.
* Default is '2' - which means disable in promisc mode
* and enable in non-promiscuous mode.
+ * multiq: This parameter used to enable/disable MULTIQUEUE support.
+ * Possible values '1' for enable and '0' for disable. Default is '0'
************************************************************************/
#include <linux/module.h>
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.26.10"
+#define DRV_VERSION "2.0.26.22"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
#define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \
ADAPTER_STATUS_RMAC_LOCAL_FAULT)))
-#define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status))
-#define PANIC 1
-#define LOW 2
-static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring)
-{
- struct mac_info *mac_control;
-
- mac_control = &sp->mac_control;
- if (rxb_size <= rxd_count[sp->rxd_mode])
- return PANIC;
- else if ((mac_control->rings[ring].pkt_cnt - rxb_size) > 16)
- return LOW;
- return 0;
-}
static inline int is_s2io_card_up(const struct s2io_nic * sp)
{
{"mc_err_cnt"}
};
-#define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN
-#define S2IO_ENHANCED_STAT_LEN sizeof(ethtool_enhanced_stats_keys)/ \
- ETH_GSTRING_LEN
-#define S2IO_DRIVER_STAT_LEN sizeof(ethtool_driver_stats_keys)/ ETH_GSTRING_LEN
+#define S2IO_XENA_STAT_LEN ARRAY_SIZE(ethtool_xena_stats_keys)
+#define S2IO_ENHANCED_STAT_LEN ARRAY_SIZE(ethtool_enhanced_stats_keys)
+#define S2IO_DRIVER_STAT_LEN ARRAY_SIZE(ethtool_driver_stats_keys)
#define XFRAME_I_STAT_LEN (S2IO_XENA_STAT_LEN + S2IO_DRIVER_STAT_LEN )
#define XFRAME_II_STAT_LEN (XFRAME_I_STAT_LEN + S2IO_ENHANCED_STAT_LEN )
#define XFRAME_I_STAT_STRINGS_LEN ( XFRAME_I_STAT_LEN * ETH_GSTRING_LEN )
#define XFRAME_II_STAT_STRINGS_LEN ( XFRAME_II_STAT_LEN * ETH_GSTRING_LEN )
-#define S2IO_TEST_LEN sizeof(s2io_gstrings) / ETH_GSTRING_LEN
+#define S2IO_TEST_LEN ARRAY_SIZE(s2io_gstrings)
#define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN
#define S2IO_TIMER_CONF(timer, handle, arg, exp) \
static void s2io_vlan_rx_register(struct net_device *dev,
struct vlan_group *grp)
{
+ int i;
struct s2io_nic *nic = dev->priv;
- unsigned long flags;
+ unsigned long flags[MAX_TX_FIFOS];
+ struct mac_info *mac_control = &nic->mac_control;
+ struct config_param *config = &nic->config;
+
+ for (i = 0; i < config->tx_fifo_num; i++)
+ spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags[i]);
- spin_lock_irqsave(&nic->tx_lock, flags);
nic->vlgrp = grp;
- spin_unlock_irqrestore(&nic->tx_lock, flags);
+ for (i = config->tx_fifo_num - 1; i >= 0; i--)
+ spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock,
+ flags[i]);
}
/* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */
static int vlan_strip_flag;
+/* Unregister the vlan */
+static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
+{
+ int i;
+ struct s2io_nic *nic = dev->priv;
+ unsigned long flags[MAX_TX_FIFOS];
+ struct mac_info *mac_control = &nic->mac_control;
+ struct config_param *config = &nic->config;
+
+ for (i = 0; i < config->tx_fifo_num; i++)
+ spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags[i]);
+
+ if (nic->vlgrp)
+ vlan_group_set_device(nic->vlgrp, vid, NULL);
+
+ for (i = config->tx_fifo_num - 1; i >= 0; i--)
+ spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock,
+ flags[i]);
+}
+
/*
* Constants to be programmed into the Xena's registers, to configure
* the XAUI.
/* Module Loadable parameters. */
-S2IO_PARM_INT(tx_fifo_num, 1);
+S2IO_PARM_INT(tx_fifo_num, FIFO_DEFAULT_NUM);
S2IO_PARM_INT(rx_ring_num, 1);
-
-
+S2IO_PARM_INT(multiq, 0);
S2IO_PARM_INT(rx_ring_mode, 1);
S2IO_PARM_INT(use_continuous_tx_intrs, 1);
S2IO_PARM_INT(rmac_pause_time, 0x100);
S2IO_PARM_INT(tmac_util_period, 5);
S2IO_PARM_INT(rmac_util_period, 5);
S2IO_PARM_INT(l3l4hdr_size, 128);
+/* 0 is no steering, 1 is Priority steering, 2 is Default steering */
+S2IO_PARM_INT(tx_steering_type, TX_DEFAULT_STEERING);
/* Frequency of Rx desc syncs expressed as power of 2 */
S2IO_PARM_INT(rxsync_frequency, 3);
/* Interrupt type. Values can be 0(INTA), 2(MSI_X) */
/* A simplifier macro used both by init and free shared_mem Fns(). */
#define TXD_MEM_PAGE_CNT(len, per_each) ((len+per_each - 1) / per_each)
+/* netqueue manipulation helper functions */
+static inline void s2io_stop_all_tx_queue(struct s2io_nic *sp)
+{
+ int i;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (sp->config.multiq) {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ netif_stop_subqueue(sp->dev, i);
+ } else
+#endif
+ {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_STOP;
+ netif_stop_queue(sp->dev);
+ }
+}
+
+static inline void s2io_stop_tx_queue(struct s2io_nic *sp, int fifo_no)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (sp->config.multiq)
+ netif_stop_subqueue(sp->dev, fifo_no);
+ else
+#endif
+ {
+ sp->mac_control.fifos[fifo_no].queue_state =
+ FIFO_QUEUE_STOP;
+ netif_stop_queue(sp->dev);
+ }
+}
+
+static inline void s2io_start_all_tx_queue(struct s2io_nic *sp)
+{
+ int i;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (sp->config.multiq) {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ netif_start_subqueue(sp->dev, i);
+ } else
+#endif
+ {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START;
+ netif_start_queue(sp->dev);
+ }
+}
+
+static inline void s2io_start_tx_queue(struct s2io_nic *sp, int fifo_no)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (sp->config.multiq)
+ netif_start_subqueue(sp->dev, fifo_no);
+ else
+#endif
+ {
+ sp->mac_control.fifos[fifo_no].queue_state =
+ FIFO_QUEUE_START;
+ netif_start_queue(sp->dev);
+ }
+}
+
+static inline void s2io_wake_all_tx_queue(struct s2io_nic *sp)
+{
+ int i;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (sp->config.multiq) {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ netif_wake_subqueue(sp->dev, i);
+ } else
+#endif
+ {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START;
+ netif_wake_queue(sp->dev);
+ }
+}
+
+static inline void s2io_wake_tx_queue(
+ struct fifo_info *fifo, int cnt, u8 multiq)
+{
+
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (multiq) {
+ if (cnt && __netif_subqueue_stopped(fifo->dev, fifo->fifo_no))
+ netif_wake_subqueue(fifo->dev, fifo->fifo_no);
+ } else
+#endif
+ if (cnt && (fifo->queue_state == FIFO_QUEUE_STOP)) {
+ if (netif_queue_stopped(fifo->dev)) {
+ fifo->queue_state = FIFO_QUEUE_START;
+ netif_wake_queue(fifo->dev);
+ }
+ }
+}
+
/**
* init_shared_mem - Allocation and Initialization of Memory
* @nic: Device private variable.
return -EINVAL;
}
+ size = 0;
+ for (i = 0; i < config->tx_fifo_num; i++) {
+ size = config->tx_cfg[i].fifo_len;
+ /*
+ * Legal values are from 2 to 8192
+ */
+ if (size < 2) {
+ DBG_PRINT(ERR_DBG, "s2io: Invalid fifo len (%d)", size);
+ DBG_PRINT(ERR_DBG, "for fifo %d\n", i);
+ DBG_PRINT(ERR_DBG, "s2io: Legal values for fifo len"
+ "are 2 to 8192\n");
+ return -EINVAL;
+ }
+ }
+
lst_size = (sizeof(struct TxD) * config->max_txds);
lst_per_page = PAGE_SIZE / lst_size;
mac_control->fifos[i].fifo_no = i;
mac_control->fifos[i].nic = nic;
mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 2;
+ mac_control->fifos[i].dev = dev;
for (j = 0; j < page_num; j++) {
int k = 0;
}
}
- nic->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL);
- if (!nic->ufo_in_band_v)
- return -ENOMEM;
- mem_allocated += (size * sizeof(u64));
+ for (i = 0; i < config->tx_fifo_num; i++) {
+ size = config->tx_cfg[i].fifo_len;
+ mac_control->fifos[i].ufo_in_band_v
+ = kcalloc(size, sizeof(u64), GFP_KERNEL);
+ if (!mac_control->fifos[i].ufo_in_band_v)
+ return -ENOMEM;
+ mem_allocated += (size * sizeof(u64));
+ }
/* Allocation and initialization of RXDs in Rings */
size = 0;
static void free_shared_mem(struct s2io_nic *nic)
{
int i, j, blk_cnt, size;
- u32 ufo_size = 0;
void *tmp_v_addr;
dma_addr_t tmp_p_addr;
struct mac_info *mac_control;
lst_per_page = PAGE_SIZE / lst_size;
for (i = 0; i < config->tx_fifo_num; i++) {
- ufo_size += config->tx_cfg[i].fifo_len;
page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
lst_per_page);
for (j = 0; j < page_num; j++) {
}
}
+ for (i = 0; i < nic->config.tx_fifo_num; i++) {
+ if (mac_control->fifos[i].ufo_in_band_v) {
+ nic->mac_control.stats_info->sw_stat.mem_freed
+ += (config->tx_cfg[i].fifo_len * sizeof(u64));
+ kfree(mac_control->fifos[i].ufo_in_band_v);
+ }
+ }
+
if (mac_control->stats_mem) {
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
+ mac_control->stats_mem_sz;
pci_free_consistent(nic->pdev,
mac_control->stats_mem_sz,
mac_control->stats_mem,
mac_control->stats_mem_phy);
- nic->mac_control.stats_info->sw_stat.mem_freed +=
- mac_control->stats_mem_sz;
- }
- if (nic->ufo_in_band_v) {
- kfree(nic->ufo_in_band_v);
- nic->mac_control.stats_info->sw_stat.mem_freed
- += (ufo_size * sizeof(u64));
}
}
return mode;
}
+/**
+ * init_tti - Initialization transmit traffic interrupt scheme
+ * @nic: device private variable
+ * @link: link status (UP/DOWN) used to enable/disable continuous
+ * transmit interrupts
+ * Description: The function configures transmit traffic interrupts
+ * Return Value: SUCCESS on success and
+ * '-1' on failure
+ */
+
+static int init_tti(struct s2io_nic *nic, int link)
+{
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
+ register u64 val64 = 0;
+ int i;
+ struct config_param *config;
+
+ config = &nic->config;
+
+ for (i = 0; i < config->tx_fifo_num; i++) {
+ /*
+ * TTI Initialization. Default Tx timer gets us about
+ * 250 interrupts per sec. Continuous interrupts are enabled
+ * by default.
+ */
+ if (nic->device_type == XFRAME_II_DEVICE) {
+ int count = (nic->config.bus_speed * 125)/2;
+ val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count);
+ } else
+ val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078);
+
+ val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) |
+ TTI_DATA1_MEM_TX_URNG_B(0x10) |
+ TTI_DATA1_MEM_TX_URNG_C(0x30) |
+ TTI_DATA1_MEM_TX_TIMER_AC_EN;
+
+ if (use_continuous_tx_intrs && (link == LINK_UP))
+ val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
+ writeq(val64, &bar0->tti_data1_mem);
+
+ val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
+ TTI_DATA2_MEM_TX_UFC_B(0x20) |
+ TTI_DATA2_MEM_TX_UFC_C(0x40) |
+ TTI_DATA2_MEM_TX_UFC_D(0x80);
+
+ writeq(val64, &bar0->tti_data2_mem);
+
+ val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD |
+ TTI_CMD_MEM_OFFSET(i);
+ writeq(val64, &bar0->tti_command_mem);
+
+ if (wait_for_cmd_complete(&bar0->tti_command_mem,
+ TTI_CMD_MEM_STROBE_NEW_CMD, S2IO_BIT_RESET) != SUCCESS)
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
/**
* init_nic - Initialization of hardware
- * @nic: device peivate variable
+ * @nic: device private variable
* Description: The function sequentially configures every block
* of the H/W from their reset values.
* Return Value: SUCCESS on success and
for (i = 0, j = 0; i < config->tx_fifo_num; i++) {
val64 |=
- vBIT(config->tx_cfg[i].fifo_len - 1, ((i * 32) + 19),
+ vBIT(config->tx_cfg[i].fifo_len - 1, ((j * 32) + 19),
13) | vBIT(config->tx_cfg[i].fifo_priority,
- ((i * 32) + 5), 3);
+ ((j * 32) + 5), 3);
if (i == (config->tx_fifo_num - 1)) {
if (i % 2 == 0)
case 1:
writeq(val64, &bar0->tx_fifo_partition_0);
val64 = 0;
+ j = 0;
break;
case 3:
writeq(val64, &bar0->tx_fifo_partition_1);
val64 = 0;
+ j = 0;
break;
case 5:
writeq(val64, &bar0->tx_fifo_partition_2);
val64 = 0;
+ j = 0;
break;
case 7:
writeq(val64, &bar0->tx_fifo_partition_3);
+ val64 = 0;
+ j = 0;
+ break;
+ default:
+ j++;
break;
}
}
/*
* Filling Tx round robin registers
- * as per the number of FIFOs
+ * as per the number of FIFOs for equal scheduling priority
*/
switch (config->tx_fifo_num) {
case 1:
- val64 = 0x0000000000000000ULL;
+ val64 = 0x0;
writeq(val64, &bar0->tx_w_round_robin_0);
writeq(val64, &bar0->tx_w_round_robin_1);
writeq(val64, &bar0->tx_w_round_robin_2);
writeq(val64, &bar0->tx_w_round_robin_4);
break;
case 2:
- val64 = 0x0000010000010000ULL;
+ val64 = 0x0001000100010001ULL;
writeq(val64, &bar0->tx_w_round_robin_0);
- val64 = 0x0100000100000100ULL;
writeq(val64, &bar0->tx_w_round_robin_1);
- val64 = 0x0001000001000001ULL;
writeq(val64, &bar0->tx_w_round_robin_2);
- val64 = 0x0000010000010000ULL;
writeq(val64, &bar0->tx_w_round_robin_3);
- val64 = 0x0100000000000000ULL;
+ val64 = 0x0001000100000000ULL;
writeq(val64, &bar0->tx_w_round_robin_4);
break;
case 3:
- val64 = 0x0001000102000001ULL;
+ val64 = 0x0001020001020001ULL;
writeq(val64, &bar0->tx_w_round_robin_0);
- val64 = 0x0001020000010001ULL;
+ val64 = 0x0200010200010200ULL;
writeq(val64, &bar0->tx_w_round_robin_1);
- val64 = 0x0200000100010200ULL;
+ val64 = 0x0102000102000102ULL;
writeq(val64, &bar0->tx_w_round_robin_2);
- val64 = 0x0001000102000001ULL;
+ val64 = 0x0001020001020001ULL;
writeq(val64, &bar0->tx_w_round_robin_3);
- val64 = 0x0001020000000000ULL;
+ val64 = 0x0200010200000000ULL;
writeq(val64, &bar0->tx_w_round_robin_4);
break;
case 4:
- val64 = 0x0001020300010200ULL;
+ val64 = 0x0001020300010203ULL;
writeq(val64, &bar0->tx_w_round_robin_0);
- val64 = 0x0100000102030001ULL;
writeq(val64, &bar0->tx_w_round_robin_1);
- val64 = 0x0200010000010203ULL;
writeq(val64, &bar0->tx_w_round_robin_2);
- val64 = 0x0001020001000001ULL;
writeq(val64, &bar0->tx_w_round_robin_3);
- val64 = 0x0203000100000000ULL;
+ val64 = 0x0001020300000000ULL;
writeq(val64, &bar0->tx_w_round_robin_4);
break;
case 5:
- val64 = 0x0001000203000102ULL;
+ val64 = 0x0001020304000102ULL;
writeq(val64, &bar0->tx_w_round_robin_0);
- val64 = 0x0001020001030004ULL;
+ val64 = 0x0304000102030400ULL;
writeq(val64, &bar0->tx_w_round_robin_1);
- val64 = 0x0001000203000102ULL;
+ val64 = 0x0102030400010203ULL;
writeq(val64, &bar0->tx_w_round_robin_2);
- val64 = 0x0001020001030004ULL;
+ val64 = 0x0400010203040001ULL;
writeq(val64, &bar0->tx_w_round_robin_3);
- val64 = 0x0001000000000000ULL;
+ val64 = 0x0203040000000000ULL;
writeq(val64, &bar0->tx_w_round_robin_4);
break;
case 6:
- val64 = 0x0001020304000102ULL;
+ val64 = 0x0001020304050001ULL;
writeq(val64, &bar0->tx_w_round_robin_0);
- val64 = 0x0304050001020001ULL;
+ val64 = 0x0203040500010203ULL;
writeq(val64, &bar0->tx_w_round_robin_1);
- val64 = 0x0203000100000102ULL;
+ val64 = 0x0405000102030405ULL;
writeq(val64, &bar0->tx_w_round_robin_2);
- val64 = 0x0304000102030405ULL;
+ val64 = 0x0001020304050001ULL;
writeq(val64, &bar0->tx_w_round_robin_3);
- val64 = 0x0001000200000000ULL;
+ val64 = 0x0203040500000000ULL;
writeq(val64, &bar0->tx_w_round_robin_4);
break;
case 7:
- val64 = 0x0001020001020300ULL;
+ val64 = 0x0001020304050600ULL;
writeq(val64, &bar0->tx_w_round_robin_0);
- val64 = 0x0102030400010203ULL;
+ val64 = 0x0102030405060001ULL;
writeq(val64, &bar0->tx_w_round_robin_1);
- val64 = 0x0405060001020001ULL;
+ val64 = 0x0203040506000102ULL;
writeq(val64, &bar0->tx_w_round_robin_2);
- val64 = 0x0304050000010200ULL;
+ val64 = 0x0304050600010203ULL;
writeq(val64, &bar0->tx_w_round_robin_3);
- val64 = 0x0102030000000000ULL;
+ val64 = 0x0405060000000000ULL;
writeq(val64, &bar0->tx_w_round_robin_4);
break;
case 8:
- val64 = 0x0001020300040105ULL;
+ val64 = 0x0001020304050607ULL;
writeq(val64, &bar0->tx_w_round_robin_0);
- val64 = 0x0200030106000204ULL;
writeq(val64, &bar0->tx_w_round_robin_1);
- val64 = 0x0103000502010007ULL;
writeq(val64, &bar0->tx_w_round_robin_2);
- val64 = 0x0304010002060500ULL;
writeq(val64, &bar0->tx_w_round_robin_3);
- val64 = 0x0103020400000000ULL;
+ val64 = 0x0001020300000000ULL;
writeq(val64, &bar0->tx_w_round_robin_4);
break;
}
MAC_RX_LINK_UTIL_VAL(rmac_util_period);
writeq(val64, &bar0->mac_link_util);
-
/*
* Initializing the Transmit and Receive Traffic Interrupt
* Scheme.
*/
- /*
- * TTI Initialization. Default Tx timer gets us about
- * 250 interrupts per sec. Continuous interrupts are enabled
- * by default.
- */
- if (nic->device_type == XFRAME_II_DEVICE) {
- int count = (nic->config.bus_speed * 125)/2;
- val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count);
- } else {
- val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078);
- }
- val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) |
- TTI_DATA1_MEM_TX_URNG_B(0x10) |
- TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN;
- if (use_continuous_tx_intrs)
- val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
- writeq(val64, &bar0->tti_data1_mem);
-
- val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
- TTI_DATA2_MEM_TX_UFC_B(0x20) |
- TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80);
- writeq(val64, &bar0->tti_data2_mem);
-
- val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
- writeq(val64, &bar0->tti_command_mem);
-
- /*
- * Once the operation completes, the Strobe bit of the command
- * register will be reset. We poll for this particular condition
- * We wait for a maximum of 500ms for the operation to complete,
- * if it's not complete by then we return error.
- */
- time = 0;
- while (TRUE) {
- val64 = readq(&bar0->tti_command_mem);
- if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
- break;
- }
- if (time > 10) {
- DBG_PRINT(ERR_DBG, "%s: TTI init Failed\n",
- dev->name);
- return -ENODEV;
- }
- msleep(50);
- time++;
- }
+ /* Initialize TTI */
+ if (SUCCESS != init_tti(nic, nic->last_link_state))
+ return -ENODEV;
/* RTI Initialization */
if (nic->device_type == XFRAME_II_DEVICE) {
u16 j, frg_cnt;
txds = txdlp;
- if (txds->Host_Control == (u64)(long)nic->ufo_in_band_v) {
+ if (txds->Host_Control == (u64)(long)fifo_data->ufo_in_band_v) {
pci_unmap_single(nic->pdev, (dma_addr_t)
txds->Buffer_Pointer, sizeof(u64),
PCI_DMA_TODEVICE);
config = &nic->config;
for (i = 0; i < config->tx_fifo_num; i++) {
- for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
+ unsigned long flags;
+ spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags);
+ for (j = 0; j < config->tx_cfg[i].fifo_len; j++) {
txdp = (struct TxD *) \
mac_control->fifos[i].list_info[j].list_virt_addr;
skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
dev->name, cnt, i);
mac_control->fifos[i].tx_curr_get_info.offset = 0;
mac_control->fifos[i].tx_curr_put_info.offset = 0;
+ spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock, flags);
}
}
struct config_param *config;
u64 tmp;
struct buffAdd *ba;
- unsigned long flags;
struct RxD_t *first_rxdp = NULL;
u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
struct RxD1 *rxdp1;
DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
dev->name, rxdp);
}
- if(!napi) {
- spin_lock_irqsave(&nic->put_lock, flags);
- mac_control->rings[ring_no].put_pos =
- (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
- spin_unlock_irqrestore(&nic->put_lock, flags);
- } else {
- mac_control->rings[ring_no].put_pos =
- (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
- }
+
if ((rxdp->Control_1 & RXD_OWN_XENA) &&
((nic->rxd_mode == RXD_MODE_3B) &&
(rxdp->Control_2 & s2BIT(0)))) {
struct XENA_dev_config __iomem *bar0 = nic->bar0;
int i;
- if (!is_s2io_card_up(nic))
- return 0;
-
mac_control = &nic->mac_control;
config = &nic->config;
{
struct s2io_nic *nic = ring_data->nic;
struct net_device *dev = (struct net_device *) nic->dev;
- int get_block, put_block, put_offset;
+ int get_block, put_block;
struct rx_curr_get_info get_info, put_info;
struct RxD_t *rxdp;
struct sk_buff *skb;
struct RxD1* rxdp1;
struct RxD3* rxdp3;
- spin_lock(&nic->rx_lock);
-
get_info = ring_data->rx_curr_get_info;
get_block = get_info.block_index;
memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
put_block = put_info.block_index;
rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
- if (!napi) {
- spin_lock(&nic->put_lock);
- put_offset = ring_data->put_pos;
- spin_unlock(&nic->put_lock);
- } else
- put_offset = ring_data->put_pos;
while (RXD_IS_UP2DT(rxdp)) {
/*
DBG_PRINT(ERR_DBG, "%s: The skb is ",
dev->name);
DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
- spin_unlock(&nic->rx_lock);
return;
}
if (nic->rxd_mode == RXD_MODE_1) {
struct lro *lro = &nic->lro0_n[i];
if (lro->in_use) {
update_L3L4_header(nic, lro);
- queue_rx_frame(lro->parent);
+ queue_rx_frame(lro->parent, lro->vlan_tag);
clear_lro_session(lro);
}
}
}
-
- spin_unlock(&nic->rx_lock);
}
/**
static void tx_intr_handler(struct fifo_info *fifo_data)
{
struct s2io_nic *nic = fifo_data->nic;
- struct net_device *dev = (struct net_device *) nic->dev;
struct tx_curr_get_info get_info, put_info;
- struct sk_buff *skb;
+ struct sk_buff *skb = NULL;
struct TxD *txdlp;
+ int pkt_cnt = 0;
+ unsigned long flags = 0;
u8 err_mask;
+ if (!spin_trylock_irqsave(&fifo_data->tx_lock, flags))
+ return;
+
get_info = fifo_data->tx_curr_get_info;
memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info));
txdlp = (struct TxD *) fifo_data->list_info[get_info.offset].
skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
if (skb == NULL) {
+ spin_unlock_irqrestore(&fifo_data->tx_lock, flags);
DBG_PRINT(ERR_DBG, "%s: Null skb ",
__FUNCTION__);
DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
return;
}
+ pkt_cnt++;
/* Updating the statistics block */
nic->stats.tx_bytes += skb->len;
get_info.offset;
}
- spin_lock(&nic->tx_lock);
- if (netif_queue_stopped(dev))
- netif_wake_queue(dev);
- spin_unlock(&nic->tx_lock);
+ s2io_wake_tx_queue(fifo_data, pkt_cnt, nic->config.multiq);
+
+ spin_unlock_irqrestore(&fifo_data->tx_lock, flags);
}
/**
/* Set swapper to enable I/O register access */
s2io_set_swapper(sp);
+ /* restore mac_addr entries */
+ do_s2io_restore_unicast_mc(sp);
+
/* Restore the MSIX table entries from local variables */
restore_xmsi_data(sp);
writeq(val64, &bar0->pcc_err_reg);
}
- /* restore the previously assigned mac address */
- do_s2io_prog_unicast(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr);
-
sp->device_enabled_once = FALSE;
}
}
/* Handle software interrupt used during MSI(X) test */
-static irqreturn_t __devinit s2io_test_intr(int irq, void *dev_id)
+static irqreturn_t s2io_test_intr(int irq, void *dev_id)
{
struct s2io_nic *sp = dev_id;
}
/* Test interrupt path by forcing a a software IRQ */
-static int __devinit s2io_test_msi(struct s2io_nic *sp)
+static int s2io_test_msi(struct s2io_nic *sp)
{
struct pci_dev *pdev = sp->pdev;
struct XENA_dev_config __iomem *bar0 = sp->bar0;
if (!sp->msi_detected) {
/* MSI(X) test failed, go back to INTx mode */
- DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated"
+ DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated "
"using MSI(X) during test\n", sp->dev->name,
pci_name(pdev));
netif_carrier_off(dev);
sp->last_link_state = 0;
- napi_enable(&sp->napi);
-
if (sp->config.intr_type == MSI_X) {
int ret = s2io_enable_msi_x(sp);
err = -ENODEV;
goto hw_init_failed;
}
-
- netif_start_queue(dev);
+ s2io_start_all_tx_queue(sp);
return 0;
hw_init_failed:
- napi_disable(&sp->napi);
if (sp->config.intr_type == MSI_X) {
if (sp->entries) {
kfree(sp->entries);
static int s2io_close(struct net_device *dev)
{
struct s2io_nic *sp = dev->priv;
+ struct config_param *config = &sp->config;
+ u64 tmp64;
+ int offset;
/* Return if the device is already closed *
* Can happen when s2io_card_up failed in change_mtu *
if (!is_s2io_card_up(sp))
return 0;
- netif_stop_queue(dev);
- napi_disable(&sp->napi);
- /* Reset card, kill tasklet and free Tx and Rx buffers. */
+ s2io_stop_all_tx_queue(sp);
+ /* delete all populated mac entries */
+ for (offset = 1; offset < config->max_mc_addr; offset++) {
+ tmp64 = do_s2io_read_unicast_mc(sp, offset);
+ if (tmp64 != S2IO_DISABLE_MAC_ENTRY)
+ do_s2io_delete_unicast_mc(sp, tmp64);
+ }
+
s2io_card_down(sp);
return 0;
register u64 val64;
struct TxD *txdp;
struct TxFIFO_element __iomem *tx_fifo;
- unsigned long flags;
+ unsigned long flags = 0;
u16 vlan_tag = 0;
- int vlan_priority = 0;
+ struct fifo_info *fifo = NULL;
struct mac_info *mac_control;
struct config_param *config;
+ int do_spin_lock = 1;
int offload_type;
+ int enable_per_list_interrupt = 0;
struct swStat *stats = &sp->mac_control.stats_info->sw_stat;
mac_control = &sp->mac_control;
DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
dev_kfree_skb_any(skb);
return 0;
-}
+ }
- spin_lock_irqsave(&sp->tx_lock, flags);
if (!is_s2io_card_up(sp)) {
DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
dev->name);
- spin_unlock_irqrestore(&sp->tx_lock, flags);
dev_kfree_skb(skb);
return 0;
}
queue = 0;
- /* Get Fifo number to Transmit based on vlan priority */
- if (sp->vlgrp && vlan_tx_tag_present(skb)) {
+ if (sp->vlgrp && vlan_tx_tag_present(skb))
vlan_tag = vlan_tx_tag_get(skb);
- vlan_priority = vlan_tag >> 13;
- queue = config->fifo_mapping[vlan_priority];
+ if (sp->config.tx_steering_type == TX_DEFAULT_STEERING) {
+ if (skb->protocol == htons(ETH_P_IP)) {
+ struct iphdr *ip;
+ struct tcphdr *th;
+ ip = ip_hdr(skb);
+
+ if ((ip->frag_off & htons(IP_OFFSET|IP_MF)) == 0) {
+ th = (struct tcphdr *)(((unsigned char *)ip) +
+ ip->ihl*4);
+
+ if (ip->protocol == IPPROTO_TCP) {
+ queue_len = sp->total_tcp_fifos;
+ queue = (ntohs(th->source) +
+ ntohs(th->dest)) &
+ sp->fifo_selector[queue_len - 1];
+ if (queue >= queue_len)
+ queue = queue_len - 1;
+ } else if (ip->protocol == IPPROTO_UDP) {
+ queue_len = sp->total_udp_fifos;
+ queue = (ntohs(th->source) +
+ ntohs(th->dest)) &
+ sp->fifo_selector[queue_len - 1];
+ if (queue >= queue_len)
+ queue = queue_len - 1;
+ queue += sp->udp_fifo_idx;
+ if (skb->len > 1024)
+ enable_per_list_interrupt = 1;
+ do_spin_lock = 0;
+ }
+ }
+ }
+ } else if (sp->config.tx_steering_type == TX_PRIORITY_STEERING)
+ /* get fifo number based on skb->priority value */
+ queue = config->fifo_mapping
+ [skb->priority & (MAX_TX_FIFOS - 1)];
+ fifo = &mac_control->fifos[queue];
+
+ if (do_spin_lock)
+ spin_lock_irqsave(&fifo->tx_lock, flags);
+ else {
+ if (unlikely(!spin_trylock_irqsave(&fifo->tx_lock, flags)))
+ return NETDEV_TX_LOCKED;
+ }
+
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (sp->config.multiq) {
+ if (__netif_subqueue_stopped(dev, fifo->fifo_no)) {
+ spin_unlock_irqrestore(&fifo->tx_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+ } else
+#endif
+ if (unlikely(fifo->queue_state == FIFO_QUEUE_STOP)) {
+ if (netif_queue_stopped(dev)) {
+ spin_unlock_irqrestore(&fifo->tx_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
}
- put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
- get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
- txdp = (struct TxD *) mac_control->fifos[queue].list_info[put_off].
- list_virt_addr;
+ put_off = (u16) fifo->tx_curr_put_info.offset;
+ get_off = (u16) fifo->tx_curr_get_info.offset;
+ txdp = (struct TxD *) fifo->list_info[put_off].list_virt_addr;
- queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
+ queue_len = fifo->tx_curr_put_info.fifo_len + 1;
/* Avoid "put" pointer going beyond "get" pointer */
if (txdp->Host_Control ||
((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
- netif_stop_queue(dev);
+ s2io_stop_tx_queue(sp, fifo->fifo_no);
dev_kfree_skb(skb);
- spin_unlock_irqrestore(&sp->tx_lock, flags);
+ spin_unlock_irqrestore(&fifo->tx_lock, flags);
return 0;
}
}
txdp->Control_1 |= TXD_GATHER_CODE_FIRST;
txdp->Control_1 |= TXD_LIST_OWN_XENA;
- txdp->Control_2 |= config->tx_intr_type;
-
- if (sp->vlgrp && vlan_tx_tag_present(skb)) {
+ txdp->Control_2 |= TXD_INT_NUMBER(fifo->fifo_no);
+ if (enable_per_list_interrupt)
+ if (put_off & (queue_len >> 5))
+ txdp->Control_2 |= TXD_INT_TYPE_PER_LIST;
+ if (vlan_tag) {
txdp->Control_2 |= TXD_VLAN_ENABLE;
txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
}
txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
txdp->Control_1 |= TXD_BUFFER0_SIZE(8);
#ifdef __BIG_ENDIAN
- sp->ufo_in_band_v[put_off] =
- (u64)skb_shinfo(skb)->ip6_frag_id;
+ /* both variants do cpu_to_be64(be32_to_cpu(...)) */
+ fifo->ufo_in_band_v[put_off] =
+ (__force u64)skb_shinfo(skb)->ip6_frag_id;
#else
- sp->ufo_in_band_v[put_off] =
- (u64)skb_shinfo(skb)->ip6_frag_id << 32;
+ fifo->ufo_in_band_v[put_off] =
+ (__force u64)skb_shinfo(skb)->ip6_frag_id << 32;
#endif
- txdp->Host_Control = (unsigned long)sp->ufo_in_band_v;
+ txdp->Host_Control = (unsigned long)fifo->ufo_in_band_v;
txdp->Buffer_Pointer = pci_map_single(sp->pdev,
- sp->ufo_in_band_v,
+ fifo->ufo_in_band_v,
sizeof(u64), PCI_DMA_TODEVICE);
if((txdp->Buffer_Pointer == 0) ||
(txdp->Buffer_Pointer == DMA_ERROR_CODE))
frg_cnt++; /* as Txd0 was used for inband header */
tx_fifo = mac_control->tx_FIFO_start[queue];
- val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
+ val64 = fifo->list_info[put_off].list_phy_addr;
writeq(val64, &tx_fifo->TxDL_Pointer);
val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
mmiowb();
put_off++;
- if (put_off == mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1)
+ if (put_off == fifo->tx_curr_put_info.fifo_len + 1)
put_off = 0;
- mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
+ fifo->tx_curr_put_info.offset = put_off;
/* Avoid "put" pointer going beyond "get" pointer */
if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
DBG_PRINT(TX_DBG,
"No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
put_off, get_off);
- netif_stop_queue(dev);
+ s2io_stop_tx_queue(sp, fifo->fifo_no);
}
mac_control->stats_info->sw_stat.mem_allocated += skb->truesize;
dev->trans_start = jiffies;
- spin_unlock_irqrestore(&sp->tx_lock, flags);
+ spin_unlock_irqrestore(&fifo->tx_lock, flags);
+
+ if (sp->config.intr_type == MSI_X)
+ tx_intr_handler(fifo);
return 0;
pci_map_failed:
stats->pci_map_fail_cnt++;
- netif_stop_queue(dev);
+ s2io_stop_tx_queue(sp, fifo->fifo_no);
stats->mem_freed += skb->truesize;
dev_kfree_skb(skb);
- spin_unlock_irqrestore(&sp->tx_lock, flags);
+ spin_unlock_irqrestore(&fifo->tx_lock, flags);
return 0;
}
static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
{
- int rxb_size, level;
-
- if (!sp->lro) {
- rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
- level = rx_buffer_level(sp, rxb_size, rng_n);
-
- if ((level == PANIC) && (!TASKLET_IN_USE)) {
- int ret;
- DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
- DBG_PRINT(INTR_DBG, "PANIC levels\n");
- if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
- DBG_PRINT(INFO_DBG, "Out of memory in %s",
- __FUNCTION__);
- clear_bit(0, (&sp->tasklet_status));
- return -1;
- }
- clear_bit(0, (&sp->tasklet_status));
- } else if (level == LOW)
- tasklet_schedule(&sp->task);
-
- } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
- DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
- DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
+ if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
}
return 0;
}
return;
reset:
- netif_stop_queue(dev);
+ s2io_stop_all_tx_queue(sp);
schedule_work(&sp->rst_timer_task);
sw_stat->soft_reset_cnt++;
return;
struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
0xfeffffffffffULL;
- u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
+ u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, mac_addr = 0;
void __iomem *add;
+ struct config_param *config = &sp->config;
if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) {
/* Enable all Multicast addresses */
&bar0->rmac_addr_data1_mem);
val64 = RMAC_ADDR_CMD_MEM_WE |
RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
- RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
+ RMAC_ADDR_CMD_MEM_OFFSET(config->max_mc_addr - 1);
writeq(val64, &bar0->rmac_addr_cmd_mem);
/* Wait till command completes */
wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
S2IO_BIT_RESET);
sp->m_cast_flg = 1;
- sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
+ sp->all_multi_pos = config->max_mc_addr - 1;
} else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) {
/* Disable all Multicast addresses */
writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
/* Update individual M_CAST address list */
if ((!sp->m_cast_flg) && dev->mc_count) {
if (dev->mc_count >
- (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) {
+ (config->max_mc_addr - config->max_mac_addr)) {
DBG_PRINT(ERR_DBG, "%s: No more Rx filters ",
dev->name);
DBG_PRINT(ERR_DBG, "can be added, please enable ");
val64 = RMAC_ADDR_CMD_MEM_WE |
RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
RMAC_ADDR_CMD_MEM_OFFSET
- (MAC_MC_ADDR_START_OFFSET + i);
+ (config->mc_start_offset + i);
writeq(val64, &bar0->rmac_addr_cmd_mem);
/* Wait for command completes */
val64 = RMAC_ADDR_CMD_MEM_WE |
RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
RMAC_ADDR_CMD_MEM_OFFSET
- (i + MAC_MC_ADDR_START_OFFSET);
+ (i + config->mc_start_offset);
writeq(val64, &bar0->rmac_addr_cmd_mem);
/* Wait for command completes */
}
}
-/* add unicast MAC address to CAM */
-static int do_s2io_add_unicast(struct s2io_nic *sp, u64 addr, int off)
+/* read from CAM unicast & multicast addresses and store it in
+ * def_mac_addr structure
+ */
+void do_s2io_store_unicast_mc(struct s2io_nic *sp)
+{
+ int offset;
+ u64 mac_addr = 0x0;
+ struct config_param *config = &sp->config;
+
+ /* store unicast & multicast mac addresses */
+ for (offset = 0; offset < config->max_mc_addr; offset++) {
+ mac_addr = do_s2io_read_unicast_mc(sp, offset);
+ /* if read fails disable the entry */
+ if (mac_addr == FAILURE)
+ mac_addr = S2IO_DISABLE_MAC_ENTRY;
+ do_s2io_copy_mac_addr(sp, offset, mac_addr);
+ }
+}
+
+/* restore unicast & multicast MAC to CAM from def_mac_addr structure */
+static void do_s2io_restore_unicast_mc(struct s2io_nic *sp)
+{
+ int offset;
+ struct config_param *config = &sp->config;
+ /* restore unicast mac address */
+ for (offset = 0; offset < config->max_mac_addr; offset++)
+ do_s2io_prog_unicast(sp->dev,
+ sp->def_mac_addr[offset].mac_addr);
+
+ /* restore multicast mac address */
+ for (offset = config->mc_start_offset;
+ offset < config->max_mc_addr; offset++)
+ do_s2io_add_mc(sp, sp->def_mac_addr[offset].mac_addr);
+}
+
+/* add a multicast MAC address to CAM */
+static int do_s2io_add_mc(struct s2io_nic *sp, u8 *addr)
+{
+ int i;
+ u64 mac_addr = 0;
+ struct config_param *config = &sp->config;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ mac_addr <<= 8;
+ mac_addr |= addr[i];
+ }
+ if ((0ULL == mac_addr) || (mac_addr == S2IO_DISABLE_MAC_ENTRY))
+ return SUCCESS;
+
+ /* check if the multicast mac already preset in CAM */
+ for (i = config->mc_start_offset; i < config->max_mc_addr; i++) {
+ u64 tmp64;
+ tmp64 = do_s2io_read_unicast_mc(sp, i);
+ if (tmp64 == S2IO_DISABLE_MAC_ENTRY) /* CAM entry is empty */
+ break;
+
+ if (tmp64 == mac_addr)
+ return SUCCESS;
+ }
+ if (i == config->max_mc_addr) {
+ DBG_PRINT(ERR_DBG,
+ "CAM full no space left for multicast MAC\n");
+ return FAILURE;
+ }
+ /* Update the internal structure with this new mac address */
+ do_s2io_copy_mac_addr(sp, i, mac_addr);
+
+ return (do_s2io_add_mac(sp, mac_addr, i));
+}
+
+/* add MAC address to CAM */
+static int do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int off)
{
u64 val64;
struct XENA_dev_config __iomem *bar0 = sp->bar0;
if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
S2IO_BIT_RESET)) {
- DBG_PRINT(INFO_DBG, "add_mac_addr failed\n");
+ DBG_PRINT(INFO_DBG, "do_s2io_add_mac failed\n");
return FAILURE;
}
return SUCCESS;
}
+/* deletes a specified unicast/multicast mac entry from CAM */
+static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr)
+{
+ int offset;
+ u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, tmp64;
+ struct config_param *config = &sp->config;
+
+ for (offset = 1;
+ offset < config->max_mc_addr; offset++) {
+ tmp64 = do_s2io_read_unicast_mc(sp, offset);
+ if (tmp64 == addr) {
+ /* disable the entry by writing 0xffffffffffffULL */
+ if (do_s2io_add_mac(sp, dis_addr, offset) == FAILURE)
+ return FAILURE;
+ /* store the new mac list from CAM */
+ do_s2io_store_unicast_mc(sp);
+ return SUCCESS;
+ }
+ }
+ DBG_PRINT(ERR_DBG, "MAC address 0x%llx not found in CAM\n",
+ (unsigned long long)addr);
+ return FAILURE;
+}
+
+/* read mac entries from CAM */
+static u64 do_s2io_read_unicast_mc(struct s2io_nic *sp, int offset)
+{
+ u64 tmp64 = 0xffffffffffff0000ULL, val64;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+
+ /* read mac addr */
+ val64 =
+ RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
+ RMAC_ADDR_CMD_MEM_OFFSET(offset);
+ writeq(val64, &bar0->rmac_addr_cmd_mem);
+
+ /* Wait till command completes */
+ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
+ S2IO_BIT_RESET)) {
+ DBG_PRINT(INFO_DBG, "do_s2io_read_unicast_mc failed\n");
+ return FAILURE;
+ }
+ tmp64 = readq(&bar0->rmac_addr_data0_mem);
+ return (tmp64 >> 16);
+}
/**
* s2io_set_mac_addr driver entry point
*/
+
static int s2io_set_mac_addr(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
/* store the MAC address in CAM */
return (do_s2io_prog_unicast(dev, dev->dev_addr));
}
-
/**
* do_s2io_prog_unicast - Programs the Xframe mac address
* @dev : pointer to the device structure.
* Return value: SUCCESS on success and an appropriate (-)ve integer
* as defined in errno.h file on failure.
*/
+
static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr)
{
struct s2io_nic *sp = dev->priv;
register u64 mac_addr = 0, perm_addr = 0;
int i;
+ u64 tmp64;
+ struct config_param *config = &sp->config;
/*
* Set the new MAC address as the new unicast filter and reflect this
if (mac_addr == perm_addr)
return SUCCESS;
+ /* check if the mac already preset in CAM */
+ for (i = 1; i < config->max_mac_addr; i++) {
+ tmp64 = do_s2io_read_unicast_mc(sp, i);
+ if (tmp64 == S2IO_DISABLE_MAC_ENTRY) /* CAM entry is empty */
+ break;
+
+ if (tmp64 == mac_addr) {
+ DBG_PRINT(INFO_DBG,
+ "MAC addr:0x%llx already present in CAM\n",
+ (unsigned long long)mac_addr);
+ return SUCCESS;
+ }
+ }
+ if (i == config->max_mac_addr) {
+ DBG_PRINT(ERR_DBG, "CAM full no space left for Unicast MAC\n");
+ return FAILURE;
+ }
/* Update the internal structure with this new mac address */
- do_s2io_copy_mac_addr(sp, 0, mac_addr);
- return (do_s2io_add_unicast(sp, mac_addr, 0));
+ do_s2io_copy_mac_addr(sp, i, mac_addr);
+ return (do_s2io_add_mac(sp, mac_addr, i));
}
/**
dev->mtu = new_mtu;
if (netif_running(dev)) {
+ s2io_stop_all_tx_queue(sp);
s2io_card_down(sp);
- netif_stop_queue(dev);
ret = s2io_card_up(sp);
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
__FUNCTION__);
return ret;
}
- if (netif_queue_stopped(dev))
- netif_wake_queue(dev);
+ s2io_wake_all_tx_queue(sp);
} else { /* Device is down */
struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = new_mtu;
return ret;
}
-/**
- * s2io_tasklet - Bottom half of the ISR.
- * @dev_adr : address of the device structure in dma_addr_t format.
- * Description:
- * This is the tasklet or the bottom half of the ISR. This is
- * an extension of the ISR which is scheduled by the scheduler to be run
- * when the load on the CPU is low. All low priority tasks of the ISR can
- * be pushed into the tasklet. For now the tasklet is used only to
- * replenish the Rx buffers in the Rx buffer descriptors.
- * Return value:
- * void.
- */
-
-static void s2io_tasklet(unsigned long dev_addr)
-{
- struct net_device *dev = (struct net_device *) dev_addr;
- struct s2io_nic *sp = dev->priv;
- int i, ret;
- struct mac_info *mac_control;
- struct config_param *config;
-
- mac_control = &sp->mac_control;
- config = &sp->config;
-
- if (!TASKLET_IN_USE) {
- for (i = 0; i < config->rx_ring_num; i++) {
- ret = fill_rx_buffers(sp, i);
- if (ret == -ENOMEM) {
- DBG_PRINT(INFO_DBG, "%s: Out of ",
- dev->name);
- DBG_PRINT(INFO_DBG, "memory in tasklet\n");
- break;
- } else if (ret == -EFILL) {
- DBG_PRINT(INFO_DBG,
- "%s: Rx Ring %d is full\n",
- dev->name, i);
- break;
- }
- }
- clear_bit(0, (&sp->tasklet_status));
- }
-}
-
/**
* s2io_set_link - Set the LInk status
* @data: long pointer to device private structue
} else {
DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
- netif_stop_queue(dev);
+ s2io_stop_all_tx_queue(nic);
}
}
val64 = readq(&bar0->adapter_control);
/* If either data or addr is zero print it */
if(!(sp->msix_info[i].addr &&
sp->msix_info[i].data)) {
- DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx"
- "Data:0x%lx\n",sp->desc[i],
+ DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx "
+ "Data:0x%llx\n",sp->desc[i],
(unsigned long long)
sp->msix_info[i].addr,
- (unsigned long)
- ntohl(sp->msix_info[i].data));
+ (unsigned long long)
+ sp->msix_info[i].data);
} else {
msix_tx_cnt++;
}
/* If either data or addr is zero print it */
if(!(sp->msix_info[i].addr &&
sp->msix_info[i].data)) {
- DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx"
- "Data:0x%lx\n",sp->desc[i],
+ DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx "
+ "Data:0x%llx\n",sp->desc[i],
(unsigned long long)
sp->msix_info[i].addr,
- (unsigned long)
- ntohl(sp->msix_info[i].data));
+ (unsigned long long)
+ sp->msix_info[i].data);
} else {
msix_rx_cnt++;
}
{
int cnt = 0;
struct XENA_dev_config __iomem *bar0 = sp->bar0;
- unsigned long flags;
register u64 val64 = 0;
+ struct config_param *config;
+ config = &sp->config;
if (!is_s2io_card_up(sp))
return;
}
clear_bit(__S2IO_STATE_CARD_UP, &sp->state);
+ /* Disable napi */
+ if (config->napi)
+ napi_disable(&sp->napi);
+
/* disable Tx and Rx traffic on the NIC */
if (do_io)
stop_nic(sp);
s2io_rem_isr(sp);
- /* Kill tasklet. */
- tasklet_kill(&sp->task);
-
/* Check if the device is Quiescent and then Reset the NIC */
while(do_io) {
/* As per the HW requirement we need to replenish the
if (do_io)
s2io_reset(sp);
- spin_lock_irqsave(&sp->tx_lock, flags);
/* Free all Tx buffers */
free_tx_buffers(sp);
- spin_unlock_irqrestore(&sp->tx_lock, flags);
/* Free all Rx buffers */
- spin_lock_irqsave(&sp->rx_lock, flags);
free_rx_buffers(sp);
- spin_unlock_irqrestore(&sp->rx_lock, flags);
clear_bit(__S2IO_STATE_LINK_TASK, &(sp->state));
}
DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
atomic_read(&sp->rx_bufs_left[i]));
}
+
+ /* Initialise napi */
+ if (config->napi)
+ napi_enable(&sp->napi);
+
/* Maintain the state prior to the open */
if (sp->promisc_flg)
sp->promisc_flg = 0;
S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
- /* Enable tasklet for the device */
- tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
-
/* Enable select interrupts */
en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS);
if (sp->config.intr_type != INTA)
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
dev->name);
}
- netif_wake_queue(dev);
+ s2io_wake_all_tx_queue(sp);
DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
dev->name);
out_unlock:
{
lro_append_pkt(sp, lro,
skb, tcp_len);
- queue_rx_frame(lro->parent);
+ queue_rx_frame(lro->parent,
+ lro->vlan_tag);
clear_lro_session(lro);
sp->mac_control.stats_info->
sw_stat.flush_max_pkts++;
lro->frags_len;
sp->mac_control.stats_info->
sw_stat.sending_both++;
- queue_rx_frame(lro->parent);
+ queue_rx_frame(lro->parent,
+ lro->vlan_tag);
clear_lro_session(lro);
goto send_up;
case 0: /* sessions exceeded */
*/
skb->ip_summed = CHECKSUM_NONE;
}
- } else {
+ } else
skb->ip_summed = CHECKSUM_NONE;
- }
+
sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
- if (!sp->lro) {
- skb->protocol = eth_type_trans(skb, dev);
- if ((sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2) &&
- vlan_strip_flag)) {
- /* Queueing the vlan frame to the upper layer */
- if (napi)
- vlan_hwaccel_receive_skb(skb, sp->vlgrp,
- RXD_GET_VLAN_TAG(rxdp->Control_2));
- else
- vlan_hwaccel_rx(skb, sp->vlgrp,
- RXD_GET_VLAN_TAG(rxdp->Control_2));
- } else {
- if (napi)
- netif_receive_skb(skb);
- else
- netif_rx(skb);
- }
- } else {
send_up:
- queue_rx_frame(skb);
- }
+ queue_rx_frame(skb, RXD_GET_VLAN_TAG(rxdp->Control_2));
dev->last_rx = jiffies;
aggregate:
atomic_dec(&sp->rx_bufs_left[ring_no]);
struct net_device *dev = (struct net_device *) sp->dev;
if (link != sp->last_link_state) {
+ init_tti(sp, link);
if (link == LINK_DOWN) {
DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
+ s2io_stop_all_tx_queue(sp);
netif_carrier_off(dev);
if(sp->mac_control.stats_info->sw_stat.link_up_cnt)
sp->mac_control.stats_info->sw_stat.link_up_time =
jiffies - sp->start_time;
sp->mac_control.stats_info->sw_stat.link_up_cnt++;
netif_carrier_on(dev);
+ s2io_wake_all_tx_queue(sp);
}
}
sp->last_link_state = link;
pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
}
-static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
+static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type,
+ u8 *dev_multiq)
{
- if ( tx_fifo_num > 8) {
- DBG_PRINT(ERR_DBG, "s2io: Requested number of Tx fifos not "
+ if ((tx_fifo_num > MAX_TX_FIFOS) ||
+ (tx_fifo_num < 1)) {
+ DBG_PRINT(ERR_DBG, "s2io: Requested number of tx fifos "
+ "(%d) not supported\n", tx_fifo_num);
+
+ if (tx_fifo_num < 1)
+ tx_fifo_num = 1;
+ else
+ tx_fifo_num = MAX_TX_FIFOS;
+
+ DBG_PRINT(ERR_DBG, "s2io: Default to %d ", tx_fifo_num);
+ DBG_PRINT(ERR_DBG, "tx fifos\n");
+ }
+
+#ifndef CONFIG_NETDEVICES_MULTIQUEUE
+ if (multiq) {
+ DBG_PRINT(ERR_DBG, "s2io: Multiqueue support not enabled\n");
+ multiq = 0;
+ }
+#endif
+ if (multiq)
+ *dev_multiq = multiq;
+
+ if (tx_steering_type && (1 == tx_fifo_num)) {
+ if (tx_steering_type != TX_DEFAULT_STEERING)
+ DBG_PRINT(ERR_DBG,
+ "s2io: Tx steering is not supported with "
+ "one fifo. Disabling Tx steering.\n");
+ tx_steering_type = NO_STEERING;
+ }
+
+ if ((tx_steering_type < NO_STEERING) ||
+ (tx_steering_type > TX_DEFAULT_STEERING)) {
+ DBG_PRINT(ERR_DBG, "s2io: Requested transmit steering not "
"supported\n");
- DBG_PRINT(ERR_DBG, "s2io: Default to 8 Tx fifos\n");
- tx_fifo_num = 8;
+ DBG_PRINT(ERR_DBG, "s2io: Disabling transmit steering\n");
+ tx_steering_type = NO_STEERING;
}
+
if ( rx_ring_num > 8) {
DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
"supported\n");
/**
* rts_ds_steer - Receive traffic steering based on IPv4 or IPv6 TOS
* or Traffic class respectively.
- * @nic: device peivate variable
+ * @nic: device private variable
* Description: The function configures the receive steering to
* desired receive ring.
* Return Value: SUCCESS on success and
struct config_param *config;
int mode;
u8 dev_intr_type = intr_type;
+ u8 dev_multiq = 0;
DECLARE_MAC_BUF(mac);
- if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
+ ret = s2io_verify_parm(pdev, &dev_intr_type, &dev_multiq);
+ if (ret)
return ret;
if ((ret = pci_enable_device(pdev))) {
pci_disable_device(pdev);
return -ENODEV;
}
-
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (dev_multiq)
+ dev = alloc_etherdev_mq(sizeof(struct s2io_nic), tx_fifo_num);
+ else
+#endif
dev = alloc_etherdev(sizeof(struct s2io_nic));
if (dev == NULL) {
DBG_PRINT(ERR_DBG, "Device allocation failed\n");
config = &sp->config;
config->napi = napi;
+ config->tx_steering_type = tx_steering_type;
/* Tx side parameters. */
- config->tx_fifo_num = tx_fifo_num;
- for (i = 0; i < MAX_TX_FIFOS; i++) {
+ if (config->tx_steering_type == TX_PRIORITY_STEERING)
+ config->tx_fifo_num = MAX_TX_FIFOS;
+ else
+ config->tx_fifo_num = tx_fifo_num;
+
+ /* Initialize the fifos used for tx steering */
+ if (config->tx_fifo_num < 5) {
+ if (config->tx_fifo_num == 1)
+ sp->total_tcp_fifos = 1;
+ else
+ sp->total_tcp_fifos = config->tx_fifo_num - 1;
+ sp->udp_fifo_idx = config->tx_fifo_num - 1;
+ sp->total_udp_fifos = 1;
+ sp->other_fifo_idx = sp->total_tcp_fifos - 1;
+ } else {
+ sp->total_tcp_fifos = (tx_fifo_num - FIFO_UDP_MAX_NUM -
+ FIFO_OTHER_MAX_NUM);
+ sp->udp_fifo_idx = sp->total_tcp_fifos;
+ sp->total_udp_fifos = FIFO_UDP_MAX_NUM;
+ sp->other_fifo_idx = sp->udp_fifo_idx + FIFO_UDP_MAX_NUM;
+ }
+
+ config->multiq = dev_multiq;
+ for (i = 0; i < config->tx_fifo_num; i++) {
config->tx_cfg[i].fifo_len = tx_fifo_len[i];
config->tx_cfg[i].fifo_priority = i;
}
/* mapping the QoS priority to the configured fifos */
for (i = 0; i < MAX_TX_FIFOS; i++)
- config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i];
+ config->fifo_mapping[i] = fifo_map[config->tx_fifo_num - 1][i];
+
+ /* map the hashing selector table to the configured fifos */
+ for (i = 0; i < config->tx_fifo_num; i++)
+ sp->fifo_selector[i] = fifo_selector[i];
+
config->tx_intr_type = TXD_INT_TYPE_UTILZ;
for (i = 0; i < config->tx_fifo_num; i++) {
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
dev->vlan_rx_register = s2io_vlan_rx_register;
+ dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid;
/*
* will use eth_mac_addr() for dev->set_mac_address
dev->features |= NETIF_F_UFO;
dev->features |= NETIF_F_HW_CSUM;
}
-
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (config->multiq)
+ dev->features |= NETIF_F_MULTI_QUEUE;
+#endif
dev->tx_timeout = &s2io_tx_watchdog;
dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
INIT_WORK(&sp->rst_timer_task, s2io_restart_nic);
*/
bar0 = sp->bar0;
val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
- RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
+ RMAC_ADDR_CMD_MEM_OFFSET(0 + S2IO_MAC_ADDR_START_OFFSET);
writeq(val64, &bar0->rmac_addr_cmd_mem);
wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET);
memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
+ /* initialize number of multicast & unicast MAC entries variables */
+ if (sp->device_type == XFRAME_I_DEVICE) {
+ config->max_mc_addr = S2IO_XENA_MAX_MC_ADDRESSES;
+ config->max_mac_addr = S2IO_XENA_MAX_MAC_ADDRESSES;
+ config->mc_start_offset = S2IO_XENA_MC_ADDR_START_OFFSET;
+ } else if (sp->device_type == XFRAME_II_DEVICE) {
+ config->max_mc_addr = S2IO_HERC_MAX_MC_ADDRESSES;
+ config->max_mac_addr = S2IO_HERC_MAX_MAC_ADDRESSES;
+ config->mc_start_offset = S2IO_HERC_MC_ADDR_START_OFFSET;
+ }
+
+ /* store mac addresses from CAM to s2io_nic structure */
+ do_s2io_store_unicast_mc(sp);
+
/* Store the values of the MSIX table in the s2io_nic structure */
store_xmsi_data(sp);
/* reset Nic and bring it to known state */
s2io_reset(sp);
/*
- * Initialize the tasklet status and link state flags
+ * Initialize link state flags
* and the card state parameter
*/
- sp->tasklet_status = 0;
sp->state = 0;
/* Initialize spinlocks */
- spin_lock_init(&sp->tx_lock);
-
- if (!napi)
- spin_lock_init(&sp->put_lock);
- spin_lock_init(&sp->rx_lock);
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ spin_lock_init(&mac_control->fifos[i].tx_lock);
/*
* SXE-002: Configure link and activity LED to init state
if (napi)
DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
+
+ DBG_PRINT(ERR_DBG, "%s: Using %d Tx fifo(s)\n", dev->name,
+ sp->config.tx_fifo_num);
+
switch(sp->config.intr_type) {
case INTA:
DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
break;
}
+ if (sp->config.multiq) {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ mac_control->fifos[i].multiq = config->multiq;
+ DBG_PRINT(ERR_DBG, "%s: Multiqueue support enabled\n",
+ dev->name);
+ } else
+ DBG_PRINT(ERR_DBG, "%s: Multiqueue support disabled\n",
+ dev->name);
+
+ switch (sp->config.tx_steering_type) {
+ case NO_STEERING:
+ DBG_PRINT(ERR_DBG, "%s: No steering enabled for"
+ " transmit\n", dev->name);
+ break;
+ case TX_PRIORITY_STEERING:
+ DBG_PRINT(ERR_DBG, "%s: Priority steering enabled for"
+ " transmit\n", dev->name);
+ break;
+ case TX_DEFAULT_STEERING:
+ DBG_PRINT(ERR_DBG, "%s: Default steering enabled for"
+ " transmit\n", dev->name);
+ }
+
if (sp->lro)
DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
dev->name);
module_exit(s2io_closer);
static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
- struct tcphdr **tcp, struct RxD_t *rxdp)
+ struct tcphdr **tcp, struct RxD_t *rxdp,
+ struct s2io_nic *sp)
{
int ip_off;
u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
return -1;
}
- /* TODO:
- * By default the VLAN field in the MAC is stripped by the card, if this
- * feature is turned off in rx_pa_cfg register, then the ip_off field
- * has to be shifted by a further 2 bytes
- */
- switch (l2_type) {
- case 0: /* DIX type */
- case 4: /* DIX type with VLAN */
- ip_off = HEADER_ETHERNET_II_802_3_SIZE;
- break;
+ /* Checking for DIX type or DIX type with VLAN */
+ if ((l2_type == 0)
+ || (l2_type == 4)) {
+ ip_off = HEADER_ETHERNET_II_802_3_SIZE;
+ /*
+ * If vlan stripping is disabled and the frame is VLAN tagged,
+ * shift the offset by the VLAN header size bytes.
+ */
+ if ((!vlan_strip_flag) &&
+ (rxdp->Control_1 & RXD_FRAME_VLAN_TAG))
+ ip_off += HEADER_VLAN_SIZE;
+ } else {
/* LLC, SNAP etc are considered non-mergeable */
- default:
- return -1;
+ return -1;
}
*ip = (struct iphdr *)((u8 *)buffer + ip_off);
}
static void initiate_new_session(struct lro *lro, u8 *l2h,
- struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
+ struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len, u16 vlan_tag)
{
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
lro->l2h = l2h;
lro->iph = ip;
lro->tcph = tcp;
lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq);
- lro->tcp_ack = ntohl(tcp->ack_seq);
+ lro->tcp_ack = tcp->ack_seq;
lro->sg_num = 1;
lro->total_len = ntohs(ip->tot_len);
lro->frags_len = 0;
+ lro->vlan_tag = vlan_tag;
/*
* check if we saw TCP timestamp. Other consistency checks have
* already been done.
*/
if (tcp->doff == 8) {
- u32 *ptr;
- ptr = (u32 *)(tcp+1);
+ __be32 *ptr;
+ ptr = (__be32 *)(tcp+1);
lro->saw_ts = 1;
- lro->cur_tsval = *(ptr+1);
+ lro->cur_tsval = ntohl(*(ptr+1));
lro->cur_tsecr = *(ptr+2);
}
lro->in_use = 1;
/* Update tsecr field if this session has timestamps enabled */
if (lro->saw_ts) {
- u32 *ptr = (u32 *)(tcp + 1);
+ __be32 *ptr = (__be32 *)(tcp + 1);
*(ptr+2) = lro->cur_tsecr;
}
lro->window = tcp->window;
if (lro->saw_ts) {
- u32 *ptr;
+ __be32 *ptr;
/* Update tsecr and tsval from this packet */
- ptr = (u32 *) (tcp + 1);
- lro->cur_tsval = *(ptr + 1);
+ ptr = (__be32 *)(tcp+1);
+ lro->cur_tsval = ntohl(*(ptr+1));
lro->cur_tsecr = *(ptr + 2);
}
}
/* Ensure timestamp value increases monotonically */
if (l_lro)
- if (l_lro->cur_tsval > *((u32 *)(ptr+2)))
+ if (l_lro->cur_tsval > ntohl(*((__be32 *)(ptr+2))))
return -1;
/* timestamp echo reply should be non-zero */
- if (*((u32 *)(ptr+6)) == 0)
+ if (*((__be32 *)(ptr+6)) == 0)
return -1;
}
struct iphdr *ip;
struct tcphdr *tcph;
int ret = 0, i;
+ u16 vlan_tag = 0;
if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp,
- rxdp))) {
+ rxdp, sp))) {
DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n",
ip->saddr, ip->daddr);
- } else {
+ } else
return ret;
- }
+ vlan_tag = RXD_GET_VLAN_TAG(rxdp->Control_2);
tcph = (struct tcphdr *)*tcp;
*tcp_len = get_l4_pyld_length(ip, tcph);
for (i=0; i<MAX_LRO_SESSIONS; i++) {
switch (ret) {
case 3:
- initiate_new_session(*lro, buffer, ip, tcph, *tcp_len);
+ initiate_new_session(*lro, buffer, ip, tcph, *tcp_len,
+ vlan_tag);
break;
case 2:
update_L3L4_header(sp, *lro);
memset(lro, 0, lro_struct_size);
}
-static void queue_rx_frame(struct sk_buff *skb)
+static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag)
{
struct net_device *dev = skb->dev;
+ struct s2io_nic *sp = dev->priv;
skb->protocol = eth_type_trans(skb, dev);
- if (napi)
- netif_receive_skb(skb);
- else
- netif_rx(skb);
+ if (sp->vlgrp && vlan_tag
+ && (vlan_strip_flag)) {
+ /* Queueing the vlan frame to the upper layer */
+ if (sp->config.napi)
+ vlan_hwaccel_receive_skb(skb, sp->vlgrp, vlan_tag);
+ else
+ vlan_hwaccel_rx(skb, sp->vlgrp, vlan_tag);
+ } else {
+ if (sp->config.napi)
+ netif_receive_skb(skb);
+ else
+ netif_rx(skb);
+ }
}
static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,