diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/Kconfig | 5 | ||||
-rw-r--r-- | drivers/net/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/phy/broadcom.c | 20 | ||||
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 2 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 68 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 11 | ||||
-rw-r--r-- | drivers/net/phy/realtek.c | 80 |
7 files changed, 158 insertions, 29 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 7fe03ce774b1..f4ca0591231d 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -60,6 +60,11 @@ config ICPLUS_PHY ---help--- Currently supports the IP175C PHY. +config REALTEK_PHY + tristate "Drivers for Realtek PHYs" + ---help--- + Supports the Realtek 821x PHY. + config FIXED_PHY bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 3d6cc7b67a80..5997d6ef702b 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -12,5 +12,6 @@ obj-$(CONFIG_SMSC_PHY) += smsc.o obj-$(CONFIG_VITESSE_PHY) += vitesse.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o +obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_FIXED_PHY) += fixed.o obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 29666c85ed55..5b80358af658 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -141,6 +141,20 @@ static struct phy_driver bcm5461_driver = { .driver = { .owner = THIS_MODULE }, }; +static struct phy_driver bcm5482_driver = { + .phy_id = 0x0143bcb0, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM5482", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = bcm54xx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm54xx_ack_interrupt, + .config_intr = bcm54xx_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + static int __init broadcom_init(void) { int ret; @@ -154,8 +168,13 @@ static int __init broadcom_init(void) ret = phy_driver_register(&bcm5461_driver); if (ret) goto out_5461; + ret = phy_driver_register(&bcm5482_driver); + if (ret) + goto out_5482; return ret; +out_5482: + phy_driver_unregister(&bcm5461_driver); out_5461: phy_driver_unregister(&bcm5421_driver); out_5421: @@ -166,6 +185,7 @@ out_5411: static void __exit broadcom_exit(void) { + phy_driver_unregister(&bcm5482_driver); phy_driver_unregister(&bcm5461_driver); phy_driver_unregister(&bcm5421_driver); phy_driver_unregister(&bcm5411_driver); diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index c30196d0ad16..6e9f619c491f 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -49,7 +49,7 @@ int mdiobus_register(struct mii_bus *bus) int i; int err = 0; - spin_lock_init(&bus->mdio_lock); + mutex_init(&bus->mdio_lock); if (NULL == bus || NULL == bus->name || NULL == bus->read || diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 7c9e6e349503..12fccb1c76dc 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -26,7 +26,6 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include <linux/spinlock.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/mii.h> @@ -72,9 +71,11 @@ int phy_read(struct phy_device *phydev, u16 regnum) int retval; struct mii_bus *bus = phydev->bus; - spin_lock_bh(&bus->mdio_lock); + BUG_ON(in_interrupt()); + + mutex_lock(&bus->mdio_lock); retval = bus->read(bus, phydev->addr, regnum); - spin_unlock_bh(&bus->mdio_lock); + mutex_unlock(&bus->mdio_lock); return retval; } @@ -95,9 +96,11 @@ int phy_write(struct phy_device *phydev, u16 regnum, u16 val) int err; struct mii_bus *bus = phydev->bus; - spin_lock_bh(&bus->mdio_lock); + BUG_ON(in_interrupt()); + + mutex_lock(&bus->mdio_lock); err = bus->write(bus, phydev->addr, regnum, val); - spin_unlock_bh(&bus->mdio_lock); + mutex_unlock(&bus->mdio_lock); return err; } @@ -428,7 +431,7 @@ int phy_start_aneg(struct phy_device *phydev) { int err; - spin_lock_bh(&phydev->lock); + mutex_lock(&phydev->lock); if (AUTONEG_DISABLE == phydev->autoneg) phy_sanitize_settings(phydev); @@ -449,13 +452,14 @@ int phy_start_aneg(struct phy_device *phydev) } out_unlock: - spin_unlock_bh(&phydev->lock); + mutex_unlock(&phydev->lock); return err; } EXPORT_SYMBOL(phy_start_aneg); static void phy_change(struct work_struct *work); +static void phy_state_machine(struct work_struct *work); static void phy_timer(unsigned long data); /** @@ -476,6 +480,7 @@ void phy_start_machine(struct phy_device *phydev, { phydev->adjust_state = handler; + INIT_WORK(&phydev->state_queue, phy_state_machine); init_timer(&phydev->phy_timer); phydev->phy_timer.function = &phy_timer; phydev->phy_timer.data = (unsigned long) phydev; @@ -493,11 +498,12 @@ void phy_start_machine(struct phy_device *phydev, void phy_stop_machine(struct phy_device *phydev) { del_timer_sync(&phydev->phy_timer); + cancel_work_sync(&phydev->state_queue); - spin_lock_bh(&phydev->lock); + mutex_lock(&phydev->lock); if (phydev->state > PHY_UP) phydev->state = PHY_UP; - spin_unlock_bh(&phydev->lock); + mutex_unlock(&phydev->lock); phydev->adjust_state = NULL; } @@ -541,9 +547,9 @@ static void phy_force_reduction(struct phy_device *phydev) */ void phy_error(struct phy_device *phydev) { - spin_lock_bh(&phydev->lock); + mutex_lock(&phydev->lock); phydev->state = PHY_HALTED; - spin_unlock_bh(&phydev->lock); + mutex_unlock(&phydev->lock); } /** @@ -705,10 +711,10 @@ static void phy_change(struct work_struct *work) if (err) goto phy_err; - spin_lock_bh(&phydev->lock); + mutex_lock(&phydev->lock); if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state)) phydev->state = PHY_CHANGELINK; - spin_unlock_bh(&phydev->lock); + mutex_unlock(&phydev->lock); atomic_dec(&phydev->irq_disable); enable_irq(phydev->irq); @@ -735,7 +741,7 @@ phy_err: */ void phy_stop(struct phy_device *phydev) { - spin_lock_bh(&phydev->lock); + mutex_lock(&phydev->lock); if (PHY_HALTED == phydev->state) goto out_unlock; @@ -751,7 +757,7 @@ void phy_stop(struct phy_device *phydev) phydev->state = PHY_HALTED; out_unlock: - spin_unlock_bh(&phydev->lock); + mutex_unlock(&phydev->lock); /* * Cannot call flush_scheduled_work() here as desired because @@ -773,7 +779,7 @@ out_unlock: */ void phy_start(struct phy_device *phydev) { - spin_lock_bh(&phydev->lock); + mutex_lock(&phydev->lock); switch (phydev->state) { case PHY_STARTING: @@ -787,19 +793,26 @@ void phy_start(struct phy_device *phydev) default: break; } - spin_unlock_bh(&phydev->lock); + mutex_unlock(&phydev->lock); } EXPORT_SYMBOL(phy_stop); EXPORT_SYMBOL(phy_start); -/* PHY timer which handles the state machine */ -static void phy_timer(unsigned long data) +/** + * phy_state_machine - Handle the state machine + * @work: work_struct that describes the work to be done + * + * Description: Scheduled by the state_queue workqueue each time + * phy_timer is triggered. + */ +static void phy_state_machine(struct work_struct *work) { - struct phy_device *phydev = (struct phy_device *)data; + struct phy_device *phydev = + container_of(work, struct phy_device, state_queue); int needs_aneg = 0; int err = 0; - spin_lock_bh(&phydev->lock); + mutex_lock(&phydev->lock); if (phydev->adjust_state) phydev->adjust_state(phydev->attached_dev); @@ -965,7 +978,7 @@ static void phy_timer(unsigned long data) break; } - spin_unlock_bh(&phydev->lock); + mutex_unlock(&phydev->lock); if (needs_aneg) err = phy_start_aneg(phydev); @@ -976,3 +989,14 @@ static void phy_timer(unsigned long data) mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ); } +/* PHY timer which schedules the state machine work */ +static void phy_timer(unsigned long data) +{ + struct phy_device *phydev = (struct phy_device *)data; + + /* + * PHY I/O operations can potentially sleep so we ensure that + * it's done from a process context + */ + schedule_work(&phydev->state_queue); +} diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 5b9e1751e1b4..f4c4fd85425f 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -25,7 +25,6 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include <linux/spinlock.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/mii.h> @@ -80,7 +79,7 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) dev->state = PHY_DOWN; - spin_lock_init(&dev->lock); + mutex_init(&dev->lock); return dev; } @@ -656,7 +655,7 @@ static int phy_probe(struct device *dev) if (!(phydrv->flags & PHY_HAS_INTERRUPT)) phydev->irq = PHY_POLL; - spin_lock_bh(&phydev->lock); + mutex_lock(&phydev->lock); /* Start out supporting everything. Eventually, * a controller will attach, and may modify one @@ -670,7 +669,7 @@ static int phy_probe(struct device *dev) if (phydev->drv->probe) err = phydev->drv->probe(phydev); - spin_unlock_bh(&phydev->lock); + mutex_unlock(&phydev->lock); return err; @@ -682,9 +681,9 @@ static int phy_remove(struct device *dev) phydev = to_phy_device(dev); - spin_lock_bh(&phydev->lock); + mutex_lock(&phydev->lock); phydev->state = PHY_DOWN; - spin_unlock_bh(&phydev->lock); + mutex_unlock(&phydev->lock); if (phydev->drv->remove) phydev->drv->remove(phydev); diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c new file mode 100644 index 000000000000..a052a6744a51 --- /dev/null +++ b/drivers/net/phy/realtek.c @@ -0,0 +1,80 @@ +/* + * drivers/net/phy/realtek.c + * + * Driver for Realtek PHYs + * + * Author: Johnson Leung <r58129@freescale.com> + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * 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; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/phy.h> + +#define RTL821x_PHYSR 0x11 +#define RTL821x_PHYSR_DUPLEX 0x2000 +#define RTL821x_PHYSR_SPEED 0xc000 +#define RTL821x_INER 0x12 +#define RTL821x_INER_INIT 0x6400 +#define RTL821x_INSR 0x13 + +MODULE_DESCRIPTION("Realtek PHY driver"); +MODULE_AUTHOR("Johnson Leung"); +MODULE_LICENSE("GPL"); + +static int rtl821x_ack_interrupt(struct phy_device *phydev) +{ + int err; + + err = phy_read(phydev, RTL821x_INSR); + + return (err < 0) ? err : 0; +} + +static int rtl821x_config_intr(struct phy_device *phydev) +{ + int err; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, RTL821x_INER, + RTL821x_INER_INIT); + else + err = phy_write(phydev, RTL821x_INER, 0); + + return err; +} + +/* RTL8211B */ +static struct phy_driver rtl821x_driver = { + .phy_id = 0x001cc912, + .name = "RTL821x Gigabit Ethernet", + .phy_id_mask = 0x001fffff, + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &genphy_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &rtl821x_ack_interrupt, + .config_intr = &rtl821x_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init realtek_init(void) +{ + int ret; + + ret = phy_driver_register(&rtl821x_driver); + + return ret; +} + +static void __exit realtek_exit(void) +{ + phy_driver_unregister(&rtl821x_driver); +} + +module_init(realtek_init); +module_exit(realtek_exit); |