Blame view

drivers/net/hyperv/netvsc_drv.c 39 KB
fceaf24a9   Hank Janssen   Staging: hv: add ...
1
  /*
fceaf24a9   Hank Janssen   Staging: hv: add ...
2
3
4
5
6
7
8
9
10
11
12
13
   * Copyright (c) 2009, Microsoft Corporation.
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms and conditions of the GNU General Public License,
   * version 2, as published by the Free Software Foundation.
   *
   * This program is distributed in the hope it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   * more details.
   *
   * You should have received a copy of the GNU General Public License along with
adf8d3ff6   Jeff Kirsher   drivers/net/*: Fi...
14
   * this program; if not, see <http://www.gnu.org/licenses/>.
fceaf24a9   Hank Janssen   Staging: hv: add ...
15
16
   *
   * Authors:
d0e94d17e   Haiyang Zhang   Staging: hv: Fix ...
17
   *   Haiyang Zhang <haiyangz@microsoft.com>
fceaf24a9   Hank Janssen   Staging: hv: add ...
18
   *   Hank Janssen  <hjanssen@microsoft.com>
fceaf24a9   Hank Janssen   Staging: hv: add ...
19
   */
eb335bc42   Hank Janssen   staging: hv: repl...
20
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
fceaf24a9   Hank Janssen   Staging: hv: add ...
21
  #include <linux/init.h>
9079ce691   K. Y. Srinivasan   Staging: hv: netv...
22
  #include <linux/atomic.h>
fceaf24a9   Hank Janssen   Staging: hv: add ...
23
24
25
  #include <linux/module.h>
  #include <linux/highmem.h>
  #include <linux/device.h>
fceaf24a9   Hank Janssen   Staging: hv: add ...
26
  #include <linux/io.h>
fceaf24a9   Hank Janssen   Staging: hv: add ...
27
28
29
30
31
  #include <linux/delay.h>
  #include <linux/netdevice.h>
  #include <linux/inetdevice.h>
  #include <linux/etherdevice.h>
  #include <linux/skbuff.h>
c802db116   Haiyang Zhang   hyperv: Fix vlan_...
32
  #include <linux/if_vlan.h>
fceaf24a9   Hank Janssen   Staging: hv: add ...
33
  #include <linux/in.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
34
  #include <linux/slab.h>
fceaf24a9   Hank Janssen   Staging: hv: add ...
35
36
37
38
  #include <net/arp.h>
  #include <net/route.h>
  #include <net/sock.h>
  #include <net/pkt_sched.h>
3f335ea21   K. Y. Srinivasan   Staging: hv: Incl...
39

5ca7252a7   K. Y. Srinivasan   Staging: hv: netv...
40
  #include "hyperv_net.h"
fceaf24a9   Hank Janssen   Staging: hv: add ...
41

fa85a6c29   Haiyang Zhang   hyperv: Add a che...
42
  #define RING_SIZE_MIN 64
27a70af3f   Vitaly Kuznetsov   hv_netvsc: rework...
43
  #define LINKCHANGE_INT (2 * HZ)
a060679c6   sixiao@microsoft.com   hv_netvsc: cleanu...
44
45
46
47
48
  #define NETVSC_HW_FEATURES	(NETIF_F_RXCSUM | \
  				 NETIF_F_SG | \
  				 NETIF_F_TSO | \
  				 NETIF_F_TSO6 | \
  				 NETIF_F_HW_CSUM)
a50af86dd   stephen hemminger   netvsc: reduce ma...
49
50
51
  
  /* Restrict GSO size to account for NVGRE */
  #define NETVSC_GSO_MAX_SIZE	62768
99c8da0f4   Hank Janssen   staging: hv: Doub...
52
  static int ring_size = 128;
450d7a4b7   Stephen Hemminger   Staging: hv: ring...
53
54
  module_param(ring_size, int, S_IRUGO);
  MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
fceaf24a9   Hank Janssen   Staging: hv: add ...
55

e01ec2199   KY Srinivasan   hv_netvsc: Proper...
56
  static int max_num_vrss_chns = 8;
3f300ff41   Simon Xiao   hv_netvsc: introd...
57
58
59
60
61
62
63
64
  static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
  				NETIF_MSG_LINK | NETIF_MSG_IFUP |
  				NETIF_MSG_IFDOWN | NETIF_MSG_RX_ERR |
  				NETIF_MSG_TX_ERR;
  
  static int debug = -1;
  module_param(debug, int, S_IRUGO);
  MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
d426b2e3d   Haiyang Zhang   net/hyperv: Add s...
65
66
  static void do_set_multicast(struct work_struct *w)
  {
792df8722   Wenqi Ma   net/hyperv: Addin...
67
68
  	struct net_device_context *ndevctx =
  		container_of(w, struct net_device_context, work);
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
69
70
71
  	struct hv_device *device_obj = ndevctx->device_ctx;
  	struct net_device *ndev = hv_get_drvdata(device_obj);
  	struct netvsc_device *nvdev = ndevctx->nvdev;
d426b2e3d   Haiyang Zhang   net/hyperv: Add s...
72
  	struct rndis_device *rdev;
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
73
  	if (!nvdev)
792df8722   Wenqi Ma   net/hyperv: Addin...
74
  		return;
d426b2e3d   Haiyang Zhang   net/hyperv: Add s...
75
76
77
  
  	rdev = nvdev->extension;
  	if (rdev == NULL)
792df8722   Wenqi Ma   net/hyperv: Addin...
78
  		return;
d426b2e3d   Haiyang Zhang   net/hyperv: Add s...
79

0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
80
  	if (ndev->flags & IFF_PROMISC)
d426b2e3d   Haiyang Zhang   net/hyperv: Add s...
81
82
83
84
85
86
87
  		rndis_filter_set_packet_filter(rdev,
  			NDIS_PACKET_TYPE_PROMISCUOUS);
  	else
  		rndis_filter_set_packet_filter(rdev,
  			NDIS_PACKET_TYPE_BROADCAST |
  			NDIS_PACKET_TYPE_ALL_MULTICAST |
  			NDIS_PACKET_TYPE_DIRECTED);
d426b2e3d   Haiyang Zhang   net/hyperv: Add s...
88
  }
4e9bfefa3   Greg Kroah-Hartman   Staging: hv: remo...
89
  static void netvsc_set_multicast_list(struct net_device *net)
fceaf24a9   Hank Janssen   Staging: hv: add ...
90
  {
792df8722   Wenqi Ma   net/hyperv: Addin...
91
  	struct net_device_context *net_device_ctx = netdev_priv(net);
d426b2e3d   Haiyang Zhang   net/hyperv: Add s...
92

792df8722   Wenqi Ma   net/hyperv: Addin...
93
  	schedule_work(&net_device_ctx->work);
fceaf24a9   Hank Janssen   Staging: hv: add ...
94
  }
fceaf24a9   Hank Janssen   Staging: hv: add ...
95
96
  static int netvsc_open(struct net_device *net)
  {
2f5fa6c86   Vitaly Kuznetsov   hv_netvsc: pass s...
97
  	struct netvsc_device *nvdev = net_device_to_netvsc_device(net);
891de74d6   Haiyang Zhang   hyperv: Fix the c...
98
  	struct rndis_device *rdev;
02fafbc61   Greg Kroah-Hartman   Staging: hv: codi...
99
  	int ret = 0;
fceaf24a9   Hank Janssen   Staging: hv: add ...
100

891de74d6   Haiyang Zhang   hyperv: Fix the c...
101
  	netif_carrier_off(net);
d515d0ff3   Haiyang Zhang   staging: hv: remo...
102
  	/* Open up the device */
2f5fa6c86   Vitaly Kuznetsov   hv_netvsc: pass s...
103
  	ret = rndis_filter_open(nvdev);
d515d0ff3   Haiyang Zhang   staging: hv: remo...
104
105
106
107
  	if (ret != 0) {
  		netdev_err(net, "unable to open device (ret %d).
  ", ret);
  		return ret;
fceaf24a9   Hank Janssen   Staging: hv: add ...
108
  	}
2de8530ba   Haiyang Zhang   hv_netvsc: Add cl...
109
  	netif_tx_wake_all_queues(net);
d515d0ff3   Haiyang Zhang   staging: hv: remo...
110

891de74d6   Haiyang Zhang   hyperv: Fix the c...
111
112
113
  	rdev = nvdev->extension;
  	if (!rdev->link_state)
  		netif_carrier_on(net);
fceaf24a9   Hank Janssen   Staging: hv: add ...
114
115
  	return ret;
  }
fceaf24a9   Hank Janssen   Staging: hv: add ...
116
117
  static int netvsc_close(struct net_device *net)
  {
fceaf24a9   Hank Janssen   Staging: hv: add ...
118
  	struct net_device_context *net_device_ctx = netdev_priv(net);
3d541ac5a   Vitaly Kuznetsov   hv_netvsc: untang...
119
  	struct netvsc_device *nvdev = net_device_ctx->nvdev;
02fafbc61   Greg Kroah-Hartman   Staging: hv: codi...
120
  	int ret;
2de8530ba   Haiyang Zhang   hv_netvsc: Add cl...
121
122
  	u32 aread, awrite, i, msec = 10, retry = 0, retry_max = 20;
  	struct vmbus_channel *chn;
fceaf24a9   Hank Janssen   Staging: hv: add ...
123

0a282538c   Haiyang Zhang   net/hyperv: Use n...
124
  	netif_tx_disable(net);
fceaf24a9   Hank Janssen   Staging: hv: add ...
125

792df8722   Wenqi Ma   net/hyperv: Addin...
126
127
  	/* Make sure netvsc_set_multicast_list doesn't re-enable filter! */
  	cancel_work_sync(&net_device_ctx->work);
2f5fa6c86   Vitaly Kuznetsov   hv_netvsc: pass s...
128
  	ret = rndis_filter_close(nvdev);
2de8530ba   Haiyang Zhang   hv_netvsc: Add cl...
129
  	if (ret != 0) {
eb335bc42   Hank Janssen   staging: hv: repl...
130
131
  		netdev_err(net, "unable to close device (ret %d).
  ", ret);
2de8530ba   Haiyang Zhang   hv_netvsc: Add cl...
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  		return ret;
  	}
  
  	/* Ensure pending bytes in ring are read */
  	while (true) {
  		aread = 0;
  		for (i = 0; i < nvdev->num_chn; i++) {
  			chn = nvdev->chn_table[i];
  			if (!chn)
  				continue;
  
  			hv_get_ringbuffer_availbytes(&chn->inbound, &aread,
  						     &awrite);
  
  			if (aread)
  				break;
  
  			hv_get_ringbuffer_availbytes(&chn->outbound, &aread,
  						     &awrite);
  
  			if (aread)
  				break;
  		}
  
  		retry++;
  		if (retry > retry_max || aread == 0)
  			break;
  
  		msleep(msec);
  
  		if (msec < 1000)
  			msec *= 2;
  	}
  
  	if (aread) {
  		netdev_err(net, "Ring buffer not empty after closing rndis
  ");
  		ret = -ETIMEDOUT;
  	}
fceaf24a9   Hank Janssen   Staging: hv: add ...
171

fceaf24a9   Hank Janssen   Staging: hv: add ...
172
173
  	return ret;
  }
8a00251a3   KY Srinivasan   Drivers: net: hyp...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
  static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size,
  				int pkt_type)
  {
  	struct rndis_packet *rndis_pkt;
  	struct rndis_per_packet_info *ppi;
  
  	rndis_pkt = &msg->msg.pkt;
  	rndis_pkt->data_offset += ppi_size;
  
  	ppi = (struct rndis_per_packet_info *)((void *)rndis_pkt +
  		rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_len);
  
  	ppi->size = ppi_size;
  	ppi->type = pkt_type;
  	ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
  
  	rndis_pkt->per_pkt_info_len += ppi_size;
  
  	return ppi;
  }
5b54dac85   Haiyang Zhang   hyperv: Add suppo...
194
195
196
197
  static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,
  			void *accel_priv, select_queue_fallback_t fallback)
  {
  	struct net_device_context *net_device_ctx = netdev_priv(ndev);
3d541ac5a   Vitaly Kuznetsov   hv_netvsc: untang...
198
  	struct netvsc_device *nvsc_dev = net_device_ctx->nvdev;
5b54dac85   Haiyang Zhang   hyperv: Add suppo...
199
200
201
202
203
  	u32 hash;
  	u16 q_idx = 0;
  
  	if (nvsc_dev == NULL || ndev->real_num_tx_queues <= 1)
  		return 0;
757647e10   Vitaly Kuznetsov   hv_netvsc: use sk...
204
205
206
  	hash = skb_get_hash(skb);
  	q_idx = nvsc_dev->send_table[hash % VRSS_SEND_TAB_SIZE] %
  		ndev->real_num_tx_queues;
5b54dac85   Haiyang Zhang   hyperv: Add suppo...
207

8b9fbe1ac   Vitaly Kuznetsov   hv_netvsc: move s...
208
209
  	if (!nvsc_dev->chn_table[q_idx])
  		q_idx = 0;
5b54dac85   Haiyang Zhang   hyperv: Add suppo...
210
211
  	return q_idx;
  }
54a7357f7   KY Srinivasan   Drivers: net: hyp...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  static u32 fill_pg_buf(struct page *page, u32 offset, u32 len,
  			struct hv_page_buffer *pb)
  {
  	int j = 0;
  
  	/* Deal with compund pages by ignoring unused part
  	 * of the page.
  	 */
  	page += (offset >> PAGE_SHIFT);
  	offset &= ~PAGE_MASK;
  
  	while (len > 0) {
  		unsigned long bytes;
  
  		bytes = PAGE_SIZE - offset;
  		if (bytes > len)
  			bytes = len;
  		pb[j].pfn = page_to_pfn(page);
  		pb[j].offset = offset;
  		pb[j].len = bytes;
  
  		offset += bytes;
  		len -= bytes;
  
  		if (offset == PAGE_SIZE && len) {
  			page++;
  			offset = 0;
  			j++;
  		}
  	}
  
  	return j + 1;
  }
8a00251a3   KY Srinivasan   Drivers: net: hyp...
245
  static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb,
a9f2e2d65   KY Srinivasan   hv_netvsc: Elimin...
246
247
  			   struct hv_netvsc_packet *packet,
  			   struct hv_page_buffer **page_buf)
54a7357f7   KY Srinivasan   Drivers: net: hyp...
248
  {
a9f2e2d65   KY Srinivasan   hv_netvsc: Elimin...
249
  	struct hv_page_buffer *pb = *page_buf;
54a7357f7   KY Srinivasan   Drivers: net: hyp...
250
251
252
253
254
255
  	u32 slots_used = 0;
  	char *data = skb->data;
  	int frags = skb_shinfo(skb)->nr_frags;
  	int i;
  
  	/* The packet is laid out thus:
aa0a34be6   Haiyang Zhang   hv_netvsc: Implem...
256
  	 * 1. hdr: RNDIS header and PPI
54a7357f7   KY Srinivasan   Drivers: net: hyp...
257
258
259
260
261
262
263
  	 * 2. skb linear data
  	 * 3. skb fragment data
  	 */
  	if (hdr != NULL)
  		slots_used += fill_pg_buf(virt_to_page(hdr),
  					offset_in_page(hdr),
  					len, &pb[slots_used]);
aa0a34be6   Haiyang Zhang   hv_netvsc: Implem...
264
265
  	packet->rmsg_size = len;
  	packet->rmsg_pgcnt = slots_used;
54a7357f7   KY Srinivasan   Drivers: net: hyp...
266
267
268
269
270
271
272
273
274
275
276
  	slots_used += fill_pg_buf(virt_to_page(data),
  				offset_in_page(data),
  				skb_headlen(skb), &pb[slots_used]);
  
  	for (i = 0; i < frags; i++) {
  		skb_frag_t *frag = skb_shinfo(skb)->frags + i;
  
  		slots_used += fill_pg_buf(skb_frag_page(frag),
  					frag->page_offset,
  					skb_frag_size(frag), &pb[slots_used]);
  	}
8a00251a3   KY Srinivasan   Drivers: net: hyp...
277
  	return slots_used;
54a7357f7   KY Srinivasan   Drivers: net: hyp...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  }
  
  static int count_skb_frag_slots(struct sk_buff *skb)
  {
  	int i, frags = skb_shinfo(skb)->nr_frags;
  	int pages = 0;
  
  	for (i = 0; i < frags; i++) {
  		skb_frag_t *frag = skb_shinfo(skb)->frags + i;
  		unsigned long size = skb_frag_size(frag);
  		unsigned long offset = frag->page_offset;
  
  		/* Skip unused frames from start of page */
  		offset &= ~PAGE_MASK;
  		pages += PFN_UP(offset + size);
  	}
  	return pages;
  }
  
  static int netvsc_get_slots(struct sk_buff *skb)
  {
  	char *data = skb->data;
  	unsigned int offset = offset_in_page(data);
  	unsigned int len = skb_headlen(skb);
  	int slots;
  	int frag_slots;
  
  	slots = DIV_ROUND_UP(offset + len, PAGE_SIZE);
  	frag_slots = count_skb_frag_slots(skb);
  	return slots + frag_slots;
  }
08cd04bf6   KY Srinivasan   Drivers: net: hyp...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  static u32 get_net_transport_info(struct sk_buff *skb, u32 *trans_off)
  {
  	u32 ret_val = TRANSPORT_INFO_NOT_IP;
  
  	if ((eth_hdr(skb)->h_proto != htons(ETH_P_IP)) &&
  		(eth_hdr(skb)->h_proto != htons(ETH_P_IPV6))) {
  		goto not_ip;
  	}
  
  	*trans_off = skb_transport_offset(skb);
  
  	if ((eth_hdr(skb)->h_proto == htons(ETH_P_IP))) {
  		struct iphdr *iphdr = ip_hdr(skb);
  
  		if (iphdr->protocol == IPPROTO_TCP)
  			ret_val = TRANSPORT_INFO_IPV4_TCP;
  		else if (iphdr->protocol == IPPROTO_UDP)
  			ret_val = TRANSPORT_INFO_IPV4_UDP;
  	} else {
  		if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
  			ret_val = TRANSPORT_INFO_IPV6_TCP;
  		else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
  			ret_val = TRANSPORT_INFO_IPV6_UDP;
  	}
  
  not_ip:
  	return ret_val;
  }
02fafbc61   Greg Kroah-Hartman   Staging: hv: codi...
337
  static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
fceaf24a9   Hank Janssen   Staging: hv: add ...
338
  {
fceaf24a9   Hank Janssen   Staging: hv: add ...
339
  	struct net_device_context *net_device_ctx = netdev_priv(net);
981a1bd85   Vitaly Kuznetsov   hv_netvsc: use si...
340
  	struct hv_netvsc_packet *packet = NULL;
02fafbc61   Greg Kroah-Hartman   Staging: hv: codi...
341
  	int ret;
8a00251a3   KY Srinivasan   Drivers: net: hyp...
342
343
344
345
  	unsigned int num_data_pgs;
  	struct rndis_message *rndis_msg;
  	struct rndis_packet *rndis_pkt;
  	u32 rndis_msg_size;
8a00251a3   KY Srinivasan   Drivers: net: hyp...
346
  	struct rndis_per_packet_info *ppi;
08cd04bf6   KY Srinivasan   Drivers: net: hyp...
347
348
349
  	struct ndis_tcp_ip_checksum_info *csum_info;
  	int  hdr_offset;
  	u32 net_trans_info;
307f09952   Haiyang Zhang   hyperv: Add hash ...
350
  	u32 hash;
e88f7e078   Vitaly Kuznetsov   hv_netvsc: try li...
351
  	u32 skb_length;
b08cc7915   KY Srinivasan   hv_netvsc: Elimin...
352
  	struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
a9f2e2d65   KY Srinivasan   hv_netvsc: Elimin...
353
  	struct hv_page_buffer *pb = page_buf;
fceaf24a9   Hank Janssen   Staging: hv: add ...
354

54a7357f7   KY Srinivasan   Drivers: net: hyp...
355
356
  	/* We will atmost need two pages to describe the rndis
  	 * header. We can only transmit MAX_PAGE_BUFFER_COUNT number
e88f7e078   Vitaly Kuznetsov   hv_netvsc: try li...
357
358
  	 * of pages in a single packet. If skb is scattered around
  	 * more pages we try linearizing it.
54a7357f7   KY Srinivasan   Drivers: net: hyp...
359
  	 */
e88f7e078   Vitaly Kuznetsov   hv_netvsc: try li...
360

e88f7e078   Vitaly Kuznetsov   hv_netvsc: try li...
361
  	skb_length = skb->len;
8a00251a3   KY Srinivasan   Drivers: net: hyp...
362
  	num_data_pgs = netvsc_get_slots(skb) + 2;
0ab05141f   Stephen Hemminger   hv_netvsc: rearra...
363
364
  
  	if (unlikely(num_data_pgs > MAX_PAGE_BUFFER_COUNT)) {
4323b47cf   Stephen Hemminger   hv_netvsc: add et...
365
366
367
368
  		++net_device_ctx->eth_stats.tx_scattered;
  
  		if (skb_linearize(skb))
  			goto no_memory;
0ab05141f   Stephen Hemminger   hv_netvsc: rearra...
369
370
371
  
  		num_data_pgs = netvsc_get_slots(skb) + 2;
  		if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
4323b47cf   Stephen Hemminger   hv_netvsc: add et...
372
  			++net_device_ctx->eth_stats.tx_too_big;
0ab05141f   Stephen Hemminger   hv_netvsc: rearra...
373
374
  			goto drop;
  		}
54a7357f7   KY Srinivasan   Drivers: net: hyp...
375
  	}
fceaf24a9   Hank Janssen   Staging: hv: add ...
376

c0eb45403   KY Srinivasan   hv_netvsc: Don't ...
377
378
379
380
381
382
  	/*
  	 * Place the rndis header in the skb head room and
  	 * the skb->cb will be used for hv_netvsc_packet
  	 * structure.
  	 */
  	ret = skb_cow_head(skb, RNDIS_AND_PPI_SIZE);
4323b47cf   Stephen Hemminger   hv_netvsc: add et...
383
384
  	if (ret)
  		goto no_memory;
c0eb45403   KY Srinivasan   hv_netvsc: Don't ...
385
386
387
388
  	/* Use the skb control buffer for building up the packet */
  	BUILD_BUG_ON(sizeof(struct hv_netvsc_packet) >
  			FIELD_SIZEOF(struct sk_buff, cb));
  	packet = (struct hv_netvsc_packet *)skb->cb;
