Commit 3271e4f1 authored by David S. Miller's avatar David S. Miller

Merge branch 'hv_netvsc-next'

K. Y. Srinivasan says:

====================
hv_netvsc: Eliminate memory allocation in the send path

The network protocol used to communicate with the host is the remote ndis (rndis)
protocol. We need to decorate each outgoing packet with a rndis header and
additional rndis state (rndis per-packet state). To manage this state, we
currently allocate memory in the transmit path. Eliminate this allocation by
requesting additional head room in the skb.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4e833c59 b08cc791
...@@ -128,6 +128,7 @@ struct ndis_tcp_ip_checksum_info; ...@@ -128,6 +128,7 @@ struct ndis_tcp_ip_checksum_info;
struct hv_netvsc_packet { struct hv_netvsc_packet {
/* Bookkeeping stuff */ /* Bookkeeping stuff */
u32 status; u32 status;
bool part_of_skb;
struct hv_device *device; struct hv_device *device;
bool is_data_pkt; bool is_data_pkt;
...@@ -150,7 +151,7 @@ struct hv_netvsc_packet { ...@@ -150,7 +151,7 @@ struct hv_netvsc_packet {
/* Points to the send/receive buffer where the ethernet frame is */ /* Points to the send/receive buffer where the ethernet frame is */
void *data; void *data;
u32 page_buf_cnt; u32 page_buf_cnt;
struct hv_page_buffer page_buf[0]; struct hv_page_buffer *page_buf;
}; };
struct netvsc_device_info { struct netvsc_device_info {
......
...@@ -866,8 +866,13 @@ int netvsc_send(struct hv_device *device, ...@@ -866,8 +866,13 @@ int netvsc_send(struct hv_device *device,
netvsc_copy_to_send_buf(net_device, netvsc_copy_to_send_buf(net_device,
section_index, msd_len, section_index, msd_len,
packet); packet);
skb = (struct sk_buff *) if (!packet->part_of_skb) {
(unsigned long)packet->send_completion_tid; skb = (struct sk_buff *)
(unsigned long)
packet->send_completion_tid;
packet->send_completion_tid = 0;
}
packet->page_buf_cnt = 0; packet->page_buf_cnt = 0;
packet->send_buf_index = section_index; packet->send_buf_index = section_index;
......
...@@ -234,11 +234,11 @@ static void netvsc_xmit_completion(void *context) ...@@ -234,11 +234,11 @@ static void netvsc_xmit_completion(void *context)
struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
struct sk_buff *skb = (struct sk_buff *) struct sk_buff *skb = (struct sk_buff *)
(unsigned long)packet->send_completion_tid; (unsigned long)packet->send_completion_tid;
u32 index = packet->send_buf_index;
kfree(packet); if (!packet->part_of_skb)
kfree(packet);
if (skb && (index == NETVSC_INVALID_INDEX)) if (skb)
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
...@@ -384,6 +384,9 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -384,6 +384,9 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
u32 net_trans_info; u32 net_trans_info;
u32 hash; u32 hash;
u32 skb_length = skb->len; u32 skb_length = skb->len;
u32 head_room = skb_headroom(skb);
u32 pkt_sz;
struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
/* We will atmost need two pages to describe the rndis /* We will atmost need two pages to describe the rndis
...@@ -398,24 +401,32 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -398,24 +401,32 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
/* Allocate a netvsc packet based on # of frags. */ pkt_sz = sizeof(struct hv_netvsc_packet) +
packet = kzalloc(sizeof(struct hv_netvsc_packet) + sizeof(struct rndis_message) +
(num_data_pgs * sizeof(struct hv_page_buffer)) + NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE +
sizeof(struct rndis_message) + NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE;
NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE +
NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE, GFP_ATOMIC); if (head_room < pkt_sz) {
if (!packet) { packet = kmalloc(pkt_sz, GFP_ATOMIC);
/* out of memory, drop packet */ if (!packet) {
netdev_err(net, "unable to allocate hv_netvsc_packet\n"); /* out of memory, drop packet */
netdev_err(net, "unable to alloc hv_netvsc_packet\n");
dev_kfree_skb(skb); dev_kfree_skb(skb);
net->stats.tx_dropped++; net->stats.tx_dropped++;
return NETDEV_TX_OK; return NETDEV_TX_OK;
}
packet->part_of_skb = false;
} else {
/* Use the headroom for building up the packet */
packet = (struct hv_netvsc_packet *)skb->head;
packet->part_of_skb = true;
} }
packet->status = 0;
packet->xmit_more = skb->xmit_more; packet->xmit_more = skb->xmit_more;
packet->vlan_tci = skb->vlan_tci; packet->vlan_tci = skb->vlan_tci;
packet->page_buf = page_buf;
packet->q_idx = skb_get_queue_mapping(skb); packet->q_idx = skb_get_queue_mapping(skb);
...@@ -423,8 +434,13 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -423,8 +434,13 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
packet->total_data_buflen = skb->len; packet->total_data_buflen = skb->len;
packet->rndis_msg = (struct rndis_message *)((unsigned long)packet + packet->rndis_msg = (struct rndis_message *)((unsigned long)packet +
sizeof(struct hv_netvsc_packet) + sizeof(struct hv_netvsc_packet));
(num_data_pgs * sizeof(struct hv_page_buffer)));
memset(packet->rndis_msg, 0, sizeof(struct rndis_message) +
NDIS_VLAN_PPI_SIZE +
NDIS_CSUM_PPI_SIZE +
NDIS_LSO_PPI_SIZE +
NDIS_HASH_PPI_SIZE);
/* Set the completion routine */ /* Set the completion routine */
packet->send_completion = netvsc_xmit_completion; packet->send_completion = netvsc_xmit_completion;
...@@ -556,7 +572,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -556,7 +572,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
rndis_msg->msg_len += rndis_msg_size; rndis_msg->msg_len += rndis_msg_size;
packet->total_data_buflen = rndis_msg->msg_len; packet->total_data_buflen = rndis_msg->msg_len;
packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size, packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
skb, &packet->page_buf[0]); skb, &page_buf[0]);
ret = netvsc_send(net_device_ctx->device_ctx, packet); ret = netvsc_send(net_device_ctx->device_ctx, packet);
...@@ -565,7 +581,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -565,7 +581,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
net->stats.tx_bytes += skb_length; net->stats.tx_bytes += skb_length;
net->stats.tx_packets++; net->stats.tx_packets++;
} else { } else {
kfree(packet); if (!packet->part_of_skb)
kfree(packet);
if (ret != -EAGAIN) { if (ret != -EAGAIN) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
net->stats.tx_dropped++; net->stats.tx_dropped++;
...@@ -847,12 +864,18 @@ static int netvsc_probe(struct hv_device *dev, ...@@ -847,12 +864,18 @@ static int netvsc_probe(struct hv_device *dev,
struct netvsc_device_info device_info; struct netvsc_device_info device_info;
struct netvsc_device *nvdev; struct netvsc_device *nvdev;
int ret; int ret;
u32 max_needed_headroom;
net = alloc_etherdev_mq(sizeof(struct net_device_context), net = alloc_etherdev_mq(sizeof(struct net_device_context),
num_online_cpus()); num_online_cpus());
if (!net) if (!net)
return -ENOMEM; return -ENOMEM;
max_needed_headroom = sizeof(struct hv_netvsc_packet) +
sizeof(struct rndis_message) +
NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE +
NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE;
netif_carrier_off(net); netif_carrier_off(net);
net_device_ctx = netdev_priv(net); net_device_ctx = netdev_priv(net);
...@@ -871,6 +894,13 @@ static int netvsc_probe(struct hv_device *dev, ...@@ -871,6 +894,13 @@ static int netvsc_probe(struct hv_device *dev,
net->ethtool_ops = &ethtool_ops; net->ethtool_ops = &ethtool_ops;
SET_NETDEV_DEV(net, &dev->device); SET_NETDEV_DEV(net, &dev->device);
/*
* Request additional head room in the skb.
* We will use this space to build the rndis
* heaser and other state we need to maintain.
*/
net->needed_headroom = max_needed_headroom;
/* Notify the netvsc driver of the new device */ /* Notify the netvsc driver of the new device */
device_info.ring_size = ring_size; device_info.ring_size = ring_size;
ret = rndis_filter_device_add(dev, &device_info); ret = rndis_filter_device_add(dev, &device_info);
......
...@@ -210,6 +210,7 @@ static int rndis_filter_send_request(struct rndis_device *dev, ...@@ -210,6 +210,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
{ {
int ret; int ret;
struct hv_netvsc_packet *packet; struct hv_netvsc_packet *packet;
struct hv_page_buffer page_buf[2];
/* Setup the packet to send it */ /* Setup the packet to send it */
packet = &req->pkt; packet = &req->pkt;
...@@ -217,6 +218,7 @@ static int rndis_filter_send_request(struct rndis_device *dev, ...@@ -217,6 +218,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
packet->is_data_pkt = false; packet->is_data_pkt = false;
packet->total_data_buflen = req->request_msg.msg_len; packet->total_data_buflen = req->request_msg.msg_len;
packet->page_buf_cnt = 1; packet->page_buf_cnt = 1;
packet->page_buf = page_buf;
packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >> packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >>
PAGE_SHIFT; PAGE_SHIFT;
......
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