[PATCH] ibm_emac: fix graceful stop timeout handling

This patch fixes graceful stop timeout handling in PPC4xx EMAC driver.

Currently, when we stop TX/RX channels we just do some number of loops
without relying on actual spent time. This has finally bitten me on
one of our systems (heavy network traffic during start up, RX channel
is stopped several times to configure multicast list).

Graceful channel stop can take up to 1 frame time, so I've added
device specific timeout counter which depends on current link speed
and calls to udelay() to really wait required amount of time before
giving up.

Signed-off-by: Eugene Surovegin <ebs@ebshome.net>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>

authored by Eugene Surovegin and committed by Jeff Garzik 8169bd91 be0df20c

+31 -9
+29 -9
drivers/net/ibm_emac/ibm_emac_core.c
··· 65 65 */ 66 66 67 67 #define DRV_NAME "emac" 68 - #define DRV_VERSION "3.53" 68 + #define DRV_VERSION "3.54" 69 69 #define DRV_DESC "PPC 4xx OCP EMAC driver" 70 70 71 71 MODULE_DESCRIPTION(DRV_DESC); ··· 158 158 #define PHY_POLL_LINK_ON HZ 159 159 #define PHY_POLL_LINK_OFF (HZ / 5) 160 160 161 + /* Graceful stop timeouts in us. 162 + * We should allow up to 1 frame time (full-duplex, ignoring collisions) 163 + */ 164 + #define STOP_TIMEOUT_10 1230 165 + #define STOP_TIMEOUT_100 124 166 + #define STOP_TIMEOUT_1000 13 167 + #define STOP_TIMEOUT_1000_JUMBO 73 168 + 161 169 /* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */ 162 170 static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = { 163 171 "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum", ··· 230 222 231 223 r = in_be32(&p->mr0); 232 224 if (r & EMAC_MR0_TXE) { 233 - int n = 300; 225 + int n = dev->stop_timeout; 234 226 out_be32(&p->mr0, r & ~EMAC_MR0_TXE); 235 - while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) 227 + while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) { 228 + udelay(1); 236 229 --n; 230 + } 237 231 if (unlikely(!n)) 238 232 emac_report_timeout_error(dev, "TX disable timeout"); 239 233 } ··· 258 248 if (!(r & EMAC_MR0_RXE)) { 259 249 if (unlikely(!(r & EMAC_MR0_RXI))) { 260 250 /* Wait if previous async disable is still in progress */ 261 - int n = 100; 262 - while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) 251 + int n = dev->stop_timeout; 252 + while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) { 253 + udelay(1); 263 254 --n; 255 + } 264 256 if (unlikely(!n)) 265 257 emac_report_timeout_error(dev, 266 258 "RX disable timeout"); ··· 285 273 286 274 r = in_be32(&p->mr0); 287 275 if (r & EMAC_MR0_RXE) { 288 - int n = 300; 276 + int n = dev->stop_timeout; 289 277 out_be32(&p->mr0, r & ~EMAC_MR0_RXE); 290 - while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) 278 + while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) { 279 + udelay(1); 291 280 --n; 281 + } 292 282 if (unlikely(!n)) 293 283 emac_report_timeout_error(dev, "RX disable timeout"); 294 284 } ··· 409 395 r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST; 410 396 if (dev->phy.duplex == DUPLEX_FULL) 411 397 r |= EMAC_MR1_FDE; 398 + dev->stop_timeout = STOP_TIMEOUT_10; 412 399 switch (dev->phy.speed) { 413 400 case SPEED_1000: 414 401 if (emac_phy_gpcs(dev->phy.mode)) { ··· 424 409 r |= EMAC_MR1_MF_1000; 425 410 r |= EMAC_MR1_RFS_16K; 426 411 gige = 1; 427 - 428 - if (dev->ndev->mtu > ETH_DATA_LEN) 412 + 413 + if (dev->ndev->mtu > ETH_DATA_LEN) { 429 414 r |= EMAC_MR1_JPSM; 415 + dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO; 416 + } else 417 + dev->stop_timeout = STOP_TIMEOUT_1000; 430 418 break; 431 419 case SPEED_100: 432 420 r |= EMAC_MR1_MF_100; 421 + dev->stop_timeout = STOP_TIMEOUT_100; 433 422 /* Fall through */ 434 423 default: 435 424 r |= EMAC_MR1_RFS_4K; ··· 2067 2048 dev->phy.duplex = DUPLEX_FULL; 2068 2049 dev->phy.autoneg = AUTONEG_DISABLE; 2069 2050 dev->phy.pause = dev->phy.asym_pause = 0; 2051 + dev->stop_timeout = STOP_TIMEOUT_100; 2070 2052 init_timer(&dev->link_timer); 2071 2053 dev->link_timer.function = emac_link_timer; 2072 2054 dev->link_timer.data = (unsigned long)dev;
+2
drivers/net/ibm_emac/ibm_emac_core.h
··· 189 189 struct timer_list link_timer; 190 190 int reset_failed; 191 191 192 + int stop_timeout; /* in us */ 193 + 192 194 struct ibm_emac_error_stats estats; 193 195 struct net_device_stats nstats; 194 196