summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/faraday/ftmac100.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/faraday/ftmac100.c')
-rw-r--r--drivers/net/ethernet/faraday/ftmac100.c65
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)