]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/linux/0006-Drivers-net-hyperv-Cleanup-the-send-path.patch
make.sh limit build to 23 parallel threads.
[ipfire-2.x.git] / src / patches / linux / 0006-Drivers-net-hyperv-Cleanup-the-send-path.patch
CommitLineData
a7b0967d
MT
1From d972eb71fb95660fe74616901b55b0d7a336daed Mon Sep 17 00:00:00 2001
2From: KY Srinivasan <kys@microsoft.com>
3Date: Sat, 8 Mar 2014 19:23:14 -0800
4Subject: [PATCH 06/25] Drivers: net: hyperv: Cleanup the send path
5
6In preparation for enabling offloads, cleanup the send path.
7
8Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
9Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
10Signed-off-by: David S. Miller <davem@davemloft.net>
11---
12 drivers/net/hyperv/hyperv_net.h | 7 +---
13 drivers/net/hyperv/netvsc_drv.c | 88 +++++++++++++++++++++++++++++++--------
14 drivers/net/hyperv/rndis_filter.c | 66 -----------------------------
15 3 files changed, 71 insertions(+), 90 deletions(-)
16
17diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
18index 39fc230f5c20..694bf7cada90 100644
19--- a/drivers/net/hyperv/hyperv_net.h
20+++ b/drivers/net/hyperv/hyperv_net.h
21@@ -73,7 +73,7 @@ struct hv_netvsc_packet {
22 } completion;
23
24 /* This points to the memory after page_buf */
25- void *extension;
26+ struct rndis_message *rndis_msg;
27
28 u32 total_data_buflen;
29 /* Points to the send/receive buffer where the ethernet frame is */
30@@ -126,11 +126,6 @@ void rndis_filter_device_remove(struct hv_device *dev);
31 int rndis_filter_receive(struct hv_device *dev,
32 struct hv_netvsc_packet *pkt);
33
34-
35-
36-int rndis_filter_send(struct hv_device *dev,
37- struct hv_netvsc_packet *pkt);
38-
39 int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
40 int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac);
41
42diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
43index 72961741be54..87293a15e470 100644
44--- a/drivers/net/hyperv/netvsc_drv.c
45+++ b/drivers/net/hyperv/netvsc_drv.c
46@@ -128,6 +128,27 @@ static int netvsc_close(struct net_device *net)
47 return ret;
48 }
49
50+static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size,
51+ int pkt_type)
52+{
53+ struct rndis_packet *rndis_pkt;
54+ struct rndis_per_packet_info *ppi;
55+
56+ rndis_pkt = &msg->msg.pkt;
57+ rndis_pkt->data_offset += ppi_size;
58+
59+ ppi = (struct rndis_per_packet_info *)((void *)rndis_pkt +
60+ rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_len);
61+
62+ ppi->size = ppi_size;
63+ ppi->type = pkt_type;
64+ ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
65+
66+ rndis_pkt->per_pkt_info_len += ppi_size;
67+
68+ return ppi;
69+}
70+
71 static void netvsc_xmit_completion(void *context)
72 {
73 struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
74@@ -174,8 +195,8 @@ static u32 fill_pg_buf(struct page *page, u32 offset, u32 len,
75 return j + 1;
76 }
77
78-static void init_page_array(void *hdr, u32 len, struct sk_buff *skb,
79- struct hv_page_buffer *pb)
80+static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb,
81+ struct hv_page_buffer *pb)
82 {
83 u32 slots_used = 0;
84 char *data = skb->data;
85@@ -203,6 +224,7 @@ static void init_page_array(void *hdr, u32 len, struct sk_buff *skb,
86 frag->page_offset,
87 skb_frag_size(frag), &pb[slots_used]);
88 }
89+ return slots_used;
90 }
91
92 static int count_skb_frag_slots(struct sk_buff *skb)
93@@ -240,15 +262,20 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
94 struct net_device_context *net_device_ctx = netdev_priv(net);
95 struct hv_netvsc_packet *packet;
96 int ret;
97- unsigned int num_data_pages;
98 u32 skb_length = skb->len;
99+ unsigned int num_data_pgs;
100+ struct rndis_message *rndis_msg;
101+ struct rndis_packet *rndis_pkt;
102+ u32 rndis_msg_size;
103+ bool isvlan;
104+ struct rndis_per_packet_info *ppi;
105
106 /* We will atmost need two pages to describe the rndis
107 * header. We can only transmit MAX_PAGE_BUFFER_COUNT number
108 * of pages in a single packet.
109 */
110- num_data_pages = netvsc_get_slots(skb) + 2;
111- if (num_data_pages > MAX_PAGE_BUFFER_COUNT) {
112+ num_data_pgs = netvsc_get_slots(skb) + 2;
113+ if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
114 netdev_err(net, "Packet too big: %u\n", skb->len);
115 dev_kfree_skb(skb);
116 net->stats.tx_dropped++;
117@@ -257,7 +284,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
118
119 /* Allocate a netvsc packet based on # of frags. */
120 packet = kzalloc(sizeof(struct hv_netvsc_packet) +
121- (num_data_pages * sizeof(struct hv_page_buffer)) +
122+ (num_data_pgs * sizeof(struct hv_page_buffer)) +
123 sizeof(struct rndis_message) +
124 NDIS_VLAN_PPI_SIZE, GFP_ATOMIC);
125 if (!packet) {
126@@ -271,26 +298,51 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
127
128 packet->vlan_tci = skb->vlan_tci;
129
130- packet->extension = (void *)(unsigned long)packet +
131- sizeof(struct hv_netvsc_packet) +
132- (num_data_pages * sizeof(struct hv_page_buffer));
133-
134- /* If the rndis msg goes beyond 1 page, we will add 1 later */
135- packet->page_buf_cnt = num_data_pages - 1;
136-
137- /* Initialize it from the skb */
138+ packet->is_data_pkt = true;
139 packet->total_data_buflen = skb->len;
140
141- /* Start filling in the page buffers starting after RNDIS buffer. */
142- init_page_array(NULL, 0, skb, &packet->page_buf[1]);
143+ packet->rndis_msg = (struct rndis_message *)((unsigned long)packet +
144+ sizeof(struct hv_netvsc_packet) +
145+ (num_data_pgs * sizeof(struct hv_page_buffer)));
146
147 /* Set the completion routine */
148 packet->completion.send.send_completion = netvsc_xmit_completion;
149 packet->completion.send.send_completion_ctx = packet;
150 packet->completion.send.send_completion_tid = (unsigned long)skb;
151
152- ret = rndis_filter_send(net_device_ctx->device_ctx,
153- packet);
154+ isvlan = packet->vlan_tci & VLAN_TAG_PRESENT;
155+
156+ /* Add the rndis header */
157+ rndis_msg = packet->rndis_msg;
158+ rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
159+ rndis_msg->msg_len = packet->total_data_buflen;
160+ rndis_pkt = &rndis_msg->msg.pkt;
161+ rndis_pkt->data_offset = sizeof(struct rndis_packet);
162+ rndis_pkt->data_len = packet->total_data_buflen;
163+ rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet);
164+
165+ rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
166+
167+ if (isvlan) {
168+ struct ndis_pkt_8021q_info *vlan;
169+
170+ rndis_msg_size += NDIS_VLAN_PPI_SIZE;
171+ ppi = init_ppi_data(rndis_msg, NDIS_VLAN_PPI_SIZE,
172+ IEEE_8021Q_INFO);
173+ vlan = (struct ndis_pkt_8021q_info *)((void *)ppi +
174+ ppi->ppi_offset);
175+ vlan->vlanid = packet->vlan_tci & VLAN_VID_MASK;
176+ vlan->pri = (packet->vlan_tci & VLAN_PRIO_MASK) >>
177+ VLAN_PRIO_SHIFT;
178+ }
179+
180+ /* Start filling in the page buffers with the rndis hdr */
181+ rndis_msg->msg_len += rndis_msg_size;
182+ packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
183+ skb, &packet->page_buf[0]);
184+
185+ ret = netvsc_send(net_device_ctx->device_ctx, packet);
186+
187 if (ret == 0) {
188 net->stats.tx_bytes += skb_length;
189 net->stats.tx_packets++;
190diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
191index 6a9f6021f09c..dcbf144ea7da 100644
192--- a/drivers/net/hyperv/rndis_filter.c
193+++ b/drivers/net/hyperv/rndis_filter.c
194@@ -910,69 +910,3 @@ int rndis_filter_close(struct hv_device *dev)
195
196 return rndis_filter_close_device(nvdev->extension);
197 }
198-
199-int rndis_filter_send(struct hv_device *dev,
200- struct hv_netvsc_packet *pkt)
201-{
202- struct rndis_message *rndis_msg;
203- struct rndis_packet *rndis_pkt;
204- u32 rndis_msg_size;
205- bool isvlan = pkt->vlan_tci & VLAN_TAG_PRESENT;
206-
207- /* Add the rndis header */
208- rndis_msg = (struct rndis_message *)pkt->extension;
209-
210- rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
211- if (isvlan)
212- rndis_msg_size += NDIS_VLAN_PPI_SIZE;
213-
214- rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
215- rndis_msg->msg_len = pkt->total_data_buflen +
216- rndis_msg_size;
217-
218- rndis_pkt = &rndis_msg->msg.pkt;
219- rndis_pkt->data_offset = sizeof(struct rndis_packet);
220- if (isvlan)
221- rndis_pkt->data_offset += NDIS_VLAN_PPI_SIZE;
222- rndis_pkt->data_len = pkt->total_data_buflen;
223-
224- if (isvlan) {
225- struct rndis_per_packet_info *ppi;
226- struct ndis_pkt_8021q_info *vlan;
227-
228- rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet);
229- rndis_pkt->per_pkt_info_len = NDIS_VLAN_PPI_SIZE;
230-
231- ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt +
232- rndis_pkt->per_pkt_info_offset);
233- ppi->size = NDIS_VLAN_PPI_SIZE;
234- ppi->type = IEEE_8021Q_INFO;
235- ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
236-
237- vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi +
238- ppi->ppi_offset);
239- vlan->vlanid = pkt->vlan_tci & VLAN_VID_MASK;
240- vlan->pri = (pkt->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
241- }
242-
243- pkt->is_data_pkt = true;
244- pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT;
245- pkt->page_buf[0].offset =
246- (unsigned long)rndis_msg & (PAGE_SIZE-1);
247- pkt->page_buf[0].len = rndis_msg_size;
248-
249- /* Add one page_buf if the rndis msg goes beyond page boundary */
250- if (pkt->page_buf[0].offset + rndis_msg_size > PAGE_SIZE) {
251- int i;
252- for (i = pkt->page_buf_cnt; i > 1; i--)
253- pkt->page_buf[i] = pkt->page_buf[i-1];
254- pkt->page_buf_cnt++;
255- pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset;
256- pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong)
257- rndis_msg + pkt->page_buf[0].len)) >> PAGE_SHIFT;
258- pkt->page_buf[1].offset = 0;
259- pkt->page_buf[1].len = rndis_msg_size - pkt->page_buf[0].len;
260- }
261-
262- return netvsc_send(dev, pkt);
263-}
264--
2652.4.3
266