diff options
Diffstat (limited to 'drivers/net/ethernet/freescale')
| -rw-r--r-- | drivers/net/ethernet/freescale/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/net/ethernet/freescale/Makefile | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/freescale/fec.c | 412 | ||||
| -rw-r--r-- | drivers/net/ethernet/freescale/fec.h | 23 | ||||
| -rw-r--r-- | drivers/net/ethernet/freescale/fec_mpc52xx.c | 66 | ||||
| -rw-r--r-- | drivers/net/ethernet/freescale/fec_ptp.c | 4 | ||||
| -rw-r--r-- | drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c | 4 | ||||
| -rw-r--r-- | drivers/net/ethernet/freescale/gianfar.c | 278 | ||||
| -rw-r--r-- | drivers/net/ethernet/freescale/gianfar.h | 208 | ||||
| -rw-r--r-- | drivers/net/ethernet/freescale/gianfar_ethtool.c | 35 | ||||
| -rw-r--r-- | drivers/net/ethernet/freescale/ucc_geth_ethtool.c | 8 | 
11 files changed, 629 insertions, 421 deletions
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index ec490d741fc..6048dc8604e 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -26,6 +26,7 @@ config FEC  		   ARCH_MXC || SOC_IMX28)  	default ARCH_MXC || SOC_IMX28 if ARM  	select PHYLIB +	select PTP_1588_CLOCK  	---help---  	  Say Y here if you want to use the built-in 10/100 Fast ethernet  	  controller on some Motorola ColdFire and Freescale i.MX processors. @@ -92,12 +93,4 @@ config GIANFAR  	  This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,  	  and MPC86xx family of chips, and the FEC on the 8540. -config FEC_PTP -	bool "PTP Hardware Clock (PHC)" -	depends on FEC && ARCH_MXC && !SOC_IMX25 && !SOC_IMX27 && !SOC_IMX35 && !SOC_IMX5 -	select PTP_1588_CLOCK -	--help--- -	  Say Y here if you want to use PTP Hardware Clock (PHC) in the -	  driver.  Only the basic clock operations have been implemented. -  endif # NET_VENDOR_FREESCALE diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile index d4d19b3d00a..b7d58fe6f53 100644 --- a/drivers/net/ethernet/freescale/Makefile +++ b/drivers/net/ethernet/freescale/Makefile @@ -2,8 +2,7 @@  # Makefile for the Freescale network device drivers.  # -obj-$(CONFIG_FEC) += fec.o -obj-$(CONFIG_FEC_PTP) += fec_ptp.o +obj-$(CONFIG_FEC) += fec.o fec_ptp.o  obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o  ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)  	obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c index 0704bcab178..fccc3bf2141 100644 --- a/drivers/net/ethernet/freescale/fec.c +++ b/drivers/net/ethernet/freescale/fec.c @@ -67,6 +67,15 @@  #endif  #define DRIVER_NAME	"fec" +#define FEC_NAPI_WEIGHT	64 + +/* Pause frame feild and FIFO threshold */ +#define FEC_ENET_FCE	(1 << 5) +#define FEC_ENET_RSEM_V	0x84 +#define FEC_ENET_RSFL_V	16 +#define FEC_ENET_RAEM_V	0x8 +#define FEC_ENET_RAFL_V	0x8 +#define FEC_ENET_OPD_V	0xFFF0  /* Controller is ENET-MAC */  #define FEC_QUIRK_ENET_MAC		(1 << 0) @@ -76,6 +85,8 @@  #define FEC_QUIRK_USE_GASKET		(1 << 2)  /* Controller has GBIT support */  #define FEC_QUIRK_HAS_GBIT		(1 << 3) +/* Controller has extend desc buffer */ +#define FEC_QUIRK_HAS_BUFDESC_EX	(1 << 4)  static struct platform_device_id fec_devtype[] = {  	{ @@ -93,7 +104,8 @@ static struct platform_device_id fec_devtype[] = {  		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,  	}, {  		.name = "imx6q-fec", -		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT, +		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | +				FEC_QUIRK_HAS_BUFDESC_EX,  	}, {  		/* sentinel */  	} @@ -140,7 +152,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");  #endif  #endif /* CONFIG_M5272 */ -#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE) +#if (((RX_RING_SIZE + TX_RING_SIZE) * 32) > PAGE_SIZE)  #error "FEC: descriptor ring size constants too large"  #endif @@ -157,6 +169,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");  #define FEC_ENET_EBERR	((uint)0x00400000)	/* SDMA bus error */  #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII) +#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))  /* The FEC stores dest/src/type, data, and checksum for receive packets.   */ @@ -190,8 +203,29 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");  /* Transmitter timeout */  #define TX_TIMEOUT (2 * HZ) +#define FEC_PAUSE_FLAG_AUTONEG	0x1 +#define FEC_PAUSE_FLAG_ENABLE	0x2 +  static int mii_cnt; +static struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, int is_ex) +{ +	struct bufdesc_ex *ex = (struct bufdesc_ex *)bdp; +	if (is_ex) +		return (struct bufdesc *)(ex + 1); +	else +		return bdp + 1; +} + +static struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp, int is_ex) +{ +	struct bufdesc_ex *ex = (struct bufdesc_ex *)bdp; +	if (is_ex) +		return (struct bufdesc *)(ex - 1); +	else +		return bdp - 1; +} +  static void *swap_buffer(void *bufaddr, int len)  {  	int i; @@ -248,7 +282,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)  	 */  	if (((unsigned long) bufaddr) & FEC_ALIGNMENT) {  		unsigned int index; -		index = bdp - fep->tx_bd_base; +		if (fep->bufdesc_ex) +			index = (struct bufdesc_ex *)bdp - +				(struct bufdesc_ex *)fep->tx_bd_base; +		else +			index = bdp - fep->tx_bd_base;  		memcpy(fep->tx_bounce[index], skb->data, skb->len);  		bufaddr = fep->tx_bounce[index];  	} @@ -280,17 +318,19 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)  			| BD_ENET_TX_LAST | BD_ENET_TX_TC);  	bdp->cbd_sc = status; -#ifdef CONFIG_FEC_PTP -	bdp->cbd_bdu = 0; -	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && +	if (fep->bufdesc_ex) { + +		struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; +		ebdp->cbd_bdu = 0; +		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&  			fep->hwts_tx_en)) { -			bdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT); +			ebdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);  			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; -	} else { +		} else { -		bdp->cbd_esc = BD_ENET_TX_INT; +			ebdp->cbd_esc = BD_ENET_TX_INT; +		}  	} -#endif  	/* Trigger transmission start */  	writel(0, fep->hwp + FEC_X_DES_ACTIVE); @@ -298,7 +338,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)  	if (status & BD_ENET_TX_WRAP)  		bdp = fep->tx_bd_base;  	else -		bdp++; +		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);  	if (bdp == fep->dirty_tx) {  		fep->tx_full = 1; @@ -359,8 +399,12 @@ fec_restart(struct net_device *ndev, int duplex)  	/* Set receive and transmit descriptor base. */  	writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); -	writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE, -			fep->hwp + FEC_X_DES_START); +	if (fep->bufdesc_ex) +		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc_ex) +			* RX_RING_SIZE, fep->hwp + FEC_X_DES_START); +	else +		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) +			* RX_RING_SIZE,	fep->hwp + FEC_X_DES_START);  	fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;  	fep->cur_rx = fep->rx_bd_base; @@ -439,6 +483,25 @@ fec_restart(struct net_device *ndev, int duplex)  		}  #endif  	} + +	/* enable pause frame*/ +	if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) || +	    ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) && +	     fep->phy_dev && fep->phy_dev->pause)) { +		rcntl |= FEC_ENET_FCE; + +		/* set FIFO thresh hold parameter to reduce overrun */ +		writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM); +		writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL); +		writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM); +		writel(FEC_ENET_RAFL_V, fep->hwp + FEC_R_FIFO_RAFL); + +		/* OPD */ +		writel(FEC_ENET_OPD_V, fep->hwp + FEC_OPD); +	} else { +		rcntl &= ~FEC_ENET_FCE; +	} +  	writel(rcntl, fep->hwp + FEC_R_CNTRL);  	if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { @@ -448,17 +511,16 @@ fec_restart(struct net_device *ndev, int duplex)  		writel(1 << 8, fep->hwp + FEC_X_WMRK);  	} -#ifdef CONFIG_FEC_PTP -	ecntl |= (1 << 4); -#endif +	if (fep->bufdesc_ex) +		ecntl |= (1 << 4);  	/* And last, enable the transmit and receive processing */  	writel(ecntl, fep->hwp + FEC_ECNTRL);  	writel(0, fep->hwp + FEC_R_DES_ACTIVE); -#ifdef CONFIG_FEC_PTP -	fec_ptp_start_cyclecounter(ndev); -#endif +	if (fep->bufdesc_ex) +		fec_ptp_start_cyclecounter(ndev); +  	/* Enable interrupts we wish to service */  	writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);  } @@ -544,19 +606,20 @@ fec_enet_tx(struct net_device *ndev)  			ndev->stats.tx_packets++;  		} -#ifdef CONFIG_FEC_PTP -		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) { +		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) && +			fep->bufdesc_ex) {  			struct skb_shared_hwtstamps shhwtstamps;  			unsigned long flags; +			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;  			memset(&shhwtstamps, 0, sizeof(shhwtstamps));  			spin_lock_irqsave(&fep->tmreg_lock, flags);  			shhwtstamps.hwtstamp = ns_to_ktime( -				timecounter_cyc2time(&fep->tc, bdp->ts)); +				timecounter_cyc2time(&fep->tc, ebdp->ts));  			spin_unlock_irqrestore(&fep->tmreg_lock, flags);  			skb_tstamp_tx(skb, &shhwtstamps);  		} -#endif +  		if (status & BD_ENET_TX_READY)  			printk("HEY! Enet xmit interrupt and TX_READY.\n"); @@ -575,7 +638,7 @@ fec_enet_tx(struct net_device *ndev)  		if (status & BD_ENET_TX_WRAP)  			bdp = fep->tx_bd_base;  		else -			bdp++; +			bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);  		/* Since we have freed up a buffer, the ring is no longer full  		 */ @@ -595,8 +658,8 @@ fec_enet_tx(struct net_device *ndev)   * not been given to the system, we just set the empty indicator,   * effectively tossing the packet.   */ -static void -fec_enet_rx(struct net_device *ndev) +static int +fec_enet_rx(struct net_device *ndev, int budget)  {  	struct fec_enet_private *fep = netdev_priv(ndev);  	const struct platform_device_id *id_entry = @@ -606,13 +669,12 @@ fec_enet_rx(struct net_device *ndev)  	struct	sk_buff	*skb;  	ushort	pkt_len;  	__u8 *data; +	int	pkt_received = 0;  #ifdef CONFIG_M532x  	flush_cache_all();  #endif -	spin_lock(&fep->hw_lock); -  	/* First, grab all of the stats for the incoming packet.  	 * These get messed up if we get called due to a busy condition.  	 */ @@ -620,6 +682,10 @@ fec_enet_rx(struct net_device *ndev)  	while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { +		if (pkt_received >= budget) +			break; +		pkt_received++; +  		/* Since we have allocated space to hold a complete frame,  		 * the last indicator should be set.  		 */ @@ -683,23 +749,25 @@ fec_enet_rx(struct net_device *ndev)  			skb_put(skb, pkt_len - 4);	/* Make room */  			skb_copy_to_linear_data(skb, data, pkt_len - 4);  			skb->protocol = eth_type_trans(skb, ndev); -#ifdef CONFIG_FEC_PTP +  			/* Get receive timestamp from the skb */ -			if (fep->hwts_rx_en) { +			if (fep->hwts_rx_en && fep->bufdesc_ex) {  				struct skb_shared_hwtstamps *shhwtstamps =  							    skb_hwtstamps(skb);  				unsigned long flags; +				struct bufdesc_ex *ebdp = +					(struct bufdesc_ex *)bdp;  				memset(shhwtstamps, 0, sizeof(*shhwtstamps));  				spin_lock_irqsave(&fep->tmreg_lock, flags);  				shhwtstamps->hwtstamp = ns_to_ktime( -				    timecounter_cyc2time(&fep->tc, bdp->ts)); +				    timecounter_cyc2time(&fep->tc, ebdp->ts));  				spin_unlock_irqrestore(&fep->tmreg_lock, flags);  			} -#endif +  			if (!skb_defer_rx_timestamp(skb)) -				netif_rx(skb); +				napi_gro_receive(&fep->napi, skb);  		}  		bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data, @@ -712,17 +780,19 @@ rx_processing_done:  		status |= BD_ENET_RX_EMPTY;  		bdp->cbd_sc = status; -#ifdef CONFIG_FEC_PTP -		bdp->cbd_esc = BD_ENET_RX_INT; -		bdp->cbd_prot = 0; -		bdp->cbd_bdu = 0; -#endif +		if (fep->bufdesc_ex) { +			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; + +			ebdp->cbd_esc = BD_ENET_RX_INT; +			ebdp->cbd_prot = 0; +			ebdp->cbd_bdu = 0; +		}  		/* Update BD pointer to next entry */  		if (status & BD_ENET_RX_WRAP)  			bdp = fep->rx_bd_base;  		else -			bdp++; +			bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);  		/* Doing this here will keep the FEC running while we process  		 * incoming frames.  On a heavily loaded network, we should be  		 * able to keep up at the expense of system resources. @@ -731,7 +801,7 @@ rx_processing_done:  	}  	fep->cur_rx = bdp; -	spin_unlock(&fep->hw_lock); +	return pkt_received;  }  static irqreturn_t @@ -748,7 +818,13 @@ fec_enet_interrupt(int irq, void *dev_id)  		if (int_events & FEC_ENET_RXF) {  			ret = IRQ_HANDLED; -			fec_enet_rx(ndev); + +			/* Disable the RX interrupt */ +			if (napi_schedule_prep(&fep->napi)) { +				writel(FEC_RX_DISABLED_IMASK, +					fep->hwp + FEC_IMASK); +				__napi_schedule(&fep->napi); +			}  		}  		/* Transmit OK, or non-fatal error. Update the buffer @@ -769,10 +845,21 @@ fec_enet_interrupt(int irq, void *dev_id)  	return ret;  } +static int fec_enet_rx_napi(struct napi_struct *napi, int budget) +{ +	struct net_device *ndev = napi->dev; +	int pkts = fec_enet_rx(ndev, budget); +	struct fec_enet_private *fep = netdev_priv(ndev); +	if (pkts < budget) { +		napi_complete(napi); +		writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); +	} +	return pkts; +}  /* ------------------------------------------------------------------------- */ -static void __inline__ fec_get_mac(struct net_device *ndev) +static void fec_get_mac(struct net_device *ndev)  {  	struct fec_enet_private *fep = netdev_priv(ndev);  	struct fec_platform_data *pdata = fep->pdev->dev.platform_data; @@ -973,7 +1060,7 @@ static int fec_enet_mii_probe(struct net_device *ndev)  	}  	snprintf(phy_name, sizeof(phy_name), PHY_ID_FMT, mdio_bus_id, phy_id); -	phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0, +	phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link,  			      fep->phy_interface);  	if (IS_ERR(phy_dev)) {  		printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name); @@ -981,8 +1068,10 @@ static int fec_enet_mii_probe(struct net_device *ndev)  	}  	/* mask with MAC supported features */ -	if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) +	if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) {  		phy_dev->supported &= PHY_GBIT_FEATURES; +		phy_dev->supported |= SUPPORTED_Pause; +	}  	else  		phy_dev->supported &= PHY_BASIC_FEATURES; @@ -1133,17 +1222,95 @@ static void fec_enet_get_drvinfo(struct net_device *ndev,  {  	struct fec_enet_private *fep = netdev_priv(ndev); -	strcpy(info->driver, fep->pdev->dev.driver->name); -	strcpy(info->version, "Revision: 1.0"); -	strcpy(info->bus_info, dev_name(&ndev->dev)); +	strlcpy(info->driver, fep->pdev->dev.driver->name, +		sizeof(info->driver)); +	strlcpy(info->version, "Revision: 1.0", sizeof(info->version)); +	strlcpy(info->bus_info, dev_name(&ndev->dev), sizeof(info->bus_info)); +} + +static int fec_enet_get_ts_info(struct net_device *ndev, +				struct ethtool_ts_info *info) +{ +	struct fec_enet_private *fep = netdev_priv(ndev); + +	if (fep->bufdesc_ex) { + +		info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | +					SOF_TIMESTAMPING_RX_SOFTWARE | +					SOF_TIMESTAMPING_SOFTWARE | +					SOF_TIMESTAMPING_TX_HARDWARE | +					SOF_TIMESTAMPING_RX_HARDWARE | +					SOF_TIMESTAMPING_RAW_HARDWARE; +		if (fep->ptp_clock) +			info->phc_index = ptp_clock_index(fep->ptp_clock); +		else +			info->phc_index = -1; + +		info->tx_types = (1 << HWTSTAMP_TX_OFF) | +				 (1 << HWTSTAMP_TX_ON); + +		info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | +				   (1 << HWTSTAMP_FILTER_ALL); +		return 0; +	} else { +		return ethtool_op_get_ts_info(ndev, info); +	} +} + +static void fec_enet_get_pauseparam(struct net_device *ndev, +				    struct ethtool_pauseparam *pause) +{ +	struct fec_enet_private *fep = netdev_priv(ndev); + +	pause->autoneg = (fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) != 0; +	pause->tx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) != 0; +	pause->rx_pause = pause->tx_pause; +} + +static int fec_enet_set_pauseparam(struct net_device *ndev, +				   struct ethtool_pauseparam *pause) +{ +	struct fec_enet_private *fep = netdev_priv(ndev); + +	if (pause->tx_pause != pause->rx_pause) { +		netdev_info(ndev, +			"hardware only support enable/disable both tx and rx"); +		return -EINVAL; +	} + +	fep->pause_flag = 0; + +	/* tx pause must be same as rx pause */ +	fep->pause_flag |= pause->rx_pause ? FEC_PAUSE_FLAG_ENABLE : 0; +	fep->pause_flag |= pause->autoneg ? FEC_PAUSE_FLAG_AUTONEG : 0; + +	if (pause->rx_pause || pause->autoneg) { +		fep->phy_dev->supported |= ADVERTISED_Pause; +		fep->phy_dev->advertising |= ADVERTISED_Pause; +	} else { +		fep->phy_dev->supported &= ~ADVERTISED_Pause; +		fep->phy_dev->advertising &= ~ADVERTISED_Pause; +	} + +	if (pause->autoneg) { +		if (netif_running(ndev)) +			fec_stop(ndev); +		phy_start_aneg(fep->phy_dev); +	} +	if (netif_running(ndev)) +		fec_restart(ndev, 0); + +	return 0;  }  static const struct ethtool_ops fec_enet_ethtool_ops = { +	.get_pauseparam		= fec_enet_get_pauseparam, +	.set_pauseparam		= fec_enet_set_pauseparam,  	.get_settings		= fec_enet_get_settings,  	.set_settings		= fec_enet_set_settings,  	.get_drvinfo		= fec_enet_get_drvinfo,  	.get_link		= ethtool_op_get_link, -	.get_ts_info		= ethtool_op_get_ts_info, +	.get_ts_info		= fec_enet_get_ts_info,  };  static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) @@ -1157,10 +1324,9 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)  	if (!phydev)  		return -ENODEV; -#ifdef CONFIG_FEC_PTP -	if (cmd == SIOCSHWTSTAMP) +	if (cmd == SIOCSHWTSTAMP && fep->bufdesc_ex)  		return fec_ptp_ioctl(ndev, rq, cmd); -#endif +  	return phy_mii_ioctl(phydev, rq, cmd);  } @@ -1180,7 +1346,7 @@ static void fec_enet_free_buffers(struct net_device *ndev)  					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);  		if (skb)  			dev_kfree_skb(skb); -		bdp++; +		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);  	}  	bdp = fep->tx_bd_base; @@ -1207,14 +1373,17 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)  		bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data,  				FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);  		bdp->cbd_sc = BD_ENET_RX_EMPTY; -#ifdef CONFIG_FEC_PTP -		bdp->cbd_esc = BD_ENET_RX_INT; -#endif -		bdp++; + +		if (fep->bufdesc_ex) { +			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; +			ebdp->cbd_esc = BD_ENET_RX_INT; +		} + +		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);  	}  	/* Set the last buffer to wrap. */ -	bdp--; +	bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);  	bdp->cbd_sc |= BD_SC_WRAP;  	bdp = fep->tx_bd_base; @@ -1224,14 +1393,16 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)  		bdp->cbd_sc = 0;  		bdp->cbd_bufaddr = 0; -#ifdef CONFIG_FEC_PTP -		bdp->cbd_esc = BD_ENET_RX_INT; -#endif -		bdp++; +		if (fep->bufdesc_ex) { +			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; +			ebdp->cbd_esc = BD_ENET_RX_INT; +		} + +		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);  	}  	/* Set the last buffer to wrap. */ -	bdp--; +	bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);  	bdp->cbd_sc |= BD_SC_WRAP;  	return 0; @@ -1243,6 +1414,8 @@ fec_enet_open(struct net_device *ndev)  	struct fec_enet_private *fep = netdev_priv(ndev);  	int ret; +	napi_enable(&fep->napi); +  	/* I should reset the ring buffers here, but I don't yet know  	 * a simple way to do that.  	 */ @@ -1444,24 +1617,31 @@ static int fec_enet_init(struct net_device *ndev)  	/* Set receive and transmit descriptor base. */  	fep->rx_bd_base = cbd_base; -	fep->tx_bd_base = cbd_base + RX_RING_SIZE; +	if (fep->bufdesc_ex) +		fep->tx_bd_base = (struct bufdesc *) +			(((struct bufdesc_ex *)cbd_base) + RX_RING_SIZE); +	else +		fep->tx_bd_base = cbd_base + RX_RING_SIZE;  	/* The FEC Ethernet specific entries in the device structure */  	ndev->watchdog_timeo = TX_TIMEOUT;  	ndev->netdev_ops = &fec_netdev_ops;  	ndev->ethtool_ops = &fec_enet_ethtool_ops; +	writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK); +	netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT); +  	/* Initialize the receive buffer descriptors. */  	bdp = fep->rx_bd_base;  	for (i = 0; i < RX_RING_SIZE; i++) {  		/* Initialize the BD for every fragment in the page. */  		bdp->cbd_sc = 0; -		bdp++; +		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);  	}  	/* Set the last buffer to wrap */ -	bdp--; +	bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);  	bdp->cbd_sc |= BD_SC_WRAP;  	/* ...and the same for transmit */ @@ -1471,11 +1651,11 @@ static int fec_enet_init(struct net_device *ndev)  		/* Initialize the BD for every fragment in the page. */  		bdp->cbd_sc = 0;  		bdp->cbd_bufaddr = 0; -		bdp++; +		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);  	}  	/* Set the last buffer to wrap */ -	bdp--; +	bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);  	bdp->cbd_sc |= BD_SC_WRAP;  	fec_restart(ndev, 0); @@ -1509,22 +1689,25 @@ static void fec_reset_phy(struct platform_device *pdev)  		msec = 1;  	phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0); +	if (!gpio_is_valid(phy_reset)) +		return; +  	err = devm_gpio_request_one(&pdev->dev, phy_reset,  				    GPIOF_OUT_INIT_LOW, "phy-reset");  	if (err) { -		pr_debug("FEC: failed to get gpio phy-reset: %d\n", err); +		dev_err(&pdev->dev, "failed to get phy-reset-gpios: %d\n", err);  		return;  	}  	msleep(msec);  	gpio_set_value(phy_reset, 1);  }  #else /* CONFIG_OF */ -static inline int fec_get_phy_mode_dt(struct platform_device *pdev) +static int fec_get_phy_mode_dt(struct platform_device *pdev)  {  	return -ENODEV;  } -static inline void fec_reset_phy(struct platform_device *pdev) +static void fec_reset_phy(struct platform_device *pdev)  {  	/*  	 * In case of platform probe, the reset has been done @@ -1570,10 +1753,17 @@ fec_probe(struct platform_device *pdev)  	/* setup board info structure */  	fep = netdev_priv(ndev); +	/* default enable pause frame auto negotiation */ +	if (pdev->id_entry && +	    (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT)) +		fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG; +  	fep->hwp = ioremap(r->start, resource_size(r));  	fep->pdev = pdev;  	fep->dev_id = dev_id++; +	fep->bufdesc_ex = 0; +  	if (!fep->hwp) {  		ret = -ENOMEM;  		goto failed_ioremap; @@ -1592,24 +1782,6 @@ fec_probe(struct platform_device *pdev)  		fep->phy_interface = ret;  	} -	for (i = 0; i < FEC_IRQ_NUM; i++) { -		irq = platform_get_irq(pdev, i); -		if (irq < 0) { -			if (i) -				break; -			ret = irq; -			goto failed_irq; -		} -		ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev); -		if (ret) { -			while (--i >= 0) { -				irq = platform_get_irq(pdev, i); -				free_irq(irq, ndev); -			} -			goto failed_irq; -		} -	} -  	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);  	if (IS_ERR(pinctrl)) {  		ret = PTR_ERR(pinctrl); @@ -1628,19 +1800,19 @@ fec_probe(struct platform_device *pdev)  		goto failed_clk;  	} -#ifdef CONFIG_FEC_PTP  	fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp"); +	fep->bufdesc_ex = +		pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;  	if (IS_ERR(fep->clk_ptp)) {  		ret = PTR_ERR(fep->clk_ptp); -		goto failed_clk; +		fep->bufdesc_ex = 0;  	} -#endif  	clk_prepare_enable(fep->clk_ahb);  	clk_prepare_enable(fep->clk_ipg); -#ifdef CONFIG_FEC_PTP -	clk_prepare_enable(fep->clk_ptp); -#endif +	if (!IS_ERR(fep->clk_ptp)) +		clk_prepare_enable(fep->clk_ptp); +  	reg_phy = devm_regulator_get(&pdev->dev, "phy");  	if (!IS_ERR(reg_phy)) {  		ret = regulator_enable(reg_phy); @@ -1653,10 +1825,31 @@ fec_probe(struct platform_device *pdev)  	fec_reset_phy(pdev); +	if (fep->bufdesc_ex) +		fec_ptp_init(ndev, pdev); +  	ret = fec_enet_init(ndev);  	if (ret)  		goto failed_init; +	for (i = 0; i < FEC_IRQ_NUM; i++) { +		irq = platform_get_irq(pdev, i); +		if (irq < 0) { +			if (i) +				break; +			ret = irq; +			goto failed_irq; +		} +		ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev); +		if (ret) { +			while (--i >= 0) { +				irq = platform_get_irq(pdev, i); +				free_irq(irq, ndev); +			} +			goto failed_irq; +		} +	} +  	ret = fec_enet_mii_init(pdev);  	if (ret)  		goto failed_mii_init; @@ -1668,30 +1861,25 @@ fec_probe(struct platform_device *pdev)  	if (ret)  		goto failed_register; -#ifdef CONFIG_FEC_PTP -	fec_ptp_init(ndev, pdev); -#endif -  	return 0;  failed_register:  	fec_enet_mii_remove(fep);  failed_mii_init:  failed_init: -failed_regulator: -	clk_disable_unprepare(fep->clk_ahb); -	clk_disable_unprepare(fep->clk_ipg); -#ifdef CONFIG_FEC_PTP -	clk_disable_unprepare(fep->clk_ptp); -#endif -failed_pin: -failed_clk:  	for (i = 0; i < FEC_IRQ_NUM; i++) {  		irq = platform_get_irq(pdev, i);  		if (irq > 0)  			free_irq(irq, ndev);  	}  failed_irq: +failed_regulator: +	clk_disable_unprepare(fep->clk_ahb); +	clk_disable_unprepare(fep->clk_ipg); +	if (!IS_ERR(fep->clk_ptp)) +		clk_disable_unprepare(fep->clk_ptp); +failed_pin: +failed_clk:  	iounmap(fep->hwp);  failed_ioremap:  	free_netdev(ndev); @@ -1711,19 +1899,17 @@ fec_drv_remove(struct platform_device *pdev)  	unregister_netdev(ndev);  	fec_enet_mii_remove(fep); -	for (i = 0; i < FEC_IRQ_NUM; i++) { -		int irq = platform_get_irq(pdev, i); -		if (irq > 0) -			free_irq(irq, ndev); -	} -#ifdef CONFIG_FEC_PTP  	del_timer_sync(&fep->time_keep);  	clk_disable_unprepare(fep->clk_ptp);  	if (fep->ptp_clock)  		ptp_clock_unregister(fep->ptp_clock); -#endif  	clk_disable_unprepare(fep->clk_ahb);  	clk_disable_unprepare(fep->clk_ipg); +	for (i = 0; i < FEC_IRQ_NUM; i++) { +		int irq = platform_get_irq(pdev, i); +		if (irq > 0) +			free_irq(irq, ndev); +	}  	iounmap(fep->hwp);  	free_netdev(ndev); diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index c5a3bc1475c..01579b8e37c 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -13,11 +13,9 @@  #define	FEC_H  /****************************************************************************/ -#ifdef CONFIG_FEC_PTP  #include <linux/clocksource.h>  #include <linux/net_tstamp.h>  #include <linux/ptp_clock_kernel.h> -#endif  #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \      defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ @@ -50,6 +48,10 @@  #define FEC_R_DES_START		0x180 /* Receive descriptor ring */  #define FEC_X_DES_START		0x184 /* Transmit descriptor ring */  #define FEC_R_BUFF_SIZE		0x188 /* Maximum receive buff size */ +#define FEC_R_FIFO_RSFL		0x190 /* Receive FIFO section full threshold */ +#define FEC_R_FIFO_RSEM		0x194 /* Receive FIFO section empty threshold */ +#define FEC_R_FIFO_RAEM		0x198 /* Receive FIFO almost empty threshold */ +#define FEC_R_FIFO_RAFL		0x19c /* Receive FIFO almost full threshold */  #define FEC_MIIGSK_CFGR		0x300 /* MIIGSK Configuration reg */  #define FEC_MIIGSK_ENR		0x308 /* MIIGSK Enable reg */ @@ -94,14 +96,17 @@ struct bufdesc {  	unsigned short cbd_datlen;	/* Data length */  	unsigned short cbd_sc;	/* Control and status info */  	unsigned long cbd_bufaddr;	/* Buffer address */ -#ifdef CONFIG_FEC_PTP +}; + +struct bufdesc_ex { +	struct bufdesc desc;  	unsigned long cbd_esc;  	unsigned long cbd_prot;  	unsigned long cbd_bdu;  	unsigned long ts;  	unsigned short res0[4]; -#endif  }; +  #else  struct bufdesc {  	unsigned short	cbd_sc;			/* Control and status info */ @@ -203,9 +208,7 @@ struct fec_enet_private {  	struct clk *clk_ipg;  	struct clk *clk_ahb; -#ifdef CONFIG_FEC_PTP  	struct clk *clk_ptp; -#endif  	/* The saved address of a sent-in-place packet/buffer, for skfree(). */  	unsigned char *tx_bounce[TX_RING_SIZE]; @@ -243,8 +246,11 @@ struct fec_enet_private {  	int	full_duplex;  	struct	completion mdio_done;  	int	irq[FEC_IRQ_NUM]; +	int	bufdesc_ex; +	int	pause_flag; + +	struct	napi_struct napi; -#ifdef CONFIG_FEC_PTP  	struct ptp_clock *ptp_clock;  	struct ptp_clock_info ptp_caps;  	unsigned long last_overflow_check; @@ -257,15 +263,12 @@ struct fec_enet_private {  	int hwts_rx_en;  	int hwts_tx_en;  	struct timer_list time_keep; -#endif  }; -#ifdef CONFIG_FEC_PTP  void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev);  void fec_ptp_start_cyclecounter(struct net_device *ndev);  int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd); -#endif  /****************************************************************************/  #endif /* FEC_H */ diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx.c b/drivers/net/ethernet/freescale/fec_mpc52xx.c index 817d081d2cd..77943a6a1b8 100644 --- a/drivers/net/ethernet/freescale/fec_mpc52xx.c +++ b/drivers/net/ethernet/freescale/fec_mpc52xx.c @@ -29,6 +29,7 @@  #include <linux/delay.h>  #include <linux/of_device.h>  #include <linux/of_mdio.h> +#include <linux/of_net.h>  #include <linux/of_platform.h>  #include <linux/netdevice.h> @@ -40,8 +41,8 @@  #include <asm/delay.h>  #include <asm/mpc52xx.h> -#include <sysdev/bestcomm/bestcomm.h> -#include <sysdev/bestcomm/fec.h> +#include <linux/fsl/bestcomm/bestcomm.h> +#include <linux/fsl/bestcomm/fec.h>  #include "fec_mpc52xx.h" @@ -76,10 +77,6 @@ static void mpc52xx_fec_stop(struct net_device *dev);  static void mpc52xx_fec_start(struct net_device *dev);  static void mpc52xx_fec_reset(struct net_device *dev); -static u8 mpc52xx_fec_mac_addr[6]; -module_param_array_named(mac, mpc52xx_fec_mac_addr, byte, NULL, 0); -MODULE_PARM_DESC(mac, "six hex digits, ie. 0x1,0x2,0xc0,0x01,0xba,0xbe"); -  #define MPC52xx_MESSAGES_DEFAULT ( NETIF_MSG_DRV | NETIF_MSG_PROBE | \  		NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP)  static int debug = -1;	/* the above default */ @@ -110,15 +107,6 @@ static void mpc52xx_fec_set_paddr(struct net_device *dev, u8 *mac)  	out_be32(&fec->paddr2, (*(u16 *)(&mac[4]) << 16) | FEC_PADDR2_TYPE);  } -static void mpc52xx_fec_get_paddr(struct net_device *dev, u8 *mac) -{ -	struct mpc52xx_fec_priv *priv = netdev_priv(dev); -	struct mpc52xx_fec __iomem *fec = priv->fec; - -	*(u32 *)(&mac[0]) = in_be32(&fec->paddr1); -	*(u16 *)(&mac[4]) = in_be32(&fec->paddr2) >> 16; -} -  static int mpc52xx_fec_set_mac_address(struct net_device *dev, void *addr)  {  	struct sockaddr *sock = addr; @@ -853,6 +841,8 @@ static int mpc52xx_fec_probe(struct platform_device *op)  	struct resource mem;  	const u32 *prop;  	int prop_size; +	struct device_node *np = op->dev.of_node; +	const char *mac_addr;  	phys_addr_t rx_fifo;  	phys_addr_t tx_fifo; @@ -866,7 +856,7 @@ static int mpc52xx_fec_probe(struct platform_device *op)  	priv->ndev = ndev;  	/* Reserve FEC control zone */ -	rv = of_address_to_resource(op->dev.of_node, 0, &mem); +	rv = of_address_to_resource(np, 0, &mem);  	if (rv) {  		printk(KERN_ERR DRIVER_NAME ": "  				"Error while parsing device node resource\n" ); @@ -919,7 +909,7 @@ static int mpc52xx_fec_probe(struct platform_device *op)  	/* Get the IRQ we need one by one */  		/* Control */ -	ndev->irq = irq_of_parse_and_map(op->dev.of_node, 0); +	ndev->irq = irq_of_parse_and_map(np, 0);  		/* RX */  	priv->r_irq = bcom_get_task_irq(priv->rx_dmatsk); @@ -927,11 +917,33 @@ static int mpc52xx_fec_probe(struct platform_device *op)  		/* TX */  	priv->t_irq = bcom_get_task_irq(priv->tx_dmatsk); -	/* MAC address init */ -	if (!is_zero_ether_addr(mpc52xx_fec_mac_addr)) -		memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6); -	else -		mpc52xx_fec_get_paddr(ndev, ndev->dev_addr); +	/* +	 * MAC address init: +	 * +	 * First try to read MAC address from DT +	 */ +	mac_addr = of_get_mac_address(np); +	if (mac_addr) { +		memcpy(ndev->dev_addr, mac_addr, ETH_ALEN); +	} else { +		struct mpc52xx_fec __iomem *fec = priv->fec; + +		/* +		 * If the MAC addresse is not provided via DT then read +		 * it back from the controller regs +		 */ +		*(u32 *)(&ndev->dev_addr[0]) = in_be32(&fec->paddr1); +		*(u16 *)(&ndev->dev_addr[4]) = in_be32(&fec->paddr2) >> 16; +	} + +	/* +	 * Check if the MAC address is valid, if not get a random one +	 */ +	if (!is_valid_ether_addr(ndev->dev_addr)) { +		eth_hw_addr_random(ndev); +		dev_warn(&ndev->dev, "using random MAC address %pM\n", +			 ndev->dev_addr); +	}  	priv->msg_enable = netif_msg_init(debug, MPC52xx_MESSAGES_DEFAULT); @@ -942,20 +954,20 @@ static int mpc52xx_fec_probe(struct platform_device *op)  	/* Start with safe defaults for link connection */  	priv->speed = 100;  	priv->duplex = DUPLEX_HALF; -	priv->mdio_speed = ((mpc5xxx_get_bus_frequency(op->dev.of_node) >> 20) / 5) << 1; +	priv->mdio_speed = ((mpc5xxx_get_bus_frequency(np) >> 20) / 5) << 1;  	/* The current speed preconfigures the speed of the MII link */ -	prop = of_get_property(op->dev.of_node, "current-speed", &prop_size); +	prop = of_get_property(np, "current-speed", &prop_size);  	if (prop && (prop_size >= sizeof(u32) * 2)) {  		priv->speed = prop[0];  		priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF;  	}  	/* If there is a phy handle, then get the PHY node */ -	priv->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0); +	priv->phy_node = of_parse_phandle(np, "phy-handle", 0);  	/* the 7-wire property means don't use MII mode */ -	if (of_find_property(op->dev.of_node, "fsl,7-wire-mode", NULL)) { +	if (of_find_property(np, "fsl,7-wire-mode", NULL)) {  		priv->seven_wire_mode = 1;  		dev_info(&ndev->dev, "using 7-wire PHY mode\n");  	} @@ -970,6 +982,8 @@ static int mpc52xx_fec_probe(struct platform_device *op)  	/* We're done ! */  	dev_set_drvdata(&op->dev, ndev); +	printk(KERN_INFO "%s: %s MAC %pM\n", +	       ndev->name, op->dev.of_node->full_name, ndev->dev_addr);  	return 0; diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index c40526c78c2..1f17ca0f220 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -104,7 +104,7 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev)  	unsigned long flags;  	int inc; -	inc = 1000000000 / clk_get_rate(fep->clk_ptp); +	inc = 1000000000 / fep->cycle_speed;  	/* grab the ptp lock */  	spin_lock_irqsave(&fep->tmreg_lock, flags); @@ -363,6 +363,8 @@ void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev)  	fep->ptp_caps.settime = fec_ptp_settime;  	fep->ptp_caps.enable = fec_ptp_enable; +	fep->cycle_speed = clk_get_rate(fep->clk_ptp); +  	spin_lock_init(&fep->tmreg_lock);  	fec_ptp_start_cyclecounter(ndev); diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c index e9879c5af7b..46df28893c1 100644 --- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c @@ -888,8 +888,8 @@ static struct net_device_stats *fs_enet_get_stats(struct net_device *dev)  static void fs_get_drvinfo(struct net_device *dev,  			    struct ethtool_drvinfo *info)  { -	strcpy(info->driver, DRV_MODULE_NAME); -	strcpy(info->version, DRV_MODULE_VERSION); +	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); +	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));  }  static int fs_get_regs_len(struct net_device *dev) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index bffb2edd685..d2c5441d1bf 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -133,8 +133,8 @@ static void gfar_netpoll(struct net_device *dev);  #endif  int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit);  static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue); -static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, -			      int amount_pull, struct napi_struct *napi); +static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, +			       int amount_pull, struct napi_struct *napi);  void gfar_halt(struct net_device *dev);  static void gfar_halt_nodisable(struct net_device *dev);  void gfar_start(struct net_device *dev); @@ -231,7 +231,7 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)  	dma_addr_t addr;  	int i, j, k;  	struct gfar_private *priv = netdev_priv(ndev); -	struct device *dev = &priv->ofdev->dev; +	struct device *dev = priv->dev;  	struct gfar_priv_tx_q *tx_queue = NULL;  	struct gfar_priv_rx_q *rx_queue = NULL; @@ -277,14 +277,12 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)  	/* Setup the skbuff rings */  	for (i = 0; i < priv->num_tx_queues; i++) {  		tx_queue = priv->tx_queue[i]; -		tx_queue->tx_skbuff = kmalloc(sizeof(*tx_queue->tx_skbuff) * -					      tx_queue->tx_ring_size, -					      GFP_KERNEL); -		if (!tx_queue->tx_skbuff) { -			netif_err(priv, ifup, ndev, -				  "Could not allocate tx_skbuff\n"); +		tx_queue->tx_skbuff = +			kmalloc_array(tx_queue->tx_ring_size, +				      sizeof(*tx_queue->tx_skbuff), +				      GFP_KERNEL); +		if (!tx_queue->tx_skbuff)  			goto cleanup; -		}  		for (k = 0; k < tx_queue->tx_ring_size; k++)  			tx_queue->tx_skbuff[k] = NULL; @@ -292,15 +290,12 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)  	for (i = 0; i < priv->num_rx_queues; i++) {  		rx_queue = priv->rx_queue[i]; -		rx_queue->rx_skbuff = kmalloc(sizeof(*rx_queue->rx_skbuff) * -					      rx_queue->rx_ring_size, -					      GFP_KERNEL); - -		if (!rx_queue->rx_skbuff) { -			netif_err(priv, ifup, ndev, -				  "Could not allocate rx_skbuff\n"); +		rx_queue->rx_skbuff = +			kmalloc_array(rx_queue->rx_ring_size, +				      sizeof(*rx_queue->rx_skbuff), +				      GFP_KERNEL); +		if (!rx_queue->rx_skbuff)  			goto cleanup; -		}  		for (j = 0; j < rx_queue->rx_ring_size; j++)  			rx_queue->rx_skbuff[j] = NULL; @@ -349,14 +344,23 @@ static void gfar_init_mac(struct net_device *ndev)  	/* Configure the coalescing support */  	gfar_configure_coalescing(priv, 0xFF, 0xFF); +	/* set this when rx hw offload (TOE) functions are being used */ +	priv->uses_rxfcb = 0; +  	if (priv->rx_filer_enable) {  		rctrl |= RCTRL_FILREN;  		/* Program the RIR0 reg with the required distribution */  		gfar_write(®s->rir0, DEFAULT_RIR0);  	} -	if (ndev->features & NETIF_F_RXCSUM) +	/* Restore PROMISC mode */ +	if (ndev->flags & IFF_PROMISC) +		rctrl |= RCTRL_PROM; + +	if (ndev->features & NETIF_F_RXCSUM) {  		rctrl |= RCTRL_CHECKSUMMING; +		priv->uses_rxfcb = 1; +	}  	if (priv->extended_hash) {  		rctrl |= RCTRL_EXTHASH; @@ -378,11 +382,15 @@ static void gfar_init_mac(struct net_device *ndev)  	}  	/* Enable HW time stamping if requested from user space */ -	if (priv->hwts_rx_en) +	if (priv->hwts_rx_en) {  		rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE; +		priv->uses_rxfcb = 1; +	} -	if (ndev->features & NETIF_F_HW_VLAN_RX) +	if (ndev->features & NETIF_F_HW_VLAN_RX) {  		rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; +		priv->uses_rxfcb = 1; +	}  	/* Init rctrl based on our settings */  	gfar_write(®s->rctrl, rctrl); @@ -501,20 +509,6 @@ void unlock_tx_qs(struct gfar_private *priv)  		spin_unlock(&priv->tx_queue[i]->txlock);  } -static bool gfar_is_vlan_on(struct gfar_private *priv) -{ -	return (priv->ndev->features & NETIF_F_HW_VLAN_RX) || -	       (priv->ndev->features & NETIF_F_HW_VLAN_TX); -} - -/* Returns 1 if incoming frames use an FCB */ -static inline int gfar_uses_fcb(struct gfar_private *priv) -{ -	return gfar_is_vlan_on(priv) || -	       (priv->ndev->features & NETIF_F_RXCSUM) || -	       (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER); -} -  static void free_tx_pointers(struct gfar_private *priv)  {  	int i; @@ -540,6 +534,19 @@ static void unmap_group_regs(struct gfar_private *priv)  			iounmap(priv->gfargrp[i].regs);  } +static void free_gfar_dev(struct gfar_private *priv) +{ +	int i, j; + +	for (i = 0; i < priv->num_grps; i++) +		for (j = 0; j < GFAR_NUM_IRQS; j++) { +			kfree(priv->gfargrp[i].irqinfo[j]); +			priv->gfargrp[i].irqinfo[j] = NULL; +		} + +	free_netdev(priv->ndev); +} +  static void disable_napi(struct gfar_private *priv)  {  	int i; @@ -559,40 +566,46 @@ static void enable_napi(struct gfar_private *priv)  static int gfar_parse_group(struct device_node *np,  			    struct gfar_private *priv, const char *model)  { +	struct gfar_priv_grp *grp = &priv->gfargrp[priv->num_grps];  	u32 *queue_mask; +	int i; -	priv->gfargrp[priv->num_grps].regs = of_iomap(np, 0); -	if (!priv->gfargrp[priv->num_grps].regs) +	for (i = 0; i < GFAR_NUM_IRQS; i++) { +		grp->irqinfo[i] = kzalloc(sizeof(struct gfar_irqinfo), +					  GFP_KERNEL); +		if (!grp->irqinfo[i]) +			return -ENOMEM; +	} + +	grp->regs = of_iomap(np, 0); +	if (!grp->regs)  		return -ENOMEM; -	priv->gfargrp[priv->num_grps].interruptTransmit = -			irq_of_parse_and_map(np, 0); +	gfar_irq(grp, TX)->irq = irq_of_parse_and_map(np, 0);  	/* If we aren't the FEC we have multiple interrupts */  	if (model && strcasecmp(model, "FEC")) { -		priv->gfargrp[priv->num_grps].interruptReceive = -			irq_of_parse_and_map(np, 1); -		priv->gfargrp[priv->num_grps].interruptError = -			irq_of_parse_and_map(np,2); -		if (priv->gfargrp[priv->num_grps].interruptTransmit == NO_IRQ || -		    priv->gfargrp[priv->num_grps].interruptReceive  == NO_IRQ || -		    priv->gfargrp[priv->num_grps].interruptError    == NO_IRQ) +		gfar_irq(grp, RX)->irq = irq_of_parse_and_map(np, 1); +		gfar_irq(grp, ER)->irq = irq_of_parse_and_map(np, 2); +		if (gfar_irq(grp, TX)->irq == NO_IRQ || +		    gfar_irq(grp, RX)->irq == NO_IRQ || +		    gfar_irq(grp, ER)->irq == NO_IRQ)  			return -EINVAL;  	} -	priv->gfargrp[priv->num_grps].grp_id = priv->num_grps; -	priv->gfargrp[priv->num_grps].priv = priv; -	spin_lock_init(&priv->gfargrp[priv->num_grps].grplock); +	grp->grp_id = priv->num_grps; +	grp->priv = priv; +	spin_lock_init(&grp->grplock);  	if (priv->mode == MQ_MG_MODE) {  		queue_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL); -		priv->gfargrp[priv->num_grps].rx_bit_map = queue_mask ? +		grp->rx_bit_map = queue_mask ?  			*queue_mask : (DEFAULT_MAPPING >> priv->num_grps);  		queue_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL); -		priv->gfargrp[priv->num_grps].tx_bit_map = queue_mask ? +		grp->tx_bit_map = queue_mask ?  			*queue_mask : (DEFAULT_MAPPING >> priv->num_grps);  	} else { -		priv->gfargrp[priv->num_grps].rx_bit_map = 0xFF; -		priv->gfargrp[priv->num_grps].tx_bit_map = 0xFF; +		grp->rx_bit_map = 0xFF; +		grp->tx_bit_map = 0xFF;  	}  	priv->num_grps++; @@ -645,7 +658,6 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)  		return -ENOMEM;  	priv = netdev_priv(dev); -	priv->node = ofdev->dev.of_node;  	priv->ndev = dev;  	priv->num_tx_queues = num_tx_qs; @@ -777,7 +789,7 @@ tx_alloc_failed:  	free_tx_pointers(priv);  err_grp_init:  	unmap_group_regs(priv); -	free_netdev(dev); +	free_gfar_dev(priv);  	return err;  } @@ -983,7 +995,7 @@ static int gfar_probe(struct platform_device *ofdev)  	priv = netdev_priv(dev);  	priv->ndev = dev;  	priv->ofdev = ofdev; -	priv->node = ofdev->dev.of_node; +	priv->dev = &ofdev->dev;  	SET_NETDEV_DEV(dev, &ofdev->dev);  	spin_lock_init(&priv->bflock); @@ -1020,8 +1032,6 @@ static int gfar_probe(struct platform_device *ofdev)  	/* Set the dev->base_addr to the gfar reg region */  	dev->base_addr = (unsigned long) regs; -	SET_NETDEV_DEV(dev, &ofdev->dev); -  	/* Fill in the dev structure */  	dev->watchdog_timeo = TX_TIMEOUT;  	dev->mtu = 1500; @@ -1182,15 +1192,16 @@ static int gfar_probe(struct platform_device *ofdev)  	/* fill out IRQ number and name fields */  	for (i = 0; i < priv->num_grps; i++) { +		struct gfar_priv_grp *grp = &priv->gfargrp[i];  		if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { -			sprintf(priv->gfargrp[i].int_name_tx, "%s%s%c%s", +			sprintf(gfar_irq(grp, TX)->name, "%s%s%c%s",  				dev->name, "_g", '0' + i, "_tx"); -			sprintf(priv->gfargrp[i].int_name_rx, "%s%s%c%s", +			sprintf(gfar_irq(grp, RX)->name, "%s%s%c%s",  				dev->name, "_g", '0' + i, "_rx"); -			sprintf(priv->gfargrp[i].int_name_er, "%s%s%c%s", +			sprintf(gfar_irq(grp, ER)->name, "%s%s%c%s",  				dev->name, "_g", '0' + i, "_er");  		} else -			strcpy(priv->gfargrp[i].int_name_tx, dev->name); +			strcpy(gfar_irq(grp, TX)->name, dev->name);  	}  	/* Initialize the filer table */ @@ -1223,7 +1234,7 @@ register_fail:  		of_node_put(priv->phy_node);  	if (priv->tbi_node)  		of_node_put(priv->tbi_node); -	free_netdev(dev); +	free_gfar_dev(priv);  	return err;  } @@ -1240,7 +1251,7 @@ static int gfar_remove(struct platform_device *ofdev)  	unregister_netdev(priv->ndev);  	unmap_group_regs(priv); -	free_netdev(priv->ndev); +	free_gfar_dev(priv);  	return 0;  } @@ -1648,9 +1659,9 @@ void gfar_halt(struct net_device *dev)  static void free_grp_irqs(struct gfar_priv_grp *grp)  { -	free_irq(grp->interruptError, grp); -	free_irq(grp->interruptTransmit, grp); -	free_irq(grp->interruptReceive, grp); +	free_irq(gfar_irq(grp, TX)->irq, grp); +	free_irq(gfar_irq(grp, RX)->irq, grp); +	free_irq(gfar_irq(grp, ER)->irq, grp);  }  void stop_gfar(struct net_device *dev) @@ -1679,7 +1690,7 @@ void stop_gfar(struct net_device *dev)  			free_grp_irqs(&priv->gfargrp[i]);  	} else {  		for (i = 0; i < priv->num_grps; i++) -			free_irq(priv->gfargrp[i].interruptTransmit, +			free_irq(gfar_irq(&priv->gfargrp[i], TX)->irq,  				 &priv->gfargrp[i]);  	} @@ -1698,13 +1709,13 @@ static void free_skb_tx_queue(struct gfar_priv_tx_q *tx_queue)  		if (!tx_queue->tx_skbuff[i])  			continue; -		dma_unmap_single(&priv->ofdev->dev, txbdp->bufPtr, +		dma_unmap_single(priv->dev, txbdp->bufPtr,  				 txbdp->length, DMA_TO_DEVICE);  		txbdp->lstatus = 0;  		for (j = 0; j < skb_shinfo(tx_queue->tx_skbuff[i])->nr_frags;  		     j++) {  			txbdp++; -			dma_unmap_page(&priv->ofdev->dev, txbdp->bufPtr, +			dma_unmap_page(priv->dev, txbdp->bufPtr,  				       txbdp->length, DMA_TO_DEVICE);  		}  		txbdp++; @@ -1725,8 +1736,8 @@ static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue)  	for (i = 0; i < rx_queue->rx_ring_size; i++) {  		if (rx_queue->rx_skbuff[i]) { -			dma_unmap_single(&priv->ofdev->dev, -					 rxbdp->bufPtr, priv->rx_buffer_size, +			dma_unmap_single(priv->dev, rxbdp->bufPtr, +					 priv->rx_buffer_size,  					 DMA_FROM_DEVICE);  			dev_kfree_skb_any(rx_queue->rx_skbuff[i]);  			rx_queue->rx_skbuff[i] = NULL; @@ -1765,7 +1776,7 @@ static void free_skb_resources(struct gfar_private *priv)  			free_skb_rx_queue(rx_queue);  	} -	dma_free_coherent(&priv->ofdev->dev, +	dma_free_coherent(priv->dev,  			  sizeof(struct txbd8) * priv->total_tx_ring_size +  			  sizeof(struct rxbd8) * priv->total_rx_ring_size,  			  priv->tx_queue[0]->tx_bd_base, @@ -1854,32 +1865,34 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)  		/* Install our interrupt handlers for Error,  		 * Transmit, and Receive  		 */ -		if ((err = request_irq(grp->interruptError, gfar_error, -				       0, grp->int_name_er, grp)) < 0) { +		err = request_irq(gfar_irq(grp, ER)->irq, gfar_error, 0, +				  gfar_irq(grp, ER)->name, grp); +		if (err < 0) {  			netif_err(priv, intr, dev, "Can't get IRQ %d\n", -				  grp->interruptError); +				  gfar_irq(grp, ER)->irq);  			goto err_irq_fail;  		} - -		if ((err = request_irq(grp->interruptTransmit, gfar_transmit, -				       0, grp->int_name_tx, grp)) < 0) { +		err = request_irq(gfar_irq(grp, TX)->irq, gfar_transmit, 0, +				  gfar_irq(grp, TX)->name, grp); +		if (err < 0) {  			netif_err(priv, intr, dev, "Can't get IRQ %d\n", -				  grp->interruptTransmit); +				  gfar_irq(grp, TX)->irq);  			goto tx_irq_fail;  		} - -		if ((err = request_irq(grp->interruptReceive, gfar_receive, -				       0, grp->int_name_rx, grp)) < 0) { +		err = request_irq(gfar_irq(grp, RX)->irq, gfar_receive, 0, +				  gfar_irq(grp, RX)->name, grp); +		if (err < 0) {  			netif_err(priv, intr, dev, "Can't get IRQ %d\n", -				  grp->interruptReceive); +				  gfar_irq(grp, RX)->irq);  			goto rx_irq_fail;  		}  	} else { -		if ((err = request_irq(grp->interruptTransmit, gfar_interrupt, -				       0, grp->int_name_tx, grp)) < 0) { +		err = request_irq(gfar_irq(grp, TX)->irq, gfar_interrupt, 0, +				  gfar_irq(grp, TX)->name, grp); +		if (err < 0) {  			netif_err(priv, intr, dev, "Can't get IRQ %d\n", -				  grp->interruptTransmit); +				  gfar_irq(grp, TX)->irq);  			goto err_irq_fail;  		}  	} @@ -1887,9 +1900,9 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)  	return 0;  rx_irq_fail: -	free_irq(grp->interruptTransmit, grp); +	free_irq(gfar_irq(grp, TX)->irq, grp);  tx_irq_fail: -	free_irq(grp->interruptError, grp); +	free_irq(gfar_irq(grp, ER)->irq, grp);  err_irq_fail:  	return err; @@ -2143,7 +2156,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)  			if (i == nr_frags - 1)  				lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); -			bufaddr = skb_frag_dma_map(&priv->ofdev->dev, +			bufaddr = skb_frag_dma_map(priv->dev,  						   &skb_shinfo(skb)->frags[i],  						   0,  						   length, @@ -2195,7 +2208,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)  		lstatus |= BD_LFLAG(TXBD_TOE);  	} -	txbdp_start->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data, +	txbdp_start->bufPtr = dma_map_single(priv->dev, skb->data,  					     skb_headlen(skb), DMA_TO_DEVICE);  	/* If time stamping is requested one additional TxBD must be set up. The @@ -2308,10 +2321,13 @@ void gfar_check_rx_parser_mode(struct gfar_private *priv)  	tempval = gfar_read(®s->rctrl);  	/* If parse is no longer required, then disable parser */ -	if (tempval & RCTRL_REQ_PARSER) +	if (tempval & RCTRL_REQ_PARSER) {  		tempval |= RCTRL_PRSDEP_INIT; -	else +		priv->uses_rxfcb = 1; +	} else {  		tempval &= ~RCTRL_PRSDEP_INIT; +		priv->uses_rxfcb = 0; +	}  	gfar_write(®s->rctrl, tempval);  } @@ -2344,6 +2360,7 @@ void gfar_vlan_mode(struct net_device *dev, netdev_features_t features)  		tempval = gfar_read(®s->rctrl);  		tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT);  		gfar_write(®s->rctrl, tempval); +		priv->uses_rxfcb = 1;  	} else {  		/* Disable VLAN tag extraction */  		tempval = gfar_read(®s->rctrl); @@ -2367,15 +2384,12 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)  	int oldsize = priv->rx_buffer_size;  	int frame_size = new_mtu + ETH_HLEN; -	if (gfar_is_vlan_on(priv)) -		frame_size += VLAN_HLEN; -  	if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {  		netif_err(priv, drv, dev, "Invalid MTU setting\n");  		return -EINVAL;  	} -	if (gfar_uses_fcb(priv)) +	if (priv->uses_rxfcb)  		frame_size += GMAC_FCB_LEN;  	frame_size += priv->padding; @@ -2508,7 +2522,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)  		} else  			buflen = bdp->length; -		dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr, +		dma_unmap_single(priv->dev, bdp->bufPtr,  				 buflen, DMA_TO_DEVICE);  		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) { @@ -2527,7 +2541,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)  		bdp = next_txbd(bdp, base, tx_ring_size);  		for (i = 0; i < frags; i++) { -			dma_unmap_page(&priv->ofdev->dev, bdp->bufPtr, +			dma_unmap_page(priv->dev, bdp->bufPtr,  				       bdp->length, DMA_TO_DEVICE);  			bdp->lstatus &= BD_LFLAG(TXBD_WRAP);  			bdp = next_txbd(bdp, base, tx_ring_size); @@ -2593,7 +2607,7 @@ static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,  	struct gfar_private *priv = netdev_priv(dev);  	dma_addr_t buf; -	buf = dma_map_single(&priv->ofdev->dev, skb->data, +	buf = dma_map_single(priv->dev, skb->data,  			     priv->rx_buffer_size, DMA_FROM_DEVICE);  	gfar_init_rxbdp(rx_queue, bdp, buf);  } @@ -2627,7 +2641,7 @@ static inline void count_errors(unsigned short status, struct net_device *dev)  	if (status & RXBD_TRUNCATED) {  		stats->rx_length_errors++; -		estats->rx_trunc++; +		atomic64_inc(&estats->rx_trunc);  		return;  	} @@ -2636,20 +2650,20 @@ static inline void count_errors(unsigned short status, struct net_device *dev)  		stats->rx_length_errors++;  		if (status & RXBD_LARGE) -			estats->rx_large++; +			atomic64_inc(&estats->rx_large);  		else -			estats->rx_short++; +			atomic64_inc(&estats->rx_short);  	}  	if (status & RXBD_NONOCTET) {  		stats->rx_frame_errors++; -		estats->rx_nonoctet++; +		atomic64_inc(&estats->rx_nonoctet);  	}  	if (status & RXBD_CRCERR) { -		estats->rx_crcerr++; +		atomic64_inc(&estats->rx_crcerr);  		stats->rx_crc_errors++;  	}  	if (status & RXBD_OVERRUN) { -		estats->rx_overrun++; +		atomic64_inc(&estats->rx_overrun);  		stats->rx_crc_errors++;  	}  } @@ -2674,8 +2688,8 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)  /* gfar_process_frame() -- handle one incoming packet if skb isn't NULL. */ -static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, -			      int amount_pull, struct napi_struct *napi) +static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, +			       int amount_pull, struct napi_struct *napi)  {  	struct gfar_private *priv = netdev_priv(dev);  	struct rxfcb *fcb = NULL; @@ -2722,10 +2736,8 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,  	/* Send the packet up the stack */  	ret = napi_gro_receive(napi, skb); -	if (GRO_DROP == ret) -		priv->extra_stats.kernel_dropped++; - -	return 0; +	if (unlikely(GRO_DROP == ret)) +		atomic64_inc(&priv->extra_stats.kernel_dropped);  }  /* gfar_clean_rx_ring() -- Processes each frame in the rx ring @@ -2746,7 +2758,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)  	bdp = rx_queue->cur_rx;  	base = rx_queue->rx_bd_base; -	amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0); +	amount_pull = priv->uses_rxfcb ? GMAC_FCB_LEN : 0;  	while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {  		struct sk_buff *newskb; @@ -2758,7 +2770,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)  		skb = rx_queue->rx_skbuff[rx_queue->skb_currx]; -		dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr, +		dma_unmap_single(priv->dev, bdp->bufPtr,  				 priv->rx_buffer_size, DMA_FROM_DEVICE);  		if (unlikely(!(bdp->status & RXBD_ERR) && @@ -2791,7 +2803,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)  			} else {  				netif_warn(priv, rx_err, dev, "Missing skb!\n");  				rx_queue->stats.rx_dropped++; -				priv->extra_stats.rx_skbmissing++; +				atomic64_inc(&priv->extra_stats.rx_skbmissing);  			}  		} @@ -2894,21 +2906,23 @@ static void gfar_netpoll(struct net_device *dev)  	/* If the device has multiple interrupts, run tx/rx */  	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {  		for (i = 0; i < priv->num_grps; i++) { -			disable_irq(priv->gfargrp[i].interruptTransmit); -			disable_irq(priv->gfargrp[i].interruptReceive); -			disable_irq(priv->gfargrp[i].interruptError); -			gfar_interrupt(priv->gfargrp[i].interruptTransmit, -				       &priv->gfargrp[i]); -			enable_irq(priv->gfargrp[i].interruptError); -			enable_irq(priv->gfargrp[i].interruptReceive); -			enable_irq(priv->gfargrp[i].interruptTransmit); +			struct gfar_priv_grp *grp = &priv->gfargrp[i]; + +			disable_irq(gfar_irq(grp, TX)->irq); +			disable_irq(gfar_irq(grp, RX)->irq); +			disable_irq(gfar_irq(grp, ER)->irq); +			gfar_interrupt(gfar_irq(grp, TX)->irq, grp); +			enable_irq(gfar_irq(grp, ER)->irq); +			enable_irq(gfar_irq(grp, RX)->irq); +			enable_irq(gfar_irq(grp, TX)->irq);  		}  	} else {  		for (i = 0; i < priv->num_grps; i++) { -			disable_irq(priv->gfargrp[i].interruptTransmit); -			gfar_interrupt(priv->gfargrp[i].interruptTransmit, -				       &priv->gfargrp[i]); -			enable_irq(priv->gfargrp[i].interruptTransmit); +			struct gfar_priv_grp *grp = &priv->gfargrp[i]; + +			disable_irq(gfar_irq(grp, TX)->irq); +			gfar_interrupt(gfar_irq(grp, TX)->irq, grp); +			enable_irq(gfar_irq(grp, TX)->irq);  		}  	}  } @@ -3224,7 +3238,7 @@ static irqreturn_t gfar_error(int irq, void *grp_id)  			netif_dbg(priv, tx_err, dev,  				  "TX FIFO underrun, packet dropped\n");  			dev->stats.tx_dropped++; -			priv->extra_stats.tx_underrun++; +			atomic64_inc(&priv->extra_stats.tx_underrun);  			local_irq_save(flags);  			lock_tx_qs(priv); @@ -3239,7 +3253,7 @@ static irqreturn_t gfar_error(int irq, void *grp_id)  	}  	if (events & IEVENT_BSY) {  		dev->stats.rx_errors++; -		priv->extra_stats.rx_bsy++; +		atomic64_inc(&priv->extra_stats.rx_bsy);  		gfar_receive(irq, grp_id); @@ -3248,19 +3262,19 @@ static irqreturn_t gfar_error(int irq, void *grp_id)  	}  	if (events & IEVENT_BABR) {  		dev->stats.rx_errors++; -		priv->extra_stats.rx_babr++; +		atomic64_inc(&priv->extra_stats.rx_babr);  		netif_dbg(priv, rx_err, dev, "babbling RX error\n");  	}  	if (events & IEVENT_EBERR) { -		priv->extra_stats.eberr++; +		atomic64_inc(&priv->extra_stats.eberr);  		netif_dbg(priv, rx_err, dev, "bus error\n");  	}  	if (events & IEVENT_RXC)  		netif_dbg(priv, rx_status, dev, "control frame\n");  	if (events & IEVENT_BABT) { -		priv->extra_stats.tx_babt++; +		atomic64_inc(&priv->extra_stats.tx_babt);  		netif_dbg(priv, tx_err, dev, "babbling TX error\n");  	}  	return IRQ_HANDLED; diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index 22eabc13ca9..63a28d294e2 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -627,36 +627,29 @@ struct rmon_mib  };  struct gfar_extra_stats { -	u64 kernel_dropped; -	u64 rx_large; -	u64 rx_short; -	u64 rx_nonoctet; -	u64 rx_crcerr; -	u64 rx_overrun; -	u64 rx_bsy; -	u64 rx_babr; -	u64 rx_trunc; -	u64 eberr; -	u64 tx_babt; -	u64 tx_underrun; -	u64 rx_skbmissing; -	u64 tx_timeout; +	atomic64_t kernel_dropped; +	atomic64_t rx_large; +	atomic64_t rx_short; +	atomic64_t rx_nonoctet; +	atomic64_t rx_crcerr; +	atomic64_t rx_overrun; +	atomic64_t rx_bsy; +	atomic64_t rx_babr; +	atomic64_t rx_trunc; +	atomic64_t eberr; +	atomic64_t tx_babt; +	atomic64_t tx_underrun; +	atomic64_t rx_skbmissing; +	atomic64_t tx_timeout;  };  #define GFAR_RMON_LEN ((sizeof(struct rmon_mib) - 16)/sizeof(u32)) -#define GFAR_EXTRA_STATS_LEN (sizeof(struct gfar_extra_stats)/sizeof(u64)) +#define GFAR_EXTRA_STATS_LEN \ +	(sizeof(struct gfar_extra_stats)/sizeof(atomic64_t)) -/* Number of stats in the stats structure (ignore car and cam regs)*/ +/* Number of stats exported via ethtool */  #define GFAR_STATS_LEN (GFAR_RMON_LEN + GFAR_EXTRA_STATS_LEN) -#define GFAR_INFOSTR_LEN 32 - -struct gfar_stats { -	u64 extra[GFAR_EXTRA_STATS_LEN]; -	u64 rmon[GFAR_RMON_LEN]; -}; - -  struct gfar {  	u32	tsec_id;	/* 0x.000 - Controller ID register */  	u32	tsec_id2;	/* 0x.004 - Controller ID2 register */ @@ -937,26 +930,25 @@ struct tx_q_stats {   *	@txtime: coalescing value if based on time   */  struct gfar_priv_tx_q { +	/* cacheline 1 */  	spinlock_t txlock __attribute__ ((aligned (SMP_CACHE_BYTES))); -	struct sk_buff ** tx_skbuff; -	/* Buffer descriptor pointers */ -	dma_addr_t tx_bd_dma_base;  	struct	txbd8 *tx_bd_base;  	struct	txbd8 *cur_tx; -	struct	txbd8 *dirty_tx; +	unsigned int num_txbdfree; +	unsigned short skb_curtx; +	unsigned short tx_ring_size;  	struct tx_q_stats stats; -	struct	net_device *dev;  	struct gfar_priv_grp *grp; -	u16	skb_curtx; -	u16	skb_dirtytx; -	u16	qindex; -	unsigned int tx_ring_size; -	unsigned int num_txbdfree; +	/* cacheline 2 */ +	struct net_device *dev; +	struct sk_buff **tx_skbuff; +	struct	txbd8 *dirty_tx; +	unsigned short skb_dirtytx; +	unsigned short qindex;  	/* Configuration info for the coalescing features */ -	unsigned char txcoalescing; +	unsigned int txcoalescing;  	unsigned long txic; -	unsigned short txcount; -	unsigned short txtime; +	dma_addr_t tx_bd_dma_base;  };  /* @@ -999,18 +991,25 @@ struct gfar_priv_rx_q {  	unsigned long rxic;  }; +enum gfar_irqinfo_id { +	GFAR_TX = 0, +	GFAR_RX = 1, +	GFAR_ER = 2, +	GFAR_NUM_IRQS = 3 +}; + +struct gfar_irqinfo { +	unsigned int irq; +	char name[GFAR_INT_NAME_MAX]; +}; +  /**   *	struct gfar_priv_grp - per group structure   *	@napi: the napi poll function   *	@priv: back pointer to the priv structure   *	@regs: the ioremapped register space for this group   *	@grp_id: group id for this group - *	@interruptTransmit: The TX interrupt number for this group - *	@interruptReceive: The RX interrupt number for this group - *	@interruptError: The ERROR interrupt number for this group - *	@int_name_tx: tx interrupt name for this group - *	@int_name_rx: rx interrupt name for this group - *	@int_name_er: er interrupt name for this group + *	@irqinfo: TX/RX/ER irq data for this group   */  struct gfar_priv_grp { @@ -1019,23 +1018,20 @@ struct gfar_priv_grp {  	struct gfar_private *priv;  	struct gfar __iomem *regs;  	unsigned int grp_id; -	unsigned long rx_bit_map; -	unsigned long tx_bit_map; -	unsigned long num_tx_queues;  	unsigned long num_rx_queues; +	unsigned long rx_bit_map; +	/* cacheline 3 */  	unsigned int rstat;  	unsigned int tstat; -	unsigned int imask; -	unsigned int ievent; -	unsigned int interruptTransmit; -	unsigned int interruptReceive; -	unsigned int interruptError; +	unsigned long num_tx_queues; +	unsigned long tx_bit_map; -	char int_name_tx[GFAR_INT_NAME_MAX]; -	char int_name_rx[GFAR_INT_NAME_MAX]; -	char int_name_er[GFAR_INT_NAME_MAX]; +	struct gfar_irqinfo *irqinfo[GFAR_NUM_IRQS];  }; +#define gfar_irq(grp, ID) \ +	((grp)->irqinfo[GFAR_##ID]) +  enum gfar_errata {  	GFAR_ERRATA_74		= 0x01,  	GFAR_ERRATA_76		= 0x02, @@ -1053,28 +1049,65 @@ enum gfar_errata {   * the buffer descriptor determines the actual condition.   */  struct gfar_private { - -	/* Indicates how many tx, rx queues are enabled */ -	unsigned int num_tx_queues;  	unsigned int num_rx_queues; -	unsigned int num_grps; -	unsigned int mode; -	/* The total tx and rx ring size for the enabled queues */ -	unsigned int total_tx_ring_size; -	unsigned int total_rx_ring_size; - -	struct device_node *node; +	struct device *dev;  	struct net_device *ndev; -	struct platform_device *ofdev;  	enum gfar_errata errata; +	unsigned int rx_buffer_size; + +	u16 uses_rxfcb; +	u16 padding; + +	/* HW time stamping enabled flag */ +	int hwts_rx_en; +	int hwts_tx_en; -	struct gfar_priv_grp gfargrp[MAXGROUPS];  	struct gfar_priv_tx_q *tx_queue[MAX_TX_QS];  	struct gfar_priv_rx_q *rx_queue[MAX_RX_QS]; +	struct gfar_priv_grp gfargrp[MAXGROUPS]; + +	u32 device_flags; + +	unsigned int mode; +	unsigned int num_tx_queues; +	unsigned int num_grps; + +	/* Network Statistics */ +	struct gfar_extra_stats extra_stats; + +	/* PHY stuff */ +	phy_interface_t interface; +	struct device_node *phy_node; +	struct device_node *tbi_node; +	struct phy_device *phydev; +	struct mii_bus *mii_bus; +	int oldspeed; +	int oldduplex; +	int oldlink; + +	/* Bitfield update lock */ +	spinlock_t bflock; + +	uint32_t msg_enable; + +	struct work_struct reset_task; + +	struct platform_device *ofdev; +	unsigned char +		extended_hash:1, +		bd_stash_en:1, +		rx_filer_enable:1, +		/* Wake-on-LAN enabled */ +		wol_en:1, +		/* Enable priorty based Tx scheduling in Hw */ +		prio_sched_en:1; + +	/* The total tx and rx ring size for the enabled queues */ +	unsigned int total_tx_ring_size; +	unsigned int total_rx_ring_size;  	/* RX per device parameters */ -	unsigned int rx_buffer_size;  	unsigned int rx_stash_size;  	unsigned int rx_stash_index; @@ -1093,39 +1126,6 @@ struct gfar_private {  	unsigned int fifo_starve;  	unsigned int fifo_starve_off; -	/* Bitfield update lock */ -	spinlock_t bflock; - -	phy_interface_t interface; -	struct device_node *phy_node; -	struct device_node *tbi_node; -	u32 device_flags; -	unsigned char -		extended_hash:1, -		bd_stash_en:1, -		rx_filer_enable:1, -		wol_en:1, /* Wake-on-LAN enabled */ -		prio_sched_en:1; /* Enable priorty based Tx scheduling in Hw */ -	unsigned short padding; - -	/* PHY stuff */ -	struct phy_device *phydev; -	struct mii_bus *mii_bus; -	int oldspeed; -	int oldduplex; -	int oldlink; - -	uint32_t msg_enable; - -	struct work_struct reset_task; - -	/* Network Statistics */ -	struct gfar_extra_stats extra_stats; - -	/* HW time stamping enabled flag */ -	int hwts_rx_en; -	int hwts_tx_en; -  	/*Filer table*/  	unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];  	unsigned int ftp_rqfcr[MAX_FILER_IDX + 1]; @@ -1138,16 +1138,16 @@ static inline int gfar_has_errata(struct gfar_private *priv,  	return priv->errata & err;  } -static inline u32 gfar_read(volatile unsigned __iomem *addr) +static inline u32 gfar_read(unsigned __iomem *addr)  {  	u32 val; -	val = in_be32(addr); +	val = ioread32be(addr);  	return val;  } -static inline void gfar_write(volatile unsigned __iomem *addr, u32 val) +static inline void gfar_write(unsigned __iomem *addr, u32 val)  { -	out_be32(addr, val); +	iowrite32be(val, addr);  }  static inline void gfar_write_filer(struct gfar_private *priv, diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index ab6762caa95..75e89acf491 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -149,20 +149,17 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,  	int i;  	struct gfar_private *priv = netdev_priv(dev);  	struct gfar __iomem *regs = priv->gfargrp[0].regs; -	u64 *extra = (u64 *) & priv->extra_stats; +	atomic64_t *extra = (atomic64_t *)&priv->extra_stats; + +	for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) +		buf[i] = atomic64_read(&extra[i]);  	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {  		u32 __iomem *rmon = (u32 __iomem *) ®s->rmon; -		struct gfar_stats *stats = (struct gfar_stats *) buf; - -		for (i = 0; i < GFAR_RMON_LEN; i++) -			stats->rmon[i] = (u64) gfar_read(&rmon[i]); -		for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) -			stats->extra[i] = extra[i]; -	} else -		for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) -			buf[i] = extra[i]; +		for (; i < GFAR_STATS_LEN; i++, rmon++) +			buf[i] = (u64) gfar_read(rmon); +	}  }  static int gfar_sset_count(struct net_device *dev, int sset) @@ -184,10 +181,11 @@ static int gfar_sset_count(struct net_device *dev, int sset)  static void gfar_gdrvinfo(struct net_device *dev,  			  struct ethtool_drvinfo *drvinfo)  { -	strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN); -	strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN); -	strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN); -	strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN); +	strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); +	strlcpy(drvinfo->version, gfar_driver_version, +		sizeof(drvinfo->version)); +	strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); +	strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info));  	drvinfo->regdump_len = 0;  	drvinfo->eedump_len = 0;  } @@ -715,12 +713,11 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow,  	int j = MAX_FILER_IDX, l = 0x0;  	int ret = 1; -	local_rqfpr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1), -			      GFP_KERNEL); -	local_rqfcr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1), -			      GFP_KERNEL); +	local_rqfpr = kmalloc_array(MAX_FILER_IDX + 1, sizeof(unsigned int), +				    GFP_KERNEL); +	local_rqfcr = kmalloc_array(MAX_FILER_IDX + 1, sizeof(unsigned int), +				    GFP_KERNEL);  	if (!local_rqfpr || !local_rqfcr) { -		pr_err("Out of memory\n");  		ret = 0;  		goto err;  	} diff --git a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c index 37b03530601..1ebf7128ec0 100644 --- a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c +++ b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c @@ -350,10 +350,10 @@ static void  uec_get_drvinfo(struct net_device *netdev,                         struct ethtool_drvinfo *drvinfo)  { -	strncpy(drvinfo->driver, DRV_NAME, 32); -	strncpy(drvinfo->version, DRV_VERSION, 32); -	strncpy(drvinfo->fw_version, "N/A", 32); -	strncpy(drvinfo->bus_info, "QUICC ENGINE", 32); +	strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); +	strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version)); +	strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); +	strlcpy(drvinfo->bus_info, "QUICC ENGINE", sizeof(drvinfo->bus_info));  	drvinfo->eedump_len = 0;  	drvinfo->regdump_len = uec_get_regs_len(netdev);  }  |