Commit 0ab05141 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller

hv_netvsc: rearrange start_xmit

Rearrange the transmit routine to eliminate goto's and unnecessary
boolean variables. Use standard functions to test for vlan tag.
Signed-off-by: default avatarStephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fd612602
...@@ -357,11 +357,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -357,11 +357,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
struct rndis_message *rndis_msg; struct rndis_message *rndis_msg;
struct rndis_packet *rndis_pkt; struct rndis_packet *rndis_pkt;
u32 rndis_msg_size; u32 rndis_msg_size;
bool isvlan;
bool linear = false;
struct rndis_per_packet_info *ppi; struct rndis_per_packet_info *ppi;
struct ndis_tcp_ip_checksum_info *csum_info; struct ndis_tcp_ip_checksum_info *csum_info;
struct ndis_tcp_lso_info *lso_info;
int hdr_offset; int hdr_offset;
u32 net_trans_info; u32 net_trans_info;
u32 hash; u32 hash;
...@@ -376,22 +373,23 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -376,22 +373,23 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
* more pages we try linearizing it. * more pages we try linearizing it.
*/ */
check_size:
skb_length = skb->len; skb_length = skb->len;
num_data_pgs = netvsc_get_slots(skb) + 2; num_data_pgs = netvsc_get_slots(skb) + 2;
if (num_data_pgs > MAX_PAGE_BUFFER_COUNT && linear) {
net_alert_ratelimited("packet too big: %u pages (%u bytes)\n", if (unlikely(num_data_pgs > MAX_PAGE_BUFFER_COUNT)) {
num_data_pgs, skb->len);
ret = -EFAULT;
goto drop;
} else if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
if (skb_linearize(skb)) { if (skb_linearize(skb)) {
net_alert_ratelimited("failed to linearize skb\n"); net_alert_ratelimited("failed to linearize skb\n");
ret = -ENOMEM; ret = -ENOMEM;
goto drop; goto drop;
} }
linear = true;
goto check_size; num_data_pgs = netvsc_get_slots(skb) + 2;
if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
net_alert_ratelimited("packet too big: %u pages (%u bytes)\n",
num_data_pgs, skb->len);
ret = -EFAULT;
goto drop;
}
} }
/* /*
...@@ -418,8 +416,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -418,8 +416,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
memset(rndis_msg, 0, RNDIS_AND_PPI_SIZE); memset(rndis_msg, 0, RNDIS_AND_PPI_SIZE);
isvlan = skb->vlan_tci & VLAN_TAG_PRESENT;
/* Add the rndis header */ /* Add the rndis header */
rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET; rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
rndis_msg->msg_len = packet->total_data_buflen; rndis_msg->msg_len = packet->total_data_buflen;
...@@ -438,7 +434,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -438,7 +434,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
*(u32 *)((void *)ppi + ppi->ppi_offset) = hash; *(u32 *)((void *)ppi + ppi->ppi_offset) = hash;
} }
if (isvlan) { if (skb_vlan_tag_present(skb)) {
struct ndis_pkt_8021q_info *vlan; struct ndis_pkt_8021q_info *vlan;
rndis_msg_size += NDIS_VLAN_PPI_SIZE; rndis_msg_size += NDIS_VLAN_PPI_SIZE;
...@@ -459,8 +455,37 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -459,8 +455,37 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
* Setup the sendside checksum offload only if this is not a * Setup the sendside checksum offload only if this is not a
* GSO packet. * GSO packet.
*/ */
if (skb_is_gso(skb)) if (skb_is_gso(skb)) {
goto do_lso; struct ndis_tcp_lso_info *lso_info;
rndis_msg_size += NDIS_LSO_PPI_SIZE;
ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE,
TCP_LARGESEND_PKTINFO);
lso_info = (struct ndis_tcp_lso_info *)((void *)ppi +
ppi->ppi_offset);
lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE;
if (net_trans_info & (INFO_IPV4 << 16)) {
lso_info->lso_v2_transmit.ip_version =
NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4;
ip_hdr(skb)->tot_len = 0;
ip_hdr(skb)->check = 0;
tcp_hdr(skb)->check =
~csum_tcpudp_magic(ip_hdr(skb)->saddr,
ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
} else {
lso_info->lso_v2_transmit.ip_version =
NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6;
ipv6_hdr(skb)->payload_len = 0;
tcp_hdr(skb)->check =
~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
}
lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset;
lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size;
goto do_send;
}
if ((skb->ip_summed == CHECKSUM_NONE) || if ((skb->ip_summed == CHECKSUM_NONE) ||
(skb->ip_summed == CHECKSUM_UNNECESSARY)) (skb->ip_summed == CHECKSUM_UNNECESSARY))
...@@ -507,35 +532,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -507,35 +532,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
csum_info->transmit.udp_checksum = 0; csum_info->transmit.udp_checksum = 0;
} }
goto do_send;
do_lso:
rndis_msg_size += NDIS_LSO_PPI_SIZE;
ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE,
TCP_LARGESEND_PKTINFO);
lso_info = (struct ndis_tcp_lso_info *)((void *)ppi +
ppi->ppi_offset);
lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE;
if (net_trans_info & (INFO_IPV4 << 16)) {
lso_info->lso_v2_transmit.ip_version =
NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4;
ip_hdr(skb)->tot_len = 0;
ip_hdr(skb)->check = 0;
tcp_hdr(skb)->check =
~csum_tcpudp_magic(ip_hdr(skb)->saddr,
ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
} else {
lso_info->lso_v2_transmit.ip_version =
NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6;
ipv6_hdr(skb)->payload_len = 0;
tcp_hdr(skb)->check =
~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
}
lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset;
lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size;
do_send: do_send:
/* Start filling in the page buffers with the rndis hdr */ /* Start filling in the page buffers with the rndis hdr */
...@@ -548,21 +544,21 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -548,21 +544,21 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
skb_tx_timestamp(skb); skb_tx_timestamp(skb);
ret = netvsc_send(net_device_ctx->device_ctx, packet, ret = netvsc_send(net_device_ctx->device_ctx, packet,
rndis_msg, &pb, skb); rndis_msg, &pb, skb);
if (likely(ret == 0)) {
drop:
if (ret == 0) {
u64_stats_update_begin(&tx_stats->syncp); u64_stats_update_begin(&tx_stats->syncp);
tx_stats->packets++; tx_stats->packets++;
tx_stats->bytes += skb_length; tx_stats->bytes += skb_length;
u64_stats_update_end(&tx_stats->syncp); u64_stats_update_end(&tx_stats->syncp);
} else { return NETDEV_TX_OK;
if (ret != -EAGAIN) {
dev_kfree_skb_any(skb);
net->stats.tx_dropped++;
}
} }
if (ret == -EAGAIN)
return NETDEV_TX_BUSY;
drop:
dev_kfree_skb_any(skb);
net->stats.tx_dropped++;
return (ret == -EAGAIN) ? NETDEV_TX_BUSY : NETDEV_TX_OK; return NETDEV_TX_OK;
} }
/* /*
......
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