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