1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2013 Nexenta Inc. All rights reserved. 14 * Copyright (c) 2014, 2016 by Delphix. All rights reserved. 15 * Copyright 2015 Joyent, Inc. 16 */ 17 18 /* Based on the NetBSD virtio driver by Minoura Makoto. */ 19 /* 20 * Copyright (c) 2010 Minoura Makoto. 21 * All rights reserved. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 33 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 34 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 35 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 36 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 37 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 41 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44 #include <sys/types.h> 45 #include <sys/errno.h> 46 #include <sys/param.h> 47 #include <sys/stropts.h> 48 #include <sys/stream.h> 49 #include <sys/strsubr.h> 50 #include <sys/kmem.h> 51 #include <sys/conf.h> 52 #include <sys/devops.h> 53 #include <sys/ksynch.h> 54 #include <sys/stat.h> 55 #include <sys/modctl.h> 56 #include <sys/debug.h> 57 #include <sys/pci.h> 58 #include <sys/ethernet.h> 59 #include <sys/vlan.h> 60 61 #include <sys/dlpi.h> 62 #include <sys/taskq.h> 63 #include <sys/cyclic.h> 64 65 #include <sys/pattr.h> 66 #include <sys/strsun.h> 67 68 #include <sys/random.h> 69 #include <sys/containerof.h> 70 #include <sys/stream.h> 71 72 #include <sys/mac.h> 73 #include <sys/mac_provider.h> 74 #include <sys/mac_ether.h> 75 76 #include "virtiovar.h" 77 #include "virtioreg.h" 78 79 /* Configuration registers */ 80 #define VIRTIO_NET_CONFIG_MAC 0 /* 8bit x 6byte */ 81 #define VIRTIO_NET_CONFIG_STATUS 6 /* 16bit */ 82 83 /* Feature bits */ 84 #define VIRTIO_NET_F_CSUM (1 << 0) /* Host handles pkts w/ partial csum */ 85 #define VIRTIO_NET_F_GUEST_CSUM (1 << 1) /* Guest handles pkts w/ part csum */ 86 #define VIRTIO_NET_F_MAC (1 << 5) /* Host has given MAC address. */ 87 #define VIRTIO_NET_F_GSO (1 << 6) /* Host handles pkts w/ any GSO type */ 88 #define VIRTIO_NET_F_GUEST_TSO4 (1 << 7) /* Guest can handle TSOv4 in. */ 89 #define VIRTIO_NET_F_GUEST_TSO6 (1 << 8) /* Guest can handle TSOv6 in. */ 90 #define VIRTIO_NET_F_GUEST_ECN (1 << 9) /* Guest can handle TSO[6] w/ ECN in */ 91 #define VIRTIO_NET_F_GUEST_UFO (1 << 10) /* Guest can handle UFO in. */ 92 #define VIRTIO_NET_F_HOST_TSO4 (1 << 11) /* Host can handle TSOv4 in. */ 93 #define VIRTIO_NET_F_HOST_TSO6 (1 << 12) /* Host can handle TSOv6 in. */ 94 #define VIRTIO_NET_F_HOST_ECN (1 << 13) /* Host can handle TSO[6] w/ ECN in */ 95 #define VIRTIO_NET_F_HOST_UFO (1 << 14) /* Host can handle UFO in. */ 96 #define VIRTIO_NET_F_MRG_RXBUF (1 << 15) /* Host can merge receive buffers. */ 97 #define VIRTIO_NET_F_STATUS (1 << 16) /* Config.status available */ 98 #define VIRTIO_NET_F_CTRL_VQ (1 << 17) /* Control channel available */ 99 #define VIRTIO_NET_F_CTRL_RX (1 << 18) /* Control channel RX mode support */ 100 #define VIRTIO_NET_F_CTRL_VLAN (1 << 19) /* Control channel VLAN filtering */ 101 #define VIRTIO_NET_F_CTRL_RX_EXTRA (1 << 20) /* Extra RX mode control support */ 102 103 #define VIRTIO_NET_FEATURE_BITS \ 104 "\020" \ 105 "\1CSUM" \ 106 "\2GUEST_CSUM" \ 107 "\6MAC" \ 108 "\7GSO" \ 109 "\10GUEST_TSO4" \ 110 "\11GUEST_TSO6" \ 111 "\12GUEST_ECN" \ 112 "\13GUEST_UFO" \ 113 "\14HOST_TSO4" \ 114 "\15HOST_TSO6" \ 115 "\16HOST_ECN" \ 116 "\17HOST_UFO" \ 117 "\20MRG_RXBUF" \ 118 "\21STATUS" \ 119 "\22CTRL_VQ" \ 120 "\23CTRL_RX" \ 121 "\24CTRL_VLAN" \ 122 "\25CTRL_RX_EXTRA" 123 124 /* Status */ 125 #define VIRTIO_NET_S_LINK_UP 1 126 127 #pragma pack(1) 128 /* Packet header structure */ 129 struct virtio_net_hdr { 130 uint8_t flags; 131 uint8_t gso_type; 132 uint16_t hdr_len; 133 uint16_t gso_size; 134 uint16_t csum_start; 135 uint16_t csum_offset; 136 }; 137 #pragma pack() 138 139 #define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* flags */ 140 #define VIRTIO_NET_HDR_GSO_NONE 0 /* gso_type */ 141 #define VIRTIO_NET_HDR_GSO_TCPV4 1 /* gso_type */ 142 #define VIRTIO_NET_HDR_GSO_UDP 3 /* gso_type */ 143 #define VIRTIO_NET_HDR_GSO_TCPV6 4 /* gso_type */ 144 #define VIRTIO_NET_HDR_GSO_ECN 0x80 /* gso_type, |'ed */ 145 146 147 /* Control virtqueue */ 148 #pragma pack(1) 149 struct virtio_net_ctrl_cmd { 150 uint8_t class; 151 uint8_t command; 152 }; 153 #pragma pack() 154 155 #define VIRTIO_NET_CTRL_RX 0 156 #define VIRTIO_NET_CTRL_RX_PROMISC 0 157 #define VIRTIO_NET_CTRL_RX_ALLMULTI 1 158 159 #define VIRTIO_NET_CTRL_MAC 1 160 #define VIRTIO_NET_CTRL_MAC_TABLE_SET 0 161 162 #define VIRTIO_NET_CTRL_VLAN 2 163 #define VIRTIO_NET_CTRL_VLAN_ADD 0 164 #define VIRTIO_NET_CTRL_VLAN_DEL 1 165 166 #pragma pack(1) 167 struct virtio_net_ctrl_status { 168 uint8_t ack; 169 }; 170 171 struct virtio_net_ctrl_rx { 172 uint8_t onoff; 173 }; 174 175 struct virtio_net_ctrl_mac_tbl { 176 uint32_t nentries; 177 uint8_t macs[][ETHERADDRL]; 178 }; 179 180 struct virtio_net_ctrl_vlan { 181 uint16_t id; 182 }; 183 #pragma pack() 184 185 static int vioif_quiesce(dev_info_t *); 186 static int vioif_attach(dev_info_t *, ddi_attach_cmd_t); 187 static int vioif_detach(dev_info_t *, ddi_detach_cmd_t); 188 189 DDI_DEFINE_STREAM_OPS(vioif_ops, 190 nulldev, /* identify */ 191 nulldev, /* probe */ 192 vioif_attach, /* attach */ 193 vioif_detach, /* detach */ 194 nodev, /* reset */ 195 NULL, /* cb_ops */ 196 D_MP, /* bus_ops */ 197 NULL, /* power */ 198 vioif_quiesce /* quiesce */); 199 200 static char vioif_ident[] = "VirtIO ethernet driver"; 201 202 /* Standard Module linkage initialization for a Streams driver */ 203 extern struct mod_ops mod_driverops; 204 205 static struct modldrv modldrv = { 206 &mod_driverops, /* Type of module. This one is a driver */ 207 vioif_ident, /* short description */ 208 &vioif_ops /* driver specific ops */ 209 }; 210 211 static struct modlinkage modlinkage = { 212 MODREV_1, 213 { 214 (void *)&modldrv, 215 NULL, 216 }, 217 }; 218 219 ddi_device_acc_attr_t vioif_attr = { 220 DDI_DEVICE_ATTR_V0, 221 DDI_NEVERSWAP_ACC, /* virtio is always native byte order */ 222 DDI_STORECACHING_OK_ACC, 223 DDI_DEFAULT_ACC 224 }; 225 226 /* 227 * A mapping represents a binding for a single buffer that is contiguous in the 228 * virtual address space. 229 */ 230 struct vioif_buf_mapping { 231 caddr_t vbm_buf; 232 ddi_dma_handle_t vbm_dmah; 233 ddi_acc_handle_t vbm_acch; 234 ddi_dma_cookie_t vbm_dmac; 235 unsigned int vbm_ncookies; 236 }; 237 238 /* 239 * Rx buffers can be loaned upstream, so the code has 240 * to allocate them dynamically. 241 */ 242 struct vioif_rx_buf { 243 struct vioif_softc *rb_sc; 244 frtn_t rb_frtn; 245 246 struct vioif_buf_mapping rb_mapping; 247 }; 248 249 /* 250 * Tx buffers have two mapping types. One, "inline", is pre-allocated and is 251 * used to hold the virtio_net_header. Small packets also get copied there, as 252 * it's faster then mapping them. Bigger packets get mapped using the "external" 253 * mapping array. An array is used, because a packet may consist of muptiple 254 * fragments, so each fragment gets bound to an entry. According to my 255 * observations, the number of fragments does not exceed 2, but just in case, 256 * a bigger, up to VIOIF_INDIRECT_MAX - 1 array is allocated. To save resources, 257 * the dma handles are allocated lazily in the tx path. 258 */ 259 struct vioif_tx_buf { 260 mblk_t *tb_mp; 261 262 /* inline buffer */ 263 struct vioif_buf_mapping tb_inline_mapping; 264 265 /* External buffers */ 266 struct vioif_buf_mapping *tb_external_mapping; 267 unsigned int tb_external_num; 268 }; 269 270 struct vioif_softc { 271 dev_info_t *sc_dev; /* mirrors virtio_softc->sc_dev */ 272 struct virtio_softc sc_virtio; 273 274 mac_handle_t sc_mac_handle; 275 mac_register_t *sc_macp; 276 277 struct virtqueue *sc_rx_vq; 278 struct virtqueue *sc_tx_vq; 279 struct virtqueue *sc_ctrl_vq; 280 281 unsigned int sc_tx_stopped:1; 282 283 /* Feature bits. */ 284 unsigned int sc_rx_csum:1; 285 unsigned int sc_tx_csum:1; 286 unsigned int sc_tx_tso4:1; 287 288 /* 289 * For debugging, it is useful to know whether the MAC address we 290 * are using came from the host (via VIRTIO_NET_CONFIG_MAC) or 291 * was otherwise generated or set from within the guest. 292 */ 293 unsigned int sc_mac_from_host:1; 294 295 int sc_mtu; 296 uint8_t sc_mac[ETHERADDRL]; 297 /* 298 * For rx buffers, we keep a pointer array, because the buffers 299 * can be loaned upstream, and we have to repopulate the array with 300 * new members. 301 */ 302 struct vioif_rx_buf **sc_rxbufs; 303 304 /* 305 * For tx, we just allocate an array of buffers. The packet can 306 * either be copied into the inline buffer, or the external mapping 307 * could be used to map the packet 308 */ 309 struct vioif_tx_buf *sc_txbufs; 310 311 kstat_t *sc_intrstat; 312 /* 313 * We "loan" rx buffers upstream and reuse them after they are 314 * freed. This lets us avoid allocations in the hot path. 315 */ 316 kmem_cache_t *sc_rxbuf_cache; 317 ulong_t sc_rxloan; 318 319 /* Copying small packets turns out to be faster then mapping them. */ 320 unsigned long sc_rxcopy_thresh; 321 unsigned long sc_txcopy_thresh; 322 323 /* 324 * Statistics visible through mac: 325 */ 326 uint64_t sc_ipackets; 327 uint64_t sc_opackets; 328 uint64_t sc_rbytes; 329 uint64_t sc_obytes; 330 uint64_t sc_brdcstxmt; 331 uint64_t sc_brdcstrcv; 332 uint64_t sc_multixmt; 333 uint64_t sc_multircv; 334 uint64_t sc_norecvbuf; 335 uint64_t sc_notxbuf; 336 uint64_t sc_ierrors; 337 uint64_t sc_oerrors; 338 339 /* 340 * Internal debugging statistics: 341 */ 342 uint64_t sc_rxfail_dma_handle; 343 uint64_t sc_rxfail_dma_buffer; 344 uint64_t sc_rxfail_dma_bind; 345 uint64_t sc_rxfail_chain_undersize; 346 uint64_t sc_rxfail_no_descriptors; 347 uint64_t sc_txfail_dma_handle; 348 uint64_t sc_txfail_dma_bind; 349 uint64_t sc_txfail_indirect_limit; 350 }; 351 352 #define ETHER_HEADER_LEN sizeof (struct ether_header) 353 354 /* MTU + the ethernet header. */ 355 #define MAX_PAYLOAD 65535 356 #define MAX_MTU (MAX_PAYLOAD - ETHER_HEADER_LEN) 357 #define DEFAULT_MTU ETHERMTU 358 359 /* 360 * Yeah, we spend 8M per device. Turns out, there is no point 361 * being smart and using merged rx buffers (VIRTIO_NET_F_MRG_RXBUF), 362 * because vhost does not support them, and we expect to be used with 363 * vhost in production environment. 364 */ 365 /* The buffer keeps both the packet data and the virtio_net_header. */ 366 #define VIOIF_RX_SIZE (MAX_PAYLOAD + sizeof (struct virtio_net_hdr)) 367 368 /* 369 * We win a bit on header alignment, but the host wins a lot 370 * more on moving aligned buffers. Might need more thought. 371 */ 372 #define VIOIF_IP_ALIGN 0 373 374 /* Maximum number of indirect descriptors, somewhat arbitrary. */ 375 #define VIOIF_INDIRECT_MAX 128 376 377 /* 378 * We pre-allocate a reasonably large buffer to copy small packets 379 * there. Bigger packets are mapped, packets with multiple 380 * cookies are mapped as indirect buffers. 381 */ 382 #define VIOIF_TX_INLINE_SIZE 2048 383 384 /* Native queue size for all queues */ 385 #define VIOIF_RX_QLEN 0 386 #define VIOIF_TX_QLEN 0 387 #define VIOIF_CTRL_QLEN 0 388 389 static uchar_t vioif_broadcast[ETHERADDRL] = { 390 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 391 }; 392 393 #define VIOIF_TX_THRESH_MAX 640 394 #define VIOIF_RX_THRESH_MAX 640 395 396 #define CACHE_NAME_SIZE 32 397 398 static char vioif_txcopy_thresh[] = 399 "vioif_txcopy_thresh"; 400 static char vioif_rxcopy_thresh[] = 401 "vioif_rxcopy_thresh"; 402 403 static char *vioif_priv_props[] = { 404 vioif_txcopy_thresh, 405 vioif_rxcopy_thresh, 406 NULL 407 }; 408 409 /* Add up to ddi? */ 410 static ddi_dma_cookie_t * 411 vioif_dma_curr_cookie(ddi_dma_handle_t dmah) 412 { 413 ddi_dma_impl_t *dmah_impl = (void *) dmah; 414 ASSERT(dmah_impl->dmai_cookie); 415 return (dmah_impl->dmai_cookie); 416 } 417 418 static void 419 vioif_dma_reset_cookie(ddi_dma_handle_t dmah, ddi_dma_cookie_t *dmac) 420 { 421 ddi_dma_impl_t *dmah_impl = (void *) dmah; 422 dmah_impl->dmai_cookie = dmac; 423 } 424 425 static link_state_t 426 vioif_link_state(struct vioif_softc *sc) 427 { 428 if (sc->sc_virtio.sc_features & VIRTIO_NET_F_STATUS) { 429 if (virtio_read_device_config_2(&sc->sc_virtio, 430 VIRTIO_NET_CONFIG_STATUS) & VIRTIO_NET_S_LINK_UP) { 431 return (LINK_STATE_UP); 432 } else { 433 return (LINK_STATE_DOWN); 434 } 435 } 436 437 return (LINK_STATE_UP); 438 } 439 440 static ddi_dma_attr_t vioif_inline_buf_dma_attr = { 441 DMA_ATTR_V0, /* Version number */ 442 0, /* low address */ 443 0xFFFFFFFFFFFFFFFF, /* high address */ 444 0xFFFFFFFF, /* counter register max */ 445 1, /* page alignment */ 446 1, /* burst sizes: 1 - 32 */ 447 1, /* minimum transfer size */ 448 0xFFFFFFFF, /* max transfer size */ 449 0xFFFFFFFFFFFFFFF, /* address register max */ 450 1, /* scatter-gather capacity */ 451 1, /* device operates on bytes */ 452 0, /* attr flag: set to 0 */ 453 }; 454 455 static ddi_dma_attr_t vioif_mapped_buf_dma_attr = { 456 DMA_ATTR_V0, /* Version number */ 457 0, /* low address */ 458 0xFFFFFFFFFFFFFFFF, /* high address */ 459 0xFFFFFFFF, /* counter register max */ 460 1, /* page alignment */ 461 1, /* burst sizes: 1 - 32 */ 462 1, /* minimum transfer size */ 463 0xFFFFFFFF, /* max transfer size */ 464 0xFFFFFFFFFFFFFFF, /* address register max */ 465 466 /* One entry is used for the virtio_net_hdr on the tx path */ 467 VIOIF_INDIRECT_MAX - 1, /* scatter-gather capacity */ 468 1, /* device operates on bytes */ 469 0, /* attr flag: set to 0 */ 470 }; 471 472 static ddi_device_acc_attr_t vioif_bufattr = { 473 DDI_DEVICE_ATTR_V0, 474 DDI_NEVERSWAP_ACC, 475 DDI_STORECACHING_OK_ACC, 476 DDI_DEFAULT_ACC 477 }; 478 479 static void 480 vioif_rx_free(caddr_t free_arg) 481 { 482 struct vioif_rx_buf *buf = (void *) free_arg; 483 struct vioif_softc *sc = buf->rb_sc; 484 485 kmem_cache_free(sc->sc_rxbuf_cache, buf); 486 atomic_dec_ulong(&sc->sc_rxloan); 487 } 488 489 static int 490 vioif_rx_construct(void *buffer, void *user_arg, int kmflags) 491 { 492 _NOTE(ARGUNUSED(kmflags)); 493 struct vioif_softc *sc = user_arg; 494 struct vioif_rx_buf *buf = buffer; 495 size_t len; 496 497 if (ddi_dma_alloc_handle(sc->sc_dev, &vioif_mapped_buf_dma_attr, 498 DDI_DMA_SLEEP, NULL, &buf->rb_mapping.vbm_dmah)) { 499 sc->sc_rxfail_dma_handle++; 500 goto exit_handle; 501 } 502 503 if (ddi_dma_mem_alloc(buf->rb_mapping.vbm_dmah, 504 VIOIF_RX_SIZE + sizeof (struct virtio_net_hdr), 505 &vioif_bufattr, DDI_DMA_STREAMING, DDI_DMA_SLEEP, 506 NULL, &buf->rb_mapping.vbm_buf, &len, &buf->rb_mapping.vbm_acch)) { 507 sc->sc_rxfail_dma_buffer++; 508 goto exit_alloc; 509 } 510 ASSERT(len >= VIOIF_RX_SIZE); 511 512 if (ddi_dma_addr_bind_handle(buf->rb_mapping.vbm_dmah, NULL, 513 buf->rb_mapping.vbm_buf, len, DDI_DMA_READ | DDI_DMA_STREAMING, 514 DDI_DMA_SLEEP, NULL, &buf->rb_mapping.vbm_dmac, 515 &buf->rb_mapping.vbm_ncookies)) { 516 sc->sc_rxfail_dma_bind++; 517 goto exit_bind; 518 } 519 520 ASSERT(buf->rb_mapping.vbm_ncookies <= VIOIF_INDIRECT_MAX); 521 522 buf->rb_sc = sc; 523 buf->rb_frtn.free_arg = (void *) buf; 524 buf->rb_frtn.free_func = vioif_rx_free; 525 526 return (0); 527 exit_bind: 528 ddi_dma_mem_free(&buf->rb_mapping.vbm_acch); 529 exit_alloc: 530 ddi_dma_free_handle(&buf->rb_mapping.vbm_dmah); 531 exit_handle: 532 533 return (ENOMEM); 534 } 535 536 static void 537 vioif_rx_destruct(void *buffer, void *user_arg) 538 { 539 _NOTE(ARGUNUSED(user_arg)); 540 struct vioif_rx_buf *buf = buffer; 541 542 ASSERT(buf->rb_mapping.vbm_acch); 543 ASSERT(buf->rb_mapping.vbm_acch); 544 545 (void) ddi_dma_unbind_handle(buf->rb_mapping.vbm_dmah); 546 ddi_dma_mem_free(&buf->rb_mapping.vbm_acch); 547 ddi_dma_free_handle(&buf->rb_mapping.vbm_dmah); 548 } 549 550 static void 551 vioif_free_mems(struct vioif_softc *sc) 552 { 553 int i; 554 555 for (i = 0; i < sc->sc_tx_vq->vq_num; i++) { 556 struct vioif_tx_buf *buf = &sc->sc_txbufs[i]; 557 int j; 558 559 /* Tear down the internal mapping. */ 560 561 ASSERT(buf->tb_inline_mapping.vbm_acch); 562 ASSERT(buf->tb_inline_mapping.vbm_dmah); 563 564 (void) ddi_dma_unbind_handle(buf->tb_inline_mapping.vbm_dmah); 565 ddi_dma_mem_free(&buf->tb_inline_mapping.vbm_acch); 566 ddi_dma_free_handle(&buf->tb_inline_mapping.vbm_dmah); 567 568 /* We should not see any in-flight buffers at this point. */ 569 ASSERT(!buf->tb_mp); 570 571 /* Free all the dma hdnales we allocated lazily. */ 572 for (j = 0; buf->tb_external_mapping[j].vbm_dmah; j++) 573 ddi_dma_free_handle( 574 &buf->tb_external_mapping[j].vbm_dmah); 575 /* Free the external mapping array. */ 576 kmem_free(buf->tb_external_mapping, 577 sizeof (struct vioif_tx_buf) * VIOIF_INDIRECT_MAX - 1); 578 } 579 580 kmem_free(sc->sc_txbufs, sizeof (struct vioif_tx_buf) * 581 sc->sc_tx_vq->vq_num); 582 583 for (i = 0; i < sc->sc_rx_vq->vq_num; i++) { 584 struct vioif_rx_buf *buf = sc->sc_rxbufs[i]; 585 586 if (buf) 587 kmem_cache_free(sc->sc_rxbuf_cache, buf); 588 } 589 kmem_free(sc->sc_rxbufs, sizeof (struct vioif_rx_buf *) * 590 sc->sc_rx_vq->vq_num); 591 } 592 593 static int 594 vioif_alloc_mems(struct vioif_softc *sc) 595 { 596 int i, txqsize, rxqsize; 597 size_t len; 598 unsigned int nsegments; 599 600 txqsize = sc->sc_tx_vq->vq_num; 601 rxqsize = sc->sc_rx_vq->vq_num; 602 603 sc->sc_txbufs = kmem_zalloc(sizeof (struct vioif_tx_buf) * txqsize, 604 KM_SLEEP); 605 if (sc->sc_txbufs == NULL) { 606 dev_err(sc->sc_dev, CE_WARN, 607 "Failed to allocate the tx buffers array"); 608 goto exit_txalloc; 609 } 610 611 /* 612 * We don't allocate the rx vioif_bufs, just the pointers, as 613 * rx vioif_bufs can be loaned upstream, and we don't know the 614 * total number we need. 615 */ 616 sc->sc_rxbufs = kmem_zalloc(sizeof (struct vioif_rx_buf *) * rxqsize, 617 KM_SLEEP); 618 if (sc->sc_rxbufs == NULL) { 619 dev_err(sc->sc_dev, CE_WARN, 620 "Failed to allocate the rx buffers pointer array"); 621 goto exit_rxalloc; 622 } 623 624 for (i = 0; i < txqsize; i++) { 625 struct vioif_tx_buf *buf = &sc->sc_txbufs[i]; 626 627 /* Allocate and bind an inline mapping. */ 628 629 if (ddi_dma_alloc_handle(sc->sc_dev, 630 &vioif_inline_buf_dma_attr, 631 DDI_DMA_SLEEP, NULL, &buf->tb_inline_mapping.vbm_dmah)) { 632 633 dev_err(sc->sc_dev, CE_WARN, 634 "Can't allocate dma handle for tx buffer %d", i); 635 goto exit_tx; 636 } 637 638 if (ddi_dma_mem_alloc(buf->tb_inline_mapping.vbm_dmah, 639 VIOIF_TX_INLINE_SIZE, &vioif_bufattr, DDI_DMA_STREAMING, 640 DDI_DMA_SLEEP, NULL, &buf->tb_inline_mapping.vbm_buf, 641 &len, &buf->tb_inline_mapping.vbm_acch)) { 642 643 dev_err(sc->sc_dev, CE_WARN, 644 "Can't allocate tx buffer %d", i); 645 goto exit_tx; 646 } 647 ASSERT(len >= VIOIF_TX_INLINE_SIZE); 648 649 if (ddi_dma_addr_bind_handle(buf->tb_inline_mapping.vbm_dmah, 650 NULL, buf->tb_inline_mapping.vbm_buf, len, 651 DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, 652 &buf->tb_inline_mapping.vbm_dmac, &nsegments)) { 653 654 dev_err(sc->sc_dev, CE_WARN, 655 "Can't bind tx buffer %d", i); 656 goto exit_tx; 657 } 658 659 /* We asked for a single segment */ 660 ASSERT(nsegments == 1); 661 662 /* 663 * We allow up to VIOIF_INDIRECT_MAX - 1 external mappings. 664 * In reality, I don't expect more then 2-3 used, but who 665 * knows. 666 */ 667 buf->tb_external_mapping = kmem_zalloc( 668 sizeof (struct vioif_tx_buf) * VIOIF_INDIRECT_MAX - 1, 669 KM_SLEEP); 670 671 /* 672 * The external mapping's dma handles are allocate lazily, 673 * as we don't expect most of them to be used.. 674 */ 675 } 676 677 return (0); 678 679 exit_tx: 680 for (i = 0; i < txqsize; i++) { 681 struct vioif_tx_buf *buf = &sc->sc_txbufs[i]; 682 683 if (buf->tb_inline_mapping.vbm_dmah) 684 (void) ddi_dma_unbind_handle( 685 buf->tb_inline_mapping.vbm_dmah); 686 687 if (buf->tb_inline_mapping.vbm_acch) 688 ddi_dma_mem_free( 689 &buf->tb_inline_mapping.vbm_acch); 690 691 if (buf->tb_inline_mapping.vbm_dmah) 692 ddi_dma_free_handle( 693 &buf->tb_inline_mapping.vbm_dmah); 694 695 if (buf->tb_external_mapping) 696 kmem_free(buf->tb_external_mapping, 697 sizeof (struct vioif_tx_buf) * 698 VIOIF_INDIRECT_MAX - 1); 699 } 700 701 kmem_free(sc->sc_rxbufs, sizeof (struct vioif_rx_buf) * rxqsize); 702 703 exit_rxalloc: 704 kmem_free(sc->sc_txbufs, sizeof (struct vioif_tx_buf) * txqsize); 705 exit_txalloc: 706 return (ENOMEM); 707 } 708 709 /* ARGSUSED */ 710 int 711 vioif_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 712 { 713 return (DDI_SUCCESS); 714 } 715 716 /* ARGSUSED */ 717 int 718 vioif_promisc(void *arg, boolean_t on) 719 { 720 return (DDI_SUCCESS); 721 } 722 723 /* ARGSUSED */ 724 int 725 vioif_unicst(void *arg, const uint8_t *macaddr) 726 { 727 return (DDI_FAILURE); 728 } 729 730 731 static uint_t 732 vioif_add_rx(struct vioif_softc *sc, int kmflag) 733 { 734 uint_t num_added = 0; 735 struct vq_entry *ve; 736 737 while ((ve = vq_alloc_entry(sc->sc_rx_vq)) != NULL) { 738 struct vioif_rx_buf *buf = sc->sc_rxbufs[ve->qe_index]; 739 740 if (buf == NULL) { 741 /* First run, allocate the buffer. */ 742 buf = kmem_cache_alloc(sc->sc_rxbuf_cache, kmflag); 743 sc->sc_rxbufs[ve->qe_index] = buf; 744 } 745 746 /* Still nothing? Bye. */ 747 if (buf == NULL) { 748 sc->sc_norecvbuf++; 749 vq_free_entry(sc->sc_rx_vq, ve); 750 break; 751 } 752 753 ASSERT(buf->rb_mapping.vbm_ncookies >= 1); 754 755 /* 756 * For an unknown reason, the virtio_net_hdr must be placed 757 * as a separate virtio queue entry. 758 */ 759 virtio_ve_add_indirect_buf(ve, 760 buf->rb_mapping.vbm_dmac.dmac_laddress, 761 sizeof (struct virtio_net_hdr), B_FALSE); 762 763 /* Add the rest of the first cookie. */ 764 virtio_ve_add_indirect_buf(ve, 765 buf->rb_mapping.vbm_dmac.dmac_laddress + 766 sizeof (struct virtio_net_hdr), 767 buf->rb_mapping.vbm_dmac.dmac_size - 768 sizeof (struct virtio_net_hdr), B_FALSE); 769 770 /* 771 * If the buffer consists of a single cookie (unlikely for a 772 * 64-k buffer), we are done. Otherwise, add the rest of the 773 * cookies using indirect entries. 774 */ 775 if (buf->rb_mapping.vbm_ncookies > 1) { 776 ddi_dma_cookie_t *first_extra_dmac; 777 ddi_dma_cookie_t dmac; 778 first_extra_dmac = 779 vioif_dma_curr_cookie(buf->rb_mapping.vbm_dmah); 780 781 ddi_dma_nextcookie(buf->rb_mapping.vbm_dmah, &dmac); 782 virtio_ve_add_cookie(ve, buf->rb_mapping.vbm_dmah, 783 dmac, buf->rb_mapping.vbm_ncookies - 1, B_FALSE); 784 vioif_dma_reset_cookie(buf->rb_mapping.vbm_dmah, 785 first_extra_dmac); 786 } 787 788 virtio_push_chain(ve, B_FALSE); 789 num_added++; 790 } 791 792 return (num_added); 793 } 794 795 static uint_t 796 vioif_populate_rx(struct vioif_softc *sc, int kmflag) 797 { 798 uint_t num_added = vioif_add_rx(sc, kmflag); 799 800 if (num_added > 0) 801 virtio_sync_vq(sc->sc_rx_vq); 802 803 return (num_added); 804 } 805 806 static uint_t 807 vioif_process_rx(struct vioif_softc *sc) 808 { 809 struct vq_entry *ve; 810 struct vioif_rx_buf *buf; 811 mblk_t *mphead = NULL, *lastmp = NULL, *mp; 812 uint32_t len; 813 uint_t num_processed = 0; 814 815 while ((ve = virtio_pull_chain(sc->sc_rx_vq, &len))) { 816 817 buf = sc->sc_rxbufs[ve->qe_index]; 818 ASSERT(buf); 819 820 if (len < sizeof (struct virtio_net_hdr)) { 821 sc->sc_rxfail_chain_undersize++; 822 sc->sc_ierrors++; 823 virtio_free_chain(ve); 824 continue; 825 } 826 827 len -= sizeof (struct virtio_net_hdr); 828 /* 829 * We copy small packets that happen to fit into a single 830 * cookie and reuse the buffers. For bigger ones, we loan 831 * the buffers upstream. 832 */ 833 if (len < sc->sc_rxcopy_thresh) { 834 mp = allocb(len, 0); 835 if (mp == NULL) { 836 sc->sc_norecvbuf++; 837 sc->sc_ierrors++; 838 839 virtio_free_chain(ve); 840 break; 841 } 842 843 bcopy((char *)buf->rb_mapping.vbm_buf + 844 sizeof (struct virtio_net_hdr), mp->b_rptr, len); 845 mp->b_wptr = mp->b_rptr + len; 846 847 } else { 848 mp = desballoc((unsigned char *) 849 buf->rb_mapping.vbm_buf + 850 sizeof (struct virtio_net_hdr) + 851 VIOIF_IP_ALIGN, len, 0, &buf->rb_frtn); 852 if (mp == NULL) { 853 sc->sc_norecvbuf++; 854 sc->sc_ierrors++; 855 856 virtio_free_chain(ve); 857 break; 858 } 859 mp->b_wptr = mp->b_rptr + len; 860 861 atomic_inc_ulong(&sc->sc_rxloan); 862 /* 863 * Buffer loaned, we will have to allocate a new one 864 * for this slot. 865 */ 866 sc->sc_rxbufs[ve->qe_index] = NULL; 867 } 868 869 /* 870 * virtio-net does not tell us if this packet is multicast 871 * or broadcast, so we have to check it. 872 */ 873 if (mp->b_rptr[0] & 0x1) { 874 if (bcmp(mp->b_rptr, vioif_broadcast, ETHERADDRL) != 0) 875 sc->sc_multircv++; 876 else 877 sc->sc_brdcstrcv++; 878 } 879 880 sc->sc_rbytes += len; 881 sc->sc_ipackets++; 882 883 virtio_free_chain(ve); 884 885 if (lastmp == NULL) { 886 mphead = mp; 887 } else { 888 lastmp->b_next = mp; 889 } 890 lastmp = mp; 891 num_processed++; 892 } 893 894 if (mphead != NULL) { 895 mac_rx(sc->sc_mac_handle, NULL, mphead); 896 } 897 898 return (num_processed); 899 } 900 901 static uint_t 902 vioif_reclaim_used_tx(struct vioif_softc *sc) 903 { 904 struct vq_entry *ve; 905 struct vioif_tx_buf *buf; 906 uint32_t len; 907 mblk_t *mp; 908 uint_t num_reclaimed = 0; 909 910 while ((ve = virtio_pull_chain(sc->sc_tx_vq, &len))) { 911 /* We don't chain descriptors for tx, so don't expect any. */ 912 ASSERT(!ve->qe_next); 913 914 buf = &sc->sc_txbufs[ve->qe_index]; 915 mp = buf->tb_mp; 916 buf->tb_mp = NULL; 917 918 if (mp != NULL) { 919 for (int i = 0; i < buf->tb_external_num; i++) 920 (void) ddi_dma_unbind_handle( 921 buf->tb_external_mapping[i].vbm_dmah); 922 } 923 924 virtio_free_chain(ve); 925 926 /* External mapping used, mp was not freed in vioif_send() */ 927 if (mp != NULL) 928 freemsg(mp); 929 num_reclaimed++; 930 } 931 932 if (sc->sc_tx_stopped && num_reclaimed > 0) { 933 sc->sc_tx_stopped = 0; 934 mac_tx_update(sc->sc_mac_handle); 935 } 936 937 return (num_reclaimed); 938 } 939 940 /* sc will be used to update stat counters. */ 941 /* ARGSUSED */ 942 static inline void 943 vioif_tx_inline(struct vioif_softc *sc, struct vq_entry *ve, mblk_t *mp, 944 size_t msg_size) 945 { 946 struct vioif_tx_buf *buf; 947 buf = &sc->sc_txbufs[ve->qe_index]; 948 949 ASSERT(buf); 950 951 /* Frees mp */ 952 mcopymsg(mp, buf->tb_inline_mapping.vbm_buf + 953 sizeof (struct virtio_net_hdr)); 954 955 virtio_ve_add_indirect_buf(ve, 956 buf->tb_inline_mapping.vbm_dmac.dmac_laddress + 957 sizeof (struct virtio_net_hdr), msg_size, B_TRUE); 958 } 959 960 static inline int 961 vioif_tx_lazy_handle_alloc(struct vioif_softc *sc, struct vioif_tx_buf *buf, 962 int i) 963 { 964 int ret = DDI_SUCCESS; 965 966 if (!buf->tb_external_mapping[i].vbm_dmah) { 967 ret = ddi_dma_alloc_handle(sc->sc_dev, 968 &vioif_mapped_buf_dma_attr, DDI_DMA_SLEEP, NULL, 969 &buf->tb_external_mapping[i].vbm_dmah); 970 if (ret != DDI_SUCCESS) { 971 sc->sc_txfail_dma_handle++; 972 } 973 } 974 975 return (ret); 976 } 977 978 static inline int 979 vioif_tx_external(struct vioif_softc *sc, struct vq_entry *ve, mblk_t *mp, 980 size_t msg_size) 981 { 982 _NOTE(ARGUNUSED(msg_size)); 983 984 struct vioif_tx_buf *buf; 985 mblk_t *nmp; 986 int i, j; 987 int ret = DDI_SUCCESS; 988 989 buf = &sc->sc_txbufs[ve->qe_index]; 990 991 ASSERT(buf); 992 993 buf->tb_external_num = 0; 994 i = 0; 995 nmp = mp; 996 997 while (nmp) { 998 size_t len; 999 ddi_dma_cookie_t dmac; 1000 unsigned int ncookies; 1001 1002 len = MBLKL(nmp); 1003 /* 1004 * For some reason, the network stack can 1005 * actually send us zero-length fragments. 1006 */ 1007 if (len == 0) { 1008 nmp = nmp->b_cont; 1009 continue; 1010 } 1011 1012 ret = vioif_tx_lazy_handle_alloc(sc, buf, i); 1013 if (ret != DDI_SUCCESS) { 1014 sc->sc_notxbuf++; 1015 sc->sc_oerrors++; 1016 goto exit_lazy_alloc; 1017 } 1018 ret = ddi_dma_addr_bind_handle( 1019 buf->tb_external_mapping[i].vbm_dmah, NULL, 1020 (caddr_t)nmp->b_rptr, len, 1021 DDI_DMA_WRITE | DDI_DMA_STREAMING, 1022 DDI_DMA_SLEEP, NULL, &dmac, &ncookies); 1023 1024 if (ret != DDI_SUCCESS) { 1025 sc->sc_txfail_dma_bind++; 1026 sc->sc_oerrors++; 1027 goto exit_bind; 1028 } 1029 1030 /* Check if we still fit into the indirect table. */ 1031 if (virtio_ve_indirect_available(ve) < ncookies) { 1032 sc->sc_txfail_indirect_limit++; 1033 sc->sc_notxbuf++; 1034 sc->sc_oerrors++; 1035 1036 ret = DDI_FAILURE; 1037 goto exit_limit; 1038 } 1039 1040 virtio_ve_add_cookie(ve, buf->tb_external_mapping[i].vbm_dmah, 1041 dmac, ncookies, B_TRUE); 1042 1043 nmp = nmp->b_cont; 1044 i++; 1045 } 1046 1047 buf->tb_external_num = i; 1048 /* Save the mp to free it when the packet is sent. */ 1049 buf->tb_mp = mp; 1050 1051 return (DDI_SUCCESS); 1052 1053 exit_limit: 1054 exit_bind: 1055 exit_lazy_alloc: 1056 1057 for (j = 0; j < i; j++) { 1058 (void) ddi_dma_unbind_handle( 1059 buf->tb_external_mapping[j].vbm_dmah); 1060 } 1061 1062 return (ret); 1063 } 1064 1065 static boolean_t 1066 vioif_send(struct vioif_softc *sc, mblk_t *mp) 1067 { 1068 struct vq_entry *ve; 1069 struct vioif_tx_buf *buf; 1070 struct virtio_net_hdr *net_header = NULL; 1071 size_t msg_size = 0; 1072 uint32_t csum_start; 1073 uint32_t csum_stuff; 1074 uint32_t csum_flags; 1075 uint32_t lso_flags; 1076 uint32_t lso_mss; 1077 mblk_t *nmp; 1078 int ret; 1079 boolean_t lso_required = B_FALSE; 1080 1081 for (nmp = mp; nmp; nmp = nmp->b_cont) 1082 msg_size += MBLKL(nmp); 1083 1084 if (sc->sc_tx_tso4) { 1085 mac_lso_get(mp, &lso_mss, &lso_flags); 1086 lso_required = (lso_flags & HW_LSO); 1087 } 1088 1089 ve = vq_alloc_entry(sc->sc_tx_vq); 1090 1091 if (ve == NULL) { 1092 sc->sc_notxbuf++; 1093 /* Out of free descriptors - try later. */ 1094 return (B_FALSE); 1095 } 1096 buf = &sc->sc_txbufs[ve->qe_index]; 1097 1098 /* Use the inline buffer of the first entry for the virtio_net_hdr. */ 1099 (void) memset(buf->tb_inline_mapping.vbm_buf, 0, 1100 sizeof (struct virtio_net_hdr)); 1101 1102 net_header = (struct virtio_net_hdr *)buf->tb_inline_mapping.vbm_buf; 1103 1104 mac_hcksum_get(mp, &csum_start, &csum_stuff, NULL, 1105 NULL, &csum_flags); 1106 1107 /* They want us to do the TCP/UDP csum calculation. */ 1108 if (csum_flags & HCK_PARTIALCKSUM) { 1109 struct ether_header *eth_header; 1110 int eth_hsize; 1111 1112 /* Did we ask for it? */ 1113 ASSERT(sc->sc_tx_csum); 1114 1115 /* We only asked for partial csum packets. */ 1116 ASSERT(!(csum_flags & HCK_IPV4_HDRCKSUM)); 1117 ASSERT(!(csum_flags & HCK_FULLCKSUM)); 1118 1119 eth_header = (void *) mp->b_rptr; 1120 if (eth_header->ether_type == htons(ETHERTYPE_VLAN)) { 1121 eth_hsize = sizeof (struct ether_vlan_header); 1122 } else { 1123 eth_hsize = sizeof (struct ether_header); 1124 } 1125 net_header->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; 1126 net_header->csum_start = eth_hsize + csum_start; 1127 net_header->csum_offset = csum_stuff - csum_start; 1128 } 1129 1130 /* setup LSO fields if required */ 1131 if (lso_required) { 1132 net_header->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; 1133 net_header->gso_size = (uint16_t)lso_mss; 1134 } 1135 1136 virtio_ve_add_indirect_buf(ve, 1137 buf->tb_inline_mapping.vbm_dmac.dmac_laddress, 1138 sizeof (struct virtio_net_hdr), B_TRUE); 1139 1140 /* meanwhile update the statistic */ 1141 if (mp->b_rptr[0] & 0x1) { 1142 if (bcmp(mp->b_rptr, vioif_broadcast, ETHERADDRL) != 0) 1143 sc->sc_multixmt++; 1144 else 1145 sc->sc_brdcstxmt++; 1146 } 1147 1148 /* 1149 * We copy small packets into the inline buffer. The bigger ones 1150 * get mapped using the mapped buffer. 1151 */ 1152 if (msg_size < sc->sc_txcopy_thresh) { 1153 vioif_tx_inline(sc, ve, mp, msg_size); 1154 } else { 1155 /* statistic gets updated by vioif_tx_external when fail */ 1156 ret = vioif_tx_external(sc, ve, mp, msg_size); 1157 if (ret != DDI_SUCCESS) 1158 goto exit_tx_external; 1159 } 1160 1161 virtio_push_chain(ve, B_TRUE); 1162 1163 sc->sc_opackets++; 1164 sc->sc_obytes += msg_size; 1165 1166 return (B_TRUE); 1167 1168 exit_tx_external: 1169 1170 vq_free_entry(sc->sc_tx_vq, ve); 1171 /* 1172 * vioif_tx_external can fail when the buffer does not fit into the 1173 * indirect descriptor table. Free the mp. I don't expect this ever 1174 * to happen. 1175 */ 1176 freemsg(mp); 1177 1178 return (B_TRUE); 1179 } 1180 1181 mblk_t * 1182 vioif_tx(void *arg, mblk_t *mp) 1183 { 1184 struct vioif_softc *sc = arg; 1185 mblk_t *nmp; 1186 1187 while (mp != NULL) { 1188 nmp = mp->b_next; 1189 mp->b_next = NULL; 1190 1191 if (!vioif_send(sc, mp)) { 1192 sc->sc_tx_stopped = 1; 1193 mp->b_next = nmp; 1194 break; 1195 } 1196 mp = nmp; 1197 } 1198 1199 return (mp); 1200 } 1201 1202 int 1203 vioif_start(void *arg) 1204 { 1205 struct vioif_softc *sc = arg; 1206 struct vq_entry *ve; 1207 uint32_t len; 1208 1209 mac_link_update(sc->sc_mac_handle, vioif_link_state(sc)); 1210 1211 virtio_start_vq_intr(sc->sc_rx_vq); 1212 1213 /* 1214 * Don't start interrupts on sc_tx_vq. We use VIRTIO_F_NOTIFY_ON_EMPTY, 1215 * so the device will send a transmit interrupt when the queue is empty 1216 * and we can reclaim it in one sweep. 1217 */ 1218 1219 /* 1220 * Clear any data that arrived early on the receive queue and populate 1221 * it with free buffers that the device can use moving forward. 1222 */ 1223 while ((ve = virtio_pull_chain(sc->sc_rx_vq, &len)) != NULL) { 1224 virtio_free_chain(ve); 1225 } 1226 (void) vioif_populate_rx(sc, KM_SLEEP); 1227 1228 return (DDI_SUCCESS); 1229 } 1230 1231 void 1232 vioif_stop(void *arg) 1233 { 1234 struct vioif_softc *sc = arg; 1235 1236 virtio_stop_vq_intr(sc->sc_rx_vq); 1237 } 1238 1239 /* ARGSUSED */ 1240 static int 1241 vioif_stat(void *arg, uint_t stat, uint64_t *val) 1242 { 1243 struct vioif_softc *sc = arg; 1244 1245 switch (stat) { 1246 case MAC_STAT_IERRORS: 1247 *val = sc->sc_ierrors; 1248 break; 1249 case MAC_STAT_OERRORS: 1250 *val = sc->sc_oerrors; 1251 break; 1252 case MAC_STAT_MULTIRCV: 1253 *val = sc->sc_multircv; 1254 break; 1255 case MAC_STAT_BRDCSTRCV: 1256 *val = sc->sc_brdcstrcv; 1257 break; 1258 case MAC_STAT_MULTIXMT: 1259 *val = sc->sc_multixmt; 1260 break; 1261 case MAC_STAT_BRDCSTXMT: 1262 *val = sc->sc_brdcstxmt; 1263 break; 1264 case MAC_STAT_IPACKETS: 1265 *val = sc->sc_ipackets; 1266 break; 1267 case MAC_STAT_RBYTES: 1268 *val = sc->sc_rbytes; 1269 break; 1270 case MAC_STAT_OPACKETS: 1271 *val = sc->sc_opackets; 1272 break; 1273 case MAC_STAT_OBYTES: 1274 *val = sc->sc_obytes; 1275 break; 1276 case MAC_STAT_NORCVBUF: 1277 *val = sc->sc_norecvbuf; 1278 break; 1279 case MAC_STAT_NOXMTBUF: 1280 *val = sc->sc_notxbuf; 1281 break; 1282 case MAC_STAT_IFSPEED: 1283 /* always 1 Gbit */ 1284 *val = 1000000000ULL; 1285 break; 1286 case ETHER_STAT_LINK_DUPLEX: 1287 /* virtual device, always full-duplex */ 1288 *val = LINK_DUPLEX_FULL; 1289 break; 1290 1291 default: 1292 return (ENOTSUP); 1293 } 1294 1295 return (DDI_SUCCESS); 1296 } 1297 1298 static int 1299 vioif_set_prop_private(struct vioif_softc *sc, const char *pr_name, 1300 uint_t pr_valsize, const void *pr_val) 1301 { 1302 _NOTE(ARGUNUSED(pr_valsize)); 1303 1304 long result; 1305 1306 if (strcmp(pr_name, vioif_txcopy_thresh) == 0) { 1307 1308 if (pr_val == NULL) 1309 return (EINVAL); 1310 1311 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 1312 1313 if (result < 0 || result > VIOIF_TX_THRESH_MAX) 1314 return (EINVAL); 1315 sc->sc_txcopy_thresh = result; 1316 } 1317 if (strcmp(pr_name, vioif_rxcopy_thresh) == 0) { 1318 1319 if (pr_val == NULL) 1320 return (EINVAL); 1321 1322 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 1323 1324 if (result < 0 || result > VIOIF_RX_THRESH_MAX) 1325 return (EINVAL); 1326 sc->sc_rxcopy_thresh = result; 1327 } 1328 return (0); 1329 } 1330 1331 static int 1332 vioif_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1333 uint_t pr_valsize, const void *pr_val) 1334 { 1335 struct vioif_softc *sc = arg; 1336 const uint32_t *new_mtu; 1337 int err; 1338 1339 switch (pr_num) { 1340 case MAC_PROP_MTU: 1341 new_mtu = pr_val; 1342 1343 if (*new_mtu > MAX_MTU) { 1344 return (EINVAL); 1345 } 1346 1347 err = mac_maxsdu_update(sc->sc_mac_handle, *new_mtu); 1348 if (err) { 1349 return (err); 1350 } 1351 break; 1352 case MAC_PROP_PRIVATE: 1353 err = vioif_set_prop_private(sc, pr_name, 1354 pr_valsize, pr_val); 1355 if (err) 1356 return (err); 1357 break; 1358 default: 1359 return (ENOTSUP); 1360 } 1361 1362 return (0); 1363 } 1364 1365 static int 1366 vioif_get_prop_private(struct vioif_softc *sc, const char *pr_name, 1367 uint_t pr_valsize, void *pr_val) 1368 { 1369 int err = ENOTSUP; 1370 int value; 1371 1372 if (strcmp(pr_name, vioif_txcopy_thresh) == 0) { 1373 1374 value = sc->sc_txcopy_thresh; 1375 err = 0; 1376 goto done; 1377 } 1378 if (strcmp(pr_name, vioif_rxcopy_thresh) == 0) { 1379 1380 value = sc->sc_rxcopy_thresh; 1381 err = 0; 1382 goto done; 1383 } 1384 done: 1385 if (err == 0) { 1386 (void) snprintf(pr_val, pr_valsize, "%d", value); 1387 } 1388 return (err); 1389 } 1390 1391 static int 1392 vioif_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1393 uint_t pr_valsize, void *pr_val) 1394 { 1395 struct vioif_softc *sc = arg; 1396 int err = ENOTSUP; 1397 1398 switch (pr_num) { 1399 case MAC_PROP_PRIVATE: 1400 err = vioif_get_prop_private(sc, pr_name, 1401 pr_valsize, pr_val); 1402 break; 1403 default: 1404 break; 1405 } 1406 return (err); 1407 } 1408 1409 static void 1410 vioif_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1411 mac_prop_info_handle_t prh) 1412 { 1413 struct vioif_softc *sc = arg; 1414 char valstr[64]; 1415 int value; 1416 1417 switch (pr_num) { 1418 case MAC_PROP_MTU: 1419 mac_prop_info_set_range_uint32(prh, ETHERMIN, MAX_MTU); 1420 break; 1421 1422 case MAC_PROP_PRIVATE: 1423 bzero(valstr, sizeof (valstr)); 1424 if (strcmp(pr_name, vioif_txcopy_thresh) == 0) { 1425 value = sc->sc_txcopy_thresh; 1426 } else if (strcmp(pr_name, vioif_rxcopy_thresh) == 0) { 1427 value = sc->sc_rxcopy_thresh; 1428 } else { 1429 return; 1430 } 1431 (void) snprintf(valstr, sizeof (valstr), "%d", value); 1432 break; 1433 1434 default: 1435 break; 1436 } 1437 } 1438 1439 static boolean_t 1440 vioif_getcapab(void *arg, mac_capab_t cap, void *cap_data) 1441 { 1442 struct vioif_softc *sc = arg; 1443 1444 switch (cap) { 1445 case MAC_CAPAB_HCKSUM: 1446 if (sc->sc_tx_csum) { 1447 uint32_t *txflags = cap_data; 1448 1449 *txflags = HCKSUM_INET_PARTIAL; 1450 return (B_TRUE); 1451 } 1452 return (B_FALSE); 1453 case MAC_CAPAB_LSO: 1454 if (sc->sc_tx_tso4) { 1455 mac_capab_lso_t *cap_lso = cap_data; 1456 1457 cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4; 1458 cap_lso->lso_basic_tcp_ipv4.lso_max = MAX_MTU; 1459 return (B_TRUE); 1460 } 1461 return (B_FALSE); 1462 default: 1463 break; 1464 } 1465 return (B_FALSE); 1466 } 1467 1468 static mac_callbacks_t vioif_m_callbacks = { 1469 .mc_callbacks = (MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO), 1470 .mc_getstat = vioif_stat, 1471 .mc_start = vioif_start, 1472 .mc_stop = vioif_stop, 1473 .mc_setpromisc = vioif_promisc, 1474 .mc_multicst = vioif_multicst, 1475 .mc_unicst = vioif_unicst, 1476 .mc_tx = vioif_tx, 1477 /* Optional callbacks */ 1478 .mc_reserved = NULL, /* reserved */ 1479 .mc_ioctl = NULL, /* mc_ioctl */ 1480 .mc_getcapab = vioif_getcapab, /* mc_getcapab */ 1481 .mc_open = NULL, /* mc_open */ 1482 .mc_close = NULL, /* mc_close */ 1483 .mc_setprop = vioif_setprop, 1484 .mc_getprop = vioif_getprop, 1485 .mc_propinfo = vioif_propinfo, 1486 }; 1487 1488 static void 1489 vioif_show_features(struct vioif_softc *sc, const char *prefix, 1490 uint32_t features) 1491 { 1492 char buf[512]; 1493 char *bufp = buf; 1494 char *bufend = buf + sizeof (buf); 1495 1496 /* LINTED E_PTRDIFF_OVERFLOW */ 1497 bufp += snprintf(bufp, bufend - bufp, prefix); 1498 /* LINTED E_PTRDIFF_OVERFLOW */ 1499 bufp += virtio_show_features(features, bufp, bufend - bufp); 1500 *bufp = '\0'; 1501 1502 /* Using '!' to only CE_NOTE this to the system log. */ 1503 dev_err(sc->sc_dev, CE_NOTE, "!%s Vioif (%b)", buf, features, 1504 VIRTIO_NET_FEATURE_BITS); 1505 } 1506 1507 /* 1508 * Find out which features are supported by the device and 1509 * choose which ones we wish to use. 1510 */ 1511 static int 1512 vioif_dev_features(struct vioif_softc *sc) 1513 { 1514 uint32_t host_features; 1515 1516 host_features = virtio_negotiate_features(&sc->sc_virtio, 1517 VIRTIO_NET_F_CSUM | 1518 VIRTIO_NET_F_HOST_TSO4 | 1519 VIRTIO_NET_F_HOST_ECN | 1520 VIRTIO_NET_F_MAC | 1521 VIRTIO_NET_F_STATUS | 1522 VIRTIO_F_RING_INDIRECT_DESC | 1523 VIRTIO_F_NOTIFY_ON_EMPTY); 1524 1525 vioif_show_features(sc, "Host features: ", host_features); 1526 vioif_show_features(sc, "Negotiated features: ", 1527 sc->sc_virtio.sc_features); 1528 1529 if (!(sc->sc_virtio.sc_features & VIRTIO_F_RING_INDIRECT_DESC)) { 1530 dev_err(sc->sc_dev, CE_WARN, 1531 "Host does not support RING_INDIRECT_DESC. Cannot attach."); 1532 return (DDI_FAILURE); 1533 } 1534 1535 return (DDI_SUCCESS); 1536 } 1537 1538 static int 1539 vioif_has_feature(struct vioif_softc *sc, uint32_t feature) 1540 { 1541 return (virtio_has_feature(&sc->sc_virtio, feature)); 1542 } 1543 1544 static void 1545 vioif_set_mac(struct vioif_softc *sc) 1546 { 1547 int i; 1548 1549 for (i = 0; i < ETHERADDRL; i++) { 1550 virtio_write_device_config_1(&sc->sc_virtio, 1551 VIRTIO_NET_CONFIG_MAC + i, sc->sc_mac[i]); 1552 } 1553 sc->sc_mac_from_host = 0; 1554 } 1555 1556 /* Get the mac address out of the hardware, or make up one. */ 1557 static void 1558 vioif_get_mac(struct vioif_softc *sc) 1559 { 1560 int i; 1561 if (sc->sc_virtio.sc_features & VIRTIO_NET_F_MAC) { 1562 for (i = 0; i < ETHERADDRL; i++) { 1563 sc->sc_mac[i] = virtio_read_device_config_1( 1564 &sc->sc_virtio, 1565 VIRTIO_NET_CONFIG_MAC + i); 1566 } 1567 sc->sc_mac_from_host = 1; 1568 } else { 1569 /* Get a few random bytes */ 1570 (void) random_get_pseudo_bytes(sc->sc_mac, ETHERADDRL); 1571 /* Make sure it's a unicast MAC */ 1572 sc->sc_mac[0] &= ~1; 1573 /* Set the "locally administered" bit */ 1574 sc->sc_mac[1] |= 2; 1575 1576 vioif_set_mac(sc); 1577 1578 dev_err(sc->sc_dev, CE_NOTE, 1579 "!Generated a random MAC address: %s", 1580 ether_sprintf((struct ether_addr *)sc->sc_mac)); 1581 } 1582 } 1583 1584 /* 1585 * Virtqueue interrupt handlers 1586 */ 1587 /* ARGSUSED */ 1588 uint_t 1589 vioif_rx_handler(caddr_t arg1, caddr_t arg2) 1590 { 1591 struct virtio_softc *vsc = (void *) arg1; 1592 struct vioif_softc *sc = __containerof(vsc, 1593 struct vioif_softc, sc_virtio); 1594 1595 /* 1596 * The return values of these functions are not needed but they make 1597 * debugging interrupts simpler because you can use them to detect when 1598 * stuff was processed and repopulated in this handler. 1599 */ 1600 (void) vioif_process_rx(sc); 1601 (void) vioif_populate_rx(sc, KM_NOSLEEP); 1602 1603 return (DDI_INTR_CLAIMED); 1604 } 1605 1606 /* ARGSUSED */ 1607 uint_t 1608 vioif_tx_handler(caddr_t arg1, caddr_t arg2) 1609 { 1610 struct virtio_softc *vsc = (void *)arg1; 1611 struct vioif_softc *sc = __containerof(vsc, 1612 struct vioif_softc, sc_virtio); 1613 1614 /* 1615 * The return value of this function is not needed but makes debugging 1616 * interrupts simpler because you can use it to detect if anything was 1617 * reclaimed in this handler. 1618 */ 1619 (void) vioif_reclaim_used_tx(sc); 1620 1621 return (DDI_INTR_CLAIMED); 1622 } 1623 1624 static int 1625 vioif_register_ints(struct vioif_softc *sc) 1626 { 1627 int ret; 1628 1629 struct virtio_int_handler vioif_vq_h[] = { 1630 { vioif_rx_handler }, 1631 { vioif_tx_handler }, 1632 { NULL } 1633 }; 1634 1635 ret = virtio_register_ints(&sc->sc_virtio, NULL, vioif_vq_h); 1636 1637 return (ret); 1638 } 1639 1640 1641 static void 1642 vioif_check_features(struct vioif_softc *sc) 1643 { 1644 if (vioif_has_feature(sc, VIRTIO_NET_F_CSUM)) { 1645 /* The GSO/GRO featured depend on CSUM, check them here. */ 1646 sc->sc_tx_csum = 1; 1647 sc->sc_rx_csum = 1; 1648 1649 if (!vioif_has_feature(sc, VIRTIO_NET_F_GUEST_CSUM)) { 1650 sc->sc_rx_csum = 0; 1651 } 1652 dev_err(sc->sc_dev, CE_NOTE, "!Csum enabled."); 1653 1654 if (vioif_has_feature(sc, VIRTIO_NET_F_HOST_TSO4)) { 1655 1656 sc->sc_tx_tso4 = 1; 1657 /* 1658 * We don't seem to have a way to ask the system 1659 * not to send us LSO packets with Explicit 1660 * Congestion Notification bit set, so we require 1661 * the device to support it in order to do 1662 * LSO. 1663 */ 1664 if (!vioif_has_feature(sc, VIRTIO_NET_F_HOST_ECN)) { 1665 dev_err(sc->sc_dev, CE_NOTE, 1666 "!TSO4 supported, but not ECN. " 1667 "Not using LSO."); 1668 sc->sc_tx_tso4 = 0; 1669 } else { 1670 dev_err(sc->sc_dev, CE_NOTE, "!LSO enabled"); 1671 } 1672 } 1673 } 1674 } 1675 1676 static int 1677 vioif_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 1678 { 1679 int ret, instance; 1680 struct vioif_softc *sc; 1681 struct virtio_softc *vsc; 1682 mac_register_t *macp; 1683 char cache_name[CACHE_NAME_SIZE]; 1684 1685 instance = ddi_get_instance(devinfo); 1686 1687 switch (cmd) { 1688 case DDI_ATTACH: 1689 break; 1690 1691 case DDI_RESUME: 1692 case DDI_PM_RESUME: 1693 /* We do not support suspend/resume for vioif. */ 1694 goto exit; 1695 1696 default: 1697 goto exit; 1698 } 1699 1700 sc = kmem_zalloc(sizeof (struct vioif_softc), KM_SLEEP); 1701 ddi_set_driver_private(devinfo, sc); 1702 1703 vsc = &sc->sc_virtio; 1704 1705 /* Duplicate for less typing */ 1706 sc->sc_dev = devinfo; 1707 vsc->sc_dev = devinfo; 1708 1709 /* 1710 * Initialize interrupt kstat. 1711 */ 1712 sc->sc_intrstat = kstat_create("vioif", instance, "intr", "controller", 1713 KSTAT_TYPE_INTR, 1, 0); 1714 if (sc->sc_intrstat == NULL) { 1715 dev_err(devinfo, CE_WARN, "kstat_create failed"); 1716 goto exit_intrstat; 1717 } 1718 kstat_install(sc->sc_intrstat); 1719 1720 /* map BAR 0 */ 1721 ret = ddi_regs_map_setup(devinfo, 1, 1722 (caddr_t *)&sc->sc_virtio.sc_io_addr, 1723 0, 0, &vioif_attr, &sc->sc_virtio.sc_ioh); 1724 if (ret != DDI_SUCCESS) { 1725 dev_err(devinfo, CE_WARN, "unable to map bar 0: %d", ret); 1726 goto exit_map; 1727 } 1728 1729 virtio_device_reset(&sc->sc_virtio); 1730 virtio_set_status(&sc->sc_virtio, VIRTIO_CONFIG_DEVICE_STATUS_ACK); 1731 virtio_set_status(&sc->sc_virtio, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER); 1732 1733 ret = vioif_dev_features(sc); 1734 if (ret) 1735 goto exit_features; 1736 1737 vsc->sc_nvqs = vioif_has_feature(sc, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2; 1738 1739 (void) snprintf(cache_name, CACHE_NAME_SIZE, "vioif%d_rx", instance); 1740 sc->sc_rxbuf_cache = kmem_cache_create(cache_name, 1741 sizeof (struct vioif_rx_buf), 0, vioif_rx_construct, 1742 vioif_rx_destruct, NULL, sc, NULL, KM_SLEEP); 1743 if (sc->sc_rxbuf_cache == NULL) { 1744 dev_err(sc->sc_dev, CE_WARN, "Can't allocate the buffer cache"); 1745 goto exit_cache; 1746 } 1747 1748 ret = vioif_register_ints(sc); 1749 if (ret) { 1750 dev_err(sc->sc_dev, CE_WARN, 1751 "Failed to allocate interrupt(s)!"); 1752 goto exit_ints; 1753 } 1754 1755 /* 1756 * Register layout determined, can now access the 1757 * device-specific bits 1758 */ 1759 vioif_get_mac(sc); 1760 1761 sc->sc_rx_vq = virtio_alloc_vq(&sc->sc_virtio, 0, 1762 VIOIF_RX_QLEN, VIOIF_INDIRECT_MAX, "rx"); 1763 if (!sc->sc_rx_vq) 1764 goto exit_alloc1; 1765 virtio_stop_vq_intr(sc->sc_rx_vq); 1766 1767 sc->sc_tx_vq = virtio_alloc_vq(&sc->sc_virtio, 1, 1768 VIOIF_TX_QLEN, VIOIF_INDIRECT_MAX, "tx"); 1769 if (!sc->sc_tx_vq) 1770 goto exit_alloc2; 1771 virtio_stop_vq_intr(sc->sc_tx_vq); 1772 1773 if (vioif_has_feature(sc, VIRTIO_NET_F_CTRL_VQ)) { 1774 sc->sc_ctrl_vq = virtio_alloc_vq(&sc->sc_virtio, 2, 1775 VIOIF_CTRL_QLEN, 0, "ctrl"); 1776 if (!sc->sc_ctrl_vq) { 1777 goto exit_alloc3; 1778 } 1779 virtio_stop_vq_intr(sc->sc_ctrl_vq); 1780 } 1781 1782 virtio_set_status(&sc->sc_virtio, 1783 VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK); 1784 1785 sc->sc_rxloan = 0; 1786 1787 /* set some reasonable-small default values */ 1788 sc->sc_rxcopy_thresh = 300; 1789 sc->sc_txcopy_thresh = 300; 1790 sc->sc_mtu = ETHERMTU; 1791 1792 vioif_check_features(sc); 1793 1794 if (vioif_alloc_mems(sc) != 0) 1795 goto exit_alloc_mems; 1796 1797 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 1798 dev_err(devinfo, CE_WARN, "Failed to allocate a mac_register"); 1799 goto exit_macalloc; 1800 } 1801 1802 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 1803 macp->m_driver = sc; 1804 macp->m_dip = devinfo; 1805 macp->m_src_addr = sc->sc_mac; 1806 macp->m_callbacks = &vioif_m_callbacks; 1807 macp->m_min_sdu = 0; 1808 macp->m_max_sdu = sc->sc_mtu; 1809 macp->m_margin = VLAN_TAGSZ; 1810 macp->m_priv_props = vioif_priv_props; 1811 1812 sc->sc_macp = macp; 1813 1814 /* Pre-fill the rx ring. */ 1815 (void) vioif_populate_rx(sc, KM_SLEEP); 1816 1817 ret = mac_register(macp, &sc->sc_mac_handle); 1818 if (ret != 0) { 1819 dev_err(devinfo, CE_WARN, "vioif_attach: " 1820 "mac_register() failed, ret=%d", ret); 1821 goto exit_register; 1822 } 1823 1824 ret = virtio_enable_ints(&sc->sc_virtio); 1825 if (ret) { 1826 dev_err(devinfo, CE_WARN, "Failed to enable interrupts"); 1827 goto exit_enable_ints; 1828 } 1829 1830 mac_link_update(sc->sc_mac_handle, LINK_STATE_UP); 1831 return (DDI_SUCCESS); 1832 1833 exit_enable_ints: 1834 (void) mac_unregister(sc->sc_mac_handle); 1835 exit_register: 1836 mac_free(macp); 1837 exit_macalloc: 1838 vioif_free_mems(sc); 1839 exit_alloc_mems: 1840 virtio_release_ints(&sc->sc_virtio); 1841 if (sc->sc_ctrl_vq) 1842 virtio_free_vq(sc->sc_ctrl_vq); 1843 exit_alloc3: 1844 virtio_free_vq(sc->sc_tx_vq); 1845 exit_alloc2: 1846 virtio_free_vq(sc->sc_rx_vq); 1847 exit_alloc1: 1848 exit_ints: 1849 kmem_cache_destroy(sc->sc_rxbuf_cache); 1850 exit_cache: 1851 exit_features: 1852 virtio_set_status(&sc->sc_virtio, VIRTIO_CONFIG_DEVICE_STATUS_FAILED); 1853 ddi_regs_map_free(&sc->sc_virtio.sc_ioh); 1854 exit_intrstat: 1855 exit_map: 1856 kstat_delete(sc->sc_intrstat); 1857 kmem_free(sc, sizeof (struct vioif_softc)); 1858 exit: 1859 return (DDI_FAILURE); 1860 } 1861 1862 static int 1863 vioif_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 1864 { 1865 struct vioif_softc *sc; 1866 1867 if ((sc = ddi_get_driver_private(devinfo)) == NULL) 1868 return (DDI_FAILURE); 1869 1870 switch (cmd) { 1871 case DDI_DETACH: 1872 break; 1873 1874 case DDI_PM_SUSPEND: 1875 /* We do not support suspend/resume for vioif. */ 1876 return (DDI_FAILURE); 1877 1878 default: 1879 return (DDI_FAILURE); 1880 } 1881 1882 if (sc->sc_rxloan > 0) { 1883 dev_err(devinfo, CE_WARN, "!Some rx buffers are still upstream," 1884 " not detaching."); 1885 return (DDI_FAILURE); 1886 } 1887 1888 virtio_stop_vq_intr(sc->sc_rx_vq); 1889 virtio_stop_vq_intr(sc->sc_tx_vq); 1890 1891 virtio_release_ints(&sc->sc_virtio); 1892 1893 if (mac_unregister(sc->sc_mac_handle)) { 1894 return (DDI_FAILURE); 1895 } 1896 1897 mac_free(sc->sc_macp); 1898 1899 vioif_free_mems(sc); 1900 virtio_free_vq(sc->sc_rx_vq); 1901 virtio_free_vq(sc->sc_tx_vq); 1902 1903 virtio_device_reset(&sc->sc_virtio); 1904 1905 ddi_regs_map_free(&sc->sc_virtio.sc_ioh); 1906 1907 kmem_cache_destroy(sc->sc_rxbuf_cache); 1908 kstat_delete(sc->sc_intrstat); 1909 kmem_free(sc, sizeof (struct vioif_softc)); 1910 1911 return (DDI_SUCCESS); 1912 } 1913 1914 static int 1915 vioif_quiesce(dev_info_t *devinfo) 1916 { 1917 struct vioif_softc *sc; 1918 1919 if ((sc = ddi_get_driver_private(devinfo)) == NULL) 1920 return (DDI_FAILURE); 1921 1922 virtio_stop_vq_intr(sc->sc_rx_vq); 1923 virtio_stop_vq_intr(sc->sc_tx_vq); 1924 virtio_device_reset(&sc->sc_virtio); 1925 1926 return (DDI_SUCCESS); 1927 } 1928 1929 int 1930 _init(void) 1931 { 1932 int ret = 0; 1933 1934 mac_init_ops(&vioif_ops, "vioif"); 1935 1936 ret = mod_install(&modlinkage); 1937 if (ret != DDI_SUCCESS) { 1938 mac_fini_ops(&vioif_ops); 1939 return (ret); 1940 } 1941 1942 return (0); 1943 } 1944 1945 int 1946 _fini(void) 1947 { 1948 int ret; 1949 1950 ret = mod_remove(&modlinkage); 1951 if (ret == DDI_SUCCESS) { 1952 mac_fini_ops(&vioif_ops); 1953 } 1954 1955 return (ret); 1956 } 1957 1958 int 1959 _info(struct modinfo *pModinfo) 1960 { 1961 return (mod_info(&modlinkage, pModinfo)); 1962 } 1963