diff options
Diffstat (limited to 'drivers/net')
86 files changed, 895 insertions, 1519 deletions
| diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 184c434ae305..0dceba1a2ba1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1648,7 +1648,7 @@ static int __bond_release_one(struct net_device *bond_dev,  	/* slave is not a slave or master is not master of this slave */  	if (!(slave_dev->flags & IFF_SLAVE) ||  	    !netdev_has_upper_dev(slave_dev, bond_dev)) { -		netdev_err(bond_dev, "cannot release %s\n", +		netdev_dbg(bond_dev, "cannot release %s\n",  			   slave_dev->name);  		return -EINVAL;  	} diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c index a5fefb9059c5..b306210b02b7 100644 --- a/drivers/net/caif/caif_virtio.c +++ b/drivers/net/caif/caif_virtio.c @@ -257,7 +257,6 @@ static int cfv_rx_poll(struct napi_struct *napi, int quota)  	struct vringh_kiov *riov = &cfv->ctx.riov;  	unsigned int skb_len; -again:  	do {  		skb = NULL; @@ -322,7 +321,6 @@ exit:  		    napi_schedule_prep(napi)) {  			vringh_notify_disable_kern(cfv->vr_rx);  			__napi_schedule(napi); -			goto again;  		}  		break; diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index f363972cd77d..e36d10520e24 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -103,27 +103,34 @@ static void c_can_hw_raminit_syscon(const struct c_can_priv *priv, bool enable)  	mask = 1 << raminit->bits.start | 1 << raminit->bits.done;  	regmap_read(raminit->syscon, raminit->reg, &ctrl); -	/* We clear the done and start bit first. The start bit is +	/* We clear the start bit first. The start bit is  	 * looking at the 0 -> transition, but is not self clearing; -	 * And we clear the init done bit as well.  	 * NOTE: DONE must be written with 1 to clear it. +	 * We can't clear the DONE bit here using regmap_update_bits() +	 * as it will bypass the write if initial condition is START:0 DONE:1 +	 * e.g. on DRA7 which needs START pulse.  	 */ -	ctrl &= ~(1 << raminit->bits.start); -	ctrl |= 1 << raminit->bits.done; -	regmap_write(raminit->syscon, raminit->reg, ctrl); +	ctrl &= ~mask;	/* START = 0, DONE = 0 */ +	regmap_update_bits(raminit->syscon, raminit->reg, mask, ctrl); -	ctrl &= ~(1 << raminit->bits.done); -	c_can_hw_raminit_wait_syscon(priv, mask, ctrl); +	/* check if START bit is 0. Ignore DONE bit for now +	 * as it can be either 0 or 1. +	 */ +	c_can_hw_raminit_wait_syscon(priv, 1 << raminit->bits.start, ctrl);  	if (enable) { -		/* Set start bit and wait for the done bit. */ +		/* Clear DONE bit & set START bit. */  		ctrl |= 1 << raminit->bits.start; -		regmap_write(raminit->syscon, raminit->reg, ctrl); - +		/* DONE must be written with 1 to clear it */ +		ctrl |= 1 << raminit->bits.done; +		regmap_update_bits(raminit->syscon, raminit->reg, mask, ctrl); +		/* prevent further clearing of DONE bit */ +		ctrl &= ~(1 << raminit->bits.done);  		/* clear START bit if start pulse is needed */  		if (raminit->needs_pulse) {  			ctrl &= ~(1 << raminit->bits.start); -			regmap_write(raminit->syscon, raminit->reg, ctrl); +			regmap_update_bits(raminit->syscon, raminit->reg, +					   mask, ctrl);  		}  		ctrl |= 1 << raminit->bits.done; diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 3ec8f6f25e5f..847c1f813261 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -807,10 +807,14 @@ static int can_changelink(struct net_device *dev,  		if (dev->flags & IFF_UP)  			return -EBUSY;  		cm = nla_data(data[IFLA_CAN_CTRLMODE]); -		if (cm->flags & ~priv->ctrlmode_supported) + +		/* check whether changed bits are allowed to be modified */ +		if (cm->mask & ~priv->ctrlmode_supported)  			return -EOPNOTSUPP; + +		/* clear bits to be modified and copy the flag values */  		priv->ctrlmode &= ~cm->mask; -		priv->ctrlmode |= cm->flags; +		priv->ctrlmode |= (cm->flags & cm->mask);  		/* CAN_CTRLMODE_FD can only be set when driver supports FD */  		if (priv->ctrlmode & CAN_CTRLMODE_FD) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index d7bc462aafdc..244529881be9 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -955,6 +955,11 @@ static struct net_device *alloc_m_can_dev(void)  	priv->can.data_bittiming_const = &m_can_data_bittiming_const;  	priv->can.do_set_mode = m_can_set_mode;  	priv->can.do_get_berr_counter = m_can_get_berr_counter; + +	/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.1 */ +	priv->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO; + +	/* CAN_CTRLMODE_FD_NON_ISO can not be changed with M_CAN IP v3.0.1 */  	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |  					CAN_CTRLMODE_LISTENONLY |  					CAN_CTRLMODE_BERR_REPORTING | diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 541fb7a05625..c32cd61073bc 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -520,10 +520,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,  		skb = alloc_can_err_skb(priv->netdev, &cf);  		if (skb) {  			cf->can_id |= CAN_ERR_RESTARTED; -			netif_rx(skb);  			stats->rx_packets++;  			stats->rx_bytes += cf->can_dlc; +			netif_rx(skb);  		} else {  			netdev_err(priv->netdev,  				   "No memory left for err_skb\n"); @@ -770,10 +770,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,  	priv->can.state = new_state; -	netif_rx(skb); -  	stats->rx_packets++;  	stats->rx_bytes += cf->can_dlc; +	netif_rx(skb);  }  static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, @@ -805,10 +804,9 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,  		stats->rx_over_errors++;  		stats->rx_errors++; -		netif_rx(skb); -  		stats->rx_packets++;  		stats->rx_bytes += cf->can_dlc; +		netif_rx(skb);  	}  } @@ -887,10 +885,9 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,  			       cf->can_dlc);  	} -	netif_rx(skb); -  	stats->rx_packets++;  	stats->rx_bytes += cf->can_dlc; +	netif_rx(skb);  }  static void kvaser_usb_start_chip_reply(const struct kvaser_usb *dev, @@ -1246,6 +1243,9 @@ static int kvaser_usb_close(struct net_device *netdev)  	if (err)  		netdev_warn(netdev, "Cannot stop device, error %d\n", err); +	/* reset tx contexts */ +	kvaser_usb_unlink_tx_urbs(priv); +  	priv->can.state = CAN_STATE_STOPPED;  	close_candev(priv->netdev); @@ -1294,12 +1294,14 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,  	if (!urb) {  		netdev_err(netdev, "No memory left for URBs\n");  		stats->tx_dropped++; -		goto nourbmem; +		dev_kfree_skb(skb); +		return NETDEV_TX_OK;  	}  	buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);  	if (!buf) {  		stats->tx_dropped++; +		dev_kfree_skb(skb);  		goto nobufmem;  	} @@ -1334,6 +1336,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,  		}  	} +	/* This should never happen; it implies a flow control bug */  	if (!context) {  		netdev_warn(netdev, "cannot find free context\n");  		ret =  NETDEV_TX_BUSY; @@ -1364,9 +1367,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,  	if (unlikely(err)) {  		can_free_echo_skb(netdev, context->echo_index); -		skb = NULL; /* set to NULL to avoid double free in -			     * dev_kfree_skb(skb) */ -  		atomic_dec(&priv->active_tx_urbs);  		usb_unanchor_urb(urb); @@ -1388,8 +1388,6 @@ releasebuf:  	kfree(buf);  nobufmem:  	usb_free_urb(urb); -nourbmem: -	dev_kfree_skb(skb);  	return ret;  } @@ -1502,6 +1500,10 @@ static int kvaser_usb_init_one(struct usb_interface *intf,  	struct kvaser_usb_net_priv *priv;  	int i, err; +	err = kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, channel); +	if (err) +		return err; +  	netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);  	if (!netdev) {  		dev_err(&intf->dev, "Cannot alloc candev\n"); @@ -1606,9 +1608,6 @@ static int kvaser_usb_probe(struct usb_interface *intf,  	usb_set_intfdata(intf, dev); -	for (i = 0; i < MAX_NET_DEVICES; i++) -		kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i); -  	err = kvaser_usb_get_software_info(dev);  	if (err) {  		dev_err(&intf->dev, diff --git a/drivers/net/ethernet/8390/ne2k-pci.c b/drivers/net/ethernet/8390/ne2k-pci.c index 89c8d9fc97de..57e97910c728 100644 --- a/drivers/net/ethernet/8390/ne2k-pci.c +++ b/drivers/net/ethernet/8390/ne2k-pci.c @@ -246,13 +246,13 @@ static int ne2k_pci_init_one(struct pci_dev *pdev,  	if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {  		dev_err(&pdev->dev, "no I/O resource at PCI BAR #0\n"); -		return -ENODEV; +		goto err_out;  	}  	if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) {  		dev_err(&pdev->dev, "I/O resource 0x%x @ 0x%lx busy\n",  			NE_IO_EXTENT, ioaddr); -		return -EBUSY; +		goto err_out;  	}  	reg0 = inb(ioaddr); @@ -392,6 +392,8 @@ err_out_free_netdev:  	free_netdev (dev);  err_out_free_res:  	release_region (ioaddr, NE_IO_EXTENT); +err_out: +	pci_disable_device(pdev);  	return -ENODEV;  } diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index df76050d0a9d..eadcb053807e 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -156,18 +156,6 @@ source "drivers/net/ethernet/realtek/Kconfig"  source "drivers/net/ethernet/renesas/Kconfig"  source "drivers/net/ethernet/rdc/Kconfig"  source "drivers/net/ethernet/rocker/Kconfig" - -config S6GMAC -	tristate "S6105 GMAC ethernet support" -	depends on XTENSA_VARIANT_S6000 -	select PHYLIB -	---help--- -	  This driver supports the on chip ethernet device on the -	  S6105 xtensa processor. - -	  To compile this driver as a module, choose M here. The module -	  will be called s6gmac. -  source "drivers/net/ethernet/samsung/Kconfig"  source "drivers/net/ethernet/seeq/Kconfig"  source "drivers/net/ethernet/silan/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index bf56f8b36e90..1367afcd0a8b 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -66,7 +66,6 @@ obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/  obj-$(CONFIG_SH_ETH) += renesas/  obj-$(CONFIG_NET_VENDOR_RDC) += rdc/  obj-$(CONFIG_NET_VENDOR_ROCKER) += rocker/ -obj-$(CONFIG_S6GMAC) += s6gmac.o  obj-$(CONFIG_NET_VENDOR_SAMSUNG) += samsung/  obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/  obj-$(CONFIG_NET_VENDOR_SILAN) += silan/ diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c index 1fcd5568a352..f3470d96837a 100644 --- a/drivers/net/ethernet/allwinner/sun4i-emac.c +++ b/drivers/net/ethernet/allwinner/sun4i-emac.c @@ -850,8 +850,10 @@ static int emac_probe(struct platform_device *pdev)  	}  	db->clk = devm_clk_get(&pdev->dev, NULL); -	if (IS_ERR(db->clk)) +	if (IS_ERR(db->clk)) { +		ret = PTR_ERR(db->clk);  		goto out; +	}  	clk_prepare_enable(db->clk); diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index 3498760dc22a..760c72c6e2ac 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -1170,10 +1170,6 @@ tx_request_irq_error:  init_error:  	free_skbufs(dev);  alloc_skbuf_error: -	if (priv->phydev) { -		phy_disconnect(priv->phydev); -		priv->phydev = NULL; -	}  phy_error:  	return ret;  } @@ -1186,12 +1182,9 @@ static int tse_shutdown(struct net_device *dev)  	int ret;  	unsigned long int flags; -	/* Stop and disconnect the PHY */ -	if (priv->phydev) { +	/* Stop the PHY */ +	if (priv->phydev)  		phy_stop(priv->phydev); -		phy_disconnect(priv->phydev); -		priv->phydev = NULL; -	}  	netif_stop_queue(dev);  	napi_disable(&priv->napi); @@ -1525,6 +1518,10 @@ err_free_netdev:  static int altera_tse_remove(struct platform_device *pdev)  {  	struct net_device *ndev = platform_get_drvdata(pdev); +	struct altera_tse_private *priv = netdev_priv(ndev); + +	if (priv->phydev) +		phy_disconnect(priv->phydev);  	platform_set_drvdata(pdev, NULL);  	altera_tse_mdio_destroy(ndev); diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index e398eda07298..c8af3ce3ea38 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -184,15 +184,16 @@ static void alx_schedule_reset(struct alx_priv *alx)  	schedule_work(&alx->reset_wk);  } -static bool alx_clean_rx_irq(struct alx_priv *alx, int budget) +static int alx_clean_rx_irq(struct alx_priv *alx, int budget)  {  	struct alx_rx_queue *rxq = &alx->rxq;  	struct alx_rrd *rrd;  	struct alx_buffer *rxb;  	struct sk_buff *skb;  	u16 length, rfd_cleaned = 0; +	int work = 0; -	while (budget > 0) { +	while (work < budget) {  		rrd = &rxq->rrd[rxq->rrd_read_idx];  		if (!(rrd->word3 & cpu_to_le32(1 << RRD_UPDATED_SHIFT)))  			break; @@ -203,7 +204,7 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget)  		    ALX_GET_FIELD(le32_to_cpu(rrd->word0),  				  RRD_NOR) != 1) {  			alx_schedule_reset(alx); -			return 0; +			return work;  		}  		rxb = &rxq->bufs[rxq->read_idx]; @@ -243,7 +244,7 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget)  		}  		napi_gro_receive(&alx->napi, skb); -		budget--; +		work++;  next_pkt:  		if (++rxq->read_idx == alx->rx_ringsz) @@ -258,21 +259,22 @@ next_pkt:  	if (rfd_cleaned)  		alx_refill_rx_ring(alx, GFP_ATOMIC); -	return budget > 0; +	return work;  }  static int alx_poll(struct napi_struct *napi, int budget)  {  	struct alx_priv *alx = container_of(napi, struct alx_priv, napi);  	struct alx_hw *hw = &alx->hw; -	bool complete = true;  	unsigned long flags; +	bool tx_complete; +	int work; -	complete = alx_clean_tx_irq(alx) && -		   alx_clean_rx_irq(alx, budget); +	tx_complete = alx_clean_tx_irq(alx); +	work = alx_clean_rx_irq(alx, budget); -	if (!complete) -		return 1; +	if (!tx_complete || work == budget) +		return budget;  	napi_complete(&alx->napi); @@ -284,7 +286,7 @@ static int alx_poll(struct napi_struct *napi, int budget)  	alx_post_write(hw); -	return 0; +	return work;  }  static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 05c6af6c418f..3007d95fbb9f 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1167,10 +1167,10 @@ static int bgmac_poll(struct napi_struct *napi, int weight)  		bgmac->int_status = 0;  	} -	if (handled < weight) +	if (handled < weight) {  		napi_complete(napi); - -	bgmac_chip_intrs_on(bgmac); +		bgmac_chip_intrs_on(bgmac); +	}  	return handled;  } @@ -1515,6 +1515,8 @@ static int bgmac_probe(struct bcma_device *core)  	if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)  		bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n"); +	netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT); +  	err = bgmac_mii_register(bgmac);  	if (err) {  		bgmac_err(bgmac, "Cannot register MDIO\n"); @@ -1529,8 +1531,6 @@ static int bgmac_probe(struct bcma_device *core)  	netif_carrier_off(net_dev); -	netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT); -  	return 0;  err_mii_unregister: @@ -1549,9 +1549,9 @@ static void bgmac_remove(struct bcma_device *core)  {  	struct bgmac *bgmac = bcma_get_drvdata(core); -	netif_napi_del(&bgmac->napi);  	unregister_netdev(bgmac->net_dev);  	bgmac_mii_unregister(bgmac); +	netif_napi_del(&bgmac->napi);  	bgmac_dma_free(bgmac);  	bcma_set_drvdata(core, NULL);  	free_netdev(bgmac->net_dev); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 9f5e38769a29..72eef9fc883e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -12553,9 +12553,11 @@ static int bnx2x_get_phys_port_id(struct net_device *netdev,  	return 0;  } -static bool bnx2x_gso_check(struct sk_buff *skb, struct net_device *dev) +static netdev_features_t bnx2x_features_check(struct sk_buff *skb, +					      struct net_device *dev, +					      netdev_features_t features)  { -	return vxlan_gso_check(skb); +	return vxlan_features_check(skb, features);  }  static const struct net_device_ops bnx2x_netdev_ops = { @@ -12589,7 +12591,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {  #endif  	.ndo_get_phys_port_id	= bnx2x_get_phys_port_id,  	.ndo_set_vf_link_state	= bnx2x_set_vf_link_state, -	.ndo_gso_check		= bnx2x_gso_check, +	.ndo_features_check	= bnx2x_features_check,  };  static int bnx2x_set_coherency_mask(struct bnx2x *bp) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index bb48a610b72a..96bf01ba32dd 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -7413,6 +7413,8 @@ static inline void tg3_netif_start(struct tg3 *tp)  }  static void tg3_irq_quiesce(struct tg3 *tp) +	__releases(tp->lock) +	__acquires(tp->lock)  {  	int i; @@ -7421,8 +7423,12 @@ static void tg3_irq_quiesce(struct tg3 *tp)  	tp->irq_sync = 1;  	smp_mb(); +	spin_unlock_bh(&tp->lock); +  	for (i = 0; i < tp->irq_cnt; i++)  		synchronize_irq(tp->napi[i].irq_vec); + +	spin_lock_bh(&tp->lock);  }  /* Fully shutdown all tg3 driver activity elsewhere in the system. @@ -9018,6 +9024,8 @@ static void tg3_restore_clk(struct tg3 *tp)  /* tp->lock is held. */  static int tg3_chip_reset(struct tg3 *tp) +	__releases(tp->lock) +	__acquires(tp->lock)  {  	u32 val;  	void (*write_op)(struct tg3 *, u32, u32); @@ -9073,9 +9081,13 @@ static int tg3_chip_reset(struct tg3 *tp)  	}  	smp_mb(); +	tg3_full_unlock(tp); +  	for (i = 0; i < tp->irq_cnt; i++)  		synchronize_irq(tp->napi[i].irq_vec); +	tg3_full_lock(tp, 0); +  	if (tg3_asic_rev(tp) == ASIC_REV_57780) {  		val = tr32(TG3_PCIE_LNKCTL) & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN;  		tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS); @@ -10903,11 +10915,13 @@ static void tg3_timer(unsigned long __opaque)  {  	struct tg3 *tp = (struct tg3 *) __opaque; -	if (tp->irq_sync || tg3_flag(tp, RESET_TASK_PENDING)) -		goto restart_timer; -  	spin_lock(&tp->lock); +	if (tp->irq_sync || tg3_flag(tp, RESET_TASK_PENDING)) { +		spin_unlock(&tp->lock); +		goto restart_timer; +	} +  	if (tg3_asic_rev(tp) == ASIC_REV_5717 ||  	    tg3_flag(tp, 57765_CLASS))  		tg3_chk_missed_msi(tp); @@ -11101,11 +11115,13 @@ static void tg3_reset_task(struct work_struct *work)  	struct tg3 *tp = container_of(work, struct tg3, reset_task);  	int err; +	rtnl_lock();  	tg3_full_lock(tp, 0);  	if (!netif_running(tp->dev)) {  		tg3_flag_clear(tp, RESET_TASK_PENDING);  		tg3_full_unlock(tp); +		rtnl_unlock();  		return;  	} @@ -11138,6 +11154,7 @@ out:  		tg3_phy_start(tp);  	tg3_flag_clear(tp, RESET_TASK_PENDING); +	rtnl_unlock();  }  static int tg3_request_irq(struct tg3 *tp, int irq_num) @@ -17800,23 +17817,6 @@ static int tg3_init_one(struct pci_dev *pdev,  		goto err_out_apeunmap;  	} -	/* -	 * Reset chip in case UNDI or EFI driver did not shutdown -	 * DMA self test will enable WDMAC and we'll see (spurious) -	 * pending DMA on the PCI bus at that point. -	 */ -	if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) || -	    (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { -		tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); -		tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); -	} - -	err = tg3_test_dma(tp); -	if (err) { -		dev_err(&pdev->dev, "DMA engine test failed, aborting\n"); -		goto err_out_apeunmap; -	} -  	intmbx = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW;  	rcvmbx = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW;  	sndmbx = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; @@ -17861,6 +17861,23 @@ static int tg3_init_one(struct pci_dev *pdev,  			sndmbx += 0xc;  	} +	/* +	 * Reset chip in case UNDI or EFI driver did not shutdown +	 * DMA self test will enable WDMAC and we'll see (spurious) +	 * pending DMA on the PCI bus at that point. +	 */ +	if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) || +	    (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { +		tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); +		tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); +	} + +	err = tg3_test_dma(tp); +	if (err) { +		dev_err(&pdev->dev, "DMA engine test failed, aborting\n"); +		goto err_out_apeunmap; +	} +  	tg3_init_coal(tp);  	pci_set_drvdata(pdev, dev); diff --git a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c index 7d6aa8c87df8..619083a860a4 100644 --- a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c +++ b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c @@ -172,7 +172,7 @@ bnad_get_debug_drvinfo(struct bnad *bnad, void *buffer, u32 len)  	/* Retrieve flash partition info */  	fcomp.comp_status = 0; -	init_completion(&fcomp.comp); +	reinit_completion(&fcomp.comp);  	spin_lock_irqsave(&bnad->bna_lock, flags);  	ret = bfa_nw_flash_get_attr(&bnad->bna.flash, &drvinfo->flash_attr,  				bnad_cb_completion, &fcomp); diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c index 55eb7f2af2b4..7ef55f5fa664 100644 --- a/drivers/net/ethernet/cadence/at91_ether.c +++ b/drivers/net/ethernet/cadence/at91_ether.c @@ -340,7 +340,7 @@ static int __init at91ether_probe(struct platform_device *pdev)  		res = PTR_ERR(lp->pclk);  		goto err_free_dev;  	} -	clk_enable(lp->pclk); +	clk_prepare_enable(lp->pclk);  	lp->hclk = ERR_PTR(-ENOENT);  	lp->tx_clk = ERR_PTR(-ENOENT); @@ -406,7 +406,7 @@ static int __init at91ether_probe(struct platform_device *pdev)  err_out_unregister_netdev:  	unregister_netdev(dev);  err_disable_clock: -	clk_disable(lp->pclk); +	clk_disable_unprepare(lp->pclk);  err_free_dev:  	free_netdev(dev);  	return res; @@ -424,7 +424,7 @@ static int at91ether_remove(struct platform_device *pdev)  	kfree(lp->mii_bus->irq);  	mdiobus_free(lp->mii_bus);  	unregister_netdev(dev); -	clk_disable(lp->pclk); +	clk_disable_unprepare(lp->pclk);  	free_netdev(dev);  	return 0; @@ -440,7 +440,7 @@ static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg)  		netif_stop_queue(net_dev);  		netif_device_detach(net_dev); -		clk_disable(lp->pclk); +		clk_disable_unprepare(lp->pclk);  	}  	return 0;  } @@ -451,7 +451,7 @@ static int at91ether_resume(struct platform_device *pdev)  	struct macb *lp = netdev_priv(net_dev);  	if (netif_running(net_dev)) { -		clk_enable(lp->pclk); +		clk_prepare_enable(lp->pclk);  		netif_device_attach(net_dev);  		netif_start_queue(net_dev); diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h index d00a751f0588..6049f70e110c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h +++ b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h @@ -96,6 +96,9 @@ struct port_info {  	s16 xact_addr_filt;		/* index of our MAC address filter */  	u16 rss_size;			/* size of VI's RSS table slice */  	u8 pidx;			/* index into adapter port[] */ +	s8 mdio_addr; +	u8 port_type;			/* firmware port type */ +	u8 mod_type;			/* firmware module type */  	u8 port_id;			/* physical port ID */  	u8 nqsets;			/* # of "Queue Sets" */  	u8 first_qset;			/* index of first "Queue Set" */ @@ -522,6 +525,7 @@ static inline struct adapter *netdev2adap(const struct net_device *dev)   * is "contracted" to provide for the common code.   */  void t4vf_os_link_changed(struct adapter *, int, int); +void t4vf_os_portmod_changed(struct adapter *, int);  /*   * SGE function prototype declarations. diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index aa74ec34a467..a936ee8958c7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -44,6 +44,7 @@  #include <linux/etherdevice.h>  #include <linux/debugfs.h>  #include <linux/ethtool.h> +#include <linux/mdio.h>  #include "t4vf_common.h"  #include "t4vf_defs.h" @@ -210,6 +211,38 @@ void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok)  }  /* + * THe port module type has changed on the indicated "port" (Virtual + * Interface). + */ +void t4vf_os_portmod_changed(struct adapter *adapter, int pidx) +{ +	static const char * const mod_str[] = { +		NULL, "LR", "SR", "ER", "passive DA", "active DA", "LRM" +	}; +	const struct net_device *dev = adapter->port[pidx]; +	const struct port_info *pi = netdev_priv(dev); + +	if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) +		dev_info(adapter->pdev_dev, "%s: port module unplugged\n", +			 dev->name); +	else if (pi->mod_type < ARRAY_SIZE(mod_str)) +		dev_info(adapter->pdev_dev, "%s: %s port module inserted\n", +			 dev->name, mod_str[pi->mod_type]); +	else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) +		dev_info(adapter->pdev_dev, "%s: unsupported optical port " +			 "module inserted\n", dev->name); +	else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) +		dev_info(adapter->pdev_dev, "%s: unknown port module inserted," +			 "forcing TWINAX\n", dev->name); +	else if (pi->mod_type == FW_PORT_MOD_TYPE_ERROR) +		dev_info(adapter->pdev_dev, "%s: transceiver module error\n", +			 dev->name); +	else +		dev_info(adapter->pdev_dev, "%s: unknown module type %d " +			 "inserted\n", dev->name, pi->mod_type); +} + +/*   * Net device operations.   * ======================   */ @@ -1193,24 +1226,103 @@ static void cxgb4vf_poll_controller(struct net_device *dev)   * state of the port to which we're linked.   */ -/* - * Return current port link settings. - */ -static int cxgb4vf_get_settings(struct net_device *dev, -				struct ethtool_cmd *cmd) -{ -	const struct port_info *pi = netdev_priv(dev); +static unsigned int t4vf_from_fw_linkcaps(enum fw_port_type type, +					  unsigned int caps) +{ +	unsigned int v = 0; + +	if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XFI || +	    type == FW_PORT_TYPE_BT_XAUI) { +		v |= SUPPORTED_TP; +		if (caps & FW_PORT_CAP_SPEED_100M) +			v |= SUPPORTED_100baseT_Full; +		if (caps & FW_PORT_CAP_SPEED_1G) +			v |= SUPPORTED_1000baseT_Full; +		if (caps & FW_PORT_CAP_SPEED_10G) +			v |= SUPPORTED_10000baseT_Full; +	} else if (type == FW_PORT_TYPE_KX4 || type == FW_PORT_TYPE_KX) { +		v |= SUPPORTED_Backplane; +		if (caps & FW_PORT_CAP_SPEED_1G) +			v |= SUPPORTED_1000baseKX_Full; +		if (caps & FW_PORT_CAP_SPEED_10G) +			v |= SUPPORTED_10000baseKX4_Full; +	} else if (type == FW_PORT_TYPE_KR) +		v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full; +	else if (type == FW_PORT_TYPE_BP_AP) +		v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | +		     SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full; +	else if (type == FW_PORT_TYPE_BP4_AP) +		v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | +		     SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full | +		     SUPPORTED_10000baseKX4_Full; +	else if (type == FW_PORT_TYPE_FIBER_XFI || +		 type == FW_PORT_TYPE_FIBER_XAUI || +		 type == FW_PORT_TYPE_SFP || +		 type == FW_PORT_TYPE_QSFP_10G || +		 type == FW_PORT_TYPE_QSA) { +		v |= SUPPORTED_FIBRE; +		if (caps & FW_PORT_CAP_SPEED_1G) +			v |= SUPPORTED_1000baseT_Full; +		if (caps & FW_PORT_CAP_SPEED_10G) +			v |= SUPPORTED_10000baseT_Full; +	} else if (type == FW_PORT_TYPE_BP40_BA || +		   type == FW_PORT_TYPE_QSFP) { +		v |= SUPPORTED_40000baseSR4_Full; +		v |= SUPPORTED_FIBRE; +	} + +	if (caps & FW_PORT_CAP_ANEG) +		v |= SUPPORTED_Autoneg; +	return v; +} + +static int cxgb4vf_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ +	const struct port_info *p = netdev_priv(dev); + +	if (p->port_type == FW_PORT_TYPE_BT_SGMII || +	    p->port_type == FW_PORT_TYPE_BT_XFI || +	    p->port_type == FW_PORT_TYPE_BT_XAUI) +		cmd->port = PORT_TP; +	else if (p->port_type == FW_PORT_TYPE_FIBER_XFI || +		 p->port_type == FW_PORT_TYPE_FIBER_XAUI) +		cmd->port = PORT_FIBRE; +	else if (p->port_type == FW_PORT_TYPE_SFP || +		 p->port_type == FW_PORT_TYPE_QSFP_10G || +		 p->port_type == FW_PORT_TYPE_QSA || +		 p->port_type == FW_PORT_TYPE_QSFP) { +		if (p->mod_type == FW_PORT_MOD_TYPE_LR || +		    p->mod_type == FW_PORT_MOD_TYPE_SR || +		    p->mod_type == FW_PORT_MOD_TYPE_ER || +		    p->mod_type == FW_PORT_MOD_TYPE_LRM) +			cmd->port = PORT_FIBRE; +		else if (p->mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE || +			 p->mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE) +			cmd->port = PORT_DA; +		else +			cmd->port = PORT_OTHER; +	} else +		cmd->port = PORT_OTHER; -	cmd->supported = pi->link_cfg.supported; -	cmd->advertising = pi->link_cfg.advertising; +	if (p->mdio_addr >= 0) { +		cmd->phy_address = p->mdio_addr; +		cmd->transceiver = XCVR_EXTERNAL; +		cmd->mdio_support = p->port_type == FW_PORT_TYPE_BT_SGMII ? +			MDIO_SUPPORTS_C22 : MDIO_SUPPORTS_C45; +	} else { +		cmd->phy_address = 0;  /* not really, but no better option */ +		cmd->transceiver = XCVR_INTERNAL; +		cmd->mdio_support = 0; +	} + +	cmd->supported = t4vf_from_fw_linkcaps(p->port_type, +					       p->link_cfg.supported); +	cmd->advertising = t4vf_from_fw_linkcaps(p->port_type, +					    p->link_cfg.advertising);  	ethtool_cmd_speed_set(cmd, -			      netif_carrier_ok(dev) ? pi->link_cfg.speed : -1); +			      netif_carrier_ok(dev) ? p->link_cfg.speed : 0);  	cmd->duplex = DUPLEX_FULL; - -	cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; -	cmd->phy_address = pi->port_id; -	cmd->transceiver = XCVR_EXTERNAL; -	cmd->autoneg = pi->link_cfg.autoneg; +	cmd->autoneg = p->link_cfg.autoneg;  	cmd->maxtxpkt = 0;  	cmd->maxrxpkt = 0;  	return 0; @@ -2318,7 +2430,7 @@ static void cfg_queues(struct adapter *adapter)  	 */  	n10g = 0;  	for_each_port(adapter, pidx) -		n10g += is_10g_port(&adap2pinfo(adapter, pidx)->link_cfg); +		n10g += is_x_10g_port(&adap2pinfo(adapter, pidx)->link_cfg);  	/*  	 * We default to 1 queue per non-10G port and up to # of cores queues diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h index 8d3237f5e364..b9debb4f29a3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h @@ -230,7 +230,7 @@ struct adapter_params {  static inline bool is_10g_port(const struct link_config *lc)  { -	return (lc->supported & SUPPORTED_10000baseT_Full) != 0; +	return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0;  }  static inline bool is_x_10g_port(const struct link_config *lc) diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c index 02e8833b7797..60426cf890a7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c @@ -245,6 +245,10 @@ static int hash_mac_addr(const u8 *addr)  	return a & 0x3f;  } +#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ +		     FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \ +		     FW_PORT_CAP_SPEED_100G | FW_PORT_CAP_ANEG) +  /**   *	init_link_config - initialize a link's SW state   *	@lc: structure holding the link state @@ -259,8 +263,8 @@ static void init_link_config(struct link_config *lc, unsigned int caps)  	lc->requested_speed = 0;  	lc->speed = 0;  	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; -	if (lc->supported & SUPPORTED_Autoneg) { -		lc->advertising = lc->supported; +	if (lc->supported & FW_PORT_CAP_ANEG) { +		lc->advertising = lc->supported & ADVERT_MASK;  		lc->autoneg = AUTONEG_ENABLE;  		lc->requested_fc |= PAUSE_AUTONEG;  	} else { @@ -280,7 +284,6 @@ int t4vf_port_init(struct adapter *adapter, int pidx)  	struct fw_vi_cmd vi_cmd, vi_rpl;  	struct fw_port_cmd port_cmd, port_rpl;  	int v; -	u32 word;  	/*  	 * Execute a VI Read command to get our Virtual Interface information @@ -319,19 +322,13 @@ int t4vf_port_init(struct adapter *adapter, int pidx)  	if (v)  		return v; -	v = 0; -	word = be16_to_cpu(port_rpl.u.info.pcap); -	if (word & FW_PORT_CAP_SPEED_100M) -		v |= SUPPORTED_100baseT_Full; -	if (word & FW_PORT_CAP_SPEED_1G) -		v |= SUPPORTED_1000baseT_Full; -	if (word & FW_PORT_CAP_SPEED_10G) -		v |= SUPPORTED_10000baseT_Full; -	if (word & FW_PORT_CAP_SPEED_40G) -		v |= SUPPORTED_40000baseSR4_Full; -	if (word & FW_PORT_CAP_ANEG) -		v |= SUPPORTED_Autoneg; -	init_link_config(&pi->link_cfg, v); +	v = be32_to_cpu(port_rpl.u.info.lstatus_to_modtype); +	pi->mdio_addr = (v & FW_PORT_CMD_MDIOCAP_F) ? +			FW_PORT_CMD_MDIOADDR_G(v) : -1; +	pi->port_type = FW_PORT_CMD_PTYPE_G(v); +	pi->mod_type = FW_PORT_MOD_TYPE_NA; + +	init_link_config(&pi->link_cfg, be16_to_cpu(port_rpl.u.info.pcap));  	return 0;  } @@ -1491,7 +1488,7 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)  		 */  		const struct fw_port_cmd *port_cmd =  			(const struct fw_port_cmd *)rpl; -		u32 word; +		u32 stat, mod;  		int action, port_id, link_ok, speed, fc, pidx;  		/* @@ -1509,21 +1506,21 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)  		port_id = FW_PORT_CMD_PORTID_G(  			be32_to_cpu(port_cmd->op_to_portid)); -		word = be32_to_cpu(port_cmd->u.info.lstatus_to_modtype); -		link_ok = (word & FW_PORT_CMD_LSTATUS_F) != 0; +		stat = be32_to_cpu(port_cmd->u.info.lstatus_to_modtype); +		link_ok = (stat & FW_PORT_CMD_LSTATUS_F) != 0;  		speed = 0;  		fc = 0; -		if (word & FW_PORT_CMD_RXPAUSE_F) +		if (stat & FW_PORT_CMD_RXPAUSE_F)  			fc |= PAUSE_RX; -		if (word & FW_PORT_CMD_TXPAUSE_F) +		if (stat & FW_PORT_CMD_TXPAUSE_F)  			fc |= PAUSE_TX; -		if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M)) +		if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))  			speed = 100; -		else if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G)) +		else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))  			speed = 1000; -		else if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G)) +		else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))  			speed = 10000; -		else if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G)) +		else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))  			speed = 40000;  		/* @@ -1540,12 +1537,21 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)  				continue;  			lc = &pi->link_cfg; + +			mod = FW_PORT_CMD_MODTYPE_G(stat); +			if (mod != pi->mod_type) { +				pi->mod_type = mod; +				t4vf_os_portmod_changed(adapter, pidx); +			} +  			if (link_ok != lc->link_ok || speed != lc->speed ||  			    fc != lc->fc) {  				/* something changed */  				lc->link_ok = link_ok;  				lc->speed = speed;  				lc->fc = fc; +				lc->supported = +					be16_to_cpu(port_cmd->u.info.pcap);  				t4vf_os_link_changed(adapter, pidx, link_ok);  			}  		} diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 868d0f605d60..b29e027c476e 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1060,10 +1060,14 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,  				     PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);  		} -		if ((netdev->features & NETIF_F_RXCSUM) && !csum_not_calc) { -			skb->csum = htons(checksum); -			skb->ip_summed = CHECKSUM_COMPLETE; -		} +		/* Hardware does not provide whole packet checksum. It only +		 * provides pseudo checksum. Since hw validates the packet +		 * checksum but not provide us the checksum value. use +		 * CHECSUM_UNNECESSARY. +		 */ +		if ((netdev->features & NETIF_F_RXCSUM) && tcp_udp_csum_ok && +		    ipv4_csum_ok) +			skb->ip_summed = CHECKSUM_UNNECESSARY;  		if (vlan_stripped)  			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci); @@ -1612,7 +1616,7 @@ static int enic_open(struct net_device *netdev)  		if (vnic_rq_desc_used(&enic->rq[i]) == 0) {  			netdev_err(netdev, "Unable to alloc receive buffers\n");  			err = -ENOMEM; -			goto err_out_notify_unset; +			goto err_out_free_rq;  		}  	} @@ -1645,7 +1649,9 @@ static int enic_open(struct net_device *netdev)  	return 0; -err_out_notify_unset: +err_out_free_rq: +	for (i = 0; i < enic->rq_count; i++) +		vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);  	enic_dev_notify_unset(enic);  err_out_free_intr:  	enic_free_intr(enic); diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c index a379c3e4b57f..13d00a38a5bd 100644 --- a/drivers/net/ethernet/dnet.c +++ b/drivers/net/ethernet/dnet.c @@ -398,13 +398,8 @@ static int dnet_poll(struct napi_struct *napi, int budget)  		 * break out of while loop if there are no more  		 * packets waiting  		 */ -		if (!(dnet_readl(bp, RX_FIFO_WCNT) >> 16)) { -			napi_complete(napi); -			int_enable = dnet_readl(bp, INTR_ENB); -			int_enable |= DNET_INTR_SRC_RX_CMDFIFOAF; -			dnet_writel(bp, int_enable, INTR_ENB); -			return 0; -		} +		if (!(dnet_readl(bp, RX_FIFO_WCNT) >> 16)) +			break;  		cmd_word = dnet_readl(bp, RX_LEN_FIFO);  		pkt_len = cmd_word & 0xFFFF; @@ -433,20 +428,17 @@ static int dnet_poll(struct napi_struct *napi, int budget)  			       "size %u.\n", dev->name, pkt_len);  	} -	budget -= npackets; -  	if (npackets < budget) {  		/* We processed all packets available.  Tell NAPI it can -		 * stop polling then re-enable rx interrupts */ +		 * stop polling then re-enable rx interrupts. +		 */  		napi_complete(napi);  		int_enable = dnet_readl(bp, INTR_ENB);  		int_enable |= DNET_INTR_SRC_RX_CMDFIFOAF;  		dnet_writel(bp, int_enable, INTR_ENB); -		return 0;  	} -	/* There are still packets waiting */ -	return 1; +	return npackets;  }  static irqreturn_t dnet_interrupt(int irq, void *dev_id) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 196073110e32..d48806b5cd88 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -4383,8 +4383,9 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,   * distinguish various types of transports (VxLAN, GRE, NVGRE ..). So, offload   * is expected to work across all types of IP tunnels once exported. Skyhawk   * supports offloads for either VxLAN or NVGRE, exclusively. So we export VxLAN - * offloads in hw_enc_features only when a VxLAN port is added. Note this only - * ensures that other tunnels work fine while VxLAN offloads are not enabled. + * offloads in hw_enc_features only when a VxLAN port is added. If other (non + * VxLAN) tunnels are configured while VxLAN offloads are enabled, offloads for + * those other tunnels are unexported on the fly through ndo_features_check().   *   * Skyhawk supports VxLAN offloads only for one UDP dport. So, if the stack   * adds more than one port, disable offloads and don't re-enable them again @@ -4459,9 +4460,45 @@ done:  	adapter->vxlan_port_count--;  } -static bool be_gso_check(struct sk_buff *skb, struct net_device *dev) +static netdev_features_t be_features_check(struct sk_buff *skb, +					   struct net_device *dev, +					   netdev_features_t features)  { -	return vxlan_gso_check(skb); +	struct be_adapter *adapter = netdev_priv(dev); +	u8 l4_hdr = 0; + +	/* The code below restricts offload features for some tunneled packets. +	 * Offload features for normal (non tunnel) packets are unchanged. +	 */ +	if (!skb->encapsulation || +	    !(adapter->flags & BE_FLAGS_VXLAN_OFFLOADS)) +		return features; + +	/* It's an encapsulated packet and VxLAN offloads are enabled. We +	 * should disable tunnel offload features if it's not a VxLAN packet, +	 * as tunnel offloads have been enabled only for VxLAN. This is done to +	 * allow other tunneled traffic like GRE work fine while VxLAN +	 * offloads are configured in Skyhawk-R. +	 */ +	switch (vlan_get_protocol(skb)) { +	case htons(ETH_P_IP): +		l4_hdr = ip_hdr(skb)->protocol; +		break; +	case htons(ETH_P_IPV6): +		l4_hdr = ipv6_hdr(skb)->nexthdr; +		break; +	default: +		return features; +	} + +	if (l4_hdr != IPPROTO_UDP || +	    skb->inner_protocol_type != ENCAP_TYPE_ETHER || +	    skb->inner_protocol != htons(ETH_P_TEB) || +	    skb_inner_mac_header(skb) - skb_transport_header(skb) != +	    sizeof(struct udphdr) + sizeof(struct vxlanhdr)) +		return features & ~(NETIF_F_ALL_CSUM | NETIF_F_GSO_MASK); + +	return features;  }  #endif @@ -4492,7 +4529,7 @@ static const struct net_device_ops be_netdev_ops = {  #ifdef CONFIG_BE2NET_VXLAN  	.ndo_add_vxlan_port	= be_add_vxlan_port,  	.ndo_del_vxlan_port	= be_del_vxlan_port, -	.ndo_gso_check		= be_gso_check, +	.ndo_features_check	= be_features_check,  #endif  }; diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 469691ad4a1e..40132929daf7 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -424,6 +424,8 @@ struct bufdesc_ex {   * (40ns * 6).   */  #define FEC_QUIRK_BUG_CAPTURE		(1 << 10) +/* Controller has only one MDIO bus */ +#define FEC_QUIRK_SINGLE_MDIO		(1 << 11)  struct fec_enet_priv_tx_q {  	int index; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 5ebdf8dc8a31..bba87775419d 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -91,7 +91,8 @@ static struct platform_device_id fec_devtype[] = {  		.driver_data = 0,  	}, {  		.name = "imx28-fec", -		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME, +		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME | +				FEC_QUIRK_SINGLE_MDIO,  	}, {  		.name = "imx6q-fec",  		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | @@ -1937,7 +1938,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)  	int err = -ENXIO, i;  	/* -	 * The dual fec interfaces are not equivalent with enet-mac. +	 * The i.MX28 dual fec interfaces are not equal.  	 * Here are the differences:  	 *  	 *  - fec0 supports MII & RMII modes while fec1 only supports RMII @@ -1952,7 +1953,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)  	 * mdio interface in board design, and need to be configured by  	 * fec0 mii_bus.  	 */ -	if ((fep->quirks & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) { +	if ((fep->quirks & FEC_QUIRK_SINGLE_MDIO) && fep->dev_id > 0) {  		/* fec1 uses fec0 mii_bus */  		if (mii_cnt && fec0_mii_bus) {  			fep->mii_bus = fec0_mii_bus; @@ -2015,7 +2016,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)  	mii_cnt++;  	/* save fec0 mii_bus */ -	if (fep->quirks & FEC_QUIRK_ENET_MAC) +	if (fep->quirks & FEC_QUIRK_SINGLE_MDIO)  		fec0_mii_bus = fep->mii_bus;  	return 0; @@ -3129,6 +3130,7 @@ fec_probe(struct platform_device *pdev)  		pdev->id_entry = of_id->data;  	fep->quirks = pdev->id_entry->driver_data; +	fep->netdev = ndev;  	fep->num_rx_queues = num_rx_qs;  	fep->num_tx_queues = num_tx_qs; diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 5b8300a32bf5..4d61ef50b465 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -281,6 +281,17 @@ config I40E_DCB  	  If unsure, say N. +config I40E_FCOE +	bool "Fibre Channel over Ethernet (FCoE)" +	default n +	depends on I40E && DCB && FCOE +	---help--- +	  Say Y here if you want to use Fibre Channel over Ethernet (FCoE) +	  in the driver. This will create new netdev for exclusive FCoE +	  use with XL710 FCoE offloads enabled. + +	  If unsure, say N. +  config I40EVF  	tristate "Intel(R) XL710 X710 Virtual Function Ethernet support"  	depends on PCI_MSI diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c index 781065eb5431..e9c3a87e5b11 100644 --- a/drivers/net/ethernet/intel/e100.c +++ b/drivers/net/ethernet/intel/e100.c @@ -1543,7 +1543,7 @@ static int e100_phy_init(struct nic *nic)  		mdio_write(netdev, nic->mii.phy_id, MII_BMCR, bmcr);  	} else if ((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&  	   (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) && -		!(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) { +		(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) {  		/* enable/disable MDI/MDI-X auto-switching. */  		mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,  				nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH); diff --git a/drivers/net/ethernet/intel/i40e/Makefile b/drivers/net/ethernet/intel/i40e/Makefile index 4b94ddb29c24..c40581999121 100644 --- a/drivers/net/ethernet/intel/i40e/Makefile +++ b/drivers/net/ethernet/intel/i40e/Makefile @@ -44,4 +44,4 @@ i40e-objs := i40e_main.o \  	i40e_virtchnl_pf.o  i40e-$(CONFIG_I40E_DCB) += i40e_dcb.o i40e_dcb_nl.o -i40e-$(CONFIG_FCOE:m=y) += i40e_fcoe.o +i40e-$(CONFIG_I40E_FCOE) += i40e_fcoe.o diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 433a55886ad2..cb0de455683e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -829,7 +829,7 @@ static void i40e_dbg_dump_desc(int cnt, int vsi_seid, int ring_id, int desc_n,  		if (desc_n >= ring->count || desc_n < 0) {  			dev_info(&pf->pdev->dev,  				 "descriptor %d not found\n", desc_n); -			return; +			goto out;  		}  		if (!is_rx_ring) {  			txd = I40E_TX_DESC(ring, desc_n); @@ -855,6 +855,8 @@ static void i40e_dbg_dump_desc(int cnt, int vsi_seid, int ring_id, int desc_n,  	} else {  		dev_info(&pf->pdev->dev, "dump desc rx/tx <vsi_seid> <ring_id> [<desc_n>]\n");  	} + +out:  	kfree(ring);  } diff --git a/drivers/net/ethernet/intel/i40e/i40e_osdep.h b/drivers/net/ethernet/intel/i40e/i40e_osdep.h index 045b5c4b98b3..ad802dd0f67a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_osdep.h +++ b/drivers/net/ethernet/intel/i40e/i40e_osdep.h @@ -78,7 +78,7 @@ do {                                                            \  } while (0)  typedef enum i40e_status_code i40e_status; -#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) +#ifdef CONFIG_I40E_FCOE  #define I40E_FCOE -#endif /* CONFIG_FCOE or CONFIG_FCOE_MODULE */ +#endif  #endif /* _I40E_OSDEP_H_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 04b441460bbd..cecb340898fe 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -658,6 +658,8 @@ static inline u32 i40e_get_head(struct i40e_ring *tx_ring)  	return le32_to_cpu(*(volatile __le32 *)head);  } +#define WB_STRIDE 0x3 +  /**   * i40e_clean_tx_irq - Reclaim resources after transmit completes   * @tx_ring:  tx ring to clean @@ -759,6 +761,18 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)  	tx_ring->q_vector->tx.total_bytes += total_bytes;  	tx_ring->q_vector->tx.total_packets += total_packets; +	/* check to see if there are any non-cache aligned descriptors +	 * waiting to be written back, and kick the hardware to force +	 * them to be written back in case of napi polling +	 */ +	if (budget && +	    !((i & WB_STRIDE) == WB_STRIDE) && +	    !test_bit(__I40E_DOWN, &tx_ring->vsi->state) && +	    (I40E_DESC_UNUSED(tx_ring) != tx_ring->count)) +		tx_ring->arm_wb = true; +	else +		tx_ring->arm_wb = false; +  	if (check_for_tx_hang(tx_ring) && i40e_check_tx_hang(tx_ring)) {  		/* schedule immediate reset if we believe we hung */  		dev_info(tx_ring->dev, "Detected Tx Unit Hang\n" @@ -777,13 +791,16 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)  		netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);  		dev_info(tx_ring->dev, -			 "tx hang detected on queue %d, resetting adapter\n", +			 "tx hang detected on queue %d, reset requested\n",  			 tx_ring->queue_index); -		tx_ring->netdev->netdev_ops->ndo_tx_timeout(tx_ring->netdev); +		/* do not fire the reset immediately, wait for the stack to +		 * decide we are truly stuck, also prevents every queue from +		 * simultaneously requesting a reset +		 */ -		/* the adapter is about to reset, no point in enabling stuff */ -		return true; +		/* the adapter is about to reset, no point in enabling polling */ +		budget = 1;  	}  	netdev_tx_completed_queue(netdev_get_tx_queue(tx_ring->netdev, @@ -806,7 +823,25 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)  		}  	} -	return budget > 0; +	return !!budget; +} + +/** + * i40e_force_wb - Arm hardware to do a wb on noncache aligned descriptors + * @vsi: the VSI we care about + * @q_vector: the vector  on which to force writeback + * + **/ +static void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) +{ +	u32 val = I40E_PFINT_DYN_CTLN_INTENA_MASK | +		  I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK | +		  I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK +		  /* allow 00 to be written to the index */; + +	wr32(&vsi->back->hw, +	     I40E_PFINT_DYN_CTLN(q_vector->v_idx + vsi->base_vector - 1), +	     val);  }  /** @@ -1290,9 +1325,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,  	 * so the total length of IPv4 header is IHL*4 bytes  	 * The UDP_0 bit *may* bet set if the *inner* header is UDP  	 */ -	if (ipv4_tunnel && -	    (decoded.inner_prot != I40E_RX_PTYPE_INNER_PROT_UDP) && -	    !(rx_status & (1 << I40E_RX_DESC_STATUS_UDP_0_SHIFT))) { +	if (ipv4_tunnel) {  		skb->transport_header = skb->mac_header +  					sizeof(struct ethhdr) +  					(ip_hdr(skb)->ihl * 4); @@ -1302,15 +1335,19 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,  					  skb->protocol == htons(ETH_P_8021AD))  					  ? VLAN_HLEN : 0; -		rx_udp_csum = udp_csum(skb); -		iph = ip_hdr(skb); -		csum = csum_tcpudp_magic( -				iph->saddr, iph->daddr, -				(skb->len - skb_transport_offset(skb)), -				IPPROTO_UDP, rx_udp_csum); +		if ((ip_hdr(skb)->protocol == IPPROTO_UDP) && +		    (udp_hdr(skb)->check != 0)) { +			rx_udp_csum = udp_csum(skb); +			iph = ip_hdr(skb); +			csum = csum_tcpudp_magic( +					iph->saddr, iph->daddr, +					(skb->len - skb_transport_offset(skb)), +					IPPROTO_UDP, rx_udp_csum); -		if (udp_hdr(skb)->check != csum) -			goto checksum_fail; +			if (udp_hdr(skb)->check != csum) +				goto checksum_fail; + +		} /* else its GRE and so no outer UDP header */  	}  	skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -1581,6 +1618,7 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)  	struct i40e_vsi *vsi = q_vector->vsi;  	struct i40e_ring *ring;  	bool clean_complete = true; +	bool arm_wb = false;  	int budget_per_ring;  	if (test_bit(__I40E_DOWN, &vsi->state)) { @@ -1591,8 +1629,10 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)  	/* Since the actual Tx work is minimal, we can give the Tx a larger  	 * budget and be more aggressive about cleaning up the Tx descriptors.  	 */ -	i40e_for_each_ring(ring, q_vector->tx) +	i40e_for_each_ring(ring, q_vector->tx) {  		clean_complete &= i40e_clean_tx_irq(ring, vsi->work_limit); +		arm_wb |= ring->arm_wb; +	}  	/* We attempt to distribute budget to each Rx queue fairly, but don't  	 * allow the budget to go below 1 because that would exit polling early. @@ -1603,8 +1643,11 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)  		clean_complete &= i40e_clean_rx_irq(ring, budget_per_ring);  	/* If work not completed, return budget and polling will return */ -	if (!clean_complete) +	if (!clean_complete) { +		if (arm_wb) +			i40e_force_wb(vsi, q_vector);  		return budget; +	}  	/* Work is done so exit the polling mode and re-enable the interrupt */  	napi_complete(napi); @@ -1840,17 +1883,16 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,  	if (err < 0)  		return err; -	if (protocol == htons(ETH_P_IP)) { -		iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb); +	iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb); +	ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb); + +	if (iph->version == 4) {  		tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);  		iph->tot_len = 0;  		iph->check = 0;  		tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,  						 0, IPPROTO_TCP, 0); -	} else if (skb_is_gso_v6(skb)) { - -		ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) -					   : ipv6_hdr(skb); +	} else if (ipv6h->version == 6) {  		tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);  		ipv6h->payload_len = 0;  		tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, @@ -1946,13 +1988,9 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,  					 I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;  			}  		} else if (tx_flags & I40E_TX_FLAGS_IPV6) { -			if (tx_flags & I40E_TX_FLAGS_TSO) { -				*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6; +			*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6; +			if (tx_flags & I40E_TX_FLAGS_TSO)  				ip_hdr(skb)->check = 0; -			} else { -				*cd_tunneling |= -					 I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM; -			}  		}  		/* Now set the ctx descriptor fields */ @@ -1962,7 +2000,10 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,  				   ((skb_inner_network_offset(skb) -  					skb_transport_offset(skb)) >> 1) <<  				   I40E_TXD_CTX_QW0_NATLEN_SHIFT; - +		if (this_ip_hdr->version == 6) { +			tx_flags &= ~I40E_TX_FLAGS_IPV4; +			tx_flags |= I40E_TX_FLAGS_IPV6; +		}  	} else {  		network_hdr_len = skb_network_header_len(skb);  		this_ip_hdr = ip_hdr(skb); @@ -2198,7 +2239,6 @@ static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,  	/* Place RS bit on last descriptor of any packet that spans across the  	 * 4th descriptor (WB_STRIDE aka 0x3) in a 64B cacheline.  	 */ -#define WB_STRIDE 0x3  	if (((i & WB_STRIDE) != WB_STRIDE) &&  	    (first <= &tx_ring->tx_bi[i]) &&  	    (first >= &tx_ring->tx_bi[i & ~WB_STRIDE])) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index e60d3accb2e2..18b00231d2f1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -241,6 +241,7 @@ struct i40e_ring {  	unsigned long last_rx_timestamp;  	bool ring_active;		/* is ring online or not */ +	bool arm_wb;		/* do something to arm write back */  	/* stats structs */  	struct i40e_queue_stats	stats; diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 051ea94bdcd3..0f69ef81751a 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -1125,7 +1125,7 @@ static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask)  	u32 swmask = mask;  	u32 fwmask = mask << 16;  	s32 ret_val = 0; -	s32 i = 0, timeout = 200; /* FIXME: find real value to use here */ +	s32 i = 0, timeout = 200;  	while (i < timeout) {  		if (igb_get_hw_semaphore(hw)) { diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 190cbd931f6b..ac6a8f1eea6c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -475,7 +475,8 @@ static int mlx4_en_tunnel_steer_add(struct mlx4_en_priv *priv, unsigned char *ad  {  	int err; -	if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) +	if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN || +	    priv->mdev->dev->caps.dmfs_high_steer_mode == MLX4_STEERING_DMFS_A0_STATIC)  		return 0; /* do nothing */  	err = mlx4_tunnel_steer_add(priv->mdev->dev, addr, priv->port, qpn, @@ -2365,9 +2366,11 @@ static void mlx4_en_del_vxlan_port(struct  net_device *dev,  	queue_work(priv->mdev->workqueue, &priv->vxlan_del_task);  } -static bool mlx4_en_gso_check(struct sk_buff *skb, struct net_device *dev) +static netdev_features_t mlx4_en_features_check(struct sk_buff *skb, +						struct net_device *dev, +						netdev_features_t features)  { -	return vxlan_gso_check(skb); +	return vxlan_features_check(skb, features);  }  #endif @@ -2400,7 +2403,7 @@ static const struct net_device_ops mlx4_netdev_ops = {  #ifdef CONFIG_MLX4_EN_VXLAN  	.ndo_add_vxlan_port	= mlx4_en_add_vxlan_port,  	.ndo_del_vxlan_port	= mlx4_en_del_vxlan_port, -	.ndo_gso_check		= mlx4_en_gso_check, +	.ndo_features_check	= mlx4_en_features_check,  #endif  }; @@ -2434,7 +2437,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = {  #ifdef CONFIG_MLX4_EN_VXLAN  	.ndo_add_vxlan_port	= mlx4_en_add_vxlan_port,  	.ndo_del_vxlan_port	= mlx4_en_del_vxlan_port, -	.ndo_gso_check		= mlx4_en_gso_check, +	.ndo_features_check	= mlx4_en_features_check,  #endif  }; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index a308d41e4de0..e3357bf523df 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -962,7 +962,17 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)  		tx_desc->ctrl.owner_opcode = op_own;  		if (send_doorbell) {  			wmb(); -			iowrite32(ring->doorbell_qpn, +			/* Since there is no iowrite*_native() that writes the +			 * value as is, without byteswapping - using the one +			 * the doesn't do byteswapping in the relevant arch +			 * endianness. +			 */ +#if defined(__LITTLE_ENDIAN) +			iowrite32( +#else +			iowrite32be( +#endif +				  ring->doorbell_qpn,  				  ring->bf.uar->map + MLX4_SEND_DOORBELL);  		} else {  			ring->xmit_more++; diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 943cbd47d832..6e08352ec994 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -1744,8 +1744,7 @@ static void choose_tunnel_offload_mode(struct mlx4_dev *dev,  				       struct mlx4_dev_cap *dev_cap)  {  	if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED && -	    dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS && -	    dev->caps.dmfs_high_steer_mode != MLX4_STEERING_DMFS_A0_STATIC) +	    dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS)  		dev->caps.tunnel_offload_mode = MLX4_TUNNEL_OFFLOAD_MODE_VXLAN;  	else  		dev->caps.tunnel_offload_mode = MLX4_TUNNEL_OFFLOAD_MODE_NONE; @@ -1829,7 +1828,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)  		err = mlx4_dev_cap(dev, &dev_cap);  		if (err) {  			mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting\n"); -			goto err_stop_fw; +			return err;  		}  		choose_steering_mode(dev, &dev_cap); @@ -1860,7 +1859,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)  					     &init_hca);  		if ((long long) icm_size < 0) {  			err = icm_size; -			goto err_stop_fw; +			return err;  		}  		dev->caps.max_fmr_maps = (1 << (32 - ilog2(dev->caps.num_mpts))) - 1; @@ -1874,7 +1873,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)  		err = mlx4_init_icm(dev, &dev_cap, &init_hca, icm_size);  		if (err) -			goto err_stop_fw; +			return err;  		err = mlx4_INIT_HCA(dev, &init_hca);  		if (err) { @@ -1886,7 +1885,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)  			err = mlx4_query_func(dev, &dev_cap);  			if (err < 0) {  				mlx4_err(dev, "QUERY_FUNC command failed, aborting.\n"); -				goto err_stop_fw; +				goto err_close;  			} else if (err & MLX4_QUERY_FUNC_NUM_SYS_EQS) {  				dev->caps.num_eqs = dev_cap.max_eqs;  				dev->caps.reserved_eqs = dev_cap.reserved_eqs; @@ -2006,11 +2005,6 @@ err_free_icm:  	if (!mlx4_is_slave(dev))  		mlx4_free_icms(dev); -err_stop_fw: -	if (!mlx4_is_slave(dev)) { -		mlx4_UNMAP_FA(dev); -		mlx4_free_icm(dev, priv->fw.fw_icm, 0); -	}  	return err;  } diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c index d6f549685c0f..7094a9c70fd5 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mr.c +++ b/drivers/net/ethernet/mellanox/mlx4/mr.c @@ -584,6 +584,7 @@ EXPORT_SYMBOL_GPL(mlx4_mr_free);  void mlx4_mr_rereg_mem_cleanup(struct mlx4_dev *dev, struct mlx4_mr *mr)  {  	mlx4_mtt_cleanup(dev, &mr->mtt); +	mr->mtt.order = -1;  }  EXPORT_SYMBOL_GPL(mlx4_mr_rereg_mem_cleanup); @@ -593,14 +594,14 @@ int mlx4_mr_rereg_mem_write(struct mlx4_dev *dev, struct mlx4_mr *mr,  {  	int err; -	mpt_entry->start       = cpu_to_be64(iova); -	mpt_entry->length      = cpu_to_be64(size); -	mpt_entry->entity_size = cpu_to_be32(page_shift); -  	err = mlx4_mtt_init(dev, npages, page_shift, &mr->mtt);  	if (err)  		return err; +	mpt_entry->start       = cpu_to_be64(mr->iova); +	mpt_entry->length      = cpu_to_be64(mr->size); +	mpt_entry->entity_size = cpu_to_be32(mr->mtt.page_shift); +  	mpt_entry->pd_flags &= cpu_to_be32(MLX4_MPT_PD_MASK |  					   MLX4_MPT_PD_FLAG_EN_INV);  	mpt_entry->flags    &= cpu_to_be32(MLX4_MPT_FLAG_FREE | diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index f1ebed6c63b1..2fa6ae026e4f 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -2303,12 +2303,6 @@ static inline int port_chk_force_flow_ctrl(struct ksz_hw *hw, int p)  /* Spanning Tree */ -static inline void port_cfg_dis_learn(struct ksz_hw *hw, int p, int set) -{ -	port_cfg(hw, p, -		KS8842_PORT_CTRL_2_OFFSET, PORT_LEARN_DISABLE, set); -} -  static inline void port_cfg_rx(struct ksz_hw *hw, int p, int set)  {  	port_cfg(hw, p, diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c index af099057f0e9..71af98bb72cb 100644 --- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c @@ -4033,8 +4033,10 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	(void)pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));  	mgp->cmd = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->cmd),  				      &mgp->cmd_bus, GFP_KERNEL); -	if (mgp->cmd == NULL) +	if (!mgp->cmd) { +		status = -ENOMEM;  		goto abort_with_enabled; +	}  	mgp->board_span = pci_resource_len(pdev, 0);  	mgp->iomem_base = pci_resource_start(pdev, 0); diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index f5e4b820128b..db0c7a9aee60 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -6987,7 +6987,9 @@ static int s2io_add_isr(struct s2io_nic *sp)  			if (sp->s2io_entries[i].in_use == MSIX_FLG) {  				if (sp->s2io_entries[i].type ==  				    MSIX_RING_TYPE) { -					sprintf(sp->desc[i], "%s:MSI-X-%d-RX", +					snprintf(sp->desc[i], +						sizeof(sp->desc[i]), +						"%s:MSI-X-%d-RX",  						dev->name, i);  					err = request_irq(sp->entries[i].vector,  							  s2io_msix_ring_handle, @@ -6996,7 +6998,9 @@ static int s2io_add_isr(struct s2io_nic *sp)  							  sp->s2io_entries[i].arg);  				} else if (sp->s2io_entries[i].type ==  					   MSIX_ALARM_TYPE) { -					sprintf(sp->desc[i], "%s:MSI-X-%d-TX", +					snprintf(sp->desc[i], +						sizeof(sp->desc[i]), +						"%s:MSI-X-%d-TX",  						dev->name, i);  					err = request_irq(sp->entries[i].vector,  							  s2io_msix_fifo_handle, @@ -8154,7 +8158,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)  			  "%s: UDP Fragmentation Offload(UFO) enabled\n",  			  dev->name);  	/* Initialize device name */ -	sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name); +	snprintf(sp->name, sizeof(sp->name), "%s Neterion %s", dev->name, +		 sp->product_name);  	if (vlan_tag_strip)  		sp->vlan_strip_flag = 1; diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c index c2f09af5c25b..4847713211ca 100644 --- a/drivers/net/ethernet/qlogic/qla3xxx.c +++ b/drivers/net/ethernet/qlogic/qla3xxx.c @@ -146,10 +146,7 @@ static int ql_wait_for_drvr_lock(struct ql3_adapter *qdev)  {  	int i = 0; -	while (i < 10) { -		if (i) -			ssleep(1); - +	do {  		if (ql_sem_lock(qdev,  				QL_DRVR_SEM_MASK,  				(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) @@ -158,7 +155,8 @@ static int ql_wait_for_drvr_lock(struct ql3_adapter *qdev)  				      "driver lock acquired\n");  			return 1;  		} -	} +		ssleep(1); +	} while (++i < 10);  	netdev_err(qdev->ndev, "Timed out waiting for driver lock...\n");  	return 0; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 1aa25b13ace1..2528c3fb6b90 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -505,9 +505,11 @@ static void qlcnic_del_vxlan_port(struct net_device *netdev,  	adapter->flags |= QLCNIC_DEL_VXLAN_PORT;  } -static bool qlcnic_gso_check(struct sk_buff *skb, struct net_device *dev) +static netdev_features_t qlcnic_features_check(struct sk_buff *skb, +					       struct net_device *dev, +					       netdev_features_t features)  { -	return vxlan_gso_check(skb); +	return vxlan_features_check(skb, features);  }  #endif @@ -532,7 +534,7 @@ static const struct net_device_ops qlcnic_netdev_ops = {  #ifdef CONFIG_QLCNIC_VXLAN  	.ndo_add_vxlan_port	= qlcnic_add_vxlan_port,  	.ndo_del_vxlan_port	= qlcnic_del_vxlan_port, -	.ndo_gso_check		= qlcnic_gso_check, +	.ndo_features_check	= qlcnic_features_check,  #endif  #ifdef CONFIG_NET_POLL_CONTROLLER  	.ndo_poll_controller = qlcnic_poll_controller, @@ -2603,6 +2605,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	} else {  		dev_err(&pdev->dev,  			"%s: failed. Please Reboot\n", __func__); +		err = -ENODEV;  		goto err_out_free_hw;  	} diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c index 6d0b9dfac313..78bb4ceb1cdd 100644 --- a/drivers/net/ethernet/realtek/8139too.c +++ b/drivers/net/ethernet/realtek/8139too.c @@ -787,10 +787,10 @@ static struct net_device *rtl8139_init_board(struct pci_dev *pdev)  	if (rc)  		goto err_out; +	disable_dev_on_err = 1;  	rc = pci_request_regions (pdev, DRV_NAME);  	if (rc)  		goto err_out; -	disable_dev_on_err = 1;  	pci_set_master (pdev); @@ -1110,6 +1110,7 @@ static int rtl8139_init_one(struct pci_dev *pdev,  	return 0;  err_out: +	netif_napi_del(&tp->napi);  	__rtl8139_cleanup_dev (dev);  	pci_disable_device (pdev);  	return i; @@ -1124,6 +1125,7 @@ static void rtl8139_remove_one(struct pci_dev *pdev)  	assert (dev != NULL);  	cancel_delayed_work_sync(&tp->thread); +	netif_napi_del(&tp->napi);  	unregister_netdev (dev); diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index c29ba80ae02b..6576243222af 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -473,6 +473,7 @@ static struct sh_eth_cpu_data r8a777x_data = {  	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |  			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE |  			  EESR_ECI, +	.fdr_value	= 0x00000f0f,  	.apr		= 1,  	.mpr		= 1, @@ -495,6 +496,9 @@ static struct sh_eth_cpu_data r8a779x_data = {  	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |  			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE |  			  EESR_ECI, +	.fdr_value	= 0x00000f0f, + +	.trscer_err_mask = DESC_I_RINT8,  	.apr		= 1,  	.mpr		= 1, @@ -856,6 +860,9 @@ static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd)  	if (!cd->eesr_err_check)  		cd->eesr_err_check = DEFAULT_EESR_ERR_CHECK; + +	if (!cd->trscer_err_mask) +		cd->trscer_err_mask = DEFAULT_TRSCER_ERR_MASK;  }  static int sh_eth_check_reset(struct net_device *ndev) @@ -1294,7 +1301,7 @@ static int sh_eth_dev_init(struct net_device *ndev, bool start)  	/* Frame recv control (enable multiple-packets per rx irq) */  	sh_eth_write(ndev, RMCR_RNC, RMCR); -	sh_eth_write(ndev, DESC_I_RINT8 | DESC_I_RINT5 | DESC_I_TINT2, TRSCER); +	sh_eth_write(ndev, mdp->cd->trscer_err_mask, TRSCER);  	if (mdp->cd->bculr)  		sh_eth_write(ndev, 0x800, BCULR);	/* Burst sycle set */ @@ -1820,6 +1827,9 @@ static int sh_eth_get_settings(struct net_device *ndev,  	unsigned long flags;  	int ret; +	if (!mdp->phydev) +		return -ENODEV; +  	spin_lock_irqsave(&mdp->lock, flags);  	ret = phy_ethtool_gset(mdp->phydev, ecmd);  	spin_unlock_irqrestore(&mdp->lock, flags); @@ -1834,6 +1844,9 @@ static int sh_eth_set_settings(struct net_device *ndev,  	unsigned long flags;  	int ret; +	if (!mdp->phydev) +		return -ENODEV; +  	spin_lock_irqsave(&mdp->lock, flags);  	/* disable tx and rx */ @@ -1868,6 +1881,9 @@ static int sh_eth_nway_reset(struct net_device *ndev)  	unsigned long flags;  	int ret; +	if (!mdp->phydev) +		return -ENODEV; +  	spin_lock_irqsave(&mdp->lock, flags);  	ret = phy_start_aneg(mdp->phydev);  	spin_unlock_irqrestore(&mdp->lock, flags); @@ -2177,6 +2193,7 @@ static int sh_eth_close(struct net_device *ndev)  	if (mdp->phydev) {  		phy_stop(mdp->phydev);  		phy_disconnect(mdp->phydev); +		mdp->phydev = NULL;  	}  	free_irq(ndev->irq, ndev); @@ -2410,7 +2427,7 @@ static int sh_eth_tsu_purge_all(struct net_device *ndev)  	struct sh_eth_private *mdp = netdev_priv(ndev);  	int i, ret; -	if (unlikely(!mdp->cd->tsu)) +	if (!mdp->cd->tsu)  		return 0;  	for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++) { @@ -2433,7 +2450,7 @@ static void sh_eth_tsu_purge_mcast(struct net_device *ndev)  	void *reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);  	int i; -	if (unlikely(!mdp->cd->tsu)) +	if (!mdp->cd->tsu)  		return;  	for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++, reg_offset += 8) { @@ -2443,8 +2460,8 @@ static void sh_eth_tsu_purge_mcast(struct net_device *ndev)  	}  } -/* Multicast reception directions set */ -static void sh_eth_set_multicast_list(struct net_device *ndev) +/* Update promiscuous flag and multicast filter */ +static void sh_eth_set_rx_mode(struct net_device *ndev)  {  	struct sh_eth_private *mdp = netdev_priv(ndev);  	u32 ecmr_bits; @@ -2455,7 +2472,9 @@ static void sh_eth_set_multicast_list(struct net_device *ndev)  	/* Initial condition is MCT = 1, PRM = 0.  	 * Depending on ndev->flags, set PRM or clear MCT  	 */ -	ecmr_bits = (sh_eth_read(ndev, ECMR) & ~ECMR_PRM) | ECMR_MCT; +	ecmr_bits = sh_eth_read(ndev, ECMR) & ~ECMR_PRM; +	if (mdp->cd->tsu) +		ecmr_bits |= ECMR_MCT;  	if (!(ndev->flags & IFF_MULTICAST)) {  		sh_eth_tsu_purge_mcast(ndev); @@ -2484,9 +2503,6 @@ static void sh_eth_set_multicast_list(struct net_device *ndev)  				}  			}  		} -	} else { -		/* Normal, unicast/broadcast-only mode. */ -		ecmr_bits = (ecmr_bits & ~ECMR_PRM) | ECMR_MCT;  	}  	/* update the ethernet mode */ @@ -2694,6 +2710,7 @@ static const struct net_device_ops sh_eth_netdev_ops = {  	.ndo_stop		= sh_eth_close,  	.ndo_start_xmit		= sh_eth_start_xmit,  	.ndo_get_stats		= sh_eth_get_stats, +	.ndo_set_rx_mode	= sh_eth_set_rx_mode,  	.ndo_tx_timeout		= sh_eth_tx_timeout,  	.ndo_do_ioctl		= sh_eth_do_ioctl,  	.ndo_validate_addr	= eth_validate_addr, @@ -2706,7 +2723,7 @@ static const struct net_device_ops sh_eth_netdev_ops_tsu = {  	.ndo_stop		= sh_eth_close,  	.ndo_start_xmit		= sh_eth_start_xmit,  	.ndo_get_stats		= sh_eth_get_stats, -	.ndo_set_rx_mode	= sh_eth_set_multicast_list, +	.ndo_set_rx_mode	= sh_eth_set_rx_mode,  	.ndo_vlan_rx_add_vid	= sh_eth_vlan_rx_add_vid,  	.ndo_vlan_rx_kill_vid	= sh_eth_vlan_rx_kill_vid,  	.ndo_tx_timeout		= sh_eth_tx_timeout, diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index 22301bf9c21d..71f5de1171bd 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -369,6 +369,8 @@ enum DESC_I_BIT {  	DESC_I_RINT1 = 0x0001,  }; +#define DEFAULT_TRSCER_ERR_MASK (DESC_I_RINT8 | DESC_I_RINT5 | DESC_I_TINT2) +  /* RPADIR */  enum RPADIR_BIT {  	RPADIR_PADS1 = 0x20000, RPADIR_PADS0 = 0x10000, @@ -470,6 +472,9 @@ struct sh_eth_cpu_data {  	unsigned long tx_check;  	unsigned long eesr_err_check; +	/* Error mask */ +	unsigned long trscer_err_mask; +  	/* hardware features */  	unsigned long irq_flags; /* IRQ configuration flags */  	unsigned no_psr:1;	/* EtherC DO NOT have PSR */ diff --git a/drivers/net/ethernet/s6gmac.c b/drivers/net/ethernet/s6gmac.c deleted file mode 100644 index f537cbea20e5..000000000000 --- a/drivers/net/ethernet/s6gmac.c +++ /dev/null @@ -1,1058 +0,0 @@ -/* - * Ethernet driver for S6105 on chip network device - * (c)2008 emlix GmbH http://www.emlix.com - * Authors:	Oskar Schirmer <[email protected]> - *		Daniel Gloeckner <[email protected]> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/types.h> -#include <linux/delay.h> -#include <linux/spinlock.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/if.h> -#include <linux/stddef.h> -#include <linux/mii.h> -#include <linux/phy.h> -#include <linux/platform_device.h> -#include <variant/hardware.h> -#include <variant/dmac.h> - -#define DRV_NAME "s6gmac" -#define DRV_PRMT DRV_NAME ": " - - -/* register declarations */ - -#define S6_GMAC_MACCONF1	0x000 -#define S6_GMAC_MACCONF1_TXENA		0 -#define S6_GMAC_MACCONF1_SYNCTX		1 -#define S6_GMAC_MACCONF1_RXENA		2 -#define S6_GMAC_MACCONF1_SYNCRX		3 -#define S6_GMAC_MACCONF1_TXFLOWCTRL	4 -#define S6_GMAC_MACCONF1_RXFLOWCTRL	5 -#define S6_GMAC_MACCONF1_LOOPBACK	8 -#define S6_GMAC_MACCONF1_RESTXFUNC	16 -#define S6_GMAC_MACCONF1_RESRXFUNC	17 -#define S6_GMAC_MACCONF1_RESTXMACCTRL	18 -#define S6_GMAC_MACCONF1_RESRXMACCTRL	19 -#define S6_GMAC_MACCONF1_SIMULRES	30 -#define S6_GMAC_MACCONF1_SOFTRES	31 -#define S6_GMAC_MACCONF2	0x004 -#define S6_GMAC_MACCONF2_FULL		0 -#define S6_GMAC_MACCONF2_CRCENA		1 -#define S6_GMAC_MACCONF2_PADCRCENA	2 -#define S6_GMAC_MACCONF2_LENGTHFCHK	4 -#define S6_GMAC_MACCONF2_HUGEFRAMENA	5 -#define S6_GMAC_MACCONF2_IFMODE		8 -#define S6_GMAC_MACCONF2_IFMODE_NIBBLE		1 -#define S6_GMAC_MACCONF2_IFMODE_BYTE		2 -#define S6_GMAC_MACCONF2_IFMODE_MASK		3 -#define S6_GMAC_MACCONF2_PREAMBLELEN	12 -#define S6_GMAC_MACCONF2_PREAMBLELEN_MASK	0x0F -#define S6_GMAC_MACIPGIFG	0x008 -#define S6_GMAC_MACIPGIFG_B2BINTERPGAP	0 -#define S6_GMAC_MACIPGIFG_B2BINTERPGAP_MASK	0x7F -#define S6_GMAC_MACIPGIFG_MINIFGENFORCE	8 -#define S6_GMAC_MACIPGIFG_B2BINTERPGAP2	16 -#define S6_GMAC_MACIPGIFG_B2BINTERPGAP1	24 -#define S6_GMAC_MACHALFDUPLEX	0x00C -#define S6_GMAC_MACHALFDUPLEX_COLLISWIN	0 -#define S6_GMAC_MACHALFDUPLEX_COLLISWIN_MASK	0x3F -#define S6_GMAC_MACHALFDUPLEX_RETXMAX	12 -#define S6_GMAC_MACHALFDUPLEX_RETXMAX_MASK	0x0F -#define S6_GMAC_MACHALFDUPLEX_EXCESSDEF	16 -#define S6_GMAC_MACHALFDUPLEX_NOBACKOFF	17 -#define S6_GMAC_MACHALFDUPLEX_BPNOBCKOF	18 -#define S6_GMAC_MACHALFDUPLEX_ALTBEBENA	19 -#define S6_GMAC_MACHALFDUPLEX_ALTBEBTRN	20 -#define S6_GMAC_MACHALFDUPLEX_ALTBEBTR_MASK	0x0F -#define S6_GMAC_MACMAXFRAMELEN	0x010 -#define S6_GMAC_MACMIICONF	0x020 -#define S6_GMAC_MACMIICONF_CSEL		0 -#define S6_GMAC_MACMIICONF_CSEL_DIV10		0 -#define S6_GMAC_MACMIICONF_CSEL_DIV12		1 -#define S6_GMAC_MACMIICONF_CSEL_DIV14		2 -#define S6_GMAC_MACMIICONF_CSEL_DIV18		3 -#define S6_GMAC_MACMIICONF_CSEL_DIV24		4 -#define S6_GMAC_MACMIICONF_CSEL_DIV34		5 -#define S6_GMAC_MACMIICONF_CSEL_DIV68		6 -#define S6_GMAC_MACMIICONF_CSEL_DIV168		7 -#define S6_GMAC_MACMIICONF_CSEL_MASK		7 -#define S6_GMAC_MACMIICONF_PREAMBLESUPR	4 -#define S6_GMAC_MACMIICONF_SCANAUTOINCR	5 -#define S6_GMAC_MACMIICMD	0x024 -#define S6_GMAC_MACMIICMD_READ		0 -#define S6_GMAC_MACMIICMD_SCAN		1 -#define S6_GMAC_MACMIIADDR	0x028 -#define S6_GMAC_MACMIIADDR_REG		0 -#define S6_GMAC_MACMIIADDR_REG_MASK		0x1F -#define S6_GMAC_MACMIIADDR_PHY		8 -#define S6_GMAC_MACMIIADDR_PHY_MASK		0x1F -#define S6_GMAC_MACMIICTRL	0x02C -#define S6_GMAC_MACMIISTAT	0x030 -#define S6_GMAC_MACMIIINDI	0x034 -#define S6_GMAC_MACMIIINDI_BUSY		0 -#define S6_GMAC_MACMIIINDI_SCAN		1 -#define S6_GMAC_MACMIIINDI_INVAL	2 -#define S6_GMAC_MACINTERFSTAT	0x03C -#define S6_GMAC_MACINTERFSTAT_LINKFAIL	3 -#define S6_GMAC_MACINTERFSTAT_EXCESSDEF	9 -#define S6_GMAC_MACSTATADDR1	0x040 -#define S6_GMAC_MACSTATADDR2	0x044 - -#define S6_GMAC_FIFOCONF0	0x048 -#define S6_GMAC_FIFOCONF0_HSTRSTWT	0 -#define S6_GMAC_FIFOCONF0_HSTRSTSR	1 -#define S6_GMAC_FIFOCONF0_HSTRSTFR	2 -#define S6_GMAC_FIFOCONF0_HSTRSTST	3 -#define S6_GMAC_FIFOCONF0_HSTRSTFT	4 -#define S6_GMAC_FIFOCONF0_WTMENREQ	8 -#define S6_GMAC_FIFOCONF0_SRFENREQ	9 -#define S6_GMAC_FIFOCONF0_FRFENREQ	10 -#define S6_GMAC_FIFOCONF0_STFENREQ	11 -#define S6_GMAC_FIFOCONF0_FTFENREQ	12 -#define S6_GMAC_FIFOCONF0_WTMENRPLY	16 -#define S6_GMAC_FIFOCONF0_SRFENRPLY	17 -#define S6_GMAC_FIFOCONF0_FRFENRPLY	18 -#define S6_GMAC_FIFOCONF0_STFENRPLY	19 -#define S6_GMAC_FIFOCONF0_FTFENRPLY	20 -#define S6_GMAC_FIFOCONF1	0x04C -#define S6_GMAC_FIFOCONF2	0x050 -#define S6_GMAC_FIFOCONF2_CFGLWM	0 -#define S6_GMAC_FIFOCONF2_CFGHWM	16 -#define S6_GMAC_FIFOCONF3	0x054 -#define S6_GMAC_FIFOCONF3_CFGFTTH	0 -#define S6_GMAC_FIFOCONF3_CFGHWMFT	16 -#define S6_GMAC_FIFOCONF4	0x058 -#define S6_GMAC_FIFOCONF_RSV_PREVDROP	0 -#define S6_GMAC_FIFOCONF_RSV_RUNT	1 -#define S6_GMAC_FIFOCONF_RSV_FALSECAR	2 -#define S6_GMAC_FIFOCONF_RSV_CODEERR	3 -#define S6_GMAC_FIFOCONF_RSV_CRCERR	4 -#define S6_GMAC_FIFOCONF_RSV_LENGTHERR	5 -#define S6_GMAC_FIFOCONF_RSV_LENRANGE	6 -#define S6_GMAC_FIFOCONF_RSV_OK		7 -#define S6_GMAC_FIFOCONF_RSV_MULTICAST	8 -#define S6_GMAC_FIFOCONF_RSV_BROADCAST	9 -#define S6_GMAC_FIFOCONF_RSV_DRIBBLE	10 -#define S6_GMAC_FIFOCONF_RSV_CTRLFRAME	11 -#define S6_GMAC_FIFOCONF_RSV_PAUSECTRL	12 -#define S6_GMAC_FIFOCONF_RSV_UNOPCODE	13 -#define S6_GMAC_FIFOCONF_RSV_VLANTAG	14 -#define S6_GMAC_FIFOCONF_RSV_LONGEVENT	15 -#define S6_GMAC_FIFOCONF_RSV_TRUNCATED	16 -#define S6_GMAC_FIFOCONF_RSV_MASK		0x3FFFF -#define S6_GMAC_FIFOCONF5	0x05C -#define S6_GMAC_FIFOCONF5_DROPLT64	18 -#define S6_GMAC_FIFOCONF5_CFGBYTM	19 -#define S6_GMAC_FIFOCONF5_RXDROPSIZE	20 -#define S6_GMAC_FIFOCONF5_RXDROPSIZE_MASK	0xF - -#define S6_GMAC_STAT_REGS	0x080 -#define S6_GMAC_STAT_SIZE_MIN		12 -#define S6_GMAC_STATTR64	0x080 -#define S6_GMAC_STATTR64_SIZE		18 -#define S6_GMAC_STATTR127	0x084 -#define S6_GMAC_STATTR127_SIZE		18 -#define S6_GMAC_STATTR255	0x088 -#define S6_GMAC_STATTR255_SIZE		18 -#define S6_GMAC_STATTR511	0x08C -#define S6_GMAC_STATTR511_SIZE		18 -#define S6_GMAC_STATTR1K	0x090 -#define S6_GMAC_STATTR1K_SIZE		18 -#define S6_GMAC_STATTRMAX	0x094 -#define S6_GMAC_STATTRMAX_SIZE		18 -#define S6_GMAC_STATTRMGV	0x098 -#define S6_GMAC_STATTRMGV_SIZE		18 -#define S6_GMAC_STATRBYT	0x09C -#define S6_GMAC_STATRBYT_SIZE		24 -#define S6_GMAC_STATRPKT	0x0A0 -#define S6_GMAC_STATRPKT_SIZE		18 -#define S6_GMAC_STATRFCS	0x0A4 -#define S6_GMAC_STATRFCS_SIZE		12 -#define S6_GMAC_STATRMCA	0x0A8 -#define S6_GMAC_STATRMCA_SIZE		18 -#define S6_GMAC_STATRBCA	0x0AC -#define S6_GMAC_STATRBCA_SIZE		22 -#define S6_GMAC_STATRXCF	0x0B0 -#define S6_GMAC_STATRXCF_SIZE		18 -#define S6_GMAC_STATRXPF	0x0B4 -#define S6_GMAC_STATRXPF_SIZE		12 -#define S6_GMAC_STATRXUO	0x0B8 -#define S6_GMAC_STATRXUO_SIZE		12 -#define S6_GMAC_STATRALN	0x0BC -#define S6_GMAC_STATRALN_SIZE		12 -#define S6_GMAC_STATRFLR	0x0C0 -#define S6_GMAC_STATRFLR_SIZE		16 -#define S6_GMAC_STATRCDE	0x0C4 -#define S6_GMAC_STATRCDE_SIZE		12 -#define S6_GMAC_STATRCSE	0x0C8 -#define S6_GMAC_STATRCSE_SIZE		12 -#define S6_GMAC_STATRUND	0x0CC -#define S6_GMAC_STATRUND_SIZE		12 -#define S6_GMAC_STATROVR	0x0D0 -#define S6_GMAC_STATROVR_SIZE		12 -#define S6_GMAC_STATRFRG	0x0D4 -#define S6_GMAC_STATRFRG_SIZE		12 -#define S6_GMAC_STATRJBR	0x0D8 -#define S6_GMAC_STATRJBR_SIZE		12 -#define S6_GMAC_STATRDRP	0x0DC -#define S6_GMAC_STATRDRP_SIZE		12 -#define S6_GMAC_STATTBYT	0x0E0 -#define S6_GMAC_STATTBYT_SIZE		24 -#define S6_GMAC_STATTPKT	0x0E4 -#define S6_GMAC_STATTPKT_SIZE		18 -#define S6_GMAC_STATTMCA	0x0E8 -#define S6_GMAC_STATTMCA_SIZE		18 -#define S6_GMAC_STATTBCA	0x0EC -#define S6_GMAC_STATTBCA_SIZE		18 -#define S6_GMAC_STATTXPF	0x0F0 -#define S6_GMAC_STATTXPF_SIZE		12 -#define S6_GMAC_STATTDFR	0x0F4 -#define S6_GMAC_STATTDFR_SIZE		12 -#define S6_GMAC_STATTEDF	0x0F8 -#define S6_GMAC_STATTEDF_SIZE		12 -#define S6_GMAC_STATTSCL	0x0FC -#define S6_GMAC_STATTSCL_SIZE		12 -#define S6_GMAC_STATTMCL	0x100 -#define S6_GMAC_STATTMCL_SIZE		12 -#define S6_GMAC_STATTLCL	0x104 -#define S6_GMAC_STATTLCL_SIZE		12 -#define S6_GMAC_STATTXCL	0x108 -#define S6_GMAC_STATTXCL_SIZE		12 -#define S6_GMAC_STATTNCL	0x10C -#define S6_GMAC_STATTNCL_SIZE		13 -#define S6_GMAC_STATTPFH	0x110 -#define S6_GMAC_STATTPFH_SIZE		12 -#define S6_GMAC_STATTDRP	0x114 -#define S6_GMAC_STATTDRP_SIZE		12 -#define S6_GMAC_STATTJBR	0x118 -#define S6_GMAC_STATTJBR_SIZE		12 -#define S6_GMAC_STATTFCS	0x11C -#define S6_GMAC_STATTFCS_SIZE		12 -#define S6_GMAC_STATTXCF	0x120 -#define S6_GMAC_STATTXCF_SIZE		12 -#define S6_GMAC_STATTOVR	0x124 -#define S6_GMAC_STATTOVR_SIZE		12 -#define S6_GMAC_STATTUND	0x128 -#define S6_GMAC_STATTUND_SIZE		12 -#define S6_GMAC_STATTFRG	0x12C -#define S6_GMAC_STATTFRG_SIZE		12 -#define S6_GMAC_STATCARRY(n)	(0x130 + 4*(n)) -#define S6_GMAC_STATCARRYMSK(n)	(0x138 + 4*(n)) -#define S6_GMAC_STATCARRY1_RDRP		0 -#define S6_GMAC_STATCARRY1_RJBR		1 -#define S6_GMAC_STATCARRY1_RFRG		2 -#define S6_GMAC_STATCARRY1_ROVR		3 -#define S6_GMAC_STATCARRY1_RUND		4 -#define S6_GMAC_STATCARRY1_RCSE		5 -#define S6_GMAC_STATCARRY1_RCDE		6 -#define S6_GMAC_STATCARRY1_RFLR		7 -#define S6_GMAC_STATCARRY1_RALN		8 -#define S6_GMAC_STATCARRY1_RXUO		9 -#define S6_GMAC_STATCARRY1_RXPF		10 -#define S6_GMAC_STATCARRY1_RXCF		11 -#define S6_GMAC_STATCARRY1_RBCA		12 -#define S6_GMAC_STATCARRY1_RMCA		13 -#define S6_GMAC_STATCARRY1_RFCS		14 -#define S6_GMAC_STATCARRY1_RPKT		15 -#define S6_GMAC_STATCARRY1_RBYT		16 -#define S6_GMAC_STATCARRY1_TRMGV	25 -#define S6_GMAC_STATCARRY1_TRMAX	26 -#define S6_GMAC_STATCARRY1_TR1K		27 -#define S6_GMAC_STATCARRY1_TR511	28 -#define S6_GMAC_STATCARRY1_TR255	29 -#define S6_GMAC_STATCARRY1_TR127	30 -#define S6_GMAC_STATCARRY1_TR64		31 -#define S6_GMAC_STATCARRY2_TDRP		0 -#define S6_GMAC_STATCARRY2_TPFH		1 -#define S6_GMAC_STATCARRY2_TNCL		2 -#define S6_GMAC_STATCARRY2_TXCL		3 -#define S6_GMAC_STATCARRY2_TLCL		4 -#define S6_GMAC_STATCARRY2_TMCL		5 -#define S6_GMAC_STATCARRY2_TSCL		6 -#define S6_GMAC_STATCARRY2_TEDF		7 -#define S6_GMAC_STATCARRY2_TDFR		8 -#define S6_GMAC_STATCARRY2_TXPF		9 -#define S6_GMAC_STATCARRY2_TBCA		10 -#define S6_GMAC_STATCARRY2_TMCA		11 -#define S6_GMAC_STATCARRY2_TPKT		12 -#define S6_GMAC_STATCARRY2_TBYT		13 -#define S6_GMAC_STATCARRY2_TFRG		14 -#define S6_GMAC_STATCARRY2_TUND		15 -#define S6_GMAC_STATCARRY2_TOVR		16 -#define S6_GMAC_STATCARRY2_TXCF		17 -#define S6_GMAC_STATCARRY2_TFCS		18 -#define S6_GMAC_STATCARRY2_TJBR		19 - -#define S6_GMAC_HOST_PBLKCTRL	0x140 -#define S6_GMAC_HOST_PBLKCTRL_TXENA	0 -#define S6_GMAC_HOST_PBLKCTRL_RXENA	1 -#define S6_GMAC_HOST_PBLKCTRL_TXSRES	2 -#define S6_GMAC_HOST_PBLKCTRL_RXSRES	3 -#define S6_GMAC_HOST_PBLKCTRL_TXBSIZ	8 -#define S6_GMAC_HOST_PBLKCTRL_RXBSIZ	12 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_16		4 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_32		5 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_64		6 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_128		7 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_MASK		0xF -#define S6_GMAC_HOST_PBLKCTRL_STATENA	16 -#define S6_GMAC_HOST_PBLKCTRL_STATAUTOZ	17 -#define S6_GMAC_HOST_PBLKCTRL_STATCLEAR	18 -#define S6_GMAC_HOST_PBLKCTRL_RGMII	19 -#define S6_GMAC_HOST_INTMASK	0x144 -#define S6_GMAC_HOST_INTSTAT	0x148 -#define S6_GMAC_HOST_INT_TXBURSTOVER	3 -#define S6_GMAC_HOST_INT_TXPREWOVER	4 -#define S6_GMAC_HOST_INT_RXBURSTUNDER	5 -#define S6_GMAC_HOST_INT_RXPOSTRFULL	6 -#define S6_GMAC_HOST_INT_RXPOSTRUNDER	7 -#define S6_GMAC_HOST_RXFIFOHWM	0x14C -#define S6_GMAC_HOST_CTRLFRAMXP	0x150 -#define S6_GMAC_HOST_DSTADDRLO(n) (0x160 + 8*(n)) -#define S6_GMAC_HOST_DSTADDRHI(n) (0x164 + 8*(n)) -#define S6_GMAC_HOST_DSTMASKLO(n) (0x180 + 8*(n)) -#define S6_GMAC_HOST_DSTMASKHI(n) (0x184 + 8*(n)) - -#define S6_GMAC_BURST_PREWR	0x1B0 -#define S6_GMAC_BURST_PREWR_LEN		0 -#define S6_GMAC_BURST_PREWR_LEN_MASK		((1 << 20) - 1) -#define S6_GMAC_BURST_PREWR_CFE		20 -#define S6_GMAC_BURST_PREWR_PPE		21 -#define S6_GMAC_BURST_PREWR_FCS		22 -#define S6_GMAC_BURST_PREWR_PAD		23 -#define S6_GMAC_BURST_POSTRD	0x1D0 -#define S6_GMAC_BURST_POSTRD_LEN	0 -#define S6_GMAC_BURST_POSTRD_LEN_MASK		((1 << 20) - 1) -#define S6_GMAC_BURST_POSTRD_DROP	20 - - -/* data handling */ - -#define S6_NUM_TX_SKB	8	/* must be larger than TX fifo size */ -#define S6_NUM_RX_SKB	16 -#define S6_MAX_FRLEN	1536 - -struct s6gmac { -	u32 reg; -	u32 tx_dma; -	u32 rx_dma; -	u32 io; -	u8 tx_chan; -	u8 rx_chan; -	spinlock_t lock; -	u8 tx_skb_i, tx_skb_o; -	u8 rx_skb_i, rx_skb_o; -	struct sk_buff *tx_skb[S6_NUM_TX_SKB]; -	struct sk_buff *rx_skb[S6_NUM_RX_SKB]; -	unsigned long carry[sizeof(struct net_device_stats) / sizeof(long)]; -	unsigned long stats[sizeof(struct net_device_stats) / sizeof(long)]; -	struct phy_device *phydev; -	struct { -		struct mii_bus *bus; -		int irq[PHY_MAX_ADDR]; -	} mii; -	struct { -		unsigned int mbit; -		u8 giga; -		u8 isup; -		u8 full; -	} link; -}; - -static void s6gmac_rx_fillfifo(struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	struct sk_buff *skb; -	while ((((u8)(pd->rx_skb_i - pd->rx_skb_o)) < S6_NUM_RX_SKB) && -	       (!s6dmac_fifo_full(pd->rx_dma, pd->rx_chan)) && -	       (skb = netdev_alloc_skb(dev, S6_MAX_FRLEN + 2))) { -		pd->rx_skb[(pd->rx_skb_i++) % S6_NUM_RX_SKB] = skb; -		s6dmac_put_fifo_cache(pd->rx_dma, pd->rx_chan, -			pd->io, (u32)skb->data, S6_MAX_FRLEN); -	} -} - -static void s6gmac_rx_interrupt(struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	u32 pfx; -	struct sk_buff *skb; -	while (((u8)(pd->rx_skb_i - pd->rx_skb_o)) > -			s6dmac_pending_count(pd->rx_dma, pd->rx_chan)) { -		skb = pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB]; -		pfx = readl(pd->reg + S6_GMAC_BURST_POSTRD); -		if (pfx & (1 << S6_GMAC_BURST_POSTRD_DROP)) { -			dev_kfree_skb_irq(skb); -		} else { -			skb_put(skb, (pfx >> S6_GMAC_BURST_POSTRD_LEN) -				& S6_GMAC_BURST_POSTRD_LEN_MASK); -			skb->protocol = eth_type_trans(skb, dev); -			skb->ip_summed = CHECKSUM_UNNECESSARY; -			netif_rx(skb); -		} -	} -} - -static void s6gmac_tx_interrupt(struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	while (((u8)(pd->tx_skb_i - pd->tx_skb_o)) > -			s6dmac_pending_count(pd->tx_dma, pd->tx_chan)) { -		dev_kfree_skb_irq(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]); -	} -	if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) -		netif_wake_queue(dev); -} - -struct s6gmac_statinf { -	unsigned reg_size : 4; /* 0: unused */ -	unsigned reg_off : 6; -	unsigned net_index : 6; -}; - -#define S6_STATS_B (8 * sizeof(u32)) -#define S6_STATS_C(b, r, f) [b] = { \ -	BUILD_BUG_ON_ZERO(r##_SIZE < S6_GMAC_STAT_SIZE_MIN) + \ -	BUILD_BUG_ON_ZERO((r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1)) \ -			>= (1<<4)) + \ -	r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1), \ -	BUILD_BUG_ON_ZERO(((unsigned)((r - S6_GMAC_STAT_REGS) / sizeof(u32))) \ -			>= ((1<<6)-1)) + \ -	(r - S6_GMAC_STAT_REGS) / sizeof(u32), \ -	BUILD_BUG_ON_ZERO((offsetof(struct net_device_stats, f)) \ -			% sizeof(unsigned long)) + \ -	BUILD_BUG_ON_ZERO((((unsigned)(offsetof(struct net_device_stats, f)) \ -			/ sizeof(unsigned long)) >= (1<<6))) + \ -	BUILD_BUG_ON_ZERO((sizeof(((struct net_device_stats *)0)->f) \ -			!= sizeof(unsigned long))) + \ -	(offsetof(struct net_device_stats, f)) / sizeof(unsigned long)}, - -static const struct s6gmac_statinf statinf[2][S6_STATS_B] = { { -	S6_STATS_C(S6_GMAC_STATCARRY1_RBYT, S6_GMAC_STATRBYT, rx_bytes) -	S6_STATS_C(S6_GMAC_STATCARRY1_RPKT, S6_GMAC_STATRPKT, rx_packets) -	S6_STATS_C(S6_GMAC_STATCARRY1_RFCS, S6_GMAC_STATRFCS, rx_crc_errors) -	S6_STATS_C(S6_GMAC_STATCARRY1_RMCA, S6_GMAC_STATRMCA, multicast) -	S6_STATS_C(S6_GMAC_STATCARRY1_RALN, S6_GMAC_STATRALN, rx_frame_errors) -	S6_STATS_C(S6_GMAC_STATCARRY1_RFLR, S6_GMAC_STATRFLR, rx_length_errors) -	S6_STATS_C(S6_GMAC_STATCARRY1_RCDE, S6_GMAC_STATRCDE, rx_missed_errors) -	S6_STATS_C(S6_GMAC_STATCARRY1_RUND, S6_GMAC_STATRUND, rx_length_errors) -	S6_STATS_C(S6_GMAC_STATCARRY1_ROVR, S6_GMAC_STATROVR, rx_length_errors) -	S6_STATS_C(S6_GMAC_STATCARRY1_RFRG, S6_GMAC_STATRFRG, rx_crc_errors) -	S6_STATS_C(S6_GMAC_STATCARRY1_RJBR, S6_GMAC_STATRJBR, rx_crc_errors) -	S6_STATS_C(S6_GMAC_STATCARRY1_RDRP, S6_GMAC_STATRDRP, rx_dropped) -}, { -	S6_STATS_C(S6_GMAC_STATCARRY2_TBYT, S6_GMAC_STATTBYT, tx_bytes) -	S6_STATS_C(S6_GMAC_STATCARRY2_TPKT, S6_GMAC_STATTPKT, tx_packets) -	S6_STATS_C(S6_GMAC_STATCARRY2_TEDF, S6_GMAC_STATTEDF, tx_aborted_errors) -	S6_STATS_C(S6_GMAC_STATCARRY2_TXCL, S6_GMAC_STATTXCL, tx_aborted_errors) -	S6_STATS_C(S6_GMAC_STATCARRY2_TNCL, S6_GMAC_STATTNCL, collisions) -	S6_STATS_C(S6_GMAC_STATCARRY2_TDRP, S6_GMAC_STATTDRP, tx_dropped) -	S6_STATS_C(S6_GMAC_STATCARRY2_TJBR, S6_GMAC_STATTJBR, tx_errors) -	S6_STATS_C(S6_GMAC_STATCARRY2_TFCS, S6_GMAC_STATTFCS, tx_errors) -	S6_STATS_C(S6_GMAC_STATCARRY2_TOVR, S6_GMAC_STATTOVR, tx_errors) -	S6_STATS_C(S6_GMAC_STATCARRY2_TUND, S6_GMAC_STATTUND, tx_errors) -	S6_STATS_C(S6_GMAC_STATCARRY2_TFRG, S6_GMAC_STATTFRG, tx_errors) -} }; - -static void s6gmac_stats_collect(struct s6gmac *pd, -		const struct s6gmac_statinf *inf) -{ -	int b; -	for (b = 0; b < S6_STATS_B; b++) { -		if (inf[b].reg_size) { -			pd->stats[inf[b].net_index] += -				readl(pd->reg + S6_GMAC_STAT_REGS -					+ sizeof(u32) * inf[b].reg_off); -		} -	} -} - -static void s6gmac_stats_carry(struct s6gmac *pd, -		const struct s6gmac_statinf *inf, u32 mask) -{ -	int b; -	while (mask) { -		b = fls(mask) - 1; -		mask &= ~(1 << b); -		pd->carry[inf[b].net_index] += (1 << inf[b].reg_size); -	} -} - -static inline u32 s6gmac_stats_pending(struct s6gmac *pd, int carry) -{ -	int r = readl(pd->reg + S6_GMAC_STATCARRY(carry)) & -		~readl(pd->reg + S6_GMAC_STATCARRYMSK(carry)); -	return r; -} - -static inline void s6gmac_stats_interrupt(struct s6gmac *pd, int carry) -{ -	u32 mask; -	mask = s6gmac_stats_pending(pd, carry); -	if (mask) { -		writel(mask, pd->reg + S6_GMAC_STATCARRY(carry)); -		s6gmac_stats_carry(pd, &statinf[carry][0], mask); -	} -} - -static irqreturn_t s6gmac_interrupt(int irq, void *dev_id) -{ -	struct net_device *dev = (struct net_device *)dev_id; -	struct s6gmac *pd = netdev_priv(dev); -	if (!dev) -		return IRQ_NONE; -	spin_lock(&pd->lock); -	if (s6dmac_termcnt_irq(pd->rx_dma, pd->rx_chan)) -		s6gmac_rx_interrupt(dev); -	s6gmac_rx_fillfifo(dev); -	if (s6dmac_termcnt_irq(pd->tx_dma, pd->tx_chan)) -		s6gmac_tx_interrupt(dev); -	s6gmac_stats_interrupt(pd, 0); -	s6gmac_stats_interrupt(pd, 1); -	spin_unlock(&pd->lock); -	return IRQ_HANDLED; -} - -static inline void s6gmac_set_dstaddr(struct s6gmac *pd, int n, -	u32 addrlo, u32 addrhi, u32 masklo, u32 maskhi) -{ -	writel(addrlo, pd->reg + S6_GMAC_HOST_DSTADDRLO(n)); -	writel(addrhi, pd->reg + S6_GMAC_HOST_DSTADDRHI(n)); -	writel(masklo, pd->reg + S6_GMAC_HOST_DSTMASKLO(n)); -	writel(maskhi, pd->reg + S6_GMAC_HOST_DSTMASKHI(n)); -} - -static inline void s6gmac_stop_device(struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	writel(0, pd->reg + S6_GMAC_MACCONF1); -} - -static inline void s6gmac_init_device(struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	int is_rgmii = !!(pd->phydev->supported -		& (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)); -#if 0 -	writel(1 << S6_GMAC_MACCONF1_SYNCTX | -		1 << S6_GMAC_MACCONF1_SYNCRX | -		1 << S6_GMAC_MACCONF1_TXFLOWCTRL | -		1 << S6_GMAC_MACCONF1_RXFLOWCTRL | -		1 << S6_GMAC_MACCONF1_RESTXFUNC | -		1 << S6_GMAC_MACCONF1_RESRXFUNC | -		1 << S6_GMAC_MACCONF1_RESTXMACCTRL | -		1 << S6_GMAC_MACCONF1_RESRXMACCTRL, -		pd->reg + S6_GMAC_MACCONF1); -#endif -	writel(1 << S6_GMAC_MACCONF1_SOFTRES, pd->reg + S6_GMAC_MACCONF1); -	udelay(1000); -	writel(1 << S6_GMAC_MACCONF1_TXENA | 1 << S6_GMAC_MACCONF1_RXENA, -		pd->reg + S6_GMAC_MACCONF1); -	writel(1 << S6_GMAC_HOST_PBLKCTRL_TXSRES | -		1 << S6_GMAC_HOST_PBLKCTRL_RXSRES, -		pd->reg + S6_GMAC_HOST_PBLKCTRL); -	writel(S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ | -		S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ | -		1 << S6_GMAC_HOST_PBLKCTRL_STATENA | -		1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR | -		is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII, -		pd->reg + S6_GMAC_HOST_PBLKCTRL); -	writel(1 << S6_GMAC_MACCONF1_TXENA | -		1 << S6_GMAC_MACCONF1_RXENA | -		(dev->flags & IFF_LOOPBACK ? 1 : 0) -			<< S6_GMAC_MACCONF1_LOOPBACK, -		pd->reg + S6_GMAC_MACCONF1); -	writel(dev->mtu && (dev->mtu < (S6_MAX_FRLEN - ETH_HLEN-ETH_FCS_LEN)) ? -			dev->mtu+ETH_HLEN+ETH_FCS_LEN : S6_MAX_FRLEN, -		pd->reg + S6_GMAC_MACMAXFRAMELEN); -	writel((pd->link.full ? 1 : 0) << S6_GMAC_MACCONF2_FULL | -		1 << S6_GMAC_MACCONF2_PADCRCENA | -		1 << S6_GMAC_MACCONF2_LENGTHFCHK | -		(pd->link.giga ? -			S6_GMAC_MACCONF2_IFMODE_BYTE : -			S6_GMAC_MACCONF2_IFMODE_NIBBLE) -			<< S6_GMAC_MACCONF2_IFMODE | -		7 << S6_GMAC_MACCONF2_PREAMBLELEN, -		pd->reg + S6_GMAC_MACCONF2); -	writel(0, pd->reg + S6_GMAC_MACSTATADDR1); -	writel(0, pd->reg + S6_GMAC_MACSTATADDR2); -	writel(1 << S6_GMAC_FIFOCONF0_WTMENREQ | -		1 << S6_GMAC_FIFOCONF0_SRFENREQ | -		1 << S6_GMAC_FIFOCONF0_FRFENREQ | -		1 << S6_GMAC_FIFOCONF0_STFENREQ | -		1 << S6_GMAC_FIFOCONF0_FTFENREQ, -		pd->reg + S6_GMAC_FIFOCONF0); -	writel(128 << S6_GMAC_FIFOCONF3_CFGFTTH | -		128 << S6_GMAC_FIFOCONF3_CFGHWMFT, -		pd->reg + S6_GMAC_FIFOCONF3); -	writel((S6_GMAC_FIFOCONF_RSV_MASK & ~( -			1 << S6_GMAC_FIFOCONF_RSV_RUNT | -			1 << S6_GMAC_FIFOCONF_RSV_CRCERR | -			1 << S6_GMAC_FIFOCONF_RSV_OK | -			1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE | -			1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME | -			1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL | -			1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE | -			1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED)) | -		1 << S6_GMAC_FIFOCONF5_DROPLT64 | -		pd->link.giga << S6_GMAC_FIFOCONF5_CFGBYTM | -		1 << S6_GMAC_FIFOCONF5_RXDROPSIZE, -		pd->reg + S6_GMAC_FIFOCONF5); -	writel(1 << S6_GMAC_FIFOCONF_RSV_RUNT | -		1 << S6_GMAC_FIFOCONF_RSV_CRCERR | -		1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE | -		1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME | -		1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL | -		1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE | -		1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED, -		pd->reg + S6_GMAC_FIFOCONF4); -	s6gmac_set_dstaddr(pd, 0, -		0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0x0000FFFF); -	s6gmac_set_dstaddr(pd, 1, -		dev->dev_addr[5] | -		dev->dev_addr[4] << 8 | -		dev->dev_addr[3] << 16 | -		dev->dev_addr[2] << 24, -		dev->dev_addr[1] | -		dev->dev_addr[0] << 8, -		0xFFFFFFFF, 0x0000FFFF); -	s6gmac_set_dstaddr(pd, 2, -		0x00000000, 0x00000100, 0x00000000, 0x00000100); -	s6gmac_set_dstaddr(pd, 3, -		0x00000000, 0x00000000, 0x00000000, 0x00000000); -	writel(1 << S6_GMAC_HOST_PBLKCTRL_TXENA | -		1 << S6_GMAC_HOST_PBLKCTRL_RXENA | -		S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ | -		S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ | -		1 << S6_GMAC_HOST_PBLKCTRL_STATENA | -		1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR | -		is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII, -		pd->reg + S6_GMAC_HOST_PBLKCTRL); -} - -static void s6mii_enable(struct s6gmac *pd) -{ -	writel(readl(pd->reg + S6_GMAC_MACCONF1) & -		~(1 << S6_GMAC_MACCONF1_SOFTRES), -		pd->reg + S6_GMAC_MACCONF1); -	writel((readl(pd->reg + S6_GMAC_MACMIICONF) -		& ~(S6_GMAC_MACMIICONF_CSEL_MASK << S6_GMAC_MACMIICONF_CSEL)) -		| (S6_GMAC_MACMIICONF_CSEL_DIV168 << S6_GMAC_MACMIICONF_CSEL), -		pd->reg + S6_GMAC_MACMIICONF); -} - -static int s6mii_busy(struct s6gmac *pd, int tmo) -{ -	while (readl(pd->reg + S6_GMAC_MACMIIINDI)) { -		if (--tmo == 0) -			return -ETIME; -		udelay(64); -	} -	return 0; -} - -static int s6mii_read(struct mii_bus *bus, int phy_addr, int regnum) -{ -	struct s6gmac *pd = bus->priv; -	s6mii_enable(pd); -	if (s6mii_busy(pd, 256)) -		return -ETIME; -	writel(phy_addr << S6_GMAC_MACMIIADDR_PHY | -		regnum << S6_GMAC_MACMIIADDR_REG, -		pd->reg + S6_GMAC_MACMIIADDR); -	writel(1 << S6_GMAC_MACMIICMD_READ, pd->reg + S6_GMAC_MACMIICMD); -	writel(0, pd->reg + S6_GMAC_MACMIICMD); -	if (s6mii_busy(pd, 256)) -		return -ETIME; -	return (u16)readl(pd->reg + S6_GMAC_MACMIISTAT); -} - -static int s6mii_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value) -{ -	struct s6gmac *pd = bus->priv; -	s6mii_enable(pd); -	if (s6mii_busy(pd, 256)) -		return -ETIME; -	writel(phy_addr << S6_GMAC_MACMIIADDR_PHY | -		regnum << S6_GMAC_MACMIIADDR_REG, -		pd->reg + S6_GMAC_MACMIIADDR); -	writel(value, pd->reg + S6_GMAC_MACMIICTRL); -	if (s6mii_busy(pd, 256)) -		return -ETIME; -	return 0; -} - -static int s6mii_reset(struct mii_bus *bus) -{ -	struct s6gmac *pd = bus->priv; -	s6mii_enable(pd); -	if (s6mii_busy(pd, PHY_INIT_TIMEOUT)) -		return -ETIME; -	return 0; -} - -static void s6gmac_set_rgmii_txclock(struct s6gmac *pd) -{ -	u32 pllsel = readl(S6_REG_GREG1 + S6_GREG1_PLLSEL); -	pllsel &= ~(S6_GREG1_PLLSEL_GMAC_MASK << S6_GREG1_PLLSEL_GMAC); -	switch (pd->link.mbit) { -	case 10: -		pllsel |= S6_GREG1_PLLSEL_GMAC_2500KHZ << S6_GREG1_PLLSEL_GMAC; -		break; -	case 100: -		pllsel |= S6_GREG1_PLLSEL_GMAC_25MHZ << S6_GREG1_PLLSEL_GMAC; -		break; -	case 1000: -		pllsel |= S6_GREG1_PLLSEL_GMAC_125MHZ << S6_GREG1_PLLSEL_GMAC; -		break; -	default: -		return; -	} -	writel(pllsel, S6_REG_GREG1 + S6_GREG1_PLLSEL); -} - -static inline void s6gmac_linkisup(struct net_device *dev, int isup) -{ -	struct s6gmac *pd = netdev_priv(dev); -	struct phy_device *phydev = pd->phydev; - -	pd->link.full = phydev->duplex; -	pd->link.giga = (phydev->speed == 1000); -	if (pd->link.mbit != phydev->speed) { -		pd->link.mbit = phydev->speed; -		s6gmac_set_rgmii_txclock(pd); -	} -	pd->link.isup = isup; -	if (isup) -		netif_carrier_on(dev); -	phy_print_status(phydev); -} - -static void s6gmac_adjust_link(struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	struct phy_device *phydev = pd->phydev; -	if (pd->link.isup && -			(!phydev->link || -			(pd->link.mbit != phydev->speed) || -			(pd->link.full != phydev->duplex))) { -		pd->link.isup = 0; -		netif_tx_disable(dev); -		if (!phydev->link) { -			netif_carrier_off(dev); -			phy_print_status(phydev); -		} -	} -	if (!pd->link.isup && phydev->link) { -		if (pd->link.full != phydev->duplex) { -			u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2); -			if (phydev->duplex) -				maccfg |= 1 << S6_GMAC_MACCONF2_FULL; -			else -				maccfg &= ~(1 << S6_GMAC_MACCONF2_FULL); -			writel(maccfg, pd->reg + S6_GMAC_MACCONF2); -		} - -		if (pd->link.giga != (phydev->speed == 1000)) { -			u32 fifocfg = readl(pd->reg + S6_GMAC_FIFOCONF5); -			u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2); -			maccfg &= ~(S6_GMAC_MACCONF2_IFMODE_MASK -				     << S6_GMAC_MACCONF2_IFMODE); -			if (phydev->speed == 1000) { -				fifocfg |= 1 << S6_GMAC_FIFOCONF5_CFGBYTM; -				maccfg |= S6_GMAC_MACCONF2_IFMODE_BYTE -					   << S6_GMAC_MACCONF2_IFMODE; -			} else { -				fifocfg &= ~(1 << S6_GMAC_FIFOCONF5_CFGBYTM); -				maccfg |= S6_GMAC_MACCONF2_IFMODE_NIBBLE -					   << S6_GMAC_MACCONF2_IFMODE; -			} -			writel(fifocfg, pd->reg + S6_GMAC_FIFOCONF5); -			writel(maccfg, pd->reg + S6_GMAC_MACCONF2); -		} - -		if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) -			netif_wake_queue(dev); -		s6gmac_linkisup(dev, 1); -	} -} - -static inline int s6gmac_phy_start(struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	int i = 0; -	struct phy_device *p = NULL; -	while ((i < PHY_MAX_ADDR) && (!(p = pd->mii.bus->phy_map[i]))) -		i++; -	p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link, -			PHY_INTERFACE_MODE_RGMII); -	if (IS_ERR(p)) { -		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); -		return PTR_ERR(p); -	} -	p->supported &= PHY_GBIT_FEATURES; -	p->advertising = p->supported; -	pd->phydev = p; -	return 0; -} - -static inline void s6gmac_init_stats(struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	u32 mask; -	mask =	1 << S6_GMAC_STATCARRY1_RDRP | -		1 << S6_GMAC_STATCARRY1_RJBR | -		1 << S6_GMAC_STATCARRY1_RFRG | -		1 << S6_GMAC_STATCARRY1_ROVR | -		1 << S6_GMAC_STATCARRY1_RUND | -		1 << S6_GMAC_STATCARRY1_RCDE | -		1 << S6_GMAC_STATCARRY1_RFLR | -		1 << S6_GMAC_STATCARRY1_RALN | -		1 << S6_GMAC_STATCARRY1_RMCA | -		1 << S6_GMAC_STATCARRY1_RFCS | -		1 << S6_GMAC_STATCARRY1_RPKT | -		1 << S6_GMAC_STATCARRY1_RBYT; -	writel(mask, pd->reg + S6_GMAC_STATCARRY(0)); -	writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(0)); -	mask =	1 << S6_GMAC_STATCARRY2_TDRP | -		1 << S6_GMAC_STATCARRY2_TNCL | -		1 << S6_GMAC_STATCARRY2_TXCL | -		1 << S6_GMAC_STATCARRY2_TEDF | -		1 << S6_GMAC_STATCARRY2_TPKT | -		1 << S6_GMAC_STATCARRY2_TBYT | -		1 << S6_GMAC_STATCARRY2_TFRG | -		1 << S6_GMAC_STATCARRY2_TUND | -		1 << S6_GMAC_STATCARRY2_TOVR | -		1 << S6_GMAC_STATCARRY2_TFCS | -		1 << S6_GMAC_STATCARRY2_TJBR; -	writel(mask, pd->reg + S6_GMAC_STATCARRY(1)); -	writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(1)); -} - -static inline void s6gmac_init_dmac(struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	s6dmac_disable_chan(pd->tx_dma, pd->tx_chan); -	s6dmac_disable_chan(pd->rx_dma, pd->rx_chan); -	s6dmac_disable_error_irqs(pd->tx_dma, 1 << S6_HIFDMA_GMACTX); -	s6dmac_disable_error_irqs(pd->rx_dma, 1 << S6_HIFDMA_GMACRX); -} - -static int s6gmac_tx(struct sk_buff *skb, struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	unsigned long flags; - -	spin_lock_irqsave(&pd->lock, flags); -	writel(skb->len << S6_GMAC_BURST_PREWR_LEN | -		0 << S6_GMAC_BURST_PREWR_CFE | -		1 << S6_GMAC_BURST_PREWR_PPE | -		1 << S6_GMAC_BURST_PREWR_FCS | -		((skb->len < ETH_ZLEN) ? 1 : 0) << S6_GMAC_BURST_PREWR_PAD, -		pd->reg + S6_GMAC_BURST_PREWR); -	s6dmac_put_fifo_cache(pd->tx_dma, pd->tx_chan, -		(u32)skb->data, pd->io, skb->len); -	if (s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) -		netif_stop_queue(dev); -	if (((u8)(pd->tx_skb_i - pd->tx_skb_o)) >= S6_NUM_TX_SKB) { -		printk(KERN_ERR "GMAC BUG: skb tx ring overflow [%x, %x]\n", -			pd->tx_skb_o, pd->tx_skb_i); -		BUG(); -	} -	pd->tx_skb[(pd->tx_skb_i++) % S6_NUM_TX_SKB] = skb; -	spin_unlock_irqrestore(&pd->lock, flags); -	return 0; -} - -static void s6gmac_tx_timeout(struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	unsigned long flags; -	spin_lock_irqsave(&pd->lock, flags); -	s6gmac_tx_interrupt(dev); -	spin_unlock_irqrestore(&pd->lock, flags); -} - -static int s6gmac_open(struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	unsigned long flags; -	phy_read_status(pd->phydev); -	spin_lock_irqsave(&pd->lock, flags); -	pd->link.mbit = 0; -	s6gmac_linkisup(dev, pd->phydev->link); -	s6gmac_init_device(dev); -	s6gmac_init_stats(dev); -	s6gmac_init_dmac(dev); -	s6gmac_rx_fillfifo(dev); -	s6dmac_enable_chan(pd->rx_dma, pd->rx_chan, -		2, 1, 0, 1, 0, 0, 0, 7, -1, 2, 0, 1); -	s6dmac_enable_chan(pd->tx_dma, pd->tx_chan, -		2, 0, 1, 0, 0, 0, 0, 7, -1, 2, 0, 1); -	writel(0 << S6_GMAC_HOST_INT_TXBURSTOVER | -		0 << S6_GMAC_HOST_INT_TXPREWOVER | -		0 << S6_GMAC_HOST_INT_RXBURSTUNDER | -		0 << S6_GMAC_HOST_INT_RXPOSTRFULL | -		0 << S6_GMAC_HOST_INT_RXPOSTRUNDER, -		pd->reg + S6_GMAC_HOST_INTMASK); -	spin_unlock_irqrestore(&pd->lock, flags); -	phy_start(pd->phydev); -	netif_start_queue(dev); -	return 0; -} - -static int s6gmac_stop(struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	unsigned long flags; -	netif_stop_queue(dev); -	phy_stop(pd->phydev); -	spin_lock_irqsave(&pd->lock, flags); -	s6gmac_init_dmac(dev); -	s6gmac_stop_device(dev); -	while (pd->tx_skb_i != pd->tx_skb_o) -		dev_kfree_skb(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]); -	while (pd->rx_skb_i != pd->rx_skb_o) -		dev_kfree_skb(pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB]); -	spin_unlock_irqrestore(&pd->lock, flags); -	return 0; -} - -static struct net_device_stats *s6gmac_stats(struct net_device *dev) -{ -	struct s6gmac *pd = netdev_priv(dev); -	struct net_device_stats *st = (struct net_device_stats *)&pd->stats; -	int i; -	do { -		unsigned long flags; -		spin_lock_irqsave(&pd->lock, flags); -		for (i = 0; i < ARRAY_SIZE(pd->stats); i++) -			pd->stats[i] = -				pd->carry[i] << (S6_GMAC_STAT_SIZE_MIN - 1); -		s6gmac_stats_collect(pd, &statinf[0][0]); -		s6gmac_stats_collect(pd, &statinf[1][0]); -		i = s6gmac_stats_pending(pd, 0) | -			s6gmac_stats_pending(pd, 1); -		spin_unlock_irqrestore(&pd->lock, flags); -	} while (i); -	st->rx_errors = st->rx_crc_errors + -			st->rx_frame_errors + -			st->rx_length_errors + -			st->rx_missed_errors; -	st->tx_errors += st->tx_aborted_errors; -	return st; -} - -static int s6gmac_probe(struct platform_device *pdev) -{ -	struct net_device *dev; -	struct s6gmac *pd; -	int res; -	unsigned long i; -	struct mii_bus *mb; - -	dev = alloc_etherdev(sizeof(*pd)); -	if (!dev) -		return -ENOMEM; - -	dev->open = s6gmac_open; -	dev->stop = s6gmac_stop; -	dev->hard_start_xmit = s6gmac_tx; -	dev->tx_timeout = s6gmac_tx_timeout; -	dev->watchdog_timeo = HZ; -	dev->get_stats = s6gmac_stats; -	dev->irq = platform_get_irq(pdev, 0); -	pd = netdev_priv(dev); -	memset(pd, 0, sizeof(*pd)); -	spin_lock_init(&pd->lock); -	pd->reg = platform_get_resource(pdev, IORESOURCE_MEM, 0)->start; -	i = platform_get_resource(pdev, IORESOURCE_DMA, 0)->start; -	pd->tx_dma = DMA_MASK_DMAC(i); -	pd->tx_chan = DMA_INDEX_CHNL(i); -	i = platform_get_resource(pdev, IORESOURCE_DMA, 1)->start; -	pd->rx_dma = DMA_MASK_DMAC(i); -	pd->rx_chan = DMA_INDEX_CHNL(i); -	pd->io = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; -	res = request_irq(dev->irq, s6gmac_interrupt, 0, dev->name, dev); -	if (res) { -		printk(KERN_ERR DRV_PRMT "irq request failed: %d\n", dev->irq); -		goto errirq; -	} -	res = register_netdev(dev); -	if (res) { -		printk(KERN_ERR DRV_PRMT "error registering device %s\n", -			dev->name); -		goto errdev; -	} -	mb = mdiobus_alloc(); -	if (!mb) { -		printk(KERN_ERR DRV_PRMT "error allocating mii bus\n"); -		res = -ENOMEM; -		goto errmii; -	} -	mb->name = "s6gmac_mii"; -	mb->read = s6mii_read; -	mb->write = s6mii_write; -	mb->reset = s6mii_reset; -	mb->priv = pd; -	snprintf(mb->id, MII_BUS_ID_SIZE, "%s-%x", pdev->name, pdev->id); -	mb->phy_mask = ~(1 << 0); -	mb->irq = &pd->mii.irq[0]; -	for (i = 0; i < PHY_MAX_ADDR; i++) { -		int n = platform_get_irq(pdev, i + 1); -		if (n < 0) -			n = PHY_POLL; -		pd->mii.irq[i] = n; -	} -	mdiobus_register(mb); -	pd->mii.bus = mb; -	res = s6gmac_phy_start(dev); -	if (res) -		return res; -	platform_set_drvdata(pdev, dev); -	return 0; -errmii: -	unregister_netdev(dev); -errdev: -	free_irq(dev->irq, dev); -errirq: -	free_netdev(dev); -	return res; -} - -static int s6gmac_remove(struct platform_device *pdev) -{ -	struct net_device *dev = platform_get_drvdata(pdev); -	if (dev) { -		struct s6gmac *pd = netdev_priv(dev); -		mdiobus_unregister(pd->mii.bus); -		unregister_netdev(dev); -		free_irq(dev->irq, dev); -		free_netdev(dev); -	} -	return 0; -} - -static struct platform_driver s6gmac_driver = { -	.probe = s6gmac_probe, -	.remove = s6gmac_remove, -	.driver = { -		.name = "s6gmac", -	}, -}; - -module_platform_driver(s6gmac_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("S6105 on chip Ethernet driver"); -MODULE_AUTHOR("Oskar Schirmer <[email protected]>"); diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 698494481d18..b1a271853d85 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -474,13 +474,19 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no,  	/* allocate memory for RX skbuff array */  	rx_ring->rx_skbuff_dma = kmalloc_array(rx_rsize,  					       sizeof(dma_addr_t), GFP_KERNEL); -	if (rx_ring->rx_skbuff_dma == NULL) -		goto dmamem_err; +	if (!rx_ring->rx_skbuff_dma) { +		dma_free_coherent(priv->device, +				  rx_rsize * sizeof(struct sxgbe_rx_norm_desc), +				  rx_ring->dma_rx, rx_ring->dma_rx_phy); +		goto error; +	}  	rx_ring->rx_skbuff = kmalloc_array(rx_rsize,  					   sizeof(struct sk_buff *), GFP_KERNEL); -	if (rx_ring->rx_skbuff == NULL) -		goto rxbuff_err; +	if (!rx_ring->rx_skbuff) { +		kfree(rx_ring->rx_skbuff_dma); +		goto error; +	}  	/* initialise the buffers */  	for (desc_index = 0; desc_index < rx_rsize; desc_index++) { @@ -502,13 +508,6 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no,  err_init_rx_buffers:  	while (--desc_index >= 0)  		free_rx_ring(priv->device, rx_ring, desc_index); -	kfree(rx_ring->rx_skbuff); -rxbuff_err: -	kfree(rx_ring->rx_skbuff_dma); -dmamem_err: -	dma_free_coherent(priv->device, -			  rx_rsize * sizeof(struct sxgbe_rx_norm_desc), -			  rx_ring->dma_rx, rx_ring->dma_rx_phy);  error:  	return -ENOMEM;  } diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c index 866560ea9e18..b02eed12bfc5 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c @@ -108,10 +108,6 @@ static int sxgbe_platform_probe(struct platform_device *pdev)  		}  	} -	/* Get MAC address if available (DT) */ -	if (mac) -		ether_addr_copy(priv->dev->dev_addr, mac); -  	priv = sxgbe_drv_probe(&(pdev->dev), plat_dat, addr);  	if (!priv) {  		pr_err("%s: main driver probe failed\n", __func__); @@ -125,6 +121,10 @@ static int sxgbe_platform_probe(struct platform_device *pdev)  		goto err_drv_remove;  	} +	/* Get MAC address if available (DT) */ +	if (mac) +		ether_addr_copy(priv->dev->dev_addr, mac); +  	/* Get the TX/RX IRQ numbers */  	for (i = 0, chan = 1; i < SXGBE_TX_QUEUES; i++) {  		priv->txq[i]->irq_no = irq_of_parse_and_map(node, chan++); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 118a427d1942..8c6b7c1651e5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1671,7 +1671,7 @@ static void stmmac_init_tx_coalesce(struct stmmac_priv *priv)   *  0 on success and an appropriate (-)ve integer as defined in errno.h   *  file on failure.   */ -static int stmmac_hw_setup(struct net_device *dev) +static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)  {  	struct stmmac_priv *priv = netdev_priv(dev);  	int ret; @@ -1708,9 +1708,11 @@ static int stmmac_hw_setup(struct net_device *dev)  	stmmac_mmc_setup(priv); -	ret = stmmac_init_ptp(priv); -	if (ret && ret != -EOPNOTSUPP) -		pr_warn("%s: failed PTP initialisation\n", __func__); +	if (init_ptp) { +		ret = stmmac_init_ptp(priv); +		if (ret && ret != -EOPNOTSUPP) +			pr_warn("%s: failed PTP initialisation\n", __func__); +	}  #ifdef CONFIG_DEBUG_FS  	ret = stmmac_init_fs(dev); @@ -1787,7 +1789,7 @@ static int stmmac_open(struct net_device *dev)  		goto init_error;  	} -	ret = stmmac_hw_setup(dev); +	ret = stmmac_hw_setup(dev, true);  	if (ret < 0) {  		pr_err("%s: Hw setup failed\n", __func__);  		goto init_error; @@ -3036,7 +3038,7 @@ int stmmac_resume(struct net_device *ndev)  	netif_device_attach(ndev);  	init_dma_desc_rings(ndev, GFP_ATOMIC); -	stmmac_hw_setup(ndev); +	stmmac_hw_setup(ndev, false);  	stmmac_init_tx_coalesce(priv);  	napi_enable(&priv->napi); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 4032b170fe24..3039de2465ba 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -430,7 +430,6 @@ static struct platform_driver stmmac_pltfr_driver = {  	.remove = stmmac_pltfr_remove,  	.driver = {  		   .name = STMMAC_RESOURCE_NAME, -		   .owner = THIS_MODULE,  		   .pm = &stmmac_pltfr_pm_ops,  		   .of_match_table = of_match_ptr(stmmac_dt_ids),  	}, diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index 45c408ef67d0..d2835bf7b4fb 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -1201,6 +1201,7 @@ static int vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb)  		segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO);  	if (IS_ERR(segs)) {  		dev->stats.tx_dropped++; +		dev_kfree_skb_any(skb);  		return NETDEV_TX_OK;  	} diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index c560f9aeb55d..e068d48b0f21 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -610,7 +610,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)  			/* Clear all mcast from ALE */  			cpsw_ale_flush_multicast(ale, ALE_ALL_PORTS << -						 priv->host_port); +						 priv->host_port, -1);  			/* Flood All Unicast Packets to Host port */  			cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 1); @@ -634,6 +634,12 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)  static void cpsw_ndo_set_rx_mode(struct net_device *ndev)  {  	struct cpsw_priv *priv = netdev_priv(ndev); +	int vid; + +	if (priv->data.dual_emac) +		vid = priv->slaves[priv->emac_port].port_vlan; +	else +		vid = priv->data.default_vlan;  	if (ndev->flags & IFF_PROMISC) {  		/* Enable promiscuous mode */ @@ -649,7 +655,8 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)  	cpsw_ale_set_allmulti(priv->ale, priv->ndev->flags & IFF_ALLMULTI);  	/* Clear all mcast from ALE */ -	cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port); +	cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port, +				 vid);  	if (!netdev_mc_empty(ndev)) {  		struct netdev_hw_addr *ha; @@ -757,6 +764,14 @@ requeue:  static irqreturn_t cpsw_interrupt(int irq, void *dev_id)  {  	struct cpsw_priv *priv = dev_id; +	int value = irq - priv->irqs_table[0]; + +	/* NOTICE: Ending IRQ here. The trick with the 'value' variable above +	 * is to make sure we will always write the correct value to the EOI +	 * register. Namely 0 for RX_THRESH Interrupt, 1 for RX Interrupt, 2 +	 * for TX Interrupt and 3 for MISC Interrupt. +	 */ +	cpdma_ctlr_eoi(priv->dma, value);  	cpsw_intr_disable(priv);  	if (priv->irq_enabled == true) { @@ -786,8 +801,6 @@ static int cpsw_poll(struct napi_struct *napi, int budget)  	int			num_tx, num_rx;  	num_tx = cpdma_chan_process(priv->txch, 128); -	if (num_tx) -		cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);  	num_rx = cpdma_chan_process(priv->rxch, budget);  	if (num_rx < budget) { @@ -795,7 +808,6 @@ static int cpsw_poll(struct napi_struct *napi, int budget)  		napi_complete(napi);  		cpsw_intr_enable(priv); -		cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);  		prim_cpsw = cpsw_get_slave_priv(priv, 0);  		if (prim_cpsw->irq_enabled == false) {  			prim_cpsw->irq_enabled = true; @@ -1310,8 +1322,6 @@ static int cpsw_ndo_open(struct net_device *ndev)  	napi_enable(&priv->napi);  	cpdma_ctlr_start(priv->dma);  	cpsw_intr_enable(priv); -	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); -	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);  	prim_cpsw = cpsw_get_slave_priv(priv, 0);  	if (prim_cpsw->irq_enabled == false) { @@ -1578,9 +1588,6 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev)  	cpdma_chan_start(priv->txch);  	cpdma_ctlr_int_ctrl(priv->dma, true);  	cpsw_intr_enable(priv); -	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); -	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); -  }  static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) @@ -1620,9 +1627,6 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)  	cpsw_interrupt(ndev->irq, priv);  	cpdma_ctlr_int_ctrl(priv->dma, true);  	cpsw_intr_enable(priv); -	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); -	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); -  }  #endif @@ -1630,16 +1634,24 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,  				unsigned short vid)  {  	int ret; -	int unreg_mcast_mask; +	int unreg_mcast_mask = 0; +	u32 port_mask; -	if (priv->ndev->flags & IFF_ALLMULTI) -		unreg_mcast_mask = ALE_ALL_PORTS; -	else -		unreg_mcast_mask = ALE_PORT_1 | ALE_PORT_2; +	if (priv->data.dual_emac) { +		port_mask = (1 << (priv->emac_port + 1)) | ALE_PORT_HOST; + +		if (priv->ndev->flags & IFF_ALLMULTI) +			unreg_mcast_mask = port_mask; +	} else { +		port_mask = ALE_ALL_PORTS; + +		if (priv->ndev->flags & IFF_ALLMULTI) +			unreg_mcast_mask = ALE_ALL_PORTS; +		else +			unreg_mcast_mask = ALE_PORT_1 | ALE_PORT_2; +	} -	ret = cpsw_ale_add_vlan(priv->ale, vid, -				ALE_ALL_PORTS << priv->host_port, -				0, ALE_ALL_PORTS << priv->host_port, +	ret = cpsw_ale_add_vlan(priv->ale, vid, port_mask, 0, port_mask,  				unreg_mcast_mask << priv->host_port);  	if (ret != 0)  		return ret; @@ -1650,8 +1662,7 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,  		goto clean_vid;  	ret = cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, -				 ALE_ALL_PORTS << priv->host_port, -				 ALE_VLAN, vid, 0); +				 port_mask, ALE_VLAN, vid, 0);  	if (ret != 0)  		goto clean_vlan_ucast;  	return 0; diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 097ebe7077ac..5246b3a18ff8 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -234,7 +234,7 @@ static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry,  		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);  } -int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask) +int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid)  {  	u32 ale_entry[ALE_ENTRY_WORDS];  	int ret, idx; @@ -245,6 +245,14 @@ int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask)  		if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR)  			continue; +		/* if vid passed is -1 then remove all multicast entry from +		 * the table irrespective of vlan id, if a valid vlan id is +		 * passed then remove only multicast added to that vlan id. +		 * if vlan id doesn't match then move on to next entry. +		 */ +		if (vid != -1 && cpsw_ale_get_vlan_id(ale_entry) != vid) +			continue; +  		if (cpsw_ale_get_mcast(ale_entry)) {  			u8 addr[6]; diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h index c0d4127aa549..af1e7ecd87c6 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.h +++ b/drivers/net/ethernet/ti/cpsw_ale.h @@ -92,7 +92,7 @@ void cpsw_ale_stop(struct cpsw_ale *ale);  int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout);  int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask); -int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask); +int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid);  int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,  		       int flags, u16 vid);  int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index ea712512c7d1..5fae4354722c 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -62,6 +62,7 @@  #include <linux/of.h>  #include <linux/of_address.h>  #include <linux/of_device.h> +#include <linux/of_mdio.h>  #include <linux/of_irq.h>  #include <linux/of_net.h> @@ -343,9 +344,7 @@ struct emac_priv {  	u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS];  	u32 rx_addr_type;  	const char *phy_id; -#ifdef CONFIG_OF  	struct device_node *phy_node; -#endif  	struct phy_device *phydev;  	spinlock_t lock;  	/*platform specific members*/ @@ -922,6 +921,16 @@ static void emac_int_disable(struct emac_priv *priv)  		if (priv->int_disable)  			priv->int_disable(); +		/* NOTE: Rx Threshold and Misc interrupts are not enabled */ + +		/* ack rxen only then a new pulse will be generated */ +		emac_write(EMAC_DM646X_MACEOIVECTOR, +			EMAC_DM646X_MAC_EOI_C0_RXEN); + +		/* ack txen- only then a new pulse will be generated */ +		emac_write(EMAC_DM646X_MACEOIVECTOR, +			EMAC_DM646X_MAC_EOI_C0_TXEN); +  		local_irq_restore(flags);  	} else { @@ -951,15 +960,6 @@ static void emac_int_enable(struct emac_priv *priv)  		 * register */  		/* NOTE: Rx Threshold and Misc interrupts are not enabled */ - -		/* ack rxen only then a new pulse will be generated */ -		emac_write(EMAC_DM646X_MACEOIVECTOR, -			EMAC_DM646X_MAC_EOI_C0_RXEN); - -		/* ack txen- only then a new pulse will be generated */ -		emac_write(EMAC_DM646X_MACEOIVECTOR, -			EMAC_DM646X_MAC_EOI_C0_TXEN); -  	} else {  		/* Set DM644x control registers for interrupt control */  		emac_ctrl_write(EMAC_CTRL_EWCTL, 0x1); @@ -1537,7 +1537,13 @@ static int emac_dev_open(struct net_device *ndev)  	int i = 0;  	struct emac_priv *priv = netdev_priv(ndev); -	pm_runtime_get(&priv->pdev->dev); +	ret = pm_runtime_get_sync(&priv->pdev->dev); +	if (ret < 0) { +		pm_runtime_put_noidle(&priv->pdev->dev); +		dev_err(&priv->pdev->dev, "%s: failed to get_sync(%d)\n", +			__func__, ret); +		return ret; +	}  	netif_carrier_off(ndev);  	for (cnt = 0; cnt < ETH_ALEN; cnt++) @@ -1596,8 +1602,20 @@ static int emac_dev_open(struct net_device *ndev)  	cpdma_ctlr_start(priv->dma);  	priv->phydev = NULL; + +	if (priv->phy_node) { +		priv->phydev = of_phy_connect(ndev, priv->phy_node, +					      &emac_adjust_link, 0, 0); +		if (!priv->phydev) { +			dev_err(emac_dev, "could not connect to phy %s\n", +				priv->phy_node->full_name); +			ret = -ENODEV; +			goto err; +		} +	} +  	/* use the first phy on the bus if pdata did not give us a phy id */ -	if (!priv->phy_id) { +	if (!priv->phydev && !priv->phy_id) {  		struct device *phy;  		phy = bus_find_device(&mdio_bus_type, NULL, NULL, @@ -1606,7 +1624,7 @@ static int emac_dev_open(struct net_device *ndev)  			priv->phy_id = dev_name(phy);  	} -	if (priv->phy_id && *priv->phy_id) { +	if (!priv->phydev && priv->phy_id && *priv->phy_id) {  		priv->phydev = phy_connect(ndev, priv->phy_id,  					   &emac_adjust_link,  					   PHY_INTERFACE_MODE_MII); @@ -1627,7 +1645,9 @@ static int emac_dev_open(struct net_device *ndev)  			"(mii_bus:phy_addr=%s, id=%x)\n",  			priv->phydev->drv->name, dev_name(&priv->phydev->dev),  			priv->phydev->phy_id); -	} else { +	} + +	if (!priv->phydev) {  		/* No PHY , fix the link, speed and duplex settings */  		dev_notice(emac_dev, "no phy, defaulting to 100/full\n");  		priv->link = 1; @@ -1724,6 +1744,15 @@ static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev)  	struct emac_priv *priv = netdev_priv(ndev);  	u32 mac_control;  	u32 stats_clear_mask; +	int err; + +	err = pm_runtime_get_sync(&priv->pdev->dev); +	if (err < 0) { +		pm_runtime_put_noidle(&priv->pdev->dev); +		dev_err(&priv->pdev->dev, "%s: failed to get_sync(%d)\n", +			__func__, err); +		return &ndev->stats; +	}  	/* update emac hardware stats and reset the registers*/ @@ -1766,6 +1795,8 @@ static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev)  	ndev->stats.tx_fifo_errors += emac_read(EMAC_TXUNDERRUN);  	emac_write(EMAC_TXUNDERRUN, stats_clear_mask); +	pm_runtime_put(&priv->pdev->dev); +  	return &ndev->stats;  } @@ -1859,7 +1890,7 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv)  static int davinci_emac_probe(struct platform_device *pdev)  {  	int rc = 0; -	struct resource *res; +	struct resource *res, *res_ctrl;  	struct net_device *ndev;  	struct emac_priv *priv;  	unsigned long hw_ram_addr; @@ -1876,6 +1907,7 @@ static int davinci_emac_probe(struct platform_device *pdev)  		return -EBUSY;  	}  	emac_bus_frequency = clk_get_rate(emac_clk); +	devm_clk_put(&pdev->dev, emac_clk);  	/* TODO: Probe PHY here if possible */ @@ -1917,11 +1949,20 @@ static int davinci_emac_probe(struct platform_device *pdev)  		rc = PTR_ERR(priv->remap_addr);  		goto no_pdata;  	} + +	res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 1); +	if (res_ctrl) { +		priv->ctrl_base = +			devm_ioremap_resource(&pdev->dev, res_ctrl); +		if (IS_ERR(priv->ctrl_base)) +			goto no_pdata; +	} else { +		priv->ctrl_base = priv->remap_addr + pdata->ctrl_mod_reg_offset; +	} +  	priv->emac_base = priv->remap_addr + pdata->ctrl_reg_offset;  	ndev->base_addr = (unsigned long)priv->remap_addr; -	priv->ctrl_base = priv->remap_addr + pdata->ctrl_mod_reg_offset; -  	hw_ram_addr = pdata->hw_ram_addr;  	if (!hw_ram_addr)  		hw_ram_addr = (u32 __force)res->start + pdata->ctrl_ram_offset; @@ -1980,12 +2021,22 @@ static int davinci_emac_probe(struct platform_device *pdev)  	ndev->ethtool_ops = ðtool_ops;  	netif_napi_add(ndev, &priv->napi, emac_poll, EMAC_POLL_WEIGHT); +	pm_runtime_enable(&pdev->dev); +	rc = pm_runtime_get_sync(&pdev->dev); +	if (rc < 0) { +		pm_runtime_put_noidle(&pdev->dev); +		dev_err(&pdev->dev, "%s: failed to get_sync(%d)\n", +			__func__, rc); +		goto no_cpdma_chan; +	} +  	/* register the network device */  	SET_NETDEV_DEV(ndev, &pdev->dev);  	rc = register_netdev(ndev);  	if (rc) {  		dev_err(&pdev->dev, "error in register_netdev\n");  		rc = -ENODEV; +		pm_runtime_put(&pdev->dev);  		goto no_cpdma_chan;  	} @@ -1995,9 +2046,7 @@ static int davinci_emac_probe(struct platform_device *pdev)  			   "(regs: %p, irq: %d)\n",  			   (void *)priv->emac_base_phys, ndev->irq);  	} - -	pm_runtime_enable(&pdev->dev); -	pm_runtime_resume(&pdev->dev); +	pm_runtime_put(&pdev->dev);  	return 0; @@ -2071,9 +2120,14 @@ static const struct emac_platform_data am3517_emac_data = {  	.hw_ram_addr		= 0x01e20000,  }; +static const struct emac_platform_data dm816_emac_data = { +	.version		= EMAC_VERSION_2, +}; +  static const struct of_device_id davinci_emac_of_match[] = {  	{.compatible = "ti,davinci-dm6467-emac", },  	{.compatible = "ti,am3517-emac", .data = &am3517_emac_data, }, +	{.compatible = "ti,dm816-emac", .data = &dm816_emac_data, },  	{},  };  MODULE_DEVICE_TABLE(of, davinci_emac_of_match); diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index 9c2d91ea0af4..dbcbf0c5bcfa 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -1043,6 +1043,7 @@ static int temac_of_probe(struct platform_device *op)  	lp->regs = of_iomap(op->dev.of_node, 0);  	if (!lp->regs) {  		dev_err(&op->dev, "could not map temac regs.\n"); +		rc = -ENOMEM;  		goto nodev;  	} @@ -1062,6 +1063,7 @@ static int temac_of_probe(struct platform_device *op)  	np = of_parse_phandle(op->dev.of_node, "llink-connected", 0);  	if (!np) {  		dev_err(&op->dev, "could not find DMA node\n"); +		rc = -ENODEV;  		goto err_iounmap;  	} diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h index 44b8d2bad8c3..4c9b4fa1d3c1 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet.h +++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h @@ -388,7 +388,6 @@ struct axidma_bd {   * @dma_err_tasklet: Tasklet structure to process Axi DMA errors   * @tx_irq:	Axidma TX IRQ number   * @rx_irq:	Axidma RX IRQ number - * @temac_type:	axienet type to identify between soft and hard temac   * @phy_type:	Phy type to identify between MII/GMII/RGMII/SGMII/1000 Base-X   * @options:	AxiEthernet option word   * @last_link:	Phy link state in which the PHY was negotiated earlier @@ -431,7 +430,6 @@ struct axienet_local {  	int tx_irq;  	int rx_irq; -	u32 temac_type;  	u32 phy_type;  	u32 options;			/* Current options word */ diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 4ea2d4e6f1d1..a6d2860b712c 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1501,6 +1501,7 @@ static int axienet_of_probe(struct platform_device *op)  	lp->regs = of_iomap(op->dev.of_node, 0);  	if (!lp->regs) {  		dev_err(&op->dev, "could not map Axi Ethernet regs.\n"); +		ret = -ENOMEM;  		goto nodev;  	}  	/* Setup checksum offload, but default to off if not specified */ @@ -1555,10 +1556,6 @@ static int axienet_of_probe(struct platform_device *op)  		if ((be32_to_cpup(p)) >= 0x4000)  			lp->jumbo_support = 1;  	} -	p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,temac-type", -				       NULL); -	if (p) -		lp->temac_type = be32_to_cpup(p);  	p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,phy-type", NULL);  	if (p)  		lp->phy_type = be32_to_cpup(p); @@ -1567,6 +1564,7 @@ static int axienet_of_probe(struct platform_device *op)  	np = of_parse_phandle(op->dev.of_node, "axistream-connected", 0);  	if (!np) {  		dev_err(&op->dev, "could not find DMA node\n"); +		ret = -ENODEV;  		goto err_iounmap;  	}  	lp->dma_regs = of_iomap(np, 0); diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c index 24858799c204..9d4ce388510a 100644 --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c @@ -1109,6 +1109,7 @@ static int xemaclite_of_probe(struct platform_device *ofdev)  	res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0);  	if (!res) {  		dev_err(dev, "no IRQ found\n"); +		rc = -ENXIO;  		goto error;  	} diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 2f48f790c9b4..384ca4f4de4a 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -590,6 +590,7 @@ struct nvsp_message {  #define NETVSC_RECEIVE_BUFFER_ID		0xcafe +#define NETVSC_SEND_BUFFER_ID			0  #define NETVSC_PACKET_SIZE                      4096 diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index dd867e6cabd6..9f49c0129a78 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -161,8 +161,8 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device)  	/* Deal with the send buffer we may have setup.  	 * If we got a  send section size, it means we received a -	 * SendsendBufferComplete msg (ie sent -	 * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need +	 * NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE msg (ie sent +	 * NVSP_MSG1_TYPE_SEND_SEND_BUF msg) therefore, we need  	 * to send a revoke msg here  	 */  	if (net_device->send_section_size) { @@ -172,7 +172,8 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device)  		revoke_packet->hdr.msg_type =  			NVSP_MSG1_TYPE_REVOKE_SEND_BUF; -		revoke_packet->msg.v1_msg.revoke_recv_buf.id = 0; +		revoke_packet->msg.v1_msg.revoke_send_buf.id = +			NETVSC_SEND_BUFFER_ID;  		ret = vmbus_sendpacket(net_device->dev->channel,  				       revoke_packet, @@ -204,7 +205,7 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device)  		net_device->send_buf_gpadl_handle = 0;  	}  	if (net_device->send_buf) { -		/* Free up the receive buffer */ +		/* Free up the send buffer */  		vfree(net_device->send_buf);  		net_device->send_buf = NULL;  	} @@ -339,9 +340,9 @@ static int netvsc_init_buf(struct hv_device *device)  	init_packet = &net_device->channel_init_pkt;  	memset(init_packet, 0, sizeof(struct nvsp_message));  	init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF; -	init_packet->msg.v1_msg.send_recv_buf.gpadl_handle = +	init_packet->msg.v1_msg.send_send_buf.gpadl_handle =  		net_device->send_buf_gpadl_handle; -	init_packet->msg.v1_msg.send_recv_buf.id = 0; +	init_packet->msg.v1_msg.send_send_buf.id = NETVSC_SEND_BUFFER_ID;  	/* Send the gpadl notification request */  	ret = vmbus_sendpacket(device->channel, init_packet, @@ -364,7 +365,7 @@ static int netvsc_init_buf(struct hv_device *device)  		netdev_err(ndev, "Unable to complete send buffer "  			   "initialization with NetVsp - status %d\n",  			   init_packet->msg.v1_msg. -			   send_recv_buf_complete.status); +			   send_send_buf_complete.status);  		ret = -EINVAL;  		goto cleanup;  	} diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index c530de1e63f5..3ad8ca76196d 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -88,6 +88,7 @@ struct kszphy_priv {  static const struct kszphy_type ksz8021_type = {  	.led_mode_reg		= MII_KSZPHY_CTRL_2, +	.has_broadcast_disable	= true,  	.has_rmii_ref_clk_sel	= true,  }; @@ -258,19 +259,6 @@ static int kszphy_config_init(struct phy_device *phydev)  	return 0;  } -static int ksz8021_config_init(struct phy_device *phydev) -{ -	int rc; - -	rc = kszphy_config_init(phydev); -	if (rc) -		return rc; - -	rc = kszphy_broadcast_disable(phydev); - -	return rc < 0 ? rc : 0; -} -  static int ksz9021_load_values_from_of(struct phy_device *phydev,  				       struct device_node *of_node, u16 reg,  				       char *field1, char *field2, @@ -584,7 +572,7 @@ static struct phy_driver ksphy_driver[] = {  	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,  	.driver_data	= &ksz8021_type,  	.probe		= kszphy_probe, -	.config_init	= ksz8021_config_init, +	.config_init	= kszphy_config_init,  	.config_aneg	= genphy_config_aneg,  	.read_status	= genphy_read_status,  	.ack_interrupt	= kszphy_ack_interrupt, @@ -601,7 +589,7 @@ static struct phy_driver ksphy_driver[] = {  	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,  	.driver_data	= &ksz8021_type,  	.probe		= kszphy_probe, -	.config_init	= ksz8021_config_init, +	.config_init	= kszphy_config_init,  	.config_aneg	= genphy_config_aneg,  	.read_status	= genphy_read_status,  	.ack_interrupt	= kszphy_ack_interrupt, diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 93e224217e24..f7ff493f1e73 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -629,6 +629,7 @@ static int team_change_mode(struct team *team, const char *kind)  static void team_notify_peers_work(struct work_struct *work)  {  	struct team *team; +	int val;  	team = container_of(work, struct team, notify_peers.dw.work); @@ -636,9 +637,14 @@ static void team_notify_peers_work(struct work_struct *work)  		schedule_delayed_work(&team->notify_peers.dw, 0);  		return;  	} +	val = atomic_dec_if_positive(&team->notify_peers.count_pending); +	if (val < 0) { +		rtnl_unlock(); +		return; +	}  	call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, team->dev);  	rtnl_unlock(); -	if (!atomic_dec_and_test(&team->notify_peers.count_pending)) +	if (val)  		schedule_delayed_work(&team->notify_peers.dw,  				      msecs_to_jiffies(team->notify_peers.interval));  } @@ -669,6 +675,7 @@ static void team_notify_peers_fini(struct team *team)  static void team_mcast_rejoin_work(struct work_struct *work)  {  	struct team *team; +	int val;  	team = container_of(work, struct team, mcast_rejoin.dw.work); @@ -676,9 +683,14 @@ static void team_mcast_rejoin_work(struct work_struct *work)  		schedule_delayed_work(&team->mcast_rejoin.dw, 0);  		return;  	} +	val = atomic_dec_if_positive(&team->mcast_rejoin.count_pending); +	if (val < 0) { +		rtnl_unlock(); +		return; +	}  	call_netdevice_notifiers(NETDEV_RESEND_IGMP, team->dev);  	rtnl_unlock(); -	if (!atomic_dec_and_test(&team->mcast_rejoin.count_pending)) +	if (val)  		schedule_delayed_work(&team->mcast_rejoin.dw,  				      msecs_to_jiffies(team->mcast_rejoin.interval));  } diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index dcb6d33141e0..1e9cdca37014 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -1276,7 +1276,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)          awd.done = 0;          urb->context = &awd; -        status = usb_submit_urb(urb, GFP_NOIO); +        status = usb_submit_urb(urb, GFP_ATOMIC);          if (status) {                  // something went wrong                  usb_free_urb(urb); diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index b8a82b86f909..602dc6668c3a 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -56,6 +56,8 @@ struct qmi_wwan_state {  /* default ethernet address used by the modem */  static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3}; +static const u8 buggy_fw_addr[ETH_ALEN] = {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}; +  /* Make up an ethernet header if the packet doesn't have one.   *   * A firmware bug common among several devices cause them to send raw @@ -332,10 +334,12 @@ next_desc:  		usb_driver_release_interface(driver, info->data);  	} -	/* Never use the same address on both ends of the link, even -	 * if the buggy firmware told us to. +	/* Never use the same address on both ends of the link, even if the +	 * buggy firmware told us to. Or, if device is assigned the well-known +	 * buggy firmware MAC address, replace it with a random address,  	 */ -	if (ether_addr_equal(dev->net->dev_addr, default_modem_addr)) +	if (ether_addr_equal(dev->net->dev_addr, default_modem_addr) || +	    ether_addr_equal(dev->net->dev_addr, buggy_fw_addr))  		eth_hw_addr_random(dev->net);  	/* make MAC addr easily distinguishable from an IP header */ diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 2d1c77e81836..bf405f134d3a 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -833,9 +833,6 @@ static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)  		index &= ~3;  	} -	generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - -	data |= __le32_to_cpu(tmp) & ~mask;  	tmp = __cpu_to_le32(data);  	generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); @@ -874,9 +871,6 @@ static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)  		index &= ~3;  	} -	generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - -	data |= __le32_to_cpu(tmp) & ~mask;  	tmp = __cpu_to_le32(data);  	generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); @@ -926,12 +920,6 @@ static void sram_write(struct r8152 *tp, u16 addr, u16 data)  	ocp_reg_write(tp, OCP_SRAM_DATA, data);  } -static u16 sram_read(struct r8152 *tp, u16 addr) -{ -	ocp_reg_write(tp, OCP_SRAM_ADDR, addr); -	return ocp_reg_read(tp, OCP_SRAM_DATA); -} -  static int read_mii_word(struct net_device *netdev, int phy_id, int reg)  {  	struct r8152 *tp = netdev_priv(netdev); @@ -1897,6 +1885,22 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev)  	netif_wake_queue(netdev);  } +static netdev_features_t +rtl8152_features_check(struct sk_buff *skb, struct net_device *dev, +		       netdev_features_t features) +{ +	u32 mss = skb_shinfo(skb)->gso_size; +	int max_offset = mss ? GTTCPHO_MAX : TCPHO_MAX; +	int offset = skb_transport_offset(skb); + +	if ((mss || skb->ip_summed == CHECKSUM_PARTIAL) && offset > max_offset) +		features &= ~(NETIF_F_ALL_CSUM | NETIF_F_GSO_MASK); +	else if ((skb->len + sizeof(struct tx_desc)) > agg_buf_sz) +		features &= ~NETIF_F_GSO_MASK; + +	return features; +} +  static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,  				      struct net_device *netdev)  { @@ -2502,24 +2506,18 @@ static void r8153_hw_phy_cfg(struct r8152 *tp)  	data = ocp_reg_read(tp, OCP_POWER_CFG);  	data |= EN_10M_PLLOFF;  	ocp_reg_write(tp, OCP_POWER_CFG, data); -	data = sram_read(tp, SRAM_IMPEDANCE); -	data &= ~RX_DRIVING_MASK; -	sram_write(tp, SRAM_IMPEDANCE, data); +	sram_write(tp, SRAM_IMPEDANCE, 0x0b13);  	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);  	ocp_data |= PFM_PWM_SWITCH;  	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); -	data = sram_read(tp, SRAM_LPF_CFG); -	data |= LPF_AUTO_TUNE; -	sram_write(tp, SRAM_LPF_CFG, data); +	/* Enable LPF corner auto tune */ +	sram_write(tp, SRAM_LPF_CFG, 0xf70f); -	data = sram_read(tp, SRAM_10M_AMP1); -	data |= GDAC_IB_UPALL; -	sram_write(tp, SRAM_10M_AMP1, data); -	data = sram_read(tp, SRAM_10M_AMP2); -	data |= AMP_DN; -	sram_write(tp, SRAM_10M_AMP2, data); +	/* Adjust 10M Amplitude */ +	sram_write(tp, SRAM_10M_AMP1, 0x00af); +	sram_write(tp, SRAM_10M_AMP2, 0x0208);  	set_bit(PHY_RESET, &tp->flags);  } @@ -3706,6 +3704,7 @@ static const struct net_device_ops rtl8152_netdev_ops = {  	.ndo_set_mac_address	= rtl8152_set_mac_address,  	.ndo_change_mtu		= rtl8152_change_mtu,  	.ndo_validate_addr	= eth_validate_addr, +	.ndo_features_check	= rtl8152_features_check,  };  static void r8152b_get_version(struct r8152 *tp) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index b8bd7191572d..5ca97713bfb3 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -760,7 +760,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)  		container_of(napi, struct receive_queue, napi);  	unsigned int r, received = 0; -again:  	received += virtnet_receive(rq, budget - received);  	/* Out of packets? */ @@ -771,7 +770,6 @@ again:  		    napi_schedule_prep(napi)) {  			virtqueue_disable_cb(rq->vq);  			__napi_schedule(napi); -			goto again;  		}  	} diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 49d9f2291998..7fbd89fbe107 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1579,8 +1579,10 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,  	bool udp_sum = !udp_get_no_check6_tx(vs->sock->sk);  	skb = udp_tunnel_handle_offloads(skb, udp_sum); -	if (IS_ERR(skb)) -		return -EINVAL; +	if (IS_ERR(skb)) { +		err = -EINVAL; +		goto err; +	}  	skb_scrub_packet(skb, xnet); @@ -1590,12 +1592,16 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,  	/* Need space for new headers (invalidates iph ptr) */  	err = skb_cow_head(skb, min_headroom); -	if (unlikely(err)) -		return err; +	if (unlikely(err)) { +		kfree_skb(skb); +		goto err; +	}  	skb = vlan_hwaccel_push_inside(skb); -	if (WARN_ON(!skb)) -		return -ENOMEM; +	if (WARN_ON(!skb)) { +		err = -ENOMEM; +		goto err; +	}  	vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));  	vxh->vx_flags = htonl(VXLAN_FLAGS); @@ -1606,6 +1612,9 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,  	udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio,  			     ttl, src_port, dst_port);  	return 0; +err: +	dst_release(dst); +	return err;  }  #endif @@ -1621,7 +1630,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,  	skb = udp_tunnel_handle_offloads(skb, udp_sum);  	if (IS_ERR(skb)) -		return -EINVAL; +		return PTR_ERR(skb);  	min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len  			+ VXLAN_HLEN + sizeof(struct iphdr) @@ -1629,8 +1638,10 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,  	/* Need space for new headers (invalidates iph ptr) */  	err = skb_cow_head(skb, min_headroom); -	if (unlikely(err)) +	if (unlikely(err)) { +		kfree_skb(skb);  		return err; +	}  	skb = vlan_hwaccel_push_inside(skb);  	if (WARN_ON(!skb)) @@ -1776,9 +1787,12 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  				     tos, ttl, df, src_port, dst_port,  				     htonl(vni << 8),  				     !net_eq(vxlan->net, dev_net(vxlan->dev))); - -		if (err < 0) +		if (err < 0) { +			/* skb is already freed. */ +			skb = NULL;  			goto rt_tx_error; +		} +  		iptunnel_xmit_stats(err, &dev->stats, dev->tstats);  #if IS_ENABLED(CONFIG_IPV6)  	} else { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 3c06e9365949..9880dae2a569 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -1070,7 +1070,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,  	 */  	if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&  	    ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) || -	     (sdiodev->pdata->oob_irq_supported))) +	     (sdiodev->pdata && sdiodev->pdata->oob_irq_supported)))  		bus_if->wowl_supported = true;  #endif @@ -1167,7 +1167,7 @@ static int brcmf_ops_sdio_resume(struct device *dev)  	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;  	brcmf_dbg(SDIO, "Enter\n"); -	if (sdiodev->pdata->oob_irq_supported) +	if (sdiodev->pdata && sdiodev->pdata->oob_irq_supported)  		disable_irq_wake(sdiodev->pdata->oob_irq_nr);  	brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);  	atomic_set(&sdiodev->suspend, false); diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig index 91c0cb3c368e..21de4fe6cf2d 100644 --- a/drivers/net/wireless/ipw2x00/Kconfig +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -65,7 +65,8 @@ config IPW2100_DEBUG  config IPW2200  	tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" -	depends on PCI && CFG80211 && CFG80211_WEXT +	depends on PCI && CFG80211 +	select CFG80211_WEXT  	select WIRELESS_EXT  	select WEXT_SPY  	select WEXT_PRIV diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index e5be2d21868f..a5f9198d5747 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -69,8 +69,8 @@  #include "iwl-agn-hw.h"  /* Highest firmware API version supported */ -#define IWL7260_UCODE_API_MAX	10 -#define IWL3160_UCODE_API_MAX	10 +#define IWL7260_UCODE_API_MAX	12 +#define IWL3160_UCODE_API_MAX	12  /* Oldest version we won't warn about */  #define IWL7260_UCODE_API_OK	10 @@ -105,7 +105,7 @@  #define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode"  #define IWL7265D_FW_PRE "iwlwifi-7265D-" -#define IWL7265D_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" +#define IWL7265D_MODULE_FIRMWARE(api) IWL7265D_FW_PRE __stringify(api) ".ucode"  #define NVM_HW_SECTION_NUM_FAMILY_7000		0 diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index bf0a95cb7153..3668fc57e770 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -69,7 +69,7 @@  #include "iwl-agn-hw.h"  /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX	10 +#define IWL8000_UCODE_API_MAX	12  /* Oldest version we won't warn about */  #define IWL8000_UCODE_API_OK	10 diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 38de1513e4de..850b85a47806 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1323,10 +1323,10 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)   try_again:  	/* try next, if any */ -	kfree(pieces);  	release_firmware(ucode_raw);  	if (iwl_request_firmware(drv, false))  		goto out_unbind; +	kfree(pieces);  	return;   out_free_fw: diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 9564ae173d06..1f7f15eb86da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -310,6 +310,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)  #define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE	(0x01000000)  #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT	28 +#define FH_MEM_TB_MAX_LENGTH			(0x00020000)  /* TFDB  Area - TFDs buffer table */  #define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK      (0xFFFFFFFF) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index f2a047f6bb3e..1bbe4fc47b97 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -243,6 +243,9 @@ enum iwl_ucode_tlv_flag {   * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif.   * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time   *	longer than the passive one, which is essential for fragmented scan. + * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, + *	regardless of the band or the number of the probes. FW will calculate + *	the actual dwell time.   */  enum iwl_ucode_tlv_api {  	IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID	= BIT(0), @@ -253,6 +256,7 @@ enum iwl_ucode_tlv_api {  	IWL_UCODE_TLV_API_LMAC_SCAN		= BIT(6),  	IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF	= BIT(7),  	IWL_UCODE_TLV_API_FRAGMENTED_SCAN	= BIT(8), +	IWL_UCODE_TLV_API_BASIC_DWELL		= BIT(13),  };  /** diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 1f2acf47bfb2..201846de94e7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -672,6 +672,7 @@ struct iwl_scan_channel_opt {   * @IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented   * @IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED: insert WFA vendor-specific TPC report   *	and DS parameter set IEs into probe requests. + * @IWL_MVM_LMAC_SCAN_FLAG_MATCH: Send match found notification on matches   */  enum iwl_mvm_lmac_scan_flags {  	IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL		= BIT(0), @@ -681,6 +682,7 @@ enum iwl_mvm_lmac_scan_flags {  	IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS	= BIT(4),  	IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED	= BIT(5),  	IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED	= BIT(6), +	IWL_MVM_LMAC_SCAN_FLAG_MATCH		= BIT(9),  };  enum iwl_scan_priority { diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 31a5b3f4266c..e880f9d4717b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1004,8 +1004,13 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)  {  	lockdep_assert_held(&mvm->mutex); -	/* disallow low power states when the FW is down */ -	iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); +	/* +	 * Disallow low power states when the FW is down by taking +	 * the UCODE_DOWN ref. in case of ongoing hw restart the +	 * ref is already taken, so don't take it again. +	 */ +	if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) +		iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);  	/* async_handlers_wk is now blocked */ @@ -1023,6 +1028,12 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)  	/* the fw is stopped, the aux sta is dead: clean up driver state */  	iwl_mvm_del_aux_sta(mvm); +	/* +	 * Clear IN_HW_RESTART flag when stopping the hw (as restart_complete() +	 * won't be called in this case). +	 */ +	clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); +  	mvm->ucode_loaded = false;  } diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index e5294d01181e..ec9a8e7bae1d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -171,15 +171,21 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid,   * 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) +static u16 iwl_mvm_get_active_dwell(struct iwl_mvm *mvm, +				    enum ieee80211_band band, int n_ssids)  { +	if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BASIC_DWELL) +		return 10;  	if (band == IEEE80211_BAND_2GHZ)  		return 20  + 3 * (n_ssids + 1);  	return 10  + 2 * (n_ssids + 1);  } -static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band) +static u16 iwl_mvm_get_passive_dwell(struct iwl_mvm *mvm, +				     enum ieee80211_band band)  { +	if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BASIC_DWELL) +			return 110;  	return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10;  } @@ -331,7 +337,8 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,  		 */  		if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {  			u32 passive_dwell = -				iwl_mvm_get_passive_dwell(IEEE80211_BAND_2GHZ); +				iwl_mvm_get_passive_dwell(mvm, +							  IEEE80211_BAND_2GHZ);  			params->max_out_time = passive_dwell;  		} else {  			params->passive_fragmented = true; @@ -348,8 +355,8 @@ not_bound:  			params->dwell[band].passive = frag_passive_dwell;  		else  			params->dwell[band].passive = -				iwl_mvm_get_passive_dwell(band); -		params->dwell[band].active = iwl_mvm_get_active_dwell(band, +				iwl_mvm_get_passive_dwell(mvm, band); +		params->dwell[band].active = iwl_mvm_get_active_dwell(mvm, band,  								      n_ssids);  	}  } @@ -1448,6 +1455,8 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,  	if (iwl_mvm_scan_pass_all(mvm, req))  		flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL; +	else +		flags |= IWL_MVM_LMAC_SCAN_FLAG_MATCH;  	if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0)  		flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 4f15d9decc81..4333306ccdee 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -108,8 +108,12 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,  			tx_flags &= ~TX_CMD_FLG_SEQ_CTL;  	} -	/* tid_tspec will default to 0 = BE when QOS isn't enabled */ -	ac = tid_to_mac80211_ac[tx_cmd->tid_tspec]; +	/* Default to 0 (BE) when tid_spec is set to IWL_TID_NON_QOS */ +	if (tx_cmd->tid_tspec < IWL_MAX_TID_COUNT) +		ac = tid_to_mac80211_ac[tx_cmd->tid_tspec]; +	else +		ac = tid_to_mac80211_ac[0]; +  	tx_flags |= iwl_mvm_bt_coex_tx_prio(mvm, hdr, info, ac) <<  			TX_CMD_FLG_BT_PRIO_POS; diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index e56e77ef5d2e..917431e30f74 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -665,7 +665,7 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm)  	if (num_of_ant(mvm->fw->valid_rx_ant) == 1)  		return false; -	if (!mvm->cfg->rx_with_siso_diversity) +	if (mvm->cfg->rx_with_siso_diversity)  		return false;  	ieee80211_iterate_active_interfaces_atomic( diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 3ee8e3848876..d5aadb00dd9e 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -367,7 +367,11 @@ static const struct pci_device_id iwl_hw_card_ids[] = {  /* 3165 Series */  	{IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)}, +	{IWL_PCI_DEVICE(0x3165, 0x4012, iwl3165_2ac_cfg)}, +	{IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)},  	{IWL_PCI_DEVICE(0x3165, 0x4210, iwl3165_2ac_cfg)}, +	{IWL_PCI_DEVICE(0x3165, 0x4410, iwl3165_2ac_cfg)}, +	{IWL_PCI_DEVICE(0x3165, 0x4510, iwl3165_2ac_cfg)},  /* 7265 Series */  	{IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, @@ -523,8 +527,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	else if (cfg == &iwl7265_n_cfg)  		cfg_7265d = &iwl7265d_n_cfg;  	if (cfg_7265d && -	    (iwl_trans->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D) +	    (iwl_trans->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D) {  		cfg = cfg_7265d; +		iwl_trans->cfg = cfg_7265d; +	}  #endif  	pci_set_drvdata(pdev, iwl_trans); diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 5d79a1f44b8e..523fe0c88dcb 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -614,7 +614,7 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,  {  	u8 *v_addr;  	dma_addr_t p_addr; -	u32 offset, chunk_sz = section->len; +	u32 offset, chunk_sz = min_t(u32, FH_MEM_TB_MAX_LENGTH, section->len);  	int ret = 0;  	IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n", @@ -1012,16 +1012,21 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)  	/* Stop the device, and put it in low power state */  	iwl_pcie_apm_stop(trans); -	/* Upon stop, the APM issues an interrupt if HW RF kill is set. -	 * Clean again the interrupt here +	/* stop and reset the on-board processor */ +	iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); +	udelay(20); + +	/* +	 * Upon stop, the APM issues an interrupt if HW RF kill is set. +	 * This is a bug in certain verions of the hardware. +	 * Certain devices also keep sending HW RF kill interrupt all +	 * the time, unless the interrupt is ACKed even if the interrupt +	 * should be masked. Re-ACK all the interrupts here.  	 */  	spin_lock(&trans_pcie->irq_lock);  	iwl_disable_interrupts(trans);  	spin_unlock(&trans_pcie->irq_lock); -	/* stop and reset the on-board processor */ -	iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); -	udelay(20);  	/* clear all status bits */  	clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 846a2e6e34d8..c70efb9a6e78 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -666,7 +666,8 @@ tx_status_ok:  }  static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw, -				    u8 *entry, int rxring_idx, int desc_idx) +				    struct sk_buff *new_skb, u8 *entry, +				    int rxring_idx, int desc_idx)  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); @@ -674,11 +675,15 @@ static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,  	u8 tmp_one = 1;  	struct sk_buff *skb; +	if (likely(new_skb)) { +		skb = new_skb; +		goto remap; +	}  	skb = dev_alloc_skb(rtlpci->rxbuffersize);  	if (!skb)  		return 0; -	rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb; +remap:  	/* just set skb->cb to mapping addr for pci_unmap_single use */  	*((dma_addr_t *)skb->cb) =  		pci_map_single(rtlpci->pdev, skb_tail_pointer(skb), @@ -686,6 +691,7 @@ static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,  	bufferaddress = *((dma_addr_t *)skb->cb);  	if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))  		return 0; +	rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb;  	if (rtlpriv->use_new_trx_flow) {  		rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,  					    HW_DESC_RX_PREPARE, @@ -781,6 +787,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)  		/*rx pkt */  		struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[  				      rtlpci->rx_ring[rxring_idx].idx]; +		struct sk_buff *new_skb;  		if (rtlpriv->use_new_trx_flow) {  			rx_remained_cnt = @@ -807,6 +814,13 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)  		pci_unmap_single(rtlpci->pdev, *((dma_addr_t *)skb->cb),  				 rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); +		/* get a new skb - if fail, old one will be reused */ +		new_skb = dev_alloc_skb(rtlpci->rxbuffersize); +		if (unlikely(!new_skb)) { +			pr_err("Allocation of new skb failed in %s\n", +			       __func__); +			goto no_new; +		}  		if (rtlpriv->use_new_trx_flow) {  			buffer_desc =  			  &rtlpci->rx_ring[rxring_idx].buffer_desc @@ -911,14 +925,16 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)  			schedule_work(&rtlpriv->works.lps_change_work);  		}  end: +		skb = new_skb; +no_new:  		if (rtlpriv->use_new_trx_flow) { -			_rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc, +			_rtl_pci_init_one_rxdesc(hw, skb, (u8 *)buffer_desc,  						 rxring_idx, -					       rtlpci->rx_ring[rxring_idx].idx); +						 rtlpci->rx_ring[rxring_idx].idx);  		} else { -			_rtl_pci_init_one_rxdesc(hw, (u8 *)pdesc, rxring_idx, +			_rtl_pci_init_one_rxdesc(hw, skb, (u8 *)pdesc, +						 rxring_idx,  						 rtlpci->rx_ring[rxring_idx].idx); -  			if (rtlpci->rx_ring[rxring_idx].idx ==  			    rtlpci->rxringcount - 1)  				rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, @@ -1307,7 +1323,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx)  		rtlpci->rx_ring[rxring_idx].idx = 0;  		for (i = 0; i < rtlpci->rxringcount; i++) {  			entry = &rtlpci->rx_ring[rxring_idx].buffer_desc[i]; -			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry, +			if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry,  						      rxring_idx, i))  				return -ENOMEM;  		} @@ -1332,7 +1348,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx)  		for (i = 0; i < rtlpci->rxringcount; i++) {  			entry = &rtlpci->rx_ring[rxring_idx].desc[i]; -			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry, +			if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry,  						      rxring_idx, i))  				return -ENOMEM;  		} diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index efbaf2ae1999..794204e34fba 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -737,6 +737,7 @@ static void connect(struct backend_info *be)  		}  		queue->remaining_credit = credit_bytes; +		queue->credit_usec = credit_usec;  		err = connect_rings(be, queue);  		if (err) { diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 22bcb4e12e2a..d8c10764f130 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -88,10 +88,8 @@ struct netfront_cb {  #define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 3)  struct netfront_stats { -	u64			rx_packets; -	u64			tx_packets; -	u64			rx_bytes; -	u64			tx_bytes; +	u64			packets; +	u64			bytes;  	struct u64_stats_sync	syncp;  }; @@ -160,7 +158,8 @@ struct netfront_info {  	struct netfront_queue *queues;  	/* Statistics */ -	struct netfront_stats __percpu *stats; +	struct netfront_stats __percpu *rx_stats; +	struct netfront_stats __percpu *tx_stats;  	atomic_t rx_gso_checksum_fixup;  }; @@ -565,7 +564,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)  {  	unsigned short id;  	struct netfront_info *np = netdev_priv(dev); -	struct netfront_stats *stats = this_cpu_ptr(np->stats); +	struct netfront_stats *tx_stats = this_cpu_ptr(np->tx_stats);  	struct xen_netif_tx_request *tx;  	char *data = skb->data;  	RING_IDX i; @@ -672,10 +671,10 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)  	if (notify)  		notify_remote_via_irq(queue->tx_irq); -	u64_stats_update_begin(&stats->syncp); -	stats->tx_bytes += skb->len; -	stats->tx_packets++; -	u64_stats_update_end(&stats->syncp); +	u64_stats_update_begin(&tx_stats->syncp); +	tx_stats->bytes += skb->len; +	tx_stats->packets++; +	u64_stats_update_end(&tx_stats->syncp);  	/* Note: It is not safe to access skb after xennet_tx_buf_gc()! */  	xennet_tx_buf_gc(queue); @@ -931,7 +930,7 @@ static int checksum_setup(struct net_device *dev, struct sk_buff *skb)  static int handle_incoming_queue(struct netfront_queue *queue,  				 struct sk_buff_head *rxq)  { -	struct netfront_stats *stats = this_cpu_ptr(queue->info->stats); +	struct netfront_stats *rx_stats = this_cpu_ptr(queue->info->rx_stats);  	int packets_dropped = 0;  	struct sk_buff *skb; @@ -952,10 +951,10 @@ static int handle_incoming_queue(struct netfront_queue *queue,  			continue;  		} -		u64_stats_update_begin(&stats->syncp); -		stats->rx_packets++; -		stats->rx_bytes += skb->len; -		u64_stats_update_end(&stats->syncp); +		u64_stats_update_begin(&rx_stats->syncp); +		rx_stats->packets++; +		rx_stats->bytes += skb->len; +		u64_stats_update_end(&rx_stats->syncp);  		/* Pass it up. */  		napi_gro_receive(&queue->napi, skb); @@ -1079,18 +1078,22 @@ static struct rtnl_link_stats64 *xennet_get_stats64(struct net_device *dev,  	int cpu;  	for_each_possible_cpu(cpu) { -		struct netfront_stats *stats = per_cpu_ptr(np->stats, cpu); +		struct netfront_stats *rx_stats = per_cpu_ptr(np->rx_stats, cpu); +		struct netfront_stats *tx_stats = per_cpu_ptr(np->tx_stats, cpu);  		u64 rx_packets, rx_bytes, tx_packets, tx_bytes;  		unsigned int start;  		do { -			start = u64_stats_fetch_begin_irq(&stats->syncp); +			start = u64_stats_fetch_begin_irq(&tx_stats->syncp); +			tx_packets = tx_stats->packets; +			tx_bytes = tx_stats->bytes; +		} while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); -			rx_packets = stats->rx_packets; -			tx_packets = stats->tx_packets; -			rx_bytes = stats->rx_bytes; -			tx_bytes = stats->tx_bytes; -		} while (u64_stats_fetch_retry_irq(&stats->syncp, start)); +		do { +			start = u64_stats_fetch_begin_irq(&rx_stats->syncp); +			rx_packets = rx_stats->packets; +			rx_bytes = rx_stats->bytes; +		} while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start));  		tot->rx_packets += rx_packets;  		tot->tx_packets += tx_packets; @@ -1275,6 +1278,15 @@ static const struct net_device_ops xennet_netdev_ops = {  #endif  }; +static void xennet_free_netdev(struct net_device *netdev) +{ +	struct netfront_info *np = netdev_priv(netdev); + +	free_percpu(np->rx_stats); +	free_percpu(np->tx_stats); +	free_netdev(netdev); +} +  static struct net_device *xennet_create_dev(struct xenbus_device *dev)  {  	int err; @@ -1295,8 +1307,11 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)  	np->queues = NULL;  	err = -ENOMEM; -	np->stats = netdev_alloc_pcpu_stats(struct netfront_stats); -	if (np->stats == NULL) +	np->rx_stats = netdev_alloc_pcpu_stats(struct netfront_stats); +	if (np->rx_stats == NULL) +		goto exit; +	np->tx_stats = netdev_alloc_pcpu_stats(struct netfront_stats); +	if (np->tx_stats == NULL)  		goto exit;  	netdev->netdev_ops	= &xennet_netdev_ops; @@ -1327,7 +1342,7 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)  	return netdev;   exit: -	free_netdev(netdev); +	xennet_free_netdev(netdev);  	return ERR_PTR(err);  } @@ -1369,7 +1384,7 @@ static int netfront_probe(struct xenbus_device *dev,  	return 0;   fail: -	free_netdev(netdev); +	xennet_free_netdev(netdev);  	dev_set_drvdata(&dev->dev, NULL);  	return err;  } @@ -2189,9 +2204,7 @@ static int xennet_remove(struct xenbus_device *dev)  		info->queues = NULL;  	} -	free_percpu(info->stats); - -	free_netdev(info->netdev); +	xennet_free_netdev(info->netdev);  	return 0;  } |