sfc: Split MAC stats DMA initiation and completion
From: Steve Hodgson <shodgson@solarflare.com> Currently we initiate MAC stats DMA and busy-wait for completion when stats are requested. We can improve on this with a periodic timer to initiate and poll for stats, and opportunistically poll when stats are requested. Since efx_nic::stats_disable_count and efx_stats_{disable,enable}() are Falcon-specific, rename them and move them accordingly. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
1dfc5ceacd
commit
55edc6e6ff
@@ -36,8 +36,6 @@
|
||||
**************************************************************************
|
||||
*/
|
||||
|
||||
static int disable_dma_stats;
|
||||
|
||||
/* This is set to 16 for a good reason. In summary, if larger than
|
||||
* 16, the descriptor cache holds more than a default socket
|
||||
* buffer's worth of packets (for UDP we can only have at most one
|
||||
@@ -1890,7 +1888,7 @@ static int falcon_reset_macs(struct efx_nic *efx)
|
||||
|
||||
/* MAC stats will fail whilst the TX fifo is draining. Serialise
|
||||
* the drain sequence with the statistics fetch */
|
||||
efx_stats_disable(efx);
|
||||
falcon_stop_nic_stats(efx);
|
||||
|
||||
efx_reado(efx, ®, FR_AB_MAC_CTRL);
|
||||
EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 1);
|
||||
@@ -1920,13 +1918,13 @@ static int falcon_reset_macs(struct efx_nic *efx)
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
efx_stats_enable(efx);
|
||||
|
||||
/* If we've reset the EM block and the link is up, then
|
||||
* we'll have to kick the XAUI link so the PHY can recover */
|
||||
if (efx->link_state.up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx))
|
||||
falcon_reset_xaui(efx);
|
||||
|
||||
falcon_start_nic_stats(efx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2010,25 +2008,19 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
|
||||
efx_writeo(efx, ®, FR_AZ_RX_CFG);
|
||||
}
|
||||
|
||||
int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
|
||||
static void falcon_stats_request(struct efx_nic *efx)
|
||||
{
|
||||
struct falcon_nic_data *nic_data = efx->nic_data;
|
||||
efx_oword_t reg;
|
||||
u32 *dma_done;
|
||||
int i;
|
||||
|
||||
if (disable_dma_stats)
|
||||
return 0;
|
||||
WARN_ON(nic_data->stats_pending);
|
||||
WARN_ON(nic_data->stats_disable_count);
|
||||
|
||||
/* Statistics fetch will fail if the MAC is in TX drain */
|
||||
if (falcon_rev(efx) >= FALCON_REV_B0) {
|
||||
efx_oword_t temp;
|
||||
efx_reado(efx, &temp, FR_AB_MAC_CTRL);
|
||||
if (EFX_OWORD_FIELD(temp, FRF_BB_TXFIFO_DRAIN_EN))
|
||||
return 0;
|
||||
}
|
||||
if (nic_data->stats_dma_done == NULL)
|
||||
return; /* no mac selected */
|
||||
|
||||
dma_done = (efx->stats_buffer.addr + done_offset);
|
||||
*dma_done = FALCON_STATS_NOT_DONE;
|
||||
*nic_data->stats_dma_done = FALCON_STATS_NOT_DONE;
|
||||
nic_data->stats_pending = true;
|
||||
wmb(); /* ensure done flag is clear */
|
||||
|
||||
/* Initiate DMA transfer of stats */
|
||||
@@ -2038,17 +2030,37 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
|
||||
efx->stats_buffer.dma_addr);
|
||||
efx_writeo(efx, ®, FR_AB_MAC_STAT_DMA);
|
||||
|
||||
/* Wait for transfer to complete */
|
||||
for (i = 0; i < 400; i++) {
|
||||
if (*(volatile u32 *)dma_done == FALCON_STATS_DONE) {
|
||||
rmb(); /* Ensure the stats are valid. */
|
||||
return 0;
|
||||
}
|
||||
udelay(10);
|
||||
}
|
||||
mod_timer(&nic_data->stats_timer, round_jiffies_up(jiffies + HZ / 2));
|
||||
}
|
||||
|
||||
EFX_ERR(efx, "timed out waiting for statistics\n");
|
||||
return -ETIMEDOUT;
|
||||
static void falcon_stats_complete(struct efx_nic *efx)
|
||||
{
|
||||
struct falcon_nic_data *nic_data = efx->nic_data;
|
||||
|
||||
if (!nic_data->stats_pending)
|
||||
return;
|
||||
|
||||
nic_data->stats_pending = 0;
|
||||
if (*nic_data->stats_dma_done == FALCON_STATS_DONE) {
|
||||
rmb(); /* read the done flag before the stats */
|
||||
efx->mac_op->update_stats(efx);
|
||||
} else {
|
||||
EFX_ERR(efx, "timed out waiting for statistics\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void falcon_stats_timer_func(unsigned long context)
|
||||
{
|
||||
struct efx_nic *efx = (struct efx_nic *)context;
|
||||
struct falcon_nic_data *nic_data = efx->nic_data;
|
||||
|
||||
spin_lock(&efx->stats_lock);
|
||||
|
||||
falcon_stats_complete(efx);
|
||||
if (nic_data->stats_disable_count == 0)
|
||||
falcon_stats_request(efx);
|
||||
|
||||
spin_unlock(&efx->stats_lock);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@@ -2206,10 +2218,12 @@ static void falcon_clock_mac(struct efx_nic *efx)
|
||||
int falcon_switch_mac(struct efx_nic *efx)
|
||||
{
|
||||
struct efx_mac_operations *old_mac_op = efx->mac_op;
|
||||
struct falcon_nic_data *nic_data = efx->nic_data;
|
||||
unsigned int stats_done_offset;
|
||||
int rc = 0;
|
||||
|
||||
/* Don't try to fetch MAC stats while we're switching MACs */
|
||||
efx_stats_disable(efx);
|
||||
falcon_stop_nic_stats(efx);
|
||||
|
||||
/* Internal loopbacks override the phy speed setting */
|
||||
if (efx->loopback_mode == LOOPBACK_GMAC) {
|
||||
@@ -2224,6 +2238,12 @@ int falcon_switch_mac(struct efx_nic *efx)
|
||||
efx->mac_op = (EFX_IS10G(efx) ?
|
||||
&falcon_xmac_operations : &falcon_gmac_operations);
|
||||
|
||||
if (EFX_IS10G(efx))
|
||||
stats_done_offset = XgDmaDone_offset;
|
||||
else
|
||||
stats_done_offset = GDmaDone_offset;
|
||||
nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset;
|
||||
|
||||
if (old_mac_op == efx->mac_op)
|
||||
goto out;
|
||||
|
||||
@@ -2235,7 +2255,7 @@ int falcon_switch_mac(struct efx_nic *efx)
|
||||
|
||||
rc = falcon_reset_macs(efx);
|
||||
out:
|
||||
efx_stats_enable(efx);
|
||||
falcon_start_nic_stats(efx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2900,6 +2920,10 @@ int falcon_probe_nic(struct efx_nic *efx)
|
||||
goto fail6;
|
||||
}
|
||||
|
||||
nic_data->stats_disable_count = 1;
|
||||
setup_timer(&nic_data->stats_timer, &falcon_stats_timer_func,
|
||||
(unsigned long)efx);
|
||||
|
||||
return 0;
|
||||
|
||||
fail6:
|
||||
@@ -3125,11 +3149,58 @@ void falcon_remove_nic(struct efx_nic *efx)
|
||||
|
||||
void falcon_update_nic_stats(struct efx_nic *efx)
|
||||
{
|
||||
struct falcon_nic_data *nic_data = efx->nic_data;
|
||||
efx_oword_t cnt;
|
||||
|
||||
if (nic_data->stats_disable_count)
|
||||
return;
|
||||
|
||||
efx_reado(efx, &cnt, FR_AZ_RX_NODESC_DROP);
|
||||
efx->n_rx_nodesc_drop_cnt +=
|
||||
EFX_OWORD_FIELD(cnt, FRF_AB_RX_NODESC_DROP_CNT);
|
||||
|
||||
if (nic_data->stats_pending &&
|
||||
*nic_data->stats_dma_done == FALCON_STATS_DONE) {
|
||||
nic_data->stats_pending = false;
|
||||
rmb(); /* read the done flag before the stats */
|
||||
efx->mac_op->update_stats(efx);
|
||||
}
|
||||
}
|
||||
|
||||
void falcon_start_nic_stats(struct efx_nic *efx)
|
||||
{
|
||||
struct falcon_nic_data *nic_data = efx->nic_data;
|
||||
|
||||
spin_lock_bh(&efx->stats_lock);
|
||||
if (--nic_data->stats_disable_count == 0)
|
||||
falcon_stats_request(efx);
|
||||
spin_unlock_bh(&efx->stats_lock);
|
||||
}
|
||||
|
||||
void falcon_stop_nic_stats(struct efx_nic *efx)
|
||||
{
|
||||
struct falcon_nic_data *nic_data = efx->nic_data;
|
||||
int i;
|
||||
|
||||
might_sleep();
|
||||
|
||||
spin_lock_bh(&efx->stats_lock);
|
||||
++nic_data->stats_disable_count;
|
||||
spin_unlock_bh(&efx->stats_lock);
|
||||
|
||||
del_timer_sync(&nic_data->stats_timer);
|
||||
|
||||
/* Wait enough time for the most recent transfer to
|
||||
* complete. */
|
||||
for (i = 0; i < 4 && nic_data->stats_pending; i++) {
|
||||
if (*nic_data->stats_dma_done == FALCON_STATS_DONE)
|
||||
break;
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
spin_lock_bh(&efx->stats_lock);
|
||||
falcon_stats_complete(efx);
|
||||
spin_unlock_bh(&efx->stats_lock);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
Reference in New Issue
Block a user