#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "Version 2.0.9.3"
+#define DRV_VERSION "Version 2.0.9.4"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
config->tx_cfg[i].fifo_len - 1;
mac_control->fifos[i].fifo_no = i;
mac_control->fifos[i].nic = nic;
- mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 1;
+ mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 2;
for (j = 0; j < page_num; j++) {
int k = 0;
}
}
+ nic->ufo_in_band_v = kmalloc((sizeof(u64) * size), GFP_KERNEL);
+ if (!nic->ufo_in_band_v)
+ return -ENOMEM;
+
/* Allocation and initialization of RXDs in Rings */
size = 0;
for (i = 0; i < config->rx_ring_num; i++) {
mac_control->stats_mem,
mac_control->stats_mem_phy);
}
+ if (nic->ufo_in_band_v)
+ kfree(nic->ufo_in_band_v);
}
/**
return SUCCESS;
}
+/**
+ * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb
+ */
+static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, int get_off)
+{
+ nic_t *nic = fifo_data->nic;
+ struct sk_buff *skb;
+ TxD_t *txds;
+ u16 j, frg_cnt;
+
+ txds = txdlp;
+ if (txds->Host_Control == (u64) nic->ufo_in_band_v) {
+ pci_unmap_single(nic->pdev, (dma_addr_t)
+ txds->Buffer_Pointer, sizeof(u64),
+ PCI_DMA_TODEVICE);
+ txds++;
+ }
+
+ skb = (struct sk_buff *) ((unsigned long)
+ txds->Host_Control);
+ if (!skb) {
+ memset(txdlp, 0, (sizeof(TxD_t) * fifo_data->max_txds));
+ return NULL;
+ }
+ pci_unmap_single(nic->pdev, (dma_addr_t)
+ txds->Buffer_Pointer,
+ skb->len - skb->data_len,
+ PCI_DMA_TODEVICE);
+ frg_cnt = skb_shinfo(skb)->nr_frags;
+ if (frg_cnt) {
+ txds++;
+ for (j = 0; j < frg_cnt; j++, txds++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[j];
+ if (!txds->Buffer_Pointer)
+ break;
+ pci_unmap_page(nic->pdev, (dma_addr_t)
+ txds->Buffer_Pointer,
+ frag->size, PCI_DMA_TODEVICE);
+ }
+ }
+ txdlp->Host_Control = 0;
+ return(skb);
+}
/**
* free_tx_buffers - Free all queued Tx buffers
int i, j;
mac_info_t *mac_control;
struct config_param *config;
- int cnt = 0, frg_cnt;
+ int cnt = 0;
mac_control = &nic->mac_control;
config = &nic->config;
for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
list_virt_addr;
- skb =
- (struct sk_buff *) ((unsigned long) txdp->
- Host_Control);
- if (skb == NULL) {
- memset(txdp, 0, sizeof(TxD_t) *
- config->max_txds);
- continue;
- }
- frg_cnt = skb_shinfo(skb)->nr_frags;
- pci_unmap_single(nic->pdev, (dma_addr_t)
- txdp->Buffer_Pointer,
- skb->len - skb->data_len,
- PCI_DMA_TODEVICE);
- if (frg_cnt) {
- TxD_t *temp;
- temp = txdp;
- txdp++;
- for (j = 0; j < frg_cnt; j++, txdp++) {
- skb_frag_t *frag =
- &skb_shinfo(skb)->frags[j];
- pci_unmap_page(nic->pdev,
- (dma_addr_t)
- txdp->
- Buffer_Pointer,
- frag->size,
- PCI_DMA_TODEVICE);
- }
- txdp = temp;
+ skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
+ if (skb) {
+ dev_kfree_skb(skb);
+ cnt++;
}
- dev_kfree_skb(skb);
- memset(txdp, 0, sizeof(TxD_t) * config->max_txds);
- cnt++;
}
DBG_PRINT(INTR_DBG,
"%s:forcibly freeing %d skbs on FIFO%d\n",
tx_curr_get_info_t get_info, put_info;
struct sk_buff *skb;
TxD_t *txdlp;
- u16 j, frg_cnt;
get_info = fifo_data->tx_curr_get_info;
put_info = fifo_data->tx_curr_put_info;
}
}
- skb = (struct sk_buff *) ((unsigned long)
- txdlp->Host_Control);
+ skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
if (skb == NULL) {
DBG_PRINT(ERR_DBG, "%s: Null skb ",
__FUNCTION__);
return;
}
- frg_cnt = skb_shinfo(skb)->nr_frags;
- nic->tx_pkt_count++;
-
- pci_unmap_single(nic->pdev, (dma_addr_t)
- txdlp->Buffer_Pointer,
- skb->len - skb->data_len,
- PCI_DMA_TODEVICE);
- if (frg_cnt) {
- TxD_t *temp;
- temp = txdlp;
- txdlp++;
- for (j = 0; j < frg_cnt; j++, txdlp++) {
- skb_frag_t *frag =
- &skb_shinfo(skb)->frags[j];
- if (!txdlp->Buffer_Pointer)
- break;
- pci_unmap_page(nic->pdev,
- (dma_addr_t)
- txdlp->
- Buffer_Pointer,
- frag->size,
- PCI_DMA_TODEVICE);
- }
- txdlp = temp;
- }
- memset(txdlp, 0,
- (sizeof(TxD_t) * fifo_data->max_txds));
-
/* Updating the statistics block */
nic->stats.tx_bytes += skb->len;
dev_kfree_skb_irq(skb);
return 0;
}
+ txdp->Control_1 = 0;
+ txdp->Control_2 = 0;
#ifdef NETIF_F_TSO
mss = skb_shinfo(skb)->tso_size;
if (mss) {
txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
}
#endif
-
- frg_cnt = skb_shinfo(skb)->nr_frags;
- frg_len = skb->len - skb->data_len;
-
- txdp->Buffer_Pointer = pci_map_single
- (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
- txdp->Host_Control = (unsigned long) skb;
if (skb->ip_summed == CHECKSUM_HW) {
txdp->Control_2 |=
(TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
TXD_TX_CKO_UDP_EN);
}
-
+ 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_VLAN_TAG(vlan_tag);
}
- txdp->Control_1 |= (TXD_BUFFER0_SIZE(frg_len) |
- TXD_GATHER_CODE_FIRST);
- txdp->Control_1 |= TXD_LIST_OWN_XENA;
+ frg_len = skb->len - skb->data_len;
+ if (skb_shinfo(skb)->ufo_size) {
+ int ufo_size;
+
+ ufo_size = skb_shinfo(skb)->ufo_size;
+ ufo_size &= ~7;
+ txdp->Control_1 |= TXD_UFO_EN;
+ 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;
+#else
+ sp->ufo_in_band_v[put_off] =
+ (u64)skb_shinfo(skb)->ip6_frag_id << 32;
+#endif
+ txdp->Host_Control = (unsigned long)sp->ufo_in_band_v;
+ txdp->Buffer_Pointer = pci_map_single(sp->pdev,
+ sp->ufo_in_band_v,
+ sizeof(u64), PCI_DMA_TODEVICE);
+ txdp++;
+ txdp->Control_1 = 0;
+ txdp->Control_2 = 0;
+ }
+
+ txdp->Buffer_Pointer = pci_map_single
+ (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
+ txdp->Host_Control = (unsigned long) skb;
+ txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
+ if (skb_shinfo(skb)->ufo_size)
+ txdp->Control_1 |= TXD_UFO_EN;
+
+ frg_cnt = skb_shinfo(skb)->nr_frags;
/* For fragmented SKB. */
for (i = 0; i < frg_cnt; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
(sp->pdev, frag->page, frag->page_offset,
frag->size, PCI_DMA_TODEVICE);
txdp->Control_1 |= TXD_BUFFER0_SIZE(frag->size);
+ if (skb_shinfo(skb)->ufo_size)
+ txdp->Control_1 |= TXD_UFO_EN;
}
txdp->Control_1 |= TXD_GATHER_CODE_LAST;
+ if (skb_shinfo(skb)->ufo_size)
+ 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;
writeq(val64, &tx_fifo->TxDL_Pointer);
if (mss)
val64 |= TX_FIFO_SPECIAL_FUNC;
#endif
+ if (skb_shinfo(skb)->ufo_size)
+ val64 |= TX_FIFO_SPECIAL_FUNC;
writeq(val64, &tx_fifo->List_Control);
mmiowb();
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
#endif
+ .get_ufo = ethtool_op_get_ufo,
+ .set_ufo = ethtool_op_set_ufo,
.self_test_count = s2io_ethtool_self_test_count,
.self_test = s2io_ethtool_test,
.get_strings = s2io_ethtool_get_strings,
break;
}
}
- config->max_txds = MAX_SKB_FRAGS + 1;
+ /* + 2 because one Txd for skb->data and one Txd for UFO */
+ config->max_txds = MAX_SKB_FRAGS + 2;
/* Rx side parameters. */
if (rx_ring_sz[0] == 0)
#ifdef NETIF_F_TSO
dev->features |= NETIF_F_TSO;
#endif
+ if (sp->device_type & XFRAME_II_DEVICE) {
+ dev->features |= NETIF_F_UFO;
+ dev->features |= NETIF_F_HW_CSUM;
+ }
dev->tx_timeout = &s2io_tx_watchdog;
dev->watchdog_timeo = WATCH_DOG_TIMEOUT;