phy.c revision 67c4f3fa25502ce7ed82fb0307e09cf36f1f81da
100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* 200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * drivers/net/phy/phy.c 300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Framework for configuring and reading PHY devices 500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Based on code in sungem_phy.c and gianfar_phy.c 600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Author: Andy Fleming 800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Copyright (c) 2004 Freescale Semiconductor, Inc. 1000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 1100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * This program is free software; you can redistribute it and/or modify it 1200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * under the terms of the GNU General Public License as published by the 1300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Free Software Foundation; either version 2 of the License, or (at your 1400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * option) any later version. 1500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 1600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 1700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/config.h> 1800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/kernel.h> 1900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/sched.h> 2000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/string.h> 2100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/errno.h> 2200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/unistd.h> 2300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/slab.h> 2400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/interrupt.h> 2500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/init.h> 2600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/delay.h> 2700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/netdevice.h> 2800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/etherdevice.h> 2900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/skbuff.h> 3000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/spinlock.h> 3100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/mm.h> 3200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/module.h> 3300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/version.h> 3400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/mii.h> 3500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/ethtool.h> 3600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/phy.h> 3700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 3800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <asm/io.h> 3900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <asm/irq.h> 4000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <asm/uaccess.h> 4100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 4200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic void phy_timer(unsigned long data); 4300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 4400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* Convenience function to print out the current phy status 4500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 4600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingvoid phy_print_status(struct phy_device *phydev) 4700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 4800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming pr_info("%s: Link is %s", phydev->dev.bus_id, 4900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->link ? "Up" : "Down"); 5000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (phydev->link) 5100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming printk(" - %d/%s", phydev->speed, 5200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming DUPLEX_FULL == phydev->duplex ? 5300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming "Full" : "Half"); 5400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 5500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming printk("\n"); 5600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 5700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingEXPORT_SYMBOL(phy_print_status); 5800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 5900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 6000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* Convenience functions for reading/writing a given PHY 6100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * register. They MUST NOT be called from interrupt context, 6200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * because the bus read/write functions may wait for an interrupt 6300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * to conclude the operation. */ 6400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingint phy_read(struct phy_device *phydev, u16 regnum) 6500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 6600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int retval; 6700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming struct mii_bus *bus = phydev->bus; 6800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 6900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_lock_bh(&bus->mdio_lock); 7000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming retval = bus->read(bus, phydev->addr, regnum); 7100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_unlock_bh(&bus->mdio_lock); 7200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 7300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return retval; 7400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 7500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingEXPORT_SYMBOL(phy_read); 7600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 7700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingint phy_write(struct phy_device *phydev, u16 regnum, u16 val) 7800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 7900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int err; 8000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming struct mii_bus *bus = phydev->bus; 8100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 8200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_lock_bh(&bus->mdio_lock); 8300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = bus->write(bus, phydev->addr, regnum, val); 8400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_unlock_bh(&bus->mdio_lock); 8500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 8600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 8700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 8800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingEXPORT_SYMBOL(phy_write); 8900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 9000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 9100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingint phy_clear_interrupt(struct phy_device *phydev) 9200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 9300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int err = 0; 9400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 9500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (phydev->drv->ack_interrupt) 9600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phydev->drv->ack_interrupt(phydev); 9700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 9800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 9900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 10000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 10100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 10200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingint phy_config_interrupt(struct phy_device *phydev, u32 interrupts) 10300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 10400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int err = 0; 10500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 10600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->interrupts = interrupts; 10700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (phydev->drv->config_intr) 10800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phydev->drv->config_intr(phydev); 10900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 11000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 11100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 11200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 11300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 11400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* phy_aneg_done 11500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 11600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * description: Reads the status register and returns 0 either if 11700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * auto-negotiation is incomplete, or if there was an error. 11800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. 11900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 12000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic inline int phy_aneg_done(struct phy_device *phydev) 12100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 12200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int retval; 12300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 12400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming retval = phy_read(phydev, MII_BMSR); 12500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 12600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); 12700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 12800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 12900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* phy_start_aneg 13000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 13100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * description: Calls the PHY driver's config_aneg, and then 13200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * sets the PHY state to PHY_AN if auto-negotiation is enabled, 13300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * and to PHY_FORCING if auto-negotiation is disabled. Unless 13400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * the PHY is currently HALTED. 13500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 13600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingint phy_start_aneg(struct phy_device *phydev) 13700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 13800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int err; 13900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 14000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_lock(&phydev->lock); 14100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 14200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (AUTONEG_DISABLE == phydev->autoneg) 14300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phy_sanitize_settings(phydev); 14400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 14500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phydev->drv->config_aneg(phydev); 14600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 14700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err < 0) 14800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming goto out_unlock; 14900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 15000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (phydev->state != PHY_HALTED) { 15100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (AUTONEG_ENABLE == phydev->autoneg) { 15200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_AN; 15300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->link_timeout = PHY_AN_TIMEOUT; 15400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } else { 15500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_FORCING; 15600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->link_timeout = PHY_FORCE_TIMEOUT; 15700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 15800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 15900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 16000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingout_unlock: 16100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_unlock(&phydev->lock); 16200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 16300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 16400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingEXPORT_SYMBOL(phy_start_aneg); 16500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 16600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 16700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* A structure for mapping a particular speed and duplex 16800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * combination to a particular SUPPORTED and ADVERTISED value */ 16900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstruct phy_setting { 17000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int speed; 17100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int duplex; 17200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming u32 setting; 17300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming}; 17400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 17500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* A mapping of all SUPPORTED settings to speed/duplex */ 17600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic struct phy_setting settings[] = { 17700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming { 17800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .speed = 10000, 17900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .duplex = DUPLEX_FULL, 18000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .setting = SUPPORTED_10000baseT_Full, 18100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming }, 18200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming { 18300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .speed = SPEED_1000, 18400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .duplex = DUPLEX_FULL, 18500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .setting = SUPPORTED_1000baseT_Full, 18600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming }, 18700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming { 18800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .speed = SPEED_1000, 18900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .duplex = DUPLEX_HALF, 19000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .setting = SUPPORTED_1000baseT_Half, 19100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming }, 19200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming { 19300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .speed = SPEED_100, 19400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .duplex = DUPLEX_FULL, 19500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .setting = SUPPORTED_100baseT_Full, 19600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming }, 19700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming { 19800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .speed = SPEED_100, 19900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .duplex = DUPLEX_HALF, 20000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .setting = SUPPORTED_100baseT_Half, 20100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming }, 20200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming { 20300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .speed = SPEED_10, 20400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .duplex = DUPLEX_FULL, 20500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .setting = SUPPORTED_10baseT_Full, 20600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming }, 20700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming { 20800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .speed = SPEED_10, 20900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .duplex = DUPLEX_HALF, 21000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .setting = SUPPORTED_10baseT_Half, 21100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming }, 21200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming}; 21300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 21400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting)) 21500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 21600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* phy_find_setting 21700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 21800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * description: Searches the settings array for the setting which 21900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * matches the desired speed and duplex, and returns the index 22000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * of that setting. Returns the index of the last setting if 22100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * none of the others match. 22200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 22300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic inline int phy_find_setting(int speed, int duplex) 22400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 22500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int idx = 0; 22600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 22700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming while (idx < ARRAY_SIZE(settings) && 22800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming (settings[idx].speed != speed || 22900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming settings[idx].duplex != duplex)) 23000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming idx++; 23100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 23200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; 23300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 23400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 23500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* phy_find_valid 23600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * idx: The first index in settings[] to search 23700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * features: A mask of the valid settings 23800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 23900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * description: Returns the index of the first valid setting less 24000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * than or equal to the one pointed to by idx, as determined by 24100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * the mask in features. Returns the index of the last setting 24200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * if nothing else matches. 24300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 24400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic inline int phy_find_valid(int idx, u32 features) 24500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 24600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features)) 24700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming idx++; 24800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 24900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; 25000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 25100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 25200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* phy_sanitize_settings 25300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 25400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * description: Make sure the PHY is set to supported speeds and 25500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * duplexes. Drop down by one in this order: 1000/FULL, 25600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF 25700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 25800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingvoid phy_sanitize_settings(struct phy_device *phydev) 25900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 26000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming u32 features = phydev->supported; 26100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int idx; 26200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 26300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Sanitize settings based on PHY capabilities */ 26400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if ((features & SUPPORTED_Autoneg) == 0) 26500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->autoneg = 0; 26600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 26700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex), 26800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming features); 26900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 27000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->speed = settings[idx].speed; 27100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->duplex = settings[idx].duplex; 27200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 27300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingEXPORT_SYMBOL(phy_sanitize_settings); 27400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 27500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* phy_force_reduction 27600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 27700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * description: Reduces the speed/duplex settings by 27800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * one notch. The order is so: 27900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, 28000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 10/FULL, 10/HALF. The function bottoms out at 10/HALF. 28100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 28200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic void phy_force_reduction(struct phy_device *phydev) 28300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 28400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int idx; 28500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 28600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming idx = phy_find_setting(phydev->speed, phydev->duplex); 28700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 28800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming idx++; 28900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 29000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming idx = phy_find_valid(idx, phydev->supported); 29100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 29200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->speed = settings[idx].speed; 29300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->duplex = settings[idx].duplex; 29400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 29500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming pr_info("Trying %d/%s\n", phydev->speed, 29600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming DUPLEX_FULL == phydev->duplex ? 29700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming "FULL" : "HALF"); 29800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 29900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 30000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* phy_ethtool_sset: 30100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * A generic ethtool sset function. Handles all the details 30200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 30300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * A few notes about parameter checking: 30400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * - We don't set port or transceiver, so we don't care what they 30500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * were set to. 30600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * - phy_start_aneg() will make sure forced settings are sane, and 30700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * choose the next best ones from the ones selected, so we don't 30800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * care if ethtool tries to give us bad values 30900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 31000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingint phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) 31100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 31200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (cmd->phy_address != phydev->addr) 31300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return -EINVAL; 31400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 31500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* We make sure that we don't pass unsupported 31600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * values in to the PHY */ 31700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming cmd->advertising &= phydev->supported; 31800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 31900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Verify the settings we care about. */ 32000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE) 32100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return -EINVAL; 32200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 32300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) 32400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return -EINVAL; 32500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 32600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (cmd->autoneg == AUTONEG_DISABLE 32700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming && ((cmd->speed != SPEED_1000 32800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming && cmd->speed != SPEED_100 32900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming && cmd->speed != SPEED_10) 33000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming || (cmd->duplex != DUPLEX_HALF 33100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming && cmd->duplex != DUPLEX_FULL))) 33200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return -EINVAL; 33300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 33400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->autoneg = cmd->autoneg; 33500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 33600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->speed = cmd->speed; 33700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 33800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->advertising = cmd->advertising; 33900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 34000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (AUTONEG_ENABLE == cmd->autoneg) 34100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->advertising |= ADVERTISED_Autoneg; 34200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming else 34300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->advertising &= ~ADVERTISED_Autoneg; 34400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 34500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->duplex = cmd->duplex; 34600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 34700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Restart the PHY */ 34800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phy_start_aneg(phydev); 34900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 35000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return 0; 35100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 35200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 35300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingint phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) 35400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 35500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming cmd->supported = phydev->supported; 35600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 35700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming cmd->advertising = phydev->advertising; 35800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 35900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming cmd->speed = phydev->speed; 36000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming cmd->duplex = phydev->duplex; 36100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming cmd->port = PORT_MII; 36200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming cmd->phy_address = phydev->addr; 36300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming cmd->transceiver = XCVR_EXTERNAL; 36400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming cmd->autoneg = phydev->autoneg; 36500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 36600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return 0; 36700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 36800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 36900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 37000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* Note that this function is currently incompatible with the 37100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * PHYCONTROL layer. It changes registers without regard to 37200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * current state. Use at own risk 37300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 37400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingint phy_mii_ioctl(struct phy_device *phydev, 37500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming struct mii_ioctl_data *mii_data, int cmd) 37600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 37700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming u16 val = mii_data->val_in; 37800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 37900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming switch (cmd) { 38000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case SIOCGMIIPHY: 38100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming mii_data->phy_id = phydev->addr; 38200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 38300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case SIOCGMIIREG: 38400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming mii_data->val_out = phy_read(phydev, mii_data->reg_num); 38500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 38600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 38700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case SIOCSMIIREG: 38800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (!capable(CAP_NET_ADMIN)) 38900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return -EPERM; 39000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 39100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (mii_data->phy_id == phydev->addr) { 39200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming switch(mii_data->reg_num) { 39300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case MII_BMCR: 39400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (val & (BMCR_RESET|BMCR_ANENABLE)) 39500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->autoneg = AUTONEG_DISABLE; 39600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming else 39700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->autoneg = AUTONEG_ENABLE; 39800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if ((!phydev->autoneg) && (val & BMCR_FULLDPLX)) 39900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->duplex = DUPLEX_FULL; 40000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming else 40100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->duplex = DUPLEX_HALF; 40200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 40300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case MII_ADVERTISE: 40400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->advertising = val; 40500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 40600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming default: 40700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* do nothing */ 40800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 40900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 41000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 41100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 41200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phy_write(phydev, mii_data->reg_num, val); 41300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 41400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (mii_data->reg_num == MII_BMCR 41500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming && val & BMCR_RESET 41600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming && phydev->drv->config_init) 41700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->drv->config_init(phydev); 41800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 41900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 42000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 42100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return 0; 42200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 42300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 42400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* phy_start_machine: 42500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 42600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * description: The PHY infrastructure can run a state machine 42700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * which tracks whether the PHY is starting up, negotiating, 42800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * etc. This function starts the timer which tracks the state 42900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * of the PHY. If you want to be notified when the state 43000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * changes, pass in the callback, otherwise, pass NULL. If you 43100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * want to maintain your own state machine, do not call this 43200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * function. */ 43300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingvoid phy_start_machine(struct phy_device *phydev, 43400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming void (*handler)(struct net_device *)) 43500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 43600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->adjust_state = handler; 43700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 43800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming init_timer(&phydev->phy_timer); 43900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->phy_timer.function = &phy_timer; 44000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->phy_timer.data = (unsigned long) phydev; 44100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming mod_timer(&phydev->phy_timer, jiffies + HZ); 44200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 44300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 44400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* phy_stop_machine 44500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 44600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * description: Stops the state machine timer, sets the state to 44700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * UP (unless it wasn't up yet), and then frees the interrupt, 44800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * if it is in use. This function must be called BEFORE 44900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * phy_detach. 45000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 45100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingvoid phy_stop_machine(struct phy_device *phydev) 45200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 45300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming del_timer_sync(&phydev->phy_timer); 45400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 45500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_lock(&phydev->lock); 45600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (phydev->state > PHY_UP) 45700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_UP; 45800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_unlock(&phydev->lock); 45900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 46000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (phydev->irq != PHY_POLL) 46100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phy_stop_interrupts(phydev); 46200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 46300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->adjust_state = NULL; 46400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 46500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 46600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* phy_error: 46700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 46800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Moves the PHY to the HALTED state in response to a read 46900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * or write error, and tells the controller the link is down. 47000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Must not be called from interrupt context, or while the 47100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * phydev->lock is held. 47200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 47300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingvoid phy_error(struct phy_device *phydev) 47400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 47500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_lock(&phydev->lock); 47600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_HALTED; 47700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_unlock(&phydev->lock); 47800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 47900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 48067c4f3fa25502ce7ed82fb0307e09cf36f1f81daJeff Garzik#ifdef CONFIG_PHYCONTROL 48167c4f3fa25502ce7ed82fb0307e09cf36f1f81daJeff Garzik 48267c4f3fa25502ce7ed82fb0307e09cf36f1f81daJeff Garzikstatic void phy_change(void *data); 48367c4f3fa25502ce7ed82fb0307e09cf36f1f81daJeff Garzik 48400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* phy_interrupt 48500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 48600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * description: When a PHY interrupt occurs, the handler disables 48700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * interrupts, and schedules a work task to clear the interrupt. 48800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 48900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic irqreturn_t phy_interrupt(int irq, void *phy_dat, struct pt_regs *regs) 49000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 49100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming struct phy_device *phydev = phy_dat; 49200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 49300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* The MDIO bus is not allowed to be written in interrupt 49400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * context, so we need to disable the irq here. A work 49500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * queue will write the PHY to disable and clear the 49600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * interrupt, and then reenable the irq line. */ 49700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming disable_irq_nosync(irq); 49800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 49900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming schedule_work(&phydev->phy_queue); 50000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 50100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return IRQ_HANDLED; 50200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 50300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 50400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* Enable the interrupts from the PHY side */ 50500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingint phy_enable_interrupts(struct phy_device *phydev) 50600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 50700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int err; 50800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 50900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_clear_interrupt(phydev); 51000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 51100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err < 0) 51200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 51300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 51400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); 51500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 51600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 51700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 51800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingEXPORT_SYMBOL(phy_enable_interrupts); 51900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 52000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* Disable the PHY interrupts from the PHY side */ 52100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingint phy_disable_interrupts(struct phy_device *phydev) 52200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 52300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int err; 52400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 52500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Disable PHY interrupts */ 52600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); 52700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 52800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err) 52900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming goto phy_err; 53000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 53100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Clear the interrupt */ 53200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_clear_interrupt(phydev); 53300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 53400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err) 53500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming goto phy_err; 53600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 53700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return 0; 53800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 53900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingphy_err: 54000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phy_error(phydev); 54100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 54200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 54300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 54400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingEXPORT_SYMBOL(phy_disable_interrupts); 54500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 54600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* phy_start_interrupts 54700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 54800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * description: Request the interrupt for the given PHY. If 54900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * this fails, then we set irq to PHY_POLL. 55000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Otherwise, we enable the interrupts in the PHY. 55100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Returns 0 on success. 55200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * This should only be called with a valid IRQ number. 55300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 55400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingint phy_start_interrupts(struct phy_device *phydev) 55500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 55600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int err = 0; 55700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 55800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming INIT_WORK(&phydev->phy_queue, phy_change, phydev); 55900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 56000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (request_irq(phydev->irq, phy_interrupt, 56100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming SA_SHIRQ, 56200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming "phy_interrupt", 56300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev) < 0) { 56400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming printk(KERN_WARNING "%s: Can't get IRQ %d (PHY)\n", 56500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->bus->name, 56600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->irq); 56700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->irq = PHY_POLL; 56800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return 0; 56900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 57000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 57100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_enable_interrupts(phydev); 57200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 57300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 57400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 57500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingEXPORT_SYMBOL(phy_start_interrupts); 57600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 57700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingint phy_stop_interrupts(struct phy_device *phydev) 57800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 57900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int err; 58000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 58100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_disable_interrupts(phydev); 58200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 58300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err) 58400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phy_error(phydev); 58500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 58600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming free_irq(phydev->irq, phydev); 58700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 58800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 58900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 59000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingEXPORT_SYMBOL(phy_stop_interrupts); 59100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 59200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 59300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* Scheduled by the phy_interrupt/timer to handle PHY changes */ 59400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic void phy_change(void *data) 59500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 59600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int err; 59700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming struct phy_device *phydev = data; 59800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 59900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_disable_interrupts(phydev); 60000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 60100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err) 60200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming goto phy_err; 60300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 60400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_lock(&phydev->lock); 60500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state)) 60600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_CHANGELINK; 60700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_unlock(&phydev->lock); 60800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 60900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming enable_irq(phydev->irq); 61000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 61100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Reenable interrupts */ 61200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); 61300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 61400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err) 61500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming goto irq_enable_err; 61600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 61700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return; 61800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 61900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingirq_enable_err: 62000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming disable_irq(phydev->irq); 62100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingphy_err: 62200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phy_error(phydev); 62300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 62400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 62500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* Bring down the PHY link, and stop checking the status. */ 62600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingvoid phy_stop(struct phy_device *phydev) 62700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 62800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_lock(&phydev->lock); 62900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 63000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (PHY_HALTED == phydev->state) 63100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming goto out_unlock; 63200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 63300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (phydev->irq != PHY_POLL) { 63400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Clear any pending interrupts */ 63500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phy_clear_interrupt(phydev); 63600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 63700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Disable PHY Interrupts */ 63800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); 63900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 64000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 64100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_HALTED; 64200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 64300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingout_unlock: 64400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_unlock(&phydev->lock); 64500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 64600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 64700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 64800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* phy_start 64900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 65000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * description: Indicates the attached device's readiness to 65100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * handle PHY-related work. Used during startup to start the 65200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * PHY, and after a call to phy_stop() to resume operation. 65300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Also used to indicate the MDIO bus has cleared an error 65400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * condition. 65500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 65600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingvoid phy_start(struct phy_device *phydev) 65700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 65800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_lock(&phydev->lock); 65900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 66000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming switch (phydev->state) { 66100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_STARTING: 66200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_PENDING; 66300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 66400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_READY: 66500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_UP; 66600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 66700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_HALTED: 66800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_RESUMING; 66900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming default: 67000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 67100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 67200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_unlock(&phydev->lock); 67300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 67400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingEXPORT_SYMBOL(phy_stop); 67500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingEXPORT_SYMBOL(phy_start); 67600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 67767c4f3fa25502ce7ed82fb0307e09cf36f1f81daJeff Garzik#endif /* CONFIG_PHYCONTROL */ 67867c4f3fa25502ce7ed82fb0307e09cf36f1f81daJeff Garzik 67900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* PHY timer which handles the state machine */ 68000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic void phy_timer(unsigned long data) 68100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 68200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming struct phy_device *phydev = (struct phy_device *)data; 68300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int needs_aneg = 0; 68400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int err = 0; 68500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 68600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_lock(&phydev->lock); 68700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 68800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (phydev->adjust_state) 68900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->adjust_state(phydev->attached_dev); 69000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 69100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming switch(phydev->state) { 69200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_DOWN: 69300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_STARTING: 69400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_READY: 69500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_PENDING: 69600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 69700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_UP: 69800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming needs_aneg = 1; 69900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 70000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->link_timeout = PHY_AN_TIMEOUT; 70100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 70200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 70300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_AN: 70400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Check if negotiation is done. Break 70500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * if there's an error */ 70600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_aneg_done(phydev); 70700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err < 0) 70800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 70900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 71000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* If auto-negotiation is done, we change to 71100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * either RUNNING, or NOLINK */ 71200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err > 0) { 71300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_read_status(phydev); 71400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 71500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err) 71600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 71700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 71800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (phydev->link) { 71900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_RUNNING; 72000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming netif_carrier_on(phydev->attached_dev); 72100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } else { 72200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_NOLINK; 72300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming netif_carrier_off(phydev->attached_dev); 72400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 72500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 72600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->adjust_link(phydev->attached_dev); 72700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 72800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } else if (0 == phydev->link_timeout--) { 72900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* The counter expired, so either we 73000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * switch to forced mode, or the 73100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * magic_aneg bit exists, and we try aneg 73200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * again */ 73300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (!(phydev->drv->flags & PHY_HAS_MAGICANEG)) { 73400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int idx; 73500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 73600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* We'll start from the 73700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * fastest speed, and work 73800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * our way down */ 73900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming idx = phy_find_valid(0, 74000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->supported); 74100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 74200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->speed = settings[idx].speed; 74300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->duplex = settings[idx].duplex; 74400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 74500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->autoneg = AUTONEG_DISABLE; 74600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_FORCING; 74700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->link_timeout = 74800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming PHY_FORCE_TIMEOUT; 74900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 75000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming pr_info("Trying %d/%s\n", 75100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->speed, 75200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming DUPLEX_FULL == 75300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->duplex ? 75400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming "FULL" : "HALF"); 75500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 75600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 75700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming needs_aneg = 1; 75800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 75900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 76000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_NOLINK: 76100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_read_status(phydev); 76200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 76300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err) 76400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 76500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 76600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (phydev->link) { 76700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_RUNNING; 76800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming netif_carrier_on(phydev->attached_dev); 76900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->adjust_link(phydev->attached_dev); 77000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 77100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 77200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_FORCING: 77300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_read_status(phydev); 77400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 77500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err) 77600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 77700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 77800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (phydev->link) { 77900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_RUNNING; 78000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming netif_carrier_on(phydev->attached_dev); 78100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } else { 78200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (0 == phydev->link_timeout--) { 78300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phy_force_reduction(phydev); 78400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming needs_aneg = 1; 78500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 78600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 78700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 78800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->adjust_link(phydev->attached_dev); 78900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 79000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_RUNNING: 79100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Only register a CHANGE if we are 79200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * polling */ 79300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (PHY_POLL == phydev->irq) 79400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_CHANGELINK; 79500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 79600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_CHANGELINK: 79700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_read_status(phydev); 79800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 79900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err) 80000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 80100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 80200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (phydev->link) { 80300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_RUNNING; 80400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming netif_carrier_on(phydev->attached_dev); 80500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } else { 80600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_NOLINK; 80700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming netif_carrier_off(phydev->attached_dev); 80800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 80900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 81000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->adjust_link(phydev->attached_dev); 81100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 81200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (PHY_POLL != phydev->irq) 81300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_config_interrupt(phydev, 81400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming PHY_INTERRUPT_ENABLED); 81500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 81600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_HALTED: 81700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (phydev->link) { 81800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->link = 0; 81900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming netif_carrier_off(phydev->attached_dev); 82000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->adjust_link(phydev->attached_dev); 82100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 82200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 82300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming case PHY_RESUMING: 82400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 82500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_clear_interrupt(phydev); 82600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 82700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err) 82800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 82900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 83000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_config_interrupt(phydev, 83100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming PHY_INTERRUPT_ENABLED); 83200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 83300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err) 83400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 83500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 83600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (AUTONEG_ENABLE == phydev->autoneg) { 83700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_aneg_done(phydev); 83800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err < 0) 83900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 84000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 84100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* err > 0 if AN is done. 84200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Otherwise, it's 0, and we're 84300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * still waiting for AN */ 84400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err > 0) { 84500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_RUNNING; 84600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } else { 84700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_AN; 84800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->link_timeout = PHY_AN_TIMEOUT; 84900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 85000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } else 85100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phydev->state = PHY_RUNNING; 85200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming break; 85300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming } 85400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 85500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming spin_unlock(&phydev->lock); 85600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 85700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (needs_aneg) 85800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_start_aneg(phydev); 85900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 86000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err < 0) 86100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming phy_error(phydev); 86200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 86300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ); 86400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 86500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 866