RDMA/nes: Fix SFP+ link down detection issue with switch port disable

In case of SFP+ PHY, link status check at interrupt processing can
give false results. For proper link status change detection a delayed
recheck is needed to give nes registers time to settle. Add a
periodic link status recheck scheduled at interrupt to detect
potential delayed registers state changes.

Addresses: http://bugs.openfabrics.org/bugzilla/show_bug.cgi?id=2117
Signed-off-by: Maciej Sosnowski <maciej.sosnowski@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>

authored by Maciej Sosnowski and committed by Roland Dreier 5f61b2c6 ea623455

+100
+11
drivers/infiniband/hw/nes/nes.c
··· 674 674 } 675 675 nes_notifiers_registered++; 676 676 677 + INIT_DELAYED_WORK(&nesdev->work, nes_recheck_link_status); 678 + 677 679 /* Initialize network devices */ 678 680 if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL) 679 681 goto bail7; ··· 758 756 struct nes_device *nesdev = pci_get_drvdata(pcidev); 759 757 struct net_device *netdev; 760 758 int netdev_index = 0; 759 + unsigned long flags; 761 760 762 761 if (nesdev->netdev_count) { 763 762 netdev = nesdev->netdev[netdev_index]; ··· 784 781 785 782 free_irq(pcidev->irq, nesdev); 786 783 tasklet_kill(&nesdev->dpc_tasklet); 784 + 785 + spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags); 786 + if (nesdev->link_recheck) { 787 + spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); 788 + cancel_delayed_work_sync(&nesdev->work); 789 + } else { 790 + spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); 791 + } 787 792 788 793 /* Deallocate the Adapter Structure */ 789 794 nes_destroy_adapter(nesdev->nesadapter);
+4
drivers/infiniband/hw/nes/nes.h
··· 268 268 u8 napi_isr_ran; 269 269 u8 disable_rx_flow_control; 270 270 u8 disable_tx_flow_control; 271 + 272 + struct delayed_work work; 273 + u8 link_recheck; 271 274 }; 272 275 273 276 ··· 510 507 void nes_iwarp_ce_handler(struct nes_device *, struct nes_hw_cq *); 511 508 int nes_destroy_cqp(struct nes_device *); 512 509 int nes_nic_cm_xmit(struct sk_buff *, struct net_device *); 510 + void nes_recheck_link_status(struct work_struct *work); 513 511 514 512 /* nes_nic.c */ 515 513 struct net_device *nes_netdev_init(struct nes_device *, void __iomem *);
+81
drivers/infiniband/hw/nes/nes_hw.c
··· 2650 2650 } 2651 2651 } 2652 2652 } 2653 + if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_SFP_D) { 2654 + if (nesdev->link_recheck) 2655 + cancel_delayed_work(&nesdev->work); 2656 + nesdev->link_recheck = 1; 2657 + schedule_delayed_work(&nesdev->work, 2658 + NES_LINK_RECHECK_DELAY); 2659 + } 2653 2660 } 2654 2661 2655 2662 spin_unlock_irqrestore(&nesadapter->phy_lock, flags); ··· 2664 2657 nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_IDLE; 2665 2658 } 2666 2659 2660 + void nes_recheck_link_status(struct work_struct *work) 2661 + { 2662 + unsigned long flags; 2663 + struct nes_device *nesdev = container_of(work, struct nes_device, work.work); 2664 + struct nes_adapter *nesadapter = nesdev->nesadapter; 2665 + struct nes_vnic *nesvnic; 2666 + u32 mac_index = nesdev->mac_index; 2667 + u16 phy_data; 2668 + u16 temp_phy_data; 2669 + 2670 + spin_lock_irqsave(&nesadapter->phy_lock, flags); 2671 + 2672 + /* check link status */ 2673 + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003); 2674 + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); 2675 + 2676 + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021); 2677 + nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); 2678 + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021); 2679 + phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); 2680 + 2681 + phy_data = (!temp_phy_data && (phy_data == 0x8000)) ? 0x4 : 0x0; 2682 + 2683 + nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", 2684 + __func__, phy_data, 2685 + nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP"); 2686 + 2687 + if (phy_data & 0x0004) { 2688 + nesadapter->mac_link_down[mac_index] = 0; 2689 + list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) { 2690 + if (nesvnic->linkup == 0) { 2691 + printk(PFX "The Link is now up for port %s, netdev %p.\n", 2692 + nesvnic->netdev->name, nesvnic->netdev); 2693 + if (netif_queue_stopped(nesvnic->netdev)) 2694 + netif_start_queue(nesvnic->netdev); 2695 + nesvnic->linkup = 1; 2696 + netif_carrier_on(nesvnic->netdev); 2697 + 2698 + spin_lock(&nesvnic->port_ibevent_lock); 2699 + if (nesdev->iw_status == 0) { 2700 + nesdev->iw_status = 1; 2701 + nes_port_ibevent(nesvnic); 2702 + } 2703 + spin_unlock(&nesvnic->port_ibevent_lock); 2704 + } 2705 + } 2706 + 2707 + } else { 2708 + nesadapter->mac_link_down[mac_index] = 1; 2709 + list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) { 2710 + if (nesvnic->linkup == 1) { 2711 + printk(PFX "The Link is now down for port %s, netdev %p.\n", 2712 + nesvnic->netdev->name, nesvnic->netdev); 2713 + if (!(netif_queue_stopped(nesvnic->netdev))) 2714 + netif_stop_queue(nesvnic->netdev); 2715 + nesvnic->linkup = 0; 2716 + netif_carrier_off(nesvnic->netdev); 2717 + 2718 + spin_lock(&nesvnic->port_ibevent_lock); 2719 + if (nesdev->iw_status == 1) { 2720 + nesdev->iw_status = 0; 2721 + nes_port_ibevent(nesvnic); 2722 + } 2723 + spin_unlock(&nesvnic->port_ibevent_lock); 2724 + } 2725 + } 2726 + } 2727 + if (nesdev->link_recheck++ < NES_LINK_RECHECK_MAX) 2728 + schedule_delayed_work(&nesdev->work, NES_LINK_RECHECK_DELAY); 2729 + else 2730 + nesdev->link_recheck = 0; 2731 + 2732 + spin_unlock_irqrestore(&nesadapter->phy_lock, flags); 2733 + } 2667 2734 2668 2735 2669 2736 static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
+4
drivers/infiniband/hw/nes/nes_hw.h
··· 1354 1354 #define BAD_FRAME_OFFSET 64 1355 1355 #define CQE_MAJOR_DRV 0x8000 1356 1356 1357 + /* Used for link status recheck after interrupt processing */ 1358 + #define NES_LINK_RECHECK_DELAY msecs_to_jiffies(50) 1359 + #define NES_LINK_RECHECK_MAX 60 1360 + 1357 1361 #define nes_vlan_rx vlan_hwaccel_receive_skb 1358 1362 #define nes_netif_rx netif_receive_skb 1359 1363