struct efx_rx_queue *rx_queue;
int i;
- /* TX queues. One per port per channel with TX capability
- * (more than one per port won't work on Linux, due to out
- * of order issues... but will be fine on Solaris)
- */
- tx_queue = &efx->tx_queue[0];
-
- /* Perform this for each channel with TX capabilities.
- * At the moment, we only support a single TX queue
- */
- tx_queue->used = 1;
- if ((!EFX_INT_MODE_USE_MSI(efx)) && separate_tx_and_rx_channels)
- tx_queue->channel = &efx->channel[1];
- else
- tx_queue->channel = &efx->channel[0];
- tx_queue->channel->used_flags |= EFX_USED_BY_TX;
- tx_queue++;
+ efx_for_each_tx_queue(tx_queue, efx) {
+ if (!EFX_INT_MODE_USE_MSI(efx) && separate_tx_and_rx_channels)
+ tx_queue->channel = &efx->channel[1];
+ else
+ tx_queue->channel = &efx->channel[0];
+ tx_queue->channel->used_flags |= EFX_USED_BY_TX;
+ }
/* RX queues. Each has a dedicated channel. */
for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
channel->evqnum = i;
channel->work_pending = 0;
}
- for (i = 0; i < EFX_MAX_TX_QUEUES; i++) {
+ for (i = 0; i < EFX_TX_QUEUE_COUNT; i++) {
tx_queue = &efx->tx_queue[i];
tx_queue->efx = efx;
tx_queue->queue = i;
[LOOPBACK_NETWORK] = "NETWORK",
};
-static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable);
-
struct ethtool_string {
char name[ETH_GSTRING_LEN];
};
}
}
-static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable)
-{
- int rc;
-
- /* Our TSO requires TX checksumming, so force TX checksumming
- * on when TSO is enabled.
- */
- if (enable) {
- rc = efx_ethtool_set_tx_csum(net_dev, 1);
- if (rc)
- return rc;
- }
-
- return ethtool_op_set_tso(net_dev, enable);
-}
-
-static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
-{
- struct efx_nic *efx = netdev_priv(net_dev);
- int rc;
-
- rc = ethtool_op_set_tx_csum(net_dev, enable);
- if (rc)
- return rc;
-
- efx_flush_queues(efx);
-
- /* Our TSO requires TX checksumming, so disable TSO when
- * checksumming is disabled
- */
- if (!enable) {
- rc = efx_ethtool_set_tso(net_dev, 0);
- if (rc)
- return rc;
- }
-
- return 0;
-}
-
static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable)
{
struct efx_nic *efx = netdev_priv(net_dev);
.get_rx_csum = efx_ethtool_get_rx_csum,
.set_rx_csum = efx_ethtool_set_rx_csum,
.get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = efx_ethtool_set_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_tso = ethtool_op_get_tso,
- .set_tso = efx_ethtool_set_tso,
+ .set_tso = ethtool_op_set_tso,
.get_flags = ethtool_op_get_flags,
.set_flags = ethtool_op_set_flags,
.self_test_count = efx_ethtool_self_test_count,
TX_NON_IP_DROP_DIS_B0, 1);
if (falcon_rev(efx) >= FALCON_REV_B0) {
- int csum = !(efx->net_dev->features & NETIF_F_IP_CSUM);
- EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, csum);
- EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, csum);
+ int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM;
+ EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, !csum);
+ EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, !csum);
}
falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
if (falcon_rev(efx) < FALCON_REV_B0) {
efx_oword_t reg;
- BUG_ON(tx_queue->queue >= 128); /* HW limit */
+ /* Only 128 bits in this register */
+ BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128);
falcon_read(efx, ®, TX_CHKSM_CFG_REG_KER_A1);
- if (efx->net_dev->features & NETIF_F_IP_CSUM)
+ if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM)
clear_bit_le(tx_queue->queue, (void *)®);
else
set_bit_le(tx_queue->queue, (void *)®);
**************************************************************************/
#define EFX_MAX_CHANNELS 32
-#define EFX_MAX_TX_QUEUES 1
#define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
+#define EFX_TX_QUEUE_OFFLOAD_CSUM 0
+#define EFX_TX_QUEUE_NO_CSUM 1
+#define EFX_TX_QUEUE_COUNT 2
+
/**
* struct efx_special_buffer - An Efx special buffer
* @addr: CPU base address of the buffer
*
* @efx: The associated Efx NIC
* @queue: DMA queue number
- * @used: Queue is used by net driver
* @channel: The associated channel
* @buffer: The software buffer ring
* @txd: The hardware descriptor ring
/* Members which don't change on the fast path */
struct efx_nic *efx ____cacheline_aligned_in_smp;
int queue;
- int used;
struct efx_channel *channel;
struct efx_nic *nic;
struct efx_tx_buffer *buffer;
enum nic_state state;
enum reset_type reset_pending;
- struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES];
+ struct efx_tx_queue tx_queue[EFX_TX_QUEUE_COUNT];
struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES];
struct efx_channel channel[EFX_MAX_CHANNELS];
/* Iterate over all used TX queues */
#define efx_for_each_tx_queue(_tx_queue, _efx) \
for (_tx_queue = &_efx->tx_queue[0]; \
- _tx_queue < &_efx->tx_queue[EFX_MAX_TX_QUEUES]; \
- _tx_queue++) \
- if (!_tx_queue->used) \
- continue; \
- else
+ _tx_queue < &_efx->tx_queue[EFX_TX_QUEUE_COUNT]; \
+ _tx_queue++)
/* Iterate over all TX queues belonging to a channel */
#define efx_for_each_channel_tx_queue(_tx_queue, _channel) \
for (_tx_queue = &_channel->efx->tx_queue[0]; \
- _tx_queue < &_channel->efx->tx_queue[EFX_MAX_TX_QUEUES]; \
+ _tx_queue < &_channel->efx->tx_queue[EFX_TX_QUEUE_COUNT]; \
_tx_queue++) \
- if ((!_tx_queue->used) || \
- (_tx_queue->channel != _channel)) \
+ if (_tx_queue->channel != _channel) \
continue; \
else
int flush;
int packet_count;
struct sk_buff **skbs;
+
+ /* Checksums are being offloaded */
+ int offload_csum;
+
atomic_t rx_good;
atomic_t rx_bad;
struct efx_loopback_payload payload;
received = (struct efx_loopback_payload *) buf_ptr;
received->ip.saddr = payload->ip.saddr;
- received->ip.check = payload->ip.check;
-
+ if (state->offload_csum)
+ received->ip.check = payload->ip.check;
+
/* Check that header exists */
if (pkt_len < sizeof(received->header)) {
EFX_ERR(efx, "saw runt RX packet (length %d) in %s loopback "
/* Test every TX queue */
efx_for_each_tx_queue(tx_queue, efx) {
+ state->offload_csum = (tx_queue->queue ==
+ EFX_TX_QUEUE_OFFLOAD_CSUM);
rc |= efx_test_loopback(tx_queue,
&tests->loopback[mode]);
if (rc)
*/
struct efx_loopback_self_tests {
- int tx_sent[EFX_MAX_TX_QUEUES];
- int tx_done[EFX_MAX_TX_QUEUES];
+ int tx_sent[EFX_TX_QUEUE_COUNT];
+ int tx_done[EFX_TX_QUEUE_COUNT];
int rx_good;
int rx_bad;
};
int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
- return efx_xmit(efx, &efx->tx_queue[0], skb);
+ struct efx_tx_queue *tx_queue;
+
+ if (likely(skb->ip_summed == CHECKSUM_PARTIAL))
+ tx_queue = &efx->tx_queue[EFX_TX_QUEUE_OFFLOAD_CSUM];
+ else
+ tx_queue = &efx->tx_queue[EFX_TX_QUEUE_NO_CSUM];
+
+ return efx_xmit(efx, tx_queue, skb);
}
void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
/* Allocate software ring */
txq_size = (efx->type->txd_ring_mask + 1) * sizeof(*tx_queue->buffer);
tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL);
- if (!tx_queue->buffer) {
- rc = -ENOMEM;
- goto fail1;
- }
+ if (!tx_queue->buffer)
+ return -ENOMEM;
for (i = 0; i <= efx->type->txd_ring_mask; ++i)
tx_queue->buffer[i].continuation = 1;
/* Allocate hardware ring */
rc = falcon_probe_tx(tx_queue);
if (rc)
- goto fail2;
+ goto fail;
return 0;
- fail2:
+ fail:
kfree(tx_queue->buffer);
tx_queue->buffer = NULL;
- fail1:
- tx_queue->used = 0;
-
return rc;
}
kfree(tx_queue->buffer);
tx_queue->buffer = NULL;
- tx_queue->used = 0;
}