diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2009-11-25 11:11:35 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-26 18:59:36 -0500 |
commit | 55edc6e6ff728681ebc10d418222740705376664 (patch) | |
tree | 66136e674adde15b9668f13d4e0486482b7f1851 /drivers/net/sfc/falcon.c | |
parent | 1dfc5ceacd00365a9089e98643f4b26253d5a6aa (diff) |
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>
Diffstat (limited to 'drivers/net/sfc/falcon.c')
-rw-r--r-- | drivers/net/sfc/falcon.c | 131 |
1 files changed, 101 insertions, 30 deletions
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 9eec88502101..3ab2daff6b48 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c | |||
@@ -36,8 +36,6 @@ | |||
36 | ************************************************************************** | 36 | ************************************************************************** |
37 | */ | 37 | */ |
38 | 38 | ||
39 | static int disable_dma_stats; | ||
40 | |||
41 | /* This is set to 16 for a good reason. In summary, if larger than | 39 | /* This is set to 16 for a good reason. In summary, if larger than |
42 | * 16, the descriptor cache holds more than a default socket | 40 | * 16, the descriptor cache holds more than a default socket |
43 | * buffer's worth of packets (for UDP we can only have at most one | 41 | * 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) | |||
1890 | 1888 | ||
1891 | /* MAC stats will fail whilst the TX fifo is draining. Serialise | 1889 | /* MAC stats will fail whilst the TX fifo is draining. Serialise |
1892 | * the drain sequence with the statistics fetch */ | 1890 | * the drain sequence with the statistics fetch */ |
1893 | efx_stats_disable(efx); | 1891 | falcon_stop_nic_stats(efx); |
1894 | 1892 | ||
1895 | efx_reado(efx, ®, FR_AB_MAC_CTRL); | 1893 | efx_reado(efx, ®, FR_AB_MAC_CTRL); |
1896 | EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 1); | 1894 | EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 1); |
@@ -1920,13 +1918,13 @@ static int falcon_reset_macs(struct efx_nic *efx) | |||
1920 | udelay(10); | 1918 | udelay(10); |
1921 | } | 1919 | } |
1922 | 1920 | ||
1923 | efx_stats_enable(efx); | ||
1924 | |||
1925 | /* If we've reset the EM block and the link is up, then | 1921 | /* If we've reset the EM block and the link is up, then |
1926 | * we'll have to kick the XAUI link so the PHY can recover */ | 1922 | * we'll have to kick the XAUI link so the PHY can recover */ |
1927 | if (efx->link_state.up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx)) | 1923 | if (efx->link_state.up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx)) |
1928 | falcon_reset_xaui(efx); | 1924 | falcon_reset_xaui(efx); |
1929 | 1925 | ||
1926 | falcon_start_nic_stats(efx); | ||
1927 | |||
1930 | return 0; | 1928 | return 0; |
1931 | } | 1929 | } |
1932 | 1930 | ||
@@ -2010,25 +2008,19 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) | |||
2010 | efx_writeo(efx, ®, FR_AZ_RX_CFG); | 2008 | efx_writeo(efx, ®, FR_AZ_RX_CFG); |
2011 | } | 2009 | } |
2012 | 2010 | ||
2013 | int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset) | 2011 | static void falcon_stats_request(struct efx_nic *efx) |
2014 | { | 2012 | { |
2013 | struct falcon_nic_data *nic_data = efx->nic_data; | ||
2015 | efx_oword_t reg; | 2014 | efx_oword_t reg; |
2016 | u32 *dma_done; | ||
2017 | int i; | ||
2018 | 2015 | ||
2019 | if (disable_dma_stats) | 2016 | WARN_ON(nic_data->stats_pending); |
2020 | return 0; | 2017 | WARN_ON(nic_data->stats_disable_count); |
2021 | 2018 | ||
2022 | /* Statistics fetch will fail if the MAC is in TX drain */ | 2019 | if (nic_data->stats_dma_done == NULL) |
2023 | if (falcon_rev(efx) >= FALCON_REV_B0) { | 2020 | return; /* no mac selected */ |
2024 | efx_oword_t temp; | ||
2025 | efx_reado(efx, &temp, FR_AB_MAC_CTRL); | ||
2026 | if (EFX_OWORD_FIELD(temp, FRF_BB_TXFIFO_DRAIN_EN)) | ||
2027 | return 0; | ||
2028 | } | ||
2029 | 2021 | ||
2030 | dma_done = (efx->stats_buffer.addr + done_offset); | 2022 | *nic_data->stats_dma_done = FALCON_STATS_NOT_DONE; |
2031 | *dma_done = FALCON_STATS_NOT_DONE; | 2023 | nic_data->stats_pending = true; |
2032 | wmb(); /* ensure done flag is clear */ | 2024 | wmb(); /* ensure done flag is clear */ |
2033 | 2025 | ||
2034 | /* Initiate DMA transfer of stats */ | 2026 | /* Initiate DMA transfer of stats */ |
@@ -2038,17 +2030,37 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset) | |||
2038 | efx->stats_buffer.dma_addr); | 2030 | efx->stats_buffer.dma_addr); |
2039 | efx_writeo(efx, ®, FR_AB_MAC_STAT_DMA); | 2031 | efx_writeo(efx, ®, FR_AB_MAC_STAT_DMA); |
2040 | 2032 | ||
2041 | /* Wait for transfer to complete */ | 2033 | mod_timer(&nic_data->stats_timer, round_jiffies_up(jiffies + HZ / 2)); |
2042 | for (i = 0; i < 400; i++) { | 2034 | } |
2043 | if (*(volatile u32 *)dma_done == FALCON_STATS_DONE) { | 2035 | |
2044 | rmb(); /* Ensure the stats are valid. */ | 2036 | static void falcon_stats_complete(struct efx_nic *efx) |
2045 | return 0; | 2037 | { |
2046 | } | 2038 | struct falcon_nic_data *nic_data = efx->nic_data; |
2047 | udelay(10); | 2039 | |
2040 | if (!nic_data->stats_pending) | ||
2041 | return; | ||
2042 | |||
2043 | nic_data->stats_pending = 0; | ||
2044 | if (*nic_data->stats_dma_done == FALCON_STATS_DONE) { | ||
2045 | rmb(); /* read the done flag before the stats */ | ||
2046 | efx->mac_op->update_stats(efx); | ||
2047 | } else { | ||
2048 | EFX_ERR(efx, "timed out waiting for statistics\n"); | ||
2048 | } | 2049 | } |
2050 | } | ||
2049 | 2051 | ||
2050 | EFX_ERR(efx, "timed out waiting for statistics\n"); | 2052 | static void falcon_stats_timer_func(unsigned long context) |
2051 | return -ETIMEDOUT; | 2053 | { |
2054 | struct efx_nic *efx = (struct efx_nic *)context; | ||
2055 | struct falcon_nic_data *nic_data = efx->nic_data; | ||
2056 | |||
2057 | spin_lock(&efx->stats_lock); | ||
2058 | |||
2059 | falcon_stats_complete(efx); | ||
2060 | if (nic_data->stats_disable_count == 0) | ||
2061 | falcon_stats_request(efx); | ||
2062 | |||
2063 | spin_unlock(&efx->stats_lock); | ||
2052 | } | 2064 | } |
2053 | 2065 | ||
2054 | /************************************************************************** | 2066 | /************************************************************************** |
@@ -2206,10 +2218,12 @@ static void falcon_clock_mac(struct efx_nic *efx) | |||
2206 | int falcon_switch_mac(struct efx_nic *efx) | 2218 | int falcon_switch_mac(struct efx_nic *efx) |
2207 | { | 2219 | { |
2208 | struct efx_mac_operations *old_mac_op = efx->mac_op; | 2220 | struct efx_mac_operations *old_mac_op = efx->mac_op; |
2221 | struct falcon_nic_data *nic_data = efx->nic_data; | ||
2222 | unsigned int stats_done_offset; | ||
2209 | int rc = 0; | 2223 | int rc = 0; |
2210 | 2224 | ||
2211 | /* Don't try to fetch MAC stats while we're switching MACs */ | 2225 | /* Don't try to fetch MAC stats while we're switching MACs */ |
2212 | efx_stats_disable(efx); | 2226 | falcon_stop_nic_stats(efx); |
2213 | 2227 | ||
2214 | /* Internal loopbacks override the phy speed setting */ | 2228 | /* Internal loopbacks override the phy speed setting */ |
2215 | if (efx->loopback_mode == LOOPBACK_GMAC) { | 2229 | if (efx->loopback_mode == LOOPBACK_GMAC) { |
@@ -2224,6 +2238,12 @@ int falcon_switch_mac(struct efx_nic *efx) | |||
2224 | efx->mac_op = (EFX_IS10G(efx) ? | 2238 | efx->mac_op = (EFX_IS10G(efx) ? |
2225 | &falcon_xmac_operations : &falcon_gmac_operations); | 2239 | &falcon_xmac_operations : &falcon_gmac_operations); |
2226 | 2240 | ||
2241 | if (EFX_IS10G(efx)) | ||
2242 | stats_done_offset = XgDmaDone_offset; | ||
2243 | else | ||
2244 | stats_done_offset = GDmaDone_offset; | ||
2245 | nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset; | ||
2246 | |||
2227 | if (old_mac_op == efx->mac_op) | 2247 | if (old_mac_op == efx->mac_op) |
2228 | goto out; | 2248 | goto out; |
2229 | 2249 | ||
@@ -2235,7 +2255,7 @@ int falcon_switch_mac(struct efx_nic *efx) | |||
2235 | 2255 | ||
2236 | rc = falcon_reset_macs(efx); | 2256 | rc = falcon_reset_macs(efx); |
2237 | out: | 2257 | out: |
2238 | efx_stats_enable(efx); | 2258 | falcon_start_nic_stats(efx); |
2239 | return rc; | 2259 | return rc; |
2240 | } | 2260 | } |
2241 | 2261 | ||
@@ -2900,6 +2920,10 @@ int falcon_probe_nic(struct efx_nic *efx) | |||
2900 | goto fail6; | 2920 | goto fail6; |
2901 | } | 2921 | } |
2902 | 2922 | ||
2923 | nic_data->stats_disable_count = 1; | ||
2924 | setup_timer(&nic_data->stats_timer, &falcon_stats_timer_func, | ||
2925 | (unsigned long)efx); | ||
2926 | |||
2903 | return 0; | 2927 | return 0; |
2904 | 2928 | ||
2905 | fail6: | 2929 | fail6: |
@@ -3125,11 +3149,58 @@ void falcon_remove_nic(struct efx_nic *efx) | |||
3125 | 3149 | ||
3126 | void falcon_update_nic_stats(struct efx_nic *efx) | 3150 | void falcon_update_nic_stats(struct efx_nic *efx) |
3127 | { | 3151 | { |
3152 | struct falcon_nic_data *nic_data = efx->nic_data; | ||
3128 | efx_oword_t cnt; | 3153 | efx_oword_t cnt; |
3129 | 3154 | ||
3155 | if (nic_data->stats_disable_count) | ||
3156 | return; | ||
3157 | |||
3130 | efx_reado(efx, &cnt, FR_AZ_RX_NODESC_DROP); | 3158 | efx_reado(efx, &cnt, FR_AZ_RX_NODESC_DROP); |
3131 | efx->n_rx_nodesc_drop_cnt += | 3159 | efx->n_rx_nodesc_drop_cnt += |
3132 | EFX_OWORD_FIELD(cnt, FRF_AB_RX_NODESC_DROP_CNT); | 3160 | EFX_OWORD_FIELD(cnt, FRF_AB_RX_NODESC_DROP_CNT); |
3161 | |||
3162 | if (nic_data->stats_pending && | ||
3163 | *nic_data->stats_dma_done == FALCON_STATS_DONE) { | ||
3164 | nic_data->stats_pending = false; | ||
3165 | rmb(); /* read the done flag before the stats */ | ||
3166 | efx->mac_op->update_stats(efx); | ||
3167 | } | ||
3168 | } | ||
3169 | |||
3170 | void falcon_start_nic_stats(struct efx_nic *efx) | ||
3171 | { | ||
3172 | struct falcon_nic_data *nic_data = efx->nic_data; | ||
3173 | |||
3174 | spin_lock_bh(&efx->stats_lock); | ||
3175 | if (--nic_data->stats_disable_count == 0) | ||
3176 | falcon_stats_request(efx); | ||
3177 | spin_unlock_bh(&efx->stats_lock); | ||
3178 | } | ||
3179 | |||
3180 | void falcon_stop_nic_stats(struct efx_nic *efx) | ||
3181 | { | ||
3182 | struct falcon_nic_data *nic_data = efx->nic_data; | ||
3183 | int i; | ||
3184 | |||
3185 | might_sleep(); | ||
3186 | |||
3187 | spin_lock_bh(&efx->stats_lock); | ||
3188 | ++nic_data->stats_disable_count; | ||
3189 | spin_unlock_bh(&efx->stats_lock); | ||
3190 | |||
3191 | del_timer_sync(&nic_data->stats_timer); | ||
3192 | |||
3193 | /* Wait enough time for the most recent transfer to | ||
3194 | * complete. */ | ||
3195 | for (i = 0; i < 4 && nic_data->stats_pending; i++) { | ||
3196 | if (*nic_data->stats_dma_done == FALCON_STATS_DONE) | ||
3197 | break; | ||
3198 | msleep(1); | ||
3199 | } | ||
3200 | |||
3201 | spin_lock_bh(&efx->stats_lock); | ||
3202 | falcon_stats_complete(efx); | ||
3203 | spin_unlock_bh(&efx->stats_lock); | ||
3133 | } | 3204 | } |
3134 | 3205 | ||
3135 | /************************************************************************** | 3206 | /************************************************************************** |