]> err.no Git - linux-2.6/blobdiff - drivers/net/ibm_newemac/core.c
ftrace: Documentation
[linux-2.6] / drivers / net / ibm_newemac / core.c
index e6c69f77259b1d3aa173715237b117f7e3ceae62..babc79ad490b6ada422a3ce96f9fefd510050b65 100644 (file)
@@ -43,6 +43,8 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/uaccess.h>
+#include <asm/dcr.h>
+#include <asm/dcr-regs.h>
 
 #include "core.h"
 
@@ -127,10 +129,35 @@ static struct device_node *emac_boot_list[EMAC_BOOT_LIST_SIZE];
 static inline void emac_report_timeout_error(struct emac_instance *dev,
                                             const char *error)
 {
-       if (net_ratelimit())
+       if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX |
+                                 EMAC_FTR_440EP_PHY_CLK_FIX))
+               DBG(dev, "%s" NL, error);
+       else if (net_ratelimit())
                printk(KERN_ERR "%s: %s\n", dev->ndev->name, error);
 }
 
+/* EMAC PHY clock workaround:
+ * 440EP/440GR has more sane SDR0_MFR register implementation than 440GX,
+ * which allows controlling each EMAC clock
+ */
+static inline void emac_rx_clk_tx(struct emac_instance *dev)
+{
+#ifdef CONFIG_PPC_DCR_NATIVE
+       if (emac_has_feature(dev, EMAC_FTR_440EP_PHY_CLK_FIX))
+               dcri_clrset(SDR0, SDR0_MFR,
+                           0, SDR0_MFR_ECS >> dev->cell_index);
+#endif
+}
+
+static inline void emac_rx_clk_default(struct emac_instance *dev)
+{
+#ifdef CONFIG_PPC_DCR_NATIVE
+       if (emac_has_feature(dev, EMAC_FTR_440EP_PHY_CLK_FIX))
+               dcri_clrset(SDR0, SDR0_MFR,
+                           SDR0_MFR_ECS >> dev->cell_index, 0);
+#endif
+}
+
 /* PHY polling intervals */
 #define PHY_POLL_LINK_ON       HZ
 #define PHY_POLL_LINK_OFF      (HZ / 5)
@@ -143,6 +170,10 @@ static inline void emac_report_timeout_error(struct emac_instance *dev,
 #define STOP_TIMEOUT_1000      13
 #define STOP_TIMEOUT_1000_JUMBO        73
 
+static unsigned char default_mcast_addr[] = {
+       0x01, 0x80, 0xC2, 0x00, 0x00, 0x01
+};
+
 /* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */
 static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = {
        "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum",
@@ -520,7 +551,10 @@ static int emac_configure(struct emac_instance *dev)
                rx_size = dev->rx_fifo_size_gige;
 
                if (dev->ndev->mtu > ETH_DATA_LEN) {
-                       mr1 |= EMAC_MR1_JPSM;
+                       if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+                               mr1 |= EMAC4_MR1_JPSM;
+                       else
+                               mr1 |= EMAC_MR1_JPSM;
                        dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO;
                } else
                        dev->stop_timeout = STOP_TIMEOUT_1000;
@@ -618,6 +652,9 @@ static int emac_configure(struct emac_instance *dev)
        if (emac_phy_gpcs(dev->phy.mode))
                emac_mii_reset_phy(&dev->phy);
 
+       /* Required for Pause packet support in EMAC */
+       dev_mc_add(ndev, default_mcast_addr, sizeof(default_mcast_addr), 1);
+
        return 0;
 }
 
@@ -701,7 +738,7 @@ static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg)
                rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);
 
        /* Wait for management interface to become idle */
-       n = 10;
+       n = 20;
        while (!emac_phy_done(dev, in_be32(&p->stacr))) {
                udelay(1);
                if (!--n) {
@@ -726,7 +763,7 @@ static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg)
        out_be32(&p->stacr, r);
 
        /* Wait for read to complete */
-       n = 100;
+       n = 200;
        while (!emac_phy_done(dev, (r = in_be32(&p->stacr)))) {
                udelay(1);
                if (!--n) {
@@ -773,7 +810,7 @@ static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg,
                rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);
 
        /* Wait for management interface to be idle */
-       n = 10;
+       n = 20;
        while (!emac_phy_done(dev, in_be32(&p->stacr))) {
                udelay(1);
                if (!--n) {
@@ -799,7 +836,7 @@ static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg,
        out_be32(&p->stacr, r);
 
        /* Wait for write to complete */
-       n = 100;
+       n = 200;
        while (!emac_phy_done(dev, in_be32(&p->stacr))) {
                udelay(1);
                if (!--n) {
@@ -1087,9 +1124,11 @@ static int emac_open(struct net_device *ndev)
                int link_poll_interval;
                if (dev->phy.def->ops->poll_link(&dev->phy)) {
                        dev->phy.def->ops->read_link(&dev->phy);
+                       emac_rx_clk_default(dev);
                        netif_carrier_on(dev->ndev);
                        link_poll_interval = PHY_POLL_LINK_ON;
                } else {
+                       emac_rx_clk_tx(dev);
                        netif_carrier_off(dev->ndev);
                        link_poll_interval = PHY_POLL_LINK_OFF;
                }
@@ -1167,6 +1206,7 @@ static void emac_link_timer(struct work_struct *work)
 
        if (dev->phy.def->ops->poll_link(&dev->phy)) {
                if (!netif_carrier_ok(dev->ndev)) {
+                       emac_rx_clk_default(dev);
                        /* Get new link parameters */
                        dev->phy.def->ops->read_link(&dev->phy);
 
@@ -1179,6 +1219,7 @@ static void emac_link_timer(struct work_struct *work)
                link_poll_interval = PHY_POLL_LINK_ON;
        } else {
                if (netif_carrier_ok(dev->ndev)) {
+                       emac_rx_clk_tx(dev);
                        netif_carrier_off(dev->ndev);
                        netif_tx_disable(dev->ndev);
                        emac_reinitialize(dev);
@@ -1235,8 +1276,8 @@ static int emac_close(struct net_device *ndev)
 static inline u16 emac_tx_csum(struct emac_instance *dev,
                               struct sk_buff *skb)
 {
-       if (emac_has_feature(dev, EMAC_FTR_HAS_TAH &&
-                            skb->ip_summed == CHECKSUM_PARTIAL)) {
+       if (emac_has_feature(dev, EMAC_FTR_HAS_TAH) &&
+               (skb->ip_summed == CHECKSUM_PARTIAL)) {
                ++dev->stats.tx_packets_csum;
                return EMAC_TX_CTRL_TAH_CSUM;
        }
@@ -1595,6 +1636,12 @@ static int emac_poll_rx(void *param, int budget)
                        goto next;
                }
 
+               if (len < ETH_HLEN) {
+                       ++dev->estats.rx_dropped_stack;
+                       emac_recycle_rx_skb(dev, slot, len);
+                       goto next;
+               }
+
                if (len && len < EMAC_RX_COPY_THRESH) {
                        struct sk_buff *copy_skb =
                            alloc_skb(len + EMAC_RX_SKB_HEADROOM + 2, GFP_ATOMIC);
@@ -2230,7 +2277,7 @@ static int __devinit emac_of_bus_notify(struct notifier_block *nb,
        return 0;
 }
 
-static struct notifier_block emac_of_bus_notifier = {
+static struct notifier_block emac_of_bus_notifier __devinitdata = {
        .notifier_call = emac_of_bus_notify
 };
 
@@ -2323,6 +2370,19 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
        dev->phy.mdio_read = emac_mdio_read;
        dev->phy.mdio_write = emac_mdio_write;
 
+       /* Enable internal clock source */
+#ifdef CONFIG_PPC_DCR_NATIVE
+       if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX))
+               dcri_clrset(SDR0, SDR0_MFR, 0, SDR0_MFR_ECS);
+#endif
+       /* PHY clock workaround */
+       emac_rx_clk_tx(dev);
+
+       /* Enable internal clock source on 440GX*/
+#ifdef CONFIG_PPC_DCR_NATIVE
+       if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX))
+               dcri_clrset(SDR0, SDR0_MFR, 0, SDR0_MFR_ECS);
+#endif
        /* Configure EMAC with defaults so we can at least use MDIO
         * This is needed mostly for 440GX
         */
@@ -2355,6 +2415,12 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
                        if (!emac_mii_phy_probe(&dev->phy, i))
                                break;
                }
+
+       /* Enable external clock source */
+#ifdef CONFIG_PPC_DCR_NATIVE
+       if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX))
+               dcri_clrset(SDR0, SDR0_MFR, SDR0_MFR_ECS, 0);
+#endif
        mutex_unlock(&emac_phy_map_lock);
        if (i == 0x20) {
                printk(KERN_WARNING "%s: can't find PHY!\n", np->full_name);
@@ -2480,8 +2546,15 @@ static int __devinit emac_init_config(struct emac_instance *dev)
        }
 
        /* Check EMAC version */
-       if (of_device_is_compatible(np, "ibm,emac4"))
+       if (of_device_is_compatible(np, "ibm,emac4")) {
                dev->features |= EMAC_FTR_EMAC4;
+               if (of_device_is_compatible(np, "ibm,emac-440gx"))
+                       dev->features |= EMAC_FTR_440GX_PHY_CLK_FIX;
+       } else {
+               if (of_device_is_compatible(np, "ibm,emac-440ep") ||
+                   of_device_is_compatible(np, "ibm,emac-440gr"))
+                       dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX;
+       }
 
        /* Fixup some feature bits based on the device tree */
        if (of_get_property(np, "has-inverted-stacr-oc", NULL))
@@ -2552,8 +2625,11 @@ static int __devinit emac_probe(struct of_device *ofdev,
        struct device_node **blist = NULL;
        int err, i;
 
-       /* Skip unused/unwired EMACS */
-       if (of_get_property(np, "unused", NULL))
+       /* Skip unused/unwired EMACS.  We leave the check for an unused
+        * property here for now, but new flat device trees should set a
+        * status property to "disabled" instead.
+        */
+       if (of_get_property(np, "unused", NULL) || !of_device_is_available(np))
                return -ENODEV;
 
        /* Find ourselves in the bootlist if we are there */
@@ -2649,6 +2725,8 @@ static int __devinit emac_probe(struct of_device *ofdev,
        /* Clean rings */
        memset(dev->tx_desc, 0, NUM_TX_BUFF * sizeof(struct mal_descriptor));
        memset(dev->rx_desc, 0, NUM_RX_BUFF * sizeof(struct mal_descriptor));
+       memset(dev->tx_skb, 0, NUM_TX_BUFF * sizeof(struct sk_buff *));
+       memset(dev->rx_skb, 0, NUM_RX_BUFF * sizeof(struct sk_buff *));
 
        /* Attach to ZMII, if needed */
        if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII) &&