[PATCH] skge: get rid of warning on race
[powerpc.git] / drivers / net / mv643xx_eth.c
index fb6b232..3cb9b3f 100644 (file)
@@ -39,6 +39,8 @@
 #include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/ethtool.h>
+#include <linux/platform_device.h>
+
 #include <asm/io.h>
 #include <asm/types.h>
 #include <asm/pgtable.h>
 
 #define INT_CAUSE_UNMASK_ALL           0x0007ffff
 #define INT_CAUSE_UNMASK_ALL_EXT       0x0011ffff
-#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK
 #define INT_CAUSE_MASK_ALL             0x00000000
+#define INT_CAUSE_MASK_ALL_EXT         0x00000000
 #define INT_CAUSE_CHECK_BITS           INT_CAUSE_UNMASK_ALL
 #define INT_CAUSE_CHECK_BITS_EXT       INT_CAUSE_UNMASK_ALL_EXT
-#endif
 
 #ifdef MV643XX_CHECKSUM_OFFLOAD_TX
 #define MAX_DESCS_PER_SKB      (MAX_SKB_FRAGS + 1)
@@ -95,7 +96,7 @@ static char mv643xx_driver_version[] = "1.0";
 static void __iomem *mv643xx_eth_shared_base;
 
 /* used to protect MV643XX_ETH_SMI_REG, which is shared across ports */
-static spinlock_t mv643xx_eth_phy_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(mv643xx_eth_phy_lock);
 
 static inline u32 mv_read(int offset)
 {
@@ -259,14 +260,13 @@ static void mv643xx_eth_update_mac_address(struct net_device *dev)
 static void mv643xx_eth_set_rx_mode(struct net_device *dev)
 {
        struct mv643xx_private *mp = netdev_priv(dev);
-       u32 config_reg;
 
-       config_reg = ethernet_get_config_reg(mp->port_num);
        if (dev->flags & IFF_PROMISC)
-               config_reg |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
+               mp->port_config |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
        else
-               config_reg &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
-       ethernet_set_config_reg(mp->port_num, config_reg);
+               mp->port_config &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
+
+       mv_write(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num), mp->port_config);
 }
 
 /*
@@ -369,15 +369,6 @@ static int mv643xx_eth_free_tx_queue(struct net_device *dev,
 
                        dev_kfree_skb_irq(pkt_info.return_info);
                        released = 0;
-
-                       /*
-                        * Decrement the number of outstanding skbs counter on
-                        * the TX queue.
-                        */
-                       if (mp->tx_ring_skbs == 0)
-                               panic("ERROR - TX outstanding SKBs"
-                                               " counter is corrupted");
-                       mp->tx_ring_skbs--;
                } else
                        dma_unmap_page(NULL, pkt_info.buf_ptr,
                                        pkt_info.byte_cnt, DMA_TO_DEVICE);
@@ -412,15 +403,13 @@ static int mv643xx_eth_receive_queue(struct net_device *dev)
        struct pkt_info pkt_info;
 
 #ifdef MV643XX_NAPI
-       while (eth_port_receive(mp, &pkt_info) == ETH_OK && budget > 0) {
+       while (budget-- > 0 && eth_port_receive(mp, &pkt_info) == ETH_OK) {
 #else
        while (eth_port_receive(mp, &pkt_info) == ETH_OK) {
 #endif
                mp->rx_ring_skbs--;
                received_packets++;
-#ifdef MV643XX_NAPI
-               budget--;
-#endif
+
                /* Update statistics. Note byte count includes 4 byte CRC count */
                stats->rx_packets++;
                stats->rx_bytes += pkt_info.byte_cnt;
@@ -1044,9 +1033,6 @@ static void mv643xx_tx(struct net_device *dev)
                                                DMA_TO_DEVICE);
 
                        dev_kfree_skb_irq(pkt_info.return_info);
-
-                       if (mp->tx_ring_skbs)
-                               mp->tx_ring_skbs--;
                } else
                        dma_unmap_page(NULL, pkt_info.buf_ptr,
                                        pkt_info.byte_cnt, DMA_TO_DEVICE);
@@ -1189,7 +1175,6 @@ linear:
                pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len,
                                                        DMA_TO_DEVICE);
                pkt_info.return_info = skb;
-               mp->tx_ring_skbs++;
                status = eth_port_send(mp, &pkt_info);
                if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
                        printk(KERN_ERR "%s: Error on transmitting packet\n",
@@ -1274,7 +1259,6 @@ linear:
                                pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT |
                                                        ETH_TX_LAST_DESC;
                                pkt_info.return_info = skb;
-                               mp->tx_ring_skbs++;
                        } else {
                                pkt_info.return_info = 0;
                        }
@@ -1311,7 +1295,6 @@ linear:
        pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len,
                                                                DMA_TO_DEVICE);
        pkt_info.return_info = skb;
-       mp->tx_ring_skbs++;
        status = eth_port_send(mp, &pkt_info);
        if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
                printk(KERN_ERR "%s: Error on transmitting packet\n",
@@ -1356,6 +1339,43 @@ static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev)
        return &mp->stats;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static inline void mv643xx_enable_irq(struct mv643xx_private *mp)
+{
+       int port_num = mp->port_num;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mp->lock, flags);
+       mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
+                                       INT_CAUSE_UNMASK_ALL);
+       mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
+                                       INT_CAUSE_UNMASK_ALL_EXT);
+       spin_unlock_irqrestore(&mp->lock, flags);
+}
+
+static inline void mv643xx_disable_irq(struct mv643xx_private *mp)
+{
+       int port_num = mp->port_num;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mp->lock, flags);
+       mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
+                                       INT_CAUSE_MASK_ALL);
+       mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
+                                       INT_CAUSE_MASK_ALL_EXT);
+       spin_unlock_irqrestore(&mp->lock, flags);
+}
+
+static void mv643xx_netpoll(struct net_device *netdev)
+{
+       struct mv643xx_private *mp = netdev_priv(netdev);
+
+       mv643xx_disable_irq(mp);
+       mv643xx_eth_int_handler(netdev->irq, netdev, NULL);
+       mv643xx_enable_irq(mp);
+}
+#endif
+
 /*/
  * mv643xx_eth_probe
  *
@@ -1367,9 +1387,8 @@ static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev)
  * Input :     struct device *
  * Output :    -ENOMEM if failed , 0 if success
  */
-static int mv643xx_eth_probe(struct device *ddev)
+static int mv643xx_eth_probe(struct platform_device *pdev)
 {
-       struct platform_device *pdev = to_platform_device(ddev);
        struct mv643xx_eth_platform_data *pd;
        int port_num = pdev->id;
        struct mv643xx_private *mp;
@@ -1382,7 +1401,7 @@ static int mv643xx_eth_probe(struct device *ddev)
        if (!dev)
                return -ENOMEM;
 
-       dev_set_drvdata(ddev, dev);
+       platform_set_drvdata(pdev, dev);
 
        mp = netdev_priv(dev);
 
@@ -1406,6 +1425,10 @@ static int mv643xx_eth_probe(struct device *ddev)
        dev->weight = 64;
 #endif
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = mv643xx_netpoll;
+#endif
+
        dev->watchdog_timeo = 2 * HZ;
        dev->tx_queue_len = mp->tx_ring_size;
        dev->base_addr = 0;
@@ -1511,6 +1534,9 @@ static int mv643xx_eth_probe(struct device *ddev)
        printk(KERN_NOTICE "%s: RX NAPI Enabled \n", dev->name);
 #endif
 
+       if (mp->tx_sram_size > 0)
+               printk(KERN_NOTICE "%s: Using SRAM\n", dev->name);
+
        return 0;
 
 out:
@@ -1519,21 +1545,20 @@ out:
        return err;
 }
 
