1 /*-
2 * Copyright (c) 2009-2012,2016 Microsoft Corp.
3 * Copyright (c) 2010-2012 Citrix Inc.
4 * Copyright (c) 2012 NetApp Inc.
5 * Copyright (c) 2016 Mike Belopuhov <mike@esdenera.com>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice unmodified, this list of conditions, and the following
13 * disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * The OpenBSD port was done under funding by Esdenera Networks GmbH.
32 */
33
34 #include "bpfilter.h"
35 #include "vlan.h"
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/atomic.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/mbuf.h>
43 #include <sys/queue.h>
44 #include <sys/sockio.h>
45 #include <sys/task.h>
46
47 #include <machine/bus.h>
48
49 #include <uvm/uvm_extern.h>
50
51 #include <dev/pv/hypervreg.h>
52 #include <dev/pv/hypervvar.h>
53
54 #include <dev/rndis.h>
55 #include <dev/pv/ndis.h>
56 #include <dev/pv/if_hvnreg.h>
57
58 #include <net/if.h>
59 #include <net/if_media.h>
60
61 #include <netinet/in.h>
62 #include <netinet/if_ether.h>
63
64 #if NBPFILTER > 0
65 #include <net/bpf.h>
66 #endif
67
68 #define HVN_NVS_MSGSIZE 32
69 #define HVN_NVS_BUFSIZE PAGE_SIZE
70
71 /*
72 * RNDIS control interface
73 */
74 #define HVN_RNDIS_CTLREQS 4
75 #define HVN_RNDIS_BUFSIZE 512
76
77 struct rndis_cmd {
78 uint32_t rc_id;
79 struct hvn_nvs_rndis rc_msg;
80 void *rc_req;
81 bus_dmamap_t rc_dmap;
82 bus_dma_segment_t rc_segs;
83 int rc_nsegs;
84 uint64_t rc_gpa;
85 struct rndis_packet_msg rc_cmp;
86 uint32_t rc_cmplen;
87 uint8_t rc_cmpbuf[HVN_RNDIS_BUFSIZE];
88 int rc_done;
89 TAILQ_ENTRY(rndis_cmd) rc_entry;
90 };
91 TAILQ_HEAD(rndis_queue, rndis_cmd);
92
93 #define HVN_MAXMTU (9 * 1024)
94
95 #define HVN_RNDIS_XFER_SIZE 2048
96
97 /*
98 * Tx ring
99 */
100 #define HVN_TX_DESC 256
101 #define HVN_TX_FRAGS 15 /* 31 is the max */
102 #define HVN_TX_FRAG_SIZE PAGE_SIZE
103 #define HVN_TX_PKT_SIZE 16384
104
105 #define HVN_RNDIS_PKT_LEN \
106 (sizeof(struct rndis_packet_msg) + \
107 sizeof(struct rndis_pktinfo) + NDIS_VLAN_INFO_SIZE + \
108 sizeof(struct rndis_pktinfo) + NDIS_TXCSUM_INFO_SIZE)
109
110 struct hvn_tx_desc {
111 uint32_t txd_id;
112 int txd_ready;
113 struct vmbus_gpa txd_sgl[HVN_TX_FRAGS + 1];
114 int txd_nsge;
115 struct mbuf *txd_buf;
116 bus_dmamap_t txd_dmap;
117 struct vmbus_gpa txd_gpa;
118 struct rndis_packet_msg *txd_req;
119 };
120
121 struct hvn_softc {
122 struct device sc_dev;
123 struct hv_softc *sc_hvsc;
124 struct hv_channel *sc_chan;
125 bus_dma_tag_t sc_dmat;
126
127 struct arpcom sc_ac;
128 struct ifmedia sc_media;
129 int sc_link_state;
130
131 /* NVS protocol */
132 int sc_proto;
133 uint32_t sc_nvstid;
134 uint8_t sc_nvsrsp[HVN_NVS_MSGSIZE];
135 uint8_t *sc_nvsbuf;
136 int sc_nvsdone;
137
138 /* RNDIS protocol */
139 int sc_ndisver;
140 uint32_t sc_rndisrid;
141 struct rndis_queue sc_cntl_sq; /* submission queue */
142 struct mutex sc_cntl_sqlck;
143 struct rndis_queue sc_cntl_cq; /* completion queue */
144 struct mutex sc_cntl_cqlck;
145 struct rndis_queue sc_cntl_fq; /* free queue */
146 struct mutex sc_cntl_fqlck;
147 struct rndis_cmd sc_cntl_msgs[HVN_RNDIS_CTLREQS];
148 struct hvn_nvs_rndis sc_data_msg;
149
150 /* Rx ring */
151 void *sc_rx_ring;
152 int sc_rx_size;
153 uint32_t sc_rx_hndl;
154
155 /* Tx ring */
156 uint32_t sc_tx_next;
157 uint32_t sc_tx_avail;
158 struct hvn_tx_desc sc_tx_desc[HVN_TX_DESC];
159 bus_dmamap_t sc_tx_rmap;
160 void *sc_tx_msgs;
161 bus_dma_segment_t sc_tx_mseg;
162 };
163
164 int hvn_match(struct device *, void *, void *);
165 void hvn_attach(struct device *, struct device *, void *);
166 int hvn_ioctl(struct ifnet *, u_long, caddr_t);
167 int hvn_media_change(struct ifnet *);
168 void hvn_media_status(struct ifnet *, struct ifmediareq *);
169 int hvn_iff(struct hvn_softc *);
170 void hvn_init(struct hvn_softc *);
171 void hvn_stop(struct hvn_softc *);
172 void hvn_start(struct ifqueue *);
173 int hvn_encap(struct hvn_softc *, struct mbuf *, struct hvn_tx_desc **);
174 void hvn_decap(struct hvn_softc *, struct hvn_tx_desc *);
175 void hvn_txeof(struct hvn_softc *, uint64_t);
176 int hvn_rx_ring_create(struct hvn_softc *);
177 int hvn_rx_ring_destroy(struct hvn_softc *);
178 int hvn_tx_ring_create(struct hvn_softc *);
179 void hvn_tx_ring_destroy(struct hvn_softc *);
180 int hvn_set_capabilities(struct hvn_softc *);
181 int hvn_get_lladdr(struct hvn_softc *);
182 int hvn_set_lladdr(struct hvn_softc *);
183 void hvn_get_link_status(struct hvn_softc *);
184 void hvn_link_status(struct hvn_softc *);
185
186 /* NSVP */
187 int hvn_nvs_attach(struct hvn_softc *);
188 void hvn_nvs_intr(void *);
189 int hvn_nvs_cmd(struct hvn_softc *, void *, size_t, uint64_t, int);
190 int hvn_nvs_ack(struct hvn_softc *, uint64_t);
191 void hvn_nvs_detach(struct hvn_softc *);
192
193 /* RNDIS */
194 int hvn_rndis_attach(struct hvn_softc *);
195 int hvn_rndis_cmd(struct hvn_softc *, struct rndis_cmd *, int);
196 void hvn_rndis_input(struct hvn_softc *, uint64_t, void *);
197 void hvn_rxeof(struct hvn_softc *, caddr_t, uint32_t, struct mbuf_list *);
198 void hvn_rndis_complete(struct hvn_softc *, caddr_t, uint32_t);
199 int hvn_rndis_output(struct hvn_softc *, struct hvn_tx_desc *);
200 void hvn_rndis_status(struct hvn_softc *, caddr_t, uint32_t);
201 int hvn_rndis_query(struct hvn_softc *, uint32_t, void *, size_t *);
202 int hvn_rndis_set(struct hvn_softc *, uint32_t, void *, size_t);
203 int hvn_rndis_close(struct hvn_softc *);
204 void hvn_rndis_detach(struct hvn_softc *);
205
206 struct cfdriver hvn_cd = {
207 NULL, "hvn", DV_IFNET
208 };
209
210 const struct cfattach hvn_ca = {
211 sizeof(struct hvn_softc), hvn_match, hvn_attach
212 };
213
214 int
hvn_match(struct device * parent,void * match,void * aux)215 hvn_match(struct device *parent, void *match, void *aux)
216 {
217 struct hv_attach_args *aa = aux;
218
219 if (strcmp("network", aa->aa_ident))
220 return (0);
221
222 return (1);
223 }
224
225 void
hvn_attach(struct device * parent,struct device * self,void * aux)226 hvn_attach(struct device *parent, struct device *self, void *aux)
227 {
228 struct hv_attach_args *aa = aux;
229 struct hvn_softc *sc = (struct hvn_softc *)self;
230 struct ifnet *ifp = &sc->sc_ac.ac_if;
231
232 sc->sc_hvsc = (struct hv_softc *)parent;
233 sc->sc_chan = aa->aa_chan;
234 sc->sc_dmat = aa->aa_dmat;
235
236 strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
237
238 printf(" channel %u", sc->sc_chan->ch_id);
239
240 if (hvn_nvs_attach(sc)) {
241 printf(": failed to init NVSP\n");
242 return;
243 }
244
245 if (hvn_rx_ring_create(sc)) {
246 printf(": failed to create Rx ring\n");
247 goto detach;
248 }
249
250 if (hvn_tx_ring_create(sc)) {
251 printf(": failed to create Tx ring\n");
252 goto detach;
253 }
254
255 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
256 ifp->if_xflags = IFXF_MPSAFE;
257 ifp->if_ioctl = hvn_ioctl;
258 ifp->if_qstart = hvn_start;
259 ifp->if_softc = sc;
260
261 ifp->if_capabilities = IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
262 IFCAP_CSUM_TCPv6;
263 if (sc->sc_ndisver > NDIS_VERSION_6_30)
264 ifp->if_capabilities |= IFCAP_CSUM_UDPv4 | IFCAP_CSUM_UDPv6;
265
266 if (sc->sc_proto >= HVN_NVS_PROTO_VERSION_2) {
267 ifp->if_hardmtu = HVN_MAXMTU;
268 #if NVLAN > 0
269 ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
270 #endif
271 }
272
273 ifq_init_maxlen(&ifp->if_snd, HVN_TX_DESC - 1);
274
275 ifmedia_init(&sc->sc_media, IFM_IMASK, hvn_media_change,
276 hvn_media_status);
277 ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
278 ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL);
279
280 if_attach(ifp);
281
282 if (hvn_rndis_attach(sc)) {
283 printf(": failed to init RNDIS\n");
284 goto detach;
285 }
286
287 printf(": NVS %d.%d NDIS %d.%d", sc->sc_proto >> 16,
288 sc->sc_proto & 0xffff, sc->sc_ndisver >> 16 ,
289 sc->sc_ndisver & 0xffff);
290
291 if (hvn_set_capabilities(sc)) {
292 printf(": failed to setup offloading\n");
293 hvn_rndis_detach(sc);
294 goto detach;
295 }
296
297 if (hvn_get_lladdr(sc)) {
298 printf(": failed to obtain an ethernet address\n");
299 hvn_rndis_detach(sc);
300 goto detach;
301 }
302
303 printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr));
304
305 ether_ifattach(ifp);
306 return;
307
308 detach:
309 hvn_rx_ring_destroy(sc);
310 hvn_tx_ring_destroy(sc);
311 hvn_nvs_detach(sc);
312 if (ifp->if_qstart)
313 if_detach(ifp);
314 }
315
316 int
hvn_ioctl(struct ifnet * ifp,u_long command,caddr_t data)317 hvn_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
318 {
319 struct hvn_softc *sc = ifp->if_softc;
320 struct ifreq *ifr = (struct ifreq *)data;
321 int s, error = 0;
322
323 s = splnet();
324
325 switch (command) {
326 case SIOCSIFADDR:
327 ifp->if_flags |= IFF_UP;
328 if (!(ifp->if_flags & IFF_RUNNING))
329 hvn_init(sc);
330 break;
331 case SIOCSIFFLAGS:
332 if (ifp->if_flags & IFF_UP) {
333 if (ifp->if_flags & IFF_RUNNING)
334 error = ENETRESET;
335 else
336 hvn_init(sc);
337 } else {
338 if (ifp->if_flags & IFF_RUNNING)
339 hvn_stop(sc);
340 }
341 break;
342 case SIOCGIFMEDIA:
343 case SIOCSIFMEDIA:
344 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
345 break;
346 default:
347 error = ether_ioctl(ifp, &sc->sc_ac, command, data);
348 }
349
350 if (error == ENETRESET) {
351 if (ifp->if_flags & IFF_RUNNING)
352 hvn_iff(sc);
353 error = 0;
354 }
355
356 splx(s);
357
358 return (error);
359 }
360
361 int
hvn_media_change(struct ifnet * ifp)362 hvn_media_change(struct ifnet *ifp)
363 {
364 return (0);
365 }
366
367 void
hvn_media_status(struct ifnet * ifp,struct ifmediareq * ifmr)368 hvn_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
369 {
370 struct hvn_softc *sc = ifp->if_softc;
371
372 hvn_get_link_status(sc);
373 hvn_link_status(sc);
374
375 ifmr->ifm_status = IFM_AVALID;
376 ifmr->ifm_active = IFM_ETHER | IFM_MANUAL;
377 if (sc->sc_link_state == LINK_STATE_UP)
378 ifmr->ifm_status |= IFM_ACTIVE;
379 }
380
381 void
hvn_link_status(struct hvn_softc * sc)382 hvn_link_status(struct hvn_softc *sc)
383 {
384 struct ifnet *ifp = &sc->sc_ac.ac_if;
385
386 if (sc->sc_link_state != ifp->if_link_state) {
387 ifp->if_link_state = sc->sc_link_state;
388 if_link_state_change(ifp);
389 }
390 }
391
392 int
hvn_iff(struct hvn_softc * sc)393 hvn_iff(struct hvn_softc *sc)
394 {
395 struct ifnet *ifp = &sc->sc_ac.ac_if;
396 uint32_t filter = 0;
397 int rv;
398
399 ifp->if_flags &= ~IFF_ALLMULTI;
400
401 if ((ifp->if_flags & IFF_PROMISC) || sc->sc_ac.ac_multirangecnt > 0) {
402 ifp->if_flags |= IFF_ALLMULTI;
403 filter = NDIS_PACKET_TYPE_PROMISCUOUS;
404 } else {
405 filter = NDIS_PACKET_TYPE_BROADCAST |
406 NDIS_PACKET_TYPE_DIRECTED;
407 if (sc->sc_ac.ac_multicnt > 0) {
408 ifp->if_flags |= IFF_ALLMULTI;
409 filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
410 }
411 }
412
413 rv = hvn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
414 &filter, sizeof(filter));
415 if (rv)
416 DPRINTF("%s: failed to set RNDIS filter to %#x\n",
417 sc->sc_dev.dv_xname, filter);
418 return (rv);
419 }
420
421 void
hvn_init(struct hvn_softc * sc)422 hvn_init(struct hvn_softc *sc)
423 {
424 struct ifnet *ifp = &sc->sc_ac.ac_if;
425
426 hvn_stop(sc);
427
428 if (hvn_iff(sc) == 0) {
429 ifp->if_flags |= IFF_RUNNING;
430 ifq_clr_oactive(&ifp->if_snd);
431 }
432 }
433
434 void
hvn_stop(struct hvn_softc * sc)435 hvn_stop(struct hvn_softc *sc)
436 {
437 struct ifnet *ifp = &sc->sc_ac.ac_if;
438
439 if (ifp->if_flags & IFF_RUNNING) {
440 ifp->if_flags &= ~IFF_RUNNING;
441 hvn_rndis_close(sc);
442 }
443
444 ifq_barrier(&ifp->if_snd);
445 sched_barrier(NULL);
446
447 ifq_clr_oactive(&ifp->if_snd);
448 }
449
450 void
hvn_start(struct ifqueue * ifq)451 hvn_start(struct ifqueue *ifq)
452 {
453 struct ifnet *ifp = ifq->ifq_if;
454 struct hvn_softc *sc = ifp->if_softc;
455 struct hvn_tx_desc *txd;
456 struct mbuf *m;
457
458 for (;;) {
459 if (!sc->sc_tx_avail) {
460 /* transient */
461 ifq_set_oactive(ifq);
462 break;
463 }
464
465 m = ifq_dequeue(ifq);
466 if (m == NULL)
467 break;
468
469 if (hvn_encap(sc, m, &txd)) {
470 /* the chain is too large */
471 ifp->if_oerrors++;
472 m_freem(m);
473 continue;
474 }
475
476 #if NBPFILTER > 0
477 if (ifp->if_bpf)
478 bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
479 #endif
480
481 if (hvn_rndis_output(sc, txd)) {
482 hvn_decap(sc, txd);
483 ifp->if_oerrors++;
484 m_freem(m);
485 continue;
486 }
487
488 sc->sc_tx_next++;
489 }
490 }
491
492 static inline char *
hvn_rndis_pktinfo_append(struct rndis_packet_msg * pkt,size_t pktsize,size_t datalen,uint32_t type)493 hvn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
494 size_t datalen, uint32_t type)
495 {
496 struct rndis_pktinfo *pi;
497 size_t pi_size = sizeof(*pi) + datalen;
498 char *cp;
499
500 KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <=
501 pktsize);
502
503 cp = (char *)pkt + pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
504 pi = (struct rndis_pktinfo *)cp;
505 pi->rm_size = pi_size;
506 pi->rm_type = type;
507 pi->rm_pktinfooffset = sizeof(*pi);
508 pkt->rm_pktinfolen += pi_size;
509 pkt->rm_dataoffset += pi_size;
510 pkt->rm_len += pi_size;
511 return ((char *)pi->rm_data);
512 }
513
514 int
hvn_encap(struct hvn_softc * sc,struct mbuf * m,struct hvn_tx_desc ** txd0)515 hvn_encap(struct hvn_softc *sc, struct mbuf *m, struct hvn_tx_desc **txd0)
516 {
517 struct hvn_tx_desc *txd;
518 struct rndis_packet_msg *pkt;
519 bus_dma_segment_t *seg;
520 size_t pktlen;
521 int i, rv;
522
523 do {
524 txd = &sc->sc_tx_desc[sc->sc_tx_next % HVN_TX_DESC];
525 sc->sc_tx_next++;
526 } while (!txd->txd_ready);
527 txd->txd_ready = 0;
528
529 pkt = txd->txd_req;
530 memset(pkt, 0, HVN_RNDIS_PKT_LEN);
531 pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
532 pkt->rm_len = sizeof(*pkt) + m->m_pkthdr.len;
533 pkt->rm_dataoffset = RNDIS_DATA_OFFSET;
534 pkt->rm_datalen = m->m_pkthdr.len;
535 pkt->rm_pktinfooffset = sizeof(*pkt); /* adjusted below */
536 pkt->rm_pktinfolen = 0;
537
538 rv = bus_dmamap_load_mbuf(sc->sc_dmat, txd->txd_dmap, m, BUS_DMA_READ |
539 BUS_DMA_NOWAIT);
540 switch (rv) {
541 case 0:
542 break;
543 case EFBIG:
544 if (m_defrag(m, M_NOWAIT) == 0 &&
545 bus_dmamap_load_mbuf(sc->sc_dmat, txd->txd_dmap, m,
546 BUS_DMA_READ | BUS_DMA_NOWAIT) == 0)
547 break;
548 /* FALLTHROUGH */
549 default:
550 DPRINTF("%s: failed to load mbuf\n", sc->sc_dev.dv_xname);
551 return (-1);
552 }
553 txd->txd_buf = m;
554
555 #if NVLAN > 0
556 if (m->m_flags & M_VLANTAG) {
557 uint32_t vlan;
558 char *cp;
559
560 vlan = NDIS_VLAN_INFO(EVL_VLANOFTAG(m->m_pkthdr.ether_vtag),
561 EVL_PRIOFTAG(m->m_pkthdr.ether_vtag));
562 cp = hvn_rndis_pktinfo_append(pkt, HVN_RNDIS_PKT_LEN,
563 NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
564 memcpy(cp, &vlan, NDIS_VLAN_INFO_SIZE);
565 }
566 #endif
567
568 if (m->m_pkthdr.csum_flags & (M_IPV4_CSUM_OUT | M_UDP_CSUM_OUT |
569 M_TCP_CSUM_OUT)) {
570 uint32_t csum = NDIS_TXCSUM_INFO_IPV4;
571 char *cp;
572
573 if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT)
574 csum |= NDIS_TXCSUM_INFO_IPCS;
575 if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT)
576 csum |= NDIS_TXCSUM_INFO_TCPCS;
577 if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT)
578 csum |= NDIS_TXCSUM_INFO_UDPCS;
579 cp = hvn_rndis_pktinfo_append(pkt, HVN_RNDIS_PKT_LEN,
580 NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
581 memcpy(cp, &csum, NDIS_TXCSUM_INFO_SIZE);
582 }
583
584 pktlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
585 pkt->rm_pktinfooffset -= RNDIS_HEADER_OFFSET;
586
587 /* Attach an RNDIS message to the first slot */
588 txd->txd_sgl[0].gpa_page = txd->txd_gpa.gpa_page;
589 txd->txd_sgl[0].gpa_ofs = txd->txd_gpa.gpa_ofs;
590 txd->txd_sgl[0].gpa_len = pktlen;
591 txd->txd_nsge = txd->txd_dmap->dm_nsegs + 1;
592
593 for (i = 0; i < txd->txd_dmap->dm_nsegs; i++) {
594 seg = &txd->txd_dmap->dm_segs[i];
595 txd->txd_sgl[1 + i].gpa_page = atop(seg->ds_addr);
596 txd->txd_sgl[1 + i].gpa_ofs = seg->ds_addr & PAGE_MASK;
597 txd->txd_sgl[1 + i].gpa_len = seg->ds_len;
598 }
599
600 *txd0 = txd;
601
602 atomic_dec_int(&sc->sc_tx_avail);
603
604 return (0);
605 }
606
607 void
hvn_decap(struct hvn_softc * sc,struct hvn_tx_desc * txd)608 hvn_decap(struct hvn_softc *sc, struct hvn_tx_desc *txd)
609 {
610 bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0,
611 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
612 bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap);
613 txd->txd_buf = NULL;
614 txd->txd_nsge = 0;
615 txd->txd_ready = 1;
616 atomic_inc_int(&sc->sc_tx_avail);
617 }
618
619 void
hvn_txeof(struct hvn_softc * sc,uint64_t tid)620 hvn_txeof(struct hvn_softc *sc, uint64_t tid)
621 {
622 struct hvn_tx_desc *txd;
623 struct mbuf *m;
624 uint32_t id = tid >> 32;
625
626 if ((tid & 0xffffffffU) != 0)
627 return;
628 id -= HVN_NVS_CHIM_SIG;
629 if (id >= HVN_TX_DESC)
630 panic("tx packet index too large: %u", id);
631
632 txd = &sc->sc_tx_desc[id];
633
634 if ((m = txd->txd_buf) == NULL)
635 panic("%s: no mbuf @%u", sc->sc_dev.dv_xname, id);
636 txd->txd_buf = NULL;
637
638 bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0,
639 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
640 bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap);
641 m_freem(m);
642
643 txd->txd_ready = 1;
644
645 atomic_inc_int(&sc->sc_tx_avail);
646
647 }
648
649 int
hvn_rx_ring_create(struct hvn_softc * sc)650 hvn_rx_ring_create(struct hvn_softc *sc)
651 {
652 struct hvn_nvs_rxbuf_conn cmd;
653 struct hvn_nvs_rxbuf_conn_resp *rsp;
654 uint64_t tid;
655
656 if (sc->sc_proto <= HVN_NVS_PROTO_VERSION_2)
657 sc->sc_rx_size = 15 * 1024 * 1024; /* 15MB */
658 else
659 sc->sc_rx_size = 16 * 1024 * 1024; /* 16MB */
660 sc->sc_rx_ring = km_alloc(sc->sc_rx_size, &kv_any, &kp_zero,
661 cold ? &kd_nowait : &kd_waitok);
662 if (sc->sc_rx_ring == NULL) {
663 DPRINTF("%s: failed to allocate Rx ring buffer\n",
664 sc->sc_dev.dv_xname);
665 return (-1);
666 }
667 if (hv_handle_alloc(sc->sc_chan, sc->sc_rx_ring, sc->sc_rx_size,
668 &sc->sc_rx_hndl)) {
669 DPRINTF("%s: failed to obtain a PA handle\n",
670 sc->sc_dev.dv_xname);
671 goto errout;
672 }
673
674 memset(&cmd, 0, sizeof(cmd));
675 cmd.nvs_type = HVN_NVS_TYPE_RXBUF_CONN;
676 cmd.nvs_gpadl = sc->sc_rx_hndl;
677 cmd.nvs_sig = HVN_NVS_RXBUF_SIG;
678
679 tid = atomic_inc_int_nv(&sc->sc_nvstid);
680 if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 100))
681 goto errout;
682
683 rsp = (struct hvn_nvs_rxbuf_conn_resp *)&sc->sc_nvsrsp;
684 if (rsp->nvs_status != HVN_NVS_STATUS_OK) {
685 DPRINTF("%s: failed to set up the Rx ring\n",
686 sc->sc_dev.dv_xname);
687 goto errout;
688 }
689 if (rsp->nvs_nsect > 1) {
690 DPRINTF("%s: invalid number of Rx ring sections: %u\n",
691 sc->sc_dev.dv_xname, rsp->nvs_nsect);
692 hvn_rx_ring_destroy(sc);
693 return (-1);
694 }
695 return (0);
696
697 errout:
698 if (sc->sc_rx_hndl) {
699 hv_handle_free(sc->sc_chan, sc->sc_rx_hndl);
700 sc->sc_rx_hndl = 0;
701 }
702 if (sc->sc_rx_ring) {
703 km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero);
704 sc->sc_rx_ring = NULL;
705 }
706 return (-1);
707 }
708
709 int
hvn_rx_ring_destroy(struct hvn_softc * sc)710 hvn_rx_ring_destroy(struct hvn_softc *sc)
711 {
712 struct hvn_nvs_rxbuf_disconn cmd;
713 uint64_t tid;
714
715 if (sc->sc_rx_ring == NULL)
716 return (0);
717
718 memset(&cmd, 0, sizeof(cmd));
719 cmd.nvs_type = HVN_NVS_TYPE_RXBUF_DISCONN;
720 cmd.nvs_sig = HVN_NVS_RXBUF_SIG;
721
722 tid = atomic_inc_int_nv(&sc->sc_nvstid);
723 if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 0))
724 return (-1);
725
726 delay(100);
727
728 hv_handle_free(sc->sc_chan, sc->sc_rx_hndl);
729
730 sc->sc_rx_hndl = 0;
731
732 km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero);
733 sc->sc_rx_ring = NULL;
734
735 return (0);
736 }
737
738 int
hvn_tx_ring_create(struct hvn_softc * sc)739 hvn_tx_ring_create(struct hvn_softc *sc)
740 {
741 struct hvn_tx_desc *txd;
742 bus_dma_segment_t *seg;
743 size_t msgsize;
744 int i, rsegs;
745 paddr_t pa;
746
747 msgsize = roundup(HVN_RNDIS_PKT_LEN, 128);
748
749 /* Allocate memory to store RNDIS messages */
750 if (bus_dmamem_alloc(sc->sc_dmat, msgsize * HVN_TX_DESC, PAGE_SIZE, 0,
751 &sc->sc_tx_mseg, 1, &rsegs, BUS_DMA_ZERO | BUS_DMA_WAITOK)) {
752 DPRINTF("%s: failed to allocate memory for RDNIS messages\n",
753 sc->sc_dev.dv_xname);
754 goto errout;
755 }
756 if (bus_dmamem_map(sc->sc_dmat, &sc->sc_tx_mseg, 1, msgsize *
757 HVN_TX_DESC, (caddr_t *)&sc->sc_tx_msgs, BUS_DMA_WAITOK)) {
758 DPRINTF("%s: failed to establish mapping for RDNIS messages\n",
759 sc->sc_dev.dv_xname);
760 goto errout;
761 }
762 if (bus_dmamap_create(sc->sc_dmat, msgsize * HVN_TX_DESC, 1,
763 msgsize * HVN_TX_DESC, 0, BUS_DMA_WAITOK, &sc->sc_tx_rmap)) {
764 DPRINTF("%s: failed to create map for RDNIS messages\n",
765 sc->sc_dev.dv_xname);
766 goto errout;
767 }
768 if (bus_dmamap_load(sc->sc_dmat, sc->sc_tx_rmap, sc->sc_tx_msgs,
769 msgsize * HVN_TX_DESC, NULL, BUS_DMA_WAITOK)) {
770 DPRINTF("%s: failed to create map for RDNIS messages\n",
771 sc->sc_dev.dv_xname);
772 goto errout;
773 }
774
775 for (i = 0; i < HVN_TX_DESC; i++) {
776 txd = &sc->sc_tx_desc[i];
777 if (bus_dmamap_create(sc->sc_dmat, HVN_TX_PKT_SIZE,
778 HVN_TX_FRAGS, HVN_TX_FRAG_SIZE, PAGE_SIZE,
779 BUS_DMA_WAITOK, &txd->txd_dmap)) {
780 DPRINTF("%s: failed to create map for TX descriptors\n",
781 sc->sc_dev.dv_xname);
782 goto errout;
783 }
784 seg = &sc->sc_tx_rmap->dm_segs[0];
785 pa = seg->ds_addr + (msgsize * i);
786 txd->txd_gpa.gpa_page = atop(pa);
787 txd->txd_gpa.gpa_ofs = pa & PAGE_MASK;
788 txd->txd_gpa.gpa_len = msgsize;
789 txd->txd_req = (void *)((caddr_t)sc->sc_tx_msgs +
790 (msgsize * i));
791 txd->txd_id = i + HVN_NVS_CHIM_SIG;
792 txd->txd_ready = 1;
793 }
794 sc->sc_tx_avail = HVN_TX_DESC;
795
796 return (0);
797
798 errout:
799 hvn_tx_ring_destroy(sc);
800 return (-1);
801 }
802
803 void
hvn_tx_ring_destroy(struct hvn_softc * sc)804 hvn_tx_ring_destroy(struct hvn_softc *sc)
805 {
806 struct hvn_tx_desc *txd;
807 int i;
808
809 for (i = 0; i < HVN_TX_DESC; i++) {
810 txd = &sc->sc_tx_desc[i];
811 if (txd->txd_dmap == NULL)
812 continue;
813 bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0,
814 BUS_DMASYNC_POSTWRITE);
815 bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap);
816 bus_dmamap_destroy(sc->sc_dmat, txd->txd_dmap);
817 txd->txd_dmap = NULL;
818 if (txd->txd_buf == NULL)
819 continue;
820 m_free(txd->txd_buf);
821 txd->txd_buf = NULL;
822 }
823 if (sc->sc_tx_rmap) {
824 bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_rmap, 0, 0,
825 BUS_DMASYNC_POSTWRITE);
826 bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_rmap);
827 bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_rmap);
828 }
829 if (sc->sc_tx_msgs) {
830 size_t msgsize = roundup(HVN_RNDIS_PKT_LEN, 128);
831
832 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_tx_msgs,
833 msgsize * HVN_TX_DESC);
834 bus_dmamem_free(sc->sc_dmat, &sc->sc_tx_mseg, 1);
835 }
836 sc->sc_tx_rmap = NULL;
837 sc->sc_tx_msgs = NULL;
838 }
839
840 int
hvn_get_lladdr(struct hvn_softc * sc)841 hvn_get_lladdr(struct hvn_softc *sc)
842 {
843 char enaddr[ETHER_ADDR_LEN];
844 size_t addrlen = ETHER_ADDR_LEN;
845 int rv;
846
847 rv = hvn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS,
848 enaddr, &addrlen);
849 if (rv == 0 && addrlen == ETHER_ADDR_LEN)
850 memcpy(sc->sc_ac.ac_enaddr, enaddr, ETHER_ADDR_LEN);
851 return (rv);
852 }
853
854 int
hvn_set_lladdr(struct hvn_softc * sc)855 hvn_set_lladdr(struct hvn_softc *sc)
856 {
857 return (hvn_rndis_set(sc, OID_802_3_CURRENT_ADDRESS,
858 sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN));
859 }
860
861 void
hvn_get_link_status(struct hvn_softc * sc)862 hvn_get_link_status(struct hvn_softc *sc)
863 {
864 uint32_t state;
865 size_t len = sizeof(state);
866
867 if (hvn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS,
868 &state, &len) == 0)
869 sc->sc_link_state = (state == NDIS_MEDIA_STATE_CONNECTED) ?
870 LINK_STATE_UP : LINK_STATE_DOWN;
871 }
872
873 int
hvn_nvs_attach(struct hvn_softc * sc)874 hvn_nvs_attach(struct hvn_softc *sc)
875 {
876 const uint32_t protos[] = {
877 HVN_NVS_PROTO_VERSION_5, HVN_NVS_PROTO_VERSION_4,
878 HVN_NVS_PROTO_VERSION_2, HVN_NVS_PROTO_VERSION_1
879 };
880 struct hvn_nvs_init cmd;
881 struct hvn_nvs_init_resp *rsp;
882 struct hvn_nvs_ndis_init ncmd;
883 struct hvn_nvs_ndis_conf ccmd;
884 uint32_t ndisver, ringsize;
885 uint64_t tid;
886 int i;
887
888 sc->sc_nvsbuf = malloc(HVN_NVS_BUFSIZE, M_DEVBUF, M_ZERO |
889 (cold ? M_NOWAIT : M_WAITOK));
890 if (sc->sc_nvsbuf == NULL) {
891 DPRINTF("%s: failed to allocate channel data buffer\n",
892 sc->sc_dev.dv_xname);
893 return (-1);
894 }
895
896 /* We need to be able to fit all RNDIS control and data messages */
897 ringsize = HVN_RNDIS_CTLREQS *
898 (sizeof(struct hvn_nvs_rndis) + sizeof(struct vmbus_gpa)) +
899 HVN_TX_DESC * (sizeof(struct hvn_nvs_rndis) +
900 (HVN_TX_FRAGS + 1) * sizeof(struct vmbus_gpa));
901
902 sc->sc_chan->ch_flags &= ~CHF_BATCHED;
903
904 /* Associate our interrupt handler with the channel */
905 if (hv_channel_open(sc->sc_chan, ringsize, NULL, 0,
906 hvn_nvs_intr, sc)) {
907 DPRINTF("%s: failed to open channel\n", sc->sc_dev.dv_xname);
908 free(sc->sc_nvsbuf, M_DEVBUF, HVN_NVS_BUFSIZE);
909 return (-1);
910 }
911
912 hv_evcount_attach(sc->sc_chan, sc->sc_dev.dv_xname);
913
914 memset(&cmd, 0, sizeof(cmd));
915 cmd.nvs_type = HVN_NVS_TYPE_INIT;
916 for (i = 0; i < nitems(protos); i++) {
917 cmd.nvs_ver_min = cmd.nvs_ver_max = protos[i];
918 tid = atomic_inc_int_nv(&sc->sc_nvstid);
919 if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 100))
920 return (-1);
921 rsp = (struct hvn_nvs_init_resp *)&sc->sc_nvsrsp;
922 if (rsp->nvs_status == HVN_NVS_STATUS_OK) {
923 sc->sc_proto = protos[i];
924 break;
925 }
926 }
927 if (!sc->sc_proto) {
928 DPRINTF("%s: failed to negotiate NVSP version\n",
929 sc->sc_dev.dv_xname);
930 return (-1);
931 }
932
933 if (sc->sc_proto >= HVN_NVS_PROTO_VERSION_2) {
934 memset(&ccmd, 0, sizeof(ccmd));
935 ccmd.nvs_type = HVN_NVS_TYPE_NDIS_CONF;
936 ccmd.nvs_mtu = HVN_MAXMTU;
937 ccmd.nvs_caps = HVN_NVS_NDIS_CONF_VLAN;
938
939 tid = atomic_inc_int_nv(&sc->sc_nvstid);
940 if (hvn_nvs_cmd(sc, &ccmd, sizeof(ccmd), tid, 100))
941 return (-1);
942 }
943
944 memset(&ncmd, 0, sizeof(ncmd));
945 ncmd.nvs_type = HVN_NVS_TYPE_NDIS_INIT;
946 if (sc->sc_proto <= HVN_NVS_PROTO_VERSION_4)
947 ndisver = NDIS_VERSION_6_1;
948 else
949 ndisver = NDIS_VERSION_6_30;
950 ncmd.nvs_ndis_major = (ndisver & 0xffff0000) >> 16;
951 ncmd.nvs_ndis_minor = (ndisver & 0x0000ffff);
952
953 tid = atomic_inc_int_nv(&sc->sc_nvstid);
954 if (hvn_nvs_cmd(sc, &ncmd, sizeof(ncmd), tid, 100))
955 return (-1);
956
957 sc->sc_ndisver = ndisver;
958
959 return (0);
960 }
961
962 void
hvn_nvs_intr(void * arg)963 hvn_nvs_intr(void *arg)
964 {
965 struct hvn_softc *sc = arg;
966 struct ifnet *ifp = &sc->sc_ac.ac_if;
967 struct vmbus_chanpkt_hdr *cph;
968 struct hvn_nvs_hdr *nvs;
969 uint64_t rid;
970 uint32_t rlen;
971 int rv;
972
973 for (;;) {
974 rv = hv_channel_recv(sc->sc_chan, sc->sc_nvsbuf,
975 HVN_NVS_BUFSIZE, &rlen, &rid, 1);
976 if (rv != 0 || rlen == 0) {
977 if (rv != EAGAIN)
978 printf("%s: failed to receive an NVSP "
979 "packet\n", sc->sc_dev.dv_xname);
980 break;
981 }
982 cph = (struct vmbus_chanpkt_hdr *)sc->sc_nvsbuf;
983 nvs = (struct hvn_nvs_hdr *)VMBUS_CHANPKT_CONST_DATA(cph);
984
985 if (cph->cph_type == VMBUS_CHANPKT_TYPE_COMP) {
986 switch (nvs->nvs_type) {
987 case HVN_NVS_TYPE_INIT_RESP:
988 case HVN_NVS_TYPE_RXBUF_CONNRESP:
989 case HVN_NVS_TYPE_CHIM_CONNRESP:
990 case HVN_NVS_TYPE_SUBCH_RESP:
991 /* copy the response back */
992 memcpy(&sc->sc_nvsrsp, nvs, HVN_NVS_MSGSIZE);
993 sc->sc_nvsdone = 1;
994 wakeup_one(&sc->sc_nvsrsp);
995 break;
996 case HVN_NVS_TYPE_RNDIS_ACK:
997 hvn_txeof(sc, cph->cph_tid);
998 break;
999 default:
1000 printf("%s: unhandled NVSP packet type %u "
1001 "on completion\n", sc->sc_dev.dv_xname,
1002 nvs->nvs_type);
1003 }
1004 } else if (cph->cph_type == VMBUS_CHANPKT_TYPE_RXBUF) {
1005 switch (nvs->nvs_type) {
1006 case HVN_NVS_TYPE_RNDIS:
1007 hvn_rndis_input(sc, cph->cph_tid, cph);
1008 break;
1009 default:
1010 printf("%s: unhandled NVSP packet type %u "
1011 "on receive\n", sc->sc_dev.dv_xname,
1012 nvs->nvs_type);
1013 }
1014 } else
1015 printf("%s: unknown NVSP packet type %u\n",
1016 sc->sc_dev.dv_xname, cph->cph_type);
1017 }
1018
1019 if (ifq_is_oactive(&ifp->if_snd))
1020 ifq_restart(&ifp->if_snd);
1021 }
1022
1023 int
hvn_nvs_cmd(struct hvn_softc * sc,void * cmd,size_t cmdsize,uint64_t tid,int timo)1024 hvn_nvs_cmd(struct hvn_softc *sc, void *cmd, size_t cmdsize, uint64_t tid,
1025 int timo)
1026 {
1027 struct hvn_nvs_hdr *hdr = cmd;
1028 int tries = 10;
1029 int rv, s;
1030
1031 KERNEL_ASSERT_LOCKED();
1032
1033 sc->sc_nvsdone = 0;
1034
1035 do {
1036 rv = hv_channel_send(sc->sc_chan, cmd, cmdsize,
1037 tid, VMBUS_CHANPKT_TYPE_INBAND,
1038 timo ? VMBUS_CHANPKT_FLAG_RC : 0);
1039 if (rv == EAGAIN) {
1040 if (cold)
1041 delay(1000);
1042 else {
1043 tsleep_nsec(cmd, PRIBIO, "nvsout",
1044 USEC_TO_NSEC(1000));
1045 }
1046 } else if (rv) {
1047 DPRINTF("%s: NVSP operation %u send error %d\n",
1048 sc->sc_dev.dv_xname, hdr->nvs_type, rv);
1049 return (rv);
1050 }
1051 } while (rv != 0 && --tries > 0);
1052
1053 if (tries == 0 && rv != 0) {
1054 printf("%s: NVSP operation %u send error %d\n",
1055 sc->sc_dev.dv_xname, hdr->nvs_type, rv);
1056 return (rv);
1057 }
1058
1059 if (timo == 0)
1060 return (0);
1061
1062 do {
1063 if (cold)
1064 delay(1000);
1065 else {
1066 tsleep_nsec(sc, PRIBIO | PCATCH, "nvscmd",
1067 USEC_TO_NSEC(1000));
1068 }
1069 s = splnet();
1070 hvn_nvs_intr(sc);
1071 splx(s);
1072 } while (--timo > 0 && sc->sc_nvsdone != 1);
1073
1074 if (timo == 0 && sc->sc_nvsdone != 1) {
1075 printf("%s: NVSP operation %u timed out\n",
1076 sc->sc_dev.dv_xname, hdr->nvs_type);
1077 return (ETIMEDOUT);
1078 }
1079 return (0);
1080 }
1081
1082 int
hvn_nvs_ack(struct hvn_softc * sc,uint64_t tid)1083 hvn_nvs_ack(struct hvn_softc *sc, uint64_t tid)
1084 {
1085 struct hvn_nvs_rndis_ack cmd;
1086 int tries = 5;
1087 int rv;
1088
1089 cmd.nvs_type = HVN_NVS_TYPE_RNDIS_ACK;
1090 cmd.nvs_status = HVN_NVS_STATUS_OK;
1091 do {
1092 rv = hv_channel_send(sc->sc_chan, &cmd, sizeof(cmd),
1093 tid, VMBUS_CHANPKT_TYPE_COMP, 0);
1094 if (rv == EAGAIN)
1095 delay(10);
1096 else if (rv) {
1097 DPRINTF("%s: NVSP acknowledgement error %d\n",
1098 sc->sc_dev.dv_xname, rv);
1099 return (rv);
1100 }
1101 } while (rv != 0 && --tries > 0);
1102 return (rv);
1103 }
1104
1105 void
hvn_nvs_detach(struct hvn_softc * sc)1106 hvn_nvs_detach(struct hvn_softc *sc)
1107 {
1108 if (hv_channel_close(sc->sc_chan) == 0) {
1109 free(sc->sc_nvsbuf, M_DEVBUF, HVN_NVS_BUFSIZE);
1110 sc->sc_nvsbuf = NULL;
1111 }
1112 }
1113
1114 static inline struct rndis_cmd *
hvn_alloc_cmd(struct hvn_softc * sc)1115 hvn_alloc_cmd(struct hvn_softc *sc)
1116 {
1117 struct rndis_cmd *rc;
1118
1119 mtx_enter(&sc->sc_cntl_fqlck);
1120 while ((rc = TAILQ_FIRST(&sc->sc_cntl_fq)) == NULL)
1121 msleep_nsec(&sc->sc_cntl_fq, &sc->sc_cntl_fqlck,
1122 PRIBIO, "nvsalloc", INFSLP);
1123 TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry);
1124 mtx_leave(&sc->sc_cntl_fqlck);
1125 return (rc);
1126 }
1127
1128 static inline void
hvn_submit_cmd(struct hvn_softc * sc,struct rndis_cmd * rc)1129 hvn_submit_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
1130 {
1131 mtx_enter(&sc->sc_cntl_sqlck);
1132 TAILQ_INSERT_TAIL(&sc->sc_cntl_sq, rc, rc_entry);
1133 mtx_leave(&sc->sc_cntl_sqlck);
1134 }
1135
1136 static inline struct rndis_cmd *
hvn_complete_cmd(struct hvn_softc * sc,uint32_t id)1137 hvn_complete_cmd(struct hvn_softc *sc, uint32_t id)
1138 {
1139 struct rndis_cmd *rc;
1140
1141 mtx_enter(&sc->sc_cntl_sqlck);
1142 TAILQ_FOREACH(rc, &sc->sc_cntl_sq, rc_entry) {
1143 if (rc->rc_id == id) {
1144 TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry);
1145 break;
1146 }
1147 }
1148 mtx_leave(&sc->sc_cntl_sqlck);
1149 if (rc != NULL) {
1150 mtx_enter(&sc->sc_cntl_cqlck);
1151 TAILQ_INSERT_TAIL(&sc->sc_cntl_cq, rc, rc_entry);
1152 mtx_leave(&sc->sc_cntl_cqlck);
1153 }
1154 return (rc);
1155 }
1156
1157 static inline void
hvn_release_cmd(struct hvn_softc * sc,struct rndis_cmd * rc)1158 hvn_release_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
1159 {
1160 mtx_enter(&sc->sc_cntl_cqlck);
1161 TAILQ_REMOVE(&sc->sc_cntl_cq, rc, rc_entry);
1162 mtx_leave(&sc->sc_cntl_cqlck);
1163 }
1164
1165 static inline int
hvn_rollback_cmd(struct hvn_softc * sc,struct rndis_cmd * rc)1166 hvn_rollback_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
1167 {
1168 struct rndis_cmd *rn;
1169
1170 mtx_enter(&sc->sc_cntl_sqlck);
1171 TAILQ_FOREACH(rn, &sc->sc_cntl_sq, rc_entry) {
1172 if (rn == rc) {
1173 TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry);
1174 mtx_leave(&sc->sc_cntl_sqlck);
1175 return (0);
1176 }
1177 }
1178 mtx_leave(&sc->sc_cntl_sqlck);
1179 return (-1);
1180 }
1181
1182 static inline void
hvn_free_cmd(struct hvn_softc * sc,struct rndis_cmd * rc)1183 hvn_free_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
1184 {
1185 memset(rc->rc_req, 0, sizeof(struct rndis_packet_msg));
1186 memset(&rc->rc_cmp, 0, sizeof(rc->rc_cmp));
1187 memset(&rc->rc_msg, 0, sizeof(rc->rc_msg));
1188 mtx_enter(&sc->sc_cntl_fqlck);
1189 TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry);
1190 mtx_leave(&sc->sc_cntl_fqlck);
1191 wakeup(&sc->sc_cntl_fq);
1192 }
1193
1194 int
hvn_rndis_attach(struct hvn_softc * sc)1195 hvn_rndis_attach(struct hvn_softc *sc)
1196 {
1197 struct rndis_init_req *req;
1198 struct rndis_init_comp *cmp;
1199 struct rndis_cmd *rc;
1200 int i, rv;
1201
1202 /* RNDIS control message queues */
1203 TAILQ_INIT(&sc->sc_cntl_sq);
1204 TAILQ_INIT(&sc->sc_cntl_cq);
1205 TAILQ_INIT(&sc->sc_cntl_fq);
1206 mtx_init(&sc->sc_cntl_sqlck, IPL_NET);
1207 mtx_init(&sc->sc_cntl_cqlck, IPL_NET);
1208 mtx_init(&sc->sc_cntl_fqlck, IPL_NET);
1209
1210 for (i = 0; i < HVN_RNDIS_CTLREQS; i++) {
1211 rc = &sc->sc_cntl_msgs[i];
1212 if (bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1,
1213 PAGE_SIZE, 0, BUS_DMA_WAITOK, &rc->rc_dmap)) {
1214 DPRINTF("%s: failed to create RNDIS command map\n",
1215 sc->sc_dev.dv_xname);
1216 goto errout;
1217 }
1218 if (bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE,
1219 0, &rc->rc_segs, 1, &rc->rc_nsegs, BUS_DMA_NOWAIT |
1220 BUS_DMA_ZERO)) {
1221 DPRINTF("%s: failed to allocate RNDIS command\n",
1222 sc->sc_dev.dv_xname);
1223 bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
1224 goto errout;
1225 }
1226 if (bus_dmamem_map(sc->sc_dmat, &rc->rc_segs, rc->rc_nsegs,
1227 PAGE_SIZE, (caddr_t *)&rc->rc_req, BUS_DMA_NOWAIT)) {
1228 DPRINTF("%s: failed to allocate RNDIS command\n",
1229 sc->sc_dev.dv_xname);
1230 bus_dmamem_free(sc->sc_dmat, &rc->rc_segs,
1231 rc->rc_nsegs);
1232 bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
1233 goto errout;
1234 }
1235 if (bus_dmamap_load(sc->sc_dmat, rc->rc_dmap, rc->rc_req,
1236 PAGE_SIZE, NULL, BUS_DMA_WAITOK)) {
1237 DPRINTF("%s: failed to load RNDIS command map\n",
1238 sc->sc_dev.dv_xname);
1239 bus_dmamem_free(sc->sc_dmat, &rc->rc_segs,
1240 rc->rc_nsegs);
1241 bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
1242 goto errout;
1243 }
1244 rc->rc_gpa = atop(rc->rc_dmap->dm_segs[0].ds_addr);
1245 TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry);
1246 }
1247
1248 rc = hvn_alloc_cmd(sc);
1249
1250 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1251 BUS_DMASYNC_PREREAD);
1252
1253 rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1254
1255 req = rc->rc_req;
1256 req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
1257 req->rm_len = sizeof(*req);
1258 req->rm_rid = rc->rc_id;
1259 req->rm_ver_major = RNDIS_VERSION_MAJOR;
1260 req->rm_ver_minor = RNDIS_VERSION_MINOR;
1261 req->rm_max_xfersz = HVN_RNDIS_XFER_SIZE;
1262
1263 rc->rc_cmplen = sizeof(*cmp);
1264
1265 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1266 BUS_DMASYNC_PREWRITE);
1267
1268 if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
1269 DPRINTF("%s: INITIALIZE_MSG failed, error %d\n",
1270 sc->sc_dev.dv_xname, rv);
1271 hvn_free_cmd(sc, rc);
1272 goto errout;
1273 }
1274 cmp = (struct rndis_init_comp *)&rc->rc_cmp;
1275 if (cmp->rm_status != RNDIS_STATUS_SUCCESS) {
1276 DPRINTF("%s: failed to init RNDIS, error %#x\n",
1277 sc->sc_dev.dv_xname, cmp->rm_status);
1278 hvn_free_cmd(sc, rc);
1279 goto errout;
1280 }
1281
1282 hvn_free_cmd(sc, rc);
1283
1284 /* Initialize RNDIS Data command */
1285 memset(&sc->sc_data_msg, 0, sizeof(sc->sc_data_msg));
1286 sc->sc_data_msg.nvs_type = HVN_NVS_TYPE_RNDIS;
1287 sc->sc_data_msg.nvs_rndis_mtype = HVN_NVS_RNDIS_MTYPE_DATA;
1288 sc->sc_data_msg.nvs_chim_idx = HVN_NVS_CHIM_IDX_INVALID;
1289
1290 return (0);
1291
1292 errout:
1293 for (i = 0; i < HVN_RNDIS_CTLREQS; i++) {
1294 rc = &sc->sc_cntl_msgs[i];
1295 if (rc->rc_req == NULL)
1296 continue;
1297 TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry);
1298 bus_dmamem_free(sc->sc_dmat, &rc->rc_segs, rc->rc_nsegs);
1299 rc->rc_req = NULL;
1300 bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
1301 }
1302 return (-1);
1303 }
1304
1305 int
hvn_set_capabilities(struct hvn_softc * sc)1306 hvn_set_capabilities(struct hvn_softc *sc)
1307 {
1308 struct ndis_offload_params params;
1309 size_t len = sizeof(params);
1310
1311 memset(¶ms, 0, sizeof(params));
1312
1313 params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
1314 if (sc->sc_ndisver < NDIS_VERSION_6_30) {
1315 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
1316 len = params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
1317 } else {
1318 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
1319 len = params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE;
1320 }
1321
1322 params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
1323 params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
1324 params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
1325 if (sc->sc_ndisver >= NDIS_VERSION_6_30) {
1326 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
1327 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
1328 }
1329
1330 return (hvn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, ¶ms, len));
1331 }
1332
1333 int
hvn_rndis_cmd(struct hvn_softc * sc,struct rndis_cmd * rc,int timo)1334 hvn_rndis_cmd(struct hvn_softc *sc, struct rndis_cmd *rc, int timo)
1335 {
1336 struct hvn_nvs_rndis *msg = &rc->rc_msg;
1337 struct rndis_msghdr *hdr = rc->rc_req;
1338 struct vmbus_gpa sgl[1];
1339 int tries = 10;
1340 int rv, s;
1341
1342 KERNEL_ASSERT_LOCKED();
1343
1344 KASSERT(timo > 0);
1345
1346 msg->nvs_type = HVN_NVS_TYPE_RNDIS;
1347 msg->nvs_rndis_mtype = HVN_NVS_RNDIS_MTYPE_CTRL;
1348 msg->nvs_chim_idx = HVN_NVS_CHIM_IDX_INVALID;
1349
1350 sgl[0].gpa_page = rc->rc_gpa;
1351 sgl[0].gpa_len = hdr->rm_len;
1352 sgl[0].gpa_ofs = 0;
1353
1354 rc->rc_done = 0;
1355
1356 hvn_submit_cmd(sc, rc);
1357
1358 do {
1359 rv = hv_channel_send_sgl(sc->sc_chan, sgl, 1, &rc->rc_msg,
1360 sizeof(*msg), rc->rc_id);
1361 if (rv == EAGAIN) {
1362 if (cold)
1363 delay(100);
1364 else {
1365 tsleep_nsec(rc, PRIBIO, "rndisout",
1366 USEC_TO_NSEC(100));
1367 }
1368 } else if (rv) {
1369 DPRINTF("%s: RNDIS operation %u send error %d\n",
1370 sc->sc_dev.dv_xname, hdr->rm_type, rv);
1371 hvn_rollback_cmd(sc, rc);
1372 return (rv);
1373 }
1374 } while (rv != 0 && --tries > 0);
1375
1376 if (tries == 0 && rv != 0) {
1377 printf("%s: RNDIS operation %u send error %d\n",
1378 sc->sc_dev.dv_xname, hdr->rm_type, rv);
1379 return (rv);
1380 }
1381
1382 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1383 BUS_DMASYNC_POSTWRITE);
1384
1385 do {
1386 if (cold)
1387 delay(1000);
1388 else {
1389 tsleep_nsec(rc, PRIBIO | PCATCH, "rndiscmd",
1390 USEC_TO_NSEC(1000));
1391 }
1392 s = splnet();
1393 hvn_nvs_intr(sc);
1394 splx(s);
1395 } while (--timo > 0 && rc->rc_done != 1);
1396
1397 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1398 BUS_DMASYNC_POSTREAD);
1399
1400 if (rc->rc_done != 1) {
1401 rv = timo == 0 ? ETIMEDOUT : EINTR;
1402 if (hvn_rollback_cmd(sc, rc)) {
1403 hvn_release_cmd(sc, rc);
1404 rv = 0;
1405 } else if (rv == ETIMEDOUT) {
1406 printf("%s: RNDIS operation %u timed out\n",
1407 sc->sc_dev.dv_xname, hdr->rm_type);
1408 }
1409 return (rv);
1410 }
1411
1412 hvn_release_cmd(sc, rc);
1413 return (0);
1414 }
1415
1416 void
hvn_rndis_input(struct hvn_softc * sc,uint64_t tid,void * arg)1417 hvn_rndis_input(struct hvn_softc *sc, uint64_t tid, void *arg)
1418 {
1419 struct ifnet *ifp = &sc->sc_ac.ac_if;
1420 struct mbuf_list ml = MBUF_LIST_INITIALIZER();
1421 struct vmbus_chanpkt_prplist *cp = arg;
1422 uint32_t off, len, type;
1423 int i;
1424
1425 if (sc->sc_rx_ring == NULL) {
1426 DPRINTF("%s: invalid rx ring\n", sc->sc_dev.dv_xname);
1427 return;
1428 }
1429 for (i = 0; i < cp->cp_range_cnt; i++) {
1430 off = cp->cp_range[i].gpa_ofs;
1431 len = cp->cp_range[i].gpa_len;
1432
1433 KASSERT(off + len <= sc->sc_rx_size);
1434 KASSERT(len >= RNDIS_HEADER_OFFSET + 4);
1435
1436 memcpy(&type, (caddr_t)sc->sc_rx_ring + off, sizeof(type));
1437 switch (type) {
1438 /* data message */
1439 case REMOTE_NDIS_PACKET_MSG:
1440 hvn_rxeof(sc, (caddr_t)sc->sc_rx_ring +
1441 off, len, &ml);
1442 break;
1443 /* completion messages */
1444 case REMOTE_NDIS_INITIALIZE_CMPLT:
1445 case REMOTE_NDIS_QUERY_CMPLT:
1446 case REMOTE_NDIS_SET_CMPLT:
1447 case REMOTE_NDIS_RESET_CMPLT:
1448 case REMOTE_NDIS_KEEPALIVE_CMPLT:
1449 hvn_rndis_complete(sc, (caddr_t)sc->sc_rx_ring +
1450 off, len);
1451 break;
1452 /* notification message */
1453 case REMOTE_NDIS_INDICATE_STATUS_MSG:
1454 hvn_rndis_status(sc, (caddr_t)sc->sc_rx_ring +
1455 off, len);
1456 break;
1457 default:
1458 printf("%s: unhandled RNDIS message type %u\n",
1459 sc->sc_dev.dv_xname, type);
1460 }
1461 }
1462 hvn_nvs_ack(sc, tid);
1463
1464 if (ifp->if_flags & IFF_RUNNING)
1465 if_input(ifp, &ml);
1466 else
1467 ml_purge(&ml);
1468 }
1469
1470 static inline struct mbuf *
hvn_devget(struct hvn_softc * sc,caddr_t buf,uint32_t len)1471 hvn_devget(struct hvn_softc *sc, caddr_t buf, uint32_t len)
1472 {
1473 struct mbuf *m;
1474
1475 if (len + ETHER_ALIGN <= MHLEN)
1476 MGETHDR(m, M_NOWAIT, MT_DATA);
1477 else
1478 m = MCLGETL(NULL, M_NOWAIT, len + ETHER_ALIGN);
1479 if (m == NULL)
1480 return (NULL);
1481 m->m_len = m->m_pkthdr.len = len;
1482 m_adj(m, ETHER_ALIGN);
1483
1484 if (m_copyback(m, 0, len, buf, M_NOWAIT)) {
1485 m_freem(m);
1486 return (NULL);
1487 }
1488
1489 return (m);
1490 }
1491
1492 void
hvn_rxeof(struct hvn_softc * sc,caddr_t buf,uint32_t len,struct mbuf_list * ml)1493 hvn_rxeof(struct hvn_softc *sc, caddr_t buf, uint32_t len, struct mbuf_list *ml)
1494 {
1495 struct ifnet *ifp = &sc->sc_ac.ac_if;
1496 struct rndis_packet_msg *pkt;
1497 struct rndis_pktinfo *pi;
1498 uint32_t csum, vlan;
1499 struct mbuf *m;
1500
1501 if (!(ifp->if_flags & IFF_RUNNING))
1502 return;
1503
1504 if (len < sizeof(*pkt)) {
1505 printf("%s: data packet too short: %u\n",
1506 sc->sc_dev.dv_xname, len);
1507 return;
1508 }
1509
1510 pkt = (struct rndis_packet_msg *)buf;
1511
1512 if (pkt->rm_dataoffset + pkt->rm_datalen > len) {
1513 printf("%s: data packet out of bounds: %u@%u\n",
1514 sc->sc_dev.dv_xname, pkt->rm_dataoffset, pkt->rm_datalen);
1515 return;
1516 }
1517
1518 if ((m = hvn_devget(sc, buf + RNDIS_HEADER_OFFSET + pkt->rm_dataoffset,
1519 pkt->rm_datalen)) == NULL) {
1520 ifp->if_ierrors++;
1521 return;
1522 }
1523
1524 if (pkt->rm_pktinfooffset + pkt->rm_pktinfolen > len) {
1525 printf("%s: pktinfo is out of bounds: %u@%u vs %u\n",
1526 sc->sc_dev.dv_xname, pkt->rm_pktinfolen,
1527 pkt->rm_pktinfooffset, len);
1528 goto done;
1529 }
1530 pi = (struct rndis_pktinfo *)((caddr_t)pkt + RNDIS_HEADER_OFFSET +
1531 pkt->rm_pktinfooffset);
1532 while (pkt->rm_pktinfolen > 0) {
1533 if (pi->rm_size > pkt->rm_pktinfolen) {
1534 printf("%s: invalid pktinfo size: %u/%u\n",
1535 sc->sc_dev.dv_xname, pi->rm_size,
1536 pkt->rm_pktinfolen);
1537 break;
1538 }
1539 switch (pi->rm_type) {
1540 case NDIS_PKTINFO_TYPE_CSUM:
1541 memcpy(&csum, pi->rm_data, sizeof(csum));
1542 if (csum & NDIS_RXCSUM_INFO_IPCS_OK)
1543 m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
1544 if (csum & NDIS_RXCSUM_INFO_TCPCS_OK)
1545 m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK;
1546 if (csum & NDIS_RXCSUM_INFO_UDPCS_OK)
1547 m->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK;
1548 break;
1549 case NDIS_PKTINFO_TYPE_VLAN:
1550 memcpy(&vlan, pi->rm_data, sizeof(vlan));
1551 #if NVLAN > 0
1552 if (vlan != 0xffffffff) {
1553 m->m_pkthdr.ether_vtag =
1554 NDIS_VLAN_INFO_ID(vlan) |
1555 (NDIS_VLAN_INFO_PRI(vlan) << EVL_PRIO_BITS);
1556 m->m_flags |= M_VLANTAG;
1557 }
1558 #endif
1559 break;
1560 default:
1561 DPRINTF("%s: unhandled pktinfo type %u\n",
1562 sc->sc_dev.dv_xname, pi->rm_type);
1563 }
1564 pkt->rm_pktinfolen -= pi->rm_size;
1565 pi = (struct rndis_pktinfo *)((caddr_t)pi + pi->rm_size);
1566 }
1567
1568 done:
1569 ml_enqueue(ml, m);
1570 }
1571
1572 void
hvn_rndis_complete(struct hvn_softc * sc,caddr_t buf,uint32_t len)1573 hvn_rndis_complete(struct hvn_softc *sc, caddr_t buf, uint32_t len)
1574 {
1575 struct rndis_cmd *rc;
1576 uint32_t id;
1577
1578 memcpy(&id, buf + RNDIS_HEADER_OFFSET, sizeof(id));
1579 if ((rc = hvn_complete_cmd(sc, id)) != NULL) {
1580 if (len < rc->rc_cmplen)
1581 printf("%s: RNDIS response %u too short: %u\n",
1582 sc->sc_dev.dv_xname, id, len);
1583 else
1584 memcpy(&rc->rc_cmp, buf, rc->rc_cmplen);
1585 if (len > rc->rc_cmplen &&
1586 len - rc->rc_cmplen > HVN_RNDIS_BUFSIZE)
1587 printf("%s: RNDIS response %u too large: %u\n",
1588 sc->sc_dev.dv_xname, id, len);
1589 else if (len > rc->rc_cmplen)
1590 memcpy(&rc->rc_cmpbuf, buf + rc->rc_cmplen,
1591 len - rc->rc_cmplen);
1592 rc->rc_done = 1;
1593 wakeup_one(rc);
1594 } else
1595 DPRINTF("%s: failed to complete RNDIS request id %u\n",
1596 sc->sc_dev.dv_xname, id);
1597 }
1598
1599 int
hvn_rndis_output(struct hvn_softc * sc,struct hvn_tx_desc * txd)1600 hvn_rndis_output(struct hvn_softc *sc, struct hvn_tx_desc *txd)
1601 {
1602 uint64_t rid = (uint64_t)txd->txd_id << 32;
1603 int rv;
1604
1605 rv = hv_channel_send_sgl(sc->sc_chan, txd->txd_sgl, txd->txd_nsge,
1606 &sc->sc_data_msg, sizeof(sc->sc_data_msg), rid);
1607 if (rv) {
1608 DPRINTF("%s: RNDIS data send error %d\n",
1609 sc->sc_dev.dv_xname, rv);
1610 return (rv);
1611 }
1612
1613 return (0);
1614 }
1615
1616 void
hvn_rndis_status(struct hvn_softc * sc,caddr_t buf,uint32_t len)1617 hvn_rndis_status(struct hvn_softc *sc, caddr_t buf, uint32_t len)
1618 {
1619 uint32_t status;
1620
1621 memcpy(&status, buf + RNDIS_HEADER_OFFSET, sizeof(status));
1622 switch (status) {
1623 case RNDIS_STATUS_MEDIA_CONNECT:
1624 sc->sc_link_state = LINK_STATE_UP;
1625 break;
1626 case RNDIS_STATUS_MEDIA_DISCONNECT:
1627 sc->sc_link_state = LINK_STATE_DOWN;
1628 break;
1629 /* Ignore these */
1630 case RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG:
1631 return;
1632 default:
1633 DPRINTF("%s: unhandled status %#x\n", sc->sc_dev.dv_xname,
1634 status);
1635 return;
1636 }
1637 KERNEL_LOCK();
1638 hvn_link_status(sc);
1639 KERNEL_UNLOCK();
1640 }
1641
1642 int
hvn_rndis_query(struct hvn_softc * sc,uint32_t oid,void * res,size_t * length)1643 hvn_rndis_query(struct hvn_softc *sc, uint32_t oid, void *res, size_t *length)
1644 {
1645 struct rndis_cmd *rc;
1646 struct rndis_query_req *req;
1647 struct rndis_query_comp *cmp;
1648 size_t olength = *length;
1649 int rv;
1650
1651 rc = hvn_alloc_cmd(sc);
1652
1653 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1654 BUS_DMASYNC_PREREAD);
1655
1656 rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1657
1658 req = rc->rc_req;
1659 req->rm_type = REMOTE_NDIS_QUERY_MSG;
1660 req->rm_len = sizeof(*req);
1661 req->rm_rid = rc->rc_id;
1662 req->rm_oid = oid;
1663 req->rm_infobufoffset = sizeof(*req) - RNDIS_HEADER_OFFSET;
1664
1665 rc->rc_cmplen = sizeof(*cmp);
1666
1667 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1668 BUS_DMASYNC_PREWRITE);
1669
1670 if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
1671 DPRINTF("%s: QUERY_MSG failed, error %d\n",
1672 sc->sc_dev.dv_xname, rv);
1673 hvn_free_cmd(sc, rc);
1674 return (rv);
1675 }
1676
1677 cmp = (struct rndis_query_comp *)&rc->rc_cmp;
1678 switch (cmp->rm_status) {
1679 case RNDIS_STATUS_SUCCESS:
1680 if (cmp->rm_infobuflen > olength) {
1681 rv = EINVAL;
1682 break;
1683 }
1684 memcpy(res, rc->rc_cmpbuf, cmp->rm_infobuflen);
1685 *length = cmp->rm_infobuflen;
1686 break;
1687 default:
1688 *length = 0;
1689 rv = EIO;
1690 }
1691
1692 hvn_free_cmd(sc, rc);
1693
1694 return (rv);
1695 }
1696
1697 int
hvn_rndis_set(struct hvn_softc * sc,uint32_t oid,void * data,size_t length)1698 hvn_rndis_set(struct hvn_softc *sc, uint32_t oid, void *data, size_t length)
1699 {
1700 struct rndis_cmd *rc;
1701 struct rndis_set_req *req;
1702 struct rndis_set_comp *cmp;
1703 int rv;
1704
1705 rc = hvn_alloc_cmd(sc);
1706
1707 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1708 BUS_DMASYNC_PREREAD);
1709
1710 rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1711
1712 req = rc->rc_req;
1713 req->rm_type = REMOTE_NDIS_SET_MSG;
1714 req->rm_len = sizeof(*req) + length;
1715 req->rm_rid = rc->rc_id;
1716 req->rm_oid = oid;
1717 req->rm_infobufoffset = sizeof(*req) - RNDIS_HEADER_OFFSET;
1718
1719 rc->rc_cmplen = sizeof(*cmp);
1720
1721 if (length > 0) {
1722 KASSERT(sizeof(*req) + length < PAGE_SIZE);
1723 req->rm_infobuflen = length;
1724 memcpy((caddr_t)(req + 1), data, length);
1725 }
1726
1727 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1728 BUS_DMASYNC_PREWRITE);
1729
1730 if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
1731 DPRINTF("%s: SET_MSG failed, error %d\n",
1732 sc->sc_dev.dv_xname, rv);
1733 hvn_free_cmd(sc, rc);
1734 return (rv);
1735 }
1736
1737 cmp = (struct rndis_set_comp *)&rc->rc_cmp;
1738 if (cmp->rm_status != RNDIS_STATUS_SUCCESS)
1739 rv = EIO;
1740
1741 hvn_free_cmd(sc, rc);
1742
1743 return (rv);
1744 }
1745
1746 int
hvn_rndis_close(struct hvn_softc * sc)1747 hvn_rndis_close(struct hvn_softc *sc)
1748 {
1749 uint32_t filter = 0;
1750 int rv;
1751
1752 rv = hvn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
1753 &filter, sizeof(filter));
1754 if (rv)
1755 DPRINTF("%s: failed to clear RNDIS filter\n",
1756 sc->sc_dev.dv_xname);
1757 return (rv);
1758 }
1759
1760 void
hvn_rndis_detach(struct hvn_softc * sc)1761 hvn_rndis_detach(struct hvn_softc *sc)
1762 {
1763 struct rndis_cmd *rc;
1764 struct rndis_halt_req *req;
1765 int rv;
1766
1767 rc = hvn_alloc_cmd(sc);
1768
1769 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1770 BUS_DMASYNC_PREREAD);
1771
1772 rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1773
1774 req = rc->rc_req;
1775 req->rm_type = REMOTE_NDIS_HALT_MSG;
1776 req->rm_len = sizeof(*req);
1777 req->rm_rid = rc->rc_id;
1778
1779 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1780 BUS_DMASYNC_PREWRITE);
1781
1782 if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0)
1783 DPRINTF("%s: HALT_MSG failed, error %d\n",
1784 sc->sc_dev.dv_xname, rv);
1785
1786 hvn_free_cmd(sc, rc);
1787 }
1788