]> git.ipfire.org Git - ipfire-2.x.git/blob - 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
1 From d972eb71fb95660fe74616901b55b0d7a336daed Mon Sep 17 00:00:00 2001
2 From: KY Srinivasan <kys@microsoft.com>
3 Date: Sat, 8 Mar 2014 19:23:14 -0800
4 Subject: [PATCH 06/25] Drivers: net: hyperv: Cleanup the send path
5
6 In preparation for enabling offloads, cleanup the send path.
7
8 Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
9 Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
10 Signed-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
17 diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
18 index 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
42 diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
43 index 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++;
190 diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
191 index 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 --
265 2.4.3
266