summaryrefslogtreecommitdiff
path: root/drivers/net/ibm_newemac
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ibm_newemac')
-rw-r--r--drivers/net/ibm_newemac/core.c83
-rw-r--r--drivers/net/ibm_newemac/core.h14
-rw-r--r--drivers/net/ibm_newemac/mal.c20
-rw-r--r--drivers/net/ibm_newemac/rgmii.c2
-rw-r--r--drivers/net/ibm_newemac/tah.c2
-rw-r--r--drivers/net/ibm_newemac/zmii.c2
6 files changed, 105 insertions, 18 deletions
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 378a23963495..5d2108c5ac7c 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -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)
@@ -524,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;
@@ -708,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) {
@@ -733,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) {
@@ -780,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) {
@@ -806,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) {
@@ -1094,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;
}
@@ -1174,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);
@@ -1186,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);
@@ -2237,7 +2271,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
};
@@ -2330,6 +2364,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
*/
@@ -2362,6 +2409,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);
@@ -2487,8 +2540,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))
@@ -2559,8 +2619,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 */
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h
index 4e74d8287c65..1683db9870a4 100644
--- a/drivers/net/ibm_newemac/core.h
+++ b/drivers/net/ibm_newemac/core.h
@@ -301,6 +301,14 @@ struct emac_instance {
* Set if we have new type STACR with STAOPC
*/
#define EMAC_FTR_HAS_NEW_STACR 0x00000040
+/*
+ * Set if we need phy clock workaround for 440gx
+ */
+#define EMAC_FTR_440GX_PHY_CLK_FIX 0x00000080
+/*
+ * Set if we need phy clock workaround for 440ep or 440gr
+ */
+#define EMAC_FTR_440EP_PHY_CLK_FIX 0x00000100
/* Right now, we don't quite handle the always/possible masks on the
@@ -312,8 +320,8 @@ enum {
EMAC_FTRS_POSSIBLE =
#ifdef CONFIG_IBM_NEW_EMAC_EMAC4
- EMAC_FTR_EMAC4 | EMAC_FTR_HAS_NEW_STACR |
- EMAC_FTR_STACR_OC_INVERT |
+ EMAC_FTR_EMAC4 | EMAC_FTR_HAS_NEW_STACR |
+ EMAC_FTR_STACR_OC_INVERT | EMAC_FTR_440GX_PHY_CLK_FIX |
#endif
#ifdef CONFIG_IBM_NEW_EMAC_TAH
EMAC_FTR_HAS_TAH |
@@ -324,7 +332,7 @@ enum {
#ifdef CONFIG_IBM_NEW_EMAC_RGMII
EMAC_FTR_HAS_RGMII |
#endif
- 0,
+ EMAC_FTR_440EP_PHY_CLK_FIX,
};
static inline int emac_has_feature(struct emac_instance *dev,
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c
index 6869f08c9dcb..10c267b2b961 100644
--- a/drivers/net/ibm_newemac/mal.c
+++ b/drivers/net/ibm_newemac/mal.c
@@ -61,8 +61,8 @@ int __devinit mal_register_commac(struct mal_instance *mal,
return 0;
}
-void __devexit mal_unregister_commac(struct mal_instance *mal,
- struct mal_commac *commac)
+void mal_unregister_commac(struct mal_instance *mal,
+ struct mal_commac *commac)
{
unsigned long flags;
@@ -136,6 +136,14 @@ void mal_enable_rx_channel(struct mal_instance *mal, int channel)
{
unsigned long flags;
+ /*
+ * On some 4xx PPC's (e.g. 460EX/GT), the rx channel is a multiple
+ * of 8, but enabling in MAL_RXCASR needs the divided by 8 value
+ * for the bitmask
+ */
+ if (!(channel % 8))
+ channel >>= 3;
+
spin_lock_irqsave(&mal->lock, flags);
MAL_DBG(mal, "enable_rx(%d)" NL, channel);
@@ -148,6 +156,14 @@ void mal_enable_rx_channel(struct mal_instance *mal, int channel)
void mal_disable_rx_channel(struct mal_instance *mal, int channel)
{
+ /*
+ * On some 4xx PPC's (e.g. 460EX/GT), the rx channel is a multiple
+ * of 8, but enabling in MAL_RXCASR needs the divided by 8 value
+ * for the bitmask
+ */
+ if (!(channel % 8))
+ channel >>= 3;
+
set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel));
MAL_DBG(mal, "disable_rx(%d)" NL, channel);
diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ibm_newemac/rgmii.c
index 5757788227be..e32da3de2695 100644
--- a/drivers/net/ibm_newemac/rgmii.c
+++ b/drivers/net/ibm_newemac/rgmii.c
@@ -179,7 +179,7 @@ void rgmii_put_mdio(struct of_device *ofdev, int input)
mutex_unlock(&dev->lock);
}
-void __devexit rgmii_detach(struct of_device *ofdev, int input)
+void rgmii_detach(struct of_device *ofdev, int input)
{
struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
struct rgmii_regs __iomem *p = dev->base;
diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ibm_newemac/tah.c
index b023d10d7e1c..30173a9fb557 100644
--- a/drivers/net/ibm_newemac/tah.c
+++ b/drivers/net/ibm_newemac/tah.c
@@ -35,7 +35,7 @@ int __devinit tah_attach(struct of_device *ofdev, int channel)
return 0;
}
-void __devexit tah_detach(struct of_device *ofdev, int channel)
+void tah_detach(struct of_device *ofdev, int channel)
{
struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
diff --git a/drivers/net/ibm_newemac/zmii.c b/drivers/net/ibm_newemac/zmii.c
index 2ea472aeab06..17b154124943 100644
--- a/drivers/net/ibm_newemac/zmii.c
+++ b/drivers/net/ibm_newemac/zmii.c
@@ -189,7 +189,7 @@ void zmii_set_speed(struct of_device *ofdev, int input, int speed)
mutex_unlock(&dev->lock);
}
-void __devexit zmii_detach(struct of_device *ofdev, int input)
+void zmii_detach(struct of_device *ofdev, int input)
{
struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);