kernel: update stmmac ethernet driver from latest linux-sh4-2.6.32.y - _stm24_0217
This commit is contained in:
@@ -277,6 +277,13 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
|
||||
if (!netdev)
|
||||
return true;
|
||||
|
||||
/* PHY supports WoL+ that has been enabled by ethtool.
|
||||
* So we can call the suspend function that is expected
|
||||
* able to program internal registers to wake-up the system.
|
||||
*/
|
||||
if (phydev->wol)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Don't suspend PHY if the attched netdev parent may wakeup.
|
||||
* The parent may point to a PCI device, as in tg3 driver.
|
||||
|
@@ -299,6 +299,36 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
|
||||
}
|
||||
EXPORT_SYMBOL(phy_ethtool_gset);
|
||||
|
||||
int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
u32 support = phydev->drv->wol_supported;
|
||||
|
||||
if (wol->wolopts & ~support)
|
||||
return -EINVAL;
|
||||
|
||||
phydev->wol = wol->wolopts;
|
||||
if (wol->wolopts) {
|
||||
device_set_wakeup_enable(&phydev->dev, 1);
|
||||
enable_irq_wake(phydev->irq);
|
||||
} else {
|
||||
device_set_wakeup_enable(&phydev->dev, 0);
|
||||
disable_irq_wake(phydev->irq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(phy_ethtool_set_wol);
|
||||
|
||||
int phy_ethtool_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
if (device_can_wakeup(&phydev->dev)) {
|
||||
wol->supported = phydev->drv->wol_supported;
|
||||
wol->wolopts = phydev->wol;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(phy_ethtool_get_wol);
|
||||
|
||||
/**
|
||||
* phy_mii_ioctl - generic PHY MII ioctl interface
|
||||
* @phydev: the phy_device struct
|
||||
@@ -510,7 +540,7 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
|
||||
{
|
||||
struct phy_device *phydev = phy_dat;
|
||||
|
||||
if (PHY_HALTED == phydev->state)
|
||||
if ((PHY_HALTED == phydev->state) && (!device_may_wakeup(&phydev->dev)))
|
||||
return IRQ_NONE; /* It can't be ours. */
|
||||
|
||||
/* The MDIO bus is not allowed to be written in interrupt
|
||||
@@ -964,3 +994,35 @@ static void phy_state_machine(struct work_struct *work)
|
||||
|
||||
schedule_delayed_work(&phydev->state_queue, PHY_STATE_TIME * HZ);
|
||||
}
|
||||
|
||||
int phy_read_page(struct phy_device *phydev, u16 regnum, int page)
|
||||
{
|
||||
int ret, old;
|
||||
|
||||
old = phy_read(phydev, 20);
|
||||
|
||||
/* Write the page in 0.20 reg */
|
||||
phy_write(phydev, 20, page);
|
||||
/* Read data from user page for the regnum */
|
||||
ret = phy_read(phydev, regnum);
|
||||
/* Restore page0 */
|
||||
phy_write(phydev, 20, old);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(phy_read_page);
|
||||
|
||||
int phy_write_page(struct phy_device *phydev, u16 regnum, int page, int data)
|
||||
{
|
||||
int old = phy_read(phydev, 20);
|
||||
|
||||
/* Write the page in 0.20 reg */
|
||||
phy_write(phydev, 20, page);
|
||||
/* Write date to page for regnum */
|
||||
phy_write(phydev, regnum, data);
|
||||
/* Restore page0 */
|
||||
phy_write(phydev, 20, old);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(phy_write_page);
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include <linux/mii.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/mdio.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
@@ -874,6 +875,140 @@ int genphy_resume(struct phy_device *phydev)
|
||||
}
|
||||
EXPORT_SYMBOL(genphy_resume);
|
||||
|
||||
static inline void mmd_phy_cl45(struct mii_bus *bus, int prtad, int devad,
|
||||
int addr)
|
||||
{
|
||||
/* Write the desired MMD Devad */
|
||||
bus->write(bus, addr, MII_MMD_CRTL, devad);
|
||||
|
||||
/* Write the desired MMD register address */
|
||||
bus->write(bus, addr, MII_MMD_DATA, prtad);
|
||||
|
||||
/* Select the Function : DATA with no post increment */
|
||||
bus->write(bus, addr, MII_MMD_CRTL,
|
||||
(devad | MII_MMD_CTRL_FUNC_DATA_NOINCR));
|
||||
}
|
||||
|
||||
/**
|
||||
* read_phy_mmd - reads data from the MMD register (clause 22 to access to
|
||||
* clause 45)
|
||||
* @bus: the target MII bus
|
||||
* @prtad: MMD Address
|
||||
* @devad: MMD DEVAD
|
||||
* @addr: PHY address on the MII bus
|
||||
*
|
||||
* Description: Reads data from the MMD regisetrs of the
|
||||
* phy addr. To read these register we have:
|
||||
* 1) Write reg 13 // DEVAD
|
||||
* 2) Write reg 14 // MMD Address
|
||||
* 3) Write reg 13 // MMD Data Command for MMD DEVAD
|
||||
* 3) Read reg 14 // Read MMD data
|
||||
*/
|
||||
static int read_phy_mmd(struct mii_bus *bus, int prtad, int devad, int addr)
|
||||
{
|
||||
u32 ret;
|
||||
|
||||
mmd_phy_cl45(bus, prtad, devad, addr);
|
||||
|
||||
/* Read the content of the MMD's selected register */
|
||||
ret = bus->read(bus, addr, MII_MMD_DATA);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* write_phy_mmd - writes data to the MMD register (clause 22 to access to
|
||||
* clause 45)
|
||||
* @bus: the target MII bus
|
||||
* @prtad: MMD Address
|
||||
* @devad: MMD DEVAD
|
||||
* @addr: PHY address on the MII bus
|
||||
* @data: data to write in the MMD register
|
||||
*
|
||||
* Description: write data from the MMD regisetrs of the
|
||||
* phy addr. To read these register we have:
|
||||
* 1) Write reg 13 // DEVAD
|
||||
* 2) Write reg 14 // MMD Address
|
||||
* 3) Write reg 13 // MMD Data Command for MMD DEVAD
|
||||
* 3) Write reg 14 // Write MMD data
|
||||
*/
|
||||
static void write_phy_mmd(struct mii_bus *bus, int prtad, int devad, int addr,
|
||||
u32 data)
|
||||
{
|
||||
mmd_phy_cl45(bus, prtad, devad, addr);
|
||||
|
||||
/* Write the data into MMD's selected register */
|
||||
bus->write(bus, addr, MII_MMD_DATA, data);
|
||||
}
|
||||
|
||||
/* phy_check_eee
|
||||
* @dev: device to probe and init
|
||||
*
|
||||
* Description: check if the Energy-Efficient Ethernet (EEE)
|
||||
* is supported by looking at the MMD registers 3.20 and 3.60/61
|
||||
*/
|
||||
int phy_check_eee(struct phy_device *phydev)
|
||||
{
|
||||
int ret = -EPROTONOSUPPORT;
|
||||
|
||||
/* According to 802.3az,the EEE is supported only in full duplex-mode.
|
||||
* Also EEE feature is active when core is operating with MII, GMII
|
||||
* or RGMII */
|
||||
if ((phydev->duplex == DUPLEX_FULL) &&
|
||||
((phydev->interface == PHY_INTERFACE_MODE_MII) ||
|
||||
(phydev->interface == PHY_INTERFACE_MODE_GMII) ||
|
||||
(phydev->interface == PHY_INTERFACE_MODE_RGMII))) {
|
||||
int eee_cap, eee_link;
|
||||
|
||||
/* EEE ability must be supported in both local and remote
|
||||
* PHY devices. */
|
||||
eee_cap = read_phy_mmd(phydev->bus, MDIO_EEE_PART_LINK,
|
||||
MDIO_MMD_AN, phydev->addr);
|
||||
if (eee_cap < 0)
|
||||
return eee_cap;
|
||||
|
||||
eee_link = read_phy_mmd(phydev->bus, MDIO_EEE_CAP,
|
||||
MDIO_MMD_PCS, phydev->addr);
|
||||
if (eee_link < 0)
|
||||
return eee_link;
|
||||
|
||||
if (eee_cap && eee_link) {
|
||||
/* Configure the PHY to stop receiving xMII clock
|
||||
* while it is signaling LPI */
|
||||
int pcs_ctrl = read_phy_mmd(phydev->bus, MDIO_CTRL1,
|
||||
MDIO_MMD_PCS,
|
||||
phydev->addr);
|
||||
if (pcs_ctrl < 0)
|
||||
return pcs_ctrl;
|
||||
|
||||
pcs_ctrl |= MDIO_PCS_CLK_STOP_ENABLE;
|
||||
write_phy_mmd(phydev->bus, MDIO_CTRL1, MDIO_MMD_PCS,
|
||||
phydev->addr, pcs_ctrl);
|
||||
|
||||
ret = 0; /* EEE supported */
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(phy_get_eee_err);
|
||||
|
||||
/* phy_get_eee_err
|
||||
* @dev: device to probe and init
|
||||
*
|
||||
* Description: it is to report the number of time where the PHY
|
||||
* failed to complete its normal wake sequence.
|
||||
*/
|
||||
int phy_get_eee_err(struct phy_device *phydev)
|
||||
{
|
||||
return read_phy_mmd(phydev->bus, MDIO_EEE_WK_ERR, MDIO_MMD_PCS,
|
||||
phydev->addr);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(phy_check_eee);
|
||||
|
||||
/**
|
||||
* phy_probe - probe and init a PHY device
|
||||
* @dev: device to probe and init
|
||||
@@ -900,6 +1035,13 @@ static int phy_probe(struct device *dev)
|
||||
/* Disable the interrupt if the PHY doesn't support it */
|
||||
if (!(phydrv->flags & PHY_HAS_INTERRUPT))
|
||||
phydev->irq = PHY_POLL;
|
||||
else {
|
||||
/* Check if the PHY is WoL capable but driver cannot work
|
||||
* in polling mode.
|
||||
*/
|
||||
if (phydrv->wol_supported)
|
||||
device_set_wakeup_capable(dev, 1);
|
||||
}
|
||||
|
||||
mutex_lock(&phydev->lock);
|
||||
|
||||
|
Reference in New Issue
Block a user