summaryrefslogtreecommitdiff
path: root/drivers/net/phy/marvell.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/marvell.c')
-rw-r--r--drivers/net/phy/marvell.c102
1 files changed, 80 insertions, 22 deletions
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index f71cffa88406..2c688d661297 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -55,6 +55,8 @@
#define MII_M1011_IMASK 0x12
#define MII_M1011_IMASK_INIT 0x6400
#define MII_M1011_IMASK_CLEAR 0x0000
+/* WOL Event Interrupt Enable, 88E1318S and 88E1510 only */
+#define MII_M1011_IMASK_WOL BIT(7)
#define MII_M1011_PHY_SCR 0x10
#define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11)
@@ -139,11 +141,6 @@
#define MII_88E1318S_PHY_MSCR1_REG 16
#define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6)
-/* Copper Specific Interrupt Enable Register */
-#define MII_88E1318S_PHY_CSIER 0x12
-/* WOL Event Interrupt Enable */
-#define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7)
-
#define MII_88E1318S_PHY_LED_FUNC 0x10
#define MII_88E1318S_PHY_LED_FUNC_OFF (0x8)
#define MII_88E1318S_PHY_LED_FUNC_ON (0x9)
@@ -354,6 +351,7 @@ struct marvell_priv {
u32 step;
s8 pair;
u8 vct_phase;
+ bool wol_enabled;
};
static int marvell_read_page(struct phy_device *phydev)
@@ -407,7 +405,8 @@ static int marvell_config_intr(struct phy_device *phydev)
return err;
}
-static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev)
+static irqreturn_t __marvell_handle_interrupt(struct phy_device *phydev,
+ u16 mask)
{
int irq_status;
@@ -417,7 +416,7 @@ static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev)
return IRQ_NONE;
}
- if (!(irq_status & MII_M1011_IMASK_INIT))
+ if (!(irq_status & mask))
return IRQ_NONE;
phy_trigger_machine(phydev);
@@ -425,6 +424,57 @@ static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev)
return IRQ_HANDLED;
}
+static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev)
+{
+ return __marvell_handle_interrupt(phydev, MII_M1011_IMASK_INIT);
+}
+
+/* WOL_EIE also routes WoL events to INTn. Keep it set while WoL is enabled,
+ * unless INTn is the PHY interrupt and that interrupt is being disabled:
+ * nothing would read IEVENT after free_irq() to release the line.
+ */
+static u16 m88e1318_wol_imask(struct phy_device *phydev)
+{
+ struct marvell_priv *priv = phydev->priv;
+
+ if (priv->wol_enabled &&
+ (phydev->interrupts == PHY_INTERRUPT_ENABLED ||
+ !phy_interrupt_is_valid(phydev)))
+ return MII_M1011_IMASK_WOL;
+
+ return 0;
+}
+
+static int m88e1318_config_intr(struct phy_device *phydev)
+{
+ bool enable = phydev->interrupts == PHY_INTERRUPT_ENABLED;
+ u16 imask;
+ int err;
+
+ if (enable) {
+ err = marvell_ack_interrupt(phydev);
+ if (err)
+ return err;
+ }
+
+ /* Serialise against m88e1318_set_wol() updating wol_enabled */
+ phy_lock_mdio_bus(phydev);
+ imask = enable ? MII_M1011_IMASK_INIT : MII_M1011_IMASK_CLEAR;
+ imask |= m88e1318_wol_imask(phydev);
+ err = __phy_write(phydev, MII_M1011_IMASK, imask);
+ phy_unlock_mdio_bus(phydev);
+ if (err || enable)
+ return err;
+
+ return marvell_ack_interrupt(phydev);
+}
+
+static irqreturn_t m88e1318_handle_interrupt(struct phy_device *phydev)
+{
+ return __marvell_handle_interrupt(phydev, MII_M1011_IMASK_INIT |
+ MII_M1011_IMASK_WOL);
+}
+
static int marvell_set_polarity(struct phy_device *phydev, int polarity)
{
u16 val;
@@ -1969,18 +2019,27 @@ static void m88e1318_get_wol(struct phy_device *phydev,
static int m88e1318_set_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol)
{
+ struct marvell_priv *priv = phydev->priv;
int err = 0, oldpage;
oldpage = phy_save_page(phydev);
if (oldpage < 0)
goto error;
- if (wol->wolopts & (WAKE_MAGIC | WAKE_PHY)) {
- /* Explicitly switch to page 0x00, just to be sure */
- err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE);
- if (err < 0)
- goto error;
+ priv->wol_enabled = !!(wol->wolopts & (WAKE_MAGIC | WAKE_PHY));
+
+ /* Explicitly switch to page 0x00, just to be sure */
+ err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE);
+ if (err < 0)
+ goto error;
+
+ /* Update the WOL interrupt enable */
+ err = __phy_modify(phydev, MII_M1011_IMASK, MII_M1011_IMASK_WOL,
+ m88e1318_wol_imask(phydev));
+ if (err < 0)
+ goto error;
+ if (priv->wol_enabled) {
/* If WOL event happened once, the LED[2] interrupt pin
* will not be cleared unless we reading the interrupt status
* register. If interrupts are in use, the normal interrupt
@@ -1990,12 +2049,6 @@ static int m88e1318_set_wol(struct phy_device *phydev,
if (!phy_interrupt_is_valid(phydev))
__phy_read(phydev, MII_M1011_IEVENT);
- /* Enable the WOL interrupt */
- err = __phy_set_bits(phydev, MII_88E1318S_PHY_CSIER,
- MII_88E1318S_PHY_CSIER_WOL_EIE);
- if (err < 0)
- goto error;
-
err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE);
if (err < 0)
goto error;
@@ -3817,8 +3870,8 @@ static struct phy_driver marvell_drivers[] = {
.config_init = m88e1318_config_init,
.config_aneg = m88e1318_config_aneg,
.read_status = marvell_read_status,
- .config_intr = marvell_config_intr,
- .handle_interrupt = marvell_handle_interrupt,
+ .config_intr = m88e1318_config_intr,
+ .handle_interrupt = m88e1318_handle_interrupt,
.get_wol = m88e1318_get_wol,
.set_wol = m88e1318_set_wol,
.resume = genphy_resume,
@@ -3913,6 +3966,11 @@ static struct phy_driver marvell_drivers[] = {
.get_stats = marvell_get_stats,
.get_tunable = m88e1011_get_tunable,
.set_tunable = m88e1011_set_tunable,
+ .led_brightness_set = m88e1318_led_brightness_set,
+ .led_blink_set = m88e1318_led_blink_set,
+ .led_hw_is_supported = m88e1318_led_hw_is_supported,
+ .led_hw_control_set = m88e1318_led_hw_control_set,
+ .led_hw_control_get = m88e1318_led_hw_control_get,
},
{
.phy_id = MARVELL_PHY_ID_88E1510,
@@ -3925,8 +3983,8 @@ static struct phy_driver marvell_drivers[] = {
.config_init = m88e1510_config_init,
.config_aneg = m88e1510_config_aneg,
.read_status = marvell_read_status,
- .config_intr = marvell_config_intr,
- .handle_interrupt = marvell_handle_interrupt,
+ .config_intr = m88e1318_config_intr,
+ .handle_interrupt = m88e1318_handle_interrupt,
.get_wol = m88e1318_get_wol,
.set_wol = m88e1318_set_wol,
.resume = m88e1510_resume,