Lines 52-58
Link Here
|
52 |
na->tx_rings[idx]->nr_mode == NKR_NETMAP_ON); |
52 |
na->tx_rings[idx]->nr_mode == NKR_NETMAP_ON); |
53 |
} |
53 |
} |
54 |
|
54 |
|
|
|
55 |
/* Free all the unused buffer in all the RX virtqueues. |
56 |
* This function is called when entering and exiting netmap mode. |
57 |
* - buffers queued by the virtio driver return skbuf/mbuf pointer |
58 |
* and need to be freed; |
59 |
* - buffers queued by netmap return the txq/rxq, and do not need work |
60 |
*/ |
55 |
static void |
61 |
static void |
|
|
62 |
vtnet_netmap_free_bufs(struct vtnet_softc *sc) |
63 |
{ |
64 |
int i, nmb = 0, n = 0, last; |
65 |
|
66 |
for (i = 0; i < sc->vtnet_max_vq_pairs; i++) { |
67 |
struct vtnet_rxq *rxq = &sc->vtnet_rxqs[i]; |
68 |
struct vtnet_txq *txq = &sc->vtnet_txqs[i]; |
69 |
struct vtnet_tx_header *txhdr; |
70 |
struct virtqueue *vq; |
71 |
struct mbuf *m; |
72 |
|
73 |
last = 0; |
74 |
vq = rxq->vtnrx_vq; |
75 |
while ((m = virtqueue_drain(vq, &last)) != NULL) { |
76 |
n++; |
77 |
if (m != (void *)rxq) |
78 |
m_freem(m); |
79 |
else |
80 |
nmb++; |
81 |
} |
82 |
|
83 |
last = 0; |
84 |
vq = txq->vtntx_vq; |
85 |
while ((txhdr = virtqueue_drain(vq, &last)) != NULL) { |
86 |
n++; |
87 |
if (txhdr != (void *)txq) { |
88 |
m_freem(txhdr->vth_mbuf); |
89 |
uma_zfree(vtnet_tx_header_zone, txhdr); |
90 |
} else |
91 |
nmb++; |
92 |
} |
93 |
} |
94 |
D("freed %d mbufs, %d netmap bufs on %d queues", |
95 |
n - nmb, nmb, i); |
96 |
} |
97 |
|
98 |
static void |
56 |
vtnet_free_used(struct virtqueue *vq, int netmap_bufs, enum txrx t, int idx) |
99 |
vtnet_free_used(struct virtqueue *vq, int netmap_bufs, enum txrx t, int idx) |
57 |
{ |
100 |
{ |
58 |
void *cookie; |
101 |
void *cookie; |
Lines 89-95
Link Here
|
89 |
{ |
132 |
{ |
90 |
struct ifnet *ifp = na->ifp; |
133 |
struct ifnet *ifp = na->ifp; |
91 |
struct vtnet_softc *sc = ifp->if_softc; |
134 |
struct vtnet_softc *sc = ifp->if_softc; |
92 |
int success; |
|
|
93 |
enum txrx t; |
135 |
enum txrx t; |
94 |
int i; |
136 |
int i; |
95 |
|
137 |
|
Lines 98-112
Link Here
|
98 |
vtnet_drain_taskqueues(sc); |
140 |
vtnet_drain_taskqueues(sc); |
99 |
|
141 |
|
100 |
VTNET_CORE_LOCK(sc); |
142 |
VTNET_CORE_LOCK(sc); |
101 |
|
|
|
102 |
/* We need nm_netmap_on() to return true when called by |
143 |
/* We need nm_netmap_on() to return true when called by |
103 |
* vtnet_init_locked() below. */ |
144 |
* vtnet_init_locked() below. */ |
104 |
if (state) |
145 |
/* enable or disable flags and callbacks in na and ifp */ |
|
|
146 |
if (state) { |
105 |
nm_set_native_flags(na); |
147 |
nm_set_native_flags(na); |
106 |
|
148 |
} else { |
|
|
149 |
nm_clear_native_flags(na); |
150 |
} |
107 |
/* We need to trigger a device reset in order to unexpose guest buffers |
151 |
/* We need to trigger a device reset in order to unexpose guest buffers |
108 |
* published to the host. */ |
152 |
* published to the host. */ |
109 |
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); |
153 |
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); |
|
|
154 |
|
155 |
/* drain queues so netmap and native drivers |
156 |
* do not interfere with each other |
157 |
*/ |
158 |
// vtnet_netmap_free_bufs(sc); |
110 |
/* Get pending used buffers. The way they are freed depends on whether |
159 |
/* Get pending used buffers. The way they are freed depends on whether |
111 |
* they are netmap buffer or they are mbufs. We can tell apart the two |
160 |
* they are netmap buffer or they are mbufs. We can tell apart the two |
112 |
* cases by looking at kring->nr_mode, before this is possibly updated |
161 |
* cases by looking at kring->nr_mode, before this is possibly updated |
Lines 128-136
Link Here
|
128 |
kring->nr_mode == NKR_NETMAP_ON, NR_RX, i); |
177 |
kring->nr_mode == NKR_NETMAP_ON, NR_RX, i); |
129 |
VTNET_RXQ_UNLOCK(rxq); |
178 |
VTNET_RXQ_UNLOCK(rxq); |
130 |
} |
179 |
} |
131 |
vtnet_init_locked(sc); |
180 |
vtnet_init_locked(sc); /* also enable intr */ |
132 |
success = (ifp->if_drv_flags & IFF_DRV_RUNNING) ? 0 : ENXIO; |
|
|
133 |
|
134 |
if (state) { |
181 |
if (state) { |
135 |
for_rx_tx(t) { |
182 |
for_rx_tx(t) { |
136 |
/* Hardware rings. */ |
183 |
/* Hardware rings. */ |
Lines 173-180
Link Here
|
173 |
} |
220 |
} |
174 |
|
221 |
|
175 |
VTNET_CORE_UNLOCK(sc); |
222 |
VTNET_CORE_UNLOCK(sc); |
176 |
|
223 |
return (ifp->if_drv_flags & IFF_DRV_RUNNING) ? 0 : ENXIO; |
177 |
return success; |
|
|
178 |
} |
224 |
} |
179 |
|
225 |
|
180 |
|
226 |
|
Lines 187-192
Link Here
|
187 |
struct netmap_ring *ring = kring->ring; |
233 |
struct netmap_ring *ring = kring->ring; |
188 |
u_int ring_nr = kring->ring_id; |
234 |
u_int ring_nr = kring->ring_id; |
189 |
u_int nm_i; /* index into the netmap ring */ |
235 |
u_int nm_i; /* index into the netmap ring */ |
|
|
236 |
// u_int nic_i; /* index into the NIC ring */ |
190 |
u_int const lim = kring->nkr_num_slots - 1; |
237 |
u_int const lim = kring->nkr_num_slots - 1; |
191 |
u_int const head = kring->rhead; |
238 |
u_int const head = kring->rhead; |
192 |
|
239 |
|
Lines 206-211
Link Here
|
206 |
if (nm_i != head) { /* we have new packets to send */ |
253 |
if (nm_i != head) { /* we have new packets to send */ |
207 |
struct sglist *sg = txq->vtntx_sg; |
254 |
struct sglist *sg = txq->vtntx_sg; |
208 |
|
255 |
|
|
|
256 |
// nic_i = netmap_idx_k2n(kring, nm_i); |
209 |
for (; nm_i != head; nm_i = nm_next(nm_i, lim)) { |
257 |
for (; nm_i != head; nm_i = nm_next(nm_i, lim)) { |
210 |
/* we use an empty header here */ |
258 |
/* we use an empty header here */ |
211 |
struct netmap_slot *slot = &ring->slot[nm_i]; |
259 |
struct netmap_slot *slot = &ring->slot[nm_i]; |
Lines 221-269
Link Here
|
221 |
* and kick the hypervisor (if necessary). |
269 |
* and kick the hypervisor (if necessary). |
222 |
*/ |
270 |
*/ |
223 |
sglist_reset(sg); // cheap |
271 |
sglist_reset(sg); // cheap |
|
|
272 |
// if vtnet_hdr_size > 0 ... |
224 |
err = sglist_append(sg, &txq->vtntx_shrhdr, sc->vtnet_hdr_size); |
273 |
err = sglist_append(sg, &txq->vtntx_shrhdr, sc->vtnet_hdr_size); |
|
|
274 |
// XXX later, support multi segment |
275 |
// err = sglist_append_phys(sg, paddr, len); |
225 |
err |= sglist_append_phys(sg, paddr, len); |
276 |
err |= sglist_append_phys(sg, paddr, len); |
226 |
KASSERT(err == 0, ("%s: cannot append to sglist %d", |
277 |
KASSERT(err == 0, ("%s: cannot append to sglist %d", |
227 |
__func__, err)); |
278 |
__func__, err)); |
228 |
err = virtqueue_enqueue(vq, /*cookie=*/txq, sg, |
279 |
err = virtqueue_enqueue(vq, /*cookie=*/txq, sg, |
229 |
/*readable=*/sg->sg_nseg, |
280 |
/*readable=*/sg->sg_nseg, |
230 |
/*writeable=*/0); |
281 |
/*writeable=*/0); |
|
|
282 |
/* use na as the cookie */ |
283 |
err = virtqueue_enqueue(vq, txq, sg, sg->sg_nseg, 0); |
231 |
if (unlikely(err)) { |
284 |
if (unlikely(err)) { |
232 |
if (err != ENOSPC) |
285 |
if (err != ENOSPC) |
233 |
nm_prerr("virtqueue_enqueue(%s) failed: %d\n", |
286 |
nm_prerr("virtqueue_enqueue(%s) failed: %d\n", |
234 |
kring->name, err); |
287 |
kring->name, err); |
235 |
break; |
288 |
break; |
236 |
} |
289 |
} |
|
|
290 |
// nic_i = nm_next(nic_i, lim); |
237 |
} |
291 |
} |
238 |
|
292 |
|
|
|
293 |
/* No more free TX slots? Ask the hypervisor for notifications, |
294 |
* possibly only when a considerable amount of work has been |
295 |
* done. |
296 |
*/ |
297 |
ND(3,"sent %d packets, hwcur %d", n, nm_i); |
298 |
// virtqueue_disable_intr(vq); // ?? |
239 |
virtqueue_notify(vq); |
299 |
virtqueue_notify(vq); |
240 |
|
300 |
|
241 |
/* Update hwcur depending on where we stopped. */ |
301 |
/* Update hwcur depending on where we stopped. */ |
242 |
kring->nr_hwcur = nm_i; /* note we migth break early */ |
302 |
kring->nr_hwcur = nm_i; /* note we migth break early */ |
|
|
303 |
|
304 |
} else { |
305 |
if (ring->head != ring->tail) |
306 |
ND(5, "pure notify ? head %d tail %d nused %d %d", |
307 |
ring->head, ring->tail, virtqueue_nused(vq), |
308 |
(virtqueue_dump(vq), 1)); |
309 |
virtqueue_notify(vq); |
310 |
if (interrupts) { |
311 |
virtqueue_enable_intr(vq); // like postpone with 0 |
312 |
} |
243 |
} |
313 |
} |
244 |
|
314 |
|
245 |
/* Free used slots. We only consider our own used buffers, recognized |
315 |
/* Free used slots. We only consider our own used buffers, recognized |
246 |
* by the token we passed to virtqueue_enqueue. |
316 |
* by the token we passed to virtqueue_add_outbuf. |
247 |
*/ |
317 |
*/ |
248 |
n = 0; |
318 |
n = 0; |
249 |
for (;;) { |
319 |
for (;;) { |
250 |
void *token = virtqueue_dequeue(vq, NULL); |
320 |
struct vtnet_tx_header *txhdr = virtqueue_dequeue(vq, NULL); |
251 |
if (token == NULL) |
321 |
if (txhdr == NULL) |
252 |
break; |
322 |
break; |
253 |
if (unlikely(token != (void *)txq)) |
323 |
if (likely(txhdr == (void *)txq)) { |
254 |
nm_prerr("BUG: TX token mismatch\n"); |
|
|
255 |
else |
256 |
n++; |
324 |
n++; |
|
|
325 |
if (virtqueue_nused(vq) < 32) { // XXX slow release |
326 |
break; |
327 |
} |
328 |
} else { /* leftover from previous transmission */ |
329 |
nm_prerr("BUG: TX token mismatch\n"); |
330 |
m_freem(txhdr->vth_mbuf); |
331 |
uma_zfree(vtnet_tx_header_zone, txhdr); |
332 |
} |
257 |
} |
333 |
} |
258 |
if (n > 0) { |
334 |
if (n) { |
259 |
kring->nr_hwtail += n; |
335 |
kring->nr_hwtail += n; |
260 |
if (kring->nr_hwtail > lim) |
336 |
if (kring->nr_hwtail > lim) |
261 |
kring->nr_hwtail -= lim + 1; |
337 |
kring->nr_hwtail -= lim + 1; |
262 |
} |
338 |
} |
|
|
339 |
if (nm_i != kring->nr_hwtail /* && vtnet_txq_below_threshold(txq) == 0*/) { |
340 |
ND(3, "disable intr, hwcur %d", nm_i); |
341 |
virtqueue_disable_intr(vq); |
342 |
} else if (interrupts && virtqueue_nfree(vq) < 32) { |
343 |
ND(3, "enable intr, hwcur %d", nm_i); |
344 |
virtqueue_postpone_intr(vq, VQ_POSTPONE_SHORT); |
345 |
} |
263 |
|
346 |
|
264 |
if (interrupts && virtqueue_nfree(vq) < 32) |
|
|
265 |
virtqueue_postpone_intr(vq, VQ_POSTPONE_LONG); |
266 |
|
267 |
return 0; |
347 |
return 0; |
268 |
} |
348 |
} |
269 |
|
349 |
|
Lines 289-295
Link Here
|
289 |
struct netmap_slot *slot = &ring->slot[nm_i]; |
369 |
struct netmap_slot *slot = &ring->slot[nm_i]; |
290 |
uint64_t paddr; |
370 |
uint64_t paddr; |
291 |
void *addr = PNMB(na, slot, &paddr); |
371 |
void *addr = PNMB(na, slot, &paddr); |
292 |
int err; |
372 |
int err = 0; |
293 |
|
373 |
|
294 |
if (addr == NETMAP_BUF_BASE(na)) { /* bad buf */ |
374 |
if (addr == NETMAP_BUF_BASE(na)) { /* bad buf */ |
295 |
if (netmap_ring_reinit(kring)) |
375 |
if (netmap_ring_reinit(kring)) |
Lines 297-318
Link Here
|
297 |
} |
377 |
} |
298 |
|
378 |
|
299 |
slot->flags &= ~NS_BUF_CHANGED; |
379 |
slot->flags &= ~NS_BUF_CHANGED; |
300 |
sglist_reset(&sg); |
380 |
sglist_reset(&sg); // cheap |
301 |
err = sglist_append(&sg, &rxq->vtnrx_shrhdr, sc->vtnet_hdr_size); |
381 |
err = sglist_append(&sg, &rxq->vtnrx_shrhdr, sc->vtnet_hdr_size); |
|
|
382 |
// err = sglist_append_phys(&sg, paddr, NETMAP_BUF_SIZE(na)); |
302 |
err |= sglist_append_phys(&sg, paddr, NETMAP_BUF_SIZE(na)); |
383 |
err |= sglist_append_phys(&sg, paddr, NETMAP_BUF_SIZE(na)); |
303 |
KASSERT(err == 0, ("%s: cannot append to sglist %d", |
|
|
304 |
__func__, err)); |
305 |
/* writable for the host */ |
384 |
/* writable for the host */ |
306 |
err = virtqueue_enqueue(vq, /*cookie=*/rxq, &sg, |
385 |
err = virtqueue_enqueue(vq, /*cookie=*/rxq, &sg, |
307 |
/*readable=*/0, /*writeable=*/sg.sg_nseg); |
386 |
/*readable=*/0, /*writeable=*/sg.sg_nseg); |
|
|
387 |
KASSERT(err == 0, ("%s: cannot append to sglist %d", |
388 |
__func__, err)); |
389 |
|
308 |
if (unlikely(err)) { |
390 |
if (unlikely(err)) { |
309 |
if (err != ENOSPC) |
391 |
if (err != ENOSPC) |
310 |
nm_prerr("virtqueue_enqueue(%s) failed: %d\n", |
392 |
nm_prerr("virtqueue_enqueue(%s) failed: %d\n", |
311 |
kring->name, err); |
393 |
kring->name, err); |
312 |
break; |
394 |
break; |
313 |
} |
395 |
} |
|
|
396 |
nm_i = nm_next(nm_i, lim); |
314 |
} |
397 |
} |
315 |
|
|
|
316 |
return nm_i; |
398 |
return nm_i; |
317 |
} |
399 |
} |
318 |
|
400 |
|
Lines 357-364
Link Here
|
357 |
u_int nm_i; /* index into the netmap ring */ |
439 |
u_int nm_i; /* index into the netmap ring */ |
358 |
u_int const lim = kring->nkr_num_slots - 1; |
440 |
u_int const lim = kring->nkr_num_slots - 1; |
359 |
u_int const head = kring->rhead; |
441 |
u_int const head = kring->rhead; |
360 |
int force_update = (flags & NAF_FORCE_READ) || |
442 |
int force_update = (flags & NAF_FORCE_READ) || (kring->nr_kflags & NKR_PENDINTR); |
361 |
(kring->nr_kflags & NKR_PENDINTR); |
|
|
362 |
int interrupts = !(kring->nr_kflags & NKR_NOINTR); |
443 |
int interrupts = !(kring->nr_kflags & NKR_NOINTR); |
363 |
|
444 |
|
364 |
/* device-specific */ |
445 |
/* device-specific */ |
Lines 366-381
Link Here
|
366 |
struct vtnet_rxq *rxq = &sc->vtnet_rxqs[ring_nr]; |
447 |
struct vtnet_rxq *rxq = &sc->vtnet_rxqs[ring_nr]; |
367 |
struct virtqueue *vq = rxq->vtnrx_vq; |
448 |
struct virtqueue *vq = rxq->vtnrx_vq; |
368 |
|
449 |
|
|
|
450 |
/* XXX netif_carrier_ok ? */ |
451 |
|
452 |
// if (head > lim) |
453 |
// return netmap_ring_reinit(kring); |
454 |
|
369 |
rmb(); |
455 |
rmb(); |
370 |
/* |
456 |
/* |
371 |
* First part: import newly received packets. |
457 |
* First part: import newly received packets. |
372 |
* Only accept our own buffers (matching the token). We should only get |
458 |
* Only accept our own buffers (matching the token). We should only get |
373 |
* matching buffers. We may need to stop early to avoid hwtail to overrun |
459 |
* matching buffers, because of vtnet_netmap_free_rx_unused_bufs() |
374 |
* hwcur. |
460 |
* and vtnet_netmap_init_buffers(). We may need to stop early to avoid |
|
|
461 |
* hwtail to overrun hwcur. |
375 |
*/ |
462 |
*/ |
376 |
if (netmap_no_pendintr || force_update) { |
463 |
if (netmap_no_pendintr || force_update) { |
377 |
uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim); |
464 |
uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim); |
378 |
void *token; |
465 |
struct netmap_adapter *token; |
379 |
|
466 |
|
380 |
vtnet_rxq_disable_intr(rxq); |
467 |
vtnet_rxq_disable_intr(rxq); |
381 |
|
468 |
|
Lines 408-431
Link Here
|
408 |
kring->nr_hwtail = nm_i; |
495 |
kring->nr_hwtail = nm_i; |
409 |
kring->nr_kflags &= ~NKR_PENDINTR; |
496 |
kring->nr_kflags &= ~NKR_PENDINTR; |
410 |
} |
497 |
} |
411 |
ND("[B] h %d c %d hwcur %d hwtail %d", ring->head, ring->cur, |
498 |
ND("[B] h %d c %d hwcur %d hwtail %d", |
412 |
kring->nr_hwcur, kring->nr_hwtail); |
499 |
ring->head, ring->cur, kring->nr_hwcur, |
|
|
500 |
kring->nr_hwtail); |
413 |
|
501 |
|
414 |
/* |
502 |
/* |
415 |
* Second part: skip past packets that userspace has released. |
503 |
* Second part: skip past packets that userspace has released. |
416 |
*/ |
504 |
*/ |
417 |
nm_i = kring->nr_hwcur; /* netmap ring index */ |
505 |
nm_i = kring->nr_hwcur; /* netmap ring index */ |
418 |
if (nm_i != head) { |
506 |
if (nm_i != head) { |
419 |
int nm_j = vtnet_netmap_kring_refill(kring, nm_i, head); |
507 |
int err = vtnet_netmap_kring_refill(kring, nm_i, head); |
420 |
if (nm_j < 0) |
508 |
if (err < 0) |
421 |
return nm_j; |
509 |
return 1; |
422 |
kring->nr_hwcur = nm_j; |
510 |
kring->nr_hwcur = err; |
423 |
virtqueue_notify(vq); |
511 |
virtqueue_notify(vq); |
|
|
512 |
/* After draining the queue may need an intr from the hypervisor */ |
513 |
if (interrupts) { |
514 |
vtnet_rxq_enable_intr(rxq); |
515 |
} |
424 |
} |
516 |
} |
|
|
517 |
ND("[C] h %d c %d t %d hwcur %d hwtail %d", |
518 |
ring->head, ring->cur, ring->tail, |
519 |
kring->nr_hwcur, kring->nr_hwtail); |
425 |
|
520 |
|
426 |
ND("[C] h %d c %d t %d hwcur %d hwtail %d", ring->head, ring->cur, |
|
|
427 |
ring->tail, kring->nr_hwcur, kring->nr_hwtail); |
428 |
|
429 |
return 0; |
521 |
return 0; |
430 |
} |
522 |
} |
431 |
|
523 |
|
Lines 452-458
Link Here
|
452 |
} |
544 |
} |
453 |
} |
545 |
} |
454 |
|
546 |
|
|
|
547 |
/* Make RX virtqueues buffers pointing to netmap buffers. */ |
455 |
static int |
548 |
static int |
|
|
549 |
vtnet_netmap_init_rx_buffers(struct vtnet_softc *sc) |
550 |
{ |
551 |
struct ifnet *ifp = sc->vtnet_ifp; |
552 |
struct netmap_adapter* na = NA(ifp); |
553 |
unsigned int r; |
554 |
|
555 |
if (!nm_native_on(na)) |
556 |
return 0; |
557 |
for (r = 0; r < na->num_rx_rings; r++) { |
558 |
struct netmap_kring *kring = na->rx_rings[r]; |
559 |
struct vtnet_rxq *rxq = &sc->vtnet_rxqs[r]; |
560 |
struct virtqueue *vq = rxq->vtnrx_vq; |
561 |
struct netmap_slot* slot; |
562 |
int err = 0; |
563 |
|
564 |
slot = netmap_reset(na, NR_RX, r, 0); |
565 |
if (!slot) { |
566 |
D("strange, null netmap ring %d", r); |
567 |
return 0; |
568 |
} |
569 |
/* Add up to na>-num_rx_desc-1 buffers to this RX virtqueue. |
570 |
* It's important to leave one virtqueue slot free, otherwise |
571 |
* we can run into ring->cur/ring->tail wraparounds. |
572 |
*/ |
573 |
err = vtnet_netmap_kring_refill(kring, 0, na->num_rx_desc-1); |
574 |
if (err < 0) |
575 |
return 0; |
576 |
virtqueue_notify(vq); |
577 |
} |
578 |
|
579 |
return 1; |
580 |
} |
581 |
|
582 |
static int |
456 |
vtnet_netmap_tx_slots(struct vtnet_softc *sc) |
583 |
vtnet_netmap_tx_slots(struct vtnet_softc *sc) |
457 |
{ |
584 |
{ |
458 |
int div; |
585 |
int div; |
Lines 521-540
Link Here
|
521 |
|
648 |
|
522 |
na.ifp = sc->vtnet_ifp; |
649 |
na.ifp = sc->vtnet_ifp; |
523 |
na.na_flags = 0; |
650 |
na.na_flags = 0; |
|
|
651 |
// na.num_tx_desc = 1024;// sc->vtnet_rx_nmbufs; |
524 |
na.num_tx_desc = vtnet_netmap_tx_slots(sc); |
652 |
na.num_tx_desc = vtnet_netmap_tx_slots(sc); |
|
|
653 |
// na.num_rx_desc = 1024; // sc->vtnet_rx_nmbufs; |
525 |
na.num_rx_desc = vtnet_netmap_rx_slots(sc); |
654 |
na.num_rx_desc = vtnet_netmap_rx_slots(sc); |
526 |
na.num_tx_rings = na.num_rx_rings = sc->vtnet_max_vq_pairs; |
|
|
527 |
na.rx_buf_maxsize = 0; |
655 |
na.rx_buf_maxsize = 0; |
528 |
na.nm_register = vtnet_netmap_reg; |
656 |
na.nm_register = vtnet_netmap_reg; |
529 |
na.nm_txsync = vtnet_netmap_txsync; |
657 |
na.nm_txsync = vtnet_netmap_txsync; |
530 |
na.nm_rxsync = vtnet_netmap_rxsync; |
658 |
na.nm_rxsync = vtnet_netmap_rxsync; |
531 |
na.nm_intr = vtnet_netmap_intr; |
659 |
na.nm_intr = vtnet_netmap_intr; |
|
|
660 |
na.num_tx_rings = na.num_rx_rings = sc->vtnet_max_vq_pairs; |
532 |
na.nm_config = vtnet_netmap_config; |
661 |
na.nm_config = vtnet_netmap_config; |
|
|
662 |
D("max rings %d", sc->vtnet_max_vq_pairs); |
533 |
|
663 |
|
534 |
netmap_attach(&na); |
|
|
535 |
|
536 |
nm_prinf("vtnet attached txq=%d, txd=%d rxq=%d, rxd=%d\n", |
664 |
nm_prinf("vtnet attached txq=%d, txd=%d rxq=%d, rxd=%d\n", |
537 |
na.num_tx_rings, na.num_tx_desc, |
665 |
na.num_tx_rings, na.num_tx_desc, |
538 |
na.num_tx_rings, na.num_rx_desc); |
666 |
na.num_tx_rings, na.num_rx_desc); |
|
|
667 |
|
668 |
netmap_attach(&na); |
539 |
} |
669 |
} |
540 |
/* end of file */ |
670 |
/* end of file */ |