diff options
Diffstat (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac_main.c')
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 1340 | 
1 files changed, 1013 insertions, 327 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 39c6c552463..618446ae1ec 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -46,7 +46,9 @@  #ifdef CONFIG_STMMAC_DEBUG_FS  #include <linux/debugfs.h>  #include <linux/seq_file.h> -#endif +#endif /* CONFIG_STMMAC_DEBUG_FS */ +#include <linux/net_tstamp.h> +#include "stmmac_ptp.h"  #include "stmmac.h"  #undef STMMAC_DEBUG @@ -79,14 +81,14 @@  #define JUMBO_LEN	9000  /* Module parameters */ -#define TX_TIMEO 5000 /* default 5 seconds */ +#define TX_TIMEO	5000  static int watchdog = TX_TIMEO;  module_param(watchdog, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(watchdog, "Transmit timeout in milliseconds"); +MODULE_PARM_DESC(watchdog, "Transmit timeout in milliseconds (default 5s)"); -static int debug = -1;		/* -1: default, 0: no output, 16:  all */ +static int debug = -1;  module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Message Level (0: no output, 16: all)"); +MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)");  int phyaddr = -1;  module_param(phyaddr, int, S_IRUGO); @@ -130,6 +132,13 @@ module_param(eee_timer, int, S_IRUGO | S_IWUSR);  MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec");  #define STMMAC_LPI_TIMER(x) (jiffies + msecs_to_jiffies(x)) +/* By default the driver will use the ring mode to manage tx and rx descriptors + * but passing this value so user can force to use the chain instead of the ring + */ +static unsigned int chain_mode; +module_param(chain_mode, int, S_IRUGO); +MODULE_PARM_DESC(chain_mode, "To use chain instead of ring mode"); +  static irqreturn_t stmmac_interrupt(int irq, void *dev_id);  #ifdef CONFIG_STMMAC_DEBUG_FS @@ -164,6 +173,18 @@ static void stmmac_verify_args(void)  		eee_timer = STMMAC_DEFAULT_LPI_TIMER;  } +/** + * stmmac_clk_csr_set - dynamically set the MDC clock + * @priv: driver private structure + * Description: this is to dynamically set the MDC clock according to the csr + * clock input. + * Note: + *	If a specific clk_csr value is passed from the platform + *	this means that the CSR Clock Range selection cannot be + *	changed at run-time and it is fixed (as reported in the driver + *	documentation). Viceversa the driver will try to set the MDC + *	clock dynamically according to the actual clock input. + */  static void stmmac_clk_csr_set(struct stmmac_priv *priv)  {  	u32 clk_rate; @@ -171,7 +192,12 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv)  	clk_rate = clk_get_rate(priv->stmmac_clk);  	/* Platform provided default clk_csr would be assumed valid -	 * for all other cases except for the below mentioned ones. */ +	 * for all other cases except for the below mentioned ones. +	 * For values higher than the IEEE 802.3 specified frequency +	 * we can not estimate the proper divider as it is not known +	 * the frequency of clk_csr_i. So we do not change the default +	 * divider. +	 */  	if (!(priv->clk_csr & MAC_CSR_H_FRQ_MASK)) {  		if (clk_rate < CSR_F_35M)  			priv->clk_csr = STMMAC_CSR_20_35M; @@ -185,10 +211,7 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv)  			priv->clk_csr = STMMAC_CSR_150_250M;  		else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M))  			priv->clk_csr = STMMAC_CSR_250_300M; -	} /* For values higher than the IEEE 802.3 specified frequency -	   * we can not estimate the proper divider as it is not known -	   * the frequency of clk_csr_i. So we do not change the default -	   * divider. */ +	}  }  #if defined(STMMAC_XMIT_DEBUG) || defined(STMMAC_RX_DEBUG) @@ -213,18 +236,25 @@ static inline u32 stmmac_tx_avail(struct stmmac_priv *priv)  	return priv->dirty_tx + priv->dma_tx_size - priv->cur_tx - 1;  } -/* On some ST platforms, some HW system configuraton registers have to be - * set according to the link speed negotiated. +/** + * stmmac_hw_fix_mac_speed: callback for speed selection + * @priv: driver private structure + * Description: on some platforms (e.g. ST), some HW system configuraton + * registers have to be set according to the link speed negotiated.   */  static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv)  {  	struct phy_device *phydev = priv->phydev;  	if (likely(priv->plat->fix_mac_speed)) -		priv->plat->fix_mac_speed(priv->plat->bsp_priv, -					  phydev->speed); +		priv->plat->fix_mac_speed(priv->plat->bsp_priv, phydev->speed);  } +/** + * stmmac_enable_eee_mode: Check and enter in LPI mode + * @priv: driver private structure + * Description: this function is to verify and enter in LPI mode for EEE. + */  static void stmmac_enable_eee_mode(struct stmmac_priv *priv)  {  	/* Check and enter in LPI mode */ @@ -233,19 +263,24 @@ static void stmmac_enable_eee_mode(struct stmmac_priv *priv)  		priv->hw->mac->set_eee_mode(priv->ioaddr);  } +/** + * stmmac_disable_eee_mode: disable/exit from EEE + * @priv: driver private structure + * Description: this function is to exit and disable EEE in case of + * LPI state is true. This is called by the xmit. + */  void stmmac_disable_eee_mode(struct stmmac_priv *priv)  { -	/* Exit and disable EEE in case of we are are in LPI state. */  	priv->hw->mac->reset_eee_mode(priv->ioaddr);  	del_timer_sync(&priv->eee_ctrl_timer);  	priv->tx_path_in_lpi_mode = false;  }  /** - * stmmac_eee_ctrl_timer + * stmmac_eee_ctrl_timer: EEE TX SW timer.   * @arg : data hook   * Description: - *  If there is no data transfer and if we are not in LPI state, + *  if there is no data transfer and if we are not in LPI state,   *  then MAC Transmitter can be moved to LPI state.   */  static void stmmac_eee_ctrl_timer(unsigned long arg) @@ -257,8 +292,8 @@ static void stmmac_eee_ctrl_timer(unsigned long arg)  }  /** - * stmmac_eee_init - * @priv: private device pointer + * stmmac_eee_init: init EEE + * @priv: driver private structure   * Description:   *  If the EEE support has been enabled while configuring the driver,   *  if the GMAC actually supports the EEE (from the HW cap reg) and the @@ -294,16 +329,359 @@ out:  	return ret;  } +/** + * stmmac_eee_adjust: adjust HW EEE according to the speed + * @priv: driver private structure + * Description: + *	When the EEE has been already initialised we have to + *	modify the PLS bit in the LPI ctrl & status reg according + *	to the PHY link status. For this reason. + */  static void stmmac_eee_adjust(struct stmmac_priv *priv)  { -	/* When the EEE has been already initialised we have to -	 * modify the PLS bit in the LPI ctrl & status reg according -	 * to the PHY link status. For this reason. -	 */  	if (priv->eee_enabled)  		priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link);  } +/* stmmac_get_tx_hwtstamp: get HW TX timestamps + * @priv: driver private structure + * @entry : descriptor index to be used. + * @skb : the socket buffer + * Description : + * This function will read timestamp from the descriptor & pass it to stack. + * and also perform some sanity checks. + */ +static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv, +				   unsigned int entry, struct sk_buff *skb) +{ +	struct skb_shared_hwtstamps shhwtstamp; +	u64 ns; +	void *desc = NULL; + +	if (!priv->hwts_tx_en) +		return; + +	/* exit if skb doesn't support hw tstamp */ +	if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))) +		return; + +	if (priv->adv_ts) +		desc = (priv->dma_etx + entry); +	else +		desc = (priv->dma_tx + entry); + +	/* check tx tstamp status */ +	if (!priv->hw->desc->get_tx_timestamp_status((struct dma_desc *)desc)) +		return; + +	/* get the valid tstamp */ +	ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts); + +	memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps)); +	shhwtstamp.hwtstamp = ns_to_ktime(ns); +	/* pass tstamp to stack */ +	skb_tstamp_tx(skb, &shhwtstamp); + +	return; +} + +/* stmmac_get_rx_hwtstamp: get HW RX timestamps + * @priv: driver private structure + * @entry : descriptor index to be used. + * @skb : the socket buffer + * Description : + * This function will read received packet's timestamp from the descriptor + * and pass it to stack. It also perform some sanity checks. + */ +static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, +				   unsigned int entry, struct sk_buff *skb) +{ +	struct skb_shared_hwtstamps *shhwtstamp = NULL; +	u64 ns; +	void *desc = NULL; + +	if (!priv->hwts_rx_en) +		return; + +	if (priv->adv_ts) +		desc = (priv->dma_erx + entry); +	else +		desc = (priv->dma_rx + entry); + +	/* exit if rx tstamp is not valid */ +	if (!priv->hw->desc->get_rx_timestamp_status(desc, priv->adv_ts)) +		return; + +	/* get valid tstamp */ +	ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts); +	shhwtstamp = skb_hwtstamps(skb); +	memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps)); +	shhwtstamp->hwtstamp = ns_to_ktime(ns); +} + +/** + *  stmmac_hwtstamp_ioctl - control hardware timestamping. + *  @dev: device pointer. + *  @ifr: An IOCTL specefic structure, that can contain a pointer to + *  a proprietary structure used to pass information to the driver. + *  Description: + *  This function configures the MAC to enable/disable both outgoing(TX) + *  and incoming(RX) packets time stamping based on user input. + *  Return Value: + *  0 on success and an appropriate -ve integer on failure. + */ +static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) +{ +	struct stmmac_priv *priv = netdev_priv(dev); +	struct hwtstamp_config config; +	struct timespec now; +	u64 temp = 0; +	u32 ptp_v2 = 0; +	u32 tstamp_all = 0; +	u32 ptp_over_ipv4_udp = 0; +	u32 ptp_over_ipv6_udp = 0; +	u32 ptp_over_ethernet = 0; +	u32 snap_type_sel = 0; +	u32 ts_master_en = 0; +	u32 ts_event_en = 0; +	u32 value = 0; + +	if (!(priv->dma_cap.time_stamp || priv->adv_ts)) { +		netdev_alert(priv->dev, "No support for HW time stamping\n"); +		priv->hwts_tx_en = 0; +		priv->hwts_rx_en = 0; + +		return -EOPNOTSUPP; +	} + +	if (copy_from_user(&config, ifr->ifr_data, +			   sizeof(struct hwtstamp_config))) +		return -EFAULT; + +	pr_debug("%s config flags:0x%x, tx_type:0x%x, rx_filter:0x%x\n", +		 __func__, config.flags, config.tx_type, config.rx_filter); + +	/* reserved for future extensions */ +	if (config.flags) +		return -EINVAL; + +	switch (config.tx_type) { +	case HWTSTAMP_TX_OFF: +		priv->hwts_tx_en = 0; +		break; +	case HWTSTAMP_TX_ON: +		priv->hwts_tx_en = 1; +		break; +	default: +		return -ERANGE; +	} + +	if (priv->adv_ts) { +		switch (config.rx_filter) { +		case HWTSTAMP_FILTER_NONE: +			/* time stamp no incoming packet at all */ +			config.rx_filter = HWTSTAMP_FILTER_NONE; +			break; + +		case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: +			/* PTP v1, UDP, any kind of event packet */ +			config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; +			/* take time stamp for all event messages */ +			snap_type_sel = PTP_TCR_SNAPTYPSEL_1; + +			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; +			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; +			break; + +		case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: +			/* PTP v1, UDP, Sync packet */ +			config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC; +			/* take time stamp for SYNC messages only */ +			ts_event_en = PTP_TCR_TSEVNTENA; + +			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; +			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; +			break; + +		case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: +			/* PTP v1, UDP, Delay_req packet */ +			config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ; +			/* take time stamp for Delay_Req messages only */ +			ts_master_en = PTP_TCR_TSMSTRENA; +			ts_event_en = PTP_TCR_TSEVNTENA; + +			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; +			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; +			break; + +		case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: +			/* PTP v2, UDP, any kind of event packet */ +			config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; +			ptp_v2 = PTP_TCR_TSVER2ENA; +			/* take time stamp for all event messages */ +			snap_type_sel = PTP_TCR_SNAPTYPSEL_1; + +			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; +			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; +			break; + +		case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: +			/* PTP v2, UDP, Sync packet */ +			config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC; +			ptp_v2 = PTP_TCR_TSVER2ENA; +			/* take time stamp for SYNC messages only */ +			ts_event_en = PTP_TCR_TSEVNTENA; + +			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; +			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; +			break; + +		case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: +			/* PTP v2, UDP, Delay_req packet */ +			config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ; +			ptp_v2 = PTP_TCR_TSVER2ENA; +			/* take time stamp for Delay_Req messages only */ +			ts_master_en = PTP_TCR_TSMSTRENA; +			ts_event_en = PTP_TCR_TSEVNTENA; + +			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; +			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; +			break; + +		case HWTSTAMP_FILTER_PTP_V2_EVENT: +			/* PTP v2/802.AS1 any layer, any kind of event packet */ +			config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; +			ptp_v2 = PTP_TCR_TSVER2ENA; +			/* take time stamp for all event messages */ +			snap_type_sel = PTP_TCR_SNAPTYPSEL_1; + +			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; +			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; +			ptp_over_ethernet = PTP_TCR_TSIPENA; +			break; + +		case HWTSTAMP_FILTER_PTP_V2_SYNC: +			/* PTP v2/802.AS1, any layer, Sync packet */ +			config.rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC; +			ptp_v2 = PTP_TCR_TSVER2ENA; +			/* take time stamp for SYNC messages only */ +			ts_event_en = PTP_TCR_TSEVNTENA; + +			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; +			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; +			ptp_over_ethernet = PTP_TCR_TSIPENA; +			break; + +		case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: +			/* PTP v2/802.AS1, any layer, Delay_req packet */ +			config.rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ; +			ptp_v2 = PTP_TCR_TSVER2ENA; +			/* take time stamp for Delay_Req messages only */ +			ts_master_en = PTP_TCR_TSMSTRENA; +			ts_event_en = PTP_TCR_TSEVNTENA; + +			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; +			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; +			ptp_over_ethernet = PTP_TCR_TSIPENA; +			break; + +		case HWTSTAMP_FILTER_ALL: +			/* time stamp any incoming packet */ +			config.rx_filter = HWTSTAMP_FILTER_ALL; +			tstamp_all = PTP_TCR_TSENALL; +			break; + +		default: +			return -ERANGE; +		} +	} else { +		switch (config.rx_filter) { +		case HWTSTAMP_FILTER_NONE: +			config.rx_filter = HWTSTAMP_FILTER_NONE; +			break; +		default: +			/* PTP v1, UDP, any kind of event packet */ +			config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; +			break; +		} +	} +	priv->hwts_rx_en = ((config.rx_filter == HWTSTAMP_FILTER_NONE) ? 0 : 1); + +	if (!priv->hwts_tx_en && !priv->hwts_rx_en) +		priv->hw->ptp->config_hw_tstamping(priv->ioaddr, 0); +	else { +		value = (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | PTP_TCR_TSCTRLSSR | +			 tstamp_all | ptp_v2 | ptp_over_ethernet | +			 ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en | +			 ts_master_en | snap_type_sel); + +		priv->hw->ptp->config_hw_tstamping(priv->ioaddr, value); + +		/* program Sub Second Increment reg */ +		priv->hw->ptp->config_sub_second_increment(priv->ioaddr); + +		/* calculate default added value: +		 * formula is : +		 * addend = (2^32)/freq_div_ratio; +		 * where, freq_div_ratio = STMMAC_SYSCLOCK/50MHz +		 * hence, addend = ((2^32) * 50MHz)/STMMAC_SYSCLOCK; +		 * NOTE: STMMAC_SYSCLOCK should be >= 50MHz to +		 *       achive 20ns accuracy. +		 * +		 * 2^x * y == (y << x), hence +		 * 2^32 * 50000000 ==> (50000000 << 32) +		 */ +		temp = (u64) (50000000ULL << 32); +		priv->default_addend = div_u64(temp, STMMAC_SYSCLOCK); +		priv->hw->ptp->config_addend(priv->ioaddr, +					     priv->default_addend); + +		/* initialize system time */ +		getnstimeofday(&now); +		priv->hw->ptp->init_systime(priv->ioaddr, now.tv_sec, +					    now.tv_nsec); +	} + +	return copy_to_user(ifr->ifr_data, &config, +			    sizeof(struct hwtstamp_config)) ? -EFAULT : 0; +} + +/** + * stmmac_init_ptp: init PTP + * @priv: driver private structure + * Description: this is to verify if the HW supports the PTPv1 or v2. + * This is done by looking at the HW cap. register. + * Also it registers the ptp driver. + */ +static int stmmac_init_ptp(struct stmmac_priv *priv) +{ +	if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) +		return -EOPNOTSUPP; + +	if (netif_msg_hw(priv)) { +		if (priv->dma_cap.time_stamp) { +			pr_debug("IEEE 1588-2002 Time Stamp supported\n"); +			priv->adv_ts = 0; +		} +		if (priv->dma_cap.atime_stamp && priv->extend_desc) { +			pr_debug +			    ("IEEE 1588-2008 Advanced Time Stamp supported\n"); +			priv->adv_ts = 1; +		} +	} + +	priv->hw->ptp = &stmmac_ptp; +	priv->hwts_tx_en = 0; +	priv->hwts_rx_en = 0; + +	return stmmac_ptp_register(priv); +} + +static void stmmac_release_ptp(struct stmmac_priv *priv) +{ +	stmmac_ptp_unregister(priv); +} +  /**   * stmmac_adjust_link   * @dev: net device structure @@ -349,7 +727,7 @@ static void stmmac_adjust_link(struct net_device *dev)  			case 1000:  				if (likely(priv->plat->has_gmac))  					ctrl &= ~priv->hw->link.port; -					stmmac_hw_fix_mac_speed(priv); +				stmmac_hw_fix_mac_speed(priv);  				break;  			case 100:  			case 10: @@ -367,8 +745,8 @@ static void stmmac_adjust_link(struct net_device *dev)  				break;  			default:  				if (netif_msg_link(priv)) -					pr_warning("%s: Speed (%d) is not 10" -				       " or 100!\n", dev->name, phydev->speed); +					pr_warn("%s: Speed (%d) not 10/100\n", +						dev->name, phydev->speed);  				break;  			} @@ -399,6 +777,31 @@ static void stmmac_adjust_link(struct net_device *dev)  }  /** + * stmmac_check_pcs_mode: verify if RGMII/SGMII is supported + * @priv: driver private structure + * Description: this is to verify if the HW supports the PCS. + * Physical Coding Sublayer (PCS) interface that can be used when the MAC is + * configured for the TBI, RTBI, or SGMII PHY interface. + */ +static void stmmac_check_pcs_mode(struct stmmac_priv *priv) +{ +	int interface = priv->plat->interface; + +	if (priv->dma_cap.pcs) { +		if ((interface & PHY_INTERFACE_MODE_RGMII) || +		    (interface & PHY_INTERFACE_MODE_RGMII_ID) || +		    (interface & PHY_INTERFACE_MODE_RGMII_RXID) || +		    (interface & PHY_INTERFACE_MODE_RGMII_TXID)) { +			pr_debug("STMMAC: PCS RGMII support enable\n"); +			priv->pcs = STMMAC_PCS_RGMII; +		} else if (interface & PHY_INTERFACE_MODE_SGMII) { +			pr_debug("STMMAC: PCS SGMII support enable\n"); +			priv->pcs = STMMAC_PCS_SGMII; +		} +	} +} + +/**   * stmmac_init_phy - PHY initialization   * @dev: net device structure   * Description: it initializes the driver's PHY state, and attaches the PHY @@ -419,10 +822,10 @@ static int stmmac_init_phy(struct net_device *dev)  	if (priv->plat->phy_bus_name)  		snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x", -				priv->plat->phy_bus_name, priv->plat->bus_id); +			 priv->plat->phy_bus_name, priv->plat->bus_id);  	else  		snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", -				priv->plat->bus_id); +			 priv->plat->bus_id);  	snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,  		 priv->plat->phy_addr); @@ -461,29 +864,57 @@ static int stmmac_init_phy(struct net_device *dev)  }  /** - * display_ring - * @p: pointer to the ring. + * stmmac_display_ring: display ring + * @head: pointer to the head of the ring passed.   * @size: size of the ring. - * Description: display all the descriptors within the ring. + * @extend_desc: to verify if extended descriptors are used. + * Description: display the control/status and buffer descriptors.   */ -static void display_ring(struct dma_desc *p, int size) +static void stmmac_display_ring(void *head, int size, int extend_desc)  { -	struct tmp_s { -		u64 a; -		unsigned int b; -		unsigned int c; -	};  	int i; +	struct dma_extended_desc *ep = (struct dma_extended_desc *)head; +	struct dma_desc *p = (struct dma_desc *)head; +  	for (i = 0; i < size; i++) { -		struct tmp_s *x = (struct tmp_s *)(p + i); -		pr_info("\t%d [0x%x]: DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x", -		       i, (unsigned int)virt_to_phys(&p[i]), -		       (unsigned int)(x->a), (unsigned int)((x->a) >> 32), -		       x->b, x->c); +		u64 x; +		if (extend_desc) { +			x = *(u64 *) ep; +			pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n", +				i, (unsigned int)virt_to_phys(ep), +				(unsigned int)x, (unsigned int)(x >> 32), +				ep->basic.des2, ep->basic.des3); +			ep++; +		} else { +			x = *(u64 *) p; +			pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x", +				i, (unsigned int)virt_to_phys(p), +				(unsigned int)x, (unsigned int)(x >> 32), +				p->des2, p->des3); +			p++; +		}  		pr_info("\n");  	}  } +static void stmmac_display_rings(struct stmmac_priv *priv) +{ +	unsigned int txsize = priv->dma_tx_size; +	unsigned int rxsize = priv->dma_rx_size; + +	if (priv->extend_desc) { +		pr_info("Extended RX descriptor ring:\n"); +		stmmac_display_ring((void *)priv->dma_erx, rxsize, 1); +		pr_info("Extended TX descriptor ring:\n"); +		stmmac_display_ring((void *)priv->dma_etx, txsize, 1); +	} else { +		pr_info("RX descriptor ring:\n"); +		stmmac_display_ring((void *)priv->dma_rx, rxsize, 0); +		pr_info("TX descriptor ring:\n"); +		stmmac_display_ring((void *)priv->dma_tx, txsize, 0); +	} +} +  static int stmmac_set_bfsize(int mtu, int bufsize)  {  	int ret = bufsize; @@ -501,6 +932,65 @@ static int stmmac_set_bfsize(int mtu, int bufsize)  }  /** + * stmmac_clear_descriptors: clear descriptors + * @priv: driver private structure + * Description: this function is called to clear the tx and rx descriptors + * in case of both basic and extended descriptors are used. + */ +static void stmmac_clear_descriptors(struct stmmac_priv *priv) +{ +	int i; +	unsigned int txsize = priv->dma_tx_size; +	unsigned int rxsize = priv->dma_rx_size; + +	/* Clear the Rx/Tx descriptors */ +	for (i = 0; i < rxsize; i++) +		if (priv->extend_desc) +			priv->hw->desc->init_rx_desc(&priv->dma_erx[i].basic, +						     priv->use_riwt, priv->mode, +						     (i == rxsize - 1)); +		else +			priv->hw->desc->init_rx_desc(&priv->dma_rx[i], +						     priv->use_riwt, priv->mode, +						     (i == rxsize - 1)); +	for (i = 0; i < txsize; i++) +		if (priv->extend_desc) +			priv->hw->desc->init_tx_desc(&priv->dma_etx[i].basic, +						     priv->mode, +						     (i == txsize - 1)); +		else +			priv->hw->desc->init_tx_desc(&priv->dma_tx[i], +						     priv->mode, +						     (i == txsize - 1)); +} + +static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, +				  int i) +{ +	struct sk_buff *skb; + +	skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN, +				 GFP_KERNEL); +	if (unlikely(skb == NULL)) { +		pr_err("%s: Rx init fails; skb is NULL\n", __func__); +		return 1; +	} +	skb_reserve(skb, NET_IP_ALIGN); +	priv->rx_skbuff[i] = skb; +	priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data, +						priv->dma_buf_sz, +						DMA_FROM_DEVICE); + +	p->des2 = priv->rx_skbuff_dma[i]; + +	if ((priv->mode == STMMAC_RING_MODE) && +	    (priv->dma_buf_sz == BUF_SIZE_16KiB)) +		priv->hw->ring->init_desc3(p); + +	return 0; +} + +/**   * init_dma_desc_rings - init the RX/TX descriptor rings   * @dev: net device structure   * Description:  this function initializes the DMA RX/TX descriptors @@ -511,110 +1001,114 @@ static void init_dma_desc_rings(struct net_device *dev)  {  	int i;  	struct stmmac_priv *priv = netdev_priv(dev); -	struct sk_buff *skb;  	unsigned int txsize = priv->dma_tx_size;  	unsigned int rxsize = priv->dma_rx_size; -	unsigned int bfsize; -	int dis_ic = 0; -	int des3_as_data_buf = 0; +	unsigned int bfsize = 0;  	/* Set the max buffer size according to the DESC mode -	 * and the MTU. Note that RING mode allows 16KiB bsize. */ -	bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu); +	 * and the MTU. Note that RING mode allows 16KiB bsize. +	 */ +	if (priv->mode == STMMAC_RING_MODE) +		bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu); -	if (bfsize == BUF_SIZE_16KiB) -		des3_as_data_buf = 1; -	else +	if (bfsize < BUF_SIZE_16KiB)  		bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);  	DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n",  	    txsize, rxsize, bfsize); -	priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t), -					    GFP_KERNEL); -	priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *), -					GFP_KERNEL); -	priv->dma_rx = -	    (struct dma_desc *)dma_alloc_coherent(priv->device, -						  rxsize * +	if (priv->extend_desc) { +		priv->dma_erx = dma_alloc_coherent(priv->device, rxsize * +						   sizeof(struct +							  dma_extended_desc), +						   &priv->dma_rx_phy, +						   GFP_KERNEL); +		priv->dma_etx = dma_alloc_coherent(priv->device, txsize * +						   sizeof(struct +							  dma_extended_desc), +						   &priv->dma_tx_phy, +						   GFP_KERNEL); +		if ((!priv->dma_erx) || (!priv->dma_etx)) +			return; +	} else { +		priv->dma_rx = dma_alloc_coherent(priv->device, rxsize *  						  sizeof(struct dma_desc),  						  &priv->dma_rx_phy,  						  GFP_KERNEL); -	priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *), -					GFP_KERNEL); -	priv->dma_tx = -	    (struct dma_desc *)dma_alloc_coherent(priv->device, -						  txsize * +		priv->dma_tx = dma_alloc_coherent(priv->device, txsize *  						  sizeof(struct dma_desc),  						  &priv->dma_tx_phy,  						  GFP_KERNEL); - -	if ((priv->dma_rx == NULL) || (priv->dma_tx == NULL)) { -		pr_err("%s:ERROR allocating the DMA Tx/Rx desc\n", __func__); -		return; +		if ((!priv->dma_rx) || (!priv->dma_tx)) +			return;  	} -	DBG(probe, INFO, "stmmac (%s) DMA desc: virt addr (Rx %p, " -	    "Tx %p)\n\tDMA phy addr (Rx 0x%08x, Tx 0x%08x)\n", -	    dev->name, priv->dma_rx, priv->dma_tx, -	    (unsigned int)priv->dma_rx_phy, (unsigned int)priv->dma_tx_phy); +	priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t), +					    GFP_KERNEL); +	priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *), +					GFP_KERNEL); +	priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t), +					    GFP_KERNEL); +	priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *), +					GFP_KERNEL); +	if (netif_msg_drv(priv)) +		pr_debug("(%s) dma_rx_phy=0x%08x dma_tx_phy=0x%08x\n", __func__, +			 (u32) priv->dma_rx_phy, (u32) priv->dma_tx_phy);  	/* RX INITIALIZATION */ -	DBG(probe, INFO, "stmmac: SKB addresses:\n" -			 "skb\t\tskb data\tdma data\n"); - +	DBG(probe, INFO, "stmmac: SKB addresses:\nskb\t\tskb data\tdma data\n");  	for (i = 0; i < rxsize; i++) { -		struct dma_desc *p = priv->dma_rx + i; +		struct dma_desc *p; +		if (priv->extend_desc) +			p = &((priv->dma_erx + i)->basic); +		else +			p = priv->dma_rx + i; -		skb = __netdev_alloc_skb(dev, bfsize + NET_IP_ALIGN, -					 GFP_KERNEL); -		if (unlikely(skb == NULL)) { -			pr_err("%s: Rx init fails; skb is NULL\n", __func__); +		if (stmmac_init_rx_buffers(priv, p, i))  			break; -		} -		skb_reserve(skb, NET_IP_ALIGN); -		priv->rx_skbuff[i] = skb; -		priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data, -						bfsize, DMA_FROM_DEVICE); - -		p->des2 = priv->rx_skbuff_dma[i]; - -		priv->hw->ring->init_desc3(des3_as_data_buf, p);  		DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i], -			priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]); +		    priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]);  	}  	priv->cur_rx = 0;  	priv->dirty_rx = (unsigned int)(i - rxsize);  	priv->dma_buf_sz = bfsize;  	buf_sz = bfsize; +	/* Setup the chained descriptor addresses */ +	if (priv->mode == STMMAC_CHAIN_MODE) { +		if (priv->extend_desc) { +			priv->hw->chain->init(priv->dma_erx, priv->dma_rx_phy, +					      rxsize, 1); +			priv->hw->chain->init(priv->dma_etx, priv->dma_tx_phy, +					      txsize, 1); +		} else { +			priv->hw->chain->init(priv->dma_rx, priv->dma_rx_phy, +					      rxsize, 0); +			priv->hw->chain->init(priv->dma_tx, priv->dma_tx_phy, +					      txsize, 0); +		} +	} +  	/* TX INITIALIZATION */  	for (i = 0; i < txsize; i++) { +		struct dma_desc *p; +		if (priv->extend_desc) +			p = &((priv->dma_etx + i)->basic); +		else +			p = priv->dma_tx + i; +		p->des2 = 0; +		priv->tx_skbuff_dma[i] = 0;  		priv->tx_skbuff[i] = NULL; -		priv->dma_tx[i].des2 = 0;  	} -	/* In case of Chained mode this sets the des3 to the next -	 * element in the chain */ -	priv->hw->ring->init_dma_chain(priv->dma_rx, priv->dma_rx_phy, rxsize); -	priv->hw->ring->init_dma_chain(priv->dma_tx, priv->dma_tx_phy, txsize); -  	priv->dirty_tx = 0;  	priv->cur_tx = 0; -	if (priv->use_riwt) -		dis_ic = 1; -	/* Clear the Rx/Tx descriptors */ -	priv->hw->desc->init_rx_desc(priv->dma_rx, rxsize, dis_ic); -	priv->hw->desc->init_tx_desc(priv->dma_tx, txsize); +	stmmac_clear_descriptors(priv); -	if (netif_msg_hw(priv)) { -		pr_info("RX descriptor ring:\n"); -		display_ring(priv->dma_rx, rxsize); -		pr_info("TX descriptor ring:\n"); -		display_ring(priv->dma_tx, txsize); -	} +	if (netif_msg_hw(priv)) +		stmmac_display_rings(priv);  }  static void dma_free_rx_skbufs(struct stmmac_priv *priv) @@ -637,13 +1131,20 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)  	for (i = 0; i < priv->dma_tx_size; i++) {  		if (priv->tx_skbuff[i] != NULL) { -			struct dma_desc *p = priv->dma_tx + i; -			if (p->des2) -				dma_unmap_single(priv->device, p->des2, +			struct dma_desc *p; +			if (priv->extend_desc) +				p = &((priv->dma_etx + i)->basic); +			else +				p = priv->dma_tx + i; + +			if (priv->tx_skbuff_dma[i]) +				dma_unmap_single(priv->device, +						 priv->tx_skbuff_dma[i],  						 priv->hw->desc->get_tx_len(p),  						 DMA_TO_DEVICE);  			dev_kfree_skb_any(priv->tx_skbuff[i]);  			priv->tx_skbuff[i] = NULL; +			priv->tx_skbuff_dma[i] = 0;  		}  	}  } @@ -654,29 +1155,38 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)  	dma_free_rx_skbufs(priv);  	dma_free_tx_skbufs(priv); -	/* Free the region of consistent memory previously allocated for -	 * the DMA */ -	dma_free_coherent(priv->device, -			  priv->dma_tx_size * sizeof(struct dma_desc), -			  priv->dma_tx, priv->dma_tx_phy); -	dma_free_coherent(priv->device, -			  priv->dma_rx_size * sizeof(struct dma_desc), -			  priv->dma_rx, priv->dma_rx_phy); +	/* Free DMA regions of consistent memory previously allocated */ +	if (!priv->extend_desc) { +		dma_free_coherent(priv->device, +				  priv->dma_tx_size * sizeof(struct dma_desc), +				  priv->dma_tx, priv->dma_tx_phy); +		dma_free_coherent(priv->device, +				  priv->dma_rx_size * sizeof(struct dma_desc), +				  priv->dma_rx, priv->dma_rx_phy); +	} else { +		dma_free_coherent(priv->device, priv->dma_tx_size * +				  sizeof(struct dma_extended_desc), +				  priv->dma_etx, priv->dma_tx_phy); +		dma_free_coherent(priv->device, priv->dma_rx_size * +				  sizeof(struct dma_extended_desc), +				  priv->dma_erx, priv->dma_rx_phy); +	}  	kfree(priv->rx_skbuff_dma);  	kfree(priv->rx_skbuff); +	kfree(priv->tx_skbuff_dma);  	kfree(priv->tx_skbuff);  }  /**   *  stmmac_dma_operation_mode - HW DMA operation mode - *  @priv : pointer to the private device structure. + *  @priv: driver private structure   *  Description: it sets the DMA operation mode: tx/rx DMA thresholds   *  or Store-And-Forward capability.   */  static void stmmac_dma_operation_mode(struct stmmac_priv *priv)  {  	if (likely(priv->plat->force_sf_dma_mode || -		((priv->plat->tx_coe) && (!priv->no_csum_insertion)))) { +		   ((priv->plat->tx_coe) && (!priv->no_csum_insertion)))) {  		/*  		 * In case of GMAC, SF mode can be enabled  		 * to perform the TX COE in HW. This depends on: @@ -684,8 +1194,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)  		 * 2) There is no bugged Jumbo frame support  		 *    that needs to not insert csum in the TDES.  		 */ -		priv->hw->dma->dma_mode(priv->ioaddr, -					SF_DMA_MODE, SF_DMA_MODE); +		priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE);  		tc = SF_DMA_MODE;  	} else  		priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); @@ -693,7 +1202,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)  /**   * stmmac_tx_clean: - * @priv: private data pointer + * @priv: driver private structure   * Description: it reclaims resources after transmission completes.   */  static void stmmac_tx_clean(struct stmmac_priv *priv) @@ -708,40 +1217,50 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)  		int last;  		unsigned int entry = priv->dirty_tx % txsize;  		struct sk_buff *skb = priv->tx_skbuff[entry]; -		struct dma_desc *p = priv->dma_tx + entry; +		struct dma_desc *p; + +		if (priv->extend_desc) +			p = (struct dma_desc *)(priv->dma_etx + entry); +		else +			p = priv->dma_tx + entry;  		/* Check if the descriptor is owned by the DMA. */  		if (priv->hw->desc->get_tx_owner(p))  			break; -		/* Verify tx error by looking at the last segment */ +		/* Verify tx error by looking at the last segment. */  		last = priv->hw->desc->get_tx_ls(p);  		if (likely(last)) {  			int tx_error = -				priv->hw->desc->tx_status(&priv->dev->stats, -							  &priv->xstats, p, -							  priv->ioaddr); +			    priv->hw->desc->tx_status(&priv->dev->stats, +						      &priv->xstats, p, +						      priv->ioaddr);  			if (likely(tx_error == 0)) {  				priv->dev->stats.tx_packets++;  				priv->xstats.tx_pkt_n++;  			} else  				priv->dev->stats.tx_errors++; + +			stmmac_get_tx_hwtstamp(priv, entry, skb);  		}  		TX_DBG("%s: curr %d, dirty %d\n", __func__, -			priv->cur_tx, priv->dirty_tx); +		       priv->cur_tx, priv->dirty_tx); -		if (likely(p->des2)) -			dma_unmap_single(priv->device, p->des2, +		if (likely(priv->tx_skbuff_dma[entry])) { +			dma_unmap_single(priv->device, +					 priv->tx_skbuff_dma[entry],  					 priv->hw->desc->get_tx_len(p),  					 DMA_TO_DEVICE); -		priv->hw->ring->clean_desc3(p); +			priv->tx_skbuff_dma[entry] = 0; +		} +		priv->hw->ring->clean_desc3(priv, p);  		if (likely(skb != NULL)) {  			dev_kfree_skb(skb);  			priv->tx_skbuff[entry] = NULL;  		} -		priv->hw->desc->release_tx_desc(p); +		priv->hw->desc->release_tx_desc(p, priv->mode);  		priv->dirty_tx++;  	} @@ -749,7 +1268,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)  		     stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) {  		netif_tx_lock(priv->dev);  		if (netif_queue_stopped(priv->dev) && -		     stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv)) { +		    stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv)) {  			TX_DBG("%s: restart transmit\n", __func__);  			netif_wake_queue(priv->dev);  		} @@ -773,20 +1292,29 @@ static inline void stmmac_disable_dma_irq(struct stmmac_priv *priv)  	priv->hw->dma->disable_dma_irq(priv->ioaddr);  } -  /** - * stmmac_tx_err: - * @priv: pointer to the private device structure + * stmmac_tx_err: irq tx error mng function + * @priv: driver private structure   * Description: it cleans the descriptors and restarts the transmission   * in case of errors.   */  static void stmmac_tx_err(struct stmmac_priv *priv)  { +	int i; +	int txsize = priv->dma_tx_size;  	netif_stop_queue(priv->dev);  	priv->hw->dma->stop_tx(priv->ioaddr);  	dma_free_tx_skbufs(priv); -	priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size); +	for (i = 0; i < txsize; i++) +		if (priv->extend_desc) +			priv->hw->desc->init_tx_desc(&priv->dma_etx[i].basic, +						     priv->mode, +						     (i == txsize - 1)); +		else +			priv->hw->desc->init_tx_desc(&priv->dma_tx[i], +						     priv->mode, +						     (i == txsize - 1));  	priv->dirty_tx = 0;  	priv->cur_tx = 0;  	priv->hw->dma->start_tx(priv->ioaddr); @@ -795,6 +1323,14 @@ static void stmmac_tx_err(struct stmmac_priv *priv)  	netif_wake_queue(priv->dev);  } +/** + * stmmac_dma_interrupt: DMA ISR + * @priv: driver private structure + * Description: this is the DMA ISR. It is called by the main ISR. + * It calls the dwmac dma routine to understand which type of interrupt + * happened. In case of there is a Normal interrupt and either TX or RX + * interrupt happened so the NAPI is scheduled. + */  static void stmmac_dma_interrupt(struct stmmac_priv *priv)  {  	int status; @@ -817,13 +1353,16 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)  		stmmac_tx_err(priv);  } +/** + * stmmac_mmc_setup: setup the Mac Management Counters (MMC) + * @priv: driver private structure + * Description: this masks the MMC irq, in fact, the counters are managed in SW. + */  static void stmmac_mmc_setup(struct stmmac_priv *priv)  {  	unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET | -			    MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET; +	    MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET; -	/* Mask MMC irq, counters are managed in SW and registers -	 * are cleared on each READ eventually. */  	dwmac_mmc_intr_all_mask(priv->ioaddr);  	if (priv->dma_cap.rmon) { @@ -837,8 +1376,7 @@ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)  {  	u32 hwid = priv->hw->synopsys_uid; -	/* Only check valid Synopsys Id because old MAC chips -	 * have no HW registers where get the ID */ +	/* Check Synopsys Id (not available on old chips) */  	if (likely(hwid)) {  		u32 uid = ((hwid & 0x0000ff00) >> 8);  		u32 synid = (hwid & 0x000000ff); @@ -852,14 +1390,24 @@ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)  }  /** - * stmmac_selec_desc_mode - * @priv : private structure - * Description: select the Enhanced/Alternate or Normal descriptors + * stmmac_selec_desc_mode: to select among: normal/alternate/extend descriptors + * @priv: driver private structure + * Description: select the Enhanced/Alternate or Normal descriptors. + * In case of Enhanced/Alternate, it looks at the extended descriptors are + * supported by the HW cap. register.   */  static void stmmac_selec_desc_mode(struct stmmac_priv *priv)  {  	if (priv->plat->enh_desc) {  		pr_info(" Enhanced/Alternate descriptors\n"); + +		/* GMAC older than 3.50 has no extended descriptors */ +		if (priv->synopsys_id >= DWMAC_CORE_3_50) { +			pr_info("\tEnabled extended descriptors\n"); +			priv->extend_desc = 1; +		} else +			pr_warn("Extended descriptors not supported\n"); +  		priv->hw->desc = &enh_desc_ops;  	} else {  		pr_info(" Normal descriptors\n"); @@ -868,8 +1416,8 @@ static void stmmac_selec_desc_mode(struct stmmac_priv *priv)  }  /** - * stmmac_get_hw_features - * @priv : private device pointer + * stmmac_get_hw_features: get MAC capabilities from the HW cap. register. + * @priv: driver private structure   * Description:   *  new GMAC chip generations have a new register to indicate the   *  presence of the optional feature/functions. @@ -887,69 +1435,78 @@ static int stmmac_get_hw_features(struct stmmac_priv *priv)  		priv->dma_cap.mbps_1000 = (hw_cap & DMA_HW_FEAT_GMIISEL) >> 1;  		priv->dma_cap.half_duplex = (hw_cap & DMA_HW_FEAT_HDSEL) >> 2;  		priv->dma_cap.hash_filter = (hw_cap & DMA_HW_FEAT_HASHSEL) >> 4; -		priv->dma_cap.multi_addr = -			(hw_cap & DMA_HW_FEAT_ADDMACADRSEL) >> 5; +		priv->dma_cap.multi_addr = (hw_cap & DMA_HW_FEAT_ADDMAC) >> 5;  		priv->dma_cap.pcs = (hw_cap & DMA_HW_FEAT_PCSSEL) >> 6;  		priv->dma_cap.sma_mdio = (hw_cap & DMA_HW_FEAT_SMASEL) >> 8;  		priv->dma_cap.pmt_remote_wake_up = -			(hw_cap & DMA_HW_FEAT_RWKSEL) >> 9; +		    (hw_cap & DMA_HW_FEAT_RWKSEL) >> 9;  		priv->dma_cap.pmt_magic_frame = -			(hw_cap & DMA_HW_FEAT_MGKSEL) >> 10; +		    (hw_cap & DMA_HW_FEAT_MGKSEL) >> 10;  		/* MMC */  		priv->dma_cap.rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11; -		/* IEEE 1588-2002*/ +		/* IEEE 1588-2002 */  		priv->dma_cap.time_stamp = -			(hw_cap & DMA_HW_FEAT_TSVER1SEL) >> 12; -		/* IEEE 1588-2008*/ +		    (hw_cap & DMA_HW_FEAT_TSVER1SEL) >> 12; +		/* IEEE 1588-2008 */  		priv->dma_cap.atime_stamp = -			(hw_cap & DMA_HW_FEAT_TSVER2SEL) >> 13; +		    (hw_cap & DMA_HW_FEAT_TSVER2SEL) >> 13;  		/* 802.3az - Energy-Efficient Ethernet (EEE) */  		priv->dma_cap.eee = (hw_cap & DMA_HW_FEAT_EEESEL) >> 14;  		priv->dma_cap.av = (hw_cap & DMA_HW_FEAT_AVSEL) >> 15;  		/* TX and RX csum */  		priv->dma_cap.tx_coe = (hw_cap & DMA_HW_FEAT_TXCOESEL) >> 16;  		priv->dma_cap.rx_coe_type1 = -			(hw_cap & DMA_HW_FEAT_RXTYP1COE) >> 17; +		    (hw_cap & DMA_HW_FEAT_RXTYP1COE) >> 17;  		priv->dma_cap.rx_coe_type2 = -			(hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18; +		    (hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18;  		priv->dma_cap.rxfifo_over_2048 = -			(hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19; +		    (hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19;  		/* TX and RX number of channels */  		priv->dma_cap.number_rx_channel = -			(hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20; +		    (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;  		priv->dma_cap.number_tx_channel = -			(hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22; -		/* Alternate (enhanced) DESC mode*/ -		priv->dma_cap.enh_desc = -			(hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24; +		    (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22; +		/* Alternate (enhanced) DESC mode */ +		priv->dma_cap.enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;  	}  	return hw_cap;  } +/** + * stmmac_check_ether_addr: check if the MAC addr is valid + * @priv: driver private structure + * Description: + * it is to verify if the MAC address is valid, in case of failures it + * generates a random MAC address + */  static void stmmac_check_ether_addr(struct stmmac_priv *priv)  { -	/* verify if the MAC address is valid, in case of failures it -	 * generates a random MAC address */  	if (!is_valid_ether_addr(priv->dev->dev_addr)) {  		priv->hw->mac->get_umac_addr((void __iomem *)  					     priv->dev->base_addr,  					     priv->dev->dev_addr, 0); -		if  (!is_valid_ether_addr(priv->dev->dev_addr)) +		if (!is_valid_ether_addr(priv->dev->dev_addr))  			eth_hw_addr_random(priv->dev);  	} -	pr_warning("%s: device MAC address %pM\n", priv->dev->name, -						   priv->dev->dev_addr); +	pr_warn("%s: device MAC address %pM\n", priv->dev->name, +		priv->dev->dev_addr);  } +/** + * stmmac_init_dma_engine: DMA init. + * @priv: driver private structure + * Description: + * It inits the DMA invoking the specific MAC/GMAC callback. + * Some DMA parameters can be passed from the platform; + * in case of these are not passed a default is kept for the MAC or GMAC. + */  static int stmmac_init_dma_engine(struct stmmac_priv *priv)  {  	int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, burst_len = 0;  	int mixed_burst = 0; +	int atds = 0; -	/* Some DMA parameters can be passed from the platform; -	 * in case of these are not passed we keep a default -	 * (good for all the chips) and init the DMA! */  	if (priv->plat->dma_cfg) {  		pbl = priv->plat->dma_cfg->pbl;  		fixed_burst = priv->plat->dma_cfg->fixed_burst; @@ -957,13 +1514,16 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)  		burst_len = priv->plat->dma_cfg->burst_len;  	} +	if (priv->extend_desc && (priv->mode == STMMAC_RING_MODE)) +		atds = 1; +  	return priv->hw->dma->init(priv->ioaddr, pbl, fixed_burst, mixed_burst,  				   burst_len, priv->dma_tx_phy, -				   priv->dma_rx_phy); +				   priv->dma_rx_phy, atds);  }  /** - * stmmac_tx_timer: + * stmmac_tx_timer: mitigation sw timer for tx.   * @data: data pointer   * Description:   * This is the timer handler to directly invoke the stmmac_tx_clean. @@ -976,8 +1536,8 @@ static void stmmac_tx_timer(unsigned long data)  }  /** - * stmmac_tx_timer: - * @priv: private data structure + * stmmac_init_tx_coalesce: init tx mitigation options. + * @priv: driver private structure   * Description:   * This inits the transmit coalesce parameters: i.e. timer rate,   * timer handler and default threshold used for enabling the @@ -1012,10 +1572,14 @@ static int stmmac_open(struct net_device *dev)  	stmmac_check_ether_addr(priv); -	ret = stmmac_init_phy(dev); -	if (unlikely(ret)) { -		pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret); -		goto open_error; +	if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && +	    priv->pcs != STMMAC_PCS_RTBI) { +		ret = stmmac_init_phy(dev); +		if (ret) { +			pr_err("%s: Cannot attach to PHY (error: %d)\n", +			       __func__, ret); +			goto open_error; +		}  	}  	/* Create and initialize the TX/RX descriptors chains. */ @@ -1043,7 +1607,7 @@ static int stmmac_open(struct net_device *dev)  	/* Request the IRQ lines */  	ret = request_irq(dev->irq, stmmac_interrupt, -			 IRQF_SHARED, dev->name, dev); +			  IRQF_SHARED, dev->name, dev);  	if (unlikely(ret < 0)) {  		pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n",  		       __func__, dev->irq, ret); @@ -1055,8 +1619,8 @@ static int stmmac_open(struct net_device *dev)  		ret = request_irq(priv->wol_irq, stmmac_interrupt,  				  IRQF_SHARED, dev->name, dev);  		if (unlikely(ret < 0)) { -			pr_err("%s: ERROR: allocating the ext WoL IRQ %d " -			       "(error: %d)\n",	__func__, priv->wol_irq, ret); +			pr_err("%s: ERROR: allocating the WoL IRQ %d (%d)\n", +			       __func__, priv->wol_irq, ret);  			goto open_error_wolirq;  		}  	} @@ -1084,10 +1648,14 @@ static int stmmac_open(struct net_device *dev)  	stmmac_mmc_setup(priv); +	ret = stmmac_init_ptp(priv); +	if (ret) +		pr_warn("%s: failed PTP initialisation\n", __func__); +  #ifdef CONFIG_STMMAC_DEBUG_FS  	ret = stmmac_init_fs(dev);  	if (ret < 0) -		pr_warning("%s: failed debugFS registration\n", __func__); +		pr_warn("%s: failed debugFS registration\n", __func__);  #endif  	/* Start the ball rolling... */  	DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name); @@ -1104,7 +1672,13 @@ static int stmmac_open(struct net_device *dev)  		phy_start(priv->phydev);  	priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS_TIMER; -	priv->eee_enabled = stmmac_eee_init(priv); + +	/* Using PCS we cannot dial with the phy registers at this stage +	 * so we do not support extra feature like EEE. +	 */ +	if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && +	    priv->pcs != STMMAC_PCS_RTBI) +		priv->eee_enabled = stmmac_eee_init(priv);  	stmmac_init_tx_coalesce(priv); @@ -1113,6 +1687,9 @@ static int stmmac_open(struct net_device *dev)  		priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT);  	} +	if (priv->pcs && priv->hw->mac->ctrl_ane) +		priv->hw->mac->ctrl_ane(priv->ioaddr, 0); +  	napi_enable(&priv->napi);  	netif_start_queue(dev); @@ -1184,21 +1761,25 @@ static int stmmac_release(struct net_device *dev)  #endif  	clk_disable_unprepare(priv->stmmac_clk); +	stmmac_release_ptp(priv); +  	return 0;  }  /** - *  stmmac_xmit: + *  stmmac_xmit: Tx entry point of the driver   *  @skb : the socket buffer   *  @dev : device pointer - *  Description : Tx entry point of the driver. + *  Description : this is the tx entry point of the driver. + *  It programs the chain or the ring and supports oversized frames + *  and SG feature.   */  static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)  {  	struct stmmac_priv *priv = netdev_priv(dev);  	unsigned int txsize = priv->dma_tx_size;  	unsigned int entry; -	int i, csum_insertion = 0; +	int i, csum_insertion = 0, is_jumbo = 0;  	int nfrags = skb_shinfo(skb)->nr_frags;  	struct dma_desc *desc, *first;  	unsigned int nopaged_len = skb_headlen(skb); @@ -1207,8 +1788,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)  		if (!netif_queue_stopped(dev)) {  			netif_stop_queue(dev);  			/* This is a hard error, log it. */ -			pr_err("%s: BUG! Tx Ring full when queue awake\n", -				__func__); +			pr_err("%s: Tx Ring full when queue awake\n", __func__);  		}  		return NETDEV_TX_BUSY;  	} @@ -1222,10 +1802,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)  #ifdef STMMAC_XMIT_DEBUG  	if ((skb->len > ETH_FRAME_LEN) || nfrags) -		pr_debug("stmmac xmit: [entry %d]\n" -			 "\tskb addr %p - len: %d - nopaged_len: %d\n" +		pr_debug("%s: [entry %d]: skb addr %p len: %d nopagedlen: %d\n"  			 "\tn_frags: %d - ip_summed: %d - %s gso\n" -			 "\ttx_count_frames %d\n", entry, +			 "\ttx_count_frames %d\n", __func__, entry,  			 skb, skb->len, nopaged_len, nfrags, skb->ip_summed,  			 !skb_is_gso(skb) ? "isn't" : "is",  			 priv->tx_count_frames); @@ -1233,7 +1812,11 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)  	csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL); -	desc = priv->dma_tx + entry; +	if (priv->extend_desc) +		desc = (struct dma_desc *)(priv->dma_etx + entry); +	else +		desc = priv->dma_tx + entry; +  	first = desc;  #ifdef STMMAC_XMIT_DEBUG @@ -1244,28 +1827,46 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)  #endif  	priv->tx_skbuff[entry] = skb; -	if (priv->hw->ring->is_jumbo_frm(skb->len, priv->plat->enh_desc)) { -		entry = priv->hw->ring->jumbo_frm(priv, skb, csum_insertion); -		desc = priv->dma_tx + entry; +	/* To program the descriptors according to the size of the frame */ +	if (priv->mode == STMMAC_RING_MODE) { +		is_jumbo = priv->hw->ring->is_jumbo_frm(skb->len, +							priv->plat->enh_desc); +		if (unlikely(is_jumbo)) +			entry = priv->hw->ring->jumbo_frm(priv, skb, +							  csum_insertion);  	} else { +		is_jumbo = priv->hw->chain->is_jumbo_frm(skb->len, +							 priv->plat->enh_desc); +		if (unlikely(is_jumbo)) +			entry = priv->hw->chain->jumbo_frm(priv, skb, +							   csum_insertion); +	} +	if (likely(!is_jumbo)) {  		desc->des2 = dma_map_single(priv->device, skb->data, -					nopaged_len, DMA_TO_DEVICE); +					    nopaged_len, DMA_TO_DEVICE); +		priv->tx_skbuff_dma[entry] = desc->des2;  		priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, -						csum_insertion); -	} +						csum_insertion, priv->mode); +	} else +		desc = first;  	for (i = 0; i < nfrags; i++) {  		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];  		int len = skb_frag_size(frag);  		entry = (++priv->cur_tx) % txsize; -		desc = priv->dma_tx + entry; +		if (priv->extend_desc) +			desc = (struct dma_desc *)(priv->dma_etx + entry); +		else +			desc = priv->dma_tx + entry;  		TX_DBG("\t[entry %d] segment len: %d\n", entry, len);  		desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len,  					      DMA_TO_DEVICE); +		priv->tx_skbuff_dma[entry] = desc->des2;  		priv->tx_skbuff[entry] = NULL; -		priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion); +		priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion, +						priv->mode);  		wmb();  		priv->hw->desc->set_tx_owner(desc);  		wmb(); @@ -1298,11 +1899,14 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)  #ifdef STMMAC_XMIT_DEBUG  	if (netif_msg_pktdata(priv)) { -		pr_info("stmmac xmit: current=%d, dirty=%d, entry=%d, " -		       "first=%p, nfrags=%d\n", -		       (priv->cur_tx % txsize), (priv->dirty_tx % txsize), -		       entry, first, nfrags); -		display_ring(priv->dma_tx, txsize); +		pr_info("%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d" +			__func__, (priv->cur_tx % txsize), +			(priv->dirty_tx % txsize), entry, first, nfrags); +		if (priv->extend_desc) +			stmmac_display_ring((void *)priv->dma_etx, txsize, 1); +		else +			stmmac_display_ring((void *)priv->dma_tx, txsize, 0); +  		pr_info(">>> frame to be transmitted: ");  		print_pkt(skb->data, skb->len);  	} @@ -1314,7 +1918,15 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)  	dev->stats.tx_bytes += skb->len; -	skb_tx_timestamp(skb); +	if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && +		     priv->hwts_tx_en)) { +		/* declare that device is doing timestamping */ +		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; +		priv->hw->desc->enable_tx_timestamp(first); +	} + +	if (!priv->hwts_tx_en) +		skb_tx_timestamp(skb);  	priv->hw->dma->enable_dma_transmission(priv->ioaddr); @@ -1323,14 +1935,26 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)  	return NETDEV_TX_OK;  } +/** + * stmmac_rx_refill: refill used skb preallocated buffers + * @priv: driver private structure + * Description : this is to reallocate the skb for the reception process + * that is based on zero-copy. + */  static inline void stmmac_rx_refill(struct stmmac_priv *priv)  {  	unsigned int rxsize = priv->dma_rx_size;  	int bfsize = priv->dma_buf_sz; -	struct dma_desc *p = priv->dma_rx;  	for (; priv->cur_rx - priv->dirty_rx > 0; priv->dirty_rx++) {  		unsigned int entry = priv->dirty_rx % rxsize; +		struct dma_desc *p; + +		if (priv->extend_desc) +			p = (struct dma_desc *)(priv->dma_erx + entry); +		else +			p = priv->dma_rx + entry; +  		if (likely(priv->rx_skbuff[entry] == NULL)) {  			struct sk_buff *skb; @@ -1344,80 +1968,116 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)  			    dma_map_single(priv->device, skb->data, bfsize,  					   DMA_FROM_DEVICE); -			(p + entry)->des2 = priv->rx_skbuff_dma[entry]; +			p->des2 = priv->rx_skbuff_dma[entry]; -			if (unlikely(priv->plat->has_gmac)) -				priv->hw->ring->refill_desc3(bfsize, p + entry); +			priv->hw->ring->refill_desc3(priv, p);  			RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);  		}  		wmb(); -		priv->hw->desc->set_rx_owner(p + entry); +		priv->hw->desc->set_rx_owner(p);  		wmb();  	}  } +/** + * stmmac_rx_refill: refill used skb preallocated buffers + * @priv: driver private structure + * @limit: napi bugget. + * Description :  this the function called by the napi poll method. + * It gets all the frames inside the ring. + */  static int stmmac_rx(struct stmmac_priv *priv, int limit)  {  	unsigned int rxsize = priv->dma_rx_size;  	unsigned int entry = priv->cur_rx % rxsize;  	unsigned int next_entry;  	unsigned int count = 0; -	struct dma_desc *p = priv->dma_rx + entry; -	struct dma_desc *p_next; +	int coe = priv->plat->rx_coe;  #ifdef STMMAC_RX_DEBUG  	if (netif_msg_hw(priv)) {  		pr_debug(">>> stmmac_rx: descriptor ring:\n"); -		display_ring(priv->dma_rx, rxsize); +		if (priv->extend_desc) +			stmmac_display_ring((void *)priv->dma_erx, rxsize, 1); +		else +			stmmac_display_ring((void *)priv->dma_rx, rxsize, 0);  	}  #endif -	while (!priv->hw->desc->get_rx_owner(p)) { +	while (count < limit) {  		int status; +		struct dma_desc *p; + +		if (priv->extend_desc) +			p = (struct dma_desc *)(priv->dma_erx + entry); +		else +			p = priv->dma_rx + entry; -		if (count >= limit) +		if (priv->hw->desc->get_rx_owner(p))  			break;  		count++;  		next_entry = (++priv->cur_rx) % rxsize; -		p_next = priv->dma_rx + next_entry; -		prefetch(p_next); +		if (priv->extend_desc) +			prefetch(priv->dma_erx + next_entry); +		else +			prefetch(priv->dma_rx + next_entry);  		/* read the status of the incoming frame */ -		status = (priv->hw->desc->rx_status(&priv->dev->stats, -						    &priv->xstats, p)); -		if (unlikely(status == discard_frame)) +		status = priv->hw->desc->rx_status(&priv->dev->stats, +						   &priv->xstats, p); +		if ((priv->extend_desc) && (priv->hw->desc->rx_extended_status)) +			priv->hw->desc->rx_extended_status(&priv->dev->stats, +							   &priv->xstats, +							   priv->dma_erx + +							   entry); +		if (unlikely(status == discard_frame)) {  			priv->dev->stats.rx_errors++; -		else { +			if (priv->hwts_rx_en && !priv->extend_desc) { +				/* DESC2 & DESC3 will be overwitten by device +				 * with timestamp value, hence reinitialize +				 * them in stmmac_rx_refill() function so that +				 * device can reuse it. +				 */ +				priv->rx_skbuff[entry] = NULL; +				dma_unmap_single(priv->device, +						 priv->rx_skbuff_dma[entry], +						 priv->dma_buf_sz, +						 DMA_FROM_DEVICE); +			} +		} else {  			struct sk_buff *skb;  			int frame_len; -			frame_len = priv->hw->desc->get_rx_frame_len(p, -					priv->plat->rx_coe); +			frame_len = priv->hw->desc->get_rx_frame_len(p, coe); +  			/* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3 -			 * Type frames (LLC/LLC-SNAP) */ +			 * Type frames (LLC/LLC-SNAP) +			 */  			if (unlikely(status != llc_snap))  				frame_len -= ETH_FCS_LEN;  #ifdef STMMAC_RX_DEBUG  			if (frame_len > ETH_FRAME_LEN)  				pr_debug("\tRX frame size %d, COE status: %d\n", -					frame_len, status); +					 frame_len, status);  			if (netif_msg_hw(priv))  				pr_debug("\tdesc: %p [entry %d] buff=0x%x\n", -					p, entry, p->des2); +					 p, entry, p->des2);  #endif  			skb = priv->rx_skbuff[entry];  			if (unlikely(!skb)) {  				pr_err("%s: Inconsistent Rx descriptor chain\n", -					priv->dev->name); +				       priv->dev->name);  				priv->dev->stats.rx_dropped++;  				break;  			}  			prefetch(skb->data - NET_IP_ALIGN);  			priv->rx_skbuff[entry] = NULL; +			stmmac_get_rx_hwtstamp(priv, entry, skb); +  			skb_put(skb, frame_len);  			dma_unmap_single(priv->device,  					 priv->rx_skbuff_dma[entry], @@ -1430,7 +2090,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)  #endif  			skb->protocol = eth_type_trans(skb, priv->dev); -			if (unlikely(!priv->plat->rx_coe)) +			if (unlikely(!coe))  				skb_checksum_none_assert(skb);  			else  				skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -1441,7 +2101,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)  			priv->dev->stats.rx_bytes += frame_len;  		}  		entry = next_entry; -		p = p_next;	/* use prefetched values */  	}  	stmmac_rx_refill(priv); @@ -1499,18 +2158,16 @@ static int stmmac_config(struct net_device *dev, struct ifmap *map)  	/* Don't allow changing the I/O address */  	if (map->base_addr != dev->base_addr) { -		pr_warning("%s: can't change I/O address\n", dev->name); +		pr_warn("%s: can't change I/O address\n", dev->name);  		return -EOPNOTSUPP;  	}  	/* Don't allow changing the IRQ */  	if (map->irq != dev->irq) { -		pr_warning("%s: can't change IRQ number %d\n", -		       dev->name, dev->irq); +		pr_warn("%s: not change IRQ number %d\n", dev->name, dev->irq);  		return -EOPNOTSUPP;  	} -	/* ignore other fields */  	return 0;  } @@ -1570,7 +2227,7 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)  }  static netdev_features_t stmmac_fix_features(struct net_device *dev, -	netdev_features_t features) +					     netdev_features_t features)  {  	struct stmmac_priv *priv = netdev_priv(dev); @@ -1584,13 +2241,22 @@ static netdev_features_t stmmac_fix_features(struct net_device *dev,  	/* Some GMAC devices have a bugged Jumbo frame support that  	 * needs to have the Tx COE disabled for oversized frames  	 * (due to limited buffer sizes). In this case we disable -	 * the TX csum insertionin the TDES and not use SF. */ +	 * the TX csum insertionin the TDES and not use SF. +	 */  	if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN))  		features &= ~NETIF_F_ALL_CSUM;  	return features;  } +/** + *  stmmac_interrupt - main ISR + *  @irq: interrupt number. + *  @dev_id: to pass the net device pointer. + *  Description: this is the main driver interrupt service routine. + *  It calls the DMA ISR and also the core ISR to manage PMT, MMC, LPI + *  interrupts. + */  static irqreturn_t stmmac_interrupt(int irq, void *dev_id)  {  	struct net_device *dev = (struct net_device *)dev_id; @@ -1604,30 +2270,14 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)  	/* To handle GMAC own interrupts */  	if (priv->plat->has_gmac) {  		int status = priv->hw->mac->host_irq_status((void __iomem *) -							    dev->base_addr); +							    dev->base_addr, +							    &priv->xstats);  		if (unlikely(status)) { -			if (status & core_mmc_tx_irq) -				priv->xstats.mmc_tx_irq_n++; -			if (status & core_mmc_rx_irq) -				priv->xstats.mmc_rx_irq_n++; -			if (status & core_mmc_rx_csum_offload_irq) -				priv->xstats.mmc_rx_csum_offload_irq_n++; -			if (status & core_irq_receive_pmt_irq) -				priv->xstats.irq_receive_pmt_irq_n++; -  			/* For LPI we need to save the tx status */ -			if (status & core_irq_tx_path_in_lpi_mode) { -				priv->xstats.irq_tx_path_in_lpi_mode_n++; +			if (status & CORE_IRQ_TX_PATH_IN_LPI_MODE)  				priv->tx_path_in_lpi_mode = true; -			} -			if (status & core_irq_tx_path_exit_lpi_mode) { -				priv->xstats.irq_tx_path_exit_lpi_mode_n++; +			if (status & CORE_IRQ_TX_PATH_EXIT_LPI_MODE)  				priv->tx_path_in_lpi_mode = false; -			} -			if (status & core_irq_rx_path_in_lpi_mode) -				priv->xstats.irq_rx_path_in_lpi_mode_n++; -			if (status & core_irq_rx_path_exit_lpi_mode) -				priv->xstats.irq_rx_path_exit_lpi_mode_n++;  		}  	} @@ -1639,7 +2289,8 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)  #ifdef CONFIG_NET_POLL_CONTROLLER  /* Polling receive - used by NETCONSOLE and other diagnostic tools - * to allow network I/O with interrupts disabled. */ + * to allow network I/O with interrupts disabled. + */  static void stmmac_poll_controller(struct net_device *dev)  {  	disable_irq(dev->irq); @@ -1655,21 +2306,30 @@ static void stmmac_poll_controller(struct net_device *dev)   *  a proprietary structure used to pass information to the driver.   *  @cmd: IOCTL command   *  Description: - *  Currently there are no special functionality supported in IOCTL, just the - *  phy_mii_ioctl(...) can be invoked. + *  Currently it supports the phy_mii_ioctl(...) and HW time stamping.   */  static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)  {  	struct stmmac_priv *priv = netdev_priv(dev); -	int ret; +	int ret = -EOPNOTSUPP;  	if (!netif_running(dev))  		return -EINVAL; -	if (!priv->phydev) -		return -EINVAL; - -	ret = phy_mii_ioctl(priv->phydev, rq, cmd); +	switch (cmd) { +	case SIOCGMIIPHY: +	case SIOCGMIIREG: +	case SIOCSMIIREG: +		if (!priv->phydev) +			return -EINVAL; +		ret = phy_mii_ioctl(priv->phydev, rq, cmd); +		break; +	case SIOCSHWTSTAMP: +		ret = stmmac_hwtstamp_ioctl(dev, rq); +		break; +	default: +		break; +	}  	return ret;  } @@ -1679,40 +2339,51 @@ static struct dentry *stmmac_fs_dir;  static struct dentry *stmmac_rings_status;  static struct dentry *stmmac_dma_cap; -static int stmmac_sysfs_ring_read(struct seq_file *seq, void *v) +static void sysfs_display_ring(void *head, int size, int extend_desc, +			       struct seq_file *seq)  { -	struct tmp_s { -		u64 a; -		unsigned int b; -		unsigned int c; -	};  	int i; -	struct net_device *dev = seq->private; -	struct stmmac_priv *priv = netdev_priv(dev); +	struct dma_extended_desc *ep = (struct dma_extended_desc *)head; +	struct dma_desc *p = (struct dma_desc *)head; -	seq_printf(seq, "=======================\n"); -	seq_printf(seq, " RX descriptor ring\n"); -	seq_printf(seq, "=======================\n"); - -	for (i = 0; i < priv->dma_rx_size; i++) { -		struct tmp_s *x = (struct tmp_s *)(priv->dma_rx + i); -		seq_printf(seq, "[%d] DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x", -			   i, (unsigned int)(x->a), -			   (unsigned int)((x->a) >> 32), x->b, x->c); +	for (i = 0; i < size; i++) { +		u64 x; +		if (extend_desc) { +			x = *(u64 *) ep; +			seq_printf(seq, "%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n", +				   i, (unsigned int)virt_to_phys(ep), +				   (unsigned int)x, (unsigned int)(x >> 32), +				   ep->basic.des2, ep->basic.des3); +			ep++; +		} else { +			x = *(u64 *) p; +			seq_printf(seq, "%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n", +				   i, (unsigned int)virt_to_phys(ep), +				   (unsigned int)x, (unsigned int)(x >> 32), +				   p->des2, p->des3); +			p++; +		}  		seq_printf(seq, "\n");  	} +} -	seq_printf(seq, "\n"); -	seq_printf(seq, "=======================\n"); -	seq_printf(seq, "  TX descriptor ring\n"); -	seq_printf(seq, "=======================\n"); +static int stmmac_sysfs_ring_read(struct seq_file *seq, void *v) +{ +	struct net_device *dev = seq->private; +	struct stmmac_priv *priv = netdev_priv(dev); +	unsigned int txsize = priv->dma_tx_size; +	unsigned int rxsize = priv->dma_rx_size; -	for (i = 0; i < priv->dma_tx_size; i++) { -		struct tmp_s *x = (struct tmp_s *)(priv->dma_tx + i); -		seq_printf(seq, "[%d] DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x", -			   i, (unsigned int)(x->a), -			   (unsigned int)((x->a) >> 32), x->b, x->c); -		seq_printf(seq, "\n"); +	if (priv->extend_desc) { +		seq_printf(seq, "Extended RX descriptor ring:\n"); +		sysfs_display_ring((void *)priv->dma_erx, rxsize, 1, seq); +		seq_printf(seq, "Extended TX descriptor ring:\n"); +		sysfs_display_ring((void *)priv->dma_etx, txsize, 1, seq); +	} else { +		seq_printf(seq, "RX descriptor ring:\n"); +		sysfs_display_ring((void *)priv->dma_rx, rxsize, 0, seq); +		seq_printf(seq, "TX descriptor ring:\n"); +		sysfs_display_ring((void *)priv->dma_tx, txsize, 0, seq);  	}  	return 0; @@ -1817,8 +2488,8 @@ static int stmmac_init_fs(struct net_device *dev)  	/* Entry to report DMA RX/TX rings */  	stmmac_rings_status = debugfs_create_file("descriptors_status", -					   S_IRUGO, stmmac_fs_dir, dev, -					   &stmmac_rings_status_fops); +						  S_IRUGO, stmmac_fs_dir, dev, +						  &stmmac_rings_status_fops);  	if (!stmmac_rings_status || IS_ERR(stmmac_rings_status)) {  		pr_info("ERROR creating stmmac ring debugfs file\n"); @@ -1868,7 +2539,7 @@ static const struct net_device_ops stmmac_netdev_ops = {  /**   *  stmmac_hw_init - Init the MAC device - *  @priv : pointer to the private device structure. + *  @priv: driver private structure   *  Description: this function detects which MAC device   *  (GMAC/MAC10-100) has to attached, checks the HW capability   *  (if supported) and sets the driver's features (for example @@ -1877,7 +2548,7 @@ static const struct net_device_ops stmmac_netdev_ops = {   */  static int stmmac_hw_init(struct stmmac_priv *priv)  { -	int ret = 0; +	int ret;  	struct mac_device_info *mac;  	/* Identify the MAC HW device */ @@ -1892,12 +2563,23 @@ static int stmmac_hw_init(struct stmmac_priv *priv)  	priv->hw = mac; -	/* To use the chained or ring mode */ -	priv->hw->ring = &ring_mode_ops; -  	/* Get and dump the chip ID */  	priv->synopsys_id = stmmac_get_synopsys_id(priv); +	/* To use alternate (extended) or normal descriptor structures */ +	stmmac_selec_desc_mode(priv); + +	/* To use the chained or ring mode */ +	if (chain_mode) { +		priv->hw->chain = &chain_mode_ops; +		pr_info(" Chain mode enabled\n"); +		priv->mode = STMMAC_CHAIN_MODE; +	} else { +		priv->hw->ring = &ring_mode_ops; +		pr_info(" Ring mode enabled\n"); +		priv->mode = STMMAC_RING_MODE; +	} +  	/* Get the HW capability (new GMAC newer than 3.50a) */  	priv->hw_cap_support = stmmac_get_hw_features(priv);  	if (priv->hw_cap_support) { @@ -1921,14 +2603,9 @@ static int stmmac_hw_init(struct stmmac_priv *priv)  	} else  		pr_info(" No HW DMA feature register supported"); -	/* Select the enhnaced/normal descriptor structures */ -	stmmac_selec_desc_mode(priv); - -	/* Enable the IPC (Checksum Offload) and check if the feature has been -	 * enabled during the core configuration. */  	ret = priv->hw->mac->rx_ipc(priv->ioaddr);  	if (!ret) { -		pr_warning(" RX IPC Checksum Offload not configured.\n"); +		pr_warn(" RX IPC Checksum Offload not configured.\n");  		priv->plat->rx_coe = STMMAC_RX_COE_NONE;  	} @@ -1943,7 +2620,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv)  		device_set_wakeup_capable(priv->device, 1);  	} -	return ret; +	return 0;  }  /** @@ -1984,12 +2661,15 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,  	stmmac_verify_args();  	/* Override with kernel parameters if supplied XXX CRS XXX -	 * this needs to have multiple instances */ +	 * this needs to have multiple instances +	 */  	if ((phyaddr >= 0) && (phyaddr <= 31))  		priv->plat->phy_addr = phyaddr;  	/* Init MAC and get the capabilities */ -	stmmac_hw_init(priv); +	ret = stmmac_hw_init(priv); +	if (ret) +		goto error_free_netdev;  	ndev->netdev_ops = &stmmac_netdev_ops; @@ -1999,7 +2679,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,  	ndev->watchdog_timeo = msecs_to_jiffies(watchdog);  #ifdef STMMAC_VLAN_TAG_USED  	/* Both mac100 and gmac support receive VLAN tag detection */ -	ndev->features |= NETIF_F_HW_VLAN_RX; +	ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;  #endif  	priv->msg_enable = netif_msg_init(debug, default_msg_level); @@ -2029,7 +2709,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,  	priv->stmmac_clk = clk_get(priv->device, STMMAC_RESOURCE_NAME);  	if (IS_ERR(priv->stmmac_clk)) { -		pr_warning("%s: warning: cannot get CSR clock\n", __func__); +		pr_warn("%s: warning: cannot get CSR clock\n", __func__);  		goto error_clk_get;  	} @@ -2044,12 +2724,17 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,  	else  		priv->clk_csr = priv->plat->clk_csr; -	/* MDIO bus Registration */ -	ret = stmmac_mdio_register(ndev); -	if (ret < 0) { -		pr_debug("%s: MDIO bus (id: %d) registration failed", -			 __func__, priv->plat->bus_id); -		goto error_mdio_register; +	stmmac_check_pcs_mode(priv); + +	if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && +	    priv->pcs != STMMAC_PCS_RTBI) { +		/* MDIO bus Registration */ +		ret = stmmac_mdio_register(ndev); +		if (ret < 0) { +			pr_debug("%s: MDIO bus (id: %d) registration failed", +				 __func__, priv->plat->bus_id); +			goto error_mdio_register; +		}  	}  	return priv; @@ -2060,6 +2745,7 @@ error_clk_get:  	unregister_netdev(ndev);  error_netdev_register:  	netif_napi_del(&priv->napi); +error_free_netdev:  	free_netdev(ndev);  	return NULL; @@ -2081,7 +2767,9 @@ int stmmac_dvr_remove(struct net_device *ndev)  	priv->hw->dma->stop_tx(priv->ioaddr);  	stmmac_set_mac(priv->ioaddr, false); -	stmmac_mdio_unregister(ndev); +	if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && +	    priv->pcs != STMMAC_PCS_RTBI) +		stmmac_mdio_unregister(ndev);  	netif_carrier_off(ndev);  	unregister_netdev(ndev);  	free_netdev(ndev); @@ -2093,7 +2781,6 @@ int stmmac_dvr_remove(struct net_device *ndev)  int stmmac_suspend(struct net_device *ndev)  {  	struct stmmac_priv *priv = netdev_priv(ndev); -	int dis_ic = 0;  	unsigned long flags;  	if (!ndev || !netif_running(ndev)) @@ -2107,18 +2794,13 @@ int stmmac_suspend(struct net_device *ndev)  	netif_device_detach(ndev);  	netif_stop_queue(ndev); -	if (priv->use_riwt) -		dis_ic = 1; -  	napi_disable(&priv->napi);  	/* Stop TX/RX DMA */  	priv->hw->dma->stop_tx(priv->ioaddr);  	priv->hw->dma->stop_rx(priv->ioaddr); -	/* Clear the Rx/Tx descriptors */ -	priv->hw->desc->init_rx_desc(priv->dma_rx, priv->dma_rx_size, -				     dis_ic); -	priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size); + +	stmmac_clear_descriptors(priv);  	/* Enable Power down mode by programming the PMT regs */  	if (device_may_wakeup(priv->device)) @@ -2146,7 +2828,8 @@ int stmmac_resume(struct net_device *ndev)  	 * automatically as soon as a magic packet or a Wake-up frame  	 * is received. Anyway, it's better to manually clear  	 * this bit because it can generate problems while resuming -	 * from another devices (e.g. serial console). */ +	 * from another devices (e.g. serial console). +	 */  	if (device_may_wakeup(priv->device))  		priv->hw->mac->pmt(priv->ioaddr, 0);  	else @@ -2257,6 +2940,9 @@ static int __init stmmac_cmdline_opt(char *str)  		} else if (!strncmp(opt, "eee_timer:", 10)) {  			if (kstrtoint(opt + 10, 0, &eee_timer))  				goto err; +		} else if (!strncmp(opt, "chain_mode:", 11)) { +			if (kstrtoint(opt + 11, 0, &chain_mode)) +				goto err;  		}  	}  	return 0; @@ -2267,7 +2953,7 @@ err:  }  __setup("stmmaceth=", stmmac_cmdline_opt); -#endif +#endif /* MODULE */  MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet device driver");  MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");  |