Commit a8729eb302a5b5da8b0b4d29582c42648a2e0f12
Committed by
David S. Miller
1 parent
140bc92903
Exists in
master
and in
39 other branches
phylib: Allow early-out in phy_change
Marvell 88E1121R Dual PHY device can be hardware-configured to use shared interrupt pin for both PHY ports. For such PHY configurations using shared PHY interrupt phy_interrupt() handler will also schedule a work for PHY port which didn't cause an interrupt. This patch adds a possibility for PHY drivers to provide did_interrupt() function which reports if the PHY (or a PHY port in a multi-PHY device) generated an interrupt. This function is called in phy_change() as phy_change() shouldn't proceed if it is invoked for a PHY which didn't cause an interrupt. So check for interrupt originator in phy_change() to allow early-out. Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 2 changed files with 15 additions and 0 deletions Side-by-side Diff
drivers/net/phy/phy.c
... | ... | @@ -655,6 +655,10 @@ |
655 | 655 | struct phy_device *phydev = |
656 | 656 | container_of(work, struct phy_device, phy_queue); |
657 | 657 | |
658 | + if (phydev->drv->did_interrupt && | |
659 | + !phydev->drv->did_interrupt(phydev)) | |
660 | + goto ignore; | |
661 | + | |
658 | 662 | err = phy_disable_interrupts(phydev); |
659 | 663 | |
660 | 664 | if (err) |
... | ... | @@ -679,6 +683,11 @@ |
679 | 683 | cancel_delayed_work_sync(&phydev->state_queue); |
680 | 684 | schedule_delayed_work(&phydev->state_queue, 0); |
681 | 685 | |
686 | + return; | |
687 | + | |
688 | +ignore: | |
689 | + atomic_dec(&phydev->irq_disable); | |
690 | + enable_irq(phydev->irq); | |
682 | 691 | return; |
683 | 692 | |
684 | 693 | irq_enable_err: |
include/linux/phy.h
... | ... | @@ -388,6 +388,12 @@ |
388 | 388 | /* Enables or disables interrupts */ |
389 | 389 | int (*config_intr)(struct phy_device *phydev); |
390 | 390 | |
391 | + /* | |
392 | + * Checks if the PHY generated an interrupt. | |
393 | + * For multi-PHY devices with shared PHY interrupt pin | |
394 | + */ | |
395 | + int (*did_interrupt)(struct phy_device *phydev); | |
396 | + | |
391 | 397 | /* Clears up any memory if needed */ |
392 | 398 | void (*remove)(struct phy_device *phydev); |
393 | 399 |