diff options
Diffstat (limited to 'drivers/net/ethernet/faraday/ftmac100.c')
-rw-r--r-- | drivers/net/ethernet/faraday/ftmac100.c | 65 |
1 files changed, 45 insertions, 20 deletions
diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c index d95d78230828..6c8c78018ce6 100644 --- a/drivers/net/ethernet/faraday/ftmac100.c +++ b/drivers/net/ethernet/faraday/ftmac100.c @@ -11,6 +11,8 @@ #include <linux/dma-mapping.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> +#include <linux/if_ether.h> +#include <linux/if_vlan.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -27,8 +29,8 @@ #define RX_QUEUE_ENTRIES 128 /* must be power of 2 */ #define TX_QUEUE_ENTRIES 16 /* must be power of 2 */ -#define MAX_PKT_SIZE 1518 #define RX_BUF_SIZE 2044 /* must be smaller than 0x7ff */ +#define MAX_PKT_SIZE RX_BUF_SIZE /* multi-segment not supported */ #if MAX_PKT_SIZE > 0x7ff #error invalid MAX_PKT_SIZE @@ -159,6 +161,7 @@ static void ftmac100_set_mac(struct ftmac100 *priv, const unsigned char *mac) static int ftmac100_start_hw(struct ftmac100 *priv) { struct net_device *netdev = priv->netdev; + unsigned int maccr = MACCR_ENABLE_ALL; if (ftmac100_reset(priv)) return -EIO; @@ -175,7 +178,11 @@ static int ftmac100_start_hw(struct ftmac100 *priv) ftmac100_set_mac(priv, netdev->dev_addr); - iowrite32(MACCR_ENABLE_ALL, priv->base + FTMAC100_OFFSET_MACCR); + /* See ftmac100_change_mtu() */ + if (netdev->mtu > ETH_DATA_LEN) + maccr |= FTMAC100_MACCR_RX_FTL; + + iowrite32(maccr, priv->base + FTMAC100_OFFSET_MACCR); return 0; } @@ -218,11 +225,6 @@ static bool ftmac100_rxdes_crc_error(struct ftmac100_rxdes *rxdes) return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_CRC_ERR); } -static bool ftmac100_rxdes_frame_too_long(struct ftmac100_rxdes *rxdes) -{ - return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_FTL); -} - static bool ftmac100_rxdes_runt(struct ftmac100_rxdes *rxdes) { return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RUNT); @@ -337,13 +339,7 @@ static bool ftmac100_rx_packet_error(struct ftmac100 *priv, error = true; } - if (unlikely(ftmac100_rxdes_frame_too_long(rxdes))) { - if (net_ratelimit()) - netdev_info(netdev, "rx frame too long\n"); - - netdev->stats.rx_length_errors++; - error = true; - } else if (unlikely(ftmac100_rxdes_runt(rxdes))) { + if (unlikely(ftmac100_rxdes_runt(rxdes))) { if (net_ratelimit()) netdev_info(netdev, "rx runt\n"); @@ -356,6 +352,11 @@ static bool ftmac100_rx_packet_error(struct ftmac100 *priv, netdev->stats.rx_length_errors++; error = true; } + /* + * FTMAC100_RXDES0_FTL is not an error, it just indicates that the + * frame is longer than 1518 octets. Receiving these is possible when + * we told the hardware not to drop them, via FTMAC100_MACCR_RX_FTL. + */ return error; } @@ -400,12 +401,13 @@ static bool ftmac100_rx_packet(struct ftmac100 *priv, int *processed) return true; } - /* - * It is impossible to get multi-segment packets - * because we always provide big enough receive buffers. - */ + /* We don't support multi-segment packets for now, so drop them. */ ret = ftmac100_rxdes_last_segment(rxdes); - BUG_ON(!ret); + if (unlikely(!ret)) { + netdev->stats.rx_length_errors++; + ftmac100_rx_drop_packet(priv); + return true; + } /* start processing */ skb = netdev_alloc_skb_ip_align(netdev, 128); @@ -1037,6 +1039,28 @@ static int ftmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int c return generic_mii_ioctl(&priv->mii, data, cmd, NULL); } +static int ftmac100_change_mtu(struct net_device *netdev, int mtu) +{ + struct ftmac100 *priv = netdev_priv(netdev); + unsigned int maccr; + + maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR); + if (mtu > ETH_DATA_LEN) { + /* process long packets in the driver */ + maccr |= FTMAC100_MACCR_RX_FTL; + } else { + /* Let the controller drop incoming packets greater + * than 1518 (that is 1500 + 14 Ethernet + 4 FCS). + */ + maccr &= ~FTMAC100_MACCR_RX_FTL; + } + iowrite32(maccr, priv->base + FTMAC100_OFFSET_MACCR); + + netdev->mtu = mtu; + + return 0; +} + static const struct net_device_ops ftmac100_netdev_ops = { .ndo_open = ftmac100_open, .ndo_stop = ftmac100_stop, @@ -1044,6 +1068,7 @@ static const struct net_device_ops ftmac100_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, .ndo_eth_ioctl = ftmac100_do_ioctl, + .ndo_change_mtu = ftmac100_change_mtu, }; /****************************************************************************** @@ -1075,7 +1100,7 @@ static int ftmac100_probe(struct platform_device *pdev) SET_NETDEV_DEV(netdev, &pdev->dev); netdev->ethtool_ops = &ftmac100_ethtool_ops; netdev->netdev_ops = &ftmac100_netdev_ops; - netdev->max_mtu = MAX_PKT_SIZE; + netdev->max_mtu = MAX_PKT_SIZE - VLAN_ETH_HLEN; err = platform_get_ethdev_address(&pdev->dev, netdev); if (err == -EPROBE_DEFER) |