aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/phy.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-02-01 18:56:08 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-02-01 18:56:08 -0500
commit34229b277480f46c1e9a19f027f30b074512e68b (patch)
tree90d8b43ebceb850b0e7852d75283aebbd2abbc00 /drivers/net/phy/phy.c
parent2c923414d3963b959f65a8a6031972402e6a34a5 (diff)
parent53729eb174c1589f9185340ffe8c10b3f39f3ef3 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull networking fixes from David Miller: "This looks like a lot but it's a mixture of regression fixes as well as fixes for longer standing issues. 1) Fix on-channel cancellation in mac80211, from Johannes Berg. 2) Handle CHECKSUM_COMPLETE properly in xt_TCPMSS netfilter xtables module, from Eric Dumazet. 3) Avoid infinite loop in UDP SO_REUSEPORT logic, also from Eric Dumazet. 4) Avoid a NULL deref if we try to set SO_REUSEPORT after a socket is bound, from Craig Gallek. 5) GRO key comparisons don't take lightweight tunnels into account, from Jesse Gross. 6) Fix struct pid leak via SCM credentials in AF_UNIX, from Eric Dumazet. 7) We need to set the rtnl_link_ops of ipv6 SIT tunnels before we register them, otherwise the NEWLINK netlink message is missing the proper attributes. From Thadeu Lima de Souza Cascardo. 8) Several Spectrum chip bug fixes for mlxsw switch driver, from Ido Schimmel 9) Handle fragments properly in ipv4 easly socket demux, from Eric Dumazet. 10) Don't ignore the ifindex key specifier on ipv6 output route lookups, from Paolo Abeni" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (128 commits) tcp: avoid cwnd undo after receiving ECN irda: fix a potential use-after-free in ircomm_param_request net: tg3: avoid uninitialized variable warning net: nb8800: avoid uninitialized variable warning net: vxge: avoid unused function warnings net: bgmac: clarify CONFIG_BCMA dependency net: hp100: remove unnecessary #ifdefs net: davinci_cpdma: use dma_addr_t for DMA address ipv6/udp: use sticky pktinfo egress ifindex on connect() ipv6: enforce flowi6_oif usage in ip6_dst_lookup_tail() netlink: not trim skb for mmaped socket when dump vxlan: fix a out of bounds access in __vxlan_find_mac net: dsa: mv88e6xxx: fix port VLAN maps fib_trie: Fix shift by 32 in fib_table_lookup net: moxart: use correct accessors for DMA memory ipv4: ipconfig: avoid unused ic_proto_used symbol bnxt_en: Fix crash in bnxt_free_tx_skbs() during tx timeout. bnxt_en: Exclude rx_drop_pkts hw counter from the stack's rx_dropped counter. bnxt_en: Ring free response from close path should use completion ring net_sched: drr: check for NULL pointer in drr_dequeue ...
Diffstat (limited to 'drivers/net/phy/phy.c')
-rw-r--r--drivers/net/phy/phy.c46
1 files changed, 28 insertions, 18 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 8763bb20988a..5590b9c182c9 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -692,25 +692,29 @@ void phy_change(struct work_struct *work)
692 struct phy_device *phydev = 692 struct phy_device *phydev =
693 container_of(work, struct phy_device, phy_queue); 693 container_of(work, struct phy_device, phy_queue);
694 694
695 if (phydev->drv->did_interrupt && 695 if (phy_interrupt_is_valid(phydev)) {
696 !phydev->drv->did_interrupt(phydev)) 696 if (phydev->drv->did_interrupt &&
697 goto ignore; 697 !phydev->drv->did_interrupt(phydev))
698 goto ignore;
698 699
699 if (phy_disable_interrupts(phydev)) 700 if (phy_disable_interrupts(phydev))
700 goto phy_err; 701 goto phy_err;
702 }
701 703
702 mutex_lock(&phydev->lock); 704 mutex_lock(&phydev->lock);
703 if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state)) 705 if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
704 phydev->state = PHY_CHANGELINK; 706 phydev->state = PHY_CHANGELINK;
705 mutex_unlock(&phydev->lock); 707 mutex_unlock(&phydev->lock);
706 708
707 atomic_dec(&phydev->irq_disable); 709 if (phy_interrupt_is_valid(phydev)) {
708 enable_irq(phydev->irq); 710 atomic_dec(&phydev->irq_disable);
711 enable_irq(phydev->irq);
709 712
710 /* Reenable interrupts */ 713 /* Reenable interrupts */
711 if (PHY_HALTED != phydev->state && 714 if (PHY_HALTED != phydev->state &&
712 phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED)) 715 phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED))
713 goto irq_enable_err; 716 goto irq_enable_err;
717 }
714 718
715 /* reschedule state queue work to run as soon as possible */ 719 /* reschedule state queue work to run as soon as possible */
716 cancel_delayed_work_sync(&phydev->state_queue); 720 cancel_delayed_work_sync(&phydev->state_queue);
@@ -905,10 +909,10 @@ void phy_state_machine(struct work_struct *work)
905 phydev->adjust_link(phydev->attached_dev); 909 phydev->adjust_link(phydev->attached_dev);
906 break; 910 break;
907 case PHY_RUNNING: 911 case PHY_RUNNING:
908 /* Only register a CHANGE if we are polling or ignoring 912 /* Only register a CHANGE if we are polling and link changed
909 * interrupts and link changed since latest checking. 913 * since latest checking.
910 */ 914 */
911 if (!phy_interrupt_is_valid(phydev)) { 915 if (phydev->irq == PHY_POLL) {
912 old_link = phydev->link; 916 old_link = phydev->link;
913 err = phy_read_status(phydev); 917 err = phy_read_status(phydev);
914 if (err) 918 if (err)
@@ -1000,15 +1004,21 @@ void phy_state_machine(struct work_struct *work)
1000 phy_state_to_str(old_state), 1004 phy_state_to_str(old_state),
1001 phy_state_to_str(phydev->state)); 1005 phy_state_to_str(phydev->state));
1002 1006
1003 queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 1007 /* Only re-schedule a PHY state machine change if we are polling the
1004 PHY_STATE_TIME * HZ); 1008 * PHY, if PHY_IGNORE_INTERRUPT is set, then we will be moving
1009 * between states from phy_mac_interrupt()
1010 */
1011 if (phydev->irq == PHY_POLL)
1012 queue_delayed_work(system_power_efficient_wq, &phydev->state_queue,
1013 PHY_STATE_TIME * HZ);
1005} 1014}
1006 1015
1007void phy_mac_interrupt(struct phy_device *phydev, int new_link) 1016void phy_mac_interrupt(struct phy_device *phydev, int new_link)
1008{ 1017{
1009 cancel_work_sync(&phydev->phy_queue);
1010 phydev->link = new_link; 1018 phydev->link = new_link;
1011 schedule_work(&phydev->phy_queue); 1019
1020 /* Trigger a state machine change */
1021 queue_work(system_power_efficient_wq, &phydev->phy_queue);
1012} 1022}
1013EXPORT_SYMBOL(phy_mac_interrupt); 1023EXPORT_SYMBOL(phy_mac_interrupt);
1014 1024