]>
Commit | Line | Data |
---|---|---|
a7b0967d MT |
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 |