[PATCH] s2io: UFO support
This patch implements the UFO support in S2io driver. This patch uses the UFO interface available in linux-2.6.15 kernel. Signed-off-by: Ananda Raju <ananda.raju@neterion.com> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
This commit is contained in:
parent
1f8fc99300
commit
fed5eccdcf
|
@ -66,7 +66,7 @@
|
||||||
#include "s2io.h"
|
#include "s2io.h"
|
||||||
#include "s2io-regs.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. */
|
/* S2io Driver name & version. */
|
||||||
static char s2io_driver_name[] = "Neterion";
|
static char s2io_driver_name[] = "Neterion";
|
||||||
|
@ -412,7 +412,7 @@ static int init_shared_mem(struct s2io_nic *nic)
|
||||||
config->tx_cfg[i].fifo_len - 1;
|
config->tx_cfg[i].fifo_len - 1;
|
||||||
mac_control->fifos[i].fifo_no = i;
|
mac_control->fifos[i].fifo_no = i;
|
||||||
mac_control->fifos[i].nic = nic;
|
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++) {
|
for (j = 0; j < page_num; j++) {
|
||||||
int k = 0;
|
int k = 0;
|
||||||
|
@ -459,6 +459,10 @@ static int init_shared_mem(struct s2io_nic *nic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 */
|
/* Allocation and initialization of RXDs in Rings */
|
||||||
size = 0;
|
size = 0;
|
||||||
for (i = 0; i < config->rx_ring_num; i++) {
|
for (i = 0; i < config->rx_ring_num; i++) {
|
||||||
|
@ -731,6 +735,8 @@ static void free_shared_mem(struct s2io_nic *nic)
|
||||||
mac_control->stats_mem,
|
mac_control->stats_mem,
|
||||||
mac_control->stats_mem_phy);
|
mac_control->stats_mem_phy);
|
||||||
}
|
}
|
||||||
|
if (nic->ufo_in_band_v)
|
||||||
|
kfree(nic->ufo_in_band_v);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2003,6 +2009,49 @@ static int start_nic(struct s2io_nic *nic)
|
||||||
|
|
||||||
return SUCCESS;
|
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
|
* free_tx_buffers - Free all queued Tx buffers
|
||||||
|
@ -2020,7 +2069,7 @@ static void free_tx_buffers(struct s2io_nic *nic)
|
||||||
int i, j;
|
int i, j;
|
||||||
mac_info_t *mac_control;
|
mac_info_t *mac_control;
|
||||||
struct config_param *config;
|
struct config_param *config;
|
||||||
int cnt = 0, frg_cnt;
|
int cnt = 0;
|
||||||
|
|
||||||
mac_control = &nic->mac_control;
|
mac_control = &nic->mac_control;
|
||||||
config = &nic->config;
|
config = &nic->config;
|
||||||
|
@ -2029,38 +2078,11 @@ static void free_tx_buffers(struct s2io_nic *nic)
|
||||||
for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
|
for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
|
||||||
txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
|
txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
|
||||||
list_virt_addr;
|
list_virt_addr;
|
||||||
skb =
|
skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
|
||||||
(struct sk_buff *) ((unsigned long) txdp->
|
if (skb) {
|
||||||
Host_Control);
|
dev_kfree_skb(skb);
|
||||||
if (skb == NULL) {
|
cnt++;
|
||||||
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;
|
|
||||||
}
|
|
||||||
dev_kfree_skb(skb);
|
|
||||||
memset(txdp, 0, sizeof(TxD_t) * config->max_txds);
|
|
||||||
cnt++;
|
|
||||||
}
|
}
|
||||||
DBG_PRINT(INTR_DBG,
|
DBG_PRINT(INTR_DBG,
|
||||||
"%s:forcibly freeing %d skbs on FIFO%d\n",
|
"%s:forcibly freeing %d skbs on FIFO%d\n",
|
||||||
|
@ -2661,7 +2683,6 @@ static void tx_intr_handler(fifo_info_t *fifo_data)
|
||||||
tx_curr_get_info_t get_info, put_info;
|
tx_curr_get_info_t get_info, put_info;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
TxD_t *txdlp;
|
TxD_t *txdlp;
|
||||||
u16 j, frg_cnt;
|
|
||||||
|
|
||||||
get_info = fifo_data->tx_curr_get_info;
|
get_info = fifo_data->tx_curr_get_info;
|
||||||
put_info = fifo_data->tx_curr_put_info;
|
put_info = fifo_data->tx_curr_put_info;
|
||||||
|
@ -2684,8 +2705,7 @@ to loss of link\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
skb = (struct sk_buff *) ((unsigned long)
|
skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
|
||||||
txdlp->Host_Control);
|
|
||||||
if (skb == NULL) {
|
if (skb == NULL) {
|
||||||
DBG_PRINT(ERR_DBG, "%s: Null skb ",
|
DBG_PRINT(ERR_DBG, "%s: Null skb ",
|
||||||
__FUNCTION__);
|
__FUNCTION__);
|
||||||
|
@ -2693,34 +2713,6 @@ to loss of link\n");
|
||||||
return;
|
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 */
|
/* Updating the statistics block */
|
||||||
nic->stats.tx_bytes += skb->len;
|
nic->stats.tx_bytes += skb->len;
|
||||||
dev_kfree_skb_irq(skb);
|
dev_kfree_skb_irq(skb);
|
||||||
|
@ -3527,6 +3519,8 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
txdp->Control_1 = 0;
|
||||||
|
txdp->Control_2 = 0;
|
||||||
#ifdef NETIF_F_TSO
|
#ifdef NETIF_F_TSO
|
||||||
mss = skb_shinfo(skb)->tso_size;
|
mss = skb_shinfo(skb)->tso_size;
|
||||||
if (mss) {
|
if (mss) {
|
||||||
|
@ -3534,19 +3528,13 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
|
txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
if (skb->ip_summed == CHECKSUM_HW) {
|
||||||
txdp->Control_2 |=
|
txdp->Control_2 |=
|
||||||
(TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
|
(TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
|
||||||
TXD_TX_CKO_UDP_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;
|
txdp->Control_2 |= config->tx_intr_type;
|
||||||
|
|
||||||
if (sp->vlgrp && vlan_tx_tag_present(skb)) {
|
if (sp->vlgrp && vlan_tx_tag_present(skb)) {
|
||||||
|
@ -3554,10 +3542,40 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
|
txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
txdp->Control_1 |= (TXD_BUFFER0_SIZE(frg_len) |
|
frg_len = skb->len - skb->data_len;
|
||||||
TXD_GATHER_CODE_FIRST);
|
if (skb_shinfo(skb)->ufo_size) {
|
||||||
txdp->Control_1 |= TXD_LIST_OWN_XENA;
|
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 fragmented SKB. */
|
||||||
for (i = 0; i < frg_cnt; i++) {
|
for (i = 0; i < frg_cnt; i++) {
|
||||||
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
||||||
|
@ -3569,9 +3587,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
(sp->pdev, frag->page, frag->page_offset,
|
(sp->pdev, frag->page, frag->page_offset,
|
||||||
frag->size, PCI_DMA_TODEVICE);
|
frag->size, PCI_DMA_TODEVICE);
|
||||||
txdp->Control_1 |= TXD_BUFFER0_SIZE(frag->size);
|
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;
|
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];
|
tx_fifo = mac_control->tx_FIFO_start[queue];
|
||||||
val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
|
val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
|
||||||
writeq(val64, &tx_fifo->TxDL_Pointer);
|
writeq(val64, &tx_fifo->TxDL_Pointer);
|
||||||
|
@ -3583,6 +3606,8 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
if (mss)
|
if (mss)
|
||||||
val64 |= TX_FIFO_SPECIAL_FUNC;
|
val64 |= TX_FIFO_SPECIAL_FUNC;
|
||||||
#endif
|
#endif
|
||||||
|
if (skb_shinfo(skb)->ufo_size)
|
||||||
|
val64 |= TX_FIFO_SPECIAL_FUNC;
|
||||||
writeq(val64, &tx_fifo->List_Control);
|
writeq(val64, &tx_fifo->List_Control);
|
||||||
|
|
||||||
mmiowb();
|
mmiowb();
|
||||||
|
@ -5190,6 +5215,8 @@ static struct ethtool_ops netdev_ethtool_ops = {
|
||||||
.get_tso = ethtool_op_get_tso,
|
.get_tso = ethtool_op_get_tso,
|
||||||
.set_tso = ethtool_op_set_tso,
|
.set_tso = ethtool_op_set_tso,
|
||||||
#endif
|
#endif
|
||||||
|
.get_ufo = ethtool_op_get_ufo,
|
||||||
|
.set_ufo = ethtool_op_set_ufo,
|
||||||
.self_test_count = s2io_ethtool_self_test_count,
|
.self_test_count = s2io_ethtool_self_test_count,
|
||||||
.self_test = s2io_ethtool_test,
|
.self_test = s2io_ethtool_test,
|
||||||
.get_strings = s2io_ethtool_get_strings,
|
.get_strings = s2io_ethtool_get_strings,
|
||||||
|
@ -5941,7 +5968,8 @@ Defaulting to INTA\n");
|
||||||
break;
|
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. */
|
/* Rx side parameters. */
|
||||||
if (rx_ring_sz[0] == 0)
|
if (rx_ring_sz[0] == 0)
|
||||||
|
@ -6035,6 +6063,10 @@ Defaulting to INTA\n");
|
||||||
#ifdef NETIF_F_TSO
|
#ifdef NETIF_F_TSO
|
||||||
dev->features |= NETIF_F_TSO;
|
dev->features |= NETIF_F_TSO;
|
||||||
#endif
|
#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->tx_timeout = &s2io_tx_watchdog;
|
||||||
dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
|
dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
|
||||||
|
|
|
@ -393,7 +393,9 @@ typedef struct _TxD {
|
||||||
#define TXD_GATHER_CODE_LAST BIT(23)
|
#define TXD_GATHER_CODE_LAST BIT(23)
|
||||||
#define TXD_TCP_LSO_EN BIT(30)
|
#define TXD_TCP_LSO_EN BIT(30)
|
||||||
#define TXD_UDP_COF_EN BIT(31)
|
#define TXD_UDP_COF_EN BIT(31)
|
||||||
|
#define TXD_UFO_EN BIT(31) | BIT(30)
|
||||||
#define TXD_TCP_LSO_MSS(val) vBIT(val,34,14)
|
#define TXD_TCP_LSO_MSS(val) vBIT(val,34,14)
|
||||||
|
#define TXD_UFO_MSS(val) vBIT(val,34,14)
|
||||||
#define TXD_BUFFER0_SIZE(val) vBIT(val,48,16)
|
#define TXD_BUFFER0_SIZE(val) vBIT(val,48,16)
|
||||||
|
|
||||||
u64 Control_2;
|
u64 Control_2;
|
||||||
|
@ -789,6 +791,7 @@ struct s2io_nic {
|
||||||
|
|
||||||
spinlock_t rx_lock;
|
spinlock_t rx_lock;
|
||||||
atomic_t isr_cnt;
|
atomic_t isr_cnt;
|
||||||
|
u64 *ufo_in_band_v;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RESET_ERROR 1;
|
#define RESET_ERROR 1;
|
||||||
|
|
Loading…
Reference in New Issue