diff options
50 files changed, 3417 insertions, 112 deletions
@@ -1856,7 +1856,7 @@ E: rfkoenig@immd4.informatik.uni-erlangen.de D: The Linux Support Team Erlangen N: Andreas Koensgen -E: ajk@iehk.rwth-aachen.de +E: ajk@comnets.uni-bremen.de D: 6pack driver for AX.25 N: Harald Koerfgen diff --git a/Documentation/RCU/rculist_nulls.txt b/Documentation/RCU/rculist_nulls.txt index 93cb28d05dc..18f9651ff23 100644 --- a/Documentation/RCU/rculist_nulls.txt +++ b/Documentation/RCU/rculist_nulls.txt @@ -83,11 +83,12 @@ not detect it missed following items in original chain. obj = kmem_cache_alloc(...); lock_chain(); // typically a spin_lock() obj->key = key; -atomic_inc(&obj->refcnt); /* * we need to make sure obj->key is updated before obj->next + * or obj->refcnt */ smp_wmb(); +atomic_set(&obj->refcnt, 1); hlist_add_head_rcu(&obj->obj_node, list); unlock_chain(); // typically a spin_unlock() @@ -159,6 +160,10 @@ out: obj = kmem_cache_alloc(cachep); lock_chain(); // typically a spin_lock() obj->key = key; +/* + * changes to obj->key must be visible before refcnt one + */ +smp_wmb(); atomic_set(&obj->refcnt, 1); /* * insert obj in RCU way (readers might be traversing chain) diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c index f688eba8770..6a5be5d5c8e 100644 --- a/Documentation/connector/cn_test.c +++ b/Documentation/connector/cn_test.c @@ -1,7 +1,7 @@ /* * cn_test.c * - * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru> + * 2004+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net> * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -194,5 +194,5 @@ module_init(cn_test_init); module_exit(cn_test_fini); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); +MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>"); MODULE_DESCRIPTION("Connector's test module"); diff --git a/Documentation/connector/ucon.c b/Documentation/connector/ucon.c index d738cde2a8d..c5092ad0ce4 100644 --- a/Documentation/connector/ucon.c +++ b/Documentation/connector/ucon.c @@ -1,7 +1,7 @@ /* * ucon.c * - * Copyright (c) 2004+ Evgeniy Polyakov <johnpol@2ka.mipt.ru> + * Copyright (c) 2004+ Evgeniy Polyakov <zbr@ioremap.net> * * * This program is free software; you can redistribute it and/or modify diff --git a/Documentation/networking/6pack.txt b/Documentation/networking/6pack.txt index d0777a1200e..8f339428fdf 100644 --- a/Documentation/networking/6pack.txt +++ b/Documentation/networking/6pack.txt @@ -1,7 +1,7 @@ This is the 6pack-mini-HOWTO, written by Andreas Könsgen DG3KQ -Internet: ajk@iehk.rwth-aachen.de +Internet: ajk@comnets.uni-bremen.de AMPR-net: dg3kq@db0pra.ampr.org AX.25: dg3kq@db0ach.#nrw.deu.eu diff --git a/MAINTAINERS b/MAINTAINERS index 18c3f0c41c9..ebc269152fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -150,7 +150,7 @@ F: drivers/scsi/53c700* 6PACK NETWORK DRIVER FOR AX.25 P: Andreas Koensgen -M: ajk@iehk.rwth-aachen.de +M: ajk@comnets.uni-bremen.de L: linux-hams@vger.kernel.org S: Maintained F: drivers/net/hamradio/6pack.c @@ -1612,6 +1612,13 @@ S: Supported F: fs/configfs/ F: include/linux/configfs.h +CONNECTOR +P: Evgeniy Polyakov +M: zbr@ioremap.net +L: netdev@vger.kernel.org +S: Maintained +F: drivers/connector/ + CONTROL GROUPS (CGROUPS) P: Paul Menage M: menage@google.com @@ -4089,6 +4096,7 @@ L: netfilter@vger.kernel.org L: coreteam@netfilter.org W: http://www.netfilter.org/ W: http://www.iptables.org/ +T: git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-2.6.git S: Supported F: include/linux/netfilter* F: include/linux/netfilter/ @@ -5586,7 +5594,6 @@ S: Odd Fixes F: drivers/net/starfire* STARMODE RADIO IP (STRIP) PROTOCOL DRIVER -W: http://mosquitonet.Stanford.EDU/strip.html S: Orphan F: drivers/net/wireless/strip.c F: include/linux/if_strip.h diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index c769ef269fb..408c2af25d5 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -1,7 +1,7 @@ /* * cn_queue.c * - * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru> + * 2004+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net> * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index fd336c5a905..08b2500f21e 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -1,7 +1,7 @@ /* * connector.c * - * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru> + * 2004+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net> * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -33,7 +33,7 @@ #include <net/sock.h> MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); +MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>"); MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector."); static u32 cn_idx = CN_IDX_CONNECTOR; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c155bd3ec9f..b5a7513df4e 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1729,6 +1729,12 @@ config KS8842 help This platform driver is for Micrel KSZ8842 chip. +config KS8851 + tristate "Micrel KS8851 SPI" + depends on SPI + help + SPI driver for Micrel KS8851 SPI attached network chip. + config VIA_RHINE tristate "VIA Rhine support" depends on NET_PCI && PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4b58a59f211..ead8cab3cfe 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -88,6 +88,7 @@ obj-$(CONFIG_SKGE) += skge.o obj-$(CONFIG_SKY2) += sky2.o obj-$(CONFIG_SKFP) += skfp/ obj-$(CONFIG_KS8842) += ks8842.o +obj-$(CONFIG_KS8851) += ks8851.o obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig index 2895db13bfa..c37ee9e6b67 100644 --- a/drivers/net/arm/Kconfig +++ b/drivers/net/arm/Kconfig @@ -63,3 +63,11 @@ config IXP4XX_ETH help Say Y here if you want to use built-in Ethernet ports on IXP4xx processor. + +config W90P910_ETH + tristate "Nuvoton w90p910 Ethernet support" + depends on ARM && ARCH_W90X900 + select PHYLIB + help + Say Y here if you want to use built-in Ethernet ports + on w90p910 processor. diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile index 811a3ccd14c..303171f589e 100644 --- a/drivers/net/arm/Makefile +++ b/drivers/net/arm/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o obj-$(CONFIG_ARM_KS8695_ETHER) += ks8695net.o obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o obj-$(CONFIG_IXP4XX_ETH) += ixp4xx_eth.o +obj-$(CONFIG_W90P910_ETH) += w90p910_ether.o diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c new file mode 100644 index 00000000000..616fb7985a3 --- /dev/null +++ b/drivers/net/arm/w90p910_ether.c @@ -0,0 +1,1105 @@ +/* + * Copyright (c) 2008-2009 Nuvoton technology corporation. + * + * Wan ZongShun <mcuos.com@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation;version 2 of the License. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/mii.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/ethtool.h> +#include <linux/platform_device.h> +#include <linux/clk.h> + +#define DRV_MODULE_NAME "w90p910-emc" +#define DRV_MODULE_VERSION "0.1" + +/* Ethernet MAC Registers */ +#define REG_CAMCMR 0x00 +#define REG_CAMEN 0x04 +#define REG_CAMM_BASE 0x08 +#define REG_CAML_BASE 0x0c +#define REG_TXDLSA 0x88 +#define REG_RXDLSA 0x8C +#define REG_MCMDR 0x90 +#define REG_MIID 0x94 +#define REG_MIIDA 0x98 +#define REG_FFTCR 0x9C +#define REG_TSDR 0xa0 +#define REG_RSDR 0xa4 +#define REG_DMARFC 0xa8 +#define REG_MIEN 0xac +#define REG_MISTA 0xb0 +#define REG_CTXDSA 0xcc +#define REG_CTXBSA 0xd0 +#define REG_CRXDSA 0xd4 +#define REG_CRXBSA 0xd8 + +/* mac controller bit */ +#define MCMDR_RXON 0x01 +#define MCMDR_ACP (0x01 << 3) +#define MCMDR_SPCRC (0x01 << 5) +#define MCMDR_TXON (0x01 << 8) +#define MCMDR_FDUP (0x01 << 18) +#define MCMDR_ENMDC (0x01 << 19) +#define MCMDR_OPMOD (0x01 << 20) +#define SWR (0x01 << 24) + +/* cam command regiser */ +#define CAMCMR_AUP 0x01 +#define CAMCMR_AMP (0x01 << 1) +#define CAMCMR_ABP (0x01 << 2) +#define CAMCMR_CCAM (0x01 << 3) +#define CAMCMR_ECMP (0x01 << 4) +#define CAM0EN 0x01 + +/* mac mii controller bit */ +#define MDCCR (0x0a << 20) +#define PHYAD (0x01 << 8) +#define PHYWR (0x01 << 16) +#define PHYBUSY (0x01 << 17) +#define PHYPRESP (0x01 << 18) +#define CAM_ENTRY_SIZE 0x08 + +/* rx and tx status */ +#define TXDS_TXCP (0x01 << 19) +#define RXDS_CRCE (0x01 << 17) +#define RXDS_PTLE (0x01 << 19) +#define RXDS_RXGD (0x01 << 20) +#define RXDS_ALIE (0x01 << 21) +#define RXDS_RP (0x01 << 22) + +/* mac interrupt status*/ +#define MISTA_EXDEF (0x01 << 19) +#define MISTA_TXBERR (0x01 << 24) +#define MISTA_TDU (0x01 << 23) +#define MISTA_RDU (0x01 << 10) +#define MISTA_RXBERR (0x01 << 11) + +#define ENSTART 0x01 +#define ENRXINTR 0x01 +#define ENRXGD (0x01 << 4) +#define ENRXBERR (0x01 << 11) +#define ENTXINTR (0x01 << 16) +#define ENTXCP (0x01 << 18) +#define ENTXABT (0x01 << 21) +#define ENTXBERR (0x01 << 24) +#define ENMDC (0x01 << 19) +#define PHYBUSY (0x01 << 17) +#define MDCCR_VAL 0xa00000 + +/* rx and tx owner bit */ +#define RX_OWEN_DMA (0x01 << 31) +#define RX_OWEN_CPU (~(0x03 << 30)) +#define TX_OWEN_DMA (0x01 << 31) +#define TX_OWEN_CPU (~(0x01 << 31)) + +/* tx frame desc controller bit */ +#define MACTXINTEN 0x04 +#define CRCMODE 0x02 +#define PADDINGMODE 0x01 + +/* fftcr controller bit */ +#define TXTHD (0x03 << 8) +#define BLENGTH (0x01 << 20) + +/* global setting for driver */ +#define RX_DESC_SIZE 50 +#define TX_DESC_SIZE 10 +#define MAX_RBUFF_SZ 0x600 +#define MAX_TBUFF_SZ 0x600 +#define TX_TIMEOUT 50 +#define DELAY 1000 +#define CAM0 0x0 + +static int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg); + +struct w90p910_rxbd { + unsigned int sl; + unsigned int buffer; + unsigned int reserved; + unsigned int next; +}; + +struct w90p910_txbd { + unsigned int mode; + unsigned int buffer; + unsigned int sl; + unsigned int next; +}; + +struct recv_pdesc { + struct w90p910_rxbd desclist[RX_DESC_SIZE]; + char recv_buf[RX_DESC_SIZE][MAX_RBUFF_SZ]; +}; + +struct tran_pdesc { + struct w90p910_txbd desclist[TX_DESC_SIZE]; + char tran_buf[RX_DESC_SIZE][MAX_TBUFF_SZ]; +}; + +struct w90p910_ether { + struct recv_pdesc *rdesc; + struct recv_pdesc *rdesc_phys; + struct tran_pdesc *tdesc; + struct tran_pdesc *tdesc_phys; + struct net_device_stats stats; + struct platform_device *pdev; + struct sk_buff *skb; + struct clk *clk; + struct clk *rmiiclk; + struct mii_if_info mii; + struct timer_list check_timer; + void __iomem *reg; + unsigned int rxirq; + unsigned int txirq; + unsigned int cur_tx; + unsigned int cur_rx; + unsigned int finish_tx; + unsigned int rx_packets; + unsigned int rx_bytes; + unsigned int start_tx_ptr; + unsigned int start_rx_ptr; + unsigned int linkflag; + spinlock_t lock; +}; + +static void update_linkspeed_register(struct net_device *dev, + unsigned int speed, unsigned int duplex) +{ + struct w90p910_ether *ether = netdev_priv(dev); + unsigned int val; + + val = __raw_readl(ether->reg + REG_MCMDR); + + if (speed == SPEED_100) { + /* 100 full/half duplex */ + if (duplex == DUPLEX_FULL) { + val |= (MCMDR_OPMOD | MCMDR_FDUP); + } else { + val |= MCMDR_OPMOD; + val &= ~MCMDR_FDUP; + } + } else { + /* 10 full/half duplex */ + if (duplex == DUPLEX_FULL) { + val |= MCMDR_FDUP; + val &= ~MCMDR_OPMOD; + } else { + val &= ~(MCMDR_FDUP | MCMDR_OPMOD); + } + } + + __raw_writel(val, ether->reg + REG_MCMDR); +} + +static void update_linkspeed(struct net_device *dev) +{ + struct w90p910_ether *ether = netdev_priv(dev); + struct platform_device *pdev; + unsigned int bmsr, bmcr, lpa, speed, duplex; + + pdev = ether->pdev; + + if (!mii_link_ok(ðer->mii)) { + ether->linkflag = 0x0; + netif_carrier_off(dev); + dev_warn(&pdev->dev, "%s: Link down.\n", dev->name); + return; + } + + if (ether->linkflag == 1) + return; + + bmsr = w90p910_mdio_read(dev, ether->mii.phy_id, MII_BMSR); + bmcr = w90p910_mdio_read(dev, ether->mii.phy_id, MII_BMCR); + + if (bmcr & BMCR_ANENABLE) { + if (!(bmsr & BMSR_ANEGCOMPLETE)) + return; + + lpa = w90p910_mdio_read(dev, ether->mii.phy_id, MII_LPA); + + if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) + speed = SPEED_100; + else + speed = SPEED_10; + + if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) + duplex = DUPLEX_FULL; + else + duplex = DUPLEX_HALF; + + } else { + speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; + duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; + } + + update_linkspeed_register(dev, speed, duplex); + + dev_info(&pdev->dev, "%s: Link now %i-%s\n", dev->name, speed, + (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex"); + ether->linkflag = 0x01; + + netif_carrier_on(dev); +} + +static void w90p910_check_link(unsigned long dev_id) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct w90p910_ether *ether = netdev_priv(dev); + + update_linkspeed(dev); + mod_timer(ðer->check_timer, jiffies + msecs_to_jiffies(1000)); +} + +static void w90p910_write_cam(struct net_device *dev, + unsigned int x, unsigned char *pval) +{ + struct w90p910_ether *ether = netdev_priv(dev); + unsigned int msw, lsw; + + msw = (pval[0] << 24) | (pval[1] << 16) | (pval[2] << 8) | pval[3]; + + lsw = (pval[4] << 24) | (pval[5] << 16); + + __raw_writel(lsw, ether->reg + REG_CAML_BASE + x * CAM_ENTRY_SIZE); + __raw_writel(msw, ether->reg + REG_CAMM_BASE + x * CAM_ENTRY_SIZE); +} + +static void w90p910_init_desc(struct net_device *dev) +{ + struct w90p910_ether *ether; + struct w90p910_txbd *tdesc, *tdesc_phys; + struct w90p910_rxbd *rdesc, *rdesc_phys; + unsigned int i, j; + + ether = netdev_priv(dev); + + ether->tdesc = (struct tran_pdesc *) + dma_alloc_coherent(NULL, sizeof(struct tran_pdesc), + (dma_addr_t *) ðer->tdesc_phys, GFP_KERNEL); + + ether->rdesc = (struct recv_pdesc *) + dma_alloc_coherent(NULL, sizeof(struct recv_pdesc), + (dma_addr_t *) ðer->rdesc_phys, GFP_KERNEL); + + for (i = 0; i < TX_DESC_SIZE; i++) { + tdesc = &(ether->tdesc->desclist[i]); + + j = ((i + 1) / TX_DESC_SIZE); + + if (j != 0) { + tdesc_phys = &(ether->tdesc_phys->desclist[0]); + ether->start_tx_ptr = (unsigned int)tdesc_phys; + tdesc->next = (unsigned int)ether->start_tx_ptr; + } else { + tdesc_phys = &(ether->tdesc_phys->desclist[i+1]); + tdesc->next = (unsigned int)tdesc_phys; + } + + tdesc->buffer = (unsigned int)ether->tdesc_phys->tran_buf[i]; + tdesc->sl = 0; + tdesc->mode = 0; + } + + for (i = 0; i < RX_DESC_SIZE; i++) { + rdesc = &(ether->rdesc->desclist[i]); + + j = ((i + 1) / RX_DESC_SIZE); + + if (j != 0) { + rdesc_phys = &(ether->rdesc_phys->desclist[0]); + ether->start_rx_ptr = (unsigned int)rdesc_phys; + rdesc->next = (unsigned int)ether->start_rx_ptr; + } else { + rdesc_phys = &(ether->rdesc_phys->desclist[i+1]); + rdesc->next = (unsigned int)rdesc_phys; + } + + rdesc->sl = RX_OWEN_DMA; + rdesc->buffer = (unsigned int)ether->rdesc_phys->recv_buf[i]; + } +} + +static void w90p910_set_fifo_threshold(struct net_device *dev) +{ + struct w90p910_ether *ether = netdev_priv(dev); + unsigned int val; + + val = TXTHD | BLENGTH; + __raw_writel(val, ether->reg + REG_FFTCR); +} + +static void w90p910_return_default_idle(struct net_device *dev) +{ + struct w90p910_ether *ether = netdev_priv(dev); + unsigned int val; + + val = __raw_readl(ether->reg + REG_MCMDR); + val |= SWR; + __raw_writel(val, ether->reg + REG_MCMDR); +} + +static void w90p910_trigger_rx(struct net_device *dev) +{ + struct w90p910_ether *ether = netdev_priv(dev); + + __raw_writel(ENSTART, ether->reg + REG_RSDR); +} + +static void w90p910_trigger_tx(struct net_device *dev) +{ + struct w90p910_ether *ether = netdev_priv(dev); + + __raw_writel(ENSTART, ether->reg + REG_TSDR); +} + +static void w90p910_enable_mac_interrupt(struct net_device *dev) +{ + struct w90p910_ether *ether = netdev_priv(dev); + unsigned int val; + + val = ENTXINTR | ENRXINTR | ENRXGD | ENTXCP; + val |= ENTXBERR | ENRXBERR | ENTXABT; + + __raw_writel(val, ether->reg + REG_MIEN); +} + +static void w90p910_get_and_clear_int(struct net_device *dev, + unsigned int *val) +{ + struct w90p910_ether *ether = netdev_priv(dev); + + *val = __raw_readl(ether->reg + REG_MISTA); + __raw_writel(*val, ether->reg + REG_MISTA); +} + +static void w90p910_set_global_maccmd(struct net_device *dev) +{ + struct w90p910_ether *ether = netdev_priv(dev); + unsigned int val; + + val = __raw_readl(ether->reg + REG_MCMDR); + val |= MCMDR_SPCRC | MCMDR_ENMDC | MCMDR_ACP | ENMDC; + __raw_writel(val, ether->reg + REG_MCMDR); +} + +static void w90p910_enable_cam(struct net_device *dev) +{ + struct w90p910_ether *ether = netdev_priv(dev); + unsigned int val; + + w90p910_write_cam(dev, CAM0, dev->dev_addr); + + val = __raw_readl(ether->reg + REG_CAMEN); + val |= CAM0EN; + __raw_writel(val, ether->reg + REG_CAMEN); +} + +static void w90p910_enable_cam_command(struct net_device *dev) +{ + struct w90p910_ether *ether = netdev_priv(dev); + unsigned int val; + + val = CAMCMR_ECMP | CAMCMR_ABP | CAMCMR_AMP; + __raw_writel(val, ether->reg + REG_CAMCMR); +} + +static void w90p910_enable_tx(struct net_device *dev, unsigned int enable) +{ + struct w90p910_ether *ether = netdev_priv(dev); + unsigned int val; + + val = __raw_readl(ether->reg + REG_MCMDR); + + if (enable) + val |= MCMDR_TXON; + else + val &= ~MCMDR_TXON; + + __raw_writel(val, ether->reg + REG_MCMDR); +} + +static void w90p910_enable_rx(struct net_device *dev, unsigned int enable) +{ + struct w90p910_ether *ether = netdev_priv(dev); + unsigned int val; + + val = __raw_readl(ether->reg + REG_MCMDR); + + if (enable) + val |= MCMDR_RXON; + else + val &= ~MCMDR_RXON; + + __raw_writel(val, ether->reg + REG_MCMDR); +} + +static void w90p910_set_curdest(struct net_device *dev) +{ + struct w90p910_ether *ether = netdev_priv(dev); + + __raw_writel(ether->start_rx_ptr, ether->reg + REG_RXDLSA); + __raw_writel(ether->start_tx_ptr, ether->reg + REG_TXDLSA); +} + +static void w90p910_reset_mac(struct net_device *dev) +{ + struct w90p910_ether *ether = netdev_priv(dev); + + spin_lock(ðer->lock); + + w90p910_enable_tx(dev, 0); + w90p910_enable_rx(dev, 0); + w90p910_set_fifo_threshold(dev); + w90p910_return_default_idle(dev); + + if (!netif_queue_stopped(dev)) + netif_stop_queue(dev); + + w90p910_init_desc(dev); + + dev->trans_start = jiffies; + ether->cur_tx = 0x0; + ether->finish_tx = 0x0; + ether->cur_rx = 0x0; + + w90p910_set_curdest(dev); + w90p910_enable_cam(dev); + w90p910_enable_cam_command(dev); + w90p910_enable_mac_interrupt(dev); + w90p910_enable_tx(dev, 1); + w90p910_enable_rx(dev, 1); + w90p910_trigger_tx(dev); + w90p910_trigger_rx(dev); + + dev->trans_start = jiffies; + + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + + spin_unlock(ðer->lock); +} + +static void w90p910_mdio_write(struct net_device *dev, + int phy_id, int reg, int data) +{ + struct w90p910_ether *ether = netdev_priv(dev); + struct platform_device *pdev; + unsigned int val, i; + + pdev = ether->pdev; + + __raw_writel(data, ether->reg + REG_MIID); + + val = (phy_id << 0x08) | reg; + val |= PHYBUSY | PHYWR | MDCCR_VAL; + __raw_writel(val, ether->reg + REG_MIIDA); + + for (i = 0; i < DELAY; i++) { + if ((__raw_readl(ether->reg + REG_MIIDA) & PHYBUSY) == 0) + break; + } + + if (i == DELAY) + dev_warn(&pdev->dev, "mdio write timed out\n"); +} + +static int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg) +{ + struct w90p910_ether *ether = netdev_priv(dev); + struct platform_device *pdev; + unsigned int val, i, data; + + pdev = ether->pdev; + + val = (phy_id << 0x08) | reg; + val |= PHYBUSY | MDCCR_VAL; + __raw_writel(val, ether->reg + REG_MIIDA); + + for (i = 0; i < DELAY; i++) { + if ((__raw_readl(ether->reg + REG_MIIDA) & PHYBUSY) == 0) + break; + } + + if (i == DELAY) |