]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/faraday/ftgmac100.c
ftgmac100: Move ftgmac100_hard_start_xmit() around
[karo-tx-linux.git] / drivers / net / ethernet / faraday / ftgmac100.c
index 41e8467f272a104192f657c37ba7f9674e256c64..8231d972de1604aef864b21c52f092bfa8a2394f 100644 (file)
@@ -350,7 +350,7 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
        struct ftgmac100_rxdes *rxdes;
        struct sk_buff *skb;
        unsigned int pointer, size;
-       u32 status;
+       u32 status, csum_vlan;
        dma_addr_t map;
 
        /* Grab next RX descriptor */
@@ -372,10 +372,27 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
                     !(status & FTGMAC100_RXDES0_LRS)))
                goto drop;
 
+       /* Grab received size and csum vlan field in the descriptor */
+       size = status & FTGMAC100_RXDES0_VDBC;
+       csum_vlan = le32_to_cpu(rxdes->rxdes1);
+
        /* Any error (other than csum offload) flagged ? */
        if (unlikely(status & RXDES0_ANY_ERROR)) {
-               ftgmac100_rx_packet_error(priv, status);
-               goto drop;
+               /* Correct for incorrect flagging of runt packets
+                * with vlan tags... Just accept a runt packet that
+                * has been flagged as vlan and whose size is at
+                * least 60 bytes.
+                */
+               if ((status & FTGMAC100_RXDES0_RUNT) &&
+                   (csum_vlan & FTGMAC100_RXDES1_VLANTAG_AVAIL) &&
+                   (size >= 60))
+                       status &= ~FTGMAC100_RXDES0_RUNT;
+
+               /* Any error still in there ? */
+               if (status & RXDES0_ANY_ERROR) {
+                       ftgmac100_rx_packet_error(priv, status);
+                       goto drop;
+               }
        }
 
        /* If the packet had no skb (failed to allocate earlier)
@@ -397,19 +414,17 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
         * we accept the HW test results.
         */
        if (netdev->features & NETIF_F_RXCSUM) {
-               __le32 csum_vlan = rxdes->rxdes1;
-               __le32 err_bits = cpu_to_le32(FTGMAC100_RXDES1_TCP_CHKSUM_ERR |
-                                             FTGMAC100_RXDES1_UDP_CHKSUM_ERR |
-                                             FTGMAC100_RXDES1_IP_CHKSUM_ERR);
+               u32 err_bits = FTGMAC100_RXDES1_TCP_CHKSUM_ERR |
+                       FTGMAC100_RXDES1_UDP_CHKSUM_ERR |
+                       FTGMAC100_RXDES1_IP_CHKSUM_ERR;
                if ((csum_vlan & err_bits) ||
-                   !(csum_vlan & cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)))
+                   !(csum_vlan & FTGMAC100_RXDES1_PROT_MASK))
                        skb->ip_summed = CHECKSUM_NONE;
                else
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
        }
 
-       /* Grab received size annd transfer to skb */
-       size = status & FTGMAC100_RXDES0_VDBC;
+       /* Transfer received size to skb */
        skb_put(skb, size);
 
        /* Tear down DMA mapping, do necessary cache management */
@@ -660,6 +675,35 @@ static int ftgmac100_xmit(struct ftgmac100 *priv, struct sk_buff *skb,
        return NETDEV_TX_OK;
 }
 
+static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
+                                    struct net_device *netdev)
+{
+       struct ftgmac100 *priv = netdev_priv(netdev);
+       dma_addr_t map;
+
+       if (unlikely(skb->len > MAX_PKT_SIZE)) {
+               if (net_ratelimit())
+                       netdev_dbg(netdev, "tx packet too big\n");
+
+               netdev->stats.tx_dropped++;
+               kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
+       if (unlikely(dma_mapping_error(priv->dev, map))) {
+               /* drop packet */
+               if (net_ratelimit())
+                       netdev_err(netdev, "map socket buffer failed\n");
+
+               netdev->stats.tx_dropped++;
+               kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       return ftgmac100_xmit(priv, skb, map);
+}
+
 static void ftgmac100_free_buffers(struct ftgmac100 *priv)
 {
        int i;
@@ -1197,35 +1241,6 @@ static int ftgmac100_stop(struct net_device *netdev)
        return 0;
 }
 
-static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
-                                    struct net_device *netdev)
-{
-       struct ftgmac100 *priv = netdev_priv(netdev);
-       dma_addr_t map;
-
-       if (unlikely(skb->len > MAX_PKT_SIZE)) {
-               if (net_ratelimit())
-                       netdev_dbg(netdev, "tx packet too big\n");
-
-               netdev->stats.tx_dropped++;
-               kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
-
-       map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
-       if (unlikely(dma_mapping_error(priv->dev, map))) {
-               /* drop packet */
-               if (net_ratelimit())
-                       netdev_err(netdev, "map socket buffer failed\n");
-
-               netdev->stats.tx_dropped++;
-               kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
-
-       return ftgmac100_xmit(priv, skb, map);
-}
-
 /* optional */
 static int ftgmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 {
@@ -1235,6 +1250,17 @@ static int ftgmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int
        return phy_mii_ioctl(netdev->phydev, ifr, cmd);
 }
 
+static void ftgmac100_tx_timeout(struct net_device *netdev)
+{
+       struct ftgmac100 *priv = netdev_priv(netdev);
+
+       /* Disable all interrupts */
+       iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
+
+       /* Do the reset outside of interrupt context */
+       schedule_work(&priv->reset_task);
+}
+
 static const struct net_device_ops ftgmac100_netdev_ops = {
        .ndo_open               = ftgmac100_open,
        .ndo_stop               = ftgmac100_stop,
@@ -1242,6 +1268,7 @@ static const struct net_device_ops ftgmac100_netdev_ops = {
        .ndo_set_mac_address    = ftgmac100_set_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_do_ioctl           = ftgmac100_do_ioctl,
+       .ndo_tx_timeout         = ftgmac100_tx_timeout,
 };
 
 static int ftgmac100_setup_mdio(struct net_device *netdev)
@@ -1346,6 +1373,7 @@ static int ftgmac100_probe(struct platform_device *pdev)
 
        netdev->ethtool_ops = &ftgmac100_ethtool_ops;
        netdev->netdev_ops = &ftgmac100_netdev_ops;
+       netdev->watchdog_timeo = 5 * HZ;
 
        platform_set_drvdata(pdev, netdev);