-static int mv643xx_eth_remove(struct device *ddev)
+static int mv643xx_eth_remove(struct platform_device *pdev)
 {
-       struct net_device *dev = dev_get_drvdata(ddev);
+       struct net_device *dev = platform_get_drvdata(pdev);
 
        unregister_netdev(dev);
        flush_scheduled_work();
 
        free_netdev(dev);
-       dev_set_drvdata(ddev, NULL);
+       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
-static int mv643xx_eth_shared_probe(struct device *ddev)
+static int mv643xx_eth_shared_probe(struct platform_device *pdev)
 {
-       struct platform_device *pdev = to_platform_device(ddev);
        struct resource *res;
 
        printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n");
@@ -1551,7 +1576,7 @@ static int mv643xx_eth_shared_probe(struct device *ddev)
 
 }
 
-static int mv643xx_eth_shared_remove(struct device *ddev)
+static int mv643xx_eth_shared_remove(struct platform_device *pdev)
 {
        iounmap(mv643xx_eth_shared_base);
        mv643xx_eth_shared_base = NULL;
@@ -1559,18 +1584,20 @@ static int mv643xx_eth_shared_remove(struct device *ddev)
        return 0;
 }
 
-static struct device_driver mv643xx_eth_driver = {
-       .name = MV643XX_ETH_NAME,
-       .bus = &platform_bus_type,
+static struct platform_driver mv643xx_eth_driver = {
        .probe = mv643xx_eth_probe,
        .remove = mv643xx_eth_remove,
+       .driver = {
+               .name = MV643XX_ETH_NAME,
+       },
 };
 
-static struct device_driver mv643xx_eth_shared_driver = {
-       .name = MV643XX_ETH_SHARED_NAME,
-       .bus = &platform_bus_type,
+static struct platform_driver mv643xx_eth_shared_driver = {
        .probe = mv643xx_eth_shared_probe,
        .remove = mv643xx_eth_shared_remove,
+       .driver = {
+               .name = MV643XX_ETH_SHARED_NAME,
+       },
 };
 
 /*
@@ -1586,11 +1613,11 @@ static int __init mv643xx_init_module(void)
 {
        int rc;
 
-       rc = driver_register(&mv643xx_eth_shared_driver);
+       rc = platform_driver_register(&mv643xx_eth_shared_driver);
        if (!rc) {
-               rc = driver_register(&mv643xx_eth_driver);
+               rc = platform_driver_register(&mv643xx_eth_driver);
                if (rc)
-                       driver_unregister(&mv643xx_eth_shared_driver);
+                       platform_driver_unregister(&mv643xx_eth_shared_driver);
        }
        return rc;
 }
@@ -1606,8 +1633,8 @@ static int __init mv643xx_init_module(void)
  */
 static void __exit mv643xx_cleanup_module(void)
 {
-       driver_unregister(&mv643xx_eth_driver);
-       driver_unregister(&mv643xx_eth_shared_driver);
+       platform_driver_unregister(&mv643xx_eth_driver);
+       platform_driver_unregister(&mv643xx_eth_shared_driver);
 }
 
 module_init(mv643xx_init_module);
@@ -1883,6 +1910,9 @@ static void eth_port_start(struct mv643xx_private *mp)
        /* Enable port Rx. */
        mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
                                                mp->port_rx_queue_command);
+
+       /* Disable port bandwidth limits by clearing MTU register */
+       mv_write(MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port_num), 0);
 }
 
 /*
@@ -2292,34 +2322,6 @@ static void eth_port_reset(unsigned int port_num)
        mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), reg_data);
 }
 
-/*
- * ethernet_set_config_reg - Set specified bits in configuration register.
- *
- * DESCRIPTION:
- *     This function sets specified bits in the given ethernet
- *     configuration register.
- *
- * INPUT:
- *     unsigned int    eth_port_num    Ethernet Port number.
- *     unsigned int    value           32 bit value.
- *
- * OUTPUT:
- *     The set bits in the value parameter are set in the configuration
- *     register.
- *
- * RETURN:
- *     None.
- *
- */
-static void ethernet_set_config_reg(unsigned int eth_port_num,
-                                                       unsigned int value)
-{
-       unsigned int eth_config_reg;
-
-       eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num));
-       eth_config_reg |= value;
-       mv_write(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num), eth_config_reg);
-}
 
 static int eth_port_autoneg_supported(unsigned int eth_port_num)
 {
@@ -2345,31 +2347,6 @@ static int eth_port_link_is_up(unsigned int eth_port_num)
        return 0;
 }
 
-/*
- * ethernet_get_config_reg - Get the port configuration register
- *
- * DESCRIPTION:
- *     This function returns the configuration register value of the given
- *     ethernet port.
- *
- * INPUT:
- *     unsigned int    eth_port_num    Ethernet Port number.
- *
- * OUTPUT:
- *     None.
- *
- * RETURN:
- *     Port configuration register value.
- */
-static unsigned int ethernet_get_config_reg(unsigned int eth_port_num)
-{
-       unsigned int eth_config_reg;
-
-       eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_EXTEND_REG
-                                                               (eth_port_num));
-       return eth_config_reg;
-}
-
 /*
  * eth_port_read_smi_reg - Read PHY registers
  *
@@ -2528,6 +2505,9 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
                return ETH_ERROR;
        }
 
+       mp->tx_ring_skbs++;
+       BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
+
        /* Get the Tx Desc ring indexes */
        tx_desc_curr = mp->tx_curr_desc_q;
        tx_desc_used = mp->tx_used_desc_q;
@@ -2594,6 +2574,9 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
        if (mp->tx_resource_err)
                return ETH_QUEUE_FULL;
 
+       mp->tx_ring_skbs++;
+       BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
+
        /* Get the Tx Desc ring indexes */
        tx_desc_curr = mp->tx_curr_desc_q;
        tx_desc_used = mp->tx_used_desc_q;
@@ -2694,6 +2677,9 @@ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp,
        /* Any Tx return cancels the Tx resource error status */
        mp->tx_resource_err = 0;
 
+       BUG_ON(mp->tx_ring_skbs == 0);
+       mp->tx_ring_skbs--;
+
        return ETH_OK;
 }