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