mwifiex: add firmware dump feature for PCIe
[deliverable/linux.git] / drivers / net / hyperv / rndis_filter.c
CommitLineData
fceaf24a 1/*
fceaf24a
HJ
2 * Copyright (c) 2009, Microsoft Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
adf8d3ff 14 * this program; if not, see <http://www.gnu.org/licenses/>.
fceaf24a
HJ
15 *
16 * Authors:
17 * Haiyang Zhang <haiyangz@microsoft.com>
18 * Hank Janssen <hjanssen@microsoft.com>
fceaf24a 19 */
5654e932 20#include <linux/kernel.h>
0c3b7b2f
S
21#include <linux/sched.h>
22#include <linux/wait.h>
45da89e5 23#include <linux/highmem.h>
5a0e3ad6 24#include <linux/slab.h>
0120ee0d 25#include <linux/io.h>
9f8bd8ba 26#include <linux/if_ether.h>
eb335bc4 27#include <linux/netdevice.h>
1f5f3a75 28#include <linux/if_vlan.h>
1ce09e89 29#include <linux/nls.h>
3f335ea2 30
5ca7252a 31#include "hyperv_net.h"
fceaf24a 32
fceaf24a 33
5b54dac8 34#define RNDIS_EXT_LEN PAGE_SIZE
e681b954 35struct rndis_request {
c2a4efdd 36 struct list_head list_ent;
98d79690 37 struct completion wait_event;
fceaf24a 38
a3a6cab5 39 struct rndis_message response_msg;
0120ee0d 40 /*
a3a6cab5
HZ
41 * The buffer for extended info after the RNDIS response message. It's
42 * referenced based on the data offset in the RNDIS message. Its size
43 * is enough for current needs, and should be sufficient for the near
44 * future.
0120ee0d 45 */
a3a6cab5 46 u8 response_ext[RNDIS_EXT_LEN];
fceaf24a 47
454f18a9 48 /* Simplify allocation by having a netvsc packet inline */
c2a4efdd 49 struct hv_netvsc_packet pkt;
99e3fcfa
HZ
50 /* Set 2 pages for rndis requests crossing page boundary */
51 struct hv_page_buffer buf[2];
0f48917b 52
c2a4efdd 53 struct rndis_message request_msg;
0f48917b 54 /*
a3a6cab5
HZ
55 * The buffer for the extended info after the RNDIS request message.
56 * It is referenced and sized in a similar way as response_ext.
0f48917b 57 */
a3a6cab5 58 u8 request_ext[RNDIS_EXT_LEN];
e681b954 59};
fceaf24a 60
9c26aa0d 61static struct rndis_device *get_rndis_device(void)
fceaf24a 62{
e681b954 63 struct rndis_device *device;
fceaf24a 64
e681b954 65 device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL);
fceaf24a 66 if (!device)
fceaf24a 67 return NULL;
fceaf24a 68
880fb89c 69 spin_lock_init(&device->request_lock);
fceaf24a 70
c2a4efdd 71 INIT_LIST_HEAD(&device->req_list);
fceaf24a 72
c2a4efdd 73 device->state = RNDIS_DEV_UNINITIALIZED;
fceaf24a
HJ
74
75 return device;
76}
77
9c26aa0d 78static struct rndis_request *get_rndis_request(struct rndis_device *dev,
c2a4efdd
HZ
79 u32 msg_type,
80 u32 msg_len)
fceaf24a 81{
e681b954 82 struct rndis_request *request;
c2a4efdd 83 struct rndis_message *rndis_msg;
9f33d054 84 struct rndis_set_request *set;
880fb89c 85 unsigned long flags;
fceaf24a 86
e681b954 87 request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL);
fceaf24a 88 if (!request)
fceaf24a 89 return NULL;
fceaf24a 90
98d79690 91 init_completion(&request->wait_event);
fceaf24a 92
c2a4efdd 93 rndis_msg = &request->request_msg;
a388eb17
HZ
94 rndis_msg->ndis_msg_type = msg_type;
95 rndis_msg->msg_len = msg_len;
fceaf24a 96
5b54dac8
HZ
97 request->pkt.q_idx = 0;
98
0120ee0d
GKH
99 /*
100 * Set the request id. This field is always after the rndis header for
101 * request/response packet types so we just used the SetRequest as a
102 * template
103 */
a388eb17
HZ
104 set = &rndis_msg->msg.set_req;
105 set->req_id = atomic_inc_return(&dev->new_req_id);
fceaf24a 106
454f18a9 107 /* Add to the request list */
c2a4efdd
HZ
108 spin_lock_irqsave(&dev->request_lock, flags);
109 list_add_tail(&request->list_ent, &dev->req_list);
110 spin_unlock_irqrestore(&dev->request_lock, flags);
fceaf24a
HJ
111
112 return request;
113}
114
9c26aa0d 115static void put_rndis_request(struct rndis_device *dev,
c2a4efdd 116 struct rndis_request *req)
fceaf24a 117{
880fb89c
GKH
118 unsigned long flags;
119
c2a4efdd
HZ
120 spin_lock_irqsave(&dev->request_lock, flags);
121 list_del(&req->list_ent);
122 spin_unlock_irqrestore(&dev->request_lock, flags);
fceaf24a 123
c2a4efdd 124 kfree(req);
fceaf24a
HJ
125}
126
729a2849
HZ
127static void dump_rndis_message(struct hv_device *hv_dev,
128 struct rndis_message *rndis_msg)
fceaf24a 129{
2ddd5e5f
S
130 struct net_device *netdev;
131 struct netvsc_device *net_device;
132
133 net_device = hv_get_drvdata(hv_dev);
134 netdev = net_device->ndev;
729a2849 135
a388eb17 136 switch (rndis_msg->ndis_msg_type) {
51491167
LW
137 case RNDIS_MSG_PACKET:
138 netdev_dbg(netdev, "RNDIS_MSG_PACKET (len %u, "
0120ee0d
GKH
139 "data offset %u data len %u, # oob %u, "
140 "oob offset %u, oob len %u, pkt offset %u, "
729a2849 141 "pkt len %u\n",
a388eb17
HZ
142 rndis_msg->msg_len,
143 rndis_msg->msg.pkt.data_offset,
144 rndis_msg->msg.pkt.data_len,
145 rndis_msg->msg.pkt.num_oob_data_elements,
146 rndis_msg->msg.pkt.oob_data_offset,
147 rndis_msg->msg.pkt.oob_data_len,
148 rndis_msg->msg.pkt.per_pkt_info_offset,
149 rndis_msg->msg.pkt.per_pkt_info_len);
fceaf24a
HJ
150 break;
151
51491167
LW
152 case RNDIS_MSG_INIT_C:
153 netdev_dbg(netdev, "RNDIS_MSG_INIT_C "
0120ee0d
GKH
154 "(len %u, id 0x%x, status 0x%x, major %d, minor %d, "
155 "device flags %d, max xfer size 0x%x, max pkts %u, "
729a2849 156 "pkt aligned %u)\n",
a388eb17
HZ
157 rndis_msg->msg_len,
158 rndis_msg->msg.init_complete.req_id,
159 rndis_msg->msg.init_complete.status,
160 rndis_msg->msg.init_complete.major_ver,
161 rndis_msg->msg.init_complete.minor_ver,
162 rndis_msg->msg.init_complete.dev_flags,
163 rndis_msg->msg.init_complete.max_xfer_size,
164 rndis_msg->msg.init_complete.
165 max_pkt_per_msg,
166 rndis_msg->msg.init_complete.
167 pkt_alignment_factor);
fceaf24a
HJ
168 break;
169
51491167
LW
170 case RNDIS_MSG_QUERY_C:
171 netdev_dbg(netdev, "RNDIS_MSG_QUERY_C "
0120ee0d 172 "(len %u, id 0x%x, status 0x%x, buf len %u, "
729a2849 173 "buf offset %u)\n",
a388eb17
HZ
174 rndis_msg->msg_len,
175 rndis_msg->msg.query_complete.req_id,
176 rndis_msg->msg.query_complete.status,
177 rndis_msg->msg.query_complete.
178 info_buflen,
179 rndis_msg->msg.query_complete.
180 info_buf_offset);
fceaf24a
HJ
181 break;
182
51491167 183 case RNDIS_MSG_SET_C:
729a2849 184 netdev_dbg(netdev,
51491167 185 "RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)\n",
a388eb17
HZ
186 rndis_msg->msg_len,
187 rndis_msg->msg.set_complete.req_id,
188 rndis_msg->msg.set_complete.status);
fceaf24a
HJ
189 break;
190
51491167
LW
191 case RNDIS_MSG_INDICATE:
192 netdev_dbg(netdev, "RNDIS_MSG_INDICATE "
729a2849 193 "(len %u, status 0x%x, buf len %u, buf offset %u)\n",
a388eb17
HZ
194 rndis_msg->msg_len,
195 rndis_msg->msg.indicate_status.status,
196 rndis_msg->msg.indicate_status.status_buflen,
197 rndis_msg->msg.indicate_status.status_buf_offset);
fceaf24a
HJ
198 break;
199
200 default:
729a2849 201 netdev_dbg(netdev, "0x%x (len %u)\n",
a388eb17
HZ
202 rndis_msg->ndis_msg_type,
203 rndis_msg->msg_len);
fceaf24a
HJ
204 break;
205 }
206}
207
9c26aa0d 208static int rndis_filter_send_request(struct rndis_device *dev,
c2a4efdd 209 struct rndis_request *req)
fceaf24a 210{
0120ee0d 211 int ret;
4193d4f4 212 struct hv_netvsc_packet *packet;
fceaf24a 213
454f18a9 214 /* Setup the packet to send it */
c2a4efdd 215 packet = &req->pkt;
fceaf24a 216
72a2f5bd 217 packet->is_data_pkt = false;
a388eb17 218 packet->total_data_buflen = req->request_msg.msg_len;
72a2f5bd 219 packet->page_buf_cnt = 1;
fceaf24a 220
ca623ad3 221 packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >>
0120ee0d 222 PAGE_SHIFT;
ca623ad3
HZ
223 packet->page_buf[0].len = req->request_msg.msg_len;
224 packet->page_buf[0].offset =
c2a4efdd 225 (unsigned long)&req->request_msg & (PAGE_SIZE - 1);
fceaf24a 226
99e3fcfa
HZ
227 /* Add one page_buf when request_msg crossing page boundary */
228 if (packet->page_buf[0].offset + packet->page_buf[0].len > PAGE_SIZE) {
229 packet->page_buf_cnt++;
230 packet->page_buf[0].len = PAGE_SIZE -
231 packet->page_buf[0].offset;
232 packet->page_buf[1].pfn = virt_to_phys((void *)&req->request_msg
233 + packet->page_buf[0].len) >> PAGE_SHIFT;
234 packet->page_buf[1].offset = 0;
235 packet->page_buf[1].len = req->request_msg.msg_len -
236 packet->page_buf[0].len;
237 }
238
893f6627 239 packet->send_completion = NULL;
fceaf24a 240
0ec6ff40 241 ret = netvsc_send(dev->net_dev->dev, packet);
fceaf24a
HJ
242 return ret;
243}
244
1b07da51
HZ
245static void rndis_set_link_state(struct rndis_device *rdev,
246 struct rndis_request *request)
247{
248 u32 link_status;
249 struct rndis_query_complete *query_complete;
250
251 query_complete = &request->response_msg.msg.query_complete;
252
253 if (query_complete->status == RNDIS_STATUS_SUCCESS &&
254 query_complete->info_buflen == sizeof(u32)) {
255 memcpy(&link_status, (void *)((unsigned long)query_complete +
256 query_complete->info_buf_offset), sizeof(u32));
257 rdev->link_state = link_status != 0;
258 }
259}
260
9c26aa0d 261static void rndis_filter_receive_response(struct rndis_device *dev,
c2a4efdd 262 struct rndis_message *resp)
fceaf24a 263{
e681b954 264 struct rndis_request *request = NULL;
0e727613 265 bool found = false;
880fb89c 266 unsigned long flags;
2ddd5e5f
S
267 struct net_device *ndev;
268
269 ndev = dev->net_dev->ndev;
fceaf24a 270
c2a4efdd
HZ
271 spin_lock_irqsave(&dev->request_lock, flags);
272 list_for_each_entry(request, &dev->req_list, list_ent) {
0120ee0d
GKH
273 /*
274 * All request/response message contains RequestId as the 1st
275 * field
276 */
a388eb17
HZ
277 if (request->request_msg.msg.init_req.req_id
278 == resp->msg.init_complete.req_id) {
0e727613 279 found = true;
fceaf24a
HJ
280 break;
281 }
282 }
c2a4efdd 283 spin_unlock_irqrestore(&dev->request_lock, flags);
fceaf24a 284
0120ee0d 285 if (found) {
a3a6cab5
HZ
286 if (resp->msg_len <=
287 sizeof(struct rndis_message) + RNDIS_EXT_LEN) {
c2a4efdd 288 memcpy(&request->response_msg, resp,
a388eb17 289 resp->msg_len);
1b07da51
HZ
290 if (request->request_msg.ndis_msg_type ==
291 RNDIS_MSG_QUERY && request->request_msg.msg.
292 query_req.oid == RNDIS_OID_GEN_MEDIA_CONNECT_STATUS)
293 rndis_set_link_state(dev, request);
0120ee0d 294 } else {
d9871158 295 netdev_err(ndev,
eb335bc4
HJ
296 "rndis response buffer overflow "
297 "detected (size %u max %zu)\n",
298 resp->msg_len,
86eedacc 299 sizeof(struct rndis_message));
0120ee0d 300
a388eb17 301 if (resp->ndis_msg_type ==
51491167 302 RNDIS_MSG_RESET_C) {
0120ee0d 303 /* does not have a request id field */
a388eb17 304 request->response_msg.msg.reset_complete.
007e5c8e 305 status = RNDIS_STATUS_BUFFER_OVERFLOW;
0120ee0d 306 } else {
a388eb17
HZ
307 request->response_msg.msg.
308 init_complete.status =
007e5c8e 309 RNDIS_STATUS_BUFFER_OVERFLOW;
fceaf24a
HJ
310 }
311 }
312
98d79690 313 complete(&request->wait_event);
0120ee0d 314 } else {
d9871158 315 netdev_err(ndev,
eb335bc4
HJ
316 "no rndis request found for this response "
317 "(id 0x%x res type 0x%x)\n",
318 resp->msg.init_complete.req_id,
319 resp->ndis_msg_type);
fceaf24a 320 }
fceaf24a
HJ
321}
322
9c26aa0d 323static void rndis_filter_receive_indicate_status(struct rndis_device *dev,
c2a4efdd 324 struct rndis_message *resp)
fceaf24a 325{
0120ee0d 326 struct rndis_indicate_status *indicate =
a388eb17 327 &resp->msg.indicate_status;
fceaf24a 328
a388eb17 329 if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) {
39fb6aab 330 netvsc_linkstatus_callback(
53d21fdb 331 dev->net_dev->dev, 1);
a388eb17 332 } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) {
39fb6aab 333 netvsc_linkstatus_callback(
53d21fdb 334 dev->net_dev->dev, 0);
0120ee0d
GKH
335 } else {
336 /*
337 * TODO:
338 */
fceaf24a
HJ
339 }
340}
341
1f5f3a75
HZ
342/*
343 * Get the Per-Packet-Info with the specified type
344 * return NULL if not found.
345 */
346static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
347{
348 struct rndis_per_packet_info *ppi;
349 int len;
350
351 if (rpkt->per_pkt_info_offset == 0)
352 return NULL;
353
354 ppi = (struct rndis_per_packet_info *)((ulong)rpkt +
355 rpkt->per_pkt_info_offset);
356 len = rpkt->per_pkt_info_len;
357
358 while (len > 0) {
359 if (ppi->type == type)
360 return (void *)((ulong)ppi + ppi->ppi_offset);
361 len -= ppi->size;
362 ppi = (struct rndis_per_packet_info *)((ulong)ppi + ppi->size);
363 }
364
365 return NULL;
366}
367
9c26aa0d 368static void rndis_filter_receive_data(struct rndis_device *dev,
c2a4efdd
HZ
369 struct rndis_message *msg,
370 struct hv_netvsc_packet *pkt)
fceaf24a 371{
c2a4efdd
HZ
372 struct rndis_packet *rndis_pkt;
373 u32 data_offset;
1f5f3a75 374 struct ndis_pkt_8021q_info *vlan;
e3d605ed 375 struct ndis_tcp_ip_checksum_info *csum_info;
fceaf24a 376
a388eb17 377 rndis_pkt = &msg->msg.pkt;
fceaf24a 378
454f18a9 379 /* Remove the rndis header and pass it back up the stack */
a388eb17 380 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
fceaf24a 381
72a2f5bd 382 pkt->total_data_buflen -= data_offset;
4b8a8bc9
WY
383
384 /*
385 * Make sure we got a valid RNDIS message, now total_data_buflen
386 * should be the data packet size plus the trailer padding size
387 */
388 if (pkt->total_data_buflen < rndis_pkt->data_len) {
389 netdev_err(dev->net_dev->ndev, "rndis message buffer "
390 "overflow detected (got %u, min %u)"
391 "...dropping this message!\n",
392 pkt->total_data_buflen, rndis_pkt->data_len);
393 return;
394 }
395
396 /*
397 * Remove the rndis trailer padding from rndis packet message
398 * rndis_pkt->data_len tell us the real data length, we only copy
399 * the data packet to the stack, without the rndis trailer padding
400 */
401 pkt->total_data_buflen = rndis_pkt->data_len;
45326342 402 pkt->data = (void *)((unsigned long)pkt->data + data_offset);
669c1fc6 403
1f5f3a75
HZ
404 vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
405 if (vlan) {
406 pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |
407 (vlan->pri << VLAN_PRIO_SHIFT);
408 } else {
409 pkt->vlan_tci = 0;
410 }
411
e3d605ed
KS
412 csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO);
413 netvsc_recv_callback(dev->net_dev->dev, pkt, csum_info);
fceaf24a
HJ
414}
415
5fcc4115 416int rndis_filter_receive(struct hv_device *dev,
c2a4efdd 417 struct hv_netvsc_packet *pkt)
fceaf24a 418{
2ddd5e5f 419 struct netvsc_device *net_dev = hv_get_drvdata(dev);
c2a4efdd 420 struct rndis_device *rndis_dev;
ef31bef6 421 struct rndis_message *rndis_msg;
2ddd5e5f 422 struct net_device *ndev;
63f6921d 423 int ret = 0;
2ddd5e5f 424
63f6921d
HZ
425 if (!net_dev) {
426 ret = -EINVAL;
427 goto exit;
428 }
8a62d716 429
715a4801
S
430 ndev = net_dev->ndev;
431
454f18a9 432 /* Make sure the rndis device state is initialized */
53d21fdb 433 if (!net_dev->extension) {
d9871158 434 netdev_err(ndev, "got rndis message but no rndis device - "
eb335bc4 435 "dropping this message!\n");
63f6921d
HZ
436 ret = -ENODEV;
437 goto exit;
fceaf24a
HJ
438 }
439
53d21fdb 440 rndis_dev = (struct rndis_device *)net_dev->extension;
c2a4efdd 441 if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
d9871158 442 netdev_err(ndev, "got rndis message but rndis device "
eb335bc4 443 "uninitialized...dropping this message!\n");
63f6921d
HZ
444 ret = -ENODEV;
445 goto exit;
fceaf24a
HJ
446 }
447
ef31bef6 448 rndis_msg = pkt->data;
fceaf24a 449
ef31bef6 450 dump_rndis_message(dev, rndis_msg);
fceaf24a 451
ef31bef6 452 switch (rndis_msg->ndis_msg_type) {
51491167 453 case RNDIS_MSG_PACKET:
0120ee0d 454 /* data msg */
ef31bef6 455 rndis_filter_receive_data(rndis_dev, rndis_msg, pkt);
fceaf24a
HJ
456 break;
457
51491167
LW
458 case RNDIS_MSG_INIT_C:
459 case RNDIS_MSG_QUERY_C:
460 case RNDIS_MSG_SET_C:
0120ee0d 461 /* completion msgs */
ef31bef6 462 rndis_filter_receive_response(rndis_dev, rndis_msg);
fceaf24a
HJ
463 break;
464
51491167 465 case RNDIS_MSG_INDICATE:
0120ee0d 466 /* notification msgs */
ef31bef6 467 rndis_filter_receive_indicate_status(rndis_dev, rndis_msg);
fceaf24a
HJ
468 break;
469 default:
d9871158 470 netdev_err(ndev,
eb335bc4 471 "unhandled rndis message (type %u len %u)\n",
ef31bef6
HZ
472 rndis_msg->ndis_msg_type,
473 rndis_msg->msg_len);
fceaf24a
HJ
474 break;
475 }
476
63f6921d
HZ
477exit:
478 if (ret != 0)
479 pkt->status = NVSP_STAT_FAIL;
480
481 return ret;
fceaf24a
HJ
482}
483
9c26aa0d 484static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
c2a4efdd 485 void *result, u32 *result_size)
fceaf24a 486{
e681b954 487 struct rndis_request *request;
c2a4efdd 488 u32 inresult_size = *result_size;
9f33d054 489 struct rndis_query_request *query;
c2a4efdd 490 struct rndis_query_complete *query_complete;
0120ee0d 491 int ret = 0;
98d79690 492 int t;
fceaf24a 493
c2a4efdd 494 if (!result)
8a62d716 495 return -EINVAL;
fceaf24a 496
c2a4efdd 497 *result_size = 0;
51491167 498 request = get_rndis_request(dev, RNDIS_MSG_QUERY,
0120ee0d
GKH
499 RNDIS_MESSAGE_SIZE(struct rndis_query_request));
500 if (!request) {
de6e0580 501 ret = -ENOMEM;
1c627870 502 goto cleanup;
fceaf24a
HJ
503 }
504
454f18a9 505 /* Setup the rndis query */
a388eb17
HZ
506 query = &request->request_msg.msg.query_req;
507 query->oid = oid;
508 query->info_buf_offset = sizeof(struct rndis_query_request);
509 query->info_buflen = 0;
510 query->dev_vc_handle = 0;
fceaf24a 511
5b54dac8
HZ
512 if (oid == OID_GEN_RECEIVE_SCALE_CAPABILITIES) {
513 struct ndis_recv_scale_cap *cap;
514
515 request->request_msg.msg_len +=
516 sizeof(struct ndis_recv_scale_cap);
517 query->info_buflen = sizeof(struct ndis_recv_scale_cap);
518 cap = (struct ndis_recv_scale_cap *)((unsigned long)query +
519 query->info_buf_offset);
520 cap->hdr.type = NDIS_OBJECT_TYPE_RSS_CAPABILITIES;
521 cap->hdr.rev = NDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2;
522 cap->hdr.size = sizeof(struct ndis_recv_scale_cap);
523 }
524
9c26aa0d 525 ret = rndis_filter_send_request(dev, request);
fceaf24a 526 if (ret != 0)
1c627870 527 goto cleanup;
fceaf24a 528
5c5781b3 529 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
98d79690 530 if (t == 0) {
0c3b7b2f 531 ret = -ETIMEDOUT;
1c627870 532 goto cleanup;
0c3b7b2f 533 }
fceaf24a 534
454f18a9 535 /* Copy the response back */
a388eb17 536 query_complete = &request->response_msg.msg.query_complete;
fceaf24a 537
a388eb17 538 if (query_complete->info_buflen > inresult_size) {
fceaf24a 539 ret = -1;
1c627870 540 goto cleanup;
fceaf24a
HJ
541 }
542
c2a4efdd
HZ
543 memcpy(result,
544 (void *)((unsigned long)query_complete +
a388eb17
HZ
545 query_complete->info_buf_offset),
546 query_complete->info_buflen);
fceaf24a 547
a388eb17 548 *result_size = query_complete->info_buflen;
fceaf24a 549
1c627870 550cleanup:
fceaf24a 551 if (request)
9c26aa0d 552 put_rndis_request(dev, request);
fceaf24a
HJ
553
554 return ret;
555}
556
9c26aa0d 557static int rndis_filter_query_device_mac(struct rndis_device *dev)
fceaf24a 558{
9f8bd8ba 559 u32 size = ETH_ALEN;
fceaf24a 560
9c26aa0d 561 return rndis_filter_query_device(dev,
0120ee0d 562 RNDIS_OID_802_3_PERMANENT_ADDRESS,
c2a4efdd 563 dev->hw_mac_adr, &size);
fceaf24a
HJ
564}
565
1ce09e89
HZ
566#define NWADR_STR "NetworkAddress"
567#define NWADR_STRLEN 14
568
569int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac)
570{
571 struct netvsc_device *nvdev = hv_get_drvdata(hdev);
572 struct rndis_device *rdev = nvdev->extension;
573 struct net_device *ndev = nvdev->ndev;
574 struct rndis_request *request;
575 struct rndis_set_request *set;
576 struct rndis_config_parameter_info *cpi;
577 wchar_t *cfg_nwadr, *cfg_mac;
578 struct rndis_set_complete *set_complete;
579 char macstr[2*ETH_ALEN+1];
580 u32 extlen = sizeof(struct rndis_config_parameter_info) +
581 2*NWADR_STRLEN + 4*ETH_ALEN;
582 int ret, t;
583
584 request = get_rndis_request(rdev, RNDIS_MSG_SET,
585 RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
586 if (!request)
587 return -ENOMEM;
588
589 set = &request->request_msg.msg.set_req;
590 set->oid = RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER;
591 set->info_buflen = extlen;
592 set->info_buf_offset = sizeof(struct rndis_set_request);
593 set->dev_vc_handle = 0;
594
595 cpi = (struct rndis_config_parameter_info *)((ulong)set +
596 set->info_buf_offset);
597 cpi->parameter_name_offset =
598 sizeof(struct rndis_config_parameter_info);
599 /* Multiply by 2 because host needs 2 bytes (utf16) for each char */
600 cpi->parameter_name_length = 2*NWADR_STRLEN;
601 cpi->parameter_type = RNDIS_CONFIG_PARAM_TYPE_STRING;
602 cpi->parameter_value_offset =
603 cpi->parameter_name_offset + cpi->parameter_name_length;
604 /* Multiply by 4 because each MAC byte displayed as 2 utf16 chars */
605 cpi->parameter_value_length = 4*ETH_ALEN;
606
607 cfg_nwadr = (wchar_t *)((ulong)cpi + cpi->parameter_name_offset);
608 cfg_mac = (wchar_t *)((ulong)cpi + cpi->parameter_value_offset);
609 ret = utf8s_to_utf16s(NWADR_STR, NWADR_STRLEN, UTF16_HOST_ENDIAN,
610 cfg_nwadr, NWADR_STRLEN);
611 if (ret < 0)
612 goto cleanup;
613 snprintf(macstr, 2*ETH_ALEN+1, "%pm", mac);
614 ret = utf8s_to_utf16s(macstr, 2*ETH_ALEN, UTF16_HOST_ENDIAN,
615 cfg_mac, 2*ETH_ALEN);
616 if (ret < 0)
617 goto cleanup;
618
619 ret = rndis_filter_send_request(rdev, request);
620 if (ret != 0)
621 goto cleanup;
622
623 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
624 if (t == 0) {
625 netdev_err(ndev, "timeout before we got a set response...\n");
626 /*
627 * can't put_rndis_request, since we may still receive a
628 * send-completion.
629 */
630 return -EBUSY;
631 } else {
632 set_complete = &request->response_msg.msg.set_complete;
b02a8067
HZ
633 if (set_complete->status != RNDIS_STATUS_SUCCESS) {
634 netdev_err(ndev, "Fail to set MAC on host side:0x%x\n",
635 set_complete->status);
1ce09e89 636 ret = -EINVAL;
b02a8067 637 }
1ce09e89
HZ
638 }
639
640cleanup:
641 put_rndis_request(rdev, request);
642 return ret;
643}
644
4a0e70ae
KS
645int rndis_filter_set_offload_params(struct hv_device *hdev,
646 struct ndis_offload_params *req_offloads)
647{
648 struct netvsc_device *nvdev = hv_get_drvdata(hdev);
649 struct rndis_device *rdev = nvdev->extension;
650 struct net_device *ndev = nvdev->ndev;
651 struct rndis_request *request;
652 struct rndis_set_request *set;
653 struct ndis_offload_params *offload_params;
654 struct rndis_set_complete *set_complete;
655 u32 extlen = sizeof(struct ndis_offload_params);
656 int ret, t;
af9893a3
KS
657 u32 vsp_version = nvdev->nvsp_version;
658
659 if (vsp_version <= NVSP_PROTOCOL_VERSION_4) {
660 extlen = VERSION_4_OFFLOAD_SIZE;
661 /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support
662 * UDP checksum offload.
663 */
664 req_offloads->udp_ip_v4_csum = 0;
665 req_offloads->udp_ip_v6_csum = 0;
666 }
4a0e70ae
KS
667
668 request = get_rndis_request(rdev, RNDIS_MSG_SET,
669 RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
670 if (!request)
671 return -ENOMEM;
672
673 set = &request->request_msg.msg.set_req;
674 set->oid = OID_TCP_OFFLOAD_PARAMETERS;
675 set->info_buflen = extlen;
676 set->info_buf_offset = sizeof(struct rndis_set_request);
677 set->dev_vc_handle = 0;
678
679 offload_params = (struct ndis_offload_params *)((ulong)set +
680 set->info_buf_offset);
681 *offload_params = *req_offloads;
682 offload_params->header.type = NDIS_OBJECT_TYPE_DEFAULT;
683 offload_params->header.revision = NDIS_OFFLOAD_PARAMETERS_REVISION_3;
684 offload_params->header.size = extlen;
685
686 ret = rndis_filter_send_request(rdev, request);
687 if (ret != 0)
688 goto cleanup;
689
690 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
691 if (t == 0) {
692 netdev_err(ndev, "timeout before we got aOFFLOAD set response...\n");
693 /* can't put_rndis_request, since we may still receive a
694 * send-completion.
695 */
696 return -EBUSY;
697 } else {
698 set_complete = &request->response_msg.msg.set_complete;
699 if (set_complete->status != RNDIS_STATUS_SUCCESS) {
af9893a3 700 netdev_err(ndev, "Fail to set offload on host side:0x%x\n",
4a0e70ae
KS
701 set_complete->status);
702 ret = -EINVAL;
703 }
704 }
705
706cleanup:
707 put_rndis_request(rdev, request);
708 return ret;
709}
1ce09e89 710
5b54dac8
HZ
711u8 netvsc_hash_key[HASH_KEYLEN] = {
712 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
713 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
714 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
715 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
716 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
717};
718
719int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
720{
721 struct net_device *ndev = rdev->net_dev->ndev;
722 struct rndis_request *request;
723 struct rndis_set_request *set;
724 struct rndis_set_complete *set_complete;
725 u32 extlen = sizeof(struct ndis_recv_scale_param) +
726 4*ITAB_NUM + HASH_KEYLEN;
727 struct ndis_recv_scale_param *rssp;
728 u32 *itab;
729 u8 *keyp;
730 int i, t, ret;
731
732 request = get_rndis_request(
733 rdev, RNDIS_MSG_SET,
734 RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
735 if (!request)
736 return -ENOMEM;
737
738 set = &request->request_msg.msg.set_req;
739 set->oid = OID_GEN_RECEIVE_SCALE_PARAMETERS;
740 set->info_buflen = extlen;
741 set->info_buf_offset = sizeof(struct rndis_set_request);
742 set->dev_vc_handle = 0;
743
744 rssp = (struct ndis_recv_scale_param *)(set + 1);
745 rssp->hdr.type = NDIS_OBJECT_TYPE_RSS_PARAMETERS;
746 rssp->hdr.rev = NDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2;
747 rssp->hdr.size = sizeof(struct ndis_recv_scale_param);
748 rssp->flag = 0;
749 rssp->hashinfo = NDIS_HASH_FUNC_TOEPLITZ | NDIS_HASH_IPV4 |
750 NDIS_HASH_TCP_IPV4;
751 rssp->indirect_tabsize = 4*ITAB_NUM;
752 rssp->indirect_taboffset = sizeof(struct ndis_recv_scale_param);
753 rssp->hashkey_size = HASH_KEYLEN;
754 rssp->kashkey_offset = rssp->indirect_taboffset +
755 rssp->indirect_tabsize;
756
757 /* Set indirection table entries */
758 itab = (u32 *)(rssp + 1);
759 for (i = 0; i < ITAB_NUM; i++)
760 itab[i] = i % num_queue;
761
762 /* Set hask key values */
763 keyp = (u8 *)((unsigned long)rssp + rssp->kashkey_offset);
764 for (i = 0; i < HASH_KEYLEN; i++)
765 keyp[i] = netvsc_hash_key[i];
766
767
768 ret = rndis_filter_send_request(rdev, request);
769 if (ret != 0)
770 goto cleanup;
771
772 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
773 if (t == 0) {
774 netdev_err(ndev, "timeout before we got a set response...\n");
775 /* can't put_rndis_request, since we may still receive a
776 * send-completion.
777 */
778 return -ETIMEDOUT;
779 } else {
780 set_complete = &request->response_msg.msg.set_complete;
781 if (set_complete->status != RNDIS_STATUS_SUCCESS) {
782 netdev_err(ndev, "Fail to set RSS parameters:0x%x\n",
783 set_complete->status);
784 ret = -EINVAL;
785 }
786 }
787
788cleanup:
789 put_rndis_request(rdev, request);
790 return ret;
791}
792
793
9c26aa0d 794static int rndis_filter_query_device_link_status(struct rndis_device *dev)
fceaf24a 795{
0120ee0d 796 u32 size = sizeof(u32);
6f27457b
S
797 u32 link_status;
798 int ret;
fceaf24a 799
6f27457b 800 ret = rndis_filter_query_device(dev,
0120ee0d 801 RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
6f27457b 802 &link_status, &size);
6f27457b
S
803
804 return ret;
fceaf24a
HJ
805}
806
d426b2e3 807int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter)
fceaf24a 808{
e681b954 809 struct rndis_request *request;
9f33d054 810 struct rndis_set_request *set;
c2a4efdd 811 struct rndis_set_complete *set_complete;
4d643114 812 u32 status;
98d79690 813 int ret, t;
2ddd5e5f
S
814 struct net_device *ndev;
815
816 ndev = dev->net_dev->ndev;
fceaf24a 817
51491167 818 request = get_rndis_request(dev, RNDIS_MSG_SET,
0120ee0d
GKH
819 RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
820 sizeof(u32));
821 if (!request) {
58ef3977 822 ret = -ENOMEM;
1c627870 823 goto cleanup;
fceaf24a
HJ
824 }
825
454f18a9 826 /* Setup the rndis set */
a388eb17
HZ
827 set = &request->request_msg.msg.set_req;
828 set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
829 set->info_buflen = sizeof(u32);
830 set->info_buf_offset = sizeof(struct rndis_set_request);
fceaf24a 831
0120ee0d 832 memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request),
c2a4efdd 833 &new_filter, sizeof(u32));
fceaf24a 834
9c26aa0d 835 ret = rndis_filter_send_request(dev, request);
fceaf24a 836 if (ret != 0)
1c627870 837 goto cleanup;
fceaf24a 838
5c5781b3 839 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
98d79690
S
840
841 if (t == 0) {
d9871158 842 netdev_err(ndev,
eb335bc4 843 "timeout before we got a set response...\n");
ea496374 844 ret = -ETIMEDOUT;
0120ee0d 845 /*
25985edc 846 * We can't deallocate the request since we may still receive a
0120ee0d
GKH
847 * send completion for it.
848 */
5585d81e 849 goto exit;
0120ee0d 850 } else {
a388eb17
HZ
851 set_complete = &request->response_msg.msg.set_complete;
852 status = set_complete->status;
fceaf24a
HJ
853 }
854
1c627870 855cleanup:
fceaf24a 856 if (request)
9c26aa0d 857 put_rndis_request(dev, request);
5585d81e 858exit:
fceaf24a
HJ
859 return ret;
860}
861
fceaf24a 862
9c26aa0d 863static int rndis_filter_init_device(struct rndis_device *dev)
fceaf24a 864{
e681b954 865 struct rndis_request *request;
9f33d054 866 struct rndis_initialize_request *init;
c2a4efdd 867 struct rndis_initialize_complete *init_complete;
4d643114 868 u32 status;
98d79690 869 int ret, t;
fceaf24a 870
51491167 871 request = get_rndis_request(dev, RNDIS_MSG_INIT,
0120ee0d
GKH
872 RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
873 if (!request) {
bc49b926 874 ret = -ENOMEM;
1c627870 875 goto cleanup;
fceaf24a
HJ
876 }
877
454f18a9 878 /* Setup the rndis set */
a388eb17
HZ
879 init = &request->request_msg.msg.init_req;
880 init->major_ver = RNDIS_MAJOR_VERSION;
881 init->minor_ver = RNDIS_MINOR_VERSION;
fb1d074e 882 init->max_xfer_size = 0x4000;
fceaf24a 883
c2a4efdd 884 dev->state = RNDIS_DEV_INITIALIZING;
fceaf24a 885
9c26aa0d 886 ret = rndis_filter_send_request(dev, request);
0120ee0d 887 if (ret != 0) {
c2a4efdd 888 dev->state = RNDIS_DEV_UNINITIALIZED;
1c627870 889 goto cleanup;
fceaf24a
HJ
890 }
891
0c3b7b2f 892
5c5781b3 893 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
98d79690
S
894
895 if (t == 0) {
0c3b7b2f 896 ret = -ETIMEDOUT;
1c627870 897 goto cleanup;
0c3b7b2f 898 }
fceaf24a 899
a388eb17
HZ
900 init_complete = &request->response_msg.msg.init_complete;
901 status = init_complete->status;
0120ee0d 902 if (status == RNDIS_STATUS_SUCCESS) {
c2a4efdd 903 dev->state = RNDIS_DEV_INITIALIZED;
fceaf24a 904 ret = 0;
0120ee0d 905 } else {
c2a4efdd 906 dev->state = RNDIS_DEV_UNINITIALIZED;
bc49b926 907 ret = -EINVAL;
fceaf24a
HJ
908 }
909
1c627870 910cleanup:
fceaf24a 911 if (request)
9c26aa0d 912 put_rndis_request(dev, request);
fceaf24a
HJ
913
914 return ret;
915}
916
9c26aa0d 917static void rndis_filter_halt_device(struct rndis_device *dev)
fceaf24a 918{
e681b954 919 struct rndis_request *request;
9f33d054 920 struct rndis_halt_request *halt;
ae9e63bb
HZ
921 struct netvsc_device *nvdev = dev->net_dev;
922 struct hv_device *hdev = nvdev->dev;
923 ulong flags;
fceaf24a 924
454f18a9 925 /* Attempt to do a rndis device halt */
51491167 926 request = get_rndis_request(dev, RNDIS_MSG_HALT,
0120ee0d 927 RNDIS_MESSAGE_SIZE(struct rndis_halt_request));
fceaf24a 928 if (!request)
1c627870 929 goto cleanup;
fceaf24a 930
454f18a9 931 /* Setup the rndis set */
a388eb17
HZ
932 halt = &request->request_msg.msg.halt_req;
933 halt->req_id = atomic_inc_return(&dev->new_req_id);
fceaf24a 934
454f18a9 935 /* Ignore return since this msg is optional. */
9c26aa0d 936 rndis_filter_send_request(dev, request);
fceaf24a 937
c2a4efdd 938 dev->state = RNDIS_DEV_UNINITIALIZED;
fceaf24a 939
1c627870 940cleanup:
ae9e63bb
HZ
941 spin_lock_irqsave(&hdev->channel->inbound_lock, flags);
942 nvdev->destroy = true;
943 spin_unlock_irqrestore(&hdev->channel->inbound_lock, flags);
944
945 /* Wait for all send completions */
946 wait_event(nvdev->wait_drain,
947 atomic_read(&nvdev->num_outstanding_sends) == 0);
948
fceaf24a 949 if (request)
9c26aa0d 950 put_rndis_request(dev, request);
fceaf24a
HJ
951 return;
952}
953
9c26aa0d 954static int rndis_filter_open_device(struct rndis_device *dev)
fceaf24a 955{
0120ee0d 956 int ret;
fceaf24a 957
c2a4efdd 958 if (dev->state != RNDIS_DEV_INITIALIZED)
fceaf24a
HJ
959 return 0;
960
9c26aa0d 961 ret = rndis_filter_set_packet_filter(dev,
0120ee0d 962 NDIS_PACKET_TYPE_BROADCAST |
95beae90 963 NDIS_PACKET_TYPE_ALL_MULTICAST |
0120ee0d 964 NDIS_PACKET_TYPE_DIRECTED);
fceaf24a 965 if (ret == 0)
c2a4efdd 966 dev->state = RNDIS_DEV_DATAINITIALIZED;
fceaf24a 967
fceaf24a
HJ
968 return ret;
969}
970
9c26aa0d 971static int rndis_filter_close_device(struct rndis_device *dev)
fceaf24a
HJ
972{
973 int ret;
974
c2a4efdd 975 if (dev->state != RNDIS_DEV_DATAINITIALIZED)
fceaf24a
HJ
976 return 0;
977
9c26aa0d 978 ret = rndis_filter_set_packet_filter(dev, 0);
fceaf24a 979 if (ret == 0)
c2a4efdd 980 dev->state = RNDIS_DEV_INITIALIZED;
fceaf24a 981
fceaf24a
HJ
982 return ret;
983}
984
5b54dac8
HZ
985static void netvsc_sc_open(struct vmbus_channel *new_sc)
986{
987 struct netvsc_device *nvscdev;
988 u16 chn_index = new_sc->offermsg.offer.sub_channel_index;
989 int ret;
990
991 nvscdev = hv_get_drvdata(new_sc->primary_channel->device_obj);
992
993 if (chn_index >= nvscdev->num_chn)
994 return;
995
996 set_per_channel_state(new_sc, nvscdev->sub_cb_buf + (chn_index - 1) *
997 NETVSC_PACKET_SIZE);
998
999 ret = vmbus_open(new_sc, nvscdev->ring_size * PAGE_SIZE,
1000 nvscdev->ring_size * PAGE_SIZE, NULL, 0,
1001 netvsc_channel_cb, new_sc);
1002
1003 if (ret == 0)
1004 nvscdev->chn_table[chn_index] = new_sc;
1005}
1006
bdbad576 1007int rndis_filter_device_add(struct hv_device *dev,
c2a4efdd 1008 void *additional_info)
fceaf24a
HJ
1009{
1010 int ret;
86c921af 1011 struct netvsc_device *net_device;
b13cc345 1012 struct rndis_device *rndis_device;
3c4debad 1013 struct netvsc_device_info *device_info = additional_info;
4a0e70ae 1014 struct ndis_offload_params offloads;
5b54dac8
HZ
1015 struct nvsp_message *init_packet;
1016 int t;
1017 struct ndis_recv_scale_cap rsscap;
1018 u32 rsscap_size = sizeof(struct ndis_recv_scale_cap);
fceaf24a 1019
b13cc345
S
1020 rndis_device = get_rndis_device();
1021 if (!rndis_device)
327efbae 1022 return -ENODEV;
fceaf24a 1023
0120ee0d
GKH
1024 /*
1025 * Let the inner driver handle this first to create the netvsc channel
1026 * NOTE! Once the channel is created, we may get a receive callback
1027 * (RndisFilterOnReceive()) before this call is completed
1028 */
ce5bf661 1029 ret = netvsc_device_add(dev, additional_info);
0120ee0d 1030 if (ret != 0) {
b13cc345 1031 kfree(rndis_device);
fceaf24a
HJ
1032 return ret;
1033 }
1034
454f18a9
BP
1035
1036 /* Initialize the rndis device */
86c921af 1037 net_device = hv_get_drvdata(dev);
5b54dac8 1038 net_device->num_chn = 1;
fceaf24a 1039
b13cc345
S
1040 net_device->extension = rndis_device;
1041 rndis_device->net_dev = net_device;
fceaf24a 1042
454f18a9 1043 /* Send the rndis initialization message */
b13cc345 1044 ret = rndis_filter_init_device(rndis_device);
0120ee0d 1045 if (ret != 0) {
5243e7bd
HZ
1046 rndis_filter_device_remove(dev);
1047 return ret;
fceaf24a
HJ
1048 }
1049
454f18a9 1050 /* Get the mac address */
b13cc345 1051 ret = rndis_filter_query_device_mac(rndis_device);
0120ee0d 1052 if (ret != 0) {
5243e7bd
HZ
1053 rndis_filter_device_remove(dev);
1054 return ret;
fceaf24a
HJ
1055 }
1056
3c4debad 1057 memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN);
fceaf24a 1058
4a0e70ae
KS
1059 /* Turn on the offloads; the host supports all of the relevant
1060 * offloads.
1061 */
1062 memset(&offloads, 0, sizeof(struct ndis_offload_params));
1063 /* A value of zero means "no change"; now turn on what we
1064 * want.
1065 */
1066 offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1067 offloads.tcp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1068 offloads.udp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1069 offloads.tcp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1070 offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1071 offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
1072
1073
1074 ret = rndis_filter_set_offload_params(dev, &offloads);
1075 if (ret)
1076 goto err_dev_remv;
1077
b13cc345 1078 rndis_filter_query_device_link_status(rndis_device);
fceaf24a 1079
6f27457b 1080 device_info->link_state = rndis_device->link_state;
eb335bc4 1081
6f27457b 1082 dev_info(&dev->device, "Device MAC %pM link state %s\n",
b13cc345 1083 rndis_device->hw_mac_adr,
6f27457b 1084 device_info->link_state ? "down" : "up");
fceaf24a 1085
5b54dac8
HZ
1086 if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5)
1087 return 0;
1088
1089 /* vRSS setup */
1090 memset(&rsscap, 0, rsscap_size);
1091 ret = rndis_filter_query_device(rndis_device,
1092 OID_GEN_RECEIVE_SCALE_CAPABILITIES,
1093 &rsscap, &rsscap_size);
1094 if (ret || rsscap.num_recv_que < 2)
1095 goto out;
1096
1097 net_device->num_chn = (num_online_cpus() < rsscap.num_recv_que) ?
1098 num_online_cpus() : rsscap.num_recv_que;
1099 if (net_device->num_chn == 1)
1100 goto out;
1101
1102 net_device->sub_cb_buf = vzalloc((net_device->num_chn - 1) *
1103 NETVSC_PACKET_SIZE);
1104 if (!net_device->sub_cb_buf) {
1105 net_device->num_chn = 1;
1106 dev_info(&dev->device, "No memory for subchannels.\n");
1107 goto out;
1108 }
1109
1110 vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open);
1111
1112 init_packet = &net_device->channel_init_pkt;
1113 memset(init_packet, 0, sizeof(struct nvsp_message));
1114 init_packet->hdr.msg_type = NVSP_MSG5_TYPE_SUBCHANNEL;
1115 init_packet->msg.v5_msg.subchn_req.op = NVSP_SUBCHANNEL_ALLOCATE;
1116 init_packet->msg.v5_msg.subchn_req.num_subchannels =
1117 net_device->num_chn - 1;
1118 ret = vmbus_sendpacket(dev->channel, init_packet,
1119 sizeof(struct nvsp_message),
1120 (unsigned long)init_packet,
1121 VM_PKT_DATA_INBAND,
1122 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
1123 if (ret)
1124 goto out;
1125 t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
1126 if (t == 0) {
1127 ret = -ETIMEDOUT;
1128 goto out;
1129 }
1130 if (init_packet->msg.v5_msg.subchn_comp.status !=
1131 NVSP_STAT_SUCCESS) {
1132 ret = -ENODEV;
1133 goto out;
1134 }
1135 net_device->num_chn = 1 +
1136 init_packet->msg.v5_msg.subchn_comp.num_subchannels;
1137
1138 vmbus_are_subchannels_present(dev->channel);
1139
1140 ret = rndis_filter_set_rss_param(rndis_device, net_device->num_chn);
1141
1142out:
1143 if (ret)
1144 net_device->num_chn = 1;
1145 return 0; /* return 0 because primary channel can be used alone */
4a0e70ae
KS
1146
1147err_dev_remv:
1148 rndis_filter_device_remove(dev);
1149 return ret;
fceaf24a
HJ
1150}
1151
df06bcff 1152void rndis_filter_device_remove(struct hv_device *dev)
fceaf24a 1153{
2ddd5e5f 1154 struct netvsc_device *net_dev = hv_get_drvdata(dev);
53d21fdb 1155 struct rndis_device *rndis_dev = net_dev->extension;
fceaf24a 1156
454f18a9 1157 /* Halt and release the rndis device */
9c26aa0d 1158 rndis_filter_halt_device(rndis_dev);
fceaf24a 1159
c2a4efdd 1160 kfree(rndis_dev);
53d21fdb 1161 net_dev->extension = NULL;
fceaf24a 1162
3fae5c8f 1163 netvsc_device_remove(dev);
fceaf24a
HJ
1164}
1165
fceaf24a 1166
9c26aa0d 1167int rndis_filter_open(struct hv_device *dev)
fceaf24a 1168{
86c921af 1169 struct netvsc_device *net_device = hv_get_drvdata(dev);
fceaf24a 1170
86c921af 1171 if (!net_device)
8a62d716
BP
1172 return -EINVAL;
1173
86c921af 1174 return rndis_filter_open_device(net_device->extension);
fceaf24a
HJ
1175}
1176
9c26aa0d 1177int rndis_filter_close(struct hv_device *dev)
fceaf24a 1178{
5fccab3b 1179 struct netvsc_device *nvdev = hv_get_drvdata(dev);
fceaf24a 1180
5fccab3b 1181 if (!nvdev)
8a62d716
BP
1182 return -EINVAL;
1183
5fccab3b 1184 return rndis_filter_close_device(nvdev->extension);
fceaf24a 1185}
This page took 0.541696 seconds and 5 git commands to generate.