Commit 92e8c831 authored by David S. Miller's avatar David S. Miller

Merge branch 'phy'

Florian Fainelli says:

====================
net: phy: soft reset rework for 10G PHYs

As reported by Shaohui, 10G PHYs may have a slightly more complex reset
sequence for which a BMCR_RESET software reset might not suffice. This
patchset offers a solution for those by allowing them to implement their
own soft_reset() callback. Finally there is an update to the PHY library
Documentation to cover for the newly added callbacks of the PHY driver
structure.

Changes in v2:
- fixed callback testing
- fixed typo in Documentation
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ee0c4c39 7f6224b7
...@@ -253,16 +253,25 @@ Writing a PHY driver ...@@ -253,16 +253,25 @@ Writing a PHY driver
Each driver consists of a number of function pointers: Each driver consists of a number of function pointers:
soft_reset: perform a PHY software reset
config_init: configures PHY into a sane state after a reset. config_init: configures PHY into a sane state after a reset.
For instance, a Davicom PHY requires descrambling disabled. For instance, a Davicom PHY requires descrambling disabled.
probe: Allocate phy->priv, optionally refuse to bind. probe: Allocate phy->priv, optionally refuse to bind.
PHY may not have been reset or had fixups run yet. PHY may not have been reset or had fixups run yet.
suspend/resume: power management suspend/resume: power management
config_aneg: Changes the speed/duplex/negotiation settings config_aneg: Changes the speed/duplex/negotiation settings
aneg_done: Determines the auto-negotiation result
read_status: Reads the current speed/duplex/negotiation settings read_status: Reads the current speed/duplex/negotiation settings
ack_interrupt: Clear a pending interrupt ack_interrupt: Clear a pending interrupt
did_interrupt: Checks if the PHY generated an interrupt
config_intr: Enable or disable interrupts config_intr: Enable or disable interrupts
remove: Does any driver take-down remove: Does any driver take-down
ts_info: Queries about the HW timestamping status
hwtstamp: Set the PHY HW timestamping configuration
rxtstamp: Requests a receive timestamp at the PHY level for a 'skb'
txtsamp: Requests a transmit timestamp at the PHY level for a 'skb'
set_wol: Enable Wake-on-LAN at the PHY level
get_wol: Get the Wake-on-LAN status at the PHY level
Of these, only config_aneg and read_status are required to be Of these, only config_aneg and read_status are required to be
assigned by the driver code. The rest are optional. Also, it is assigned by the driver code. The rest are optional. Also, it is
......
...@@ -535,16 +535,16 @@ static int phy_poll_reset(struct phy_device *phydev) ...@@ -535,16 +535,16 @@ static int phy_poll_reset(struct phy_device *phydev)
int phy_init_hw(struct phy_device *phydev) int phy_init_hw(struct phy_device *phydev)
{ {
int ret; int ret = 0;
if (!phydev->drv || !phydev->drv->config_init) if (!phydev->drv || !phydev->drv->config_init)
return 0; return 0;
ret = phy_write(phydev, MII_BMCR, BMCR_RESET); if (phydev->drv->soft_reset)
if (ret < 0) ret = phydev->drv->soft_reset(phydev);
return ret; else
ret = genphy_soft_reset(phydev);
ret = phy_poll_reset(phydev);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1045,6 +1045,27 @@ static int gen10g_read_status(struct phy_device *phydev) ...@@ -1045,6 +1045,27 @@ static int gen10g_read_status(struct phy_device *phydev)
return 0; return 0;
} }
/**
* genphy_soft_reset - software reset the PHY via BMCR_RESET bit
* @phydev: target phy_device struct
*
* Description: Perform a software PHY reset using the standard
* BMCR_RESET bit and poll for the reset bit to be cleared.
*
* Returns: 0 on success, < 0 on failure
*/
int genphy_soft_reset(struct phy_device *phydev)
{
int ret;
ret = phy_write(phydev, MII_BMCR, BMCR_RESET);
if (ret < 0)
return ret;
return phy_poll_reset(phydev);
}
EXPORT_SYMBOL(genphy_soft_reset);
static int genphy_config_init(struct phy_device *phydev) static int genphy_config_init(struct phy_device *phydev)
{ {
int val; int val;
...@@ -1091,6 +1112,12 @@ static int genphy_config_init(struct phy_device *phydev) ...@@ -1091,6 +1112,12 @@ static int genphy_config_init(struct phy_device *phydev)
return 0; return 0;
} }
static int gen10g_soft_reset(struct phy_device *phydev)
{
/* Do nothing for now */
return 0;
}
static int gen10g_config_init(struct phy_device *phydev) static int gen10g_config_init(struct phy_device *phydev)
{ {
/* Temporarily just say we support everything */ /* Temporarily just say we support everything */
...@@ -1265,6 +1292,7 @@ static struct phy_driver genphy_driver[] = { ...@@ -1265,6 +1292,7 @@ static struct phy_driver genphy_driver[] = {
.phy_id = 0xffffffff, .phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff, .phy_id_mask = 0xffffffff,
.name = "Generic PHY", .name = "Generic PHY",
.soft_reset = genphy_soft_reset,
.config_init = genphy_config_init, .config_init = genphy_config_init,
.features = 0, .features = 0,
.config_aneg = genphy_config_aneg, .config_aneg = genphy_config_aneg,
...@@ -1277,6 +1305,7 @@ static struct phy_driver genphy_driver[] = { ...@@ -1277,6 +1305,7 @@ static struct phy_driver genphy_driver[] = {
.phy_id = 0xffffffff, .phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff, .phy_id_mask = 0xffffffff,
.name = "Generic 10G PHY", .name = "Generic 10G PHY",
.soft_reset = gen10g_soft_reset,
.config_init = gen10g_config_init, .config_init = gen10g_config_init,
.features = 0, .features = 0,
.config_aneg = gen10g_config_aneg, .config_aneg = gen10g_config_aneg,
......
...@@ -439,6 +439,11 @@ struct phy_driver { ...@@ -439,6 +439,11 @@ struct phy_driver {
u32 features; u32 features;
u32 flags; u32 flags;
/*
* Called to issue a PHY software reset
*/
int (*soft_reset)(struct phy_device *phydev);
/* /*
* Called to initialize the PHY, * Called to initialize the PHY,
* including after a reset * including after a reset
...@@ -666,6 +671,7 @@ int genphy_update_link(struct phy_device *phydev); ...@@ -666,6 +671,7 @@ int genphy_update_link(struct phy_device *phydev);
int genphy_read_status(struct phy_device *phydev); int genphy_read_status(struct phy_device *phydev);
int genphy_suspend(struct phy_device *phydev); int genphy_suspend(struct phy_device *phydev);
int genphy_resume(struct phy_device *phydev); int genphy_resume(struct phy_device *phydev);
int genphy_soft_reset(struct phy_device *phydev);
void phy_driver_unregister(struct phy_driver *drv); void phy_driver_unregister(struct phy_driver *drv);
void phy_drivers_unregister(struct phy_driver *drv, int n); void phy_drivers_unregister(struct phy_driver *drv, int n);
int phy_driver_register(struct phy_driver *new_driver); int phy_driver_register(struct phy_driver *new_driver);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment