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;
struct hv_netvsc_packet {
/* Bookkeeping stuff */
u32 status;
bool part_of_skb;
struct hv_device *device;
bool is_data_pkt;
......@@ -150,7 +151,7 @@ struct hv_netvsc_packet {
/* Points to the send/receive buffer where the ethernet frame is */
void *data;
u32 page_buf_cnt;
struct hv_page_buffer page_buf[0];
struct hv_page_buffer *page_buf;
};
struct netvsc_device_info {
......
......@@ -866,8 +866,13 @@ int netvsc_send(struct hv_device *device,
netvsc_copy_to_send_buf(net_device,
section_index, msd_len,
packet);
skb = (struct sk_buff *)
(unsigned long)packet->send_completion_tid;
if (!packet->part_of_skb) {
skb = (struct sk_buff *)
(unsigned long)
packet->send_completion_tid;
packet->send_completion_tid = 0;
}
packet->page_buf_cnt = 0;
packet->send_buf_index = section_index;
......
......@@ -234,11 +234,11 @@ static void netvsc_xmit_completion(void *context)
struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
struct sk_buff *skb = (struct sk_buff *)
(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);
}
......@@ -384,6 +384,9 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
u32 net_trans_info;
u32 hash;
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
......@@ -398,24 +401,32 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
return NETDEV_TX_OK;
}
/* Allocate a netvsc packet based on # of frags. */
packet = kzalloc(sizeof(struct hv_netvsc_packet) +
(num_data_pgs * sizeof(struct hv_page_buffer)) +
sizeof(struct rndis_message) +
NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE +
NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE, GFP_ATOMIC);
if (!packet) {
/* out of memory, drop packet */
netdev_err(net, "unable to allocate hv_netvsc_packet\n");
dev_kfree_skb(skb);
net->stats.tx_dropped++;
return NETDEV_TX_OK;
pkt_sz = 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;
if (head_room < pkt_sz) {
packet = kmalloc(pkt_sz, GFP_ATOMIC);
if (!packet) {
/* out of memory, drop packet */
netdev_err(net, "unable to alloc hv_netvsc_packet\n");
dev_kfree_skb(skb);
net->stats.tx_dropped++;
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->vlan_tci = skb->vlan_tci;
packet->page_buf = page_buf;
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)
packet->total_data_buflen = skb->len;
packet->rndis_msg = (struct rndis_message *)((unsigned long)packet +
sizeof(struct hv_netvsc_packet) +
(num_data_pgs * sizeof(struct hv_page_buffer)));
sizeof(struct hv_netvsc_packet));
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 */
packet->send_completion = netvsc_xmit_completion;
......@@ -556,7 +572,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
rndis_msg->msg_len += rndis_msg_size;
packet->total_data_buflen = rndis_msg->msg_len;
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);
......@@ -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_packets++;
} else {
kfree(packet);
if (!packet->part_of_skb)
kfree(packet);
if (ret != -EAGAIN) {
dev_kfree_skb_any(skb);
net->stats.tx_dropped++;
......@@ -847,12 +864,18 @@ static int netvsc_probe(struct hv_device *dev,
struct netvsc_device_info device_info;
struct netvsc_device *nvdev;
int ret;
u32 max_needed_headroom;
net = alloc_etherdev_mq(sizeof(struct net_device_context),
num_online_cpus());
if (!net)
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);
net_device_ctx = netdev_priv(net);
......@@ -871,6 +894,13 @@ static int netvsc_probe(struct hv_device *dev,
net->ethtool_ops = &ethtool_ops;
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 */
device_info.ring_size = ring_size;
ret = rndis_filter_device_add(dev, &device_info);
......
......@@ -210,6 +210,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
{
int ret;
struct hv_netvsc_packet *packet;
struct hv_page_buffer page_buf[2];
/* Setup the packet to send it */
packet = &req->pkt;
......@@ -217,6 +218,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
packet->is_data_pkt = false;
packet->total_data_buflen = req->request_msg.msg_len;
packet->page_buf_cnt = 1;
packet->page_buf = page_buf;
packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >>
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