Commit 391587c3 authored by Dhananjay Phadke's avatar Dhananjay Phadke Committed by David S. Miller

netxen: fix ipv6 offload and tx cleanup

o fix the ip/tcp hdr offset in tx descriptors for ipv6.
o cleanup xmit function, move the tso checks into separate function,
  this reduces unnecessary endian conversions back and forth.
o optimize macros to initialize tx descriptors.
Signed-off-by: default avatarDhananjay Phadke <dhananjay@netxen.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2edbb454
...@@ -308,27 +308,16 @@ struct netxen_ring_ctx { ...@@ -308,27 +308,16 @@ struct netxen_ring_ctx {
#define netxen_set_cmd_desc_ctxid(cmd_desc, var) \ #define netxen_set_cmd_desc_ctxid(cmd_desc, var) \
((cmd_desc)->port_ctxid |= ((var) << 4 & 0xF0)) ((cmd_desc)->port_ctxid |= ((var) << 4 & 0xF0))
#define netxen_set_cmd_desc_flags(cmd_desc, val) \ #define netxen_set_tx_port(_desc, _port) \
(cmd_desc)->flags_opcode = ((cmd_desc)->flags_opcode & \ (_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0)
~cpu_to_le16(0x7f)) | cpu_to_le16((val) & 0x7f)
#define netxen_set_cmd_desc_opcode(cmd_desc, val) \ #define netxen_set_tx_flags_opcode(_desc, _flags, _opcode) \
(cmd_desc)->flags_opcode = ((cmd_desc)->flags_opcode & \ (_desc)->flags_opcode = \
~cpu_to_le16((u16)0x3f << 7)) | cpu_to_le16(((val) & 0x3f) << 7) cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7))
#define netxen_set_cmd_desc_num_of_buff(cmd_desc, val) \ #define netxen_set_tx_frags_len(_desc, _frags, _len) \
(cmd_desc)->num_of_buffers_total_length = \ (_desc)->num_of_buffers_total_length = \
((cmd_desc)->num_of_buffers_total_length & \ cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8))
~cpu_to_le32(0xff)) | cpu_to_le32((val) & 0xff)
#define netxen_set_cmd_desc_totallength(cmd_desc, val) \
(cmd_desc)->num_of_buffers_total_length = \
((cmd_desc)->num_of_buffers_total_length & \
~cpu_to_le32((u32)0xffffff << 8)) | \
cpu_to_le32(((val) & 0xffffff) << 8)
#define netxen_get_cmd_desc_opcode(cmd_desc) \
((le16_to_cpu((cmd_desc)->flags_opcode) >> 7) & 0x003f)
#define netxen_get_cmd_desc_totallength(cmd_desc) \
((le32_to_cpu((cmd_desc)->num_of_buffers_total_length) >> 8) & 0xffffff)
struct cmd_desc_type0 { struct cmd_desc_type0 {
u8 tcp_hdr_offset; /* For LSO only */ u8 tcp_hdr_offset; /* For LSO only */
...@@ -757,7 +746,7 @@ extern char netxen_nic_driver_name[]; ...@@ -757,7 +746,7 @@ extern char netxen_nic_driver_name[];
*/ */
struct netxen_skb_frag { struct netxen_skb_frag {
u64 dma; u64 dma;
u32 length; ulong length;
}; };
#define _netxen_set_bits(config_word, start, bits, val) {\ #define _netxen_set_bits(config_word, start, bits, val) {\
...@@ -783,13 +772,7 @@ struct netxen_skb_frag { ...@@ -783,13 +772,7 @@ struct netxen_skb_frag {
struct netxen_cmd_buffer { struct netxen_cmd_buffer {
struct sk_buff *skb; struct sk_buff *skb;
struct netxen_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1]; struct netxen_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1];
u32 total_length; u32 frag_count;
u32 mss;
u16 port;
u8 cmd;
u8 frag_count;
unsigned long time_stamp;
u32 state;
}; };
/* In rx_buffer, we do not need multiple fragments as is a single buffer */ /* In rx_buffer, we do not need multiple fragments as is a single buffer */
...@@ -1486,8 +1469,6 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter); ...@@ -1486,8 +1469,6 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter);
void netxen_initialize_adapter_ops(struct netxen_adapter *adapter); void netxen_initialize_adapter_ops(struct netxen_adapter *adapter);
int netxen_init_firmware(struct netxen_adapter *adapter); int netxen_init_firmware(struct netxen_adapter *adapter);
void netxen_tso_check(struct netxen_adapter *adapter,
struct cmd_desc_type0 *desc, struct sk_buff *skb);
void netxen_nic_clear_stats(struct netxen_adapter *adapter); void netxen_nic_clear_stats(struct netxen_adapter *adapter);
void netxen_watchdog_task(struct work_struct *work); void netxen_watchdog_task(struct work_struct *work);
void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx,
......
...@@ -508,12 +508,8 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter, ...@@ -508,12 +508,8 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter,
cmd_desc = &cmd_desc_arr[i]; cmd_desc = &cmd_desc_arr[i];
pbuf = &adapter->cmd_buf_arr[producer]; pbuf = &adapter->cmd_buf_arr[producer];
pbuf->mss = 0;
pbuf->total_length = 0;
pbuf->skb = NULL; pbuf->skb = NULL;
pbuf->cmd = 0;
pbuf->frag_count = 0; pbuf->frag_count = 0;
pbuf->port = 0;
/* adapter->ahw.cmd_desc_head[producer] = *cmd_desc; */ /* adapter->ahw.cmd_desc_head[producer] = *cmd_desc; */
memcpy(&adapter->ahw.cmd_desc_head[producer], memcpy(&adapter->ahw.cmd_desc_head[producer],
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include "netxen_nic_phan_reg.h" #include "netxen_nic_phan_reg.h"
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/if_vlan.h>
#include <net/ip.h> #include <net/ip.h>
MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver"); MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
...@@ -1137,29 +1138,46 @@ static int netxen_nic_close(struct net_device *netdev) ...@@ -1137,29 +1138,46 @@ static int netxen_nic_close(struct net_device *netdev)
return 0; return 0;
} }
void netxen_tso_check(struct netxen_adapter *adapter, static bool netxen_tso_check(struct net_device *netdev,
struct cmd_desc_type0 *desc, struct sk_buff *skb) struct cmd_desc_type0 *desc, struct sk_buff *skb)
{ {
if (desc->mss) { bool tso = false;
desc->total_hdr_length = (sizeof(struct ethhdr) + u8 opcode = TX_ETHER_PKT;
ip_hdrlen(skb) + tcp_hdrlen(skb));
if ((NX_IS_REVISION_P3(adapter->ahw.revision_id)) && if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
(skb->protocol == htons(ETH_P_IPV6))) skb_shinfo(skb)->gso_size > 0) {
netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO6);
else desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO); desc->total_hdr_length =
skb_transport_offset(skb) + tcp_hdrlen(skb);
opcode = (skb->protocol == htons(ETH_P_IPV6)) ?
TX_TCP_LSO6 : TX_TCP_LSO;
tso = true;
} else if (skb->ip_summed == CHECKSUM_PARTIAL) { } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (ip_hdr(skb)->protocol == IPPROTO_TCP) u8 l4proto;
netxen_set_cmd_desc_opcode(desc, TX_TCP_PKT);
else if (ip_hdr(skb)->protocol == IPPROTO_UDP) if (skb->protocol == htons(ETH_P_IP)) {
netxen_set_cmd_desc_opcode(desc, TX_UDP_PKT); l4proto = ip_hdr(skb)->protocol;
else
return; if (l4proto == IPPROTO_TCP)
opcode = TX_TCP_PKT;
else if(l4proto == IPPROTO_UDP)
opcode = TX_UDP_PKT;
} else if (skb->protocol == htons(ETH_P_IPV6)) {
l4proto = ipv6_hdr(skb)->nexthdr;
if (l4proto == IPPROTO_TCP)
opcode = TX_TCPV6_PKT;
else if(l4proto == IPPROTO_UDP)
opcode = TX_UDPV6_PKT;
}
} }
desc->tcp_hdr_offset = skb_transport_offset(skb); desc->tcp_hdr_offset = skb_transport_offset(skb);
desc->ip_hdr_offset = skb_network_offset(skb); desc->ip_hdr_offset = skb_network_offset(skb);
netxen_set_tx_flags_opcode(desc, 0, opcode);
return tso;
} }
static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
...@@ -1167,33 +1185,20 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) ...@@ -1167,33 +1185,20 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
struct netxen_adapter *adapter = netdev_priv(netdev); struct netxen_adapter *adapter = netdev_priv(netdev);
struct netxen_hardware_context *hw = &adapter->ahw; struct netxen_hardware_context *hw = &adapter->ahw;
unsigned int first_seg_len = skb->len - skb->data_len; unsigned int first_seg_len = skb->len - skb->data_len;
struct netxen_cmd_buffer *pbuf;
struct netxen_skb_frag *buffrag; struct netxen_skb_frag *buffrag;
unsigned int i; struct cmd_desc_type0 *hwdesc;
int i, k;
u32 producer, consumer; u32 producer, consumer;
u32 saved_producer = 0; int frag_count, no_of_desc;
struct cmd_desc_type0 *hwdesc;
int k;
struct netxen_cmd_buffer *pbuf = NULL;
int frag_count;
int no_of_desc;
u32 num_txd = adapter->max_tx_desc_count; u32 num_txd = adapter->max_tx_desc_count;
bool is_tso = false;
frag_count = skb_shinfo(skb)->nr_frags + 1; frag_count = skb_shinfo(skb)->nr_frags + 1;
/* There 4 fragments per descriptor */ /* There 4 fragments per descriptor */
no_of_desc = (frag_count + 3) >> 2; no_of_desc = (frag_count + 3) >> 2;
if (netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) {
if (skb_shinfo(skb)->gso_size > 0) {
no_of_desc++;
if ((ip_hdrlen(skb) + tcp_hdrlen(skb) +
sizeof(struct ethhdr)) >
(sizeof(struct cmd_desc_type0) - 2)) {
no_of_desc++;
}
}
}
producer = adapter->cmd_producer; producer = adapter->cmd_producer;
smp_mb(); smp_mb();
...@@ -1205,34 +1210,22 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) ...@@ -1205,34 +1210,22 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
} }
/* Copy the descriptors into the hardware */ /* Copy the descriptors into the hardware */
saved_producer = producer;
hwdesc = &hw->cmd_desc_head[producer]; hwdesc = &hw->cmd_desc_head[producer];
memset(hwdesc, 0, sizeof(struct cmd_desc_type0)); memset(hwdesc, 0, sizeof(struct cmd_desc_type0));
/* Take skb->data itself */ /* Take skb->data itself */
pbuf = &adapter->cmd_buf_arr[producer]; pbuf = &adapter->cmd_buf_arr[producer];
if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
skb_shinfo(skb)->gso_size > 0) { is_tso = netxen_tso_check(netdev, hwdesc, skb);
pbuf->mss = skb_shinfo(skb)->gso_size;
hwdesc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
} else {
pbuf->mss = 0;
hwdesc->mss = 0;
}
pbuf->total_length = skb->len;
pbuf->skb = skb; pbuf->skb = skb;
pbuf->cmd = TX_ETHER_PKT;
pbuf->frag_count = frag_count; pbuf->frag_count = frag_count;
pbuf->port = adapter->portnum;
buffrag = &pbuf->frag_array[0]; buffrag = &pbuf->frag_array[0];
buffrag->dma = pci_map_single(adapter->pdev, skb->data, first_seg_len, buffrag->dma = pci_map_single(adapter->pdev, skb->data, first_seg_len,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
buffrag->length = first_seg_len; buffrag->length = first_seg_len;
netxen_set_cmd_desc_totallength(hwdesc, skb->len); netxen_set_tx_frags_len(hwdesc, frag_count, skb->len);
netxen_set_cmd_desc_num_of_buff(hwdesc, frag_count); netxen_set_tx_port(hwdesc, adapter->portnum);
netxen_set_cmd_desc_opcode(hwdesc, TX_ETHER_PKT);
netxen_set_cmd_desc_port(hwdesc, adapter->portnum);
netxen_set_cmd_desc_ctxid(hwdesc, adapter->portnum);
hwdesc->buffer1_length = cpu_to_le16(first_seg_len); hwdesc->buffer1_length = cpu_to_le16(first_seg_len);
hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
...@@ -1285,16 +1278,12 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) ...@@ -1285,16 +1278,12 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
} }
producer = get_next_index(producer, num_txd); producer = get_next_index(producer, num_txd);
/* might change opcode to TX_TCP_LSO */
netxen_tso_check(adapter, &hw->cmd_desc_head[saved_producer], skb);
/* For LSO, we need to copy the MAC/IP/TCP headers into /* For LSO, we need to copy the MAC/IP/TCP headers into
* the descriptor ring * the descriptor ring
*/ */
if (netxen_get_cmd_desc_opcode(&hw->cmd_desc_head[saved_producer]) if (is_tso) {
== TX_TCP_LSO) {
int hdr_len, first_hdr_len, more_hdr; int hdr_len, first_hdr_len, more_hdr;
hdr_len = hw->cmd_desc_head[saved_producer].total_hdr_length; hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
if (hdr_len > (sizeof(struct cmd_desc_type0) - 2)) { if (hdr_len > (sizeof(struct cmd_desc_type0) - 2)) {
first_hdr_len = sizeof(struct cmd_desc_type0) - 2; first_hdr_len = sizeof(struct cmd_desc_type0) - 2;
more_hdr = 1; more_hdr = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment