diff options
Diffstat (limited to 'drivers/net')
100 files changed, 1233 insertions, 661 deletions
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index a746ba272f04..a956053608f9 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -1007,7 +1007,7 @@ static void arcnet_rx(struct net_device *dev, int bufnum) soft = &pkt.soft.rfc1201; - lp->hw.copy_from_card(dev, bufnum, 0, &pkt, sizeof(ARC_HDR_SIZE)); + lp->hw.copy_from_card(dev, bufnum, 0, &pkt, ARC_HDR_SIZE); if (pkt.hard.offset[0]) { ofs = pkt.hard.offset[0]; length = 256 - ofs; diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index 6aa7b3266c80..ac6177d3befc 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -412,10 +412,20 @@ static void esd_usb2_read_bulk_callback(struct urb *urb) switch (msg->msg.hdr.cmd) { case CMD_CAN_RX: + if (msg->msg.rx.net >= dev->net_count) { + dev_err(dev->udev->dev.parent, "format error\n"); + break; + } + esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg); break; case CMD_CAN_TX: + if (msg->msg.txdone.net >= dev->net_count) { + dev_err(dev->udev->dev.parent, "format error\n"); + break; + } + esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net], msg); break; diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index cbd388eea682..8becd3d838b5 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -779,6 +779,7 @@ static int usb_8dev_start(struct usb_8dev_priv *priv) usb_unanchor_urb(urb); usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf, urb->transfer_dma); + usb_free_urb(urb); break; } diff --git a/drivers/net/ethernet/allwinner/Kconfig b/drivers/net/ethernet/allwinner/Kconfig index 53ad213e865b..d8d95d4cd45a 100644 --- a/drivers/net/ethernet/allwinner/Kconfig +++ b/drivers/net/ethernet/allwinner/Kconfig @@ -3,19 +3,20 @@ # config NET_VENDOR_ALLWINNER - bool "Allwinner devices" - default y - depends on ARCH_SUNXI - ---help--- - If you have a network (Ethernet) card belonging to this - class, say Y and read the Ethernet-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. + bool "Allwinner devices" + default y - Note that the answer to this question doesn't directly - affect the kernel: saying N will just cause the configurator - to skip all the questions about Allwinner cards. If you say Y, - you will be asked for your specific card in the following - questions. + depends on ARCH_SUNXI + ---help--- + If you have a network (Ethernet) card belonging to this + class, say Y and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + Note that the answer to this question doesn't directly + affect the kernel: saying N will just cause the configurator + to skip all the questions about Allwinner cards. If you say Y, + you will be asked for your specific card in the following + questions. if NET_VENDOR_ALLWINNER @@ -26,6 +27,7 @@ config SUN4I_EMAC select CRC32 select MII select PHYLIB + select MDIO_SUN4I ---help--- Support for Allwinner A10 EMAC ethernet driver. diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h index b2bf324631dc..0f0556526ba9 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c.h +++ b/drivers/net/ethernet/atheros/atl1c/atl1c.h @@ -520,6 +520,9 @@ struct atl1c_adapter { struct net_device *netdev; struct pci_dev *pdev; struct napi_struct napi; + struct page *rx_page; + unsigned int rx_page_offset; + unsigned int rx_frag_size; struct atl1c_hw hw; struct atl1c_hw_stats hw_stats; struct mii_if_info mii; /* MII interface info */ diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 786a87483298..a36a760ada28 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -481,10 +481,15 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p) static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter, struct net_device *dev) { + unsigned int head_size; int mtu = dev->mtu; adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ? roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE; + + head_size = SKB_DATA_ALIGN(adapter->rx_buffer_len + NET_SKB_PAD) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + adapter->rx_frag_size = roundup_pow_of_two(head_size); } static netdev_features_t atl1c_fix_features(struct net_device *netdev, @@ -952,6 +957,10 @@ static void atl1c_free_ring_resources(struct atl1c_adapter *adapter) kfree(adapter->tpd_ring[0].buffer_info); adapter->tpd_ring[0].buffer_info = NULL; } + if (adapter->rx_page) { + put_page(adapter->rx_page); + adapter->rx_page = NULL; + } } /** @@ -1639,6 +1648,35 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter, skb_checksum_none_assert(skb); } +static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter) +{ + struct sk_buff *skb; + struct page *page; + + if (adapter->rx_frag_size > PAGE_SIZE) + return netdev_alloc_skb(adapter->netdev, + adapter->rx_buffer_len); + + page = adapter->rx_page; + if (!page) { + adapter->rx_page = page = alloc_page(GFP_ATOMIC); + if (unlikely(!page)) + return NULL; + adapter->rx_page_offset = 0; + } + + skb = build_skb(page_address(page) + adapter->rx_page_offset, + adapter->rx_frag_size); + if (likely(skb)) { + adapter->rx_page_offset += adapter->rx_frag_size; + if (adapter->rx_page_offset >= PAGE_SIZE) + adapter->rx_page = NULL; + else + get_page(page); + } + return skb; +} + static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) { struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; @@ -1660,7 +1698,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) while (next_info->flags & ATL1C_BUFFER_FREE) { rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use); - skb = netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len); + skb = atl1c_alloc_skb(adapter); if (unlikely(!skb)) { if (netif_msg_rx_err(adapter)) dev_warn(&pdev->dev, "alloc rx buffer failed\n"); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 439387b92cd5..7ecb44ad24fb 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -486,7 +486,7 @@ struct bnx2x_fastpath { struct napi_struct napi; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL unsigned int state; #define BNX2X_FP_STATE_IDLE 0 #define BNX2X_FP_STATE_NAPI (1 << 0) /* NAPI owns this FP */ @@ -498,7 +498,7 @@ struct bnx2x_fastpath { #define BNX2X_FP_USER_PEND (BNX2X_FP_STATE_POLL | BNX2X_FP_STATE_POLL_YIELD) /* protect state */ spinlock_t lock; -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ union host_hc_status_block status_blk; /* chip independent shortcuts into sb structure */ @@ -572,7 +572,7 @@ struct bnx2x_fastpath { #define bnx2x_fp_stats(bp, fp) (&((bp)->fp_stats[(fp)->index])) #define bnx2x_fp_qstats(bp, fp) (&((bp)->fp_stats[(fp)->index].eth_q_stats)) -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL static inline void bnx2x_fp_init_lock(struct bnx2x_fastpath *fp) { spin_lock_init(&fp->lock); @@ -680,7 +680,7 @@ static inline bool bnx2x_fp_ll_polling(struct bnx2x_fastpath *fp) { return false; } -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ /* Use 2500 as a mini-jumbo MTU for FCoE */ #define BNX2X_FCOE_MINI_JUMBO_MTU 2500 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 11abdcc9498a..2e90868a9276 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3119,7 +3119,7 @@ int bnx2x_poll(struct napi_struct *napi, int budget) return work_done; } -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL /* must be called with local_bh_disable()d */ int bnx2x_low_latency_recv(struct napi_struct *napi) { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index bd064c65addd..ab5bd6c319d3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -12036,7 +12036,7 @@ static const struct net_device_ops bnx2x_netdev_ops = { .ndo_fcoe_get_wwn = bnx2x_fcoe_get_wwn, #endif -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL .ndo_busy_poll = bnx2x_low_latency_recv, #endif }; diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 2aa8624abce3..51bf9ca42faf 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -17670,7 +17670,8 @@ err_out_free_res: pci_release_regions(pdev); err_out_disable_pdev: - pci_disable_device(pdev); + if (pci_is_enabled(pdev)) + pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); return err; } @@ -17835,7 +17836,8 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, rtnl_lock(); - if (!netif_running(netdev)) + /* We probably don't have netdev yet */ + if (!netdev || !netif_running(netdev)) goto done; tg3_phy_stop(tp); diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 2b0a0ea4f8e7..ae236009f1a8 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -259,6 +259,7 @@ struct bufdesc_ex { struct fec_enet_delayed_work { struct delayed_work delay_work; bool timeout; + bool trig_tx; }; /* The FEC buffer descriptors track the ring buffers. The rx_bd_base and diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 92d34d9e1046..fdf9307ba9e6 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -93,6 +93,20 @@ static void set_multicast_list(struct net_device *ndev); #define FEC_QUIRK_HAS_CSUM (1 << 5) /* Controller has hardware vlan support */ #define FEC_QUIRK_HAS_VLAN (1 << 6) +/* ENET IP errata ERR006358 + * + * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously + * detected as not set during a prior frame transmission, then the + * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs + * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in + * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously + * detected as not set during a prior frame transmission, then the + * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs + * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in + * frames not being transmitted until there is a 0-to-1 transition on + * ENET_TDAR[TDAR]. + */ +#define FEC_QUIRK_ERR006358 (1 << 7) static struct platform_device_id fec_devtype[] = { { @@ -112,7 +126,7 @@ static struct platform_device_id fec_devtype[] = { .name = "imx6q-fec", .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | - FEC_QUIRK_HAS_VLAN, + FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358, }, { .name = "mvf600-fec", .driver_data = FEC_QUIRK_ENET_MAC, @@ -275,16 +289,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct fec_enet_private *fep = netdev_priv(ndev); const struct platform_device_id *id_entry = platform_get_device_id(fep->pdev); - struct bufdesc *bdp; + struct bufdesc *bdp, *bdp_pre; void *bufaddr; unsigned short status; unsigned int index; - if (!fep->link) { - /* Link is down or auto-negotiation is in progress. */ - return NETDEV_TX_BUSY; - } - /* Fill in a Tx ring entry */ bdp = fep->cur_tx; @@ -370,6 +379,15 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) ebdp->cbd_esc |= BD_ENET_TX_PINS; } } + + bdp_pre = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); + if ((id_entry->driver_data & FEC_QUIRK_ERR006358) && + !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) { + fep->delay_work.trig_tx = true; + schedule_delayed_work(&(fep->delay_work.delay_work), + msecs_to_jiffies(1)); + } + /* If this was the last BD in the ring, start at the beginning again. */ if (status & BD_ENET_TX_WRAP) bdp = fep->tx_bd_base; @@ -689,6 +707,11 @@ static void fec_enet_work(struct work_struct *work) fec_restart(fep->netdev, fep->full_duplex); netif_wake_queue(fep->netdev); } + + if (fep->delay_work.trig_tx) { + fep->delay_work.trig_tx = false; + writel(0, fep->hwp + FEC_X_DES_ACTIVE); + } } static void @@ -2315,4 +2338,5 @@ static struct platform_driver fec_driver = { module_platform_driver(fec_driver); +MODULE_ALIAS("platform:"DRIVER_NAME); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 6a0c1b66ce54..c1d72c03cb59 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -3739,9 +3739,8 @@ static void igb_set_rx_mode(struct net_device *netdev) rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_VFE); if (netdev->flags & IFF_PROMISC) { - u32 mrqc = rd32(E1000_MRQC); /* retain VLAN HW filtering if in VT mode */ - if (mrqc & E1000_MRQC_ENABLE_VMDQ) + if (adapter->vfs_allocated_count) rctl |= E1000_RCTL_VFE; rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); vmolr |= (E1000_VMOLR_ROPE | E1000_VMOLR_MPME); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 6844f39b605b..0ac6b11c6e4e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -54,7 +54,7 @@ #include <net/busy_poll.h> -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL #define LL_EXTENDED_STATS #endif /* common prefix used by pr_<> macros */ @@ -366,7 +366,7 @@ struct ixgbe_q_vector { struct rcu_head rcu; /* to avoid race with update stats on free */ char name[IFNAMSIZ + 9]; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL unsigned int state; #define IXGBE_QV_STATE_IDLE 0 #define IXGBE_QV_STATE_NAPI 1 /* NAPI owns this QV */ @@ -377,12 +377,12 @@ struct ixgbe_q_vector { #define IXGBE_QV_YIELD (IXGBE_QV_STATE_NAPI_YIELD | IXGBE_QV_STATE_POLL_YIELD) #define IXGBE_QV_USER_PEND (IXGBE_QV_STATE_POLL | IXGBE_QV_STATE_POLL_YIELD) spinlock_t lock; -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ /* for dynamic allocation of rings associated with this q_vector */ struct ixgbe_ring ring[0] ____cacheline_internodealigned_in_smp; }; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector) { @@ -462,7 +462,7 @@ static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector) WARN_ON(!(q_vector->state & IXGBE_QV_LOCKED)); return q_vector->state & IXGBE_QV_USER_PEND; } -#else /* CONFIG_NET_LL_RX_POLL */ +#else /* CONFIG_NET_RX_BUSY_POLL */ static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector) { } @@ -491,7 +491,7 @@ static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector) { return false; } -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ #ifdef CONFIG_IXGBE_HWMON diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c index ac780770863d..7a77f37a7cbc 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c @@ -108,9 +108,8 @@ s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, /* Enable arbiter */ reg &= ~IXGBE_DPMCS_ARBDIS; - /* Enable DFP and Recycle mode */ - reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM); reg |= IXGBE_DPMCS_TSOEF; + /* Configure Max TSO packet size 34KB including payload and headers */ reg |= (0x4 << IXGBE_DPMCS_MTSOS_SHIFT); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 136de7dfe170..128d6b885326 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -2079,7 +2079,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, return total_rx_packets; } -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL /* must be called with local_bh_disable()d */ static int ixgbe_low_latency_recv(struct napi_struct *napi) { @@ -2111,7 +2111,7 @@ static int ixgbe_low_latency_recv(struct napi_struct *napi) return found; } -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ /** * ixgbe_configure_msix - Configure MSI-X hardware @@ -7310,7 +7310,7 @@ static const struct net_device_ops ixgbe_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ixgbe_netpoll, #endif -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL .ndo_busy_poll = ixgbe_low_latency_recv, #endif #ifdef IXGBE_FCOE diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 9647976d1183..2777c70c603b 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -88,6 +88,8 @@ #define MVNETA_TX_IN_PRGRS BIT(1) #define MVNETA_TX_FIFO_EMPTY BIT(8) #define MVNETA_RX_MIN_FRAME_SIZE 0x247c +#define MVNETA_SGMII_SERDES_CFG 0x24A0 +#define MVNETA_SGMII_SERDES_PROTO 0x0cc7 #define MVNETA_TYPE_PRIO 0x24bc #define MVNETA_FORCE_UNI BIT(21) #define MVNETA_TXQ_CMD_1 0x24e4 @@ -686,6 +688,8 @@ static void mvneta_port_sgmii_config(struct mvneta_port *pp) val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); val |= MVNETA_GMAC2_PSC_ENABLE; mvreg_write(pp, MVNETA_GMAC_CTRL_2, val); + + mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO); } /* Start the Ethernet port RX and TX activity */ @@ -2761,28 +2765,24 @@ static int mvneta_probe(struct platform_device *pdev) pp = netdev_priv(dev); - pp->tx_done_timer.function = mvneta_tx_done_timer_callback; - init_timer(&pp->tx_done_timer); - clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags); - pp->weight = MVNETA_RX_POLL_WEIGHT; pp->phy_node = phy_node; pp->phy_interface = phy_mode; - pp->base = of_iomap(dn, 0); - if (pp->base == NULL) { - err = -ENOMEM; - goto err_free_irq; - } - pp->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pp->clk)) { err = PTR_ERR(pp->clk); - goto err_unmap; + goto err_free_irq; } clk_prepare_enable(pp->clk); + pp->base = of_iomap(dn, 0); + if (pp->base == NULL) { + err = -ENOMEM; + goto err_clk; + } + dt_mac_addr = of_get_mac_address(dn); if (dt_mac_addr && is_valid_ether_addr(dt_mac_addr)) { mac_from = "device tree"; @@ -2799,6 +2799,9 @@ static int mvneta_probe(struct platform_device *pdev) } pp->tx_done_timer.data = (unsigned long)dev; + pp->tx_done_timer.function = mvneta_tx_done_timer_callback; + init_timer(&pp->tx_done_timer); + clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags); pp->tx_ring_size = MVNETA_MAX_TXD; pp->rx_ring_size = MVNETA_MAX_RXD; @@ -2809,7 +2812,7 @@ static int mvneta_probe(struct platform_device *pdev) err = mvneta_init(pp, phy_addr); if (err < 0) { dev_err(&pdev->dev, "can't init eth hal\n"); - goto err_clk; + goto err_unmap; } mvneta_port_power_up(pp, phy_mode); @@ -2839,10 +2842,10 @@ static int mvneta_probe(struct platform_device *pdev) err_deinit: mvneta_deinit(pp); -err_clk: - clk_disable_unprepare(pp->clk); err_unmap: iounmap(pp->base); +err_clk: + clk_disable_unprepare(pp->clk); err_free_irq: irq_dispose_mapping(dev->irq); err_free_netdev: diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 727874f575ce..a28cd801a236 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -223,7 +223,7 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset) case ETH_SS_STATS: return (priv->stats_bitmap ? bit_count : NUM_ALL_STATS) + (priv->tx_ring_num * 2) + -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL (priv->rx_ring_num * 5); #else (priv->rx_ring_num * 2); @@ -276,7 +276,7 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev, for (i = 0; i < priv->rx_ring_num; i++) { data[index++] = priv->rx_ring[i].packets; data[index++] = priv->rx_ring[i].bytes; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL data[index++] = priv->rx_ring[i].yields; data[index++] = priv->rx_ring[i].misses; data[index++] = priv->rx_ring[i].cleaned; @@ -344,7 +344,7 @@ static void mlx4_en_get_strings(struct net_device *dev, "rx%d_packets", i); sprintf(data + (index++) * ETH_GSTRING_LEN, "rx%d_bytes", i); -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL sprintf(data + (index++) * ETH_GSTRING_LEN, "rx%d_napi_yield", i); sprintf(data + (index++) * ETH_GSTRING_LEN, diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 5eac871399d8..fa37b7a61213 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -68,7 +68,7 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up) return 0; } -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL /* must be called with local_bh_disable()d */ static int mlx4_en_low_latency_recv(struct napi_struct *napi) { @@ -94,7 +94,7 @@ static int mlx4_en_low_latency_recv(struct napi_struct *napi) return done; } -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ #ifdef CONFIG_RFS_ACCEL @@ -2140,7 +2140,7 @@ static const struct net_device_ops mlx4_netdev_ops = { #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = mlx4_en_filter_rfs, #endif -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL .ndo_busy_poll = mlx4_en_low_latency_recv, #endif }; diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index aec6f5802da5..0d63daa2f422 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -845,16 +845,7 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave, MLX4_CMD_NATIVE); if (!err && dev->caps.function != slave) { - /* if config MAC in DB use it */ - if (priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac) - def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac; - else { - /* set slave default_mac address */ - MLX4_GET(def_mac, outbox->buf, QUERY_PORT_MAC_OFFSET); - def_mac += slave << 8; - priv->mfunc.master.vf_admin[slave].vport[vhcr->in_modifier].mac = def_mac; - } - + def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac; MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET); /* get port type - currently only eth is enabled */ diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index f1d818f9bb01..60c9f4f103fc 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -371,7 +371,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev->caps.sqp_demux = (mlx4_is_master(dev)) ? MLX4_MAX_NUM_SLAVES : 0; - if (!enable_64b_cqe_eqe) { + if (!enable_64b_cqe_eqe && !mlx4_is_slave(dev)) { if (dev_cap->flags & (MLX4_DEV_CAP_FLAG_64B_CQE | MLX4_DEV_CAP_FLAG_64B_EQE)) { mlx4_warn(dev, "64B EQEs/CQEs supported by the device but not enabled\n"); diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 35fb60e2320c..5e0aa569306a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -292,7 +292,7 @@ struct mlx4_en_rx_ring { void *rx_info; unsigned long bytes; unsigned long packets; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL unsigned long yields; unsigned long misses; unsigned long cleaned; @@ -318,7 +318,7 @@ struct mlx4_en_cq { struct mlx4_cqe *buf; #define MLX4_EN_OPCODE_ERROR 0x1e -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL unsigned int state; #define MLX4_EN_CQ_STATE_IDLE 0 #define MLX4_EN_CQ_STATE_NAPI 1 /* NAPI owns this CQ */ @@ -329,7 +329,7 @@ struct mlx4_en_cq { #define CQ_YIELD (MLX4_EN_CQ_STATE_NAPI_YIELD | MLX4_EN_CQ_STATE_POLL_YIELD) #define CQ_USER_PEND (MLX4_EN_CQ_STATE_POLL | MLX4_EN_CQ_STATE_POLL_YIELD) spinlock_t poll_lock; /* protects from LLS/napi conflicts */ -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ }; struct mlx4_en_port_profile { @@ -580,7 +580,7 @@ struct mlx4_mac_entry { struct rcu_head rcu; }; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq) { spin_lock_init(&cq->poll_lock); @@ -687,7 +687,7 @@ static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq) { return false; } -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 205753a04cfc..c571de85d0f9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -46,7 +46,7 @@ #include "mlx5_core.h" enum { - CMD_IF_REV = 3, + CMD_IF_REV = 4, }; enum { @@ -282,6 +282,12 @@ const char *mlx5_command_str(int command) case MLX5_CMD_OP_TEARDOWN_HCA: return "TEARDOWN_HCA"; + case MLX5_CMD_OP_ENABLE_HCA: + return "MLX5_CMD_OP_ENABLE_HCA"; + + case MLX5_CMD_OP_DISABLE_HCA: + return "MLX5_CMD_OP_DISABLE_HCA"; + case MLX5_CMD_OP_QUERY_PAGES: return "QUERY_PAGES"; @@ -1113,7 +1119,13 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector) for (i = 0; i < (1 << cmd->log_sz); i++) { if (test_bit(i, &vector)) { + struct semaphore *sem; + ent = cmd->ent_arr[i]; + if (ent->page_queue) + sem = &cmd->pages_sem; + else + sem = &cmd->sem; ktime_get_ts(&ent->ts2); memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out)); dump_command(dev, ent, 0); @@ -1136,10 +1148,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector) } else { complete(&ent->done); } - if (ent->page_queue) - up(&cmd->pages_sem); - else - up(&cmd->sem); + up(sem); } } } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 12242de2b0e3..b47739b0b5f6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -249,6 +249,44 @@ static int set_hca_ctrl(struct mlx5_core_dev *dev) return err; } +static int mlx5_core_enable_hca(struct mlx5_core_dev *dev) +{ + int err; + struct mlx5_enable_hca_mbox_in in; + struct mlx5_enable_hca_mbox_out out; + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ENABLE_HCA); + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); + if (err) + return err; + + if (out.hdr.status) + return mlx5_cmd_status_to_err(&out.hdr); + + return 0; +} + +static int mlx5_core_disable_hca(struct mlx5_core_dev *dev) +{ + int err; + struct mlx5_disable_hca_mbox_in in; + struct mlx5_disable_hca_mbox_out out; + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DISABLE_HCA); + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); + if (err) + return err; + + if (out.hdr.status) + return mlx5_cmd_status_to_err(&out.hdr); + + return 0; +} + int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) { struct mlx5_priv *priv = &dev->priv; @@ -304,28 +342,41 @@ int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) } mlx5_pagealloc_init(dev); + + err = mlx5_core_enable_hca(dev); + if (err) { + dev_err(&pdev->dev, "enable hca failed\n"); + goto err_pagealloc_cleanup; + } + + err = mlx5_satisfy_startup_pages(dev, 1); + if (err) { + dev_err(&pdev->dev, "failed to allocate boot pages\n"); + goto err_disable_hca; + } + err = set_hca_ctrl(dev); if (err) { dev_err(&pdev->dev, "set_hca_ctrl failed\n"); - goto err_pagealloc_cleanup; + goto reclaim_boot_pages; } err = handle_hca_cap(dev); if (err) { dev_err(&pdev->dev, "handle_hca_cap failed\n"); - goto err_pagealloc_cleanup; + goto reclaim_boot_pages; } - err = mlx5_satisfy_startup_pages(dev); + err = mlx5_satisfy_startup_pages(dev, 0); if (err) { - dev_err(&pdev->dev, "failed to allocate startup pages\n"); - goto err_pagealloc_cleanup; + dev_err(&pdev->dev, "failed to allocate init pages\n"); + goto reclaim_boot_pages; } err = mlx5_pagealloc_start(dev); if (err) { dev_err(&pdev->dev, "mlx5_pagealloc_start failed\n"); - goto err_reclaim_pages; + goto reclaim_boot_pages; } err = mlx5_cmd_init_hca(dev); @@ -396,9 +447,12 @@ err_stop_poll: err_pagealloc_stop: mlx5_pagealloc_stop(dev); -err_reclaim_pages: +reclaim_boot_pages: mlx5_reclaim_startup_pages(dev); +err_disable_hca: + mlx5_core_disable_hca(dev); + err_pagealloc_cleanup: mlx5_pagealloc_cleanup(dev); mlx5_cmd_cleanup(dev); @@ -434,6 +488,7 @@ void mlx5_dev_cleanup(struct mlx5_core_dev *dev) mlx5_cmd_teardown_hca(dev); mlx5_pagealloc_stop(dev); mlx5_reclaim_startup_pages(dev); + mlx5_core_disable_hca(dev); mlx5_pagealloc_cleanup(dev); mlx5_cmd_cleanup(dev); iounmap(dev->iseg); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index f0bf46339b28..4a3e137931a3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -64,7 +64,7 @@ struct mlx5_query_pages_inbox { struct mlx5_query_pages_outbox { struct mlx5_outbox_hdr hdr; - u8 reserved[2]; + __be16 num_boot_pages; __be16 func_id; __be16 init_pages; __be16 num_pages; @@ -146,7 +146,7 @@ static struct page *remove_page(struct mlx5_core_dev *dev, u64 addr) } static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id, - s16 *pages, s16 *init_pages) + s16 *pages, s16 *init_pages, u16 *boot_pages) { struct mlx5_query_pages_inbox in; struct mlx5_query_pages_outbox out; @@ -164,8 +164,13 @@ static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id, if (pages) *pages = be16_to_cpu(out.num_pages); + if (init_pages) *init_pages = be16_to_cpu(out.init_pages); + + if (boot_pages) + *boot_pages = be16_to_cpu(out.num_boot_pages); + *func_id = be16_to_cpu(out.func_id); return err; @@ -357,19 +362,22 @@ void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id, queue_work(dev->priv.pg_wq, &req->work); } -int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev) +int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot) { + u16 uninitialized_var(boot_pages); s16 uninitialized_var(init_pages); u16 uninitialized_var(func_id); int err; - err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages); + err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages, + &boot_pages); if (err) return err; - mlx5_core_dbg(dev, "requested %d init pages for func_id 0x%x\n", init_pages, func_id); - return give_pages(dev, func_id, init_pages, 0); + mlx5_core_dbg(dev, "requested %d init pages and %d boot pages for func_id 0x%x\n", + init_pages, boot_pages, func_id); + return give_pages(dev, func_id, boot ? boot_pages : init_pages, 0); } static int optimal_reclaimed_pages(void) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/uar.c b/drivers/net/ethernet/mellanox/mlx5/core/uar.c index 71d4a3937200..68f5d9c77c7b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/uar.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/uar.c @@ -164,6 +164,7 @@ int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari) uuari->uars[i].map = ioremap(addr, PAGE_SIZE); if (!uuari->uars[i].map) { mlx5_cmd_free_uar(dev, uuari->uars[i].index); + err = -ENOMEM; goto out_count; } mlx5_core_dbg(dev, "allocated uar index 0x%x, mmaped at %p\n", diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig index cb22341a14a8..a588ffde9700 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig +++ b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig @@ -4,7 +4,7 @@ config PCH_GBE tristate "OKI SEMICONDUCTOR IOH(ML7223/ML7831) GbE" - depends on PCI + depends on PCI && (X86 || COMPILE_TEST) select MII select PTP_1588_CLOCK_PCH ---help--- diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index eae41bcc0145..39351554106d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -1419,8 +1419,8 @@ void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *, u64, u64); #define ADDR_IN_RANGE(addr, low, high) \ (((addr) < (high)) && ((addr) >= (low))) -#define QLCRD32(adapter, off) \ - (adapter->ahw->hw_ops->read_reg)(adapter, off) +#define QLCRD32(adapter, off, err) \ + (adapter->ahw->hw_ops->read_reg)(adapter, off, err) #define QLCWR32(adapter, off, val) \ adapter->ahw->hw_ops->write_reg(adapter, off, val) @@ -1637,7 +1637,7 @@ void qlcnic_83xx_free_mailbox(struct qlcnic_mailbox *mbx); struct qlcnic_hardware_ops { void (*read_crb) (struct qlcnic_adapter *, char *, loff_t, size_t); void (*write_crb) (struct qlcnic_adapter *, char *, loff_t, size_t); - int (*read_reg) (struct qlcnic_adapter *, ulong); + int (*read_reg) (struct qlcnic_adapter *, ulong, int *); int (*write_reg) (struct qlcnic_adapter *, ulong, u32); void (*get_ocm_win) (struct qlcnic_hardware_context *); int (*get_mac_address) (struct qlcnic_adapter *, u8 *); @@ -1695,12 +1695,6 @@ static inline void qlcnic_write_crb(struct qlcnic_adapter *adapter, char *buf, adapter->ahw->hw_ops->write_crb(adapter, buf, offset, size); } -static inline int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, - ulong off) -{ - return adapter->ahw->hw_ops->read_reg(adapter, off); -} - static inline int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data) { @@ -1902,7 +1896,8 @@ static inline void qlcnic_free_mac_list(struct qlcnic_adapter *adapter) static inline void qlcnic_set_mac_filter_count(struct qlcnic_adapter *adapter) { - adapter->ahw->hw_ops->set_mac_filter_count(adapter); + if (adapter->ahw->hw_ops->set_mac_filter_count) + adapter->ahw->hw_ops->set_mac_filter_count(adapter); } static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter, diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 948ab72a2bc7..55a597799cf8 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -228,17 +228,17 @@ static int __qlcnic_set_win_base(struct qlcnic_adapter *adapter, u32 addr) return 0; } -int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr) +int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr, + int *err) { - int ret; struct qlcnic_hardware_context *ahw = adapter->ahw; - ret = __qlcnic_set_win_base(adapter, (u32) addr); - if (!ret) { + *err = __qlcnic_set_win_base(adapter, (u32) addr); + if (!*err) { return QLCRDX(ahw, QLCNIC_WILDCARD); } else { dev_err(&adapter->pdev->dev, - "%s failed, addr = 0x%x\n", __func__, (int)addr); + "%s failed, addr = 0x%lx\n", __func__, addr); return -EIO; } } @@ -574,7 +574,7 @@ void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *adapter) void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf, loff_t offset, size_t size) { - int ret; + int ret = 0; u32 data; if (qlcnic_api_lock(adapter)) { @@ -584,7 +584,7 @@ void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf, return; } - ret = qlcnic_83xx_rd_reg_indirect(adapter, (u32) offset); + data = QLCRD32(adapter, (u32) offset, &ret); qlcnic_api_unlock(adapter); if (ret == -EIO) { @@ -593,7 +593,6 @@ void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf, __func__, (u32)offset); return; } - data = ret; memcpy(buf, &data, size); } @@ -2077,18 +2076,25 @@ void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter) static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter, u32 data[]) { + struct qlcnic_hardware_context *ahw = adapter->ahw; u8 link_status, duplex; /* link speed */ link_status = LSB(data[3]) & 1; - adapter->ahw->link_speed = MSW(data[2]); - adapter->ahw->link_autoneg = MSB(MSW(data[3])); - adapter->ahw->module_type = MSB(LSW(data[3])); - duplex = LSB(MSW(data[3])); - if (duplex) - adapter->ahw->link_duplex = DUPLEX_FULL; - else - adapter->ahw->link_duplex = DUPLEX_HALF; - adapter->ahw->has_link_events = 1; + if (link_status) { + ahw->link_speed = MSW(data[2]); + duplex = LSB(MSW(data[3])); + if (duplex) + ahw->link_duplex = DUPLEX_FULL; + else + ahw->link_duplex = DUPLEX_HALF; + } else { + ahw->link_speed = SPEED_UNKNOWN; + ahw->link_duplex = DUPLEX_UNKNOWN; + } + + ahw->link_autoneg = MSB(MSW(data[3])); + ahw->module_type = MSB(LSW(data[3])); + ahw->has_link_events = 1; qlcnic_advert_link_change(adapter, link_status); } @@ -2390,9 +2396,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr, u8 *p_data, int count) { - int i, ret; - u32 word, range, flash_offset, addr = flash_addr; + u32 word, range, flash_offset, addr = flash_addr, ret; ulong indirect_add, direct_window; + int i, err = 0; flash_offset = addr & (QLCNIC_FLASH_SECTOR_SIZE - 1); if (addr & 0x3) { @@ -2410,10 +2416,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter, /* Multi sector read */ for (i = 0; i < count; i++) { indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr); - ret = qlcnic_83xx_rd_reg_indirect(adapter, - indirect_add); - if (ret == -EIO) - return -EIO; + ret = QLCRD32(adapter, indirect_add, &err); + if (err == -EIO) + return err; word = ret; *(u32 *)p_data = word; @@ -2434,10 +2439,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter, /* Single sector read */ for (i = 0; i < count; i++) { indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr); - ret = qlcnic_83xx_rd_reg_indirect(adapter, - indirect_add); - if (ret == -EIO) - return -EIO; + ret = QLCRD32(adapter, indirect_add, &err); + if (err == -EIO) + return err; word = ret; *(u32 *)p_data = word; @@ -2453,10 +2457,13 @@ static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter) { u32 status; int retries = QLC_83XX_FLASH_READ_RETRY_COUNT; + int err = 0; do { - status = qlcnic_83xx_rd_reg_indirect(adapter, - QLC_83XX_FLASH_STATUS); + status = QLCRD32(adapter, QLC_83XX_FLASH_STATUS, &err); + if (err == -EIO) + return err; + if ((status & QLC_83XX_FLASH_STATUS_READY) == QLC_83XX_FLASH_STATUS_READY) break; @@ -2508,7 +2515,8 @@ int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *adapter) int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter) { - int ret, mfg_id; + int ret, err = 0; + u32 mfg_id; if (qlcnic_83xx_lock_flash(adapter)) return -EIO; @@ -2523,9 +2531,11 @@ int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter) return -EIO; } - mfg_id = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA); - if (mfg_id == -EIO) - return -EIO; + mfg_id = QLCRD32(adapter, QLC_83XX_FLASH_RDDATA, &err); + if (err == -EIO) { + qlcnic_83xx_unlock_flash(adapter); + return err; + } adapter->flash_mfg_id = (mfg_id & 0xFF); qlcnic_83xx_unlock_flash(adapter); @@ -2642,7 +2652,7 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr, u32 *p_data, int count) { u32 temp; - int ret = -EIO; + int ret = -EIO, err = 0; if ((count < QLC_83XX_FLASH_WRITE_MIN) || (count > QLC_83XX_FLASH_WRITE_MAX)) { @@ -2651,8 +2661,10 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr, return -EIO; } - temp = qlcnic_83xx_rd_reg_indirect(adapter, - QLC_83XX_FLASH_SPI_CONTROL); + temp = QLCRD32(adapter, QLC_83XX_FLASH_SPI_CONTROL, &err); + if (err == -EIO) + return err; + qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_SPI_CONTROL, (temp | QLC_83XX_FLASH_SPI_CTRL)); qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR, @@ -2701,13 +2713,18 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr, return -EIO; } - ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_SPI_STATUS); + ret = QLCRD32(adapter, QLC_83XX_FLASH_SPI_STATUS, &err); + if (err == -EIO) + return err; + if ((ret & QLC_83XX_FLASH_SPI_CTRL) == QLC_83XX_FLASH_SPI_CTRL) { dev_err(&adapter->pdev->dev, "%s: failed at %d\n", __func__, __LINE__); /* Operation failed, clear error bit */ - temp = qlcnic_83xx_rd_reg_indirect(adapter, - QLC_83XX_FLASH_SPI_CONTROL); + temp = QLCRD32(adapter, QLC_83XX_FLASH_SPI_CONTROL, &err); + if (err == -EIO) + return err; + qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_SPI_CONTROL, (temp | QLC_83XX_FLASH_SPI_CTRL)); @@ -2829,6 +2846,7 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr, { int i, j, ret = 0; u32 temp; + int err = 0; /* Check alignment */ if (addr & 0xF) @@ -2861,8 +2879,12 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr, QLCNIC_TA_WRITE_START); for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = qlcnic_83xx_rd_reg_indirect(adapter, - QLCNIC_MS_CTRL); + temp = QLCRD32(adapter, QLCNIC_MS_CTRL, &err); + if (err == -EIO) { + mutex_unlock(&adapter->ahw->mem_lock); + return err; + } + if ((temp & TA_CTL_BUSY) == 0) break; } @@ -2884,9 +2906,9 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr, int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr, u8 *p_data, int count) { - int i, ret; - u32 word, addr = flash_addr; + u32 word, addr = flash_addr, ret; ulong indirect_addr; + int i, err = 0; if (qlcnic_83xx_lock_flash(adapter) != 0) return -EIO; @@ -2906,10 +2928,10 @@ int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr, } indirect_addr = QLC_83XX_FLASH_DIRECT_DATA(addr); - ret = qlcnic_83xx_rd_reg_indirect(adapter, - indirect_addr); - if (ret == -EIO) - return -EIO; + ret = QLCRD32(adapter, indirect_addr, &err); + if (err == -EIO) + return err; + word = ret; *(u32 *)p_data = word; p_data = p_data + 4; @@ -3020,8 +3042,8 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter, } if (ahw->port_type == QLCNIC_XGBE) { - ecmd->supported = SUPPORTED_1000baseT_Full; - ecmd->advertising = ADVERTISED_1000baseT_Full; + ecmd->supported = SUPPORTED_10000baseT_Full; + ecmd->advertising = ADVERTISED_10000baseT_Full; } else { ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | @@ -3375,7 +3397,8 @@ int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *adapter, static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter) { - int ret; + int ret, err = 0; + u32 temp; qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR, QLC_83XX_FLASH_OEM_READ_SIG); @@ -3385,8 +3408,11 @@ static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter) if (ret) return -EIO; - ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA); - return ret & 0xFF; + temp = QLCRD32(adapter, QLC_83XX_FLASH_RDDATA, &err); + if (err == -EIO) + return err; + + return temp & 0xFF; } int qlcnic_83xx_flash_test(struct qlcnic_adapter *adapter) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 9993705e0a43..dd22ef3d85e5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -529,7 +529,7 @@ void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *); void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *); void qlcnic_83xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t); void qlcnic_83xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t); -int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong); +int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong, int *); int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *, ulong, u32); void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *, int, u64 []); int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index bb7c649bfe53..cc1e32a7248f 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -1312,8 +1312,11 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter) { int i, j; u32 val = 0, val1 = 0, reg = 0; + int err = 0; - val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG); + val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG, &err); + if (err == -EIO) + return; dev_info(&adapter->pdev->dev, "SRE-Shim Ctrl:0x%x\n", val); for (j = 0; j < 2; j++) { @@ -1327,7 +1330,9 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter) reg = QLC_83XX_PORT1_THRESHOLD; } for (i = 0; i < 8; i++) { - val = QLCRD32(adapter, reg + (i * 0x4)); + val = QLCRD32(adapter, reg + (i * 0x4), &err); + if (err == -EIO) + return; dev_info(&adapter->pdev->dev, "0x%x ", val); } dev_info(&adapter->pdev->dev, "\n"); @@ -1344,8 +1349,10 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter) reg = QLC_83XX_PORT1_TC_MC_REG; } for (i = 0; i < 4; i++) { - val = QLCRD32(adapter, reg + (i * 0x4)); - dev_info(&adapter->pdev->dev, "0x%x ", val); + val = QLCRD32(adapter, reg + (i * 0x4), &err); + if (err == -EIO) + return; + dev_info(&adapter->pdev->dev, "0x%x ", val); } dev_info(&adapter->pdev->dev, "\n"); } @@ -1361,17 +1368,25 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter) reg = QLC_83XX_PORT1_TC_STATS; } for (i = 7; i >= 0; i--) { - val = QLCRD32(adapter, reg); + val = QLCRD32(adapter, reg, &err); + if (err == -EIO) + return; val &= ~(0x7 << 29); /* Reset bits 29 to 31 */ QLCWR32(adapter, reg, (val | (i << 29))); - val = QLCRD32(adapter, reg); + val = QLCRD32(adapter, reg, &err); + if (err == -EIO) + return; dev_info(&adapter->pdev->dev, "0x%x ", val); } dev_info(&adapter->pdev->dev, "\n"); } - val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD); - val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD); + val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD, &err); + if (err == -EIO) + return; + val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD, &err); + if (err == -EIO) + return; dev_info(&adapter->pdev->dev, "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n", val, val1); @@ -1434,7 +1449,7 @@ static void qlcnic_83xx_take_eport_out_of_reset(struct qlcnic_adapter *adapter) static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev) { u32 heartbeat, peg_status; - int retries, ret = -EIO; + int retries, ret = -EIO, err = 0; retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT; p_dev->heartbeat = QLC_SHARED_REG_RD32(p_dev, @@ -1462,11 +1477,11 @@ static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev) "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n" "PEG_NET_4_PC: 0x%x\n", peg_status, QLC_SHARED_REG_RD32(p_dev, QLCNIC_PEG_HALT_STATUS2), - QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0), - QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1), - QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2), - QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3), - QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4)); + QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0, &err), + QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1, &err), + QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2, &err), + QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3, &err), + QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4, &err)); if (QLCNIC_FWERROR_CODE(peg_status) == 0x67) dev_err(&p_dev->pdev->dev, @@ -1510,18 +1525,22 @@ int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev) static int qlcnic_83xx_poll_reg(struct qlcnic_adapter *p_dev, u32 addr, int duration, u32 mask, u32 status) { + int timeout_error, err = 0; u32 value; - int timeout_error; u8 retries; - value = qlcnic_83xx_rd_reg_indirect(p_dev, addr); + value = QLCRD32(p_dev, addr, &err); + if (err == -EIO) + return err; retries = duration / 10; do { if ((value & mask) != status) { timeout_error = 1; msleep(duration / 10); - value = qlcnic_83xx_rd_reg_indirect(p_dev, addr); + value = QLCRD32(p_dev, addr, &err); + if (err == -EIO) + return err; } else { timeout_error = 0; break; @@ -1615,9 +1634,12 @@ int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev) static void qlcnic_83xx_read_write_crb_reg(struct qlcnic_adapter *p_dev, u32 raddr, u32 waddr) { - int value; + int err = 0; + u32 value; - value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr); + value = QLCRD32(p_dev, raddr, &err); + if (err == -EIO) + return; qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value); } @@ -1626,12 +1648,16 @@ static void qlcnic_83xx_rmw_crb_reg(struct qlcnic_adapter *p_dev, u32 raddr, u32 waddr, struct qlc_83xx_rmw *p_rmw_hdr) { - int value; + int err = 0; + u32 value; - if (p_rmw_hdr->index_a) + if (p_rmw_hdr->index_a) { value = p_dev->ahw->reset.array[p_rmw_hdr->index_a]; - else - value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr); + } else { + value = QLCRD32(p_dev, raddr, &err); + if (err == -EIO) + return; + } value &= p_rmw_hdr->mask; value <<= p_rmw_hdr->shl; @@ -1684,7 +1710,7 @@ static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev, long delay; struct qlc_83xx_entry *entry; struct qlc_83xx_poll *poll; - int i; + int i, err = 0; unsigned long arg1, arg2; poll = (struct qlc_83xx_poll *)((char *)p_hdr + @@ -1708,10 +1734,12 @@ static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev, arg1, delay, poll->mask, poll->status)){ - qlcnic_83xx_rd_reg_indirect(p_dev, - arg1); - qlcnic_83xx_rd_reg_indirect(p_dev, - arg2); + QLCRD32(p_dev, arg1, &err); + if (err == -EIO) + return; + QLCRD32(p_dev, arg2, &err); + if (err == -EIO) + return; } } } @@ -1777,7 +1805,7 @@ static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev, struct qlc_83xx_entry_hdr *p_hdr) { long delay; - int index, i, j; + int index, i, j, err; struct qlc_83xx_quad_entry *entry; struct qlc_83xx_poll *poll; unsigned long addr; @@ -1797,7 +1825,10 @@ static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev, poll->mask, poll->status)){ index = p_dev->ahw->reset.array_index; addr = entry->dr_addr; - j = qlcnic_83xx_rd_reg_indirect(p_dev, addr); + j = QLCRD32(p_dev, addr, &err); + if (err == -EIO) + return; + p_dev->ahw->reset.array[index++] = j; if (index == QLC_83XX_MAX_RESET_SEQ_ENTRIES) @@ -2150,6 +2181,8 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) qlcnic_83xx_clear_function_resources(adapter); + INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work); + /* register for NIC IDC AEN Events */ qlcnic_83xx_register_nic_idc_func(adapter, 1); @@ -2170,8 +2203,6 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) if (err) goto disable_mbx_intr; - INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work); - /* Periodically monitor device status */ qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work); return 0; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index 0581a484ceb5..d09389b33474 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -104,7 +104,7 @@ static u32 qlcnic_poll_rsp(struct qlcnic_adapter *adapter) { u32 rsp; - int timeout = 0; + int timeout = 0, err = 0; do { /* give atleast 1ms for firmware to respond */ @@ -113,7 +113,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter) if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT) return QLCNIC_CDRP_RSP_TIMEOUT; - rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET); + rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET, &err); } while (!QLCNIC_CDRP_IS_RSP(rsp)); return rsp; @@ -122,7 +122,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter) int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *cmd) { - int i; + int i, err = 0; u32 rsp; u32 signature; struct pci_dev *pdev = adapter->pdev; @@ -148,7 +148,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter, dev_err(&pdev->dev, "card response timeout.\n"); cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT; } else if (rsp == QLCNIC_CDRP_RSP_FAIL) { - cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1)); + cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1), &err); switch (cmd->rsp.arg[0]) { case QLCNIC_RCODE_INVALID_ARGS: fmt = "CDRP invalid args: [%d]\n"; @@ -175,7 +175,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter, cmd->rsp.arg[0] = QLCNIC_RCODE_SUCCESS; for (i = 1; i < cmd->rsp.num; i++) - cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i)); + cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i), &err); /* Release semaphore */ qlcnic_api_unlock(adapter); @@ -210,10 +210,10 @@ int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter, u32 fw_cmd) if (err) { dev_info(&adapter->pdev->dev, "Failed to set driver version in firmware\n"); - return -EIO; + err = -EIO; } - - return 0; + qlcnic_free_mbx_args(&cmd); + return err; } int diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 94a728da3eb1..79a5855f926c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -150,6 +150,7 @@ static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { "Link_Test_on_offline", "Interrupt_Test_offline", "Internal_Loopback_offline", + "External_Loopback_offline", "EEPROM_Test_offline" }; @@ -266,7 +267,7 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter, { struct qlcnic_hardware_context *ahw = adapter->ahw; u32 speed, reg; - int check_sfp_module = 0; + int check_sfp_module = 0, err = 0; u16 pcifn = ahw->pci_func; /* read which mode */ @@ -289,7 +290,7 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter, } else if (adapter->ahw->port_type == QLCNIC_XGBE) { u32 val = 0; - val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR); + val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR, &err); if (val == QLCNIC_PORT_MODE_802_3_AP) { ecmd->supported = SUPPORTED_1000baseT_Full; @@ -300,9 +301,13 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter, } if (netif_running(adapter->netdev) && ahw->has_link_events) { - reg = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn)); - speed = P3P_LINK_SPEED_VAL(pcifn, reg); - ahw->link_speed = speed * P3P_LINK_SPEED_MHZ; + if (ahw->linkup) { + reg = QLCRD32(adapter, + P3P_LINK_SPEED_REG(pcifn), &err); + speed = P3P_LINK_SPEED_VAL(pcifn, reg); + ahw->link_speed = speed * P3P_LINK_SPEED_MHZ; + } + ethtool_cmd_speed_set(ecmd, ahw->link_speed); ecmd->autoneg = ahw->link_autoneg; ecmd->duplex = ahw->link_duplex; @@ -463,13 +468,14 @@ static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) static int qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter, u32 *regs_buff) { - int i, j = 0; + int i, j = 0, err = 0; for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++) regs_buff[i] = QLC_SHARED_REG_RD32(adapter, diag_registers[j]); j = 0; while (ext_diag_registers[j] != -1) - regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++]); + regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++], + &err); return i; } @@ -519,13 +525,16 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) static u32 qlcnic_test_link(struct net_device *dev) { struct qlcnic_adapter *adapter = netdev_priv(dev); + int err = 0; u32 val; if (qlcnic_83xx_check(adapter)) { val = qlcnic_83xx_test_link(adapter); return (val & 1) ? 0 : 1; } - val = QLCRD32(adapter, CRB_XG_STATE_P3P); + val = QLCRD32(adapter, CRB_XG_STATE_P3P, &err); + if (err == -EIO) + return err; val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val); return (val == XG_LINK_UP_P3P) ? 0 : 1; } @@ -658,6 +667,7 @@ qlcnic_get_pauseparam(struct net_device *netdev, { struct qlcnic_adapter *adapter = netdev_priv(netdev); int port = adapter->ahw->physical_port; + int err = 0; __u32 val; if (qlcnic_83xx_check(adapter)) { @@ -668,9 +678,13 @@ qlcnic_get_pauseparam(struct net_device *netdev, if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) return; /* get flow control settings */ - val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port)); + val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err); + if (err == -EIO) + return; pause->rx_pause = qlcnic_gb_get_rx_flowctl(val); - val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL); + val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err); + if (err == -EIO) + return; switch (port) { case 0: pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val)); @@ -690,7 +704,9 @@ qlcnic_get_pauseparam(struct net_device *netdev, if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) return; pause->rx_pause = 1; - val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL); + val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err); + if (err == -EIO) + return; if (port == 0) pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val)); else @@ -707,6 +723,7 @@ qlcnic_set_pauseparam(struct net_device *netdev, { struct qlcnic_adapter *adapter = netdev_priv(netdev); int port = adapter->ahw->physical_port; + int err = 0; __u32 val; if (qlcnic_83xx_check(adapter)) @@ -717,7 +734,9 @@ qlcnic_set_pauseparam(struct net_device *netdev, if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) return -EIO; /* set flow control */ - val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port)); + val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err); + if (err == -EIO) + return err; if (pause->rx_pause) qlcnic_gb_rx_flowctl(val); @@ -728,7 +747,9 @@ qlcnic_set_pauseparam(struct net_device *netdev, val); QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val); /* set autoneg */ - val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL); + val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err); + if (err == -EIO) + return err; switch (port) { case 0: if (pause->tx_pause) @@ -764,7 +785,9 @@ qlcnic_set_pauseparam(struct net_device *netdev, if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) return -EIO; - val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL); + val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err); + if (err == -EIO) + return err; if (port == 0) { if (pause->tx_pause) qlcnic_xg_unset_xg0_mask(val); @@ -788,11 +811,14 @@ static int qlcnic_reg_test(struct net_device *dev) { struct qlcnic_adapter *adapter = netdev_priv(dev); u32 data_read; + int err = 0; if (qlcnic_83xx_check(adapter)) return qlcnic_83xx_reg_test(adapter); - data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0)); + data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0), &err); + if (err == -EIO) + return err; if ((data_read & 0xffff) != adapter->pdev->vendor) return 1; @@ -1026,8 +1052,15 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, if (data[3]) eth_test->flags |= ETH_TEST_FL_FAILED; - data[4] = qlcnic_eeprom_test(dev); - if (data[4]) + if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) { + data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE); + if (data[4]) + eth_test->flags |= ETH_TEST_FL_FAILED; + eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; + } + + data[5] = qlcnic_eeprom_test(dev); + if (data[5]) eth_test->flags |= ETH_TEST_FL_FAILED; } } @@ -1257,17 +1290,20 @@ qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct qlcnic_adapter *adapter = netdev_priv(dev); u32 wol_cfg; + int err = 0; if (qlcnic_83xx_check(adapter)) return; wol->supported = 0; wol->wolopts = 0; - wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV); + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err); + if (err == -EIO) + return; if (wol_cfg & (1UL << adapter->portnum)) wol->supported |= WAKE_MAGIC; - wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG); + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err); if (wol_cfg & (1UL << adapter->portnum)) wol->wolopts |= WAKE_MAGIC; } @@ -1277,17 +1313,22 @@ qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct qlcnic_adapter *adapter = netdev_priv(dev); u32 wol_cfg; + int err = 0; if (qlcnic_83xx_check(adapter)) return -EOPNOTSUPP; if (wol->wolopts & ~WAKE_MAGIC) return -EINVAL; - wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV); + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err); + if (err == -EIO) + return err; if (!(wol_cfg & (1 << adapter->portnum))) return -EOPNOTSUPP; - wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG); + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err); + if (err == -EIO) + return err; if (wol->wolopts & WAKE_MAGIC) wol_cfg |= 1UL << adapter->portnum; else @@ -1540,7 +1581,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val) return 0; case QLCNIC_SET_QUIESCENT: case QLCNIC_RESET_QUIESCENT: - state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) netdev_info(netdev, "Device in FAILED state\n"); return 0; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index 5b5d2edf125d..4d5f59b2d153 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -317,16 +317,20 @@ static void qlcnic_write_window_reg(u32 addr, void __iomem *bar0, u32 data) int qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) { - int done = 0, timeout = 0; + int timeout = 0; + int err = 0; + u32 done = 0; while (!done) { - done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem))); + done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)), + &err); if (done == 1) break; if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) { dev_err(&adapter->pdev->dev, "Failed to acquire sem=%d lock; holdby=%d\n", - sem, id_reg ? QLCRD32(adapter, id_reg) : -1); + sem, + id_reg ? QLCRD32(adapter, id_reg, &err) : -1); return -EIO; } msleep(1); @@ -341,19 +345,22 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem) { - QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem))); + int err = 0; + + QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)), &err); } int qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr) { + int err = 0; u32 data; if (qlcnic_82xx_check(adapter)) qlcnic_read_window_reg(addr, adapter->ahw->pci_base0, &data); else { - data = qlcnic_83xx_rd_reg_indirect(adapter, addr); - if (data == -EIO) - return -EIO; + data = QLCRD32(adapter, addr, &err); + if (err == -EIO) + return err; } return data; } @@ -516,20 +523,18 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) if (netdev->flags & IFF_PROMISC) { if (!(adapter->flags & QLCNIC_PROMISC_DISABLED)) mode = VPORT_MISS_MODE_ACCEPT_ALL; - } else if (netdev->flags & IFF_ALLMULTI) { - if (netdev_mc_count(netdev) > ahw->max_mc_count) { - mode = VPORT_MISS_MODE_ACCEPT_MULTI; - } else if (!netdev_mc_empty(netdev) && - !qlcnic_sriov_vf_check(adapter)) { - netdev_for_each_mc_addr(ha, netdev) - qlcnic_nic_add_mac(adapter, ha->addr, - vlan); - } - if (mode != VPORT_MISS_MODE_ACCEPT_MULTI && - qlcnic_sriov_vf_check(adapter)) - qlcnic_vf_add_mc_list(netdev, vlan); + } else if ((netdev->flags & IFF_ALLMULTI) || + (netdev_mc_count(netdev) > ahw->max_mc_count)) { + mode = VPORT_MISS_MODE_ACCEPT_MULTI; + } else if (!netdev_mc_empty(netdev) && + !qlcnic_sriov_vf_check(adapter)) { + netdev_for_each_mc_addr(ha, netdev) + qlcnic_nic_add_mac(adapter, ha->addr, vlan); } + if (qlcnic_sriov_vf_check(adapter)) + qlcnic_vf_add_mc_list(netdev, vlan); + /* configure unicast MAC address, if there is not sufficient space * to store all the unicast addresses then enable promiscuous mode */ @@ -1161,7 +1166,8 @@ int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, return -EIO; } -int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off) +int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off, + int *err) { unsigned long flags; int rv; @@ -1417,7 +1423,7 @@ int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data) int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter) { - int offset, board_type, magic; + int offset, board_type, magic, err = 0; struct pci_dev *pdev = adapter->pdev; offset = QLCNIC_FW_MAGIC_OFFSET; @@ -1437,7 +1443,9 @@ int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter) adapter->ahw->board_type = board_type; if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) { - u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I); + u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I, &err); + if (err == -EIO) + return err; if ((gpio & 0x8000) == 0) board_type = QLCNIC_BRDTYPE_P3P_10G_TP; } @@ -1477,10 +1485,13 @@ int qlcnic_wol_supported(struct qlcnic_adapter *adapter) { u32 wol_cfg; + int err = 0; - wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV); + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err); if (wol_cfg & (1UL << adapter->portnum)) { - wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG); + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err); + if (err == -EIO) + return err; if (wol_cfg & (1 << adapter->portnum)) return 1; } @@ -1541,6 +1552,7 @@ void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter) void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf, loff_t offset, size_t size) { + int err = 0; u32 data; u64 qmdata; @@ -1548,7 +1560,7 @@ void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf, qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata); memcpy(buf, &qmdata, size); } else { - data = QLCRD32(adapter, offset); + data = QLCRD32(adapter, offset, &err); memcpy(buf, &data, size); } } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index 2c22504f57aa..4a71b28effcb 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h @@ -154,7 +154,7 @@ struct qlcnic_hardware_context; struct qlcnic_adapter; int qlcnic_82xx_start_firmware(struct qlcnic_adapter *); -int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong); +int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong, int *); int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32); int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int); int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c index d28336fc65ab..974d62607e13 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c @@ -142,7 +142,7 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter) buffrag->length, PCI_DMA_TODEVICE); buffrag->dma = 0ULL; } - for (j = 0; j < cmd_buf->frag_count; j++) { + for (j = 1; j < cmd_buf->frag_count; j++) { buffrag++; if (buffrag->dma) { pci_unmap_page(adapter->pdev, buffrag->dma, @@ -286,10 +286,11 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter) { long timeout = 0; long done = 0; + int err = 0; cond_resched(); while (done == 0) { - done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS); + done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS, &err); done &= 2; if (++timeout >= QLCNIC_MAX_ROM_WAIT_USEC) { dev_err(&adapter->pdev->dev, @@ -304,6 +305,8 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter) static int do_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp) { + int err = 0; + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr); QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 3); @@ -317,7 +320,9 @@ static int do_rom_fast_read(struct qlcnic_adapter *adapter, udelay(10); QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); - *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA); + *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA, &err); + if (err == -EIO) + return err; return 0; } @@ -369,11 +374,11 @@ int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp) int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter) { - int addr, val; + int addr, err = 0; int i, n, init_delay; struct crb_addr_pair *buf; unsigned offset; - u32 off; + u32 off, val; struct pci_dev *pdev = adapter->pdev; QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE, 0); @@ -402,7 +407,9 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter) QLCWR32(adapter, QLCNIC_CRB_NIU + 0xb0000, 0x00); /* halt sre */ - val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000); + val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000, &err); + if (err == -EIO) + return err; QLCWR32(adapter, QLCNIC_CRB_SRE + 0x1000, val & (~(0x1))); /* halt epg */ @@ -719,10 +726,12 @@ qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter) static int qlcnic_has_mn(struct qlcnic_adapter *adapter) { - u32 capability; - capability = 0; + u32 capability = 0; + int err = 0; - capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY); + capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY, &err); + if (err == -EIO) + return err; if (capability & QLCNIC_PEG_TUNE_MN_PRESENT) return 1; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 1994b446c9e7..f807f3b949e2 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -161,36 +161,68 @@ static inline int qlcnic_82xx_is_lb_pkt(u64 sts_data) return (qlcnic_get_sts_status(sts_data) == STATUS_CKSUM_LOOP) ? 1 : 0; } +static void qlcnic_delete_rx_list_mac(struct qlcnic_adapter *adapter, + struct qlcnic_filter *fil, + void *addr, u16 vlan_id) +{ + int ret; + u8 op; + + op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD; + ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op); + if (ret) + return; + + op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL; + ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op); + if (!ret) { + hlist_del(&fil->fnode); + adapter->rx_fhash.fnum--; + } +} + +static struct qlcnic_filter *qlcnic_find_mac_filter(struct hlist_head *head, + void *addr, u16 vlan_id) +{ + struct qlcnic_filter *tmp_fil = NULL; + struct hlist_node *n; + + hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { + if (!memcmp(tmp_fil->faddr, addr, ETH_ALEN) && + tmp_fil->vlan_id == vlan_id) + return tmp_fil; + } + + return NULL; +} + void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb, int loopback_pkt, u16 vlan_id) { struct ethhdr *phdr = (struct ethhdr *)(skb->data); struct qlcnic_filter *fil, *tmp_fil; - struct hlist_node *n; struct hlist_head *head; unsigned long time; u64 src_addr = 0; - u8 hindex, found = 0, op; + u8 hindex, op; int ret; memcpy(&src_addr, phdr->h_source, ETH_ALEN); + hindex = qlcnic_mac_hash(src_addr) & + (adapter->fhash.fbucket_size - 1); if (loopback_pkt) { if (adapter->rx_fhash.fnum >= adapter->rx_fhash.fmax) return; - hindex = qlcnic_mac_hash(src_addr) & - (adapter->fhash.fbucket_size - 1); head = &(adapter->rx_fhash.fhead[hindex]); - hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { - if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) && - tmp_fil->vlan_id == vlan_id) { - time = tmp_fil->ftime; - if (jiffies > (QLCNIC_READD_AGE * HZ + time)) - tmp_fil->ftime = jiffies; - return; - } + tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id); + if (tmp_fil) { + time = tmp_fil->ftime; + if (time_after(jiffies, QLCNIC_READD_AGE * HZ + time)) + tmp_fil->ftime = jiffies; + return; } fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC); @@ -205,36 +237,37 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb, adapter->rx_fhash.fnum++; spin_unlock(&adapter->rx_mac_learn_lock); } else { - hindex = qlcnic_mac_hash(src_addr) & - (adapter->fhash.fbucket_size - 1); - head = &(adapter->rx_fhash.fhead[hindex]); - spin_lock(&adapter->rx_mac_learn_lock); - hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { - if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) && - tmp_fil->vlan_id == vlan_id) { - found = 1; - break; - } - } + head = &adapter->fhash.fhead[hindex]; - if (!found) { - spin_unlock(&adapter->rx_mac_learn_lock); - return; - } + spin_lock(&adapter->mac_learn_lock); - op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD; - ret = qlcnic_sre_macaddr_change(adapter, (u8 *)&src_addr, - vlan_id, op); - if (!ret) { + tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id); + if (tmp_fil) { op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL; ret = qlcnic_sre_macaddr_change(adapter, (u8 *)&src_addr, vlan_id, op); if (!ret) { - hlist_del(&(tmp_fil->fnode)); - adapter->rx_fhash.fnum--; + hlist_del(&tmp_fil->fnode); + adapter->fhash.fnum--; } + + spin_unlock(&adapter->mac_learn_lock); + + return; } + + spin_unlock(&adapter->mac_learn_lock); + + head = &adapter->rx_fhash.fhead[hindex]; + + spin_lock(&adapter->rx_mac_learn_lock); + + tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id); + if (tmp_fil) + qlcnic_delete_rx_list_mac(adapter, tmp_fil, &src_addr, + vlan_id); + spin_unlock(&adapter->rx_mac_learn_lock); } } @@ -262,7 +295,7 @@ void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr, mac_req = (struct qlcnic_mac_req *)&(req->words[0]); mac_req->op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD; - memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN); + memcpy(mac_req->mac_addr, uaddr, ETH_ALEN); vlan_req = (struct qlcnic_vlan_req *)&req->words[1]; vlan_req->vlan_id = cpu_to_le16(vlan_id); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index cdc24e4d7e5c..b8242bc0293b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -977,8 +977,8 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) static int qlcnic_initialize_nic(struct qlcnic_adapter *adapter) { - int err; struct qlcnic_info nic_info; + int err = 0; memset(&nic_info, 0, sizeof(struct qlcnic_info)); err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw->pci_func); @@ -993,7 +993,9 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter) if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) { u32 temp; - temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2); + temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2, &err); + if (err == -EIO) + return err; adapter->ahw->extra_capability[0] = temp; } adapter->ahw->max_mac_filters = nic_info.max_mac_filters; @@ -1383,6 +1385,8 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter) if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { if (qlcnic_82xx_check(adapter)) handler = qlcnic_tmp_intr; + else + handler = qlcnic_83xx_tmp_intr; if (!QLCNIC_IS_MSI_FAMILY(adapter)) flags |= IRQF_SHARED; @@ -1531,12 +1535,12 @@ int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) if (netdev->features & NETIF_F_LRO) qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED); + set_bit(__QLCNIC_DEV_UP, &adapter->state); qlcnic_napi_enable(adapter); qlcnic_linkevent_request(adapter, 1); adapter->ahw->reset_context = 0; - set_bit(__QLCNIC_DEV_UP, &adapter->state); return 0; } @@ -2139,7 +2143,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (qlcnic_83xx_check(adapter) && !qlcnic_use_msi_x && !!qlcnic_use_msi) dev_warn(&pdev->dev, - "83xx adapter do not support MSI interrupts\n"); + "Device does not support MSI interrupts\n"); if (qlcnic_82xx_check(adapter)) { err = qlcnic_setup_intr(adapter, 0); @@ -3091,6 +3095,7 @@ qlcnic_check_health(struct qlcnic_adapter *adapter) { u32 state = 0, heartbeat; u32 peg_status; + int err = 0; if (qlcnic_check_temp(adapter)) goto detach; @@ -3137,11 +3142,11 @@ qlcnic_check_health(struct qlcnic_adapter *adapter) "PEG_NET_4_PC: 0x%x\n", peg_status, QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS2), - QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c), - QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c), - QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c), - QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c), - QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c)); + QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c, &err), + QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c, &err), + QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c, &err), + QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c, &err), + QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c, &err)); if (QLCNIC_FWERROR_CODE(peg_status) == 0x67) dev_err(&adapter->pdev->dev, "Firmware aborted with error code 0x00006700. " diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index ab8a6744d402..79e54efe07b9 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -1084,7 +1084,7 @@ flash_temp: tmpl_hdr = ahw->fw_dump.tmpl_hdr; tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF; - if ((tmpl_hdr->version & 0xffffff) >= 0x20001) + if ((tmpl_hdr->version & 0xfffff) >= 0x20001) ahw->fw_dump.use_pex_dma = true; else ahw->fw_dump.use_pex_dma = false; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index e58c1d4fa01f..046286a897ea 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -504,7 +504,7 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, INIT_LIST_HEAD(&adapter->vf_mc_list); if (!qlcnic_use_msi_x && !!qlcnic_use_msi) dev_warn(&adapter->pdev->dev, - "83xx adapter do not support MSI interrupts\n"); + "Device does not support MSI interrupts\n"); err = qlcnic_setup_intr(adapter, 1); if (err) { @@ -702,6 +702,7 @@ static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *mbx, u32 type) memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num); mbx->req.arg[0] = (type | (mbx->req.num << 16) | (3 << 29)); + mbx->rsp.arg[0] = (type & 0xffff) | mbx->rsp.num << 16; return 0; } } @@ -753,6 +754,7 @@ static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans, cmd->req.num = trans->req_pay_size / 4; cmd->rsp.num = trans->rsp_pay_size / 4; hdr = trans->rsp_hdr; + cmd->op_type = trans->req_hdr->op_type; } trans->trans_id = seq; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index ee0c1d307966..eb49cd65378c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -635,12 +635,12 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans, struct qlcnic_cmd_args *cmd) { struct qlcnic_vf_info *vf = trans->vf; - struct qlcnic_adapter *adapter = vf->adapter; - int err; + struct qlcnic_vport *vp = vf->vp; + struct qlcnic_adapter *adapter; u16 func = vf->pci_func; + int err; - cmd->rsp.arg[0] = trans->req_hdr->cmd_op; - cmd->rsp.arg[0] |= (1 << 16); + adapter = vf->adapter; if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) { err = qlcnic_sriov_pf_config_vport(adapter, 1, func); @@ -650,6 +650,8 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans, qlcnic_sriov_pf_config_vport(adapter, 0, func); } } else { + if (vp->vlan_mode == QLC_GUEST_VLAN_MODE) + vp->vlan = 0; err = qlcnic_sriov_pf_config_vport(adapter, 0, func); } @@ -1183,7 +1185,7 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans, u8 cmd_op, mode = vp->vlan_mode; cmd_op = trans->req_hdr->cmd_op; - cmd->rsp.arg[0] = (cmd_op & 0xffff) | 14 << 16 | 1 << 25; + cmd->rsp.arg[0] |= 1 << 25; switch (mode) { case QLC_GUEST_VLAN_MODE: @@ -1561,6 +1563,7 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov, struct qlcnic_vf_info *vf) { struct net_device *dev = vf->adapter->netdev; + struct qlcnic_vport *vp = vf->vp; if (!test_and_clear_bit(QLC_BC_VF_STATE, &vf->state)) { clear_bit(QLC_BC_VF_FLR, &vf->state); @@ -1573,6 +1576,9 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov, return; } + if (vp->vlan_mode == QLC_GUEST_VLAN_MODE) + vp->vlan = 0; + qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr); netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func); } @@ -1621,13 +1627,15 @@ int qlcnic_sriov_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) { struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_sriov *sriov = adapter->ahw->sriov; - int i, num_vfs = sriov->num_vfs; + int i, num_vfs; struct qlcnic_vf_info *vf_info; u8 *curr_mac; if (!qlcnic_sriov_pf_check(adapter)) return -EOPNOTSUPP; + num_vfs = sriov->num_vfs; + if (!is_valid_ether_addr(mac) || vf >= num_vfs) return -EINVAL; @@ -1741,6 +1749,7 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf, switch (vlan) { case 4095: + vp->vlan = 0; vp->vlan_mode = QLC_GUEST_VLAN_MODE; break; case 0: @@ -1759,6 +1768,29 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf, return 0; } +static inline __u32 qlcnic_sriov_get_vf_vlan(struct qlcnic_adapter *adapter, + struct qlcnic_vport *vp, int vf) +{ + __u32 vlan = 0; + + switch (vp->vlan_mode) { + case QLC_PVID_MODE: + vlan = vp->vlan; + break; + case QLC_GUEST_VLAN_MODE: + vlan = MAX_VLAN_ID; + break; + case QLC_NO_VLAN_MODE: + vlan = 0; + break; + default: + netdev_info(adapter->netdev, "Invalid VLAN mode = %d for VF %d\n", + vp->vlan_mode, vf); + } + + return vlan; +} + int qlcnic_sriov_get_vf_config(struct net_device *netdev, int vf, struct ifla_vf_info *ivi) { @@ -1774,7 +1806,7 @@ int qlcnic_sriov_get_vf_config(struct net_device *netdev, vp = sriov->vf_info[vf].vp; memcpy(&ivi->mac, vp->mac, ETH_ALEN); - ivi->vlan = vp->vlan; + ivi->vlan = qlcnic_sriov_get_vf_vlan(adapter, vp, vf); ivi->qos = vp->qos; ivi->spoofchk = vp->spoofchk; if (vp->max_tx_bw == MAX_BW) diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index e6acb9fa5767..6f35f8404d68 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -478,7 +478,7 @@ rx_status_loop: while (1) { u32 status, len; - dma_addr_t mapping; + dma_addr_t mapping, new_mapping; struct sk_buff *skb, *new_skb; struct cp_desc *desc; const unsigned buflen = cp->rx_buf_sz; @@ -520,6 +520,13 @@ rx_status_loop: goto rx_next; } + new_mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen, + PCI_DMA_FROMDEVICE); + if (dma_mapping_error(&cp->pdev->dev, new_mapping)) { + dev->stats.rx_dropped++; + goto rx_next; + } + dma_unmap_single(&cp->pdev->dev, mapping, buflen, PCI_DMA_FROMDEVICE); @@ -531,12 +538,11 @@ rx_status_loop: skb_put(skb, len); - mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen, - PCI_DMA_FROMDEVICE); cp->rx_skb[rx_tail] = new_skb; cp_rx_skb(cp, skb, desc); rx++; + mapping = new_mapping; rx_next: cp->rx_ring[rx_tail].opts2 = 0; @@ -716,6 +722,22 @@ static inline u32 cp_tx_vlan_tag(struct sk_buff *skb) TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00; } +static void unwind_tx_frag_mapping(struct cp_private *cp, struct sk_buff *skb, + int first, int entry_last) +{ + int frag, index; + struct cp_desc *txd; + skb_frag_t *this_frag; + for (frag = 0; frag+first < entry_last; frag++) { + index = first+frag; + cp->tx_skb[index] = NULL; + txd = &cp->tx_ring[index]; + this_frag = &skb_shinfo(skb)->frags[frag]; + dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr), + skb_frag_size(this_frag), PCI_DMA_TODEVICE); + } +} + static netdev_tx_t cp_start_xmit (struct sk_buff *skb, struct net_device *dev) { @@ -749,6 +771,9 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, len = skb->len; mapping = dma_map_single(&cp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE); + if (dma_mapping_error(&cp->pdev->dev, mapping)) + goto out_dma_error; + txd->opts2 = opts2; txd->addr = cpu_to_le64(mapping); wmb(); @@ -786,6 +811,9 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, first_len = skb_headlen(skb); first_mapping = dma_map_single(&cp->pdev->dev, skb->data, first_len, PCI_DMA_TODEVICE); + if (dma_mapping_error(&cp->pdev->dev, first_mapping)) + goto out_dma_error; + cp->tx_skb[entry] = skb; entry = NEXT_TX(entry); @@ -799,6 +827,11 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, mapping = dma_map_single(&cp->pdev->dev, skb_frag_address(this_frag), len, PCI_DMA_TODEVICE); + if (dma_mapping_error(&cp->pdev->dev, mapping)) { + unwind_tx_frag_mapping(cp, skb, first_entry, entry); + goto out_dma_error; + } + eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; ctrl = eor | len | DescOwn; @@ -859,11 +892,16 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1)) netif_stop_queue(dev); +out_unlock: spin_unlock_irqrestore(&cp->lock, intr_flags); cpw8(TxPoll, NormalTxPoll); return NETDEV_TX_OK; +out_dma_error: + kfree_skb(skb); + cp->dev->stats.tx_dropped++; + goto out_unlock; } /* Set or clear the multicast filter for this adaptor. @@ -1054,6 +1092,10 @@ static int cp_refill_rx(struct cp_private *cp) mapping = dma_map_single(&cp->pdev->dev, skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE); + if (dma_mapping_error(&cp->pdev->dev, mapping)) { + kfree_skb(skb); + goto err_out; + } cp->rx_skb[i] = skb; cp->rx_ring[i].opts2 = 0; diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 4106a743ca74..b5eb4195fc99 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -3689,7 +3689,7 @@ static void rtl_phy_work(struct rtl8169_private *tp) if (tp->link_ok(ioaddr)) return; - netif_warn(tp, link, tp->dev, "PHY reset until link up\n"); + netif_dbg(tp, link, tp->dev, "PHY reset until link up\n"); tp->phy_reset_enable(tp); @@ -6468,6 +6468,8 @@ static int rtl8169_close(struct net_device *dev) rtl8169_down(dev); rtl_unlock_work(tp); + cancel_work_sync(&tp->wk.work); + free_irq(pdev->irq, dev); dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, @@ -6793,8 +6795,6 @@ static void rtl_remove_one(struct pci_dev *pdev) rtl8168_driver_stop(tp); } - cancel_work_sync(&tp->wk.work); - netif_napi_del(&tp->napi); unregister_netdev(dev); diff --git a/drivers/net/ethernet/sfc/filter.c b/drivers/net/ethernet/sfc/filter.c index b74a60ab9ac7..2a469b27a506 100644 --- a/drivers/net/ethernet/sfc/filter.c +++ b/drivers/net/ethernet/sfc/filter.c @@ -1209,7 +1209,9 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, EFX_BUG_ON_PARANOID(skb_headlen(skb) < nhoff + 4 * ip->ihl + 4); ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); - efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT, 0, rxq_index); + efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT, + efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0, + rxq_index); rc = efx_filter_set_ipv4_full(&spec, ip->protocol, ip->daddr, ports[1], ip->saddr, ports[0]); if (rc) diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c index eb4aea3fe793..f5d7ad75e479 100644 --- a/drivers/net/ethernet/sis/sis900.c +++ b/drivers/net/ethernet/sis/sis900.c @@ -1318,7 +1318,7 @@ static void sis900_timer(unsigned long data) if (duplex){ sis900_set_mode(sis_priv, speed, duplex); sis630_set_eq(net_dev, sis_priv->chipset_rev); - netif_start_queue(net_dev); + netif_carrier_on(net_dev); } sis_priv->timer.expires = jiffies + HZ; @@ -1336,10 +1336,8 @@ static void sis900_timer(unsigned long data) status = sis900_default_phy(net_dev); mii_phy = sis_priv->mii; - if (status & MII_STAT_LINK){ + if (status & MII_STAT_LINK) sis900_check_mode(net_dev, mii_phy); - netif_carrier_on(net_dev); - } } else { /* Link ON -> OFF */ if (!(status & MII_STAT_LINK)){ @@ -1612,12 +1610,6 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) unsigned int index_cur_tx, index_dirty_tx; unsigned int count_dirty_tx; - /* Don't transmit data before the complete of auto-negotiation */ - if(!sis_priv->autong_complete){ - netif_stop_queue(net_dev); - return NETDEV_TX_BUSY; - } - spin_lock_irqsave(&sis_priv->lock, flags); /* Calculate the next Tx descriptor entry. */ diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index f51fcd49f3af..db6933ecb543 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -2093,7 +2093,7 @@ static int cpsw_probe(struct platform_device *pdev) while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) { for (i = res->start; i <= res->end; i++) { - if (request_irq(i, cpsw_interrupt, IRQF_DISABLED, + if (request_irq(i, cpsw_interrupt, 0, dev_name(&pdev->dev), priv)) { dev_err(priv->dev, "error attaching irq\n"); goto clean_ale_ret; diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 07b176bcf929..1a222bce4bd7 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1568,8 +1568,7 @@ static int emac_dev_open(struct net_device *ndev) while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) { for (i = res->start; i <= res->end; i++) { if (devm_request_irq(&priv->pdev->dev, i, emac_irq, - IRQF_DISABLED, - ndev->name, ndev)) + 0, ndev->name, ndev)) goto rollback; } k++; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 74907f53fdb4..a822207b8241 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -337,8 +337,11 @@ static int macvlan_open(struct net_device *dev) int err; if (vlan->port->passthru) { - if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) - dev_set_promiscuity(lowerdev, 1); + if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) { + err = dev_set_promiscuity(lowerdev, 1); + if (err < 0) + goto out; + } goto hash_add; } @@ -866,6 +869,18 @@ static int macvlan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct macvlan_dev *vlan = netdev_priv(dev); + enum macvlan_mode mode; + bool set_mode = false; + + /* Validate mode, but don't set yet: setting flags may fail. */ + if (data && data[IFLA_MACVLAN_MODE]) { + set_mode = true; + mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); + /* Passthrough mode can't be set or cleared dynamically */ + if ((mode == MACVLAN_MODE_PASSTHRU) != + (vlan->mode == MACVLAN_MODE_PASSTHRU)) + return -EINVAL; + } if (data && data[IFLA_MACVLAN_FLAGS]) { __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); @@ -882,8 +897,8 @@ static int macvlan_changelink(struct net_device *dev, } vlan->flags = flags; } - if (data && data[IFLA_MACVLAN_MODE]) - vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); + if (set_mode) + vlan->mode = mode; return 0; } diff --git a/drivers/net/phy/mdio-sun4i.c b/drivers/net/phy/mdio-sun4i.c index 61d3f4ebf52e..7f25e49ae37f 100644 --- a/drivers/net/phy/mdio-sun4i.c +++ b/drivers/net/phy/mdio-sun4i.c @@ -40,7 +40,7 @@ struct sun4i_mdio_data { static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum) { struct sun4i_mdio_data *data = bus->priv; - unsigned long start_jiffies; + unsigned long timeout_jiffies; int value; /* issue the phy address and reg */ @@ -49,10 +49,9 @@ static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum) writel(0x1, data->membase + EMAC_MAC_MCMD_REG); /* Wait read complete */ - start_jiffies = jiffies; + timeout_jiffies = jiffies + MDIO_TIMEOUT; while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) { - if (time_after(start_jiffies, - start_jiffies + MDIO_TIMEOUT)) + if (time_is_before_jiffies(timeout_jiffies)) return -ETIMEDOUT; msleep(1); } @@ -69,7 +68,7 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) { struct sun4i_mdio_data *data = bus->priv; - unsigned long start_jiffies; + unsigned long timeout_jiffies; /* issue the phy address and reg */ writel((mii_id << 8) | regnum, data->membase + EMAC_MAC_MADR_REG); @@ -77,10 +76,9 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum, writel(0x1, data->membase + EMAC_MAC_MCMD_REG); /* Wait read complete */ - start_jiffies = jiffies; + timeout_jiffies = jiffies + MDIO_TIMEOUT; while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) { - if (time_after(start_jiffies, - start_jiffies + MDIO_TIMEOUT)) + if (time_is_before_jiffies(timeout_jiffies)) return -ETIMEDOUT; msleep(1); } diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 658540433faf..5a468f317ca5 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -1032,10 +1032,10 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) dev->mii.supports_gmii = 1; dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + NETIF_F_RXCSUM; dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + NETIF_F_RXCSUM; /* Enable checksum offload */ *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | @@ -1176,7 +1176,6 @@ ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) if (((skb->len + 8) % frame_size) == 0) tx_hdr2 |= 0x80008000; /* Enable padding */ - skb_linearize(skb); headroom = skb_headroom(skb); tailroom = skb_tailroom(skb); @@ -1320,10 +1319,10 @@ static int ax88179_reset(struct usbnet *dev) 1, 1, tmp); dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + NETIF_F_RXCSUM; dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + NETIF_F_RXCSUM; /* Enable checksum offload */ *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index ee13f9eb740c..11c51f275366 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -344,17 +344,41 @@ static const int multicast_filter_limit = 32; static int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) { - return usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0), + int ret; + void *tmp; + + tmp = kmalloc(size, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0), RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, - value, index, data, size, 500); + value, index, tmp, size, 500); + + memcpy(data, tmp, size); + kfree(tmp); + + return ret; } static int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) { - return usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0), + int ret; + void *tmp; + + tmp = kmalloc(size, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + memcpy(tmp, data, size); + + ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0), RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE, - value, index, data, size, 500); + value, index, tmp, size, 500); + + kfree(tmp); + return ret; } static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size, @@ -490,37 +514,31 @@ int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data) static u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index) { - u32 data; + __le32 data; - if (type == MCU_TYPE_PLA) - pla_ocp_read(tp, index, sizeof(data), &data); - else - usb_ocp_read(tp, index, sizeof(data), &data); + generic_ocp_read(tp, index, sizeof(data), &data, type); return __le32_to_cpu(data); } static void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data) { - if (type == MCU_TYPE_PLA) - pla_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data); - else - usb_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data); + __le32 tmp = __cpu_to_le32(data); + + generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type); } static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index) { u32 data; + __le32 tmp; u8 shift = index & 2; index &= ~3; - if (type == MCU_TYPE_PLA) - pla_ocp_read(tp, index, sizeof(data), &data); - else - usb_ocp_read(tp, index, sizeof(data), &data); + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - data = __le32_to_cpu(data); + data = __le32_to_cpu(tmp); data >>= (shift * 8); data &= 0xffff; @@ -529,7 +547,8 @@ static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index) static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data) { - u32 tmp, mask = 0xffff; + u32 mask = 0xffff; + __le32 tmp; u16 byen = BYTE_EN_WORD; u8 shift = index & 2; @@ -542,34 +561,25 @@ static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data) index &= ~3; } - if (type == MCU_TYPE_PLA) - pla_ocp_read(tp, index, sizeof(tmp), &tmp); - else - usb_ocp_read(tp, index, sizeof(tmp), &tmp); + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - tmp = __le32_to_cpu(tmp) & ~mask; - tmp |= data; - tmp = __cpu_to_le32(tmp); + data |= __le32_to_cpu(tmp) & ~mask; + tmp = __cpu_to_le32(data); - if (type == MCU_TYPE_PLA) - pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp); - else - usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp); + generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); } static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index) { u32 data; + __le32 tmp; u8 shift = index & 3; index &= ~3; - if (type == MCU_TYPE_PLA) - pla_ocp_read(tp, index, sizeof(data), &data); - else - usb_ocp_read(tp, index, sizeof(data), &data); + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - data = __le32_to_cpu(data); + data = __le32_to_cpu(tmp); data >>= (shift * 8); data &= 0xff; @@ -578,7 +588,8 @@ static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index) static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data) { - u32 tmp, mask = 0xff; + u32 mask = 0xff; + __le32 tmp; u16 byen = BYTE_EN_BYTE; u8 shift = index & 3; @@ -591,19 +602,12 @@ static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data) index &= ~3; } - if (type == MCU_TYPE_PLA) - pla_ocp_read(tp, index, sizeof(tmp), &tmp); - else - usb_ocp_read(tp, index, sizeof(tmp), &tmp); + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - tmp = __le32_to_cpu(tmp) & ~mask; - tmp |= data; - tmp = __cpu_to_le32(tmp); + data |= __le32_to_cpu(tmp) & ~mask; + tmp = __cpu_to_le32(data); - if (type == MCU_TYPE_PLA) - pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp); - else - usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp); + generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); } static void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value) @@ -685,21 +689,14 @@ static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data) static inline void set_ethernet_addr(struct r8152 *tp) { struct net_device *dev = tp->netdev; - u8 *node_id; - - node_id = kmalloc(sizeof(u8) * 8, GFP_KERNEL); - if (!node_id) { - netif_err(tp, probe, dev, "out of memory"); - return; - } + u8 node_id[8] = {0}; - if (pla_ocp_read(tp, PLA_IDR, sizeof(u8) * 8, node_id) < 0) + if (pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id) < 0) netif_notice(tp, probe, dev, "inet addr fail\n"); else { memcpy(dev->dev_addr, node_id, dev->addr_len); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); } - kfree(node_id); } static int rtl8152_set_mac_address(struct net_device *netdev, void *p) @@ -882,15 +879,10 @@ static void rtl8152_set_rx_mode(struct net_device *netdev) static void _rtl8152_set_rx_mode(struct net_device *netdev) { struct r8152 *tp = netdev_priv(netdev); - u32 tmp, *mc_filter; /* Multicast hash filter */ + u32 mc_filter[2]; /* Multicast hash filter */ + __le32 tmp[2]; u32 ocp_data; - mc_filter = kmalloc(sizeof(u32) * 2, GFP_KERNEL); - if (!mc_filter) { - netif_err(tp, link, netdev, "out of memory"); - return; - } - clear_bit(RTL8152_SET_RX_MODE, &tp->flags); netif_stop_queue(netdev); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); @@ -918,14 +910,12 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev) } } - tmp = mc_filter[0]; - mc_filter[0] = __cpu_to_le32(swab32(mc_filter[1])); - mc_filter[1] = __cpu_to_le32(swab32(tmp)); + tmp[0] = __cpu_to_le32(swab32(mc_filter[1])); + tmp[1] = __cpu_to_le32(swab32(mc_filter[0])); - pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(u32) * 2, mc_filter); + pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(tmp), tmp); ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); netif_wake_queue(netdev); - kfree(mc_filter); } static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c index 852392269718..2df2f4fb42a7 100644 --- a/drivers/net/usb/r815x.c +++ b/drivers/net/usb/r815x.c @@ -24,34 +24,43 @@ static int pla_read_word(struct usb_device *udev, u16 index) { - int data, ret; + int ret; u8 shift = index & 2; - __le32 ocp_data; + __le32 *tmp; + + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; index &= ~3; ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), RTL815x_REQ_GET_REGS, RTL815x_REQT_READ, - index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data), - 500); + index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500); if (ret < 0) - return ret; + goto out2; - data = __le32_to_cpu(ocp_data); - data >>= (shift * 8); - data &= 0xffff; + ret = __le32_to_cpu(*tmp); + ret >>= (shift * 8); + ret &= 0xffff; - return data; +out2: + kfree(tmp); + return ret; } static int pla_write_word(struct usb_device *udev, u16 index, u32 data) { - __le32 ocp_data; + __le32 *tmp; u32 mask = 0xffff; u16 byen = BYTE_EN_WORD; u8 shift = index & 2; int ret; + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + data &= mask; if (shift) { @@ -63,19 +72,20 @@ static int pla_write_word(struct usb_device *udev, u16 index, u32 data) ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), RTL815x_REQ_GET_REGS, RTL815x_REQT_READ, - index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data), - 500); + index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500); if (ret < 0) - return ret; + goto out3; - data |= __le32_to_cpu(ocp_data) & ~mask; - ocp_data = __cpu_to_le32(data); + data |= __le32_to_cpu(*tmp) & ~mask; + *tmp = __cpu_to_le32(data); ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE, - index, MCU_TYPE_PLA | byen, &ocp_data, - sizeof(ocp_data), 500); + index, MCU_TYPE_PLA | byen, tmp, sizeof(*tmp), + 500); +out3: + kfree(tmp); return ret; } @@ -116,11 +126,18 @@ out1: static int r815x_mdio_read(struct net_device *netdev, int phy_id, int reg) { struct usbnet *dev = netdev_priv(netdev); + int ret; if (phy_id != R815x_PHY_ID) return -EINVAL; - return ocp_reg_read(dev, BASE_MII + reg * 2); + if (usb_autopm_get_interface(dev->intf) < 0) + return -ENODEV; + + ret = ocp_reg_read(dev, BASE_MII + reg * 2); + + usb_autopm_put_interface(dev->intf); + return ret; } static @@ -131,7 +148,12 @@ void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val) if (phy_id != R815x_PHY_ID) return; + if (usb_autopm_get_interface(dev->intf) < 0) + return; + ocp_reg_write(dev, BASE_MII + reg * 2, val); + + usb_autopm_put_interface(dev->intf); } static int r8153_bind(struct usbnet *dev, struct usb_interface *intf) @@ -150,7 +172,7 @@ static int r8153_bind(struct usbnet *dev, struct usb_interface *intf) dev->mii.phy_id = R815x_PHY_ID; dev->mii.supports_gmii = 1; - return 0; + return status; } static int r8152_bind(struct usbnet *dev, struct usb_interface *intf) @@ -169,7 +191,7 @@ static int r8152_bind(struct usbnet *dev, struct usb_interface *intf) dev->mii.phy_id = R815x_PHY_ID; dev->mii.supports_gmii = 0; - return 0; + return status; } static const struct driver_info r8152_info = { diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 75409748c774..66ebbacf066f 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -45,7 +45,6 @@ #define EEPROM_MAC_OFFSET (0x01) #define DEFAULT_TX_CSUM_ENABLE (true) #define DEFAULT_RX_CSUM_ENABLE (true) -#define DEFAULT_TSO_ENABLE (true) #define SMSC75XX_INTERNAL_PHY_ID (1) #define SMSC75XX_TX_OVERHEAD (8) #define MAX_RX_FIFO_SIZE (20 * 1024) @@ -1410,17 +1409,14 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); - if (DEFAULT_TX_CSUM_ENABLE) { + if (DEFAULT_TX_CSUM_ENABLE) dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - if (DEFAULT_TSO_ENABLE) - dev->net->features |= NETIF_F_SG | - NETIF_F_TSO | NETIF_F_TSO6; - } + if (DEFAULT_RX_CSUM_ENABLE) dev->net->features |= NETIF_F_RXCSUM; dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM; + NETIF_F_RXCSUM; ret = smsc75xx_wait_ready(dev, 0); if (ret < 0) { @@ -2200,8 +2196,6 @@ static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev, { u32 tx_cmd_a, tx_cmd_b; - skb_linearize(skb); - if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) { struct sk_buff *skb2 = skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags); diff --git a/drivers/net/veth.c b/drivers/net/veth.c index da866523cf20..eee1f19ef1e9 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -269,6 +269,7 @@ static void veth_setup(struct net_device *dev) dev->ethtool_ops = &veth_ethtool_ops; dev->features |= NETIF_F_LLTX; dev->features |= VETH_FEATURES; + dev->vlan_features = dev->features; dev->destructor = veth_dev_free; dev->hw_features = VETH_FEATURES; diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index f401c1a9d9c3..c3dd6e496327 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -136,7 +136,8 @@ struct vxlan_dev { u32 flags; /* VXLAN_F_* below */ struct work_struct sock_work; - struct work_struct igmp_work; + struct work_struct igmp_join; + struct work_struct igmp_leave; unsigned long age_interval; struct timer_list age_timer; @@ -774,7 +775,6 @@ static bool vxlan_snoop(struct net_device *dev, return false; } - /* See if multicast group is already in use by other ID */ static bool vxlan_group_used(struct vxlan_net *vn, __be32 remote_ip) { @@ -808,12 +808,13 @@ static void vxlan_sock_release(struct vxlan_net *vn, struct vxlan_sock *vs) queue_work(vxlan_wq, &vs->del_work); } -/* Callback to update multicast group membership. - * Scheduled when vxlan goes up/down. +/* Callback to update multicast group membership when first VNI on + * multicast asddress is brought up + * Done as workqueue because ip_mc_join_group acquires RTNL. */ -static void vxlan_igmp_work(struct work_struct *work) +static void vxlan_igmp_join(struct work_struct *work) { - struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_work); + struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_join); struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id); struct vxlan_sock *vs = vxlan->vn_sock; struct sock *sk = vs->sock->sk; @@ -823,10 +824,27 @@ static void vxlan_igmp_work(struct work_struct *work) }; lock_sock(sk); - if (vxlan_group_used(vn, vxlan->default_dst.remote_ip)) - ip_mc_join_group(sk, &mreq); - else - ip_mc_leave_group(sk, &mreq); + ip_mc_join_group(sk, &mreq); + release_sock(sk); + + vxlan_sock_release(vn, vs); + dev_put(vxlan->dev); +} + +/* Inverse of vxlan_igmp_join when last VNI is brought down */ +static void vxlan_igmp_leave(struct work_struct *work) +{ + struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_leave); + struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id); + struct vxlan_sock *vs = vxlan->vn_sock; + struct sock *sk = vs->sock->sk; + struct ip_mreqn mreq = { + .imr_multiaddr.s_addr = vxlan->default_dst.remote_ip, + .imr_ifindex = vxlan->default_dst.remote_ifindex, + }; + + lock_sock(sk); + ip_mc_leave_group(sk, &mreq); release_sock(sk); vxlan_sock_release(vn, vs); @@ -1397,6 +1415,7 @@ static void vxlan_uninit(struct net_device *dev) /* Start ageing timer and join group when device is brought up */ static int vxlan_open(struct net_device *dev) { + struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_sock *vs = vxlan->vn_sock; @@ -1404,10 +1423,11 @@ static int vxlan_open(struct net_device *dev) if (!vs) return -ENOTCONN; - if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) { + if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) && + ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) { vxlan_sock_hold(vs); dev_hold(dev); - queue_work(vxlan_wq, &vxlan->igmp_work); + queue_work(vxlan_wq, &vxlan->igmp_join); } if (vxlan->age_interval) @@ -1438,13 +1458,15 @@ static void vxlan_flush(struct vxlan_dev *vxlan) /* Cleanup timer and forwarding table on shutdown */ static int vxlan_stop(struct net_device *dev) { + struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_sock *vs = vxlan->vn_sock; - if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) { + if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) && + ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) { vxlan_sock_hold(vs); dev_hold(dev); - queue_work(vxlan_wq, &vxlan->igmp_work); + queue_work(vxlan_wq, &vxlan->igmp_leave); } del_timer_sync(&vxlan->age_timer); @@ -1509,7 +1531,8 @@ static void vxlan_setup(struct net_device *dev) INIT_LIST_HEAD(&vxlan->next); spin_lock_init(&vxlan->hash_lock); - INIT_WORK(&vxlan->igmp_work, vxlan_igmp_work); + INIT_WORK(&vxlan->igmp_join, vxlan_igmp_join); + INIT_WORK(&vxlan->igmp_leave, vxlan_igmp_leave); INIT_WORK(&vxlan->sock_work, vxlan_sock_work); init_timer_deferrable(&vxlan->age_timer); @@ -1916,10 +1939,12 @@ static __net_exit void vxlan_exit_net(struct net *net) { struct vxlan_net *vn = net_generic(net, vxlan_net_id); struct vxlan_dev *vxlan; + LIST_HEAD(list); rtnl_lock(); list_for_each_entry(vxlan, &vn->vxlan_list, next) - dev_close(vxlan->dev); + unregister_netdevice_queue(vxlan->dev, &list); + unregister_netdevice_many(&list); rtnl_unlock(); } diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index cde58fe96254..82e8088ca9b4 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -1,6 +1,6 @@ config ATH10K tristate "Atheros 802.11ac wireless cards support" - depends on MAC80211 + depends on MAC80211 && HAS_DMA select ATH_COMMON ---help--- This module adds support for wireless adapters based on diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 81b686c6a376..40825d43322e 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -325,7 +325,7 @@ ath5k_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr *ha; mfilt[0] = 0; - mfilt[1] = 1; + mfilt[1] = 0; netdev_hw_addr_list_for_each(ha, mc_list) { /* calculate XOR of eight 6-bit values */ diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index d1acfe98918a..1576d58291d4 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -610,7 +610,15 @@ static void ar5008_hw_override_ini(struct ath_hw *ah, REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); if (AR_SREV_9280_20_OR_LATER(ah)) { - val = REG_READ(ah, AR_PCU_MISC_MODE2); + /* + * For AR9280 and above, there is a new feature that allows + * Multicast search based on both MAC Address and Key ID. + * By default, this feature is enabled. But since the driver + * is not using this feature, we switch it off; otherwise + * multicast search based on MAC addr only will fail. + */ + val = REG_READ(ah, AR_PCU_MISC_MODE2) & + (~AR_ADHOC_MCAST_KEYID_ENABLE); if (!AR_SREV_9271(ah)) val &= ~AR_PCU_MISC_MODE2_HWWAR1; diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 9e582e14da74..5205a3625e84 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -1082,7 +1082,7 @@ static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev) struct device *dev = &hif_dev->udev->dev; struct device *parent = dev->parent; - complete(&hif_dev->fw_done); + complete_all(&hif_dev->fw_done); if (parent) device_lock(parent); @@ -1131,7 +1131,7 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context) release_firmware(fw); hif_dev->flags |= HIF_USB_READY; - complete(&hif_dev->fw_done); + complete_all(&hif_dev->fw_done); return; @@ -1295,7 +1295,9 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface) usb_set_intfdata(interface, NULL); - if (!unplugged && (hif_dev->flags & HIF_USB_START)) + /* If firmware was loaded we should drop it + * go back to first stage bootloader. */ + if (!unplugged && (hif_dev->flags & HIF_USB_READY)) ath9k_hif_usb_reboot(udev); kfree(hif_dev); @@ -1316,7 +1318,10 @@ static int ath9k_hif_usb_suspend(struct usb_interface *interface, if (!(hif_dev->flags & HIF_USB_START)) ath9k_htc_suspend(hif_dev->htc_handle); - ath9k_hif_usb_dealloc_urbs(hif_dev); + wait_for_completion(&hif_dev->fw_done); + + if (hif_dev->flags & HIF_USB_READY) + ath9k_hif_usb_dealloc_urbs(hif_dev); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 71a183ffc77f..c3676bf1d6c4 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -861,6 +861,7 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, if (error != 0) goto err_rx; + ath9k_hw_disable(priv->ah); #ifdef CONFIG_MAC80211_LEDS /* must be initialized before ieee80211_register_hw */ priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw, diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index c59ae43b9b35..927992732620 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -146,6 +146,28 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta, ARRAY_SIZE(bf->rates)); } +static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, + struct sk_buff *skb) +{ + int q; + + q = skb_get_queue_mapping(skb); + if (txq == sc->tx.uapsdq) + txq = sc->tx.txq_map[q]; + + if (txq != sc->tx.txq_map[q]) + return; + + if (WARN_ON(--txq->pending_frames < 0)) + txq->pending_frames = 0; + + if (txq->stopped && + txq->pending_frames < sc->tx.txq_max_pending[q]) { + ieee80211_wake_queue(sc->hw, q); + txq->stopped = false; + } +} + static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = tid->ac->txq; @@ -167,6 +189,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) if (!bf) { bf = ath_tx_setup_buffer(sc, txq, tid, skb); if (!bf) { + ath_txq_skb_done(sc, txq, skb); ieee80211_free_txskb(sc->hw, skb); continue; } @@ -811,6 +834,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, if (!bf) { __skb_unlink(skb, &tid->buf_q); + ath_txq_skb_done(sc, txq, skb); ieee80211_free_txskb(sc->hw, skb); continue; } @@ -1824,6 +1848,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_txq *txq, bf = ath_tx_setup_buffer(sc, txq, tid, skb); if (!bf) { + ath_txq_skb_done(sc, txq, skb); ieee80211_free_txskb(sc->hw, skb); return; } @@ -2090,6 +2115,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, bf = ath_tx_setup_buffer(sc, txq, tid, skb); if (!bf) { + ath_txq_skb_done(sc, txq, skb); if (txctl->paprd) dev_kfree_skb_any(skb); else @@ -2189,7 +2215,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; - int q, padpos, padsize; + int padpos, padsize; unsigned long flags; ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb); @@ -2225,21 +2251,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, spin_unlock_irqrestore(&sc->sc_pm_lock, flags); __skb_queue_tail(&txq->complete_q, skb); - - q = skb_get_queue_mapping(skb); - if (txq == sc->tx.uapsdq) - txq = sc->tx.txq_map[q]; - - if (txq == sc->tx.txq_map[q]) { - if (WARN_ON(--txq->pending_frames < 0)) - txq->pending_frames = 0; - - if (txq->stopped && - txq->pending_frames < sc->tx.txq_max_pending[q]) { - ieee80211_wake_queue(sc->hw, q); - txq->stopped = false; - } - } + ath_txq_skb_done(sc, txq, skb); } static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index e8308ec30970..ab636767fbde 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -145,7 +145,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix, le16_to_cpu(hdr.type), hdr.flags); if (len <= MAX_MBOXITEM_SIZE) { int n = 0; - unsigned char printbuf[16 * 3 + 2]; + char printbuf[16 * 3 + 2]; unsigned char databuf[MAX_MBOXITEM_SIZE]; void __iomem *src = wmi_buffer(wil, d.addr) + sizeof(struct wil6210_mbox_hdr); @@ -416,7 +416,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) seq_printf(s, " SKB = %p\n", skb); if (skb) { - unsigned char printbuf[16 * 3 + 2]; + char printbuf[16 * 3 + 2]; int i = 0; int len = le16_to_cpu(d->dma.length); void *p = skb->data; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 8e8975562ec3..80099016d21f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -242,7 +242,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp, { unsigned long flags; - if (!ifp) + if (!ifp || !ifp->ndev) return; brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n", diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index f0d9f7f6c83d..29b1f24c2d0f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -1744,13 +1744,14 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) ulong flags; int fifo = BRCMF_FWS_FIFO_BCMC; bool multicast = is_multicast_ether_addr(eh->h_dest); + bool pae = eh->h_proto == htons(ETH_P_PAE); /* determine the priority */ if (!skb->priority) skb->priority = cfg80211_classify8021d(skb); drvr->tx_multicast += !!multicast; - if (ntohs(eh->h_proto) == ETH_P_PAE) + if (pae) atomic_inc(&ifp->pend_8021x_cnt); if (!brcmf_fws_fc_active(fws)) { @@ -1781,6 +1782,11 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) brcmf_fws_schedule_deq(fws); } else { brcmf_err("drop skb: no hanger slot\n"); + if (pae) { + atomic_dec(&ifp->pend_8021x_cnt); + if (waitqueue_active(&ifp->pend_8021x_wait)) + wake_up(&ifp->pend_8021x_wait); + } brcmu_pkt_buf_free_skb(skb); } brcmf_fws_unlock(drvr, flags); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 277b37ae7126..7fa71f73cfe8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -1093,8 +1093,11 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n "); err = brcmf_fil_cmd_data_set(vif->ifp, BRCMF_C_DISASSOC, NULL, 0); - if (err) + if (err) { brcmf_err("WLC_DISASSOC failed (%d)\n", err); + cfg80211_disconnected(vif->wdev.netdev, 0, + NULL, 0, GFP_KERNEL); + } clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state); } clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state); diff --git a/drivers/net/wireless/cw1200/txrx.c b/drivers/net/wireless/cw1200/txrx.c index 5862c373d714..e824d4d4a18d 100644 --- a/drivers/net/wireless/cw1200/txrx.c +++ b/drivers/net/wireless/cw1200/txrx.c @@ -1165,7 +1165,7 @@ void cw1200_rx_cb(struct cw1200_common *priv, if (cw1200_handle_action_rx(priv, skb)) return; } else if (ieee80211_is_beacon(frame->frame_control) && - !arg->status && + !arg->status && priv->vif && !memcmp(ieee80211_get_SA(frame), priv->vif->bss_conf.bssid, ETH_ALEN)) { const u8 *tim_ie; diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 3952ddf2ddb2..1531a4fc0960 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -758,7 +758,7 @@ int iwl_alive_start(struct iwl_priv *priv) BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); if (ret) return ret; - } else { + } else if (priv->lib->bt_params) { /* * default is 2-wire BT coexexistence support */ diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index ff8cc75c189d..a70c7b9d9bad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -97,6 +97,8 @@ #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) +#define APMG_RTC_INT_STT_RFKILL (0x10000000) + /* Device system time */ #define DEVICE_SYSTEM_TIME_REG 0xA0206C diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 7e5e5c2f9f87..83da884cf303 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -134,7 +134,7 @@ struct wowlan_key_data { struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; struct iwl_wowlan_tkip_params_cmd *tkip; bool error, use_rsc_tsc, use_tkip; - int gtk_key_idx; + int wep_key_idx; }; static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, @@ -188,8 +188,8 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, wkc.wep_key.key_offset = 0; } else { /* others start at 1 */ - data->gtk_key_idx++; - wkc.wep_key.key_offset = data->gtk_key_idx; + data->wep_key_idx++; + wkc.wep_key.key_offset = data->wep_key_idx; } ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, CMD_SYNC, @@ -316,8 +316,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, mvm->ptk_ivlen = key->iv_len; mvm->ptk_icvlen = key->icv_len; } else { - data->gtk_key_idx++; - key->hw_key_idx = data->gtk_key_idx; + /* + * firmware only supports TSC/RSC for a single key, + * so if there are multiple keep overwriting them + * with new ones -- this relies on mac80211 doing + * list_add_tail(). + */ + key->hw_key_idx = 1; mvm->gtk_ivlen = key->iv_len; mvm->gtk_icvlen = key->icv_len; } diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index e56ed2a84888..c24a744910ac 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -988,7 +988,11 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); char buf[100]; - if (!dbgfs_dir) + /* + * Check if debugfs directory already exist before creating it. + * This may happen when, for example, resetting hw or suspend-resume + */ + if (!dbgfs_dir || mvmvif->dbgfs_dir) return; mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index b60d14151721..365095a0c3b3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -69,7 +69,6 @@ /* Scan Commands, Responses, Notifications */ /* Masks for iwl_scan_channel.type flags */ -#define SCAN_CHANNEL_TYPE_PASSIVE 0 #define SCAN_CHANNEL_TYPE_ACTIVE BIT(0) #define SCAN_CHANNEL_NARROW_BAND BIT(22) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e08683b20531..f19baf0dea6b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -257,7 +257,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) if (ret) return ret; - return ieee80211_register_hw(mvm->hw); + ret = ieee80211_register_hw(mvm->hw); + if (ret) + iwl_mvm_leds_exit(mvm); + + return ret; } static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, @@ -385,6 +389,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) ieee80211_wake_queues(mvm->hw); mvm->vif_count = 0; + mvm->rx_ba_sessions = 0; } static int iwl_mvm_mac_start(struct ieee80211_hw *hw) @@ -507,6 +512,27 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, goto out_unlock; /* + * TODO: remove this temporary code. + * Currently MVM FW supports power management only on single MAC. + * If new interface added, disable PM on existing interface. + * P2P device is a special case, since it is handled by FW similary to + * scan. If P2P deviced is added, PM remains enabled on existing + * interface. + * Note: the method below does not count the new interface being added + * at this moment. + */ + if (vif->type != NL80211_IFTYPE_P2P_DEVICE) + mvm->vif_count++; + if (mvm->vif_count > 1) { + IWL_DEBUG_MAC80211(mvm, + "Disable power on existing interfaces\n"); + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_pm_disable_iterator, mvm); + } + + /* * The AP binding flow can be done only after the beacon * template is configured (which happens only in the mac80211 * start_ap() flow), and adding the broadcast station can happen @@ -529,27 +555,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, goto out_unlock; } - /* - * TODO: remove this temporary code. - * Currently MVM FW supports power management only on single MAC. - * If new interface added, disable PM on existing interface. - * P2P device is a special case, since it is handled by FW similary to - * scan. If P2P deviced is added, PM remains enabled on existing - * interface. - * Note: the method below does not count the new interface being added - * at this moment. - */ - if (vif->type != NL80211_IFTYPE_P2P_DEVICE) - mvm->vif_count++; - if (mvm->vif_count > 1) { - IWL_DEBUG_MAC80211(mvm, - "Disable power on existing interfaces\n"); - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_pm_disable_iterator, mvm); - } - ret = iwl_mvm_mac_ctxt_add(mvm, vif); if (ret) goto out_release; @@ -1006,6 +1011,21 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); if (old_state == IEEE80211_STA_NOTEXIST && new_state == IEEE80211_STA_NONE) { + /* + * Firmware bug - it'll crash if the beacon interval is less + * than 16. We can't avoid connecting at all, so refuse the + * station state change, this will cause mac80211 to abandon + * attempts to connect to this AP, and eventually wpa_s will + * blacklist the AP... + */ + if (vif->type == NL80211_IFTYPE_STATION && + vif->bss_conf.beacon_int < 16) { + IWL_ERR(mvm, + "AP %pM beacon interval is %d, refusing due to firmware bug!\n", + sta->addr, vif->bss_conf.beacon_int); + ret = -EINVAL; + goto out_unlock; + } ret = iwl_mvm_add_sta(mvm, vif, sta); } else if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_AUTH) { @@ -1038,6 +1058,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, } else { ret = -EIO; } + out_unlock: mutex_unlock(&mvm->mutex); return ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d40d7db185d6..420e82d379d9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -419,6 +419,7 @@ struct iwl_mvm { struct work_struct sta_drained_wk; unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; atomic_t pending_frames[IWL_MVM_STATION_COUNT]; + u8 rx_ba_sessions; /* configured by mac80211 */ u32 rts_threshold; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 2157b0f8ced5..acdff6b67e04 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -137,8 +137,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd, { int fw_idx, req_idx; - fw_idx = 0; - for (req_idx = req->n_ssids - 1; req_idx > 0; req_idx--) { + for (req_idx = req->n_ssids - 1, fw_idx = 0; req_idx > 0; + req_idx--, fw_idx++) { cmd->direct_scan[fw_idx].id = WLAN_EID_SSID; cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len; memcpy(cmd->direct_scan[fw_idx].ssid, @@ -153,7 +153,9 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd, * just to notify that this scan is active and not passive. * In order to notify the FW of the number of SSIDs we wish to scan (including * the zero-length one), we need to set the corresponding bits in chan->type, - * one for each SSID, and set the active bit (first). + * one for each SSID, and set the active bit (first). The first SSID is already + * included in the probe template, so we need to set only req->n_ssids - 1 bits + * in addition to the first bit. */ static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids) { @@ -176,19 +178,12 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, struct iwl_scan_channel *chan = (struct iwl_scan_channel *) (cmd->data + le16_to_cpu(cmd->tx_cmd.len)); int i; - __le32 chan_type_value; - - if (req->n_ssids > 0) - chan_type_value = cpu_to_le32(BIT(req->n_ssids + 1) - 1); - else - chan_type_value = SCAN_CHANNEL_TYPE_PASSIVE; for (i = 0; i < cmd->channel_count; i++) { chan->channel = cpu_to_le16(req->channels[i]->hw_value); + chan->type = cpu_to_le32(BIT(req->n_ssids) - 1); if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) - chan->type = SCAN_CHANNEL_TYPE_PASSIVE; - else - chan->type = chan_type_value; + chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE); chan->active_dwell = cpu_to_le16(active_dwell); chan->passive_dwell = cpu_to_le16(passive_dwell); chan->iteration_count = cpu_to_le16(1); diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 62fe5209093b..563f559b902d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -608,6 +608,8 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta) return ret; } +#define IWL_MAX_RX_BA_SESSIONS 16 + int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u16 ssn, bool start) { @@ -618,11 +620,20 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lockdep_assert_held(&mvm->mutex); + if (start && mvm->rx_ba_sessions >= IWL_MAX_RX_BA_SESSIONS) { + IWL_WARN(mvm, "Not enough RX BA SESSIONS\n"); + return -ENOSPC; + } + cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); cmd.sta_id = mvm_sta->sta_id; cmd.add_modify = STA_MODE_MODIFY; - cmd.add_immediate_ba_tid = (u8) tid; - cmd.add_immediate_ba_ssn = cpu_to_le16(ssn); + if (start) { + cmd.add_immediate_ba_tid = (u8) tid; + cmd.add_immediate_ba_ssn = cpu_to_le16(ssn); + } else { + cmd.remove_immediate_ba_tid = (u8) tid; + } cmd.modify_mask = start ? STA_MODIFY_ADD_BA_TID : STA_MODIFY_REMOVE_BA_TID; @@ -648,6 +659,14 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, break; } + if (!ret) { + if (start) + mvm->rx_ba_sessions++; + else if (mvm->rx_ba_sessions > 0) + /* check that restart flow didn't zero the counter */ + mvm->rx_ba_sessions--; + } + return ret; } @@ -896,6 +915,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; u16 txq_id; + enum iwl_mvm_agg_state old_state; /* * First set the agg state to OFF to avoid calling @@ -905,13 +925,17 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, txq_id = tid_data->txq_id; IWL_DEBUG_TX_QUEUES(mvm, "Flush AGG: sta %d tid %d q %d state %d\n", mvmsta->sta_id, tid, txq_id, tid_data->state); + old_state = tid_data->state; tid_data->state = IWL_AGG_OFF; spin_unlock_bh(&mvmsta->lock); - if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true)) - IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); + if (old_state >= IWL_AGG_ON) { + if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true)) + IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); + + iwl_trans_txq_disable(mvm->trans, tid_data->txq_id); + } - iwl_trans_txq_disable(mvm->trans, tid_data->txq_id); mvm->queue_to_mac80211[tid_data->txq_id] = IWL_INVALID_MAC80211_QUEUE; diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 81f3ea5b09a4..ff13458efc27 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -130,6 +130,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */ {IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */ {IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x423C, 0x1326, iwl5150_abg_cfg)}, /* Half Mini Card */ {IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */ {IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */ diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index fd848cd1583e..f600e68a410a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -888,6 +888,14 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); if (hw_rfkill) { + /* + * Clear the interrupt in APMG if the NIC is going down. + * Note that when the NIC exits RFkill (else branch), we + * can't access prph and the NIC will be reset in + * start_hw anyway. + */ + iwl_write_prph(trans, APMG_RTC_INT_STT_REG, + APMG_RTC_INT_STT_RFKILL); set_bit(STATUS_RFKILL, &trans_pcie->status); if (test_and_clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 826c15602c46..96cfcdd39079 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -670,6 +670,11 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) return err; } + /* Reset the entire device */ + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + usleep_range(10, 15); + iwl_pcie_apm_init(trans); /* From now on, the op_mode will be kept updated about RF kill state */ diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index ef5fa890a286..89459db4c53b 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1716,9 +1716,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int ret; - if (priv->bss_mode != NL80211_IFTYPE_STATION) { + if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) { wiphy_err(wiphy, - "%s: reject infra assoc request in non-STA mode\n", + "%s: reject infra assoc request in non-STA role\n", dev->name); return -EINVAL; } diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index 988552dece75..5178c4630d89 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -415,7 +415,8 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) u32 k = 0; struct mwifiex_adapter *adapter = priv->adapter; - if (priv->bss_mode == NL80211_IFTYPE_STATION) { + if (priv->bss_mode == NL80211_IFTYPE_STATION || + priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) { switch (adapter->config_bands) { case BAND_B: dev_dbg(adapter->dev, "info: infra band=%d " diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index caaf4bd56b30..2cf8b964e966 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -693,7 +693,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, if (!ret) { dev_notice(adapter->dev, "WLAN FW already running! Skip FW dnld\n"); - goto done; + return 0; } poll_num = MAX_FIRMWARE_POLL_TRIES; @@ -719,14 +719,8 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, poll_fw: /* Check if the firmware is downloaded successfully or not */ ret = adapter->if_ops.check_fw_status(adapter, poll_num); - if (ret) { + if (ret) dev_err(adapter->dev, "FW failed to be active in time\n"); - return -1; - } -done: - /* re-enable host interrupt for mwifiex after fw dnld is successful */ - if (adapter->if_ops.enable_int) - adapter->if_ops.enable_int(adapter); return ret; } diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 1c8a771e8e81..12e778159ec5 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -1291,8 +1291,10 @@ int mwifiex_associate(struct mwifiex_private *priv, { u8 current_bssid[ETH_ALEN]; - /* Return error if the adapter or table entry is not marked as infra */ - if ((priv->bss_mode != NL80211_IFTYPE_STATION) || + /* Return error if the adapter is not STA role or table entry + * is not marked as infra. + */ + if ((GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) || (bss_desc->bss_mode != NL80211_IFTYPE_STATION)) return -1; diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index e15ab72fb03d..1753431de361 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -427,6 +427,10 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) "Cal data request_firmware() failed\n"); } + /* enable host interrupt after fw dnld is successful */ + if (adapter->if_ops.enable_int) + adapter->if_ops.enable_int(adapter); + adapter->init_wait_q_woken = false; ret = mwifiex_init_fw(adapter); if (ret == -1) { @@ -478,6 +482,8 @@ err_add_intf: mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev); rtnl_unlock(); err_init_fw: + if (adapter->if_ops.disable_int) + adapter->if_ops.disable_int(adapter); pr_debug("info: %s: unregister device\n", __func__); adapter->if_ops.unregister_dev(adapter); done: @@ -855,7 +861,7 @@ mwifiex_add_card(void *card, struct semaphore *sem, INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); /* Register the device. Fill up the private data structure with relevant - information from the card and request for the required IRQ. */ + information from the card. */ if (adapter->if_ops.register_dev(adapter)) { pr_err("%s: failed to register mwifiex device\n", __func__); goto err_registerdev; @@ -919,6 +925,11 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) if (!adapter) goto exit_remove; + /* We can no longer handle interrupts once we start doing the teardown + * below. */ + if (adapter->if_ops.disable_int) + adapter->if_ops.disable_int(adapter); + adapter->surprise_removed = true; /* Stop data */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 3da73d36acdf..253e0bd38e25 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -601,6 +601,7 @@ struct mwifiex_if_ops { int (*register_dev) (struct mwifiex_adapter *); void (*unregister_dev) (struct mwifiex_adapter *); int (*enable_int) (struct mwifiex_adapter *); + void (*disable_int) (struct mwifiex_adapter *); int (*process_int_status) (struct mwifiex_adapter *); int (*host_to_card) (struct mwifiex_adapter *, u8, struct sk_buff *, struct mwifiex_tx_param *); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 5ee5ed02eccd..09185c963248 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -51,6 +51,7 @@ static struct mwifiex_if_ops sdio_ops; static struct semaphore add_remove_card_sem; static int mwifiex_sdio_resume(struct device *dev); +static void mwifiex_sdio_interrupt(struct sdio_func *func); /* * SDIO probe. @@ -296,6 +297,15 @@ static struct sdio_driver mwifiex_sdio = { } }; +/* Write data into SDIO card register. Caller claims SDIO device. */ +static int +mwifiex_write_reg_locked(struct sdio_func *func, u32 reg, u8 data) +{ + int ret = -1; + sdio_writeb(func, data, reg, &ret); + return ret; +} + /* * This function writes data into SDIO card register. */ @@ -303,10 +313,10 @@ static int mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u8 data) { struct sdio_mmc_card *card = adapter->card; - int ret = -1; + int ret; sdio_claim_host(card->func); - sdio_writeb(card->func, data, reg, &ret); + ret = mwifiex_write_reg_locked(card->func, reg, data); sdio_release_host(card->func); return ret; @@ -685,23 +695,15 @@ mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) * The host interrupt mask is read, the disable bit is reset and * written back to the card host interrupt mask register. */ -static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) +static void mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) { - u8 host_int_mask, host_int_disable = HOST_INT_DISABLE; - - /* Read back the host_int_mask register */ - if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask)) - return -1; - - /* Update with the mask and write back to the register */ - host_int_mask &= ~host_int_disable; - - if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) { - dev_err(adapter->dev, "disable host interrupt failed\n"); - return -1; - } + struct sdio_mmc_card *card = adapter->card; + struct sdio_func *func = card->func; - return 0; + sdio_claim_host(func); + mwifiex_write_reg_locked(func, HOST_INT_MASK_REG, 0); + sdio_release_irq(func); + sdio_release_host(func); } /* @@ -713,14 +715,29 @@ static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; + struct sdio_func *func = card->func; + int ret; + + sdio_claim_host(func); + + /* Request the SDIO IRQ */ + ret = sdio_claim_irq(func, mwifiex_sdio_interrupt); + if (ret) { + dev_err(adapter->dev, "claim irq failed: ret=%d\n", ret); + goto out; + } /* Simply write the mask to the register */ - if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, - card->reg->host_int_enable)) { + ret = mwifiex_write_reg_locked(func, HOST_INT_MASK_REG, + card->reg->host_int_enable); + if (ret) { dev_err(adapter->dev, "enable host interrupt failed\n"); - return -1; + sdio_release_irq(func); } - return 0; + +out: + sdio_release_host(func); + return ret; } /* @@ -997,9 +1014,6 @@ mwifiex_sdio_interrupt(struct sdio_func *func) } adapter = card->adapter; - if (adapter->surprise_removed) - return; - if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP) adapter->ps_state = PS_STATE_AWAKE; @@ -1625,8 +1639,8 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, /* Allocate buffer and copy payload */ blk_size = MWIFIEX_SDIO_BLOCK_SIZE; buf_block_len = (pkt_len + blk_size - 1) / blk_size; - *(u16 *) &payload[0] = (u16) pkt_len; - *(u16 *) &payload[2] = type; + *(__le16 *)&payload[0] = cpu_to_le16((u16)pkt_len); + *(__le16 *)&payload[2] = cpu_to_le16(type); /* * This is SDIO specific header @@ -1728,9 +1742,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter) struct sdio_mmc_card *card = adapter->card; if (adapter->card) { - /* Release the SDIO IRQ */ sdio_claim_host(card->func); - sdio_release_irq(card->func); sdio_disable_func(card->func); sdio_release_host(card->func); sdio_set_drvdata(card->func, NULL); @@ -1744,7 +1756,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter) */ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) { - int ret = 0; + int ret; struct sdio_mmc_card *card = adapter->card; struct sdio_func *func = card->func; @@ -1753,22 +1765,14 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) sdio_claim_host(func); - /* Request the SDIO IRQ */ - ret = sdio_claim_irq(func, mwifiex_sdio_interrupt); - if (ret) { - pr_err("claim irq failed: ret=%d\n", ret); - goto disable_func; - } - /* Set block size */ ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE); + sdio_release_host(func); if (ret) { pr_err("cannot set SDIO block size\n"); - ret = -1; - goto release_irq; + return ret; } - sdio_release_host(func); sdio_set_drvdata(func, card); adapter->dev = &func->dev; @@ -1776,15 +1780,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) strcpy(adapter->fw_name, card->firmware); return 0; - -release_irq: - sdio_release_irq(func); -disable_func: - sdio_disable_func(func); - sdio_release_host(func); - adapter->card = NULL; - - return -1; } /* @@ -1813,9 +1808,6 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) */ mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg); - /* Disable host interrupt mask register for SDIO */ - mwifiex_sdio_disable_host_int(adapter); - /* Get SDIO ioport */ mwifiex_init_sdio_ioport(adapter); @@ -1957,6 +1949,7 @@ static struct mwifiex_if_ops sdio_ops = { .register_dev = mwifiex_register_dev, .unregister_dev = mwifiex_unregister_dev, .enable_int = mwifiex_sdio_enable_host_int, + .disable_int = mwifiex_sdio_disable_host_int, .process_int_status = mwifiex_process_int_status, .host_to_card = mwifiex_sdio_host_to_card, .wakeup = mwifiex_pm_wakeup_card, diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 6d51dfdd8251..532ae0ac4dfb 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -92,9 +92,6 @@ /* Host Control Registers : Download host interrupt mask */ #define DN_LD_HOST_INT_MASK (0x2U) -/* Disable Host interrupt mask */ -#define HOST_INT_DISABLE 0xff - /* Host Control Registers : Host interrupt status */ #define HOST_INTSTATUS_REG 0x03 /* Host Control Registers : Upload host interrupt status */ diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 206c3e038072..8af97abf7108 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -257,10 +257,10 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, goto done; } - if (priv->bss_mode == NL80211_IFTYPE_STATION) { + if (priv->bss_mode == NL80211_IFTYPE_STATION || + priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) { u8 config_bands; - /* Infra mode */ ret = mwifiex_deauthenticate(priv, NULL); if (ret) goto done; diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 9b915d3a44be..3e60a31582f8 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -1,6 +1,6 @@ menuconfig RT2X00 tristate "Ralink driver support" - depends on MAC80211 + depends on MAC80211 && HAS_DMA ---help--- This will enable the support for the Ralink drivers, developed in the rt2x00 project <http://rt2x00.serialmonkey.com>. diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 6c0a91ff963c..aa95c6cf3545 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -936,13 +936,8 @@ void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index) spin_unlock_irqrestore(&queue->index_lock, irqflags); } -void rt2x00queue_pause_queue(struct data_queue *queue) +void rt2x00queue_pause_queue_nocheck(struct data_queue *queue) { - if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) || - !test_bit(QUEUE_STARTED, &queue->flags) || - test_and_set_bit(QUEUE_PAUSED, &queue->flags)) - return; - switch (queue->qid) { case QID_AC_VO: case QID_AC_VI: @@ -958,6 +953,15 @@ void rt2x00queue_pause_queue(struct data_queue *queue) break; } } +void rt2x00queue_pause_queue(struct data_queue *queue) +{ + if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) || + !test_bit(QUEUE_STARTED, &queue->flags) || + test_and_set_bit(QUEUE_PAUSED, &queue->flags)) + return; + + rt2x00queue_pause_queue_nocheck(queue); +} EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue); void rt2x00queue_unpause_queue(struct data_queue *queue) @@ -1019,7 +1023,7 @@ void rt2x00queue_stop_queue(struct data_queue *queue) return; } - rt2x00queue_pause_queue(queue); + rt2x00queue_pause_queue_nocheck(queue); queue->rt2x00dev->ops->lib->stop_queue(queue); diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig index 7253de3d8c66..c2ffce7a907c 100644 --- a/drivers/net/wireless/rtlwifi/Kconfig +++ b/drivers/net/wireless/rtlwifi/Kconfig @@ -1,27 +1,20 @@ -config RTLWIFI - tristate "Realtek wireless card support" - depends on MAC80211 - select FW_LOADER - ---help--- - This is common code for RTL8192CE/RTL8192CU/RTL8192SE/RTL8723AE - drivers. This module does nothing by itself - the various front-end - drivers need to be enabled to support any desired devices. - - If you choose to build as a module, it'll be called rtlwifi. - -config RTLWIFI_DEBUG - bool "Debugging output for rtlwifi driver family" - depends on RTLWIFI +menuconfig RTL_CARDS + tristate "Realtek rtlwifi family of devices" + depends on MAC80211 && (PCI || USB) default y ---help--- - To use the module option that sets the dynamic-debugging level for, - the front-end driver, this parameter must be "Y". For memory-limited - systems, choose "N". If in doubt, choose "Y". + This option will enable support for the Realtek mac80211-based + wireless drivers. Drivers rtl8192ce, rtl8192cu, rtl8192se, rtl8192de, + rtl8723eu, and rtl8188eu share some common code. + +if RTL_CARDS config RTL8192CE tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter" - depends on RTLWIFI && PCI + depends on PCI select RTL8192C_COMMON + select RTLWIFI + select RTLWIFI_PCI ---help--- This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe wireless network adapters. @@ -30,7 +23,9 @@ config RTL8192CE config RTL8192SE tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter" - depends on RTLWIFI && PCI + depends on PCI + select RTLWIFI + select RTLWIFI_PCI ---help--- This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe wireless network adapters. @@ -39,7 +34,9 @@ config RTL8192SE config RTL8192DE tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter" - depends on RTLWIFI && PCI + depends on PCI + select RTLWIFI + select RTLWIFI_PCI ---help--- This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe wireless network adapters. @@ -48,7 +45,9 @@ config RTL8192DE config RTL8723AE tristate "Realtek RTL8723AE PCIe Wireless Network Adapter" - depends on RTLWIFI && PCI + depends on PCI + select RTLWIFI + select RTLWIFI_PCI ---help--- This is the driver for Realtek RTL8723AE 802.11n PCIe wireless network adapters. @@ -57,7 +56,9 @@ config RTL8723AE config RTL8188EE tristate "Realtek RTL8188EE Wireless Network Adapter" - depends on RTLWIFI && PCI + depends on PCI + select RTLWIFI + select RTLWIFI_PCI ---help--- This is the driver for Realtek RTL8188EE 802.11n PCIe wireless network adapters. @@ -66,7 +67,9 @@ config RTL8188EE config RTL8192CU tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter" - depends on RTLWIFI && USB + depends on USB + select RTLWIFI + select RTLWIFI_USB select RTL8192C_COMMON ---help--- This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB @@ -74,7 +77,28 @@ config RTL8192CU If you choose to build it as a module, it will be called rtl8192cu +config RTLWIFI + tristate + select FW_LOADER + +config RTLWIFI_PCI + tristate + +config RTLWIFI_USB + tristate + +config RTLWIFI_DEBUG + bool "Debugging output for rtlwifi driver family" + depends on RTLWIFI + default y + ---help--- + To use the module option that sets the dynamic-debugging level for, + the front-end driver, this parameter must be "Y". For memory-limited + systems, choose "N". If in doubt, choose "Y". + config RTL8192C_COMMON tristate depends on RTL8192CE || RTL8192CU - default m + default y + +endif diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile index ff02b874f8d8..d56f023a4b90 100644 --- a/drivers/net/wireless/rtlwifi/Makefile +++ b/drivers/net/wireless/rtlwifi/Makefile @@ -12,13 +12,11 @@ rtlwifi-objs := \ rtl8192c_common-objs += \ -ifneq ($(CONFIG_PCI),) -rtlwifi-objs += pci.o -endif +obj-$(CONFIG_RTLWIFI_PCI) += rtl_pci.o +rtl_pci-objs := pci.o -ifneq ($(CONFIG_USB),) -rtlwifi-objs += usb.o -endif +obj-$(CONFIG_RTLWIFI_USB) += rtl_usb.o +rtl_usb-objs := usb.o obj-$(CONFIG_RTL8192C_COMMON) += rtl8192c/ obj-$(CONFIG_RTL8192CE) += rtl8192ce/ diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 9d558ac77b0c..7651f5acc14b 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -172,6 +172,7 @@ u8 rtl_tid_to_ac(u8 tid) { return tid_to_ac[tid]; } +EXPORT_SYMBOL_GPL(rtl_tid_to_ac); static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, struct ieee80211_sta_ht_cap *ht_cap) @@ -406,6 +407,7 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw) cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); cancel_delayed_work(&rtlpriv->works.fwevt_wq); } +EXPORT_SYMBOL_GPL(rtl_deinit_deferred_work); void rtl_init_rfkill(struct ieee80211_hw *hw) { @@ -439,6 +441,7 @@ void rtl_deinit_rfkill(struct ieee80211_hw *hw) { wiphy_rfkill_stop_polling(hw->wiphy); } +EXPORT_SYMBOL_GPL(rtl_deinit_rfkill); int rtl_init_core(struct ieee80211_hw *hw) { @@ -489,10 +492,12 @@ int rtl_init_core(struct ieee80211_hw *hw) return 0; } +EXPORT_SYMBOL_GPL(rtl_init_core); void rtl_deinit_core(struct ieee80211_hw *hw) { } +EXPORT_SYMBOL_GPL(rtl_deinit_core); void rtl_init_rx_config(struct ieee80211_hw *hw) { @@ -501,6 +506,7 @@ void rtl_init_rx_config(struct ieee80211_hw *hw) rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf)); } +EXPORT_SYMBOL_GPL(rtl_init_rx_config); /********************************************************* * @@ -879,6 +885,7 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) return true; } +EXPORT_SYMBOL_GPL(rtl_tx_mgmt_proc); void rtl_get_tcb_desc(struct ieee80211_hw *hw, struct ieee80211_tx_info *info, @@ -1052,6 +1059,7 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) return true; } +EXPORT_SYMBOL_GPL(rtl_action_proc); /*should call before software enc*/ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) @@ -1125,6 +1133,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) return false; } +EXPORT_SYMBOL_GPL(rtl_is_special_data); /********************************************************* * @@ -1300,6 +1309,7 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb) rtlpriv->link_info.bcn_rx_inperiod++; } +EXPORT_SYMBOL_GPL(rtl_beacon_statistic); void rtl_watchdog_wq_callback(void *data) { @@ -1793,6 +1803,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len) mac->vendor = vendor; } +EXPORT_SYMBOL_GPL(rtl_recognize_peer); /********************************************************* * @@ -1849,6 +1860,7 @@ struct attribute_group rtl_attribute_group = { .name = "rtlsysfs", .attrs = rtl_sysfs_entries, }; +EXPORT_SYMBOL_GPL(rtl_attribute_group); MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); @@ -1856,7 +1868,8 @@ MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core"); -struct rtl_global_var global_var = {}; +struct rtl_global_var rtl_global_var = {}; +EXPORT_SYMBOL_GPL(rtl_global_var); static int __init rtl_core_module_init(void) { @@ -1864,8 +1877,8 @@ static int __init rtl_core_module_init(void) pr_err("Unable to register rtl_rc, use default RC !!\n"); /* init some global vars */ - INIT_LIST_HEAD(&global_var.glb_priv_list); - spin_lock_init(&global_var.glb_list_lock); + INIT_LIST_HEAD(&rtl_global_var.glb_priv_list); + spin_lock_init(&rtl_global_var.glb_list_lock); return 0; } diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h index 8576bc34b032..0e5fe0902daf 100644 --- a/drivers/net/wireless/rtlwifi/base.h +++ b/drivers/net/wireless/rtlwifi/base.h @@ -147,7 +147,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len); u8 rtl_tid_to_ac(u8 tid); extern struct attribute_group rtl_attribute_group; void rtl_easy_concurrent_retrytimer_callback(unsigned long data); -extern struct rtl_global_var global_var; +extern struct rtl_global_var rtl_global_var; int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, u8 desc_rate, bool first_ampdu); bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index ee84844be008..733b7ce7f0e2 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -1330,3 +1330,4 @@ const struct ieee80211_ops rtl_ops = { .rfkill_poll = rtl_op_rfkill_poll, .flush = rtl_op_flush, }; +EXPORT_SYMBOL_GPL(rtl_ops); diff --git a/drivers/net/wireless/rtlwifi/debug.c b/drivers/net/wireless/rtlwifi/debug.c index 7d52d3d7769f..76e2086e137e 100644 --- a/drivers/net/wireless/rtlwifi/debug.c +++ b/drivers/net/wireless/rtlwifi/debug.c @@ -51,3 +51,4 @@ void rtl_dbgp_flag_init(struct ieee80211_hw *hw) /*Init Debug flag enable condition */ } +EXPORT_SYMBOL_GPL(rtl_dbgp_flag_init); diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 9e3894178e77..838a1ed3f194 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -229,6 +229,7 @@ void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) *pbuf = (u8) (value32 & 0xff); } +EXPORT_SYMBOL_GPL(read_efuse_byte); void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) { diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index c97e9d327331..703f839af6ca 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -35,6 +35,13 @@ #include "efuse.h" #include <linux/export.h> #include <linux/kmemleak.h> +#include <linux/module.h> + +MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); +MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("PCI basic driver for rtlwifi"); static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { PCI_VENDOR_ID_INTEL, @@ -1008,19 +1015,6 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) return; } -static void rtl_lps_change_work_callback(struct work_struct *work) -{ - struct rtl_works *rtlworks = - container_of(work, struct rtl_works, lps_change_work); - struct ieee80211_hw *hw = rtlworks->hw; - struct rtl_priv *rtlpriv = rtl_priv(hw); - - if (rtlpriv->enter_ps) - rtl_lps_enter(hw); - else - rtl_lps_leave(hw); -} - static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); @@ -1899,7 +1893,7 @@ int rtl_pci_probe(struct pci_dev *pdev, rtlpriv->rtlhal.interface = INTF_PCI; rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); rtlpriv->intf_ops = &rtl_pci_ops; - rtlpriv->glb_var = &global_var; + rtlpriv->glb_var = &rtl_global_var; /* *init dbgp flags before all diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index 884bceae38a9..298b615964e8 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -269,6 +269,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw) spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags); } +EXPORT_SYMBOL_GPL(rtl_ips_nic_on); /*for FW LPS*/ @@ -518,6 +519,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) "u_bufferd: %x, m_buffered: %x\n", u_buffed, m_buffed); } } +EXPORT_SYMBOL_GPL(rtl_swlps_beacon); void rtl_swlps_rf_awake(struct ieee80211_hw *hw) { @@ -611,6 +613,19 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40)); } +void rtl_lps_change_work_callback(struct work_struct *work) +{ + struct rtl_works *rtlworks = + container_of(work, struct rtl_works, lps_change_work); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->enter_ps) + rtl_lps_enter(hw); + else + rtl_lps_leave(hw); +} +EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback); void rtl_swlps_wq_callback(void *data) { @@ -922,3 +937,4 @@ void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len) else rtl_p2p_noa_ie(hw, data, len - FCS_LEN); } +EXPORT_SYMBOL_GPL(rtl_p2p_info); diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h index 4d682b753f50..88bd76ea88f7 100644 --- a/drivers/net/wireless/rtlwifi/ps.h +++ b/drivers/net/wireless/rtlwifi/ps.h @@ -49,5 +49,6 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw); void rtl_swlps_rf_sleep(struct ieee80211_hw *hw); void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state); void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len); +void rtl_lps_change_work_callback(struct work_struct *work); #endif diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index a3532e077871..e56778cac9bf 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -32,6 +32,13 @@ #include "ps.h" #include "rtl8192c/fw_common.h" #include <linux/export.h> +#include <linux/module.h> + +MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); +MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("USB basic driver for rtlwifi"); #define REALTEK_USB_VENQT_READ 0xC0 #define REALTEK_USB_VENQT_WRITE 0x40 @@ -1070,6 +1077,8 @@ int rtl_usb_probe(struct usb_interface *intf, spin_lock_init(&rtlpriv->locks.usb_lock); INIT_WORK(&rtlpriv->works.fill_h2c_cmd, rtl_fill_h2c_cmd_work_callback); + INIT_WORK(&rtlpriv->works.lps_change_work, + rtl_lps_change_work_callback); rtlpriv->usb_data_index = 0; init_completion(&rtlpriv->firmware_loading_complete); |