fceaf24a9   Hank Janssen   Staging: hv: add ...
389

5b54dac85   Haiyang Zhang   hyperv: Add suppo...
390
  	packet->q_idx = skb_get_queue_mapping(skb);
4d447c9a6   Haiyang Zhang   net/hyperv: Add s...
391
  	packet->total_data_buflen = skb->len;
fceaf24a9   Hank Janssen   Staging: hv: add ...
392

c0eb45403   KY Srinivasan   hv_netvsc: Don't ...
393
  	rndis_msg = (struct rndis_message *)skb->head;
b08cc7915   KY Srinivasan   hv_netvsc: Elimin...
394

24476760e   KY Srinivasan   hv_netvsc: Elimin...
395
  	memset(rndis_msg, 0, RNDIS_AND_PPI_SIZE);
fceaf24a9   Hank Janssen   Staging: hv: add ...
396

8a00251a3   KY Srinivasan   Drivers: net: hyp...
397
  	/* Add the rndis header */
8a00251a3   KY Srinivasan   Drivers: net: hyp...
398
399
400
401
402
403
404
405
  	rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
  	rndis_msg->msg_len = packet->total_data_buflen;
  	rndis_pkt = &rndis_msg->msg.pkt;
  	rndis_pkt->data_offset = sizeof(struct rndis_packet);
  	rndis_pkt->data_len = packet->total_data_buflen;
  	rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet);
  
  	rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
307f09952   Haiyang Zhang   hyperv: Add hash ...
406
407
408
409
410
411
412
  	hash = skb_get_hash_raw(skb);
  	if (hash != 0 && net->real_num_tx_queues > 1) {
  		rndis_msg_size += NDIS_HASH_PPI_SIZE;
  		ppi = init_ppi_data(rndis_msg, NDIS_HASH_PPI_SIZE,
  				    NBL_HASH_VALUE);
  		*(u32 *)((void *)ppi + ppi->ppi_offset) = hash;
  	}
0ab05141f   Stephen Hemminger   hv_netvsc: rearra...
413
  	if (skb_vlan_tag_present(skb)) {
8a00251a3   KY Srinivasan   Drivers: net: hyp...
414
415
416
417
418
419
420
  		struct ndis_pkt_8021q_info *vlan;
  
  		rndis_msg_size += NDIS_VLAN_PPI_SIZE;
  		ppi = init_ppi_data(rndis_msg, NDIS_VLAN_PPI_SIZE,
  					IEEE_8021Q_INFO);
  		vlan = (struct ndis_pkt_8021q_info *)((void *)ppi +
  						ppi->ppi_offset);
760d1e36c   KY Srinivasan   hv_netvsc: Elimin...
421
422
  		vlan->vlanid = skb->vlan_tci & VLAN_VID_MASK;
  		vlan->pri = (skb->vlan_tci & VLAN_PRIO_MASK) >>
8a00251a3   KY Srinivasan   Drivers: net: hyp...
423
424
  				VLAN_PRIO_SHIFT;
  	}
08cd04bf6   KY Srinivasan   Drivers: net: hyp...
425
  	net_trans_info = get_net_transport_info(skb, &hdr_offset);
08cd04bf6   KY Srinivasan   Drivers: net: hyp...
426
427
428
429
430
  
  	/*
  	 * Setup the sendside checksum offload only if this is not a
  	 * GSO packet.
  	 */
52ccd6318   Arnd Bergmann   net/hyperv: avoid...
431
  	if ((net_trans_info & (INFO_TCP | INFO_UDP)) && skb_is_gso(skb)) {
0ab05141f   Stephen Hemminger   hv_netvsc: rearra...
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
  		struct ndis_tcp_lso_info *lso_info;
  
  		rndis_msg_size += NDIS_LSO_PPI_SIZE;
  		ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE,
  				    TCP_LARGESEND_PKTINFO);
  
  		lso_info = (struct ndis_tcp_lso_info *)((void *)ppi +
  							ppi->ppi_offset);
  
  		lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE;
  		if (net_trans_info & (INFO_IPV4 << 16)) {
  			lso_info->lso_v2_transmit.ip_version =
  				NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4;
  			ip_hdr(skb)->tot_len = 0;
  			ip_hdr(skb)->check = 0;
  			tcp_hdr(skb)->check =
  				~csum_tcpudp_magic(ip_hdr(skb)->saddr,
  						   ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
  		} else {
  			lso_info->lso_v2_transmit.ip_version =
  				NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6;
  			ipv6_hdr(skb)->payload_len = 0;
  			tcp_hdr(skb)->check =
  				~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
  						 &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
  		}
  		lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset;
  		lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size;
ad19bc8a9   stephen hemminger   netvsc: fix check...
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
  		if (net_trans_info & INFO_TCP) {
  			rndis_msg_size += NDIS_CSUM_PPI_SIZE;
  			ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE,
  					    TCPIP_CHKSUM_PKTINFO);
  
  			csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi +
  									 ppi->ppi_offset);
  
  			if (net_trans_info & (INFO_IPV4 << 16))
  				csum_info->transmit.is_ipv4 = 1;
  			else
  				csum_info->transmit.is_ipv6 = 1;
  
  			csum_info->transmit.tcp_checksum = 1;
  			csum_info->transmit.tcp_header_offset = hdr_offset;
  		} else {
  			/* UDP checksum (and other) offload is not supported. */
  			if (skb_checksum_help(skb))
  				goto drop;
  		}
08cd04bf6   KY Srinivasan   Drivers: net: hyp...
481
  	}
8a00251a3   KY Srinivasan   Drivers: net: hyp...
482
483
  	/* Start filling in the page buffers with the rndis hdr */
  	rndis_msg->msg_len += rndis_msg_size;
942396b01   Haiyang Zhang   hyperv: Fix the t...
484
  	packet->total_data_buflen = rndis_msg->msg_len;
8a00251a3   KY Srinivasan   Drivers: net: hyp...
485
  	packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
a9f2e2d65   KY Srinivasan   hv_netvsc: Elimin...
486
  					       skb, packet, &pb);
8a00251a3   KY Srinivasan   Drivers: net: hyp...
487

76d13b568   sixiao@microsoft.com   hv_netvsc: add so...
488
489
  	/* timestamp packet in software */
  	skb_tx_timestamp(skb);
3a3d9a0a7   KY Srinivasan   hv_netvsc: Elimin...
490
491
  	ret = netvsc_send(net_device_ctx->device_ctx, packet,
  			  rndis_msg, &pb, skb);
0ab05141f   Stephen Hemminger   hv_netvsc: rearra...
492
  	if (likely(ret == 0)) {
4323b47cf   Stephen Hemminger   hv_netvsc: add et...
493
  		struct netvsc_stats *tx_stats = this_cpu_ptr(net_device_ctx->tx_stats);
4b02b58b5   sixiao@microsoft.com   hv_netvsc: change...
494
  		u64_stats_update_begin(&tx_stats->syncp);
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
495
496
  		tx_stats->packets++;
  		tx_stats->bytes += skb_length;
4b02b58b5   sixiao@microsoft.com   hv_netvsc: change...
497
  		u64_stats_update_end(&tx_stats->syncp);
0ab05141f   Stephen Hemminger   hv_netvsc: rearra...
498
  		return NETDEV_TX_OK;
fceaf24a9   Hank Janssen   Staging: hv: add ...
499
  	}
4323b47cf   Stephen Hemminger   hv_netvsc: add et...
500
501
502
  
  	if (ret == -EAGAIN) {
  		++net_device_ctx->eth_stats.tx_busy;
0ab05141f   Stephen Hemminger   hv_netvsc: rearra...
503
  		return NETDEV_TX_BUSY;
4323b47cf   Stephen Hemminger   hv_netvsc: add et...
504
505
506
507
  	}
  
  	if (ret == -ENOSPC)
  		++net_device_ctx->eth_stats.tx_no_space;
0ab05141f   Stephen Hemminger   hv_netvsc: rearra...
508
509
510
511
  
  drop:
  	dev_kfree_skb_any(skb);
  	net->stats.tx_dropped++;
fceaf24a9   Hank Janssen   Staging: hv: add ...
512

0ab05141f   Stephen Hemminger   hv_netvsc: rearra...
513
  	return NETDEV_TX_OK;
4323b47cf   Stephen Hemminger   hv_netvsc: add et...
514
515
516
517
  
  no_memory:
  	++net_device_ctx->eth_stats.tx_no_memory;
  	goto drop;
fceaf24a9   Hank Janssen   Staging: hv: add ...
518
  }
3e1895195   Hank Janssen   staging: hv: Corr...
519
  /*
02fafbc61   Greg Kroah-Hartman   Staging: hv: codi...
520
521
   * netvsc_linkstatus_callback - Link up/down notification
   */
90ef117a3   K. Y. Srinivasan   Staging: hv: netv...
522
  void netvsc_linkstatus_callback(struct hv_device *device_obj,
3a494e710   Haiyang Zhang   hyperv: Add handl...
523
  				struct rndis_message *resp)
fceaf24a9   Hank Janssen   Staging: hv: add ...
524
  {
3a494e710   Haiyang Zhang   hyperv: Add handl...
525
  	struct rndis_indicate_status *indicate = &resp->msg.indicate_status;
2ddd5e5fb   K. Y. Srinivasan   Staging: hv: netv...
526
  	struct net_device *net;
c996edcf1   Haiyang Zhang   staging: hv: Fix ...
527
  	struct net_device_context *ndev_ctx;
27a70af3f   Vitaly Kuznetsov   hv_netvsc: rework...
528
529
  	struct netvsc_reconfig *event;
  	unsigned long flags;
891de74d6   Haiyang Zhang   hyperv: Fix the c...
530

7f5d5af0b   Haiyang Zhang   hv_netvsc: Add ha...
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
  	net = hv_get_drvdata(device_obj);
  
  	if (!net)
  		return;
  
  	ndev_ctx = netdev_priv(net);
  
  	/* Update the physical link speed when changing to another vSwitch */
  	if (indicate->status == RNDIS_STATUS_LINK_SPEED_CHANGE) {
  		u32 speed;
  
  		speed = *(u32 *)((void *)indicate + indicate->
  				 status_buf_offset) / 10000;
  		ndev_ctx->speed = speed;
  		return;
  	}
  
  	/* Handle these link change statuses below */
27a70af3f   Vitaly Kuznetsov   hv_netvsc: rework...
549
550
551
  	if (indicate->status != RNDIS_STATUS_NETWORK_CHANGE &&
  	    indicate->status != RNDIS_STATUS_MEDIA_CONNECT &&
  	    indicate->status != RNDIS_STATUS_MEDIA_DISCONNECT)
3a494e710   Haiyang Zhang   hyperv: Add handl...
552
  		return;
891de74d6   Haiyang Zhang   hyperv: Fix the c...
553

7f5d5af0b   Haiyang Zhang   hv_netvsc: Add ha...
554
  	if (net->reg_state != NETREG_REGISTERED)
fceaf24a9   Hank Janssen   Staging: hv: add ...
555
  		return;
fceaf24a9   Hank Janssen   Staging: hv: add ...
556

27a70af3f   Vitaly Kuznetsov   hv_netvsc: rework...
557
558
559
560
561
562
563
564
565
566
  	event = kzalloc(sizeof(*event), GFP_ATOMIC);
  	if (!event)
  		return;
  	event->event = indicate->status;
  
  	spin_lock_irqsave(&ndev_ctx->lock, flags);
  	list_add_tail(&event->list, &ndev_ctx->reconfig_events);
  	spin_unlock_irqrestore(&ndev_ctx->lock, flags);
  
  	schedule_delayed_work(&ndev_ctx->dwork, 0);
fceaf24a9   Hank Janssen   Staging: hv: add ...
567
  }
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
568
  static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
