diff mbox

Using phylib with a MAC-handled interrupt

Message ID 20121009181727.1845ab85@skate
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

Thomas Petazzoni Oct. 9, 2012, 4:17 p.m. UTC
Hello Andy,

I am currently working on a network driver for the MAC present in the
latest Marvell ARM SoCs. This MAC is capable of polling the PHY in
hardware, which avoids the need for Linux to poll the PHY regularly.

Therefore, I am currently trying to do an integration of the driver with
the phylib using the third solution you listed at
http://lists.openwall.net/netdev/2008/06/06/38.

Unfortunately, with the current Linux kernel, the phylib continues to
poll the PHY registers regularly even if phydev->irq is set to
PHY_IGNORE_INTERRUPT. This is due to the fact that the phylib code
override phydev->irq to be PHY_POLL whenever the PHY driver doesn't
support interrupt, which isn't correct. This is fixed by the below
patch.

However, even with the below patch, I cannot implement your solution
three described in http://lists.openwall.net/netdev/2008/06/06/38 :
taking a mutex in an interrupt handler is not possible. Therefore, I
cannot change the phydev->state field from my MAC driver to force the
PHY state machine to re-read the status of the PHY.

I tried to force the execution of the phydev->phy_queue workqueue, but
unfortunately, simply calling schedule_work(&phydev->phy_queue)
from my interrupt handler causes problems:

WARNING: at /home/thomas/projets/linux-2.6/kernel/workqueue.c:1033 __queue_work+0x1c0/0x1d8()

This is apparently because schedule_work() doesn't like when the
workqueue is already scheduled for execution, but I am not sure how to
properly handle this case.

What I would like to do is from my MAC interrupt handler, tell the
phylib "hey, something has changed, you should re-read the PHY
registers and if needed call my ->adjust_link() callback".

How can I do that with the phylib?

Thanks,

Thomas

From 3eae62a1adb08229ea4d20068ef868b731b020cb Mon Sep 17 00:00:00 2001
From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Date: Tue, 9 Oct 2012 18:10:21 +0200
Subject: [PATCH] net: phy: fix support of PHY_IGNORE_INTERRUPT

When PHY_IGNORE_INTERRUPT is set as the phydev->irq, then the phylib
shouldn't poll the PHY regularly, but instead let the MAC driver tell
the phylib when to re-read the PHY status. Unfortunately, as soon as
the PHY didn't had PHY_HAS_INTERRUPT set, the phylib was forcing
PHY_POLL as the interrupt.

Also fix two other places that test against PHY_POLL while they should
instead be testing if we have an IRQ or not.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
 drivers/net/phy/phy.c        |    4 ++--
 drivers/net/phy/phy_device.c |    2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
diff mbox

Patch

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 7ca2ff9..a1d265f 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -709,7 +709,7 @@  void phy_stop(struct phy_device *phydev)
 	if (PHY_HALTED == phydev->state)
 		goto out_unlock;
 
-	if (phydev->irq != PHY_POLL) {
+	if (phydev->irq > 0) {
 		/* Disable PHY Interrupts */
 		phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
 
@@ -896,7 +896,7 @@  void phy_state_machine(struct work_struct *work)
 
 			phydev->adjust_link(phydev->attached_dev);
 
-			if (PHY_POLL != phydev->irq)
+			if (phydev->irq > 0)
 				err = phy_config_interrupt(phydev,
 						PHY_INTERRUPT_ENABLED);
 			break;
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 8af46e8..110b3a3 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1011,7 +1011,7 @@  static int phy_probe(struct device *dev)
 	phydev->drv = phydrv;
 
 	/* Disable the interrupt if the PHY doesn't support it */
-	if (!(phydrv->flags & PHY_HAS_INTERRUPT))
+	if (!(phydrv->flags & PHY_HAS_INTERRUPT) && phydev->irq > 0)
 		phydev->irq = PHY_POLL;
 
 	mutex_lock(&phydev->lock);