diff options
Diffstat (limited to 'drivers/net/ethernet/ibm/emac/core.c')
| -rw-r--r-- | drivers/net/ethernet/ibm/emac/core.c | 124 |
1 files changed, 84 insertions, 40 deletions
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c index 2abce965c7b..87bd953cc2e 100644 --- a/drivers/net/ethernet/ibm/emac/core.c +++ b/drivers/net/ethernet/ibm/emac/core.c @@ -1,5 +1,5 @@ /* - * drivers/net/ibm_newemac/core.c + * drivers/net/ethernet/ibm/emac/core.c * * Driver for PowerPC 4xx on-chip ethernet controller. * @@ -39,6 +39,8 @@ #include <linux/bitops.h> #include <linux/workqueue.h> #include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_net.h> #include <linux/slab.h> @@ -359,10 +361,26 @@ static int emac_reset(struct emac_instance *dev) } #ifdef CONFIG_PPC_DCR_NATIVE - /* Enable internal clock source */ - if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) - dcri_clrset(SDR0, SDR0_ETH_CFG, - 0, SDR0_ETH_CFG_ECS << dev->cell_index); + /* + * PPC460EX/GT Embedded Processor Advanced User's Manual + * section 28.10.1 Mode Register 0 (EMACx_MR0) states: + * Note: The PHY must provide a TX Clk in order to perform a soft reset + * of the EMAC. If none is present, select the internal clock + * (SDR0_ETH_CFG[EMACx_PHY_CLK] = 1). + * After a soft reset, select the external clock. + */ + if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) { + if (dev->phy_address == 0xffffffff && + dev->phy_map == 0xffffffff) { + /* No PHY: select internal loop clock before reset */ + dcri_clrset(SDR0, SDR0_ETH_CFG, + 0, SDR0_ETH_CFG_ECS << dev->cell_index); + } else { + /* PHY present: select external clock before reset */ + dcri_clrset(SDR0, SDR0_ETH_CFG, + SDR0_ETH_CFG_ECS << dev->cell_index, 0); + } + } #endif out_be32(&p->mr0, EMAC_MR0_SRST); @@ -370,10 +388,14 @@ static int emac_reset(struct emac_instance *dev) --n; #ifdef CONFIG_PPC_DCR_NATIVE - /* Enable external clock source */ - if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) - dcri_clrset(SDR0, SDR0_ETH_CFG, - SDR0_ETH_CFG_ECS << dev->cell_index, 0); + if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) { + if (dev->phy_address == 0xffffffff && + dev->phy_map == 0xffffffff) { + /* No PHY: restore external clock source after reset */ + dcri_clrset(SDR0, SDR0_ETH_CFG, + SDR0_ETH_CFG_ECS << dev->cell_index, 0); + } + } #endif if (n) { @@ -434,6 +456,11 @@ static inline u32 emac_iff2rmr(struct net_device *ndev) else if (!netdev_mc_empty(ndev)) r |= EMAC_RMR_MAE; + if (emac_has_feature(dev, EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE)) { + r &= ~EMAC4_RMR_MJS_MASK; + r |= EMAC4_RMR_MJS(ndev->mtu); + } + return r; } @@ -965,6 +992,7 @@ static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu) int rx_sync_size = emac_rx_sync_size(new_mtu); int rx_skb_size = emac_rx_skb_size(new_mtu); int i, ret = 0; + int mr1_jumbo_bit_change = 0; mutex_lock(&dev->link_lock); emac_netif_stop(dev); @@ -1013,7 +1041,15 @@ static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu) } skip: /* Check if we need to change "Jumbo" bit in MR1 */ - if ((new_mtu > ETH_DATA_LEN) ^ (dev->ndev->mtu > ETH_DATA_LEN)) { + if (emac_has_feature(dev, EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE)) { + mr1_jumbo_bit_change = (new_mtu > ETH_DATA_LEN) || + (dev->ndev->mtu > ETH_DATA_LEN); + } else { + mr1_jumbo_bit_change = (new_mtu > ETH_DATA_LEN) ^ + (dev->ndev->mtu > ETH_DATA_LEN); + } + + if (mr1_jumbo_bit_change) { /* This is to prevent starting RX channel in emac_rx_enable() */ set_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags); @@ -2176,11 +2212,10 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev, { struct emac_instance *dev = netdev_priv(ndev); - strcpy(info->driver, "ibm_emac"); - strcpy(info->version, DRV_VERSION); - info->fw_version[0] = '\0'; - sprintf(info->bus_info, "PPC 4xx EMAC-%d %s", - dev->cell_index, dev->ofdev->dev.of_node->full_name); + strlcpy(info->driver, "ibm_emac", sizeof(info->driver)); + strlcpy(info->version, DRV_VERSION, sizeof(info->version)); + snprintf(info->bus_info, sizeof(info->bus_info), "PPC 4xx EMAC-%d %s", + dev->cell_index, dev->ofdev->dev.of_node->full_name); info->regdump_len = emac_ethtool_get_regs_len(ndev); } @@ -2247,8 +2282,8 @@ struct emac_depentry { #define EMAC_DEP_PREV_IDX 5 #define EMAC_DEP_COUNT 6 -static int __devinit emac_check_deps(struct emac_instance *dev, - struct emac_depentry *deps) +static int emac_check_deps(struct emac_instance *dev, + struct emac_depentry *deps) { int i, there = 0; struct device_node *np; @@ -2279,7 +2314,7 @@ static int __devinit emac_check_deps(struct emac_instance *dev, if (deps[i].ofdev == NULL) continue; if (deps[i].drvdata == NULL) - deps[i].drvdata = dev_get_drvdata(&deps[i].ofdev->dev); + deps[i].drvdata = platform_get_drvdata(deps[i].ofdev); if (deps[i].drvdata != NULL) there++; } @@ -2300,8 +2335,8 @@ static void emac_put_deps(struct emac_instance *dev) of_dev_put(dev->tah_dev); } -static int __devinit emac_of_bus_notify(struct notifier_block *nb, - unsigned long action, void *data) +static int emac_of_bus_notify(struct notifier_block *nb, unsigned long action, + void *data) { /* We are only intereted in device addition */ if (action == BUS_NOTIFY_BOUND_DRIVER) @@ -2309,11 +2344,11 @@ static int __devinit emac_of_bus_notify(struct notifier_block *nb, return 0; } -static struct notifier_block emac_of_bus_notifier __devinitdata = { +static struct notifier_block emac_of_bus_notifier = { .notifier_call = emac_of_bus_notify }; -static int __devinit emac_wait_deps(struct emac_instance *dev) +static int emac_wait_deps(struct emac_instance *dev) { struct emac_depentry deps[EMAC_DEP_COUNT]; int i, err; @@ -2353,8 +2388,8 @@ static int __devinit emac_wait_deps(struct emac_instance *dev) return err; } -static int __devinit emac_read_uint_prop(struct device_node *np, const char *name, - u32 *val, int fatal) +static int emac_read_uint_prop(struct device_node *np, const char *name, + u32 *val, int fatal) { int len; const u32 *prop = of_get_property(np, name, &len); @@ -2368,7 +2403,7 @@ static int __devinit emac_read_uint_prop(struct device_node *np, const char *nam return 0; } -static int __devinit emac_init_phy(struct emac_instance *dev) +static int emac_init_phy(struct emac_instance *dev) { struct device_node *np = dev->ofdev->dev.of_node; struct net_device *ndev = dev->ndev; @@ -2471,6 +2506,7 @@ static int __devinit emac_init_phy(struct emac_instance *dev) /* Disable any PHY features not supported by the platform */ dev->phy.def->features &= ~dev->phy_feat_exc; + dev->phy.features &= ~dev->phy_feat_exc; /* Setup initial link parameters */ if (dev->phy.features & SUPPORTED_Autoneg) { @@ -2503,7 +2539,7 @@ static int __devinit emac_init_phy(struct emac_instance *dev) return 0; } -static int __devinit emac_init_config(struct emac_instance *dev) +static int emac_init_config(struct emac_instance *dev) { struct device_node *np = dev->ofdev->dev.of_node; const void *p; @@ -2568,6 +2604,11 @@ static int __devinit emac_init_config(struct emac_instance *dev) if (of_device_is_compatible(np, "ibm,emac-405ex") || of_device_is_compatible(np, "ibm,emac-405exr")) dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX; + if (of_device_is_compatible(np, "ibm,emac-apm821xx")) { + dev->features |= (EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE | + EMAC_FTR_APM821XX_NO_HALF_DUPLEX | + EMAC_FTR_460EX_PHY_CLK_FIX); + } } else if (of_device_is_compatible(np, "ibm,emac4")) { dev->features |= EMAC_FTR_EMAC4; if (of_device_is_compatible(np, "ibm,emac-440gx")) @@ -2637,7 +2678,7 @@ static int __devinit emac_init_config(struct emac_instance *dev) np->full_name); return -ENXIO; } - memcpy(dev->ndev->dev_addr, p, 6); + memcpy(dev->ndev->dev_addr, p, ETH_ALEN); /* IAHT and GAHT filter parameterization */ if (emac_has_feature(dev, EMAC_FTR_EMAC4SYNC)) { @@ -2683,7 +2724,7 @@ static const struct net_device_ops emac_gige_netdev_ops = { .ndo_change_mtu = emac_change_mtu, }; -static int __devinit emac_probe(struct platform_device *ofdev) +static int emac_probe(struct platform_device *ofdev) { struct net_device *ndev; struct emac_instance *dev; @@ -2706,11 +2747,9 @@ static int __devinit emac_probe(struct platform_device *ofdev) /* Allocate our net_device structure */ err = -ENOMEM; ndev = alloc_etherdev(sizeof(struct emac_instance)); - if (!ndev) { - printk(KERN_ERR "%s: could not allocate ethernet device!\n", - np->full_name); + if (!ndev) goto err_gone; - } + dev = netdev_priv(ndev); dev->ndev = ndev; dev->ofdev = ofdev; @@ -2762,9 +2801,9 @@ static int __devinit emac_probe(struct platform_device *ofdev) /* display more info about what's missing ? */ goto err_reg_unmap; } - dev->mal = dev_get_drvdata(&dev->mal_dev->dev); + dev->mal = platform_get_drvdata(dev->mal_dev); if (dev->mdio_dev != NULL) - dev->mdio_instance = dev_get_drvdata(&dev->mdio_dev->dev); + dev->mdio_instance = platform_get_drvdata(dev->mdio_dev); /* Register with MAL */ dev->commac.ops = &emac_commac_ops; @@ -2818,6 +2857,13 @@ static int __devinit emac_probe(struct platform_device *ofdev) dev->stop_timeout = STOP_TIMEOUT_100; INIT_DELAYED_WORK(&dev->link_work, emac_link_timer); + /* Some SoCs like APM821xx does not support Half Duplex mode. */ + if (emac_has_feature(dev, EMAC_FTR_APM821XX_NO_HALF_DUPLEX)) { + dev->phy_feat_exc = (SUPPORTED_1000baseT_Half | + SUPPORTED_100baseT_Half | + SUPPORTED_10baseT_Half); + } + /* Find PHY if any */ err = emac_init_phy(dev); if (err != 0) @@ -2833,7 +2879,7 @@ static int __devinit emac_probe(struct platform_device *ofdev) dev->commac.ops = &emac_commac_sg_ops; } else ndev->netdev_ops = &emac_netdev_ops; - SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops); + ndev->ethtool_ops = &emac_ethtool_ops; netif_carrier_off(ndev); @@ -2848,7 +2894,7 @@ static int __devinit emac_probe(struct platform_device *ofdev) * fully initialized */ wmb(); - dev_set_drvdata(&ofdev->dev, dev); + platform_set_drvdata(ofdev, dev); /* There's a new kid in town ! Let's tell everybody */ wake_up_all(&emac_probe_wait); @@ -2905,14 +2951,12 @@ static int __devinit emac_probe(struct platform_device *ofdev) return err; } -static int __devexit emac_remove(struct platform_device *ofdev) +static int emac_remove(struct platform_device *ofdev) { - struct emac_instance *dev = dev_get_drvdata(&ofdev->dev); + struct emac_instance *dev = platform_get_drvdata(ofdev); DBG(dev, "remove" NL); - dev_set_drvdata(&ofdev->dev, NULL); - unregister_netdev(dev->ndev); cancel_work_sync(&dev->reset_work); |
