aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/freescale
diff options
context:
space:
mode:
authorClaudiu Manoil <claudiu.manoil@freescale.com>2014-02-24 05:13:43 -0500
committerDavid S. Miller <davem@davemloft.net>2014-02-24 19:38:20 -0500
commit88302648be8c45af09694363be1b165680489137 (patch)
treee90374eca907c2b74dbcb0f97ab50bcf5a95c92a /drivers/net/ethernet/freescale
parenta328ac92d3149d191a92b681a832d417da72a74c (diff)
gianfar: Fix on-the-fly vlan and mtu updates
The RCTRL and TCTRL registers should not be changed on-the-fly, while the controller is running, otherwise unexpected behaviour occurs. But that's exactly what gfar_vlan_mode() does, updating the VLAN acceleration bits inside RCTRL/TCTRL. The attempt to lock these operations doesn't help, but only adds to the confusion. There's also a dependency for Rx FCB insertion (activating /de-activating the TOE offload block on Rx) which might change the required rx buffer size. This makes matters worse as gfar_vlan_mode() ends up calling gfar_change_mtu(), though the MTU size remains the same. Note that there are other situations that may affect the required rx buffer size, like changing RXCSUM or rx hw timestamping, but errorneously the rx buffer size is not recomputed/ updated in the process. To fix this, do the vlan updates properly inside the MAC reset and reconfiguration procedure, which takes care of the rx buffer size dependecy and the rx TOE block (PRSDEP) activation/deactivation as well (in the correct order). As a consequence, MTU/ rx buff size updates are done now by the same MAC reset and reconfig procedure, so that out of context updates to MAXFRM, MRBLR, and MACCFG inside change_mtu() are no longer needed. The rx buffer size dependecy to Rx FCB is now handled for the other cases too (RXCSUM and rx hw timestamping). Signed-off-by: Claudiu Manoil <claudiu.manoil@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c165
-rw-r--r--drivers/net/ethernet/freescale/gianfar.h2
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c11
3 files changed, 51 insertions, 127 deletions
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 446e9c99379d..728078fe400e 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -329,14 +329,35 @@ static void gfar_init_tx_rx_base(struct gfar_private *priv)
329 } 329 }
330} 330}
331 331
332static void gfar_mac_rx_config(struct gfar_private *priv) 332static void gfar_rx_buff_size_config(struct gfar_private *priv)
333{ 333{
334 struct gfar __iomem *regs = priv->gfargrp[0].regs; 334 int frame_size = priv->ndev->mtu + ETH_HLEN;
335 u32 rctrl = 0;
336 335
337 /* set this when rx hw offload (TOE) functions are being used */ 336 /* set this when rx hw offload (TOE) functions are being used */
338 priv->uses_rxfcb = 0; 337 priv->uses_rxfcb = 0;
339 338
339 if (priv->ndev->features & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX))
340 priv->uses_rxfcb = 1;
341
342 if (priv->hwts_rx_en)
343 priv->uses_rxfcb = 1;
344
345 if (priv->uses_rxfcb)
346 frame_size += GMAC_FCB_LEN;
347
348 frame_size += priv->padding;
349
350 frame_size = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) +
351 INCREMENTAL_BUFFER_SIZE;
352
353 priv->rx_buffer_size = frame_size;
354}
355
356static void gfar_mac_rx_config(struct gfar_private *priv)
357{
358 struct gfar __iomem *regs = priv->gfargrp[0].regs;
359 u32 rctrl = 0;
360
340 if (priv->rx_filer_enable) { 361 if (priv->rx_filer_enable) {
341 rctrl |= RCTRL_FILREN; 362 rctrl |= RCTRL_FILREN;
342 /* Program the RIR0 reg with the required distribution */ 363 /* Program the RIR0 reg with the required distribution */
@@ -347,15 +368,11 @@ static void gfar_mac_rx_config(struct gfar_private *priv)
347 if (priv->ndev->flags & IFF_PROMISC) 368 if (priv->ndev->flags & IFF_PROMISC)
348 rctrl |= RCTRL_PROM; 369 rctrl |= RCTRL_PROM;
349 370
350 if (priv->ndev->features & NETIF_F_RXCSUM) { 371 if (priv->ndev->features & NETIF_F_RXCSUM)
351 rctrl |= RCTRL_CHECKSUMMING; 372 rctrl |= RCTRL_CHECKSUMMING;
352 priv->uses_rxfcb = 1;
353 }
354 373
355 if (priv->extended_hash) { 374 if (priv->extended_hash)
356 rctrl |= RCTRL_EXTHASH; 375 rctrl |= RCTRL_EXTHASH | RCTRL_EMEN;
357 rctrl |= RCTRL_EMEN;
358 }
359 376
360 if (priv->padding) { 377 if (priv->padding) {
361 rctrl &= ~RCTRL_PAL_MASK; 378 rctrl &= ~RCTRL_PAL_MASK;
@@ -363,15 +380,11 @@ static void gfar_mac_rx_config(struct gfar_private *priv)
363 } 380 }
364 381
365 /* Enable HW time stamping if requested from user space */ 382 /* Enable HW time stamping if requested from user space */
366 if (priv->hwts_rx_en) { 383 if (priv->hwts_rx_en)
367 rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE; 384 rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE;
368 priv->uses_rxfcb = 1;
369 }
370 385
371 if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_RX) { 386 if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
372 rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; 387 rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
373 priv->uses_rxfcb = 1;
374 }
375 388
376 /* Init rctrl based on our settings */ 389 /* Init rctrl based on our settings */
377 gfar_write(&regs->rctrl, rctrl); 390 gfar_write(&regs->rctrl, rctrl);
@@ -393,6 +406,9 @@ static void gfar_mac_tx_config(struct gfar_private *priv)
393 gfar_write(&regs->tr47wt, DEFAULT_WRRS_WEIGHT); 406 gfar_write(&regs->tr47wt, DEFAULT_WRRS_WEIGHT);
394 } 407 }
395 408
409 if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_TX)
410 tctrl |= TCTRL_VLINS;
411
396 gfar_write(&regs->tctrl, tctrl); 412 gfar_write(&regs->tctrl, tctrl);
397} 413}
398 414
@@ -1029,7 +1045,11 @@ static void gfar_mac_reset(struct gfar_private *priv)
1029 1045
1030 udelay(3); 1046 udelay(3);
1031 1047
1032 /* Initialize the max receive buffer length */ 1048 /* Compute rx_buff_size based on config flags */
1049 gfar_rx_buff_size_config(priv);
1050
1051 /* Initialize the max receive frame/buffer lengths */
1052 gfar_write(&regs->maxfrm, priv->rx_buffer_size);
1033 gfar_write(&regs->mrblr, priv->rx_buffer_size); 1053 gfar_write(&regs->mrblr, priv->rx_buffer_size);
1034 1054
1035 /* Initialize the Minimum Frame Length Register */ 1055 /* Initialize the Minimum Frame Length Register */
@@ -1037,8 +1057,15 @@ static void gfar_mac_reset(struct gfar_private *priv)
1037 1057
1038 /* Initialize MACCFG2. */ 1058 /* Initialize MACCFG2. */
1039 tempval = MACCFG2_INIT_SETTINGS; 1059 tempval = MACCFG2_INIT_SETTINGS;
1040 if (gfar_has_errata(priv, GFAR_ERRATA_74)) 1060
1061 /* If the mtu is larger than the max size for standard
1062 * ethernet frames (ie, a jumbo frame), then set maccfg2
1063 * to allow huge frames, and to check the length
1064 */
1065 if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE ||
1066 gfar_has_errata(priv, GFAR_ERRATA_74))
1041 tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK; 1067 tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK;
1068
1042 gfar_write(&regs->maccfg2, tempval); 1069 gfar_write(&regs->maccfg2, tempval);
1043 1070
1044 /* Clear mac addr hash registers */ 1071 /* Clear mac addr hash registers */
@@ -2353,77 +2380,9 @@ static int gfar_set_mac_address(struct net_device *dev)
2353 return 0; 2380 return 0;
2354} 2381}
2355 2382
2356/* Check if rx parser should be activated */
2357void gfar_check_rx_parser_mode(struct gfar_private *priv)
2358{
2359 struct gfar __iomem *regs;
2360 u32 tempval;
2361
2362 regs = priv->gfargrp[0].regs;
2363
2364 tempval = gfar_read(&regs->rctrl);
2365 /* If parse is no longer required, then disable parser */
2366 if (tempval & RCTRL_REQ_PARSER) {
2367 tempval |= RCTRL_PRSDEP_INIT;
2368 priv->uses_rxfcb = 1;
2369 } else {
2370 tempval &= ~RCTRL_PRSDEP_INIT;
2371 priv->uses_rxfcb = 0;
2372 }
2373 gfar_write(&regs->rctrl, tempval);
2374}
2375
2376/* Enables and disables VLAN insertion/extraction */
2377void gfar_vlan_mode(struct net_device *dev, netdev_features_t features)
2378{
2379 struct gfar_private *priv = netdev_priv(dev);
2380 struct gfar __iomem *regs = NULL;
2381 unsigned long flags;
2382 u32 tempval;
2383
2384 regs = priv->gfargrp[0].regs;
2385 local_irq_save(flags);
2386 lock_rx_qs(priv);
2387
2388 if (features & NETIF_F_HW_VLAN_CTAG_TX) {
2389 /* Enable VLAN tag insertion */
2390 tempval = gfar_read(&regs->tctrl);
2391 tempval |= TCTRL_VLINS;
2392 gfar_write(&regs->tctrl, tempval);
2393 } else {
2394 /* Disable VLAN tag insertion */
2395 tempval = gfar_read(&regs->tctrl);
2396 tempval &= ~TCTRL_VLINS;
2397 gfar_write(&regs->tctrl, tempval);
2398 }
2399
2400 if (features & NETIF_F_HW_VLAN_CTAG_RX) {
2401 /* Enable VLAN tag extraction */
2402 tempval = gfar_read(&regs->rctrl);
2403 tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT);
2404 gfar_write(&regs->rctrl, tempval);
2405 priv->uses_rxfcb = 1;
2406 } else {
2407 /* Disable VLAN tag extraction */
2408 tempval = gfar_read(&regs->rctrl);
2409 tempval &= ~RCTRL_VLEX;
2410 gfar_write(&regs->rctrl, tempval);
2411
2412 gfar_check_rx_parser_mode(priv);
2413 }
2414
2415 gfar_change_mtu(dev, dev->mtu);
2416
2417 unlock_rx_qs(priv);
2418 local_irq_restore(flags);
2419}
2420
2421static int gfar_change_mtu(struct net_device *dev, int new_mtu) 2383static int gfar_change_mtu(struct net_device *dev, int new_mtu)
2422{ 2384{
2423 int tempsize, tempval;
2424 struct gfar_private *priv = netdev_priv(dev); 2385 struct gfar_private *priv = netdev_priv(dev);
2425 struct gfar __iomem *regs = priv->gfargrp[0].regs;
2426 int oldsize = priv->rx_buffer_size;
2427 int frame_size = new_mtu + ETH_HLEN; 2386 int frame_size = new_mtu + ETH_HLEN;
2428 2387
2429 if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) { 2388 if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {
@@ -2431,42 +2390,12 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
2431 return -EINVAL; 2390 return -EINVAL;
2432 } 2391 }
2433 2392
2434 if (priv->uses_rxfcb) 2393 if (dev->flags & IFF_UP)
2435 frame_size += GMAC_FCB_LEN;
2436
2437 frame_size += priv->padding;
2438
2439 tempsize = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) +
2440 INCREMENTAL_BUFFER_SIZE;
2441
2442 /* Only stop and start the controller if it isn't already
2443 * stopped, and we changed something
2444 */
2445 if ((oldsize != tempsize) && (dev->flags & IFF_UP))
2446 stop_gfar(dev); 2394 stop_gfar(dev);
2447 2395
2448 priv->rx_buffer_size = tempsize;
2449
2450 dev->mtu = new_mtu; 2396 dev->mtu = new_mtu;
2451 2397
2452 gfar_write(&regs->mrblr, priv->rx_buffer_size); 2398 if (dev->flags & IFF_UP)
2453 gfar_write(&regs->maxfrm, priv->rx_buffer_size);
2454
2455 /* If the mtu is larger than the max size for standard
2456 * ethernet frames (ie, a jumbo frame), then set maccfg2
2457 * to allow huge frames, and to check the length
2458 */
2459 tempval = gfar_read(&regs->maccfg2);
2460
2461 if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE ||
2462 gfar_has_errata(priv, GFAR_ERRATA_74))
2463 tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
2464 else
2465 tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
2466
2467 gfar_write(&regs->maccfg2, tempval);
2468
2469 if ((oldsize != tempsize) && (dev->flags & IFF_UP))
2470 startup_gfar(dev); 2399 startup_gfar(dev);
2471 2400
2472 return 0; 2401 return 0;
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index 2a59398f8cf0..9db95563f8aa 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -1211,8 +1211,6 @@ void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, int enable,
1211 u32 regnum, u32 read); 1211 u32 regnum, u32 read);
1212void gfar_configure_coalescing_all(struct gfar_private *priv); 1212void gfar_configure_coalescing_all(struct gfar_private *priv);
1213int gfar_set_features(struct net_device *dev, netdev_features_t features); 1213int gfar_set_features(struct net_device *dev, netdev_features_t features);
1214void gfar_check_rx_parser_mode(struct gfar_private *priv);
1215void gfar_vlan_mode(struct net_device *dev, netdev_features_t features);
1216 1214
1217extern const struct ethtool_ops gfar_ethtool_ops; 1215extern const struct ethtool_ops gfar_ethtool_ops;
1218 1216
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 19557ec31f33..dd7ccec506f1 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -582,18 +582,15 @@ int gfar_set_features(struct net_device *dev, netdev_features_t features)
582 netdev_features_t changed = dev->features ^ features; 582 netdev_features_t changed = dev->features ^ features;
583 int err = 0; 583 int err = 0;
584 584
585 if (changed & (NETIF_F_HW_VLAN_CTAG_TX|NETIF_F_HW_VLAN_CTAG_RX)) 585 if (!(changed & (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
586 gfar_vlan_mode(dev, features); 586 NETIF_F_RXCSUM)))
587
588 if (!(changed & NETIF_F_RXCSUM))
589 return 0; 587 return 0;
590 588
589 dev->features = features;
590
591 if (dev->flags & IFF_UP) { 591 if (dev->flags & IFF_UP) {
592 /* Now we take down the rings to rebuild them */ 592 /* Now we take down the rings to rebuild them */
593 stop_gfar(dev); 593 stop_gfar(dev);
594
595 dev->features = features;
596
597 err = startup_gfar(dev); 594 err = startup_gfar(dev);
598 netif_tx_wake_all_queues(dev); 595 netif_tx_wake_all_queues(dev);
599 } 596 }