e3d605ed4   KY Srinivasan   Drivers: net: hyp...
569
  				struct hv_netvsc_packet *packet,
25b85ee89   KY Srinivasan   hv_netvsc: Elimin...
570
  				struct ndis_tcp_ip_checksum_info *csum_info,
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
571
  				void *data, u16 vlan_tci)
fceaf24a9   Hank Janssen   Staging: hv: add ...
572
  {
fceaf24a9   Hank Janssen   Staging: hv: add ...
573
  	struct sk_buff *skb;
fceaf24a9   Hank Janssen   Staging: hv: add ...
574

72a2f5bd5   Haiyang Zhang   staging: hv: Conv...
575
  	skb = netdev_alloc_skb_ip_align(net, packet->total_data_buflen);
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
576
577
  	if (!skb)
  		return skb;
fceaf24a9   Hank Janssen   Staging: hv: add ...
578

02fafbc61   Greg Kroah-Hartman   Staging: hv: codi...
579
580
581
582
  	/*
  	 * Copy to skb. This copy is needed here since the memory pointed by
  	 * hv_netvsc_packet cannot be deallocated
  	 */
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
583
584
  	memcpy(skb_put(skb, packet->total_data_buflen), data,
  	       packet->total_data_buflen);
fceaf24a9   Hank Janssen   Staging: hv: add ...
585
586
  
  	skb->protocol = eth_type_trans(skb, net);
e52fed717   Stephen Hemminger   netvsc: fix incor...
587
588
589
590
591
592
593
594
595
596
597
  
  	/* skb is already created with CHECKSUM_NONE */
  	skb_checksum_none_assert(skb);
  
  	/*
  	 * In Linux, the IP checksum is always checked.
  	 * Do L4 checksum offload if enabled and present.
  	 */
  	if (csum_info && (net->features & NETIF_F_RXCSUM)) {
  		if (csum_info->receive.tcp_checksum_succeeded ||
  		    csum_info->receive.udp_checksum_succeeded)
e3d605ed4   KY Srinivasan   Drivers: net: hyp...
598
  			skb->ip_summed = CHECKSUM_UNNECESSARY;
e3d605ed4   KY Srinivasan   Drivers: net: hyp...
599
  	}
760d1e36c   KY Srinivasan   hv_netvsc: Elimin...
600
  	if (vlan_tci & VLAN_TAG_PRESENT)
93725cbd2   Haiyang Zhang   Fix the VLAN_TAG_...
601
  		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
760d1e36c   KY Srinivasan   hv_netvsc: Elimin...
602
  				       vlan_tci);
fceaf24a9   Hank Janssen   Staging: hv: add ...
603

84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
604
605
606
607
608
609
610
611
612
613
614
615
616
617
  	return skb;
  }
  
  /*
   * netvsc_recv_callback -  Callback when we receive a packet from the
   * "wire" on the specified device.
   */
  int netvsc_recv_callback(struct hv_device *device_obj,
  				struct hv_netvsc_packet *packet,
  				void **data,
  				struct ndis_tcp_ip_checksum_info *csum_info,
  				struct vmbus_channel *channel,
  				u16 vlan_tci)
  {
3d541ac5a   Vitaly Kuznetsov   hv_netvsc: untang...
618
619
  	struct net_device *net = hv_get_drvdata(device_obj);
  	struct net_device_context *net_device_ctx = netdev_priv(net);
f207c10d9   Stephen Hemminger   hv_netvsc: use RC...
620
  	struct net_device *vf_netdev;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
621
  	struct sk_buff *skb;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
622
  	struct netvsc_stats *rx_stats;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
623

9cbcc4280   Stephen Hemminger   hv_netvsc: remove...
624
  	if (net->reg_state != NETREG_REGISTERED)
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
625
  		return NVSP_STAT_FAIL;
9cbcc4280   Stephen Hemminger   hv_netvsc: remove...
626
627
628
629
630
631
632
  	/*
  	 * If necessary, inject this packet into the VF interface.
  	 * On Hyper-V, multicast and brodcast packets are only delivered
  	 * to the synthetic interface (after subjecting these to
  	 * policy filters on the host). Deliver these via the VF
  	 * interface in the guest.
  	 */
5b3df4401   stephen hemminger   netvsc: add rcu_r...
633
  	rcu_read_lock();
f207c10d9   Stephen Hemminger   hv_netvsc: use RC...
634
  	vf_netdev = rcu_dereference(net_device_ctx->vf_netdev);
9cbcc4280   Stephen Hemminger   hv_netvsc: remove...
635
636
  	if (vf_netdev && (vf_netdev->flags & IFF_UP))
  		net = vf_netdev;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
637
638
639
640
641
  
  	/* Allocate a skb - TODO direct I/O to pages? */
  	skb = netvsc_alloc_recv_skb(net, packet, csum_info, *data, vlan_tci);
  	if (unlikely(!skb)) {
  		++net->stats.rx_dropped;
5b3df4401   stephen hemminger   netvsc: add rcu_r...
642
  		rcu_read_unlock();
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
643
644
  		return NVSP_STAT_FAIL;
  	}
5b54dac85   Haiyang Zhang   hyperv: Add suppo...
645

9cbcc4280   Stephen Hemminger   hv_netvsc: remove...
646
647
648
649
650
651
652
653
654
655
  	if (net != vf_netdev)
  		skb_record_rx_queue(skb,
  				    channel->offermsg.offer.sub_channel_index);
  
  	/*
  	 * Even if injecting the packet, record the statistics
  	 * on the synthetic device because modifying the VF device
  	 * statistics will not work correctly.
  	 */
  	rx_stats = this_cpu_ptr(net_device_ctx->rx_stats);
4b02b58b5   sixiao@microsoft.com   hv_netvsc: change...
656
  	u64_stats_update_begin(&rx_stats->syncp);
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
657
658
  	rx_stats->packets++;
  	rx_stats->bytes += packet->total_data_buflen;
f7ad75b75   Stephen Hemminger   hv_netvsc: count ...
659
660
661
662
663
  
  	if (skb->pkt_type == PACKET_BROADCAST)
  		++rx_stats->broadcast;
  	else if (skb->pkt_type == PACKET_MULTICAST)
  		++rx_stats->multicast;
4b02b58b5   sixiao@microsoft.com   hv_netvsc: change...
664
  	u64_stats_update_end(&rx_stats->syncp);
9495c282b   Stephen Hemminger   Staging: hv: hand...
665

02fafbc61   Greg Kroah-Hartman   Staging: hv: codi...
666
667
  	/*
  	 * Pass the skb back up. Network stack will deallocate the skb when it
9495c282b   Stephen Hemminger   Staging: hv: hand...
668
669
  	 * is done.
  	 * TODO - use NAPI?
02fafbc61   Greg Kroah-Hartman   Staging: hv: codi...
670
  	 */
9495c282b   Stephen Hemminger   Staging: hv: hand...
671
  	netif_rx(skb);
5b3df4401   stephen hemminger   netvsc: add rcu_r...
672
  	rcu_read_unlock();
fceaf24a9   Hank Janssen   Staging: hv: add ...
673

fceaf24a9   Hank Janssen   Staging: hv: add ...
674
675
  	return 0;
  }
f82f4ad7b   Stephen Hemminger   Staging: hv: add ...
676
677
678
  static void netvsc_get_drvinfo(struct net_device *net,
  			       struct ethtool_drvinfo *info)
  {
7826d43f2   Jiri Pirko   ethtool: fix drvi...
679
  	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
7826d43f2   Jiri Pirko   ethtool: fix drvi...
680
  	strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
f82f4ad7b   Stephen Hemminger   Staging: hv: add ...
681
  }
59995370d   Andrew Schwartzmeyer   hyperv: Implement...
682
683
684
685
  static void netvsc_get_channels(struct net_device *net,
  				struct ethtool_channels *channel)
  {
  	struct net_device_context *net_device_ctx = netdev_priv(net);
3d541ac5a   Vitaly Kuznetsov   hv_netvsc: untang...
686
  	struct netvsc_device *nvdev = net_device_ctx->nvdev;
59995370d   Andrew Schwartzmeyer   hyperv: Implement...
687
688
689
690
691
692
  
  	if (nvdev) {
  		channel->max_combined	= nvdev->max_chn;
  		channel->combined_count = nvdev->num_chn;
  	}
  }
b5960e6e2   Andrew Schwartzmeyer   hv_netvsc: Implem...
693
694
695
696
697
  static int netvsc_set_channels(struct net_device *net,
  			       struct ethtool_channels *channels)
  {
  	struct net_device_context *net_device_ctx = netdev_priv(net);
  	struct hv_device *dev = net_device_ctx->device_ctx;
3d541ac5a   Vitaly Kuznetsov   hv_netvsc: untang...
698
  	struct netvsc_device *nvdev = net_device_ctx->nvdev;
b5960e6e2   Andrew Schwartzmeyer   hv_netvsc: Implem...
699
  	struct netvsc_device_info device_info;
954591b9f   Andrew Schwartzmeyer   hv_netvsc: Fix de...
700
701
  	u32 num_chn;
  	u32 max_chn;
b5960e6e2   Andrew Schwartzmeyer   hv_netvsc: Implem...
702
703
  	int ret = 0;
  	bool recovering = false;
6da7225f5   Vitaly Kuznetsov   hv_netvsc: synchr...
704
  	if (net_device_ctx->start_remove || !nvdev || nvdev->destroy)
b5960e6e2   Andrew Schwartzmeyer   hv_netvsc: Implem...
705
  		return -ENODEV;
954591b9f   Andrew Schwartzmeyer   hv_netvsc: Fix de...
706
707
  	num_chn = nvdev->num_chn;
  	max_chn = min_t(u32, nvdev->max_chn, num_online_cpus());
b5960e6e2   Andrew Schwartzmeyer   hv_netvsc: Implem...
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
  	if (nvdev->nvsp_version < NVSP_PROTOCOL_VERSION_5) {
  		pr_info("vRSS unsupported before NVSP Version 5
  ");
  		return -EINVAL;
  	}
  
  	/* We do not support rx, tx, or other */
  	if (!channels ||
  	    channels->rx_count ||
  	    channels->tx_count ||
  	    channels->other_count ||
  	    (channels->combined_count < 1))
  		return -EINVAL;
  
  	if (channels->combined_count > max_chn) {
  		pr_info("combined channels too high, using %d
  ", max_chn);
  		channels->combined_count = max_chn;
  	}
  
  	ret = netvsc_close(net);
  	if (ret)
  		goto out;
  
   do_set:
f580aec4b   Vitaly Kuznetsov   hv_netvsc: move s...
733
  	net_device_ctx->start_remove = true;
b5960e6e2   Andrew Schwartzmeyer   hv_netvsc: Implem...
734
735
736
  	rndis_filter_device_remove(dev);
  
  	nvdev->num_chn = channels->combined_count;
b5960e6e2   Andrew Schwartzmeyer   hv_netvsc: Implem...
737
738
739
740
741
742
743
744
745
746
747
748
749
750
  	memset(&device_info, 0, sizeof(device_info));
  	device_info.num_chn = nvdev->num_chn; /* passed to RNDIS */
  	device_info.ring_size = ring_size;
  	device_info.max_num_vrss_chns = max_num_vrss_chns;
  
  	ret = rndis_filter_device_add(dev, &device_info);
  	if (ret) {
  		if (recovering) {
  			netdev_err(net, "unable to add netvsc device (ret %d)
  ", ret);
  			return ret;
  		}
  		goto recover;
  	}
3d541ac5a   Vitaly Kuznetsov   hv_netvsc: untang...
751
  	nvdev = net_device_ctx->nvdev;
b5960e6e2   Andrew Schwartzmeyer   hv_netvsc: Implem...
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
  
  	ret = netif_set_real_num_tx_queues(net, nvdev->num_chn);
  	if (ret) {
  		if (recovering) {
  			netdev_err(net, "could not set tx queue count (ret %d)
  ", ret);
  			return ret;
  		}
  		goto recover;
  	}
  
  	ret = netif_set_real_num_rx_queues(net, nvdev->num_chn);
  	if (ret) {
  		if (recovering) {
  			netdev_err(net, "could not set rx queue count (ret %d)
  ", ret);
  			return ret;
  		}
  		goto recover;
  	}
  
   out:
  	netvsc_open(net);
f580aec4b   Vitaly Kuznetsov   hv_netvsc: move s...
775
  	net_device_ctx->start_remove = false;
1bdcec8a5   Vitaly Kuznetsov   hv_netvsc: use st...
776
777
  	/* We may have missed link change notifications */
  	schedule_delayed_work(&net_device_ctx->dwork, 0);
b5960e6e2   Andrew Schwartzmeyer   hv_netvsc: Implem...
778
779
780
781
782
783
784
785
786
787
788
789
790
  
  	return ret;
  
   recover:
  	/* If the above failed, we attempt to recover through the same
  	 * process but with the original number of channels.
  	 */
  	netdev_err(net, "could not set channels, recovering
  ");
  	recovering = true;
  	channels->combined_count = num_chn;
  	goto do_set;
  }
49eb93892   sixiao@microsoft.com   hv_netvsc: add et...
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
  static bool netvsc_validate_ethtool_ss_cmd(const struct ethtool_cmd *cmd)
  {
  	struct ethtool_cmd diff1 = *cmd;
  	struct ethtool_cmd diff2 = {};
  
  	ethtool_cmd_speed_set(&diff1, 0);
  	diff1.duplex = 0;
  	/* advertising and cmd are usually set */
  	diff1.advertising = 0;
  	diff1.cmd = 0;
  	/* We set port to PORT_OTHER */
  	diff2.port = PORT_OTHER;
  
  	return !memcmp(&diff1, &diff2, sizeof(diff1));
  }
  
  static void netvsc_init_settings(struct net_device *dev)
  {
  	struct net_device_context *ndc = netdev_priv(dev);
  
  	ndc->speed = SPEED_UNKNOWN;
  	ndc->duplex = DUPLEX_UNKNOWN;
  }
  
  static int netvsc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  {
  	struct net_device_context *ndc = netdev_priv(dev);
  
  	ethtool_cmd_speed_set(cmd, ndc->speed);
  	cmd->duplex = ndc->duplex;
  	cmd->port = PORT_OTHER;
  
  	return 0;
  }
  
  static int netvsc_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  {
  	struct net_device_context *ndc = netdev_priv(dev);
  	u32 speed;
  
  	speed = ethtool_cmd_speed(cmd);
  	if (!ethtool_validate_speed(speed) ||
  	    !ethtool_validate_duplex(cmd->duplex) ||
  	    !netvsc_validate_ethtool_ss_cmd(cmd))
  		return -EINVAL;
  
  	ndc->speed = speed;
  	ndc->duplex = cmd->duplex;
  
  	return 0;
  }
4d447c9a6   Haiyang Zhang   net/hyperv: Add s...
842
843
844
  static int netvsc_change_mtu(struct net_device *ndev, int mtu)
  {
  	struct net_device_context *ndevctx = netdev_priv(ndev);
3d541ac5a   Vitaly Kuznetsov   hv_netvsc: untang...
845
846
  	struct netvsc_device *nvdev = ndevctx->nvdev;
  	struct hv_device *hdev = ndevctx->device_ctx;
4d447c9a6   Haiyang Zhang   net/hyperv: Add s...
847
848
  	struct netvsc_device_info device_info;
  	int limit = ETH_DATA_LEN;
d212b4633   Haiyang Zhang   hv_netvsc: Fix ac...
849
  	u32 num_chn;
2de8530ba   Haiyang Zhang   hv_netvsc: Add cl...
850
  	int ret = 0;
4d447c9a6   Haiyang Zhang   net/hyperv: Add s...
851

6da7225f5   Vitaly Kuznetsov   hv_netvsc: synchr...
852
  	if (ndevctx->start_remove || !nvdev || nvdev->destroy)
4d447c9a6   Haiyang Zhang   net/hyperv: Add s...
853
  		return -ENODEV;
a1eabb017   Haiyang Zhang   hyperv: Add lates...
854
  	if (nvdev->nvsp_version >= NVSP_PROTOCOL_VERSION_2)
4d3c9d37f   Haiyang Zhang   hyperv: Add proce...
855
  		limit = NETVSC_MTU - ETH_HLEN;
4d447c9a6   Haiyang Zhang   net/hyperv: Add s...
856

f9cbce34c   Haiyang Zhang   hv_netvsc: Add su...
857
  	if (mtu < NETVSC_MTU_MIN || mtu > limit)
4d447c9a6   Haiyang Zhang   net/hyperv: Add s...
858
  		return -EINVAL;
2de8530ba   Haiyang Zhang   hv_netvsc: Add cl...
859
860
861
  	ret = netvsc_close(ndev);
  	if (ret)
  		goto out;
d212b4633   Haiyang Zhang   hv_netvsc: Fix ac...
862
  	num_chn = nvdev->num_chn;
f580aec4b   Vitaly Kuznetsov   hv_netvsc: move s...
863
  	ndevctx->start_remove = true;
4d447c9a6   Haiyang Zhang   net/hyperv: Add s...
864
865
866
  	rndis_filter_device_remove(hdev);
  
  	ndev->mtu = mtu;
8ebdcc52b   Andrew Schwartzmeyer   hv_netvsc: Set vR...
867
  	memset(&device_info, 0, sizeof(device_info));
4d447c9a6   Haiyang Zhang   net/hyperv: Add s...
868
  	device_info.ring_size = ring_size;
d212b4633   Haiyang Zhang   hv_netvsc: Fix ac...
869
  	device_info.num_chn = num_chn;
e01ec2199   KY Srinivasan   hv_netvsc: Proper...
870
  	device_info.max_num_vrss_chns = max_num_vrss_chns;
4d447c9a6   Haiyang Zhang   net/hyperv: Add s...
871
  	rndis_filter_device_add(hdev, &device_info);
4d447c9a6   Haiyang Zhang   net/hyperv: Add s...
872

2de8530ba   Haiyang Zhang   hv_netvsc: Add cl...
873
874
  out:
  	netvsc_open(ndev);
f580aec4b   Vitaly Kuznetsov   hv_netvsc: move s...
875
  	ndevctx->start_remove = false;
2de8530ba   Haiyang Zhang   hv_netvsc: Add cl...
876

1bdcec8a5   Vitaly Kuznetsov   hv_netvsc: use st...
877
878
  	/* We may have missed link change notifications */
  	schedule_delayed_work(&ndevctx->dwork, 0);
2de8530ba   Haiyang Zhang   hv_netvsc: Add cl...
879
  	return ret;
4d447c9a6   Haiyang Zhang   net/hyperv: Add s...
880
  }
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
881
882
883
884
885
886
887
888
889
890
891
  static struct rtnl_link_stats64 *netvsc_get_stats64(struct net_device *net,
  						    struct rtnl_link_stats64 *t)
  {
  	struct net_device_context *ndev_ctx = netdev_priv(net);
  	int cpu;
  
  	for_each_possible_cpu(cpu) {
  		struct netvsc_stats *tx_stats = per_cpu_ptr(ndev_ctx->tx_stats,
  							    cpu);
  		struct netvsc_stats *rx_stats = per_cpu_ptr(ndev_ctx->rx_stats,
  							    cpu);
f7ad75b75   Stephen Hemminger   hv_netvsc: count ...
892
  		u64 tx_packets, tx_bytes, rx_packets, rx_bytes, rx_multicast;
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
893
894
895
  		unsigned int start;
  
  		do {
4b02b58b5   sixiao@microsoft.com   hv_netvsc: change...
896
  			start = u64_stats_fetch_begin_irq(&tx_stats->syncp);
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
897
898
  			tx_packets = tx_stats->packets;
  			tx_bytes = tx_stats->bytes;
4b02b58b5   sixiao@microsoft.com   hv_netvsc: change...
899
  		} while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start));
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
900
901
  
  		do {
4b02b58b5   sixiao@microsoft.com   hv_netvsc: change...
902
  			start = u64_stats_fetch_begin_irq(&rx_stats->syncp);
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
903
904
  			rx_packets = rx_stats->packets;
  			rx_bytes = rx_stats->bytes;
f7ad75b75   Stephen Hemminger   hv_netvsc: count ...
905
  			rx_multicast = rx_stats->multicast + rx_stats->broadcast;
4b02b58b5   sixiao@microsoft.com   hv_netvsc: change...
906
  		} while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start));
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
907
908
909
910
911
  
  		t->tx_bytes	+= tx_bytes;
  		t->tx_packets	+= tx_packets;
  		t->rx_bytes	+= rx_bytes;
  		t->rx_packets	+= rx_packets;
f7ad75b75   Stephen Hemminger   hv_netvsc: count ...
912
  		t->multicast	+= rx_multicast;
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
913
914
915
916
917
918
919
920
921
922
  	}
  
  	t->tx_dropped	= net->stats.tx_dropped;
  	t->tx_errors	= net->stats.tx_dropped;
  
  	t->rx_dropped	= net->stats.rx_dropped;
  	t->rx_errors	= net->stats.rx_errors;
  
  	return t;
  }
1ce09e899   Haiyang Zhang   hyperv: Add suppo...
923
924
925
  
  static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
  {
1ce09e899   Haiyang Zhang   hyperv: Add suppo...
926
  	struct sockaddr *addr = p;
9a4c831eb   Jianjun Kong   net/hyperv: fix w...
927
  	char save_adr[ETH_ALEN];
1ce09e899   Haiyang Zhang   hyperv: Add suppo...
928
929
930
931
932
933
934
935
936
  	unsigned char save_aatype;
  	int err;
  
  	memcpy(save_adr, ndev->dev_addr, ETH_ALEN);
  	save_aatype = ndev->addr_assign_type;
  
  	err = eth_mac_addr(ndev, p);
  	if (err != 0)
  		return err;
e834da9a4   Vitaly Kuznetsov   hv_netvsc: pass s...
937
  	err = rndis_filter_set_device_mac(ndev, addr->sa_data);
1ce09e899   Haiyang Zhang   hyperv: Add suppo...
938
939
940
941
942
943
944
945
  	if (err != 0) {
  		/* roll back to saved MAC */
  		memcpy(ndev->dev_addr, save_adr, ETH_ALEN);
  		ndev->addr_assign_type = save_aatype;
  	}
  
  	return err;
  }
4323b47cf   Stephen Hemminger   hv_netvsc: add et...
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
  static const struct {
  	char name[ETH_GSTRING_LEN];
  	u16 offset;
  } netvsc_stats[] = {
  	{ "tx_scattered", offsetof(struct netvsc_ethtool_stats, tx_scattered) },
  	{ "tx_no_memory",  offsetof(struct netvsc_ethtool_stats, tx_no_memory) },
  	{ "tx_no_space",  offsetof(struct netvsc_ethtool_stats, tx_no_space) },
  	{ "tx_too_big",	  offsetof(struct netvsc_ethtool_stats, tx_too_big) },
  	{ "tx_busy",	  offsetof(struct netvsc_ethtool_stats, tx_busy) },
  };
  
  static int netvsc_get_sset_count(struct net_device *dev, int string_set)
  {
  	switch (string_set) {
  	case ETH_SS_STATS:
  		return ARRAY_SIZE(netvsc_stats);
  	default:
  		return -EINVAL;
  	}
  }
  
  static void netvsc_get_ethtool_stats(struct net_device *dev,
  				     struct ethtool_stats *stats, u64 *data)
  {
  	struct net_device_context *ndc = netdev_priv(dev);
  	const void *nds = &ndc->eth_stats;
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(netvsc_stats); i++)
  		data[i] = *(unsigned long *)(nds + netvsc_stats[i].offset);
  }
  
  static void netvsc_get_strings(struct net_device *dev, u32 stringset, u8 *data)
  {
  	int i;
  
  	switch (stringset) {
  	case ETH_SS_STATS:
  		for (i = 0; i < ARRAY_SIZE(netvsc_stats); i++)
  			memcpy(data + i * ETH_GSTRING_LEN,
  			       netvsc_stats[i].name, ETH_GSTRING_LEN);
  		break;
  	}
  }
316158fef   Richard Weinberger   hyperv: Add netpo...
990
991
992
993
994
995
996
997
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void netvsc_poll_controller(struct net_device *net)
  {
  	/* As netvsc_start_xmit() works synchronous we don't have to
  	 * trigger anything here.
  	 */
  }
  #endif
1ce09e899   Haiyang Zhang   hyperv: Add suppo...
998

f82f4ad7b   Stephen Hemminger   Staging: hv: add ...
999
1000
  static const struct ethtool_ops ethtool_ops = {
  	.get_drvinfo	= netvsc_get_drvinfo,
f82f4ad7b   Stephen Hemminger   Staging: hv: add ...
1001
  	.get_link	= ethtool_op_get_link,
4323b47cf   Stephen Hemminger   hv_netvsc: add et...
1002
1003
1004
  	.get_ethtool_stats = netvsc_get_ethtool_stats,
  	.get_sset_count = netvsc_get_sset_count,
  	.get_strings	= netvsc_get_strings,
59995370d   Andrew Schwartzmeyer   hyperv: Implement...
1005
  	.get_channels   = netvsc_get_channels,
b5960e6e2   Andrew Schwartzmeyer   hv_netvsc: Implem...
1006
  	.set_channels   = netvsc_set_channels,
76d13b568   sixiao@microsoft.com   hv_netvsc: add so...
1007
  	.get_ts_info	= ethtool_op_get_ts_info,
49eb93892   sixiao@microsoft.com   hv_netvsc: add et...
1008
1009
  	.get_settings	= netvsc_get_settings,
  	.set_settings	= netvsc_set_settings,
f82f4ad7b   Stephen Hemminger   Staging: hv: add ...
1010
  };
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1011
1012
1013
1014
  static const struct net_device_ops device_ops = {
  	.ndo_open =			netvsc_open,
  	.ndo_stop =			netvsc_close,
  	.ndo_start_xmit =		netvsc_start_xmit,
afc4b13df   Jiri Pirko   net: remove use o...
1015
  	.ndo_set_rx_mode =		netvsc_set_multicast_list,
4d447c9a6   Haiyang Zhang   net/hyperv: Add s...
1016
  	.ndo_change_mtu =		netvsc_change_mtu,
b681b5886   Haiyang Zhang   staging: hv: Fix ...
1017
  	.ndo_validate_addr =		eth_validate_addr,
1ce09e899   Haiyang Zhang   hyperv: Add suppo...
1018
  	.ndo_set_mac_address =		netvsc_set_mac_addr,
5b54dac85   Haiyang Zhang   hyperv: Add suppo...
1019
  	.ndo_select_queue =		netvsc_select_queue,
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
1020
  	.ndo_get_stats64 =		netvsc_get_stats64,
316158fef   Richard Weinberger   hyperv: Add netpo...
1021
1022
1023
  #ifdef CONFIG_NET_POLL_CONTROLLER
  	.ndo_poll_controller =		netvsc_poll_controller,
  #endif
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1024
  };
c996edcf1   Haiyang Zhang   staging: hv: Fix ...
1025
  /*
27a70af3f   Vitaly Kuznetsov   hv_netvsc: rework...
1026
1027
1028
   * Handle link status changes. For RNDIS_STATUS_NETWORK_CHANGE emulate link
   * down/up sequence. In case of RNDIS_STATUS_MEDIA_CONNECT when carrier is
   * present send GARP packet to network peers with netif_notify_peers().
c996edcf1   Haiyang Zhang   staging: hv: Fix ...
1029
   */
891de74d6   Haiyang Zhang   hyperv: Fix the c...
1030
  static void netvsc_link_change(struct work_struct *w)
c996edcf1   Haiyang Zhang   staging: hv: Fix ...
1031
  {
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1032
1033
1034
1035
  	struct net_device_context *ndev_ctx =
  		container_of(w, struct net_device_context, dwork.work);
  	struct hv_device *device_obj = ndev_ctx->device_ctx;
  	struct net_device *net = hv_get_drvdata(device_obj);
2ddd5e5fb   K. Y. Srinivasan   Staging: hv: netv...
1036
  	struct netvsc_device *net_device;
891de74d6   Haiyang Zhang   hyperv: Fix the c...
1037
  	struct rndis_device *rdev;
27a70af3f   Vitaly Kuznetsov   hv_netvsc: rework...
1038
1039
1040
  	struct netvsc_reconfig *event = NULL;
  	bool notify = false, reschedule = false;
  	unsigned long flags, next_reconfig, delay;
c996edcf1   Haiyang Zhang   staging: hv: Fix ...
1041

1bdcec8a5   Vitaly Kuznetsov   hv_netvsc: use st...
1042
1043
1044
  	rtnl_lock();
  	if (ndev_ctx->start_remove)
  		goto out_unlock;
3d541ac5a   Vitaly Kuznetsov   hv_netvsc: untang...
1045
  	net_device = ndev_ctx->nvdev;
891de74d6   Haiyang Zhang   hyperv: Fix the c...
1046
  	rdev = net_device->extension;
891de74d6   Haiyang Zhang   hyperv: Fix the c...
1047

27a70af3f   Vitaly Kuznetsov   hv_netvsc: rework...
1048
1049
1050
1051
1052
1053
1054
1055
1056
  	next_reconfig = ndev_ctx->last_reconfig + LINKCHANGE_INT;
  	if (time_is_after_jiffies(next_reconfig)) {
  		/* link_watch only sends one notification with current state
  		 * per second, avoid doing reconfig more frequently. Handle
  		 * wrap around.
  		 */
  		delay = next_reconfig - jiffies;
  		delay = delay < LINKCHANGE_INT ? delay : LINKCHANGE_INT;
  		schedule_delayed_work(&ndev_ctx->dwork, delay);
1bdcec8a5   Vitaly Kuznetsov   hv_netvsc: use st...
1057
  		goto out_unlock;
27a70af3f   Vitaly Kuznetsov   hv_netvsc: rework...
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
  	}
  	ndev_ctx->last_reconfig = jiffies;
  
  	spin_lock_irqsave(&ndev_ctx->lock, flags);
  	if (!list_empty(&ndev_ctx->reconfig_events)) {
  		event = list_first_entry(&ndev_ctx->reconfig_events,
  					 struct netvsc_reconfig, list);
  		list_del(&event->list);
  		reschedule = !list_empty(&ndev_ctx->reconfig_events);
  	}
  	spin_unlock_irqrestore(&ndev_ctx->lock, flags);
  
  	if (!event)
1bdcec8a5   Vitaly Kuznetsov   hv_netvsc: use st...
1071
  		goto out_unlock;
27a70af3f   Vitaly Kuznetsov   hv_netvsc: rework...
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
  
  	switch (event->event) {
  		/* Only the following events are possible due to the check in
  		 * netvsc_linkstatus_callback()
  		 */
  	case RNDIS_STATUS_MEDIA_CONNECT:
  		if (rdev->link_state) {
  			rdev->link_state = false;
  			netif_carrier_on(net);
  			netif_tx_wake_all_queues(net);
  		} else {
  			notify = true;
  		}
  		kfree(event);
  		break;
  	case RNDIS_STATUS_MEDIA_DISCONNECT:
  		if (!rdev->link_state) {
  			rdev->link_state = true;
  			netif_carrier_off(net);
  			netif_tx_stop_all_queues(net);
  		}
  		kfree(event);
  		break;
  	case RNDIS_STATUS_NETWORK_CHANGE:
  		/* Only makes sense if carrier is present */
  		if (!rdev->link_state) {
  			rdev->link_state = true;
  			netif_carrier_off(net);
  			netif_tx_stop_all_queues(net);
  			event->event = RNDIS_STATUS_MEDIA_CONNECT;
  			spin_lock_irqsave(&ndev_ctx->lock, flags);
15cfd4077   Haiyang Zhang   hv_netvsc: Fix th...
1103
  			list_add(&event->list, &ndev_ctx->reconfig_events);
27a70af3f   Vitaly Kuznetsov   hv_netvsc: rework...
1104
1105
  			spin_unlock_irqrestore(&ndev_ctx->lock, flags);
  			reschedule = true;
3a494e710   Haiyang Zhang   hyperv: Add handl...
1106
  		}
27a70af3f   Vitaly Kuznetsov   hv_netvsc: rework...
1107
  		break;
891de74d6   Haiyang Zhang   hyperv: Fix the c...
1108
1109
1110
1111
1112
1113
  	}
  
  	rtnl_unlock();
  
  	if (notify)
  		netdev_notify_peers(net);
27a70af3f   Vitaly Kuznetsov   hv_netvsc: rework...
1114
1115
1116
1117
1118
1119
  
  	/* link_watch only sends one notification with current state per
  	 * second, handle next reconfig event in 2 seconds.
  	 */
  	if (reschedule)
  		schedule_delayed_work(&ndev_ctx->dwork, LINKCHANGE_INT);
1bdcec8a5   Vitaly Kuznetsov   hv_netvsc: use st...
1120
1121
1122
1123
1124
  
  	return;
  
  out_unlock:
  	rtnl_unlock();
c996edcf1   Haiyang Zhang   staging: hv: Fix ...
1125
  }
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
1126
1127
1128
1129
1130
1131
1132
1133
  static void netvsc_free_netdev(struct net_device *netdev)
  {
  	struct net_device_context *net_device_ctx = netdev_priv(netdev);
  
  	free_percpu(net_device_ctx->tx_stats);
  	free_percpu(net_device_ctx->rx_stats);
  	free_netdev(netdev);
  }
c996edcf1   Haiyang Zhang   staging: hv: Fix ...
1134

e8ff40d4b   Stephen Hemminger   hv_netvsc: improv...
1135
  static struct net_device *get_netvsc_bymac(const u8 *mac)
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1136
  {
e8ff40d4b   Stephen Hemminger   hv_netvsc: improv...
1137
  	struct net_device *dev;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1138

8737caafd   Stephen Hemminger   hv_netvsc: fix rt...
1139
  	ASSERT_RTNL();
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1140
1141
  
  	for_each_netdev(&init_net, dev) {
e8ff40d4b   Stephen Hemminger   hv_netvsc: improv...
1142
1143
1144
1145
1146
1147
1148
1149
1150
  		if (dev->netdev_ops != &device_ops)
  			continue;	/* not a netvsc device */
  
  		if (ether_addr_equal(mac, dev->perm_addr))
  			return dev;
  	}
  
  	return NULL;
  }
f207c10d9   Stephen Hemminger   hv_netvsc: use RC...
1151
  static struct net_device *get_netvsc_byref(struct net_device *vf_netdev)
e8ff40d4b   Stephen Hemminger   hv_netvsc: improv...
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
  {
  	struct net_device *dev;
  
  	ASSERT_RTNL();
  
  	for_each_netdev(&init_net, dev) {
  		struct net_device_context *net_device_ctx;
  
  		if (dev->netdev_ops != &device_ops)
  			continue;	/* not a netvsc device */
  
  		net_device_ctx = netdev_priv(dev);
  		if (net_device_ctx->nvdev == NULL)
  			continue;	/* device is removed */
f207c10d9   Stephen Hemminger   hv_netvsc: use RC...
1166
  		if (rtnl_dereference(net_device_ctx->vf_netdev) == vf_netdev)
e8ff40d4b   Stephen Hemminger   hv_netvsc: improv...
1167
  			return dev;	/* a match */
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1168
  	}
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1169

e8ff40d4b   Stephen Hemminger   hv_netvsc: improv...
1170
  	return NULL;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1171
1172
1173
1174
  }
  
  static int netvsc_register_vf(struct net_device *vf_netdev)
  {
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1175
1176
  	struct net_device *ndev;
  	struct net_device_context *net_device_ctx;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1177
  	struct netvsc_device *netvsc_dev;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1178

e8ff40d4b   Stephen Hemminger   hv_netvsc: improv...
1179
1180
  	if (vf_netdev->addr_len != ETH_ALEN)
  		return NOTIFY_DONE;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1181
1182
1183
1184
1185
  	/*
  	 * We will use the MAC address to locate the synthetic interface to
  	 * associate with the VF interface. If we don't find a matching
  	 * synthetic interface, move on.
  	 */
e8ff40d4b   Stephen Hemminger   hv_netvsc: improv...
1186
  	ndev = get_netvsc_bymac(vf_netdev->perm_addr);
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1187
1188
1189
1190
1191
  	if (!ndev)
  		return NOTIFY_DONE;
  
  	net_device_ctx = netdev_priv(ndev);
  	netvsc_dev = net_device_ctx->nvdev;
f207c10d9   Stephen Hemminger   hv_netvsc: use RC...
1192
  	if (!netvsc_dev || rtnl_dereference(net_device_ctx->vf_netdev))
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1193
  		return NOTIFY_DONE;
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1194
1195
  	netdev_info(ndev, "VF registering: %s
  ", vf_netdev->name);
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1196
1197
1198
1199
  	/*
  	 * Take a reference on the module.
  	 */
  	try_module_get(THIS_MODULE);
07d0f0008   Stephen Hemminger   hv_netvsc: dev ho...
1200
1201
  
  	dev_hold(vf_netdev);
f207c10d9   Stephen Hemminger   hv_netvsc: use RC...
1202
  	rcu_assign_pointer(net_device_ctx->vf_netdev, vf_netdev);
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1203
1204
  	return NOTIFY_OK;
  }
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1205
1206
  static int netvsc_vf_up(struct net_device *vf_netdev)
  {
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1207
  	struct net_device *ndev;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1208
  	struct netvsc_device *netvsc_dev;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1209
  	struct net_device_context *net_device_ctx;
e8ff40d4b   Stephen Hemminger   hv_netvsc: improv...
1210
  	ndev = get_netvsc_byref(vf_netdev);
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1211
1212
1213
1214
1215
  	if (!ndev)
  		return NOTIFY_DONE;
  
  	net_device_ctx = netdev_priv(ndev);
  	netvsc_dev = net_device_ctx->nvdev;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1216

0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1217
1218
  	netdev_info(ndev, "VF up: %s
  ", vf_netdev->name);
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1219
1220
1221
1222
  
  	/*
  	 * Open the device before switching data path.
  	 */
2f5fa6c86   Vitaly Kuznetsov   hv_netvsc: pass s...
1223
  	rndis_filter_open(netvsc_dev);
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1224
1225
1226
1227
  
  	/*
  	 * notify the host to switch the data path.
  	 */
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1228
1229
1230
  	netvsc_switch_datapath(ndev, true);
  	netdev_info(ndev, "Data path switched to VF: %s
  ", vf_netdev->name);
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1231

0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1232
  	netif_carrier_off(ndev);
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1233

d072218f2   Vitaly Kuznetsov   hv_netvsc: avoid ...
1234
1235
  	/* Now notify peers through VF device. */
  	call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, vf_netdev);
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1236
1237
1238
  
  	return NOTIFY_OK;
  }
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1239
1240
  static int netvsc_vf_down(struct net_device *vf_netdev)
  {
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1241
  	struct net_device *ndev;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1242
1243
  	struct netvsc_device *netvsc_dev;
  	struct net_device_context *net_device_ctx;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1244

e8ff40d4b   Stephen Hemminger   hv_netvsc: improv...
1245
  	ndev = get_netvsc_byref(vf_netdev);
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1246
1247
1248
1249
1250
  	if (!ndev)
  		return NOTIFY_DONE;
  
  	net_device_ctx = netdev_priv(ndev);
  	netvsc_dev = net_device_ctx->nvdev;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1251

0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1252
1253
  	netdev_info(ndev, "VF down: %s
  ", vf_netdev->name);
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1254
1255
1256
  	netvsc_switch_datapath(ndev, false);
  	netdev_info(ndev, "Data path switched from VF: %s
  ", vf_netdev->name);
2f5fa6c86   Vitaly Kuznetsov   hv_netvsc: pass s...
1257
  	rndis_filter_close(netvsc_dev);
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1258
  	netif_carrier_on(ndev);
d072218f2   Vitaly Kuznetsov   hv_netvsc: avoid ...
1259
1260
1261
  
  	/* Now notify peers through netvsc device. */
  	call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, ndev);
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1262
1263
1264
  
  	return NOTIFY_OK;
  }
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1265
1266
  static int netvsc_unregister_vf(struct net_device *vf_netdev)
  {
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1267
  	struct net_device *ndev;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1268
  	struct netvsc_device *netvsc_dev;
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1269
  	struct net_device_context *net_device_ctx;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1270

e8ff40d4b   Stephen Hemminger   hv_netvsc: improv...
1271
  	ndev = get_netvsc_byref(vf_netdev);
0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1272
1273
1274
1275
1276
  	if (!ndev)
  		return NOTIFY_DONE;
  
  	net_device_ctx = netdev_priv(ndev);
  	netvsc_dev = net_device_ctx->nvdev;
e8ff40d4b   Stephen Hemminger   hv_netvsc: improv...
1277

0a1275ca5   Vitaly Kuznetsov   hv_netvsc: get ri...
1278
1279
  	netdev_info(ndev, "VF unregistering: %s
  ", vf_netdev->name);
f207c10d9   Stephen Hemminger   hv_netvsc: use RC...
1280
1281
  
  	RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL);
07d0f0008   Stephen Hemminger   hv_netvsc: dev ho...
1282
  	dev_put(vf_netdev);
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1283
1284
1285
  	module_put(THIS_MODULE);
  	return NOTIFY_OK;
  }
84946899b   K. Y. Srinivasan   Staging: hv: vmbu...
1286
1287
  static int netvsc_probe(struct hv_device *dev,
  			const struct hv_vmbus_device_id *dev_id)
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1288
  {
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1289
1290
1291
  	struct net_device *net = NULL;
  	struct net_device_context *net_device_ctx;
  	struct netvsc_device_info device_info;
5b54dac85   Haiyang Zhang   hyperv: Add suppo...
1292
  	struct netvsc_device *nvdev;
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1293
  	int ret;
5b54dac85   Haiyang Zhang   hyperv: Add suppo...
1294
1295
  	net = alloc_etherdev_mq(sizeof(struct net_device_context),
  				num_online_cpus());
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1296
  	if (!net)
51a805d0c   K. Y. Srinivasan   Staging: hv: netv...
1297
  		return -ENOMEM;
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1298

1b07da516   Haiyang Zhang   hyperv: Move stat...
1299
  	netif_carrier_off(net);
b37879e6c   Haiyang Zhang   hv_netvsc: Add qu...
1300
  	netvsc_init_settings(net);
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1301
  	net_device_ctx = netdev_priv(net);
9efd21e1f   K. Y. Srinivasan   Staging: hv: Use ...
1302
  	net_device_ctx->device_ctx = dev;
3f300ff41   Simon Xiao   hv_netvsc: introd...
1303
1304
1305
1306
1307
  	net_device_ctx->msg_enable = netif_msg_init(debug, default_msg);
  	if (netif_msg_probe(net_device_ctx))
  		netdev_dbg(net, "netvsc msg_enable: %d
  ",
  			   net_device_ctx->msg_enable);
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
  	net_device_ctx->tx_stats = netdev_alloc_pcpu_stats(struct netvsc_stats);
  	if (!net_device_ctx->tx_stats) {
  		free_netdev(net);
  		return -ENOMEM;
  	}
  	net_device_ctx->rx_stats = netdev_alloc_pcpu_stats(struct netvsc_stats);
  	if (!net_device_ctx->rx_stats) {
  		free_percpu(net_device_ctx->tx_stats);
  		free_netdev(net);
  		return -ENOMEM;
  	}
2ddd5e5fb   K. Y. Srinivasan   Staging: hv: netv...
1319
  	hv_set_drvdata(dev, net);
f580aec4b   Vitaly Kuznetsov   hv_netvsc: move s...
1320
1321
  
  	net_device_ctx->start_remove = false;
891de74d6   Haiyang Zhang   hyperv: Fix the c...
1322
  	INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
792df8722   Wenqi Ma   net/hyperv: Addin...
1323
  	INIT_WORK(&net_device_ctx->work, do_set_multicast);
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1324

27a70af3f   Vitaly Kuznetsov   hv_netvsc: rework...
1325
1326
  	spin_lock_init(&net_device_ctx->lock);
  	INIT_LIST_HEAD(&net_device_ctx->reconfig_events);
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1327
  	net->netdev_ops = &device_ops;
a060679c6   sixiao@microsoft.com   hv_netvsc: cleanu...
1328
1329
  	net->hw_features = NETVSC_HW_FEATURES;
  	net->features = NETVSC_HW_FEATURES | NETIF_F_HW_VLAN_CTAG_TX;
6048718d7   Stephen Hemminger   Staging: hv: tran...
1330

7ad24ea4b   Wilfried Klaebe   net: get rid of S...
1331
  	net->ethtool_ops = &ethtool_ops;
9efd21e1f   K. Y. Srinivasan   Staging: hv: Use ...
1332
  	SET_NETDEV_DEV(net, &dev->device);
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1333

14a03cf80   Vitaly Kuznetsov   hv_netvsc: Restor...
1334
1335
  	/* We always need headroom for rndis header */
  	net->needed_headroom = RNDIS_AND_PPI_SIZE;
692e084e7   Haiyang Zhang   staging: hv: re-o...
1336
  	/* Notify the netvsc driver of the new device */
8ebdcc52b   Andrew Schwartzmeyer   hv_netvsc: Set vR...
1337
  	memset(&device_info, 0, sizeof(device_info));
692e084e7   Haiyang Zhang   staging: hv: re-o...
1338
  	device_info.ring_size = ring_size;
e01ec2199   KY Srinivasan   hv_netvsc: Proper...
1339
  	device_info.max_num_vrss_chns = max_num_vrss_chns;
692e084e7   Haiyang Zhang   staging: hv: re-o...
1340
1341
1342
1343
  	ret = rndis_filter_device_add(dev, &device_info);
  	if (ret != 0) {
  		netdev_err(net, "unable to add netvsc device (ret %d)
  ", ret);
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
1344
  		netvsc_free_netdev(net);
2ddd5e5fb   K. Y. Srinivasan   Staging: hv: netv...
1345
  		hv_set_drvdata(dev, NULL);
692e084e7   Haiyang Zhang   staging: hv: re-o...
1346
  		return ret;
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1347
  	}
692e084e7   Haiyang Zhang   staging: hv: re-o...
1348
  	memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
3d541ac5a   Vitaly Kuznetsov   hv_netvsc: untang...
1349
  	nvdev = net_device_ctx->nvdev;
5b54dac85   Haiyang Zhang   hyperv: Add suppo...
1350
1351
  	netif_set_real_num_tx_queues(net, nvdev->num_chn);
  	netif_set_real_num_rx_queues(net, nvdev->num_chn);
a50af86dd   stephen hemminger   netvsc: reduce ma...
1352
  	netif_set_gso_max_size(net, NETVSC_GSO_MAX_SIZE);
5b54dac85   Haiyang Zhang   hyperv: Add suppo...
1353

a68f96146   Haiyang Zhang   hyperv: Fix race ...
1354
1355
1356
1357
1358
  	ret = register_netdev(net);
  	if (ret != 0) {
  		pr_err("Unable to register netdev.
  ");
  		rndis_filter_device_remove(dev);
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
1359
  		netvsc_free_netdev(net);
a68f96146   Haiyang Zhang   hyperv: Fix race ...
1360
  	}
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1361
1362
  	return ret;
  }
415b023ab   K. Y. Srinivasan   Staging: hv: Use ...
1363
  static int netvsc_remove(struct hv_device *dev)
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1364
  {
2ddd5e5fb   K. Y. Srinivasan   Staging: hv: netv...
1365
  	struct net_device *net;
122a5f641   Haiyang Zhang   staging: hv: use ...
1366
  	struct net_device_context *ndev_ctx;
2ddd5e5fb   K. Y. Srinivasan   Staging: hv: netv...
1367
  	struct netvsc_device *net_device;
3d541ac5a   Vitaly Kuznetsov   hv_netvsc: untang...
1368
  	net = hv_get_drvdata(dev);
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1369

df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1370
  	if (net == NULL) {
415b023ab   K. Y. Srinivasan   Staging: hv: Use ...
1371
1372
  		dev_err(&dev->device, "No net device to remove
  ");
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1373
1374
  		return 0;
  	}
122a5f641   Haiyang Zhang   staging: hv: use ...
1375
  	ndev_ctx = netdev_priv(net);
3d541ac5a   Vitaly Kuznetsov   hv_netvsc: untang...
1376
  	net_device = ndev_ctx->nvdev;
6da7225f5   Vitaly Kuznetsov   hv_netvsc: synchr...
1377
1378
1379
1380
  	/* Avoid racing with netvsc_change_mtu()/netvsc_set_channels()
  	 * removing the device.
  	 */
  	rtnl_lock();
f580aec4b   Vitaly Kuznetsov   hv_netvsc: move s...
1381
  	ndev_ctx->start_remove = true;
6da7225f5   Vitaly Kuznetsov   hv_netvsc: synchr...
1382
  	rtnl_unlock();
f580aec4b   Vitaly Kuznetsov   hv_netvsc: move s...
1383

122a5f641   Haiyang Zhang   staging: hv: use ...
1384
  	cancel_delayed_work_sync(&ndev_ctx->dwork);
792df8722   Wenqi Ma   net/hyperv: Addin...
1385
  	cancel_work_sync(&ndev_ctx->work);
122a5f641   Haiyang Zhang   staging: hv: use ...
1386

df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1387
  	/* Stop outbound asap */
0a282538c   Haiyang Zhang   net/hyperv: Use n...
1388
  	netif_tx_disable(net);
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1389
1390
1391
1392
1393
1394
1395
  
  	unregister_netdev(net);
  
  	/*
  	 * Call to the vsc driver to let it know that the device is being
  	 * removed
  	 */
df06bcff8   Haiyang Zhang   staging: hv: chan...
1396
  	rndis_filter_device_remove(dev);
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1397

3d541ac5a   Vitaly Kuznetsov   hv_netvsc: untang...
1398
  	hv_set_drvdata(dev, NULL);
7eafd9b40   sixiao@microsoft.com   hv_netvsc: use pe...
1399
  	netvsc_free_netdev(net);
df06bcff8   Haiyang Zhang   staging: hv: chan...
1400
  	return 0;
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1401
  }
345c4cc3b   K. Y. Srinivasan   Staging: hv: netv...
1402
  static const struct hv_vmbus_device_id id_table[] = {
c45cf2d49   Greg Kroah-Hartman   Staging: hv: crea...
1403
  	/* Network guid */
8f5059446   K. Y. Srinivasan   Drivers: net: hyp...
1404
  	{ HV_NIC_GUID, },
c45cf2d49   Greg Kroah-Hartman   Staging: hv: crea...
1405
  	{ },
345c4cc3b   K. Y. Srinivasan   Staging: hv: netv...
1406
1407
1408
  };
  
  MODULE_DEVICE_TABLE(vmbus, id_table);
f1542a660   K. Y. Srinivasan   Staging: hv: Move...
1409
  /* The one and only one */
fde0ef9b2   K. Y. Srinivasan   Staging: hv: netv...
1410
  static struct  hv_driver netvsc_drv = {
d31b20fcc   Haiyang Zhang   net/hyperv: Use t...
1411
  	.name = KBUILD_MODNAME,
345c4cc3b   K. Y. Srinivasan   Staging: hv: netv...
1412
  	.id_table = id_table,
fde0ef9b2   K. Y. Srinivasan   Staging: hv: netv...
1413
1414
  	.probe = netvsc_probe,
  	.remove = netvsc_remove,
d48909703   K. Y. Srinivasan   Staging: hv: netv...
1415
  };
f1542a660   K. Y. Srinivasan   Staging: hv: Move...
1416

84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
  /*
   * On Hyper-V, every VF interface is matched with a corresponding
   * synthetic interface. The synthetic interface is presented first
   * to the guest. When the corresponding VF instance is registered,
   * we will take care of switching the data path.
   */
  static int netvsc_netdev_event(struct notifier_block *this,
  			       unsigned long event, void *ptr)
  {
  	struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
ee837a137   Stephen Hemminger   hv_netvsc: simpli...
1427
1428
1429
1430
1431
1432
1433
  	/* Skip our own events */
  	if (event_dev->netdev_ops == &device_ops)
  		return NOTIFY_DONE;
  
  	/* Avoid non-Ethernet type devices */
  	if (event_dev->type != ARPHRD_ETHER)
  		return NOTIFY_DONE;
0dbff144a   Vitaly Kuznetsov   hv_netvsc: fix bo...
1434
1435
1436
1437
1438
  	/* Avoid Vlan dev with same MAC registering as VF */
  	if (event_dev->priv_flags & IFF_802_1Q_VLAN)
  		return NOTIFY_DONE;
  
  	/* Avoid Bonding master dev with same MAC registering as VF */
ee837a137   Stephen Hemminger   hv_netvsc: simpli...
1439
1440
  	if ((event_dev->priv_flags & IFF_BONDING) &&
  	    (event_dev->flags & IFF_MASTER))
cb2911fed   Haiyang Zhang   hv_netvsc: Fix VF...
1441
  		return NOTIFY_DONE;
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
  	switch (event) {
  	case NETDEV_REGISTER:
  		return netvsc_register_vf(event_dev);
  	case NETDEV_UNREGISTER:
  		return netvsc_unregister_vf(event_dev);
  	case NETDEV_UP:
  		return netvsc_vf_up(event_dev);
  	case NETDEV_DOWN:
  		return netvsc_vf_down(event_dev);
  	default:
  		return NOTIFY_DONE;
  	}
  }
  
  static struct notifier_block netvsc_netdev_notifier = {
  	.notifier_call = netvsc_netdev_event,
  };
a9869c942   K. Y. Srinivasan   Staging: hv: netv...
1459
  static void __exit netvsc_drv_exit(void)
fceaf24a9   Hank Janssen   Staging: hv: add ...
1460
  {
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1461
  	unregister_netdevice_notifier(&netvsc_netdev_notifier);
768fa2191   Greg Kroah-Hartman   Staging: hv: fix ...
1462
  	vmbus_driver_unregister(&netvsc_drv);
fceaf24a9   Hank Janssen   Staging: hv: add ...
1463
  }
1fde28cff   K. Y. Srinivasan   Staging: hv: netv...
1464
  static int __init netvsc_drv_init(void)
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1465
  {
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1466
  	int ret;
fa85a6c29   Haiyang Zhang   hyperv: Add a che...
1467
1468
1469
1470
1471
1472
  	if (ring_size < RING_SIZE_MIN) {
  		ring_size = RING_SIZE_MIN;
  		pr_info("Increased ring_size to %d (min allowed)
  ",
  			ring_size);
  	}
84bf9cefb   KY Srinivasan   hv_netvsc: Implem...
1473
1474
1475
1476
1477
1478
1479
  	ret = vmbus_driver_register(&netvsc_drv);
  
  	if (ret)
  		return ret;
  
  	register_netdevice_notifier(&netvsc_netdev_notifier);
  	return 0;
df2fff28e   Greg Kroah-Hartman   Staging: hv: reor...
1480
  }
26c14cc11   Hank Janssen   Staging: hv: Add ...
1481
  MODULE_LICENSE("GPL");
7880fc54c   Stephen Hemminger   Staging: hv: clea...
1482
  MODULE_DESCRIPTION("Microsoft Hyper-V network driver");
fceaf24a9   Hank Janssen   Staging: hv: add ...
1483

1fde28cff   K. Y. Srinivasan   Staging: hv: netv...
1484
  module_init(netvsc_drv_init);
a9869c942   K. Y. Srinivasan   Staging: hv: netv...
1485
  module_exit(netvsc_drv_exit);