diff options
Diffstat (limited to 'drivers/net/sfc/tx.c')
-rw-r--r-- | drivers/net/sfc/tx.c | 92 |
1 files changed, 88 insertions, 4 deletions
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 2f5e9da657b..13980190821 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /**************************************************************************** | 1 | /**************************************************************************** |
2 | * Driver for Solarflare Solarstorm network controllers and boards | 2 | * Driver for Solarflare Solarstorm network controllers and boards |
3 | * Copyright 2005-2006 Fen Systems Ltd. | 3 | * Copyright 2005-2006 Fen Systems Ltd. |
4 | * Copyright 2005-2009 Solarflare Communications Inc. | 4 | * Copyright 2005-2010 Solarflare Communications Inc. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License version 2 as published | 7 | * under the terms of the GNU General Public License version 2 as published |
@@ -336,17 +336,91 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, | |||
336 | { | 336 | { |
337 | struct efx_nic *efx = netdev_priv(net_dev); | 337 | struct efx_nic *efx = netdev_priv(net_dev); |
338 | struct efx_tx_queue *tx_queue; | 338 | struct efx_tx_queue *tx_queue; |
339 | unsigned index, type; | ||
339 | 340 | ||
340 | if (unlikely(efx->port_inhibited)) | 341 | if (unlikely(efx->port_inhibited)) |
341 | return NETDEV_TX_BUSY; | 342 | return NETDEV_TX_BUSY; |
342 | 343 | ||
343 | tx_queue = efx_get_tx_queue(efx, skb_get_queue_mapping(skb), | 344 | index = skb_get_queue_mapping(skb); |
344 | skb->ip_summed == CHECKSUM_PARTIAL ? | 345 | type = skb->ip_summed == CHECKSUM_PARTIAL ? EFX_TXQ_TYPE_OFFLOAD : 0; |
345 | EFX_TXQ_TYPE_OFFLOAD : 0); | 346 | if (index >= efx->n_tx_channels) { |
347 | index -= efx->n_tx_channels; | ||
348 | type |= EFX_TXQ_TYPE_HIGHPRI; | ||
349 | } | ||
350 | tx_queue = efx_get_tx_queue(efx, index, type); | ||
346 | 351 | ||
347 | return efx_enqueue_skb(tx_queue, skb); | 352 | return efx_enqueue_skb(tx_queue, skb); |
348 | } | 353 | } |
349 | 354 | ||
355 | void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue) | ||
356 | { | ||
357 | struct efx_nic *efx = tx_queue->efx; | ||
358 | |||
359 | /* Must be inverse of queue lookup in efx_hard_start_xmit() */ | ||
360 | tx_queue->core_txq = | ||
361 | netdev_get_tx_queue(efx->net_dev, | ||
362 | tx_queue->queue / EFX_TXQ_TYPES + | ||
363 | ((tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI) ? | ||
364 | efx->n_tx_channels : 0)); | ||
365 | } | ||
366 | |||
367 | int efx_setup_tc(struct net_device *net_dev, u8 num_tc) | ||
368 | { | ||
369 | struct efx_nic *efx = netdev_priv(net_dev); | ||
370 | struct efx_channel *channel; | ||
371 | struct efx_tx_queue *tx_queue; | ||
372 | unsigned tc; | ||
373 | int rc; | ||
374 | |||
375 | if (efx_nic_rev(efx) < EFX_REV_FALCON_B0 || num_tc > EFX_MAX_TX_TC) | ||
376 | return -EINVAL; | ||
377 | |||
378 | if (num_tc == net_dev->num_tc) | ||
379 | return 0; | ||
380 | |||
381 | for (tc = 0; tc < num_tc; tc++) { | ||
382 | net_dev->tc_to_txq[tc].offset = tc * efx->n_tx_channels; | ||
383 | net_dev->tc_to_txq[tc].count = efx->n_tx_channels; | ||
384 | } | ||
385 | |||
386 | if (num_tc > net_dev->num_tc) { | ||
387 | /* Initialise high-priority queues as necessary */ | ||
388 | efx_for_each_channel(channel, efx) { | ||
389 | efx_for_each_possible_channel_tx_queue(tx_queue, | ||
390 | channel) { | ||
391 | if (!(tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI)) | ||
392 | continue; | ||
393 | if (!tx_queue->buffer) { | ||
394 | rc = efx_probe_tx_queue(tx_queue); | ||
395 | if (rc) | ||
396 | return rc; | ||
397 | } | ||
398 | if (!tx_queue->initialised) | ||
399 | efx_init_tx_queue(tx_queue); | ||
400 | efx_init_tx_queue_core_txq(tx_queue); | ||
401 | } | ||
402 | } | ||
403 | } else { | ||
404 | /* Reduce number of classes before number of queues */ | ||
405 | net_dev->num_tc = num_tc; | ||
406 | } | ||
407 | |||
408 | rc = netif_set_real_num_tx_queues(net_dev, | ||
409 | max_t(int, num_tc, 1) * | ||
410 | efx->n_tx_channels); | ||
411 | if (rc) | ||
412 | return rc; | ||
413 | |||
414 | /* Do not destroy high-priority queues when they become | ||
415 | * unused. We would have to flush them first, and it is | ||
416 | * fairly difficult to flush a subset of TX queues. Leave | ||
417 | * it to efx_fini_channels(). | ||
418 | */ | ||
419 | |||
420 | net_dev->num_tc = num_tc; | ||
421 | return 0; | ||
422 | } | ||
423 | |||
350 | void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) | 424 | void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) |
351 | { | 425 | { |
352 | unsigned fill_level; | 426 | unsigned fill_level; |
@@ -430,6 +504,8 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue) | |||
430 | 504 | ||
431 | /* Set up TX descriptor ring */ | 505 | /* Set up TX descriptor ring */ |
432 | efx_nic_init_tx(tx_queue); | 506 | efx_nic_init_tx(tx_queue); |
507 | |||
508 | tx_queue->initialised = true; | ||
433 | } | 509 | } |
434 | 510 | ||
435 | void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) | 511 | void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) |
@@ -452,9 +528,14 @@ void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) | |||
452 | 528 | ||
453 | void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) | 529 | void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) |
454 | { | 530 | { |
531 | if (!tx_queue->initialised) | ||
532 | return; | ||
533 | |||
455 | netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev, | 534 | netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev, |
456 | "shutting down TX queue %d\n", tx_queue->queue); | 535 | "shutting down TX queue %d\n", tx_queue->queue); |
457 | 536 | ||
537 | tx_queue->initialised = false; | ||
538 | |||
458 | /* Flush TX queue, remove descriptor ring */ | 539 | /* Flush TX queue, remove descriptor ring */ |
459 | efx_nic_fini_tx(tx_queue); | 540 | efx_nic_fini_tx(tx_queue); |
460 | 541 | ||
@@ -466,6 +547,9 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) | |||
466 | 547 | ||
467 | void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) | 548 | void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) |
468 | { | 549 | { |
550 | if (!tx_queue->buffer) | ||
551 | return; | ||
552 | |||
469 | netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev, | 553 | netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev, |
470 | "destroying TX queue %d\n", tx_queue->queue); | 554 | "destroying TX queue %d\n", tx_queue->queue); |
471 | efx_nic_remove_tx(tx_queue); | 555 | efx_nic_remove_tx(tx_queue); |