Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH 1/3] net: stmmac: replace all pr_xxx by their netdev_xxx counterpart
From: Giuseppe CAVALLARO @ 2016-11-17 16:39 UTC (permalink / raw)
  To: Corentin Labbe, alexandre.torgue; +Cc: netdev, linux-kernel
In-Reply-To: <1479323381-26639-1-git-send-email-clabbe.montjoie@gmail.com>

On 11/16/2016 8:09 PM, Corentin Labbe wrote:
> From: LABBE Corentin <clabbe.montjoie@gmail.com>
>
> The stmmac driver use lots of pr_xxx functions to print information.
> This is bad since we cannot know which device logs the information.
> (moreover if two stmmac device are present)
>
> Furthermore, it seems that it assumes wrongly that all logs will always
> be subsequent by using a dev_xxx then some indented pr_xxx like this:
> kernel: sun7i-dwmac 1c50000.ethernet: no reset control found
> kernel:  Ring mode enabled
> kernel:  No HW DMA feature register supported
> kernel:  Normal descriptors
> kernel:  TX Checksum insertion supported
>
> So this patch replace all pr_xxx by their netdev_xxx counterpart.
> Excepts for some printing where netdev "cause" unpretty output like:
> sun7i-dwmac 1c50000.ethernet (unnamed net_device) (uninitialized): no reset control found
> In those case, I keep dev_xxx.
>
> In the same time I remove some "stmmac:" print since
> this will be a duplicate with that dev_xxx displays.
>
> Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>

Thanks for these changes.

Acked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>

> ---
>  drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 204 ++++++++++++----------
>  drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c |  14 +-
>  2 files changed, 123 insertions(+), 95 deletions(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 8eb12353..791daf4 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -305,7 +305,7 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
>  			 */
>  			spin_lock_irqsave(&priv->lock, flags);
>  			if (priv->eee_active) {
> -				pr_debug("stmmac: disable EEE\n");
> +				netdev_dbg(priv->dev, "disable EEE\n");
>  				del_timer_sync(&priv->eee_ctrl_timer);
>  				priv->hw->mac->set_eee_timer(priv->hw, 0,
>  							     tx_lpi_timer);
> @@ -334,7 +334,7 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
>  		ret = true;
>  		spin_unlock_irqrestore(&priv->lock, flags);
>
> -		pr_debug("stmmac: Energy-Efficient Ethernet initialized\n");
> +		netdev_dbg(priv->dev, "Energy-Efficient Ethernet initialized\n");
>  	}
>  out:
>  	return ret;
> @@ -456,8 +456,8 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
>  			   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);
> +	netdev_dbg(priv->dev, "%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)
> @@ -756,8 +756,9 @@ static void stmmac_adjust_link(struct net_device *dev)
>  				break;
>  			default:
>  				if (netif_msg_link(priv))
> -					pr_warn("%s: Speed (%d) not 10/100\n",
> -						dev->name, phydev->speed);
> +					netdev_warn(priv->dev,
> +						    "Speed (%d) not 10/100\n",
> +						    phydev->speed);
>  				break;
>  			}
>
> @@ -810,10 +811,10 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
>  		    (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");
> +			netdev_dbg(priv->dev, "PCS RGMII support enabled\n");
>  			priv->hw->pcs = STMMAC_PCS_RGMII;
>  		} else if (interface == PHY_INTERFACE_MODE_SGMII) {
> -			pr_debug("STMMAC: PCS SGMII support enable\n");
> +			netdev_dbg(priv->dev, "PCS SGMII support enabled\n");
>  			priv->hw->pcs = STMMAC_PCS_SGMII;
>  		}
>  	}
> @@ -848,15 +849,15 @@ static int stmmac_init_phy(struct net_device *dev)
>
>  		snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
>  			 priv->plat->phy_addr);
> -		pr_debug("stmmac_init_phy:  trying to attach to %s\n",
> -			 phy_id_fmt);
> +		netdev_dbg(priv->dev, "stmmac_init_phy: trying to attach to %s\n",
> +			   phy_id_fmt);
>
>  		phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link,
>  				     interface);
>  	}
>
>  	if (IS_ERR_OR_NULL(phydev)) {
> -		pr_err("%s: Could not attach to PHY\n", dev->name);
> +		netdev_err(priv->dev, "Could not attach to PHY\n");
>  		if (!phydev)
>  			return -ENODEV;
>
> @@ -889,8 +890,9 @@ static int stmmac_init_phy(struct net_device *dev)
>  	if (phydev->is_pseudo_fixed_link)
>  		phydev->irq = PHY_POLL;
>
> -	pr_debug("stmmac_init_phy:  %s: attached to PHY (UID 0x%x)"
> -		 " Link = %d\n", dev->name, phydev->phy_id, phydev->link);
> +	netdev_dbg(priv->dev,
> +		   "stmmac_init_phy: attached to PHY (UID 0x%x) Link = %d\n",
> +		   phydev->phy_id, phydev->link);
>
>  	return 0;
>  }
> @@ -976,7 +978,8 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
>
>  	skb = __netdev_alloc_skb_ip_align(priv->dev, priv->dma_buf_sz, flags);
>  	if (!skb) {
> -		pr_err("%s: Rx init fails; skb is NULL\n", __func__);
> +		netdev_err(priv->dev,
> +			   "%s: Rx init fails; skb is NULL\n", __func__);
>  		return -ENOMEM;
>  	}
>  	priv->rx_skbuff[i] = skb;
> @@ -984,7 +987,7 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
>  						priv->dma_buf_sz,
>  						DMA_FROM_DEVICE);
>  	if (dma_mapping_error(priv->device, priv->rx_skbuff_dma[i])) {
> -		pr_err("%s: DMA mapping error\n", __func__);
> +		netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);
>  		dev_kfree_skb_any(skb);
>  		return -EINVAL;
>  	}
> @@ -1035,11 +1038,12 @@ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
>  	priv->dma_buf_sz = bfsize;
>
>  	if (netif_msg_probe(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);
> +		netdev_dbg(priv->dev, "(%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 */
> -		pr_debug("\tSKB addresses:\nskb\t\tskb data\tdma data\n");
> +		netdev_dbg(priv->dev, "SKB addresses:\nskb\t\tskb data\tdma data\n");
>  	}
>  	for (i = 0; i < DMA_RX_SIZE; i++) {
>  		struct dma_desc *p;
> @@ -1053,7 +1057,8 @@ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
>  			goto err_init_rx_buffers;
>
>  		if (netif_msg_probe(priv))
> -			pr_debug("[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
> +			netdev_dbg(priv->dev, "[%p]\t[%p]\t[%x]\n",
> +				   priv->rx_skbuff[i],
>  				 priv->rx_skbuff[i]->data,
>  				 (unsigned int)priv->rx_skbuff_dma[i]);
>  	}
> @@ -1386,7 +1391,8 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
>  		if (netif_queue_stopped(priv->dev) &&
>  		    stmmac_tx_avail(priv) > STMMAC_TX_THRESH) {
>  			if (netif_msg_tx_done(priv))
> -				pr_debug("%s: restart transmit\n", __func__);
> +				netdev_dbg(priv->dev, "%s: restart transmit\n",
> +					   __func__);
>  			netif_wake_queue(priv->dev);
>  		}
>  		netif_tx_unlock(priv->dev);
> @@ -1497,7 +1503,7 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv)
>  		dwmac_mmc_ctrl(priv->mmcaddr, mode);
>  		memset(&priv->mmc, 0, sizeof(struct stmmac_counters));
>  	} else
> -		pr_info(" No MAC Management Counters available\n");
> +		netdev_info(priv->dev, "No MAC Management Counters available\n");
>  }
>
>  /**
> @@ -1510,18 +1516,18 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv)
>  static void stmmac_selec_desc_mode(struct stmmac_priv *priv)
>  {
>  	if (priv->plat->enh_desc) {
> -		pr_info(" Enhanced/Alternate descriptors\n");
> +		dev_info(priv->device, "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");
> +			dev_info(priv->device, "Enabled extended descriptors\n");
>  			priv->extend_desc = 1;
>  		} else
> -			pr_warn("Extended descriptors not supported\n");
> +			dev_warn(priv->device, "Extended descriptors not supported\n");
>
>  		priv->hw->desc = &enh_desc_ops;
>  	} else {
> -		pr_info(" Normal descriptors\n");
> +		dev_info(priv->device, "Normal descriptors\n");
>  		priv->hw->desc = &ndesc_ops;
>  	}
>  }
> @@ -1562,8 +1568,8 @@ static void stmmac_check_ether_addr(struct stmmac_priv *priv)
>  					     priv->dev->dev_addr, 0);
>  		if (!is_valid_ether_addr(priv->dev->dev_addr))
>  			eth_hw_addr_random(priv->dev);
> -		pr_info("%s: device MAC address %pM\n", priv->dev->name,
> -			priv->dev->dev_addr);
> +		netdev_info(priv->dev, "device MAC address %pM\n",
> +			    priv->dev->dev_addr);
>  	}
>  }
>
> @@ -1671,7 +1677,8 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
>  	/* DMA initialization and SW reset */
>  	ret = stmmac_init_dma_engine(priv);
>  	if (ret < 0) {
> -		pr_err("%s: DMA engine initialization failed\n", __func__);
> +		netdev_err(priv->dev, "%s: DMA engine initialization failed\n",
> +			   __func__);
>  		return ret;
>  	}
>
> @@ -1700,7 +1707,7 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
>
>  	ret = priv->hw->mac->rx_ipc(priv->hw);
>  	if (!ret) {
> -		pr_warn(" RX IPC Checksum Offload disabled\n");
> +		netdev_warn(priv->dev, "RX IPC Checksum Offload disabled\n");
>  		priv->plat->rx_coe = STMMAC_RX_COE_NONE;
>  		priv->hw->rx_csum = 0;
>  	}
> @@ -1725,10 +1732,11 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
>  #ifdef CONFIG_DEBUG_FS
>  	ret = stmmac_init_fs(dev);
>  	if (ret < 0)
> -		pr_warn("%s: failed debugFS registration\n", __func__);
> +		netdev_warn(priv->dev, "%s: failed debugFS registration\n",
> +			    __func__);
>  #endif
>  	/* Start the ball rolling... */
> -	pr_debug("%s: DMA RX/TX processes started...\n", dev->name);
> +	netdev_dbg(priv->dev, "DMA RX/TX processes started...\n");
>  	priv->hw->dma->start_tx(priv->ioaddr);
>  	priv->hw->dma->start_rx(priv->ioaddr);
>
> @@ -1783,8 +1791,9 @@ static int stmmac_open(struct net_device *dev)
>  	    priv->hw->pcs != STMMAC_PCS_RTBI) {
>  		ret = stmmac_init_phy(dev);
>  		if (ret) {
> -			pr_err("%s: Cannot attach to PHY (error: %d)\n",
> -			       __func__, ret);
> +			netdev_err(priv->dev,
> +				   "%s: Cannot attach to PHY (error: %d)\n",
> +				   __func__, ret);
>  			return ret;
>  		}
>  	}
> @@ -1798,19 +1807,21 @@ static int stmmac_open(struct net_device *dev)
>
>  	ret = alloc_dma_desc_resources(priv);
>  	if (ret < 0) {
> -		pr_err("%s: DMA descriptors allocation failed\n", __func__);
> +		netdev_err(priv->dev, "%s: DMA descriptors allocation failed\n",
> +			   __func__);
>  		goto dma_desc_error;
>  	}
>
>  	ret = init_dma_desc_rings(dev, GFP_KERNEL);
>  	if (ret < 0) {
> -		pr_err("%s: DMA descriptors initialization failed\n", __func__);
> +		netdev_err(priv->dev, "%s: DMA descriptors initialization failed\n",
> +			   __func__);
>  		goto init_error;
>  	}
>
>  	ret = stmmac_hw_setup(dev, true);
>  	if (ret < 0) {
> -		pr_err("%s: Hw setup failed\n", __func__);
> +		netdev_err(priv->dev, "%s: Hw setup failed\n", __func__);
>  		goto init_error;
>  	}
>
> @@ -1823,8 +1834,9 @@ static int stmmac_open(struct net_device *dev)
>  	ret = request_irq(dev->irq, stmmac_interrupt,
>  			  IRQF_SHARED, dev->name, dev);
>  	if (unlikely(ret < 0)) {
> -		pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n",
> -		       __func__, dev->irq, ret);
> +		netdev_err(priv->dev,
> +			   "%s: ERROR: allocating the IRQ %d (error: %d)\n",
> +			   __func__, dev->irq, ret);
>  		goto init_error;
>  	}
>
> @@ -1833,8 +1845,9 @@ 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 WoL IRQ %d (%d)\n",
> -			       __func__, priv->wol_irq, ret);
> +			netdev_err(priv->dev,
> +				   "%s: ERROR: allocating the WoL IRQ %d (%d)\n",
> +				   __func__, priv->wol_irq, ret);
>  			goto wolirq_error;
>  		}
>  	}
> @@ -1844,8 +1857,9 @@ static int stmmac_open(struct net_device *dev)
>  		ret = request_irq(priv->lpi_irq, stmmac_interrupt, IRQF_SHARED,
>  				  dev->name, dev);
>  		if (unlikely(ret < 0)) {
> -			pr_err("%s: ERROR: allocating the LPI IRQ %d (%d)\n",
> -			       __func__, priv->lpi_irq, ret);
> +			netdev_err(priv->dev,
> +				   "%s: ERROR: allocating the LPI IRQ %d (%d)\n",
> +				   __func__, priv->lpi_irq, ret);
>  			goto lpiirq_error;
>  		}
>  	}
> @@ -2008,7 +2022,9 @@ static netdev_tx_t stmmac_tso_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: Tx Ring full when queue awake\n", __func__);
> +			netdev_err(priv->dev,
> +				   "%s: Tx Ring full when queue awake\n",
> +				   __func__);
>  		}
>  		spin_unlock(&priv->tx_lock);
>  		return NETDEV_TX_BUSY;
> @@ -2082,7 +2098,8 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
>
>  	if (unlikely(stmmac_tx_avail(priv) <= (MAX_SKB_FRAGS + 1))) {
>  		if (netif_msg_hw(priv))
> -			pr_debug("%s: stop transmitted packets\n", __func__);
> +			netdev_dbg(priv->dev, "%s: stop transmitted packets\n",
> +				   __func__);
>  		netif_stop_queue(dev);
>  	}
>
> @@ -2188,7 +2205,9 @@ 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: Tx Ring full when queue awake\n", __func__);
> +			netdev_err(priv->dev,
> +				   "%s: Tx Ring full when queue awake\n",
> +				   __func__);
>  		}
>  		return NETDEV_TX_BUSY;
>  	}
> @@ -2263,9 +2282,10 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
>  	if (netif_msg_pktdata(priv)) {
>  		void *tx_head;
>
> -		pr_debug("%s: curr=%d dirty=%d f=%d, e=%d, first=%p, nfrags=%d",
> -			 __func__, priv->cur_tx, priv->dirty_tx, first_entry,
> -			 entry, first, nfrags);
> +		netdev_dbg(priv->dev,
> +			   "%s: curr=%d dirty=%d f=%d, e=%d, first=%p, nfrags=%d",
> +			   __func__, priv->cur_tx, priv->dirty_tx, first_entry,
> +			   entry, first, nfrags);
>
>  		if (priv->extend_desc)
>  			tx_head = (void *)priv->dma_etx;
> @@ -2274,13 +2294,14 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
>
>  		priv->hw->desc->display_ring(tx_head, DMA_TX_SIZE, false);
>
> -		pr_debug(">>> frame to be transmitted: ");
> +		netdev_dbg(priv->dev, ">>> frame to be transmitted: ");
>  		print_pkt(skb->data, skb->len);
>  	}
>
>  	if (unlikely(stmmac_tx_avail(priv) <= (MAX_SKB_FRAGS + 1))) {
>  		if (netif_msg_hw(priv))
> -			pr_debug("%s: stop transmitted packets\n", __func__);
> +			netdev_dbg(priv->dev,
> +				   "%s: stop transmitted packets\n", __func__);
>  		netif_stop_queue(dev);
>  	}
>
> @@ -2357,7 +2378,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
>
>  dma_map_err:
>  	spin_unlock(&priv->tx_lock);
> -	dev_err(priv->device, "Tx dma map failed\n");
> +	netdev_err(priv->dev, "Tx DMA map failed\n");
>  	dev_kfree_skb(skb);
>  	priv->dev->stats.tx_dropped++;
>  	return NETDEV_TX_OK;
> @@ -2428,7 +2449,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
>  					   DMA_FROM_DEVICE);
>  			if (dma_mapping_error(priv->device,
>  					      priv->rx_skbuff_dma[entry])) {
> -				dev_err(priv->device, "Rx dma map failed\n");
> +				netdev_err(priv->dev, "Rx DMA map failed\n");
>  				dev_kfree_skb(skb);
>  				break;
>  			}
> @@ -2446,7 +2467,8 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
>  				priv->rx_zeroc_thresh--;
>
>  			if (netif_msg_rx_status(priv))
> -				pr_debug("\trefill entry #%d\n", entry);
> +				netdev_dbg(priv->dev,
> +					   "refill entry #%d\n", entry);
>  		}
>  		wmb();
>
> @@ -2479,7 +2501,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
>  	if (netif_msg_rx_status(priv)) {
>  		void *rx_head;
>
> -		pr_debug("%s: descriptor ring:\n", __func__);
> +		netdev_dbg(priv->dev, "%s: descriptor ring:\n", __func__);
>  		if (priv->extend_desc)
>  			rx_head = (void *)priv->dma_erx;
>  		else
> @@ -2549,9 +2571,9 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
>  			 *  ignored
>  			 */
>  			if (frame_len > priv->dma_buf_sz) {
> -				pr_err("%s: len %d larger than size (%d)\n",
> -				       priv->dev->name, frame_len,
> -				       priv->dma_buf_sz);
> +				netdev_err(priv->dev,
> +					   "len %d larger than size (%d)\n",
> +					   frame_len, priv->dma_buf_sz);
>  				priv->dev->stats.rx_length_errors++;
>  				break;
>  			}
> @@ -2563,11 +2585,11 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
>  				frame_len -= ETH_FCS_LEN;
>
>  			if (netif_msg_rx_status(priv)) {
> -				pr_debug("\tdesc: %p [entry %d] buff=0x%x\n",
> -					p, entry, des);
> +				netdev_dbg(priv->dev, "\tdesc: %p [entry %d] buff=0x%x\n",
> +					   p, entry, des);
>  				if (frame_len > ETH_FRAME_LEN)
> -					pr_debug("\tframe size %d, COE: %d\n",
> -						 frame_len, status);
> +					netdev_dbg(priv->dev, "frame size %d, COE: %d\n",
> +						   frame_len, status);
>  			}
>
>  			/* The zero-copy is always used for all the sizes
> @@ -2604,8 +2626,9 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
>  			} else {
>  				skb = priv->rx_skbuff[entry];
>  				if (unlikely(!skb)) {
> -					pr_err("%s: Inconsistent Rx chain\n",
> -					       priv->dev->name);
> +					netdev_err(priv->dev,
> +						   "%s: Inconsistent Rx chain\n",
> +						   priv->dev->name);
>  					priv->dev->stats.rx_dropped++;
>  					break;
>  				}
> @@ -2623,7 +2646,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
>  			stmmac_get_rx_hwtstamp(priv, entry, skb);
>
>  			if (netif_msg_pktdata(priv)) {
> -				pr_debug("frame received (%dbytes)", frame_len);
> +				netdev_dbg(priv->dev, "frame received (%dbytes)",
> +					   frame_len);
>  				print_pkt(skb->data, frame_len);
>  			}
>
> @@ -2720,8 +2744,10 @@ static void stmmac_set_rx_mode(struct net_device *dev)
>   */
>  static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
>  {
> +	struct stmmac_priv *priv = netdev_priv(dev);
> +
>  	if (netif_running(dev)) {
> -		pr_err("%s: must be stopped to change its MTU\n", dev->name);
> +		netdev_err(priv->dev, "must be stopped to change its MTU\n");
>  		return -EBUSY;
>  	}
>
> @@ -2800,7 +2826,7 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
>  		pm_wakeup_event(priv->device, 0);
>
>  	if (unlikely(!dev)) {
> -		pr_err("%s: invalid dev pointer\n", __func__);
> +		netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__);
>  		return IRQ_NONE;
>  	}
>
> @@ -3032,8 +3058,7 @@ static int stmmac_init_fs(struct net_device *dev)
>  	priv->dbgfs_dir = debugfs_create_dir(dev->name, stmmac_fs_dir);
>
>  	if (!priv->dbgfs_dir || IS_ERR(priv->dbgfs_dir)) {
> -		pr_err("ERROR %s/%s, debugfs create directory failed\n",
> -		       STMMAC_RESOURCE_NAME, dev->name);
> +		netdev_err(priv->dev, "ERROR failed to create debugfs directory\n");
>
>  		return -ENOMEM;
>  	}
> @@ -3045,7 +3070,7 @@ static int stmmac_init_fs(struct net_device *dev)
>  				    &stmmac_rings_status_fops);
>
>  	if (!priv->dbgfs_rings_status || IS_ERR(priv->dbgfs_rings_status)) {
> -		pr_info("ERROR creating stmmac ring debugfs file\n");
> +		netdev_err(priv->dev, "ERROR creating stmmac ring debugfs file\n");
>  		debugfs_remove_recursive(priv->dbgfs_dir);
>
>  		return -ENOMEM;
> @@ -3057,7 +3082,7 @@ static int stmmac_init_fs(struct net_device *dev)
>  					    dev, &stmmac_dma_cap_fops);
>
>  	if (!priv->dbgfs_dma_cap || IS_ERR(priv->dbgfs_dma_cap)) {
> -		pr_info("ERROR creating stmmac MMC debugfs file\n");
> +		netdev_err(priv->dev, "ERROR creating stmmac MMC debugfs file\n");
>  		debugfs_remove_recursive(priv->dbgfs_dir);
>
>  		return -ENOMEM;
> @@ -3129,11 +3154,11 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
>  	} else {
>  		if (chain_mode) {
>  			priv->hw->mode = &chain_mode_ops;
> -			pr_info(" Chain mode enabled\n");
> +			dev_info(priv->device, "Chain mode enabled\n");
>  			priv->mode = STMMAC_CHAIN_MODE;
>  		} else {
>  			priv->hw->mode = &ring_mode_ops;
> -			pr_info(" Ring mode enabled\n");
> +			dev_info(priv->device, "Ring mode enabled\n");
>  			priv->mode = STMMAC_RING_MODE;
>  		}
>  	}
> @@ -3141,7 +3166,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
>  	/* Get the HW capability (new GMAC newer than 3.50a) */
>  	priv->hw_cap_support = stmmac_get_hw_features(priv);
>  	if (priv->hw_cap_support) {
> -		pr_info(" DMA HW capability register supported");
> +		dev_info(priv->device, "DMA HW capability register supported\n");
>
>  		/* We can override some gmac/dma configuration fields: e.g.
>  		 * enh_desc, tx_coe (e.g. that are passed through the
> @@ -3166,8 +3191,9 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
>  		else if (priv->dma_cap.rx_coe_type1)
>  			priv->plat->rx_coe = STMMAC_RX_COE_TYPE1;
>
> -	} else
> -		pr_info(" No HW DMA feature register supported");
> +	} else {
> +		dev_info(priv->device, "No HW DMA feature register supported\n");
> +	}
>
>  	/* To use alternate (extended), normal or GMAC4 descriptor structures */
>  	if (priv->synopsys_id >= DWMAC_CORE_4_00)
> @@ -3177,20 +3203,20 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
>
>  	if (priv->plat->rx_coe) {
>  		priv->hw->rx_csum = priv->plat->rx_coe;
> -		pr_info(" RX Checksum Offload Engine supported\n");
> +		dev_info(priv->device, "RX Checksum Offload Engine supported\n");
>  		if (priv->synopsys_id < DWMAC_CORE_4_00)
> -			pr_info("\tCOE Type %d\n", priv->hw->rx_csum);
> +			dev_info(priv->device, "COE Type %d\n", priv->hw->rx_csum);
>  	}
>  	if (priv->plat->tx_coe)
> -		pr_info(" TX Checksum insertion supported\n");
> +		dev_info(priv->device, "TX Checksum insertion supported\n");
>
>  	if (priv->plat->pmt) {
> -		pr_info(" Wake-Up On Lan supported\n");
> +		dev_info(priv->device, "Wake-Up On Lan supported\n");
>  		device_set_wakeup_capable(priv->device, 1);
>  	}
>
>  	if (priv->dma_cap.tsoen)
> -		pr_info(" TSO supported\n");
> +		dev_info(priv->device, "TSO supported\n");
>
>  	return 0;
>  }
> @@ -3249,8 +3275,8 @@ int stmmac_dvr_probe(struct device *device,
>
>  	priv->stmmac_clk = devm_clk_get(priv->device, STMMAC_RESOURCE_NAME);
>  	if (IS_ERR(priv->stmmac_clk)) {
> -		dev_warn(priv->device, "%s: warning: cannot get CSR clock\n",
> -			 __func__);
> +		netdev_warn(priv->dev, "%s: warning: cannot get CSR clock\n",
> +			    __func__);
>  		/* If failed to obtain stmmac_clk and specific clk_csr value
>  		 * is NOT passed from the platform, probe fail.
>  		 */
> @@ -3299,7 +3325,7 @@ int stmmac_dvr_probe(struct device *device,
>  	if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) {
>  		ndev->hw_features |= NETIF_F_TSO;
>  		priv->tso = true;
> -		pr_info(" TSO feature enabled\n");
> +		dev_info(priv->device, "TSO feature enabled\n");
>  	}
>  	ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA;
>  	ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
> @@ -3328,7 +3354,7 @@ int stmmac_dvr_probe(struct device *device,
>  	 */
>  	if ((priv->synopsys_id >= DWMAC_CORE_3_50) && (!priv->plat->riwt_off)) {
>  		priv->use_riwt = 1;
> -		pr_info(" Enable RX Mitigation via HW Watchdog Timer\n");
> +		netdev_info(priv->dev, "Enable RX Mitigation via HW Watchdog Timer\n");
>  	}
>
>  	netif_napi_add(ndev, &priv->napi, stmmac_poll, 64);
> @@ -3338,7 +3364,8 @@ int stmmac_dvr_probe(struct device *device,
>
>  	ret = register_netdev(ndev);
>  	if (ret) {
> -		pr_err("%s: ERROR %i registering the device\n", __func__, ret);
> +		netdev_err(priv->dev, "%s: ERROR %i registering the device\n",
> +			   __func__, ret);
>  		goto error_netdev_register;
>  	}
>
> @@ -3361,8 +3388,9 @@ int stmmac_dvr_probe(struct device *device,
>  		/* 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);
> +			netdev_err(priv->dev,
> +				   "%s: MDIO bus (id: %d) registration failed",
> +				   __func__, priv->plat->bus_id);
>  			goto error_mdio_register;
>  		}
>  	}
> @@ -3395,7 +3423,7 @@ int stmmac_dvr_remove(struct device *dev)
>  	struct net_device *ndev = dev_get_drvdata(dev);
>  	struct stmmac_priv *priv = netdev_priv(ndev);
>
> -	pr_info("%s:\n\tremoving driver", __func__);
> +	netdev_info(priv->dev, "%s: removing driver", __func__);
>
>  	priv->hw->dma->stop_rx(priv->ioaddr);
>  	priv->hw->dma->stop_tx(priv->ioaddr);
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
> index ec29585..e3216e5 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
> @@ -260,7 +260,7 @@ int stmmac_mdio_reset(struct mii_bus *bus)
>  #endif
>
>  	if (data->phy_reset) {
> -		pr_debug("stmmac_mdio_reset: calling phy_reset\n");
> +		netdev_dbg(ndev, "stmmac_mdio_reset: calling phy_reset\n");
>  		data->phy_reset(priv->plat->bsp_priv);
>  	}
>
> @@ -325,7 +325,7 @@ int stmmac_mdio_register(struct net_device *ndev)
>  	else
>  		err = mdiobus_register(new_bus);
>  	if (err != 0) {
> -		pr_err("%s: Cannot register as MDIO bus\n", new_bus->name);
> +		netdev_err(ndev, "Cannot register the MDIO bus\n");
>  		goto bus_register_fail;
>  	}
>
> @@ -372,16 +372,16 @@ int stmmac_mdio_register(struct net_device *ndev)
>  				irq_str = irq_num;
>  				break;
>  			}
> -			pr_info("%s: PHY ID %08x at %d IRQ %s (%s)%s\n",
> -				ndev->name, phydev->phy_id, addr,
> -				irq_str, phydev_name(phydev),
> -				act ? " active" : "");
> +			netdev_info(ndev, "PHY ID %08x at %d IRQ %s (%s)%s\n",
> +				    phydev->phy_id, addr,
> +				    irq_str, phydev_name(phydev),
> +				    act ? " active" : "");
>  			found = 1;
>  		}
>  	}
>
>  	if (!found && !mdio_node) {
> -		pr_warn("%s: No PHY found\n", ndev->name);
> +		netdev_warn(ndev, "No PHY found\n");
>  		mdiobus_unregister(new_bus);
>  		mdiobus_free(new_bus);
>  		return -ENODEV;
>

^ permalink raw reply

* Re: [PATCH net-next 1/5] net: stmmac: Implement ethtool::nway_reset
From: Giuseppe CAVALLARO @ 2016-11-17 16:38 UTC (permalink / raw)
  To: Florian Fainelli, netdev
  Cc: davem, andrew, tremyfr, Alexandre Torgue, open list
In-Reply-To: <20161115191949.15361-2-f.fainelli@gmail.com>

On 11/15/2016 8:19 PM, Florian Fainelli wrote:
> Utilize the generic phy_ethtool_nway_reset() helper function to
> implement an autonegotiation restart.
>
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>

Acked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>

> ---
>  drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
> index 3fe9340b748f..0290d52330da 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
> @@ -870,6 +870,7 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
>  	.get_regs = stmmac_ethtool_gregs,
>  	.get_regs_len = stmmac_ethtool_get_regs_len,
>  	.get_link = ethtool_op_get_link,
> +	.nway_reset = phy_ethtool_nway_reset,
>  	.get_pauseparam = stmmac_get_pauseparam,
>  	.set_pauseparam = stmmac_set_pauseparam,
>  	.get_ethtool_stats = stmmac_get_ethtool_stats,
>

^ permalink raw reply

* Re: [PATCH net 1/2] r8152: fix the sw rx checksum is unavailable
From: Mark Lord @ 2016-11-17 14:14 UTC (permalink / raw)
  To: Hayes Wang, netdev@vger.kernel.org
  Cc: nic_swsd, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org
In-Reply-To: <0835B3720019904CB8F7AA43166CEEB20105013E@RTITMBSV03.realtek.com.tw>

(resending.. not sure if the original had mailer errors)

On 16-11-16 10:36 PM, Hayes Wang wrote:
 > [...]
 >> Fix the hw rx checksum is always enabled, and the user couldn't switch
 >> it to sw rx checksum.
 >>
 >> Note that the RTL_VER_01 only supports sw rx checksum only. Besides,
 >> the hw rx checksum for RTL_VER_02 is disabled after
 >> commit b9a321b48af4 ("r8152: Fix broken RX checksums."). Re-enable it.
 >
 > Excuse me. If I want to re-send this one patch, should I let
 > RTL_VER_02 use rx hw checksum?

Definitely NOT.

I am still doing low-level tracing through the driver as time permits,
and just now found some really interesting evidence.

Using coherent buffers (non-cacheable, allocated with usb_alloc_coherent),
I can get it to fail extremely regularly by simply reducing the buffer size
(agg_buf_sz) from 16KB down to 4KB.   This makes reproducing the issue
much much easier -- the same problems do happen with the larger 16KB size,
but much less often than with smaller sizes.

So.. with a 4KB URB transfer_buffer size, along with a ton of added error-checking,
I see this behaviour every 10 (rx) URBs or so:

First URB (number 593):
[   34.260667] r8152_rx_bottom: 593 corrupted urb: head=bf014000 urb_offset=2856/4096 pkt_len(1518) exceeds remainder(1216)
[   34.271931] r8152_dump_rx_desc: 044805ee 40080000 006005dc 06020000 00000000 00000000 rx_len=1518

Next URB (number 594):
[   34.281172] r8152_check_rx_desc: rx_desc looks bad.
[   34.286228] r8152_rx_bottom: 594 corrupted urb. head=bf018000 urb_offset=0/304 len_used=24
[   34.294774] r8152_dump_rx_desc: 00008300 00008400 00008500 00008600 00008700 00008800 rx_len=768

What the above sample shows, is the URB transfer buffer ran out of space in the middle
of a packet, and the hardware then tried to just continue that same packet in the next URB,
without an rx_desc header inserted.  The r8152.c driver always assumes the URB buffer begins
with an rx_desc, so of course this behaviour produces really weird effects, and system crashes, etc..

So until that driver bug is addressed, I would advise disabling hardware RX checksums
for all chip versions, not only for version 02.

It is not clear to me how the chip decides when to forward an rx URB to the host.
If you could describe how that part works for us, then it would help in further
understanding why fast systems (eg. a PC) don't generally notice the issue,
while much slower embedded systems do see the issue regularly.

Thanks
Mark

^ permalink raw reply

* Re: [RFC PATCH 2/2] net: macb: Add 64 bit addressing support for GEM
From: Nicolas Ferre @ 2016-11-17 13:28 UTC (permalink / raw)
  To: Harini Katakam, Rafal Ozieblo
  Cc: harini.katakam@xilinx.com, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <CAFcVECJ-ZYjGg-3CbWD2Ka8yKzOokUxS8ZHHOJXa2Z6anuTr7Q@mail.gmail.com>

Le 17/11/2016 à 13:21, Harini Katakam a écrit :
> Hi Rafal,
> 
> On Thu, Nov 17, 2016 at 5:20 PM, Rafal Ozieblo <rafalo@cadence.com> wrote:
>> Hello,
>> I think, there could a bug in your patch.
>>
>>> +
>>> +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
>>> +             dmacfg |= GEM_BIT(ADDR64);
>>> +#endif
>>
>> You enable 64 bit addressing (64b dma bus width) always when appropriate architecture config option is enabled.
>> But there are some legacy controllers which do not support that feature. According Cadence hardware team:
>> "64 bit addressing was added in July 2013. Earlier version do not have it.
>> This feature was enhanced in release August 2014 to have separate upper address values for transmit and receive."
>>
>>> /* Bitfields in NSR */
>>> @@ -474,6 +479,10 @@
>>>  struct macb_dma_desc {
>>  >      u32     addr;
>>>       u32     ctrl;
>>> +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
>>> +     u32     addrh;
>>> +     u32     resvd;
>>> +#endif
>>>  };
>>
>> It will not work for legacy hardware. Old descriptor is 2 words wide, the new one is 4 words wide.
>> If you enable CONFIG_ARCH_DMA_ADDR_T_64BIT but hardware doesn't support it at all,
>> you will miss every second descriptor.
>>
> 
> True, this feature is not available in all of Cadence IP versions.
> In fact, the IP version Zynq does not support this. But the one in ZynqMP does.
> So, we enable kernel config for 64 bit DMA addressing for this SoC and hence
> the driver picks it up. My assumption was that if the legacy IP does not support
> 64 bit addressing, then this DMA option wouldn't be enabled.
> 
> There is a design config register in Cadence IP which is being read to
> check for 64 bit address support - DMA mask is set based on that.
> But the addition of two descriptor words cannot be based on this runtime check.
> For this reason, all the static changes were placed under this check.

We have quite a bunch of options in this driver to determinate what is
the real capacity of the underlying hardware.
If HW configuration registers are not appropriate, and it seems they are
not, I would advice to simply use the DT compatibility string.

Best regards,
-- 
Nicolas Ferre

^ permalink raw reply

* Re: [PATCH net 1/2] r8152: fix the sw rx checksum is unavailable
From: Mark Lord @ 2016-11-17 14:25 UTC (permalink / raw)
  To: Hayes Wang, netdev@vger.kernel.org
  Cc: nic_swsd, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org,
	David Miller
In-Reply-To: <a4a43da6-54e0-a9c8-8802-acb4e6c4a2c8@pobox.com>

On 16-11-17 09:14 AM, Mark Lord wrote:
..
> Using coherent buffers (non-cacheable, allocated with usb_alloc_coherent),

Note that the same behaviour also happens with the original kmalloc'd buffers.

> I can get it to fail extremely regularly by simply reducing the buffer size
> (agg_buf_sz) from 16KB down to 4KB.   This makes reproducing the issue
> much much easier -- the same problems do happen with the larger 16KB size,
> but much less often than with smaller sizes.

Increasing the buffer size to 64KB makes the problem much less frequent,
as one might expect.  Thus far I haven't seen it happen at all, but a longer
run (1-3 days) is needed to make sure.  This however is NOT a "fix".

> So.. with a 4KB URB transfer_buffer size, along with a ton of added error-checking,
> I see this behaviour every 10 (rx) URBs or so:
>
> First URB (number 593):
> [   34.260667] r8152_rx_bottom: 593 corrupted urb: head=bf014000 urb_offset=2856/4096 pkt_len(1518) exceeds remainder(1216)
> [   34.271931] r8152_dump_rx_desc: 044805ee 40080000 006005dc 06020000 00000000 00000000 rx_len=1518
>
> Next URB (number 594):
> [   34.281172] r8152_check_rx_desc: rx_desc looks bad.
> [   34.286228] r8152_rx_bottom: 594 corrupted urb. head=bf018000 urb_offset=0/304 len_used=24
> [   34.294774] r8152_dump_rx_desc: 00008300 00008400 00008500 00008600 00008700 00008800 rx_len=768
>
> What the above sample shows, is the URB transfer buffer ran out of space in the middle
> of a packet, and the hardware then tried to just continue that same packet in the next URB,
> without an rx_desc header inserted.  The r8152.c driver always assumes the URB buffer begins
> with an rx_desc, so of course this behaviour produces really weird effects, and system crashes, etc..
>
> So until that driver bug is addressed, I would advise disabling hardware RX checksums
> for all chip versions, not only for version 02.
>
> It is not clear to me how the chip decides when to forward an rx URB to the host.
> If you could describe how that part works for us, then it would help in further
> understanding why fast systems (eg. a PC) don't generally notice the issue,
> while much slower embedded systems do see the issue regularly.

That last part is critical to understanding things:
How does the chip decide that a URB is "full enough" before sending it to the host?
Why does a really fast host see fewer packets jammed together into a single URB than a slower host?

The answers will help understand if there are more bugs to be found/fixed,
or if everything is explained by what has been observed thus far.

To recap:  the hardware sometimes fills a URB to the very end, and then continues the
current packet at the first byte of the following URB.  The r8152.c driver does NOT
handle this situation; instead it always interprets the first 24 bytes of every URB
as an "rx_desc" structure, without any kind of sanity/validation.  This results in
buffer overruns (it trusts the packet length field, even though the URB is too small
to hold such a packet), and other semi-random behaviour.

Using software rx checksums prevents Bad Things(tm) happening from most of this,
but even that is not perfect given the severity of the bug.

Cheers

^ permalink raw reply

* Re: [Intel-wired-lan] [PATCH v2] e1000e: free IRQ regardless of __E1000_DOWN
From: Neftin, Sasha @ 2016-11-17 13:31 UTC (permalink / raw)
  To: Baicar, Tyler, jeffrey.t.kirsher, intel-wired-lan, netdev,
	linux-kernel, okaya, timur
In-Reply-To: <3914adae-91b2-7b74-02bc-579b3e32d143@intel.com>

On 11/13/2016 10:34 AM, Neftin, Sasha wrote:
> On 11/11/2016 12:35 AM, Baicar, Tyler wrote:
>> Hello Sasha,
>>
>> On 11/9/2016 11:19 PM, Neftin, Sasha wrote:
>>> On 11/9/2016 11:41 PM, Tyler Baicar wrote:
>>>> Move IRQ free code so that it will happen regardless of the
>>>> __E1000_DOWN bit. Currently the e1000e driver only releases its IRQ
>>>> if the __E1000_DOWN bit is cleared. This is not sufficient because
>>>> it is possible for __E1000_DOWN to be set without releasing the IRQ.
>>>> In such a situation, we will hit a kernel bug later in e1000_remove
>>>> because the IRQ still has action since it was never freed. A
>>>> secondary bus reset can cause this case to happen.
>>>>
>>>> Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
>>>> ---
>>>>   drivers/net/ethernet/intel/e1000e/netdev.c | 3 ++-
>>>>   1 file changed, 2 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c
>>>> b/drivers/net/ethernet/intel/e1000e/netdev.c
>>>> index 7017281..36cfcb0 100644
>>>> --- a/drivers/net/ethernet/intel/e1000e/netdev.c
>>>> +++ b/drivers/net/ethernet/intel/e1000e/netdev.c
>>>> @@ -4679,12 +4679,13 @@ int e1000e_close(struct net_device *netdev)
>>>>         if (!test_bit(__E1000_DOWN, &adapter->state)) {
>>>>           e1000e_down(adapter, true);
>>>> -        e1000_free_irq(adapter);
>>>>             /* Link status message must follow this format */
>>>>           pr_info("%s NIC Link is Down\n", adapter->netdev->name);
>>>>       }               
>>>>   +    e1000_free_irq(adapter);
>>>> +
>>>>       napi_disable(&adapter->napi);
>>>>         e1000e_free_tx_resources(adapter->tx_ring);
>>>>
>>> I would like not recommend insert this change. This change related
>>> driver state machine, we afraid from lot of synchronization problem and
>>> issues.
>>> We need keep e1000_free_irq in loop and check for 'test_bit' ready.
>>
>> What do you mean here? There is no loop. If __E1000_DOWN is set then we
>> will never free the IRQ.
>>
>>> Another point, does before execute secondary bus reset your SW back up
>>> pcie configuration space as properly?
>>
>> After a secondary bus reset, the link needs to recover and go back to a
>> working state after 1 second.
>>
>> From the callstack, the issue is happening while removing the endpoint
>> from the system, before applying the secondary bus reset.
>>
>> The order of events is
>> 1. remove the drivers
>> 2. cause a secondary bus reset
>> 3. wait 1 second
> Actually, this is too much, usually link up in less than 100ms.You can
> check Data Link Layer indication.
>> 4. recover the link
>>
>> callstack:
>> free_msi_irqs+0x6c/0x1a8
>> pci_disable_msi+0xb0/0x148
>> e1000e_reset_interrupt_capability+0x60/0x78
>> e1000_remove+0xc8/0x180
>> pci_device_remove+0x48/0x118
>> __device_release_driver+0x80/0x108
>> device_release_driver+0x2c/0x40
>> pci_stop_bus_device+0xa0/0xb0
>> pci_stop_bus_device+0x3c/0xb0
>> pci_stop_root_bus+0x54/0x80
>> acpi_pci_root_remove+0x28/0x64
>> acpi_bus_trim+0x6c/0xa4
>> acpi_device_hotplug+0x19c/0x3f4
>> acpi_hotplug_work_fn+0x28/0x3c
>> process_one_work+0x150/0x460
>> worker_thread+0x50/0x4b8
>> kthread+0xd4/0xe8
>> ret_from_fork+0x10/0x50
>>
>> Thanks,
>> Tyler
>>
> Hello Tyler,
> Okay, we need consult more about this suggestion.
> May I ask what is setup you run? Is there NIC or on board LAN? I would
> like try reproduce this issue in our lab's too.
> Also, is same issue observed with same scenario and others NIC's too?
> Sasha
> _______________________________________________
> Intel-wired-lan mailing list
> Intel-wired-lan@lists.osuosl.org
> http://lists.osuosl.org/mailman/listinfo/intel-wired-lan
> 
Hello Tyler,
I see some in consistent implementation of __*_close methods in our
drivers. Do you have any igb NIC to check if same problem persist there?
Thanks,
Sasha

^ permalink raw reply

* RE: [RFC PATCH 2/2] net: macb: Add 64 bit addressing support for GEM
From: Rafal Ozieblo @ 2016-11-17 12:57 UTC (permalink / raw)
  To: Harini Katakam
  Cc: harini.katakam@xilinx.com, nicolas.ferre@atmel.com,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <CAFcVECJ-ZYjGg-3CbWD2Ka8yKzOokUxS8ZHHOJXa2Z6anuTr7Q@mail.gmail.com>

-----Original Message-----
From: Harini Katakam [mailto:harinikatakamlinux@gmail.com] 
Sent: 17 listopada 2016 13:22
To: Rafal Ozieblo
Cc: harini.katakam@xilinx.com; nicolas.ferre@atmel.com; netdev@vger.kernel.org; linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH 2/2] net: macb: Add 64 bit addressing support for GEM

> Hi Rafal,
>
> On Thu, Nov 17, 2016 at 5:20 PM, Rafal Ozieblo <rafalo@cadence.com> wrote:
> > Hello,
> > I think, there could a bug in your patch.
> >
> >> +
> >> +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
> >> +             dmacfg |= GEM_BIT(ADDR64); #endif
> >
> > You enable 64 bit addressing (64b dma bus width) always when appropriate architecture config option is enabled.
> > But there are some legacy controllers which do not support that feature. According Cadence hardware team:
> > "64 bit addressing was added in July 2013. Earlier version do not have it.
> > This feature was enhanced in release August 2014 to have separate upper address values for transmit and receive."
> >
> >> /* Bitfields in NSR */
> >> @@ -474,6 +479,10 @@
> >>  struct macb_dma_desc {
> >  >      u32     addr;
> >>       u32     ctrl; 
> >> +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
> >> +     u32     addrh;
> >> +     u32     resvd;
> >> +#endif
> >>  };
> >
> > It will not work for legacy hardware. Old descriptor is 2 words wide, the new one is 4 words wide.
> > If you enable CONFIG_ARCH_DMA_ADDR_T_64BIT but hardware doesn't 
> > support it at all, you will miss every second descriptor.
> >
>
> True, this feature is not available in all of Cadence IP versions.
> In fact, the IP version Zynq does not support this. But the one in ZynqMP does.
> So, we enable kernel config for 64 bit DMA addressing for this SoC and hence the driver picks it up. My assumption was that if the legacy IP does not support
> 64 bit addressing, then this DMA option wouldn't be enabled.

What for example with arm64 (which enables CONFIG_ARCH_DMA_ADDR_T_64BIT by default) and legacy IP controller? Or systems with multiple IP, both with and without 64b dma capable?
It might result in unpredictable behavio. (explained below)

> There is a design config register in Cadence IP which is being read to check for 64 bit address support - DMA mask is set based on that.
> But the addition of two descriptor words cannot be based on this runtime check.
> For this reason, all the static changes were placed under this check.

Are you talking about this?

+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+	if (GEM_BFEXT(DBWDEF, gem_readl(bp, DCFG1)) > GEM_DBW32)
+		dma_set_mask(&pdev->dev, DMA_BIT_MASK(44));
+#endif
+

It only sets the maximum address which can be seen on address bus. (its mask exactly)

+static inline void macb_set_addr(struct macb_dma_desc *desc, dma_addr_t addr)
+{
+	desc->addr = (u32)addr;
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+	desc->addrh = (u32)(addr >> 32);
+#endif
+}
+

Because addr is 32b wide, (u32)(addr >> 32) equals 0. IP controller uses 2 words for dma descriptor, so desc->addr from second hardware descriptor will be overwritten by desc->addrh from the first software descriptor.
(same desc->ctrl from second hardware descriptor will be overwritten by desc->resvd). 

Regards,
Harini

^ permalink raw reply

* Re: [RFC PATCH 2/2] net: macb: Add 64 bit addressing support for GEM
From: Harini Katakam @ 2016-11-17 12:21 UTC (permalink / raw)
  To: Rafal Ozieblo
  Cc: harini.katakam@xilinx.com, nicolas.ferre@atmel.com,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <BN3PR07MB2516B2EBCF0AE7079971DBF6C9B10@BN3PR07MB2516.namprd07.prod.outlook.com>

Hi Rafal,

On Thu, Nov 17, 2016 at 5:20 PM, Rafal Ozieblo <rafalo@cadence.com> wrote:
> Hello,
> I think, there could a bug in your patch.
>
>> +
>> +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
>> +             dmacfg |= GEM_BIT(ADDR64);
>> +#endif
>
> You enable 64 bit addressing (64b dma bus width) always when appropriate architecture config option is enabled.
> But there are some legacy controllers which do not support that feature. According Cadence hardware team:
> "64 bit addressing was added in July 2013. Earlier version do not have it.
> This feature was enhanced in release August 2014 to have separate upper address values for transmit and receive."
>
>> /* Bitfields in NSR */
>> @@ -474,6 +479,10 @@
>>  struct macb_dma_desc {
>  >      u32     addr;
>>       u32     ctrl;
>> +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
>> +     u32     addrh;
>> +     u32     resvd;
>> +#endif
>>  };
>
> It will not work for legacy hardware. Old descriptor is 2 words wide, the new one is 4 words wide.
> If you enable CONFIG_ARCH_DMA_ADDR_T_64BIT but hardware doesn't support it at all,
> you will miss every second descriptor.
>

True, this feature is not available in all of Cadence IP versions.
In fact, the IP version Zynq does not support this. But the one in ZynqMP does.
So, we enable kernel config for 64 bit DMA addressing for this SoC and hence
the driver picks it up. My assumption was that if the legacy IP does not support
64 bit addressing, then this DMA option wouldn't be enabled.

There is a design config register in Cadence IP which is being read to
check for 64 bit address support - DMA mask is set based on that.
But the addition of two descriptor words cannot be based on this runtime check.
For this reason, all the static changes were placed under this check.

Regards,
Harini

^ permalink raw reply

* Re: [RFC PATCH 2/2] net: macb: Add 64 bit addressing support for GEM
From: Rafal Ozieblo @ 2016-11-17 11:50 UTC (permalink / raw)
  To: harini.katakam@xilinx.com
  Cc: nicolas.ferre@atmel.com, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org

Hello,
I think, there could a bug in your patch.

> +
> +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
> +             dmacfg |= GEM_BIT(ADDR64);
> +#endif

You enable 64 bit addressing (64b dma bus width) always when appropriate architecture config option is enabled.
But there are some legacy controllers which do not support that feature. According Cadence hardware team:
"64 bit addressing was added in July 2013. Earlier version do not have it.
This feature was enhanced in release August 2014 to have separate upper address values for transmit and receive."

> /* Bitfields in NSR */
> @@ -474,6 +479,10 @@
>  struct macb_dma_desc {
 >	u32	addr;
>  	u32	ctrl;
> +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
> +	u32     addrh;
> +	u32     resvd;
> +#endif
>  };

It will not work for legacy hardware. Old descriptor is 2 words wide, the new one is 4 words wide.
If you enable CONFIG_ARCH_DMA_ADDR_T_64BIT but hardware doesn't support it at all,
you will miss every second descriptor.

Regards,
Rafal

 

^ permalink raw reply

* [PATCH net-next V2 7/8] net/mlx5: Add MPCNT register infrastructure
From: Saeed Mahameed @ 2016-11-17 11:46 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Gal Pressman, Saeed Mahameed
In-Reply-To: <1479383162-3432-1-git-send-email-saeedm@mellanox.com>

From: Gal Pressman <galp@mellanox.com>

Add the needed infrastructure for future use of MPCNT register.

Signed-off-by: Gal Pressman <galp@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 include/linux/mlx5/device.h   |  5 +++
 include/linux/mlx5/driver.h   |  1 +
 include/linux/mlx5/mlx5_ifc.h | 93 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 99 insertions(+)

diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h
index 52b4374..9f48936 100644
--- a/include/linux/mlx5/device.h
+++ b/include/linux/mlx5/device.h
@@ -1071,6 +1071,11 @@ enum {
 	MLX5_INFINIBAND_PORT_COUNTERS_GROUP   = 0x20,
 };
 
+enum {
+	MLX5_PCIE_PERFORMANCE_COUNTERS_GROUP       = 0x0,
+	MLX5_PCIE_TIMERS_AND_STATES_COUNTERS_GROUP = 0x2,
+};
+
 static inline u16 mlx5_to_sw_pkey_sz(int pkey_sz)
 {
 	if (pkey_sz > MLX5_MAX_LOG_PKEY_TABLE)
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index 7336c8e..ae1f451 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -121,6 +121,7 @@ enum {
 	MLX5_REG_HOST_ENDIANNESS = 0x7004,
 	MLX5_REG_MCIA		 = 0x9014,
 	MLX5_REG_MLCR		 = 0x902b,
+	MLX5_REG_MPCNT		 = 0x9051,
 };
 
 enum {
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index f08a0624..a5f0fbe 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -1757,6 +1757,80 @@ struct mlx5_ifc_eth_802_3_cntrs_grp_data_layout_bits {
 	u8         reserved_at_4c0[0x300];
 };
 
+struct mlx5_ifc_pcie_perf_cntrs_grp_data_layout_bits {
+	u8         life_time_counter_high[0x20];
+
+	u8         life_time_counter_low[0x20];
+
+	u8         rx_errors[0x20];
+
+	u8         tx_errors[0x20];
+
+	u8         l0_to_recovery_eieos[0x20];
+
+	u8         l0_to_recovery_ts[0x20];
+
+	u8         l0_to_recovery_framing[0x20];
+
+	u8         l0_to_recovery_retrain[0x20];
+
+	u8         crc_error_dllp[0x20];
+
+	u8         crc_error_tlp[0x20];
+
+	u8         reserved_at_140[0x680];
+};
+
+struct mlx5_ifc_pcie_tas_cntrs_grp_data_layout_bits {
+	u8         life_time_counter_high[0x20];
+
+	u8         life_time_counter_low[0x20];
+
+	u8         time_to_boot_image_start[0x20];
+
+	u8         time_to_link_image[0x20];
+
+	u8         calibration_time[0x20];
+
+	u8         time_to_first_perst[0x20];
+
+	u8         time_to_detect_state[0x20];
+
+	u8         time_to_l0[0x20];
+
+	u8         time_to_crs_en[0x20];
+
+	u8         time_to_plastic_image_start[0x20];
+
+	u8         time_to_iron_image_start[0x20];
+
+	u8         perst_handler[0x20];
+
+	u8         times_in_l1[0x20];
+
+	u8         times_in_l23[0x20];
+
+	u8         dl_down[0x20];
+
+	u8         config_cycle1usec[0x20];
+
+	u8         config_cycle2to7usec[0x20];
+
+	u8         config_cycle_8to15usec[0x20];
+
+	u8         config_cycle_16_to_63usec[0x20];
+
+	u8         config_cycle_64usec[0x20];
+
+	u8         correctable_err_msg_sent[0x20];
+
+	u8         non_fatal_err_msg_sent[0x20];
+
+	u8         fatal_err_msg_sent[0x20];
+
+	u8         reserved_at_2e0[0x4e0];
+};
+
 struct mlx5_ifc_cmd_inter_comp_event_bits {
 	u8         command_completion_vector[0x20];
 
@@ -2921,6 +2995,12 @@ union mlx5_ifc_eth_cntrs_grp_data_layout_auto_bits {
 	u8         reserved_at_0[0x7c0];
 };
 
+union mlx5_ifc_pcie_cntrs_grp_data_layout_auto_bits {
+	struct mlx5_ifc_pcie_perf_cntrs_grp_data_layout_bits pcie_perf_cntrs_grp_data_layout;
+	struct mlx5_ifc_pcie_tas_cntrs_grp_data_layout_bits pcie_tas_cntrs_grp_data_layout;
+	u8         reserved_at_0[0x7c0];
+};
+
 union mlx5_ifc_event_auto_bits {
 	struct mlx5_ifc_comp_event_bits comp_event;
 	struct mlx5_ifc_dct_events_bits dct_events;
@@ -7240,6 +7320,18 @@ struct mlx5_ifc_ppcnt_reg_bits {
 	union mlx5_ifc_eth_cntrs_grp_data_layout_auto_bits counter_set;
 };
 
+struct mlx5_ifc_mpcnt_reg_bits {
+	u8         reserved_at_0[0x8];
+	u8         pcie_index[0x8];
+	u8         reserved_at_10[0xa];
+	u8         grp[0x6];
+
+	u8         clr[0x1];
+	u8         reserved_at_21[0x1f];
+
+	union mlx5_ifc_pcie_cntrs_grp_data_layout_auto_bits counter_set;
+};
+
 struct mlx5_ifc_ppad_reg_bits {
 	u8         reserved_at_0[0x3];
 	u8         single_mac[0x1];
@@ -7845,6 +7937,7 @@ union mlx5_ifc_ports_control_registers_document_bits {
 	struct mlx5_ifc_pmtu_reg_bits pmtu_reg;
 	struct mlx5_ifc_ppad_reg_bits ppad_reg;
 	struct mlx5_ifc_ppcnt_reg_bits ppcnt_reg;
+	struct mlx5_ifc_mpcnt_reg_bits mpcnt_reg;
 	struct mlx5_ifc_pplm_reg_bits pplm_reg;
 	struct mlx5_ifc_pplr_reg_bits pplr_reg;
 	struct mlx5_ifc_ppsc_reg_bits ppsc_reg;
-- 
2.7.4

^ permalink raw reply related

* [PATCH net-next V2 0/8] Mellanox 100G mlx5 update 2016-11-15
From: Saeed Mahameed @ 2016-11-17 11:45 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Saeed Mahameed

Hi Dave,

This series contains four humble mlx5 features.

>From Gal, 
 - Add the support for PCIe statistics and expose them in ethtool

>From Huy,
 - Add the support for port module events reporting and statistics
 - Add the support for driver version setting into FW (for display purposes only)

>From Mohamad,
 - Extended the command interface cache flexibility

This series was generated against commit
6a02f5eb6a8a ("Merge branch 'mlxsw-i2c")

V2:
 - Changed plain "unsigned" to "unsigned int"

Thanks,
Saeed.


Gal Pressman (2):
  net/mlx5: Add MPCNT register infrastructure
  net/mlx5e: Expose PCIe statistics to ethtool

Huy Nguyen (4):
  net/mlx5: Port module event hardware structures
  net/mlx5: Add handling for port module event
  net/mlx5e: Add port module event counters to ethtool stats
  net/mlx5: Set driver version into firmware

Mohamad Haj Yahia (1):
  net/mlx5: Make the command interface cache more flexible

Saeed Mahameed (1):
  net/mlx5: Set driver version infrastructure

 drivers/net/ethernet/mellanox/mlx5/core/cmd.c      | 145 ++++++++++-----------
 .../net/ethernet/mellanox/mlx5/core/en_ethtool.c   |  40 +++++-
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c  |  24 ++++
 drivers/net/ethernet/mellanox/mlx5/core/en_stats.h |  49 ++++++-
 drivers/net/ethernet/mellanox/mlx5/core/eq.c       |  12 ++
 drivers/net/ethernet/mellanox/mlx5/core/main.c     |  37 ++++++
 .../net/ethernet/mellanox/mlx5/core/mlx5_core.h    |   1 +
 drivers/net/ethernet/mellanox/mlx5/core/port.c     |  57 ++++++++
 include/linux/mlx5/device.h                        |  16 +++
 include/linux/mlx5/driver.h                        |  42 +++++-
 include/linux/mlx5/mlx5_ifc.h                      | 118 ++++++++++++++++-
 include/linux/mlx5/port.h                          |   3 +
 12 files changed, 457 insertions(+), 87 deletions(-)

-- 
2.7.4

^ permalink raw reply

* [PATCH net-next V2 3/8] net/mlx5: Add handling for port module event
From: Saeed Mahameed @ 2016-11-17 11:45 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Huy Nguyen, Saeed Mahameed
In-Reply-To: <1479383162-3432-1-git-send-email-saeedm@mellanox.com>

From: Huy Nguyen <huyn@mellanox.com>

For each asynchronous port module event:
  1. print with ratelimit to the dmesg log
  2. increment the corresponding event counter

Signed-off-by: Huy Nguyen <huyn@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/eq.c       | 12 +++++
 .../net/ethernet/mellanox/mlx5/core/mlx5_core.h    |  1 +
 drivers/net/ethernet/mellanox/mlx5/core/port.c     | 57 ++++++++++++++++++++++
 include/linux/mlx5/driver.h                        | 27 ++++++++++
 4 files changed, 97 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index e74a73b..8ffcc88 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -139,6 +139,8 @@ static const char *eqe_type_str(u8 type)
 		return "MLX5_EVENT_TYPE_PORT_CHANGE";
 	case MLX5_EVENT_TYPE_GPIO_EVENT:
 		return "MLX5_EVENT_TYPE_GPIO_EVENT";
+	case MLX5_EVENT_TYPE_PORT_MODULE_EVENT:
+		return "MLX5_EVENT_TYPE_PORT_MODULE_EVENT";
 	case MLX5_EVENT_TYPE_REMOTE_CONFIG:
 		return "MLX5_EVENT_TYPE_REMOTE_CONFIG";
 	case MLX5_EVENT_TYPE_DB_BF_CONGESTION:
@@ -285,6 +287,11 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
 			mlx5_eswitch_vport_event(dev->priv.eswitch, eqe);
 			break;
 #endif
+
+		case MLX5_EVENT_TYPE_PORT_MODULE_EVENT:
+			mlx5_port_module_event(dev, eqe);
+			break;
+
 		default:
 			mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n",
 				       eqe->type, eq->eqn);
@@ -480,6 +487,11 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev)
 	    mlx5_core_is_pf(dev))
 		async_event_mask |= (1ull << MLX5_EVENT_TYPE_NIC_VPORT_CHANGE);
 
+	if (MLX5_CAP_GEN(dev, port_module_event))
+		async_event_mask |= (1ull << MLX5_EVENT_TYPE_PORT_MODULE_EVENT);
+	else
+		mlx5_core_dbg(dev, "port_module_event is not set\n");
+
 	err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD,
 				 MLX5_NUM_CMD_EQE, 1ull << MLX5_EVENT_TYPE_CMD,
 				 "mlx5_cmd_eq", &dev->priv.uuari.uars[0]);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index 4762bb9..7e635eb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -81,6 +81,7 @@ int mlx5_cmd_init_hca(struct mlx5_core_dev *dev);
 int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev);
 void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
 		     unsigned long param);
+void mlx5_port_module_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe);
 void mlx5_enter_error_state(struct mlx5_core_dev *dev);
 void mlx5_disable_device(struct mlx5_core_dev *dev);
 void mlx5_recover_device(struct mlx5_core_dev *dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c
index 34e7184..b77928f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c
@@ -746,3 +746,60 @@ void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
 	*supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap));
 	*enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk));
 }
+
+static const char *mlx5_pme_status[MLX5_MODULE_STATUS_NUM] = {
+	"Cable plugged",   /* MLX5_MODULE_STATUS_PLUGGED    = 0x1 */
+	"Cable unplugged", /* MLX5_MODULE_STATUS_UNPLUGGED  = 0x2 */
+	"Cable error",     /* MLX5_MODULE_STATUS_ERROR      = 0x3 */
+};
+
+static const char *mlx5_pme_error[MLX5_MODULE_EVENT_ERROR_NUM] = {
+	"Power budget exceeded",
+	"Long Range for non MLNX cable",
+	"Bus stuck(I2C or data shorted)",
+	"No EEPROM/retry timeout",
+	"Enforce part number list",
+	"Unknown identifier",
+	"High Temperature",
+	"Bad or shorted cable/module",
+	"Unknown status",
+};
+
+void mlx5_port_module_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe)
+{
+	enum port_module_event_status_type module_status;
+	enum port_module_event_error_type error_type;
+	struct mlx5_eqe_port_module *module_event_eqe;
+	struct mlx5_priv *priv = &dev->priv;
+	u8 module_num;
+
+	module_event_eqe = &eqe->data.port_module;
+	module_num = module_event_eqe->module;
+	module_status = module_event_eqe->module_status &
+			PORT_MODULE_EVENT_MODULE_STATUS_MASK;
+	error_type = module_event_eqe->error_type &
+		     PORT_MODULE_EVENT_ERROR_TYPE_MASK;
+
+	if (module_status < MLX5_MODULE_STATUS_ERROR) {
+		priv->pme_stats.status_counters[module_status - 1]++;
+	} else if (module_status == MLX5_MODULE_STATUS_ERROR) {
+		if (error_type >= MLX5_MODULE_EVENT_ERROR_UNKNOWN)
+			/* Unknown error type */
+			error_type = MLX5_MODULE_EVENT_ERROR_UNKNOWN;
+		priv->pme_stats.error_counters[error_type]++;
+	}
+
+	if (!printk_ratelimit())
+		return;
+
+	if (module_status < MLX5_MODULE_STATUS_ERROR)
+		mlx5_core_info(dev,
+			       "Port module event: module %u, %s\n",
+			       module_num, mlx5_pme_status[module_status - 1]);
+
+	else if (module_status == MLX5_MODULE_STATUS_ERROR)
+		mlx5_core_info(dev,
+			       "Port module event[error]: module %u, %s, %s\n",
+			       module_num, mlx5_pme_status[module_status - 1],
+			       mlx5_pme_error[error_type]);
+}
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index 5e7dbbc..7336c8e 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -498,6 +498,31 @@ struct mlx5_rl_table {
 	struct mlx5_rl_entry   *rl_entry;
 };
 
+enum port_module_event_status_type {
+	MLX5_MODULE_STATUS_PLUGGED   = 0x1,
+	MLX5_MODULE_STATUS_UNPLUGGED = 0x2,
+	MLX5_MODULE_STATUS_ERROR     = 0x3,
+	MLX5_MODULE_STATUS_NUM       = 0x3,
+};
+
+enum  port_module_event_error_type {
+	MLX5_MODULE_EVENT_ERROR_POWER_BUDGET_EXCEEDED,
+	MLX5_MODULE_EVENT_ERROR_LONG_RANGE_FOR_NON_MLNX_CABLE_MODULE,
+	MLX5_MODULE_EVENT_ERROR_BUS_STUCK,
+	MLX5_MODULE_EVENT_ERROR_NO_EEPROM_RETRY_TIMEOUT,
+	MLX5_MODULE_EVENT_ERROR_ENFORCE_PART_NUMBER_LIST,
+	MLX5_MODULE_EVENT_ERROR_UNKNOWN_IDENTIFIER,
+	MLX5_MODULE_EVENT_ERROR_HIGH_TEMPERATURE,
+	MLX5_MODULE_EVENT_ERROR_BAD_CABLE,
+	MLX5_MODULE_EVENT_ERROR_UNKNOWN,
+	MLX5_MODULE_EVENT_ERROR_NUM,
+};
+
+struct mlx5_port_module_event_stats {
+	u64 status_counters[MLX5_MODULE_STATUS_NUM];
+	u64 error_counters[MLX5_MODULE_EVENT_ERROR_NUM];
+};
+
 struct mlx5_priv {
 	char			name[MLX5_MAX_NAME_LEN];
 	struct mlx5_eq_table	eq_table;
@@ -559,6 +584,8 @@ struct mlx5_priv {
 	unsigned long		pci_dev_data;
 	struct mlx5_fc_stats		fc_stats;
 	struct mlx5_rl_table            rl_table;
+
+	struct mlx5_port_module_event_stats  pme_stats;
 };
 
 enum mlx5_device_state {
-- 
2.7.4

^ permalink raw reply related

* [PATCH net-next V2 1/8] net/mlx5: Make the command interface cache more flexible
From: Saeed Mahameed @ 2016-11-17 11:45 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Mohamad Haj Yahia, Saeed Mahameed
In-Reply-To: <1479383162-3432-1-git-send-email-saeedm@mellanox.com>

From: Mohamad Haj Yahia <mohamad@mellanox.com>

Add more cache command size sets and more entries for each set based on
the current commands set different sizes and commands frequency.

Fixes: e126ba97dba9 ('mlx5: Add driver for Mellanox Connect-IB adapters')
Signed-off-by: Mohamad Haj Yahia <mohamad@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 145 ++++++++++++--------------
 include/linux/mlx5/driver.h                   |  14 +--
 2 files changed, 76 insertions(+), 83 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index 8561102..0fe7a60 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -54,14 +54,6 @@ enum {
 };
 
 enum {
-	NUM_LONG_LISTS	  = 2,
-	NUM_MED_LISTS	  = 64,
-	LONG_LIST_SIZE	  = (2ULL * 1024 * 1024 * 1024 / PAGE_SIZE) * 8 + 16 +
-				MLX5_CMD_DATA_BLOCK_SIZE,
-	MED_LIST_SIZE	  = 16 + MLX5_CMD_DATA_BLOCK_SIZE,
-};
-
-enum {
 	MLX5_CMD_DELIVERY_STAT_OK			= 0x0,
 	MLX5_CMD_DELIVERY_STAT_SIGNAT_ERR		= 0x1,
 	MLX5_CMD_DELIVERY_STAT_TOK_ERR			= 0x2,
@@ -1372,10 +1364,10 @@ static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg)
 {
 	unsigned long flags;
 
-	if (msg->cache) {
-		spin_lock_irqsave(&msg->cache->lock, flags);
-		list_add_tail(&msg->list, &msg->cache->head);
-		spin_unlock_irqrestore(&msg->cache->lock, flags);
+	if (msg->parent) {
+		spin_lock_irqsave(&msg->parent->lock, flags);
+		list_add_tail(&msg->list, &msg->parent->head);
+		spin_unlock_irqrestore(&msg->parent->lock, flags);
 	} else {
 		mlx5_free_cmd_msg(dev, msg);
 	}
@@ -1472,30 +1464,37 @@ static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size,
 				      gfp_t gfp)
 {
 	struct mlx5_cmd_msg *msg = ERR_PTR(-ENOMEM);
+	struct cmd_msg_cache *ch = NULL;
 	struct mlx5_cmd *cmd = &dev->cmd;
-	struct cache_ent *ent = NULL;
-
-	if (in_size > MED_LIST_SIZE && in_size <= LONG_LIST_SIZE)
-		ent = &cmd->cache.large;
-	else if (in_size > 16 && in_size <= MED_LIST_SIZE)
-		ent = &cmd->cache.med;
-
-	if (ent) {
-		spin_lock_irq(&ent->lock);
-		if (!list_empty(&ent->head)) {
-			msg = list_entry(ent->head.next, typeof(*msg), list);
-			/* For cached lists, we must explicitly state what is
-			 * the real size
-			 */
-			msg->len = in_size;
-			list_del(&msg->list);
+	int i;
+
+	if (in_size <= 16)
+		goto cache_miss;
+
+	for (i = 0; i < MLX5_NUM_COMMAND_CACHES; i++) {
+		ch = &cmd->cache[i];
+		if (in_size > ch->max_inbox_size)
+			continue;
+		spin_lock_irq(&ch->lock);
+		if (list_empty(&ch->head)) {
+			spin_unlock_irq(&ch->lock);
+			continue;
 		}
-		spin_unlock_irq(&ent->lock);
+		msg = list_entry(ch->head.next, typeof(*msg), list);
+		/* For cached lists, we must explicitly state what is
+		 * the real size
+		 */
+		msg->len = in_size;
+		list_del(&msg->list);
+		spin_unlock_irq(&ch->lock);
+		break;
 	}
 
-	if (IS_ERR(msg))
-		msg = mlx5_alloc_cmd_msg(dev, gfp, in_size, 0);
+	if (!IS_ERR(msg))
+		return msg;
 
+cache_miss:
+	msg = mlx5_alloc_cmd_msg(dev, gfp, in_size, 0);
 	return msg;
 }
 
@@ -1593,58 +1592,56 @@ EXPORT_SYMBOL(mlx5_cmd_exec_cb);
 
 static void destroy_msg_cache(struct mlx5_core_dev *dev)
 {
-	struct mlx5_cmd *cmd = &dev->cmd;
+	struct cmd_msg_cache *ch;
 	struct mlx5_cmd_msg *msg;
 	struct mlx5_cmd_msg *n;
+	int i;
 
-	list_for_each_entry_safe(msg, n, &cmd->cache.large.head, list) {
-		list_del(&msg->list);
-		mlx5_free_cmd_msg(dev, msg);
-	}
-
-	list_for_each_entry_safe(msg, n, &cmd->cache.med.head, list) {
-		list_del(&msg->list);
-		mlx5_free_cmd_msg(dev, msg);
+	for (i = 0; i < MLX5_NUM_COMMAND_CACHES; i++) {
+		ch = &dev->cmd.cache[i];
+		list_for_each_entry_safe(msg, n, &ch->head, list) {
+			list_del(&msg->list);
+			mlx5_free_cmd_msg(dev, msg);
+		}
 	}
 }
 
-static int create_msg_cache(struct mlx5_core_dev *dev)
+static unsigned cmd_cache_num_ent[MLX5_NUM_COMMAND_CACHES] = {
+	512, 32, 16, 8, 2
+};
+
+static unsigned cmd_cache_ent_size[MLX5_NUM_COMMAND_CACHES] = {
+	16 + MLX5_CMD_DATA_BLOCK_SIZE,
+	16 + MLX5_CMD_DATA_BLOCK_SIZE * 2,
+	16 + MLX5_CMD_DATA_BLOCK_SIZE * 16,
+	16 + MLX5_CMD_DATA_BLOCK_SIZE * 256,
+	16 + MLX5_CMD_DATA_BLOCK_SIZE * 512,
+};
+
+static void create_msg_cache(struct mlx5_core_dev *dev)
 {
 	struct mlx5_cmd *cmd = &dev->cmd;
+	struct cmd_msg_cache *ch;
 	struct mlx5_cmd_msg *msg;
-	int err;
 	int i;
-
-	spin_lock_init(&cmd->cache.large.lock);
-	INIT_LIST_HEAD(&cmd->cache.large.head);
-	spin_lock_init(&cmd->cache.med.lock);
-	INIT_LIST_HEAD(&cmd->cache.med.head);
-
-	for (i = 0; i < NUM_LONG_LISTS; i++) {
-		msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, LONG_LIST_SIZE, 0);
-		if (IS_ERR(msg)) {
-			err = PTR_ERR(msg);
-			goto ex_err;
-		}
-		msg->cache = &cmd->cache.large;
-		list_add_tail(&msg->list, &cmd->cache.large.head);
-	}
-
-	for (i = 0; i < NUM_MED_LISTS; i++) {
-		msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, MED_LIST_SIZE, 0);
-		if (IS_ERR(msg)) {
-			err = PTR_ERR(msg);
-			goto ex_err;
+	int k;
+
+	/* Initialize and fill the caches with initial entries */
+	for (k = 0; k < MLX5_NUM_COMMAND_CACHES; k++) {
+		ch = &cmd->cache[k];
+		spin_lock_init(&ch->lock);
+		INIT_LIST_HEAD(&ch->head);
+		ch->num_ent = cmd_cache_num_ent[k];
+		ch->max_inbox_size = cmd_cache_ent_size[k];
+		for (i = 0; i < ch->num_ent; i++) {
+			msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL | __GFP_NOWARN,
+						 ch->max_inbox_size, 0);
+			if (IS_ERR(msg))
+				break;
+			msg->parent = ch;
+			list_add_tail(&msg->list, &ch->head);
 		}
-		msg->cache = &cmd->cache.med;
-		list_add_tail(&msg->list, &cmd->cache.med.head);
 	}
-
-	return 0;
-
-ex_err:
-	destroy_msg_cache(dev);
-	return err;
 }
 
 static int alloc_cmd_page(struct mlx5_core_dev *dev, struct mlx5_cmd *cmd)
@@ -1767,11 +1764,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev)
 
 	cmd->mode = CMD_MODE_POLLING;
 
-	err = create_msg_cache(dev);
-	if (err) {
-		dev_err(&dev->pdev->dev, "failed to create command cache\n");
-		goto err_free_page;
-	}
+	create_msg_cache(dev);
 
 	set_wqname(dev);
 	cmd->wq = create_singlethread_workqueue(cmd->wq_name);
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index ecc451d..5e7dbbc 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -208,7 +208,7 @@ struct mlx5_cmd_first {
 
 struct mlx5_cmd_msg {
 	struct list_head		list;
-	struct cache_ent	       *cache;
+	struct cmd_msg_cache	       *parent;
 	u32				len;
 	struct mlx5_cmd_first		first;
 	struct mlx5_cmd_mailbox	       *next;
@@ -228,17 +228,17 @@ struct mlx5_cmd_debug {
 	u16			outlen;
 };
 
-struct cache_ent {
+struct cmd_msg_cache {
 	/* protect block chain allocations
 	 */
 	spinlock_t		lock;
 	struct list_head	head;
+	unsigned int		max_inbox_size;
+	unsigned int		num_ent;
 };
 
-struct cmd_msg_cache {
-	struct cache_ent	large;
-	struct cache_ent	med;
-
+enum {
+	MLX5_NUM_COMMAND_CACHES = 5,
 };
 
 struct mlx5_cmd_stats {
@@ -281,7 +281,7 @@ struct mlx5_cmd {
 	struct mlx5_cmd_work_ent *ent_arr[MLX5_MAX_COMMANDS];
 	struct pci_pool *pool;
 	struct mlx5_cmd_debug dbg;
-	struct cmd_msg_cache cache;
+	struct cmd_msg_cache cache[MLX5_NUM_COMMAND_CACHES];
 	int checksum_disabled;
 	struct mlx5_cmd_stats stats[MLX5_CMD_OP_MAX];
 };
-- 
2.7.4

^ permalink raw reply related

* [PATCH net-next V2 2/8] net/mlx5: Port module event hardware structures
From: Saeed Mahameed @ 2016-11-17 11:45 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Huy Nguyen, Saeed Mahameed, Leon Romanovsky
In-Reply-To: <1479383162-3432-1-git-send-email-saeedm@mellanox.com>

From: Huy Nguyen <huyn@mellanox.com>

Add hardware structures and constants definitions needed for module
events support.

Signed-off-by: Huy Nguyen <huyn@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
---
 include/linux/mlx5/device.h   | 11 +++++++++++
 include/linux/mlx5/mlx5_ifc.h |  3 ++-
 include/linux/mlx5/port.h     |  3 +++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h
index 5827614..52b4374 100644
--- a/include/linux/mlx5/device.h
+++ b/include/linux/mlx5/device.h
@@ -277,6 +277,7 @@ enum mlx5_event {
 	MLX5_EVENT_TYPE_INTERNAL_ERROR	   = 0x08,
 	MLX5_EVENT_TYPE_PORT_CHANGE	   = 0x09,
 	MLX5_EVENT_TYPE_GPIO_EVENT	   = 0x15,
+	MLX5_EVENT_TYPE_PORT_MODULE_EVENT  = 0x16,
 	MLX5_EVENT_TYPE_REMOTE_CONFIG	   = 0x19,
 
 	MLX5_EVENT_TYPE_DB_BF_CONGESTION   = 0x1a,
@@ -552,6 +553,15 @@ struct mlx5_eqe_vport_change {
 	__be32		rsvd1[6];
 } __packed;
 
+struct mlx5_eqe_port_module {
+	u8        reserved_at_0[1];
+	u8        module;
+	u8        reserved_at_2[1];
+	u8        module_status;
+	u8        reserved_at_4[2];
+	u8        error_type;
+} __packed;
+
 union ev_data {
 	__be32				raw[7];
 	struct mlx5_eqe_cmd		cmd;
@@ -565,6 +575,7 @@ union ev_data {
 	struct mlx5_eqe_page_req	req_pages;
 	struct mlx5_eqe_page_fault	page_fault;
 	struct mlx5_eqe_vport_change	vport_change;
+	struct mlx5_eqe_port_module	port_module;
 } __packed;
 
 struct mlx5_eqe {
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index 2632cb2..cd1d530 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -824,7 +824,8 @@ struct mlx5_ifc_cmd_hca_cap_bits {
 	u8	   early_vf_enable[0x1];
 	u8         reserved_at_1a9[0x2];
 	u8         local_ca_ack_delay[0x5];
-	u8         reserved_at_1af[0x2];
+	u8         port_module_event[0x1];
+	u8         reserved_at_1b0[0x1];
 	u8         ports_check[0x1];
 	u8         reserved_at_1b2[0x1];
 	u8         disable_link_up[0x1];
diff --git a/include/linux/mlx5/port.h b/include/linux/mlx5/port.h
index b3065ac..dde8c7e 100644
--- a/include/linux/mlx5/port.h
+++ b/include/linux/mlx5/port.h
@@ -94,6 +94,9 @@ enum mlx5e_link_mode {
 
 #define MLX5E_PROT_MASK(link_mode) (1 << link_mode)
 
+#define PORT_MODULE_EVENT_MODULE_STATUS_MASK 0xF
+#define PORT_MODULE_EVENT_ERROR_TYPE_MASK         0xF
+
 int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps);
 int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
 			 int ptys_size, int proto_mask, u8 local_port);
-- 
2.7.4

^ permalink raw reply related

* [PATCH net-next V2 5/8] net/mlx5: Set driver version infrastructure
From: Saeed Mahameed @ 2016-11-17 11:45 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Saeed Mahameed, Huy Nguyen, Leon Romanovsky
In-Reply-To: <1479383162-3432-1-git-send-email-saeedm@mellanox.com>

Add driver_version capability bit is enabled, and set driver
version command in mlx5_ifc firmware header.  The only purpose
of this command is to store a driver version/OS string in FW
to be reported and displayed in various management systems,
such as IPMI/BMC.

Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Huy Nguyen <huyn@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
---
 include/linux/mlx5/mlx5_ifc.h | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index cd1d530..f08a0624 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -83,6 +83,7 @@ enum {
 	MLX5_CMD_OP_SET_HCA_CAP                   = 0x109,
 	MLX5_CMD_OP_QUERY_ISSI                    = 0x10a,
 	MLX5_CMD_OP_SET_ISSI                      = 0x10b,
+	MLX5_CMD_OP_SET_DRIVER_VERSION            = 0x10d,
 	MLX5_CMD_OP_CREATE_MKEY                   = 0x200,
 	MLX5_CMD_OP_QUERY_MKEY                    = 0x201,
 	MLX5_CMD_OP_DESTROY_MKEY                  = 0x202,
@@ -909,7 +910,7 @@ struct mlx5_ifc_cmd_hca_cap_bits {
 	u8         log_pg_sz[0x8];
 
 	u8         bf[0x1];
-	u8         reserved_at_261[0x1];
+	u8         driver_version[0x1];
 	u8         pad_tx_eth_packet[0x1];
 	u8         reserved_at_263[0x8];
 	u8         log_bf_reg_size[0x5];
@@ -4005,6 +4006,25 @@ struct mlx5_ifc_query_issi_in_bits {
 	u8         reserved_at_40[0x40];
 };
 
+struct mlx5_ifc_set_driver_version_out_bits {
+	u8         status[0x8];
+	u8         reserved_0[0x18];
+
+	u8         syndrome[0x20];
+	u8         reserved_1[0x40];
+};
+
+struct mlx5_ifc_set_driver_version_in_bits {
+	u8         opcode[0x10];
+	u8         reserved_0[0x10];
+
+	u8         reserved_1[0x10];
+	u8         op_mod[0x10];
+
+	u8         reserved_2[0x40];
+	u8         driver_version[64][0x8];
+};
+
 struct mlx5_ifc_query_hca_vport_pkey_out_bits {
 	u8         status[0x8];
 	u8         reserved_at_8[0x18];
-- 
2.7.4

^ permalink raw reply related

* [PATCH net-next V2 4/8] net/mlx5e: Add port module event counters to ethtool stats
From: Saeed Mahameed @ 2016-11-17 11:45 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Huy Nguyen, Saeed Mahameed
In-Reply-To: <1479383162-3432-1-git-send-email-saeedm@mellanox.com>

From: Huy Nguyen <huyn@mellanox.com>

Add port module event counters to ethtool -S command

Signed-off-by: Huy Nguyen <huyn@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/en_ethtool.c   | 23 +++++++++++++++++++++-
 drivers/net/ethernet/mellanox/mlx5/core/en_stats.h | 17 ++++++++++++++++
 2 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index 27ff401..b154621 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -173,7 +173,10 @@ static int mlx5e_get_sset_count(struct net_device *dev, int sset)
 		       NUM_VPORT_COUNTERS + NUM_PPORT_COUNTERS +
 		       MLX5E_NUM_RQ_STATS(priv) +
 		       MLX5E_NUM_SQ_STATS(priv) +
-		       MLX5E_NUM_PFC_COUNTERS(priv);
+		       MLX5E_NUM_PFC_COUNTERS(priv) +
+		       ARRAY_SIZE(mlx5e_pme_status_desc) +
+		       ARRAY_SIZE(mlx5e_pme_error_desc);
+
 	case ETH_SS_PRIV_FLAGS:
 		return ARRAY_SIZE(mlx5e_priv_flags);
 	/* fallthrough */
@@ -237,6 +240,13 @@ static void mlx5e_fill_stats_strings(struct mlx5e_priv *priv, uint8_t *data)
 		}
 	}
 
+	/* port module event counters */
+	for (i = 0; i < ARRAY_SIZE(mlx5e_pme_status_desc); i++)
+		strcpy(data + (idx++) * ETH_GSTRING_LEN, mlx5e_pme_status_desc[i].format);
+
+	for (i = 0; i < ARRAY_SIZE(mlx5e_pme_error_desc); i++)
+		strcpy(data + (idx++) * ETH_GSTRING_LEN, mlx5e_pme_error_desc[i].format);
+
 	if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
 		return;
 
@@ -279,6 +289,7 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev,
 				    struct ethtool_stats *stats, u64 *data)
 {
 	struct mlx5e_priv *priv = netdev_priv(dev);
+	struct mlx5_priv *mlx5_priv;
 	int i, j, tc, prio, idx = 0;
 	unsigned long pfc_combined;
 
@@ -335,6 +346,16 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev,
 		}
 	}
 
+	/* port module event counters */
+	mlx5_priv =  &priv->mdev->priv;
+	for (i = 0; i < ARRAY_SIZE(mlx5e_pme_status_desc); i++)
+		data[idx++] = MLX5E_READ_CTR64_CPU(mlx5_priv->pme_stats.status_counters,
+						   mlx5e_pme_status_desc, i);
+
+	for (i = 0; i < ARRAY_SIZE(mlx5e_pme_error_desc); i++)
+		data[idx++] = MLX5E_READ_CTR64_CPU(mlx5_priv->pme_stats.error_counters,
+						   mlx5e_pme_error_desc, i);
+
 	if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
 		return;
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
index 57452fd..b817e51 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
@@ -379,4 +379,21 @@ struct mlx5e_stats {
 	struct mlx5e_pport_stats pport;
 };
 
+static const struct counter_desc mlx5e_pme_status_desc[] = {
+	{ "module_plug", 0 },
+	{ "module_unplug", 8 },
+};
+
+static const struct counter_desc mlx5e_pme_error_desc[] = {
+	{ "module_pwr_budget_exd", 0 },  /* power budget exceed */
+	{ "module_long_range", 8 },      /* long range for non MLNX cable */
+	{ "module_bus_stuck", 16 },      /* bus stuck (I2C or data shorted) */
+	{ "module_no_eeprom", 24 },      /* no eeprom/retry time out */
+	{ "module_enforce_part", 32 },   /* enforce part number list */
+	{ "module_unknown_id", 40 },     /* unknown identifier */
+	{ "module_high_temp", 48 },      /* high temperature */
+	{ "module_bad_shorted", 56 },    /* bad or shorted cable/module */
+	{ "module_unknown_status", 64 },
+};
+
 #endif /* __MLX5_EN_STATS_H__ */
-- 
2.7.4

^ permalink raw reply related

* [PATCH net-next V2 6/8] net/mlx5: Set driver version into firmware
From: Saeed Mahameed @ 2016-11-17 11:46 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Huy Nguyen, Saeed Mahameed
In-Reply-To: <1479383162-3432-1-git-send-email-saeedm@mellanox.com>

From: Huy Nguyen <huyn@mellanox.com>

If driver_version capability bit is enabled, set driver version
to firmware after the init HCA command, for display purposes.

Example of driver version: "Linux,mlx5_core,3.0-1"

Signed-off-by: Huy Nguyen <huyn@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/main.c | 37 ++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index c074933..f28df33 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -175,6 +175,41 @@ static int wait_fw_init(struct mlx5_core_dev *dev, u32 max_wait_mili)
 	return err;
 }
 
+static void mlx5_set_driver_version(struct mlx5_core_dev *dev)
+{
+	int driver_ver_sz = MLX5_FLD_SZ_BYTES(set_driver_version_in,
+					      driver_version);
+	u8 in[MLX5_ST_SZ_BYTES(set_driver_version_in)] = {0};
+	u8 out[MLX5_ST_SZ_BYTES(set_driver_version_out)] = {0};
+	int remaining_size = driver_ver_sz;
+	char *string;
+
+	if (!MLX5_CAP_GEN(dev, driver_version))
+		return;
+
+	string = MLX5_ADDR_OF(set_driver_version_in, in, driver_version);
+
+	strncpy(string, "Linux", remaining_size);
+
+	remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
+	strncat(string, ",", remaining_size);
+
+	remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
+	strncat(string, DRIVER_NAME, remaining_size);
+
+	remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
+	strncat(string, ",", remaining_size);
+
+	remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
+	strncat(string, DRIVER_VERSION, remaining_size);
+
+	/*Send the command*/
+	MLX5_SET(set_driver_version_in, in, opcode,
+		 MLX5_CMD_OP_SET_DRIVER_VERSION);
+
+	mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
+
 static int set_dma_caps(struct pci_dev *pdev)
 {
 	int err;
@@ -1015,6 +1050,8 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 		goto err_pagealloc_stop;
 	}
 
+	mlx5_set_driver_version(dev);
+
 	mlx5_start_health_poll(dev);
 
 	err = mlx5_query_hca_caps(dev);
-- 
2.7.4

^ permalink raw reply related

* [PATCH net-next V2 8/8] net/mlx5e: Expose PCIe statistics to ethtool
From: Saeed Mahameed @ 2016-11-17 11:46 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Gal Pressman, Saeed Mahameed
In-Reply-To: <1479383162-3432-1-git-send-email-saeedm@mellanox.com>

From: Gal Pressman <galp@mellanox.com>

This patch exposes two groups of PCIe counters:
- Performance counters.
- Timers and states counters.
Queried with ethtool -S <devname>.

Signed-off-by: Gal Pressman <galp@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/en_ethtool.c   | 17 ++++++++++++
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c  | 24 ++++++++++++++++
 drivers/net/ethernet/mellanox/mlx5/core/en_stats.h | 32 +++++++++++++++++++++-
 3 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index b154621..9ea7b37 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -171,6 +171,7 @@ static int mlx5e_get_sset_count(struct net_device *dev, int sset)
 		return NUM_SW_COUNTERS +
 		       MLX5E_NUM_Q_CNTRS(priv) +
 		       NUM_VPORT_COUNTERS + NUM_PPORT_COUNTERS +
+		       NUM_PCIE_COUNTERS +
 		       MLX5E_NUM_RQ_STATS(priv) +
 		       MLX5E_NUM_SQ_STATS(priv) +
 		       MLX5E_NUM_PFC_COUNTERS(priv) +
@@ -216,6 +217,14 @@ static void mlx5e_fill_stats_strings(struct mlx5e_priv *priv, uint8_t *data)
 		strcpy(data + (idx++) * ETH_GSTRING_LEN,
 		       pport_2819_stats_desc[i].format);
 
+	for (i = 0; i < NUM_PCIE_PERF_COUNTERS; i++)
+		strcpy(data + (idx++) * ETH_GSTRING_LEN,
+		       pcie_perf_stats_desc[i].format);
+
+	for (i = 0; i < NUM_PCIE_TAS_COUNTERS; i++)
+		strcpy(data + (idx++) * ETH_GSTRING_LEN,
+		       pcie_tas_stats_desc[i].format);
+
 	for (prio = 0; prio < NUM_PPORT_PRIO; prio++) {
 		for (i = 0; i < NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS; i++)
 			sprintf(data + (idx++) * ETH_GSTRING_LEN,
@@ -325,6 +334,14 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev,
 		data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.RFC_2819_counters,
 						  pport_2819_stats_desc, i);
 
+	for (i = 0; i < NUM_PCIE_PERF_COUNTERS; i++)
+		data[idx++] = MLX5E_READ_CTR32_BE(&priv->stats.pcie.pcie_perf_counters,
+						  pcie_perf_stats_desc, i);
+
+	for (i = 0; i < NUM_PCIE_TAS_COUNTERS; i++)
+		data[idx++] = MLX5E_READ_CTR32_BE(&priv->stats.pcie.pcie_tas_counters,
+						  pcie_tas_stats_desc, i);
+
 	for (prio = 0; prio < NUM_PPORT_PRIO; prio++) {
 		for (i = 0; i < NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS; i++)
 			data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.per_prio_counters[prio],
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 52b4fd5..16a9a10 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -290,12 +290,36 @@ static void mlx5e_update_q_counter(struct mlx5e_priv *priv)
 				      &qcnt->rx_out_of_buffer);
 }
 
+static void mlx5e_update_pcie_counters(struct mlx5e_priv *priv)
+{
+	struct mlx5e_pcie_stats *pcie_stats = &priv->stats.pcie;
+	struct mlx5_core_dev *mdev = priv->mdev;
+	int sz = MLX5_ST_SZ_BYTES(mpcnt_reg);
+	void *out;
+	u32 *in;
+
+	in = mlx5_vzalloc(sz);
+	if (!in)
+		return;
+
+	out = pcie_stats->pcie_perf_counters;
+	MLX5_SET(mpcnt_reg, in, grp, MLX5_PCIE_PERFORMANCE_COUNTERS_GROUP);
+	mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_MPCNT, 0, 0);
+
+	out = pcie_stats->pcie_tas_counters;
+	MLX5_SET(mpcnt_reg, in, grp, MLX5_PCIE_TIMERS_AND_STATES_COUNTERS_GROUP);
+	mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_MPCNT, 0, 0);
+
+	kvfree(in);
+}
+
 void mlx5e_update_stats(struct mlx5e_priv *priv)
 {
 	mlx5e_update_q_counter(priv);
 	mlx5e_update_vport_counters(priv);
 	mlx5e_update_pport_counters(priv);
 	mlx5e_update_sw_counters(priv);
+	mlx5e_update_pcie_counters(priv);
 }
 
 void mlx5e_update_stats_work(struct work_struct *work)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
index b817e51..5da6a1c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
@@ -39,7 +39,7 @@
 #define MLX5E_READ_CTR32_CPU(ptr, dsc, i) \
 	(*(u32 *)((char *)ptr + dsc[i].offset))
 #define MLX5E_READ_CTR32_BE(ptr, dsc, i) \
-	be64_to_cpu(*(__be32 *)((char *)ptr + dsc[i].offset))
+	be32_to_cpu(*(__be32 *)((char *)ptr + dsc[i].offset))
 
 #define MLX5E_DECLARE_STAT(type, fld) #fld, offsetof(type, fld)
 #define MLX5E_DECLARE_RX_STAT(type, fld) "rx%d_"#fld, offsetof(type, fld)
@@ -276,6 +276,32 @@ static const struct counter_desc pport_per_prio_pfc_stats_desc[] = {
 	{ "rx_%s_pause_transition", PPORT_PER_PRIO_OFF(rx_pause_transition) },
 };
 
+#define PCIE_PERF_OFF(c) \
+	MLX5_BYTE_OFF(mpcnt_reg, counter_set.pcie_perf_cntrs_grp_data_layout.c)
+#define PCIE_PERF_GET(pcie_stats, c) \
+	MLX5_GET(mpcnt_reg, pcie_stats->pcie_perf_counters, \
+		 counter_set.pcie_perf_cntrs_grp_data_layout.c)
+#define PCIE_TAS_OFF(c) \
+	MLX5_BYTE_OFF(mpcnt_reg, counter_set.pcie_tas_cntrs_grp_data_layout.c)
+#define PCIE_TAS_GET(pcie_stats, c) \
+	MLX5_GET(mpcnt_reg, pcie_stats->pcie_tas_counters, \
+		 counter_set.pcie_tas_cntrs_grp_data_layout.c)
+
+struct mlx5e_pcie_stats {
+	__be64 pcie_perf_counters[MLX5_ST_SZ_QW(mpcnt_reg)];
+	__be64 pcie_tas_counters[MLX5_ST_SZ_QW(mpcnt_reg)];
+};
+
+static const struct counter_desc pcie_perf_stats_desc[] = {
+	{ "rx_pci_signal_integrity", PCIE_PERF_OFF(rx_errors) },
+	{ "tx_pci_signal_integrity", PCIE_PERF_OFF(tx_errors) },
+};
+
+static const struct counter_desc pcie_tas_stats_desc[] = {
+	{ "tx_pci_transport_nonfatal_msg", PCIE_TAS_OFF(non_fatal_err_msg_sent) },
+	{ "tx_pci_transport_fatal_msg", PCIE_TAS_OFF(fatal_err_msg_sent) },
+};
+
 struct mlx5e_rq_stats {
 	u64 packets;
 	u64 bytes;
@@ -360,6 +386,8 @@ static const struct counter_desc sq_stats_desc[] = {
 #define NUM_PPORT_802_3_COUNTERS	ARRAY_SIZE(pport_802_3_stats_desc)
 #define NUM_PPORT_2863_COUNTERS		ARRAY_SIZE(pport_2863_stats_desc)
 #define NUM_PPORT_2819_COUNTERS		ARRAY_SIZE(pport_2819_stats_desc)
+#define NUM_PCIE_PERF_COUNTERS		ARRAY_SIZE(pcie_perf_stats_desc)
+#define NUM_PCIE_TAS_COUNTERS		ARRAY_SIZE(pcie_tas_stats_desc)
 #define NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS \
 	ARRAY_SIZE(pport_per_prio_traffic_stats_desc)
 #define NUM_PPORT_PER_PRIO_PFC_COUNTERS \
@@ -369,6 +397,7 @@ static const struct counter_desc sq_stats_desc[] = {
 					 NUM_PPORT_2819_COUNTERS  + \
 					 NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS * \
 					 NUM_PPORT_PRIO)
+#define NUM_PCIE_COUNTERS		(NUM_PCIE_PERF_COUNTERS + NUM_PCIE_TAS_COUNTERS)
 #define NUM_RQ_STATS			ARRAY_SIZE(rq_stats_desc)
 #define NUM_SQ_STATS			ARRAY_SIZE(sq_stats_desc)
 
@@ -377,6 +406,7 @@ struct mlx5e_stats {
 	struct mlx5e_qcounter_stats qcnt;
 	struct mlx5e_vport_stats vport;
 	struct mlx5e_pport_stats pport;
+	struct mlx5e_pcie_stats pcie;
 };
 
 static const struct counter_desc mlx5e_pme_status_desc[] = {
-- 
2.7.4

^ permalink raw reply related

* Re: mwifiex: fix memory leak in mwifiex_save_hidden_ssid_channels()
From: Kalle Valo @ 2016-11-17 11:13 UTC (permalink / raw)
  To: Ricky Liang
In-Reply-To: <1478662648-70698-1-git-send-email-jcliang@chromium.org>

Ricky Liang <jcliang@chromium.org> wrote:
> kmemleak reports memory leak in mwifiex_save_hidden_ssid_channels():
> 
> unreferenced object 0xffffffc0a2914780 (size 192):
>   comm "ksdioirqd/mmc2", pid 2004, jiffies 4307182506 (age 820.684s)
>   hex dump (first 32 bytes):
>     00 06 47 49 4e 2d 32 67 01 03 c8 60 6c 03 01 40  ..GIN-2g...`l..@
>     07 10 54 57 20 34 04 1e 64 05 24 84 03 24 95 04  ..TW 4..d.$..$..
>   backtrace:
>     [<ffffffc0003375f4>] create_object+0x164/0x2b4
>     [<ffffffc0008e3530>] kmemleak_alloc+0x50/0x88
>     [<ffffffc000335120>] __kmalloc_track_caller+0x1bc/0x264
>     [<ffffffc00030899c>] kmemdup+0x38/0x64
>     [<ffffffbffc2311cc>] mwifiex_fill_new_bss_desc+0x3c/0x130 [mwifiex]
>     [<ffffffbffc22ee9c>] mwifiex_save_curr_bcn+0x4ec/0x640 [mwifiex]
>     [<ffffffbffc22f45c>] mwifiex_handle_event_ext_scan_report+0x1d4/0x268 [mwifiex]
>     [<ffffffbffc2375d0>] mwifiex_process_sta_event+0x378/0x898 [mwifiex]
>     [<ffffffbffc224dc8>] mwifiex_process_event+0x1a8/0x1e8 [mwifiex]
>     [<ffffffbffc2228f0>] mwifiex_main_process+0x258/0x534 [mwifiex]
>     [<ffffffbffc258858>] 0xffffffbffc258858
>     [<ffffffc00071ee90>] process_sdio_pending_irqs+0xf8/0x160
>     [<ffffffc00071efdc>] sdio_irq_thread+0x9c/0x1a4
>     [<ffffffc000240d08>] kthread+0xf4/0x100
>     [<ffffffc0002043fc>] ret_from_fork+0xc/0x50
>     [<ffffffffffffffff>] 0xffffffffffffffff
> 
> Signed-off-by: Ricky Liang <jcliang@chromium.org>
> Acked-by: Amitkumar Karwar <akarwar@marvell.com>
> Reviewed-by: Brian Norris <briannorris@chromium.org>

Patch applied to wireless-drivers-next.git, thanks.

5ff262229378 mwifiex: fix memory leak in mwifiex_save_hidden_ssid_channels()

-- 
https://patchwork.kernel.org/patch/9418433/

Documentation about submitting wireless patches and checking status
from patchwork:

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply

* Re: [4.9.0-rc5] AR9300 calibration problems with antenna selected
From: Kalle Valo @ 2016-11-17 11:09 UTC (permalink / raw)
  To: Krzysztof Hałasa
  Cc: netdev, ath9k-devel, linux-wireless, QCA ath9k Development,
	linux-kernel
In-Reply-To: <m3wpg52hii.fsf@t19.piap.pl>

Krzysztof wrote:
> Hi,
> 
> I recently tried to select a single antenna on AR9300 and it works for
> 30 seconds only. The subsequent calibration makes the RX signal level to
> drop from the usual -30/-40 dBm to -70/-80 dBm, and the transmission
> practically stops.
> 
> With the attached patch it works, though selecting the antenna doesn't
> seem to have any visible effect, at least with "iw wlanX station dump"
> (perhaps it works for TX).
> 
> I'm using ad-hoc mode:
> 
> rmmod ath9k
> modprobe ath9k
> iw dev wlan0 set type ibss
> iw phy phyX set antenna 2
> ip link set up dev wlan0
> iw dev wlan0 set bitrates legacy-2.4 18
> iw dev wlan0 ibss join nameXXX freqYYY
> ip addr add ZZZ broadcast + dev wlan0
> 
> The card in question is Mikrotik (Routerboard) R11e-2HPnD mPCIe adapter:
> AR9580 Wireless Network Adapter (rev 01), ID 168c:0033, subsystem
> 19b6:d016.
> ieee80211 phy0: Atheros AR9300 Rev:4 mem=0xc0f40000, irq=334
> https://routerboard.com/R11e-2HPnD
> 
> Linux 4.9.0-rc5.
> 
> 
> Is there a better way?
> 
> Signed-off-by: Krzysztof Halasa <khalasa@piap.pl>
> 
> diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
> index e9f32b5..7f17e5d 100644
> --- a/drivers/net/wireless/ath/ath9k/main.c
> +++ b/drivers/net/wireless/ath/ath9k/main.c
> @@ -2245,7 +2245,7 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
>  		return 0;
>  
>  	/* AR9100 runs into calibration issues if not all rx chains are enabled */
> -	if (AR_SREV_9100(ah))
> +	if (AR_SREV_9100(ah) || AR_SREV_9300(ah))
>  		ah->rxchainmask = 0x7;
>  	else
>  		ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);

I'll assume this is an RFC patch. Please resubmit if this is the right
approach.

Patch set to RFC.

-- 
https://patchwork.kernel.org/patch/9429263/

Documentation about submitting wireless patches and checking status
from patchwork:

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply

* Re: [4.9.0-rc5] AR9300 calibration problems with antenna selected
From: Kalle Valo @ 2016-11-17 11:09 UTC (permalink / raw)
  To: Krzysztof Hałasa
  Cc: QCA ath9k Development, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	ath9k-devel-xDcbHBWguxHbcTqmT+pZeQ, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <m3wpg52hii.fsf-5rrSNkU2MPirDJvtcaxF/A@public.gmane.org>

Krzysztof wrote:
> Hi,
> 
> I recently tried to select a single antenna on AR9300 and it works for
> 30 seconds only. The subsequent calibration makes the RX signal level to
> drop from the usual -30/-40 dBm to -70/-80 dBm, and the transmission
> practically stops.
> 
> With the attached patch it works, though selecting the antenna doesn't
> seem to have any visible effect, at least with "iw wlanX station dump"
> (perhaps it works for TX).
> 
> I'm using ad-hoc mode:
> 
> rmmod ath9k
> modprobe ath9k
> iw dev wlan0 set type ibss
> iw phy phyX set antenna 2
> ip link set up dev wlan0
> iw dev wlan0 set bitrates legacy-2.4 18
> iw dev wlan0 ibss join nameXXX freqYYY
> ip addr add ZZZ broadcast + dev wlan0
> 
> The card in question is Mikrotik (Routerboard) R11e-2HPnD mPCIe adapter:
> AR9580 Wireless Network Adapter (rev 01), ID 168c:0033, subsystem
> 19b6:d016.
> ieee80211 phy0: Atheros AR9300 Rev:4 mem=0xc0f40000, irq=334
> https://routerboard.com/R11e-2HPnD
> 
> Linux 4.9.0-rc5.
> 
> 
> Is there a better way?
> 
> Signed-off-by: Krzysztof Halasa <khalasa-NlWvg49iv0c@public.gmane.org>
> 
> diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
> index e9f32b5..7f17e5d 100644
> --- a/drivers/net/wireless/ath/ath9k/main.c
> +++ b/drivers/net/wireless/ath/ath9k/main.c
> @@ -2245,7 +2245,7 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
>  		return 0;
>  
>  	/* AR9100 runs into calibration issues if not all rx chains are enabled */
> -	if (AR_SREV_9100(ah))
> +	if (AR_SREV_9100(ah) || AR_SREV_9300(ah))
>  		ah->rxchainmask = 0x7;
>  	else
>  		ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);

I'll assume this is an RFC patch. Please resubmit if this is the right
approach.

Patch set to RFC.

-- 
https://patchwork.kernel.org/patch/9429263/

Documentation about submitting wireless patches and checking status
from patchwork:

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply

* Re: [PATCH nf-next,RFC] netfilter: nft_meta: add cgroup version 2 support
From: Pablo Neira Ayuso @ 2016-11-17 11:02 UTC (permalink / raw)
  To: Daniel Mack
  Cc: netfilter-devel-u79uwXL29TY76Z2rM5mHXA, htejun-b10kYP2dOMg,
	cgroups-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <e4e0bc59-5a97-118b-2d4e-af12c2055e7e-cYrQPVfZoowdnm+yROfE0A@public.gmane.org>

Hi Daniel,

On Mon, Nov 14, 2016 at 11:10:04AM +0100, Daniel Mack wrote:
[...]
> On 11/14/2016 10:12 AM, Pablo Neira Ayuso wrote:
> > Add cgroup version 2 support to nf_tables.
> > 
> > This extension allows us to fetch the cgroup i-node number from the
> > cgroup socket data, place it in a register, then match it against any
> > value specified by user. This approach scales up nicely since it
> > integrates well in the existing nf_tables map infrastructure.
> > 
> > Contrary to what iptables cgroup v2 match does, this patch doesn't use
> > cgroup_is_descendant() because this call cannot guarantee that the cgroup
> > hierarchy is honored in anyway given that the cgroup v2 field becomes yet
> > another packet selector that you can use to build your filtering policy.
> > 
> > Actually, using the i-node approach, it should be easy to build a policy
> > that honors the hierarchy if you need this, eg.
> > 
> > 	meta cgroup2 vmap { "/A/B" : jump b-cgroup-chain,
> > 			    "/A/C" : jump c-cgroup-chain,
> > 			    "/A" : jump a-cgroup-chain }
> > 
> > then, the b-cgroup-chain looks like:
> > 
> > 	jump a-cgroup-chain
> > 	... # specific policy b-cgroup-chain goes here
> > 
> > similarly, the c-cgroup-chain looks like:
> > 
> > 	jump a-cgroup-chain
> > 	... # specific policy c-cgroup-chain goes here
> > 
> > So both B and C would evaluate A's ruleset. Note that cgroup A would
> > also jump to the root cgroup chain policy.
> > 
> > Anyway, this cgroup i-node approach provides way more flexibility since
> > it is up to the sysadmin to decide if he wants to honor the hierarchy or
> > simply define a fast path to skip any further classification.
> 
> I don't think this can work. The problem is that inodes in cgroupfs are
> dynamically allocated when a cgroup is created, so the sysadmin cannot
> install the jump rules before that. Worse yet, inode numbers in pseudo
> filesystems are recycled, so if a cgroup goes away and a new one is
> created, the latter may well end up having the same inode than the old
> one.
>
> As cgroupfs decoupled from netfilter tables, this will lead to
> major chaos in the field.

Do you really want tight coupling? Look:

 # mkdir /tmp/x
 # mount -t cgroup2 none /tmp/x
 # mkdir /tmp/x/x
 # echo 0 > /tmp/x/x/cgroup.procs
 # iptables -I INPUT -m cgroup --path "/"
 # iptables -I INPUT -m cgroup --path "/x"
 # rmdir /tmp/x/x/
 rmdir: failed to remove '/tmp/x/x/': Device or resource busy

As soon as there is a filtering policy in iptables, you cannot update
cgroups. However, if you adopt a decoupled approach, you can update
both sides anytime.

Following the decoupled approach: If the cgroup is gone, the filtering
policy would not match anymore. You only have to subscribe to events
and perform an incremental updates to tear down the side of the
filtering policy that you don't need anymore. If a new cgroup is
created, you load the filtering policy for the new cgroup and then add
processes to that cgroup. You only have to follow the right sequence
to avoid problems.

> Note that this was different with the netclass controller in v1 that
> would assign a user-controlled numeric value to each cgroup, so both
> sides were in the control of the sysadmin. It is also different with the
> path matching logic for v2 which does a full path string comparison.
> That's potentially expensive, it does lead to predictable runtime behavior.
> 
> One way forward here would be to assign a atomically increasing 64-bit
> sequence number to each cgroup and expose that. I've recently talked to
> Tejun about that. While that won't solve the predictability issue, it
> would at least make it practically impossible to have re-used IDs.

OK, so we need to make sure the ID is unique, an incremental ID should
be fine. Probably the idr logic can be replaced by this new ID.  The
tuple [ directory-name, id ] should be enough to uniquely identify a
cgroup so it may be 32-bits after all, unless you think chances that
we get the same directory-name and id is high, then avoid wraparounds
via 64-bits.

> Anyway - I think it would be great to have an alternative to the v2 path
> matching here, but of course this patch does not solve the ingress issue
> we've been discussing. It is still impossible to reliably determine the
> cgroup of a local receiver at the time when the netfilter rules are
> processed, even for unicast packets.

This is right if we rely on early demux, however we have explicit
socket lookups in netfilter that we can reuse, see
nf_sk_lookup_slow_v{4,6}() in nf-next. This would actually allow us to
filter very early for the vast majority of usecases, using any
combination of selectors, not only focusing this specifically on
cgroups. This infrastructure supports UDP and TCP which is good start.

The problem is specifically the many-cast socket path. Actually, if
one single listener is available and the udp_hash2 chain is not too
long we already get the destination via early_demux, so that path is
already covered. The problem is the many-cast usecase with long chains
(this we could trigger a longer lookup only from netfilter, only for
people willing to filter packets) and the two-or-more many-cast socket
listener destinations for UDP. Do you really need accounting for the
many-cast case too?

Attaching several socket destinations to skbuff is a tricky, as we
would need new specific infrastructure, something like a socket
container object that keeps a list of destination sockets, all of them
holding a reference to these socket which may be expensive. Another
option is a specific many-cast input hook following the
__udp4_lib_mcast_deliver() path. Any solution for many-cast filtering
is going to be expensive.

^ permalink raw reply

* [patch] amd-xgbe: Signedness bug in xgbe_phy_link_status()
From: Dan Carpenter @ 2016-11-17 10:59 UTC (permalink / raw)
  To: Tom Lendacky; +Cc: netdev, kernel-janitors

"ret" needs to be signed for the error handling to work.

Fixes: abf0a1c2b26a ("amd-xgbe: Add support for SFP+ modules")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>

diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
index 4ba4332..a2559c2 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
@@ -2346,7 +2346,8 @@ static bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed)
 static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
 {
 	struct xgbe_phy_data *phy_data = pdata->phy_data;
-	unsigned int ret, reg;
+	unsigned int reg;
+	int ret;
 
 	*an_restart = 0;
 

^ permalink raw reply related

* Re: net/l2tp:BUG: KASAN: use-after-free in l2tp_ip6_close
From: Baozeng Ding @ 2016-11-17 10:56 UTC (permalink / raw)
  To: Guillaume Nault, Cong Wang; +Cc: Linux Kernel Network Developers
In-Reply-To: <20161116210741.zqair4zkkzscdfe5@alphalink.fr>


Hello Guillaume,
On 2016/11/17 5:07, Guillaume Nault wrote:
> On Wed, Nov 16, 2016 at 11:08:23AM -0800, Cong Wang wrote:
>> On Wed, Nov 16, 2016 at 8:30 AM, Guillaume Nault <g.nault@alphalink.fr> wrote:
>>> diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
>>> index fce25af..982f6c4 100644
>>> --- a/net/l2tp/l2tp_ip.c
>>> +++ b/net/l2tp/l2tp_ip.c
>>> @@ -251,8 +251,6 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
>>>         int ret;
>>>         int chk_addr_ret;
>>>
>>> -       if (!sock_flag(sk, SOCK_ZAPPED))
>>> -               return -EINVAL;
>>>         if (addr_len < sizeof(struct sockaddr_l2tpip))
>>>                 return -EINVAL;
>>>         if (addr->l2tp_family != AF_INET)
>>> @@ -267,6 +265,9 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
>>>         read_unlock_bh(&l2tp_ip_lock);
>>>
>>>         lock_sock(sk);
>>> +       if (!sock_flag(sk, SOCK_ZAPPED))
>>> +               goto out;
>>> +
>>>         if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_l2tpip))
>>>                 goto out;
>>>
>>> diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
>>> index ad3468c..9978d01 100644
>>> --- a/net/l2tp/l2tp_ip6.c
>>> +++ b/net/l2tp/l2tp_ip6.c
>>> @@ -269,8 +269,6 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
>>>         int addr_type;
>>>         int err;
>>>
>>> -       if (!sock_flag(sk, SOCK_ZAPPED))
>>> -               return -EINVAL;
>>>         if (addr->l2tp_family != AF_INET6)
>>>                 return -EINVAL;
>>>         if (addr_len < sizeof(*addr))
>>> @@ -296,6 +294,9 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
>>>         lock_sock(sk);
>>>
>>>         err = -EINVAL;
>>> +       if (!sock_flag(sk, SOCK_ZAPPED))
>>> +               goto out_unlock;
>>> +
>>>         if (sk->sk_state != TCP_CLOSE)
>>>                 goto out_unlock;
>>
>>
>> Makes sense, it should prevent a concurrent caller adding the socket
>> into bind table
>> twice after passing __l2tp_ip_bind_lookup() check.
> 
> Yes, and the __l2tp_ip_bind_lookup() call is also racy. But, by
> properly checking the SOCK_ZAPPED flag, we probably can remove this
> call entirely.
> 
> For now, I only wanted to make sure the issue was well identified. I'll
> submit a more complete patch for net (with protected SOCK_ZAPPED check
> in l2tp_ip_connect() too).
>
The patch fixes the issues both for l2tp_ip and l2tp_ip6

Tested-by: Baozeng Ding <sploving1@gmail.com>


Best Regards,
Baozeng Ding

^ permalink raw reply

* [PATCH net-next 5/5] sfc: remove Software TSO
From: Edward Cree @ 2016-11-17 10:52 UTC (permalink / raw)
  To: linux-net-drivers, davem; +Cc: bkenward, netdev
In-Reply-To: <ae6b02ca-9a0b-7072-6914-294fc9adb684@solarflare.com>

It gives no advantage over GSO now that xmit_more exists.  If we find
 ourselves unable to handle a TSO skb (because our TXQ doesn't have a
 TSOv2 context and the NIC doesn't support TSOv1), hand it back to GSO.
 Also do that if the TSO handler fails with EINVAL for any other reason.
As Falcon-architecture NICs don't support any firmware-assisted TSO,
 they no longer advertise TSO feature flags at all.

Signed-off-by: Edward Cree <ecree@solarflare.com>
---
 drivers/net/ethernet/sfc/ef10.c       |  15 ++
 drivers/net/ethernet/sfc/efx.c        |  38 ++---
 drivers/net/ethernet/sfc/ethtool.c    |   1 +
 drivers/net/ethernet/sfc/net_driver.h |   5 +
 drivers/net/ethernet/sfc/tx.c         |  46 +++++-
 drivers/net/ethernet/sfc/tx_tso.c     | 260 ++++++++++------------------------
 6 files changed, 154 insertions(+), 211 deletions(-)

diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index 9cbe573..0f58ea8 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -2158,6 +2158,20 @@ static int efx_ef10_tx_tso_desc(struct efx_tx_queue *tx_queue,
 	return 0;
 }
 
+static u32 efx_ef10_tso_versions(struct efx_nic *efx)
+{
+	struct efx_ef10_nic_data *nic_data = efx->nic_data;
+	u32 tso_versions = 0;
+
+	if (nic_data->datapath_caps &
+	    (1 << MC_CMD_GET_CAPABILITIES_OUT_TX_TSO_LBN))
+		tso_versions |= BIT(1);
+	if (nic_data->datapath_caps2 &
+	    (1 << MC_CMD_GET_CAPABILITIES_V2_OUT_TX_TSO_V2_LBN))
+		tso_versions |= BIT(2);
+	return tso_versions;
+}
+
 static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
 {
 	MCDI_DECLARE_BUF(inbuf, MC_CMD_INIT_TXQ_IN_LEN(EFX_MAX_DMAQ_SIZE * 8 /
@@ -5759,6 +5773,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
 #endif
 	.get_mac_address = efx_ef10_get_mac_address_pf,
 	.set_mac_address = efx_ef10_set_mac_address,
+	.tso_versions = efx_ef10_tso_versions,
 
 	.revision = EFX_REV_HUNT_A0,
 	.max_dma_mask = DMA_BIT_MASK(ESF_DZ_TX_KER_BUF_ADDR_WIDTH),
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 52ca040..756a0964 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -3200,23 +3200,6 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
 	efx = netdev_priv(net_dev);
 	efx->type = (const struct efx_nic_type *) entry->driver_data;
 	efx->fixed_features |= NETIF_F_HIGHDMA;
-	net_dev->features |= (efx->type->offload_features | NETIF_F_SG |
-			      NETIF_F_TSO | NETIF_F_RXCSUM);
-	if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
-		net_dev->features |= NETIF_F_TSO6;
-	/* Mask for features that also apply to VLAN devices */
-	net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG |
-				   NETIF_F_HIGHDMA | NETIF_F_ALL_TSO |
-				   NETIF_F_RXCSUM);
-
-	net_dev->hw_features = net_dev->features & ~efx->fixed_features;
-
-	/* Disable VLAN filtering by default.  It may be enforced if
-	 * the feature is fixed (i.e. VLAN filters are required to
-	 * receive VLAN tagged packets due to vPort restrictions).
-	 */
-	net_dev->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
-	net_dev->features |= efx->fixed_features;
 
 	pci_set_drvdata(pci_dev, efx);
 	SET_NETDEV_DEV(net_dev, &pci_dev->dev);
@@ -3239,6 +3222,27 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
 	if (rc)
 		goto fail3;
 
+	net_dev->features |= (efx->type->offload_features | NETIF_F_SG |
+			      NETIF_F_TSO | NETIF_F_RXCSUM);
+	if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
+		net_dev->features |= NETIF_F_TSO6;
+	/* Check whether device supports TSO */
+	if (!efx->type->tso_versions || !efx->type->tso_versions(efx))
+		net_dev->features &= ~NETIF_F_ALL_TSO;
+	/* Mask for features that also apply to VLAN devices */
+	net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG |
+				   NETIF_F_HIGHDMA | NETIF_F_ALL_TSO |
+				   NETIF_F_RXCSUM);
+
+	net_dev->hw_features = net_dev->features & ~efx->fixed_features;
+
+	/* Disable VLAN filtering by default.  It may be enforced if
+	 * the feature is fixed (i.e. VLAN filters are required to
+	 * receive VLAN tagged packets due to vPort restrictions).
+	 */
+	net_dev->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
+	net_dev->features |= efx->fixed_features;
+
 	rc = efx_register_netdev(efx);
 	if (rc)
 		goto fail4;
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index bd5edd6..740cdf0 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -69,6 +69,7 @@ static const struct efx_sw_stat_desc efx_sw_stat_desc[] = {
 	EFX_ETHTOOL_UINT_TXQ_STAT(tso_bursts),
 	EFX_ETHTOOL_UINT_TXQ_STAT(tso_long_headers),
 	EFX_ETHTOOL_UINT_TXQ_STAT(tso_packets),
+	EFX_ETHTOOL_UINT_TXQ_STAT(tso_fallbacks),
 	EFX_ETHTOOL_UINT_TXQ_STAT(pushes),
 	EFX_ETHTOOL_UINT_TXQ_STAT(pio_packets),
 	EFX_ETHTOOL_UINT_TXQ_STAT(cb_packets),
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 2da3e8f..f97f828 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -225,6 +225,7 @@ struct efx_tx_buffer {
  * @tso_long_headers: Number of packets with headers too long for standard
  *	blocks
  * @tso_packets: Number of packets via the TSO xmit path
+ * @tso_fallbacks: Number of times TSO fallback used
  * @pushes: Number of times the TX push feature has been used
  * @pio_packets: Number of times the TX PIO feature has been used
  * @xmit_more_available: Are any packets waiting to be pushed to the NIC
@@ -266,6 +267,7 @@ struct efx_tx_queue {
 	unsigned int tso_bursts;
 	unsigned int tso_long_headers;
 	unsigned int tso_packets;
+	unsigned int tso_fallbacks;
 	unsigned int pushes;
 	unsigned int pio_packets;
 	bool xmit_more_available;
@@ -1225,6 +1227,8 @@ struct efx_mtd_partition {
  *	and tx_type will already have been validated but this operation
  *	must validate and update rx_filter.
  * @set_mac_address: Set the MAC address of the device
+ * @tso_versions: Returns mask of firmware-assisted TSO versions supported.
+ *	If %NULL, then device does not support any TSO version.
  * @revision: Hardware architecture revision
  * @txd_ptr_tbl_base: TX descriptor ring base address
  * @rxd_ptr_tbl_base: RX descriptor ring base address
@@ -1381,6 +1385,7 @@ struct efx_nic_type {
 	void (*vswitching_remove)(struct efx_nic *efx);
 	int (*get_mac_address)(struct efx_nic *efx, unsigned char *perm_addr);
 	int (*set_mac_address)(struct efx_nic *efx);
+	u32 (*tso_versions)(struct efx_nic *efx);
 
 	int revision;
 	unsigned int txd_ptr_tbl_base;
diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c
index 3089e88..1aa728c 100644
--- a/drivers/net/ethernet/sfc/tx.c
+++ b/drivers/net/ethernet/sfc/tx.c
@@ -446,10 +446,38 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue)
 	}
 }
 
-static int efx_tx_tso_sw(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
-			 bool *data_mapped)
+/*
+ * Fallback to software TSO.
+ *
+ * This is used if we are unable to send a GSO packet through hardware TSO.
+ * This should only ever happen due to per-queue restrictions - unsupported
+ * packets should first be filtered by the feature flags.
+ *
+ * Returns 0 on success, error code otherwise.
+ */
+static int efx_tx_tso_fallback(struct efx_tx_queue *tx_queue,
+			       struct sk_buff *skb)
 {
-	return efx_enqueue_skb_tso(tx_queue, skb, data_mapped);
+	struct sk_buff *segments, *next;
+
+	segments = skb_gso_segment(skb, 0);
+	if (IS_ERR(segments))
+		return PTR_ERR(segments);
+
+	dev_kfree_skb_any(skb);
+	skb = segments;
+
+	while (skb) {
+		next = skb->next;
+		skb->next = NULL;
+
+		if (next)
+			skb->xmit_more = true;
+		efx_enqueue_skb(tx_queue, skb);
+		skb = next;
+	}
+
+	return 0;
 }
 
 /*
@@ -473,6 +501,7 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
 	bool data_mapped = false;
 	unsigned int segments;
 	unsigned int skb_len;
+	int rc;
 
 	skb_len = skb->len;
 	segments = skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 0;
@@ -485,7 +514,14 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
 	 */
 	if (segments) {
 		EFX_BUG_ON_PARANOID(!tx_queue->handle_tso);
-		if (tx_queue->handle_tso(tx_queue, skb, &data_mapped))
+		rc = tx_queue->handle_tso(tx_queue, skb, &data_mapped);
+		if (rc == -EINVAL) {
+			rc = efx_tx_tso_fallback(tx_queue, skb);
+			tx_queue->tso_fallbacks++;
+			if (rc == 0)
+				return 0;
+		}
+		if (rc)
 			goto err;
 #ifdef EFX_USE_PIO
 	} else if (skb_len <= efx_piobuf_size && !skb->xmit_more &&
@@ -801,7 +837,7 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue)
 	/* Set up default function pointers. These may get replaced by
 	 * efx_nic_init_tx() based off NIC/queue capabilities.
 	 */
-	tx_queue->handle_tso = efx_tx_tso_sw;
+	tx_queue->handle_tso = efx_enqueue_skb_tso;
 
 	/* Some older hardware requires Tx writes larger than 32. */
 	tx_queue->tx_min_size = EFX_WORKAROUND_15592(efx) ? 33 : 0;
diff --git a/drivers/net/ethernet/sfc/tx_tso.c b/drivers/net/ethernet/sfc/tx_tso.c
index 99936d7..6032887 100644
--- a/drivers/net/ethernet/sfc/tx_tso.c
+++ b/drivers/net/ethernet/sfc/tx_tso.c
@@ -29,8 +29,7 @@
 
 /* Efx legacy TCP segmentation acceleration.
  *
- * Why?  Because by doing it here in the driver we can go significantly
- * faster than the GSO.
+ * Utilises firmware support to go faster than GSO (but not as fast as TSOv2).
  *
  * Requires TX checksum offload support.
  */
@@ -47,15 +46,13 @@
  * @in_len: Remaining length in current SKB fragment
  * @unmap_len: Length of SKB fragment
  * @unmap_addr: DMA address of SKB fragment
- * @dma_flags: TX buffer flags for DMA mapping - %EFX_TX_BUF_MAP_SINGLE or 0
  * @protocol: Network protocol (after any VLAN header)
  * @ip_off: Offset of IP header
  * @tcp_off: Offset of TCP header
  * @header_len: Number of bytes of header
  * @ip_base_len: IPv4 tot_len or IPv6 payload_len, before TCP payload
- * @header_dma_addr: Header DMA address, when using option descriptors
- * @header_unmap_len: Header DMA mapped length, or 0 if not using option
- *	descriptors
+ * @header_dma_addr: Header DMA address
+ * @header_unmap_len: Header DMA mapped length
  *
  * The state used during segmentation.  It is put into this data structure
  * just to make it easy to pass into inline functions.
@@ -72,7 +69,6 @@ struct tso_state {
 	unsigned int in_len;
 	unsigned int unmap_len;
 	dma_addr_t unmap_addr;
-	unsigned short dma_flags;
 
 	__be16 protocol;
 	unsigned int ip_off;
@@ -172,63 +168,6 @@ static __be16 efx_tso_check_protocol(struct sk_buff *skb)
 	return protocol;
 }
 
-static u8 *efx_tsoh_get_buffer(struct efx_tx_queue *tx_queue,
-			       struct efx_tx_buffer *buffer, unsigned int len)
-{
-	u8 *result;
-
-	EFX_BUG_ON_PARANOID(buffer->len);
-	EFX_BUG_ON_PARANOID(buffer->flags);
-	EFX_BUG_ON_PARANOID(buffer->unmap_len);
-
-	result = efx_tx_get_copy_buffer_limited(tx_queue, buffer, len);
-
-	if (result) {
-		buffer->flags = EFX_TX_BUF_CONT;
-	} else {
-		buffer->heap_buf = kmalloc(NET_IP_ALIGN + len, GFP_ATOMIC);
-		if (unlikely(!buffer->heap_buf))
-			return NULL;
-		tx_queue->tso_long_headers++;
-		result = (u8 *)buffer->heap_buf + NET_IP_ALIGN;
-		buffer->flags = EFX_TX_BUF_CONT | EFX_TX_BUF_HEAP;
-	}
-
-	buffer->len = len;
-
-	return result;
-}
-
-/*
- * Put a TSO header into the TX queue.
- *
- * This is special-cased because we know that it is small enough to fit in
- * a single fragment, and we know it doesn't cross a page boundary.  It
- * also allows us to not worry about end-of-packet etc.
- */
-static int efx_tso_put_header(struct efx_tx_queue *tx_queue,
-			      struct efx_tx_buffer *buffer, u8 *header)
-{
-	if (unlikely(buffer->flags & EFX_TX_BUF_HEAP)) {
-		buffer->dma_addr = dma_map_single(&tx_queue->efx->pci_dev->dev,
-						  header, buffer->len,
-						  DMA_TO_DEVICE);
-		if (unlikely(dma_mapping_error(&tx_queue->efx->pci_dev->dev,
-					       buffer->dma_addr))) {
-			kfree(buffer->heap_buf);
-			buffer->len = 0;
-			buffer->flags = 0;
-			return -ENOMEM;
-		}
-		buffer->unmap_len = buffer->len;
-		buffer->dma_offset = 0;
-		buffer->flags |= EFX_TX_BUF_MAP_SINGLE;
-	}
-
-	++tx_queue->insert_count;
-	return 0;
-}
-
 
 /* Parse the SKB header and initialise state. */
 static int tso_start(struct tso_state *st, struct efx_nic *efx,
@@ -237,12 +176,8 @@ static int tso_start(struct tso_state *st, struct efx_nic *efx,
 {
 	struct device *dma_dev = &efx->pci_dev->dev;
 	unsigned int header_len, in_len;
-	bool use_opt_desc = false;
 	dma_addr_t dma_addr;
 
-	if (tx_queue->tso_version == 1)
-		use_opt_desc = true;
-
 	st->ip_off = skb_network_header(skb) - skb->data;
 	st->tcp_off = skb_transport_header(skb) - skb->data;
 	header_len = st->tcp_off + (tcp_hdr(skb)->doff << 2u);
@@ -264,30 +199,12 @@ static int tso_start(struct tso_state *st, struct efx_nic *efx,
 
 	st->out_len = skb->len - header_len;
 
-	if (!use_opt_desc) {
-		st->header_unmap_len = 0;
-
-		if (likely(in_len == 0)) {
-			st->dma_flags = 0;
-			st->unmap_len = 0;
-			return 0;
-		}
-
-		dma_addr = dma_map_single(dma_dev, skb->data + header_len,
-					  in_len, DMA_TO_DEVICE);
-		st->dma_flags = EFX_TX_BUF_MAP_SINGLE;
-		st->dma_addr = dma_addr;
-		st->unmap_addr = dma_addr;
-		st->unmap_len = in_len;
-	} else {
-		dma_addr = dma_map_single(dma_dev, skb->data,
-					  skb_headlen(skb), DMA_TO_DEVICE);
-		st->header_dma_addr = dma_addr;
-		st->header_unmap_len = skb_headlen(skb);
-		st->dma_flags = 0;
-		st->dma_addr = dma_addr + header_len;
-		st->unmap_len = 0;
-	}
+	dma_addr = dma_map_single(dma_dev, skb->data,
+				  skb_headlen(skb), DMA_TO_DEVICE);
+	st->header_dma_addr = dma_addr;
+	st->header_unmap_len = skb_headlen(skb);
+	st->dma_addr = dma_addr + header_len;
+	st->unmap_len = 0;
 
 	return unlikely(dma_mapping_error(dma_dev, dma_addr)) ? -ENOMEM : 0;
 }
@@ -298,7 +215,6 @@ static int tso_get_fragment(struct tso_state *st, struct efx_nic *efx,
 	st->unmap_addr = skb_frag_dma_map(&efx->pci_dev->dev, frag, 0,
 					  skb_frag_size(frag), DMA_TO_DEVICE);
 	if (likely(!dma_mapping_error(&efx->pci_dev->dev, st->unmap_addr))) {
-		st->dma_flags = 0;
 		st->unmap_len = skb_frag_size(frag);
 		st->in_len = skb_frag_size(frag);
 		st->dma_addr = st->unmap_addr;
@@ -352,7 +268,6 @@ static void tso_fill_packet_with_fragment(struct efx_tx_queue *tx_queue,
 		/* Transfer ownership of the DMA mapping */
 		buffer->unmap_len = st->unmap_len;
 		buffer->dma_offset = buffer->unmap_len - buffer->len;
-		buffer->flags |= st->dma_flags;
 		st->unmap_len = 0;
 	}
 
@@ -369,7 +284,7 @@ static void tso_fill_packet_with_fragment(struct efx_tx_queue *tx_queue,
  * @st:			TSO state
  *
  * Generate a new header and prepare for the new packet.  Return 0 on
- * success, or -%ENOMEM if failed to alloc header.
+ * success, or -%ENOMEM if failed to alloc header, or other negative error.
  */
 static int tso_start_new_packet(struct efx_tx_queue *tx_queue,
 				const struct sk_buff *skb,
@@ -378,7 +293,7 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue,
 	struct efx_tx_buffer *buffer =
 		efx_tx_queue_get_insert_buffer(tx_queue);
 	bool is_last = st->out_len <= skb_shinfo(skb)->gso_size;
-	u8 tcp_flags_mask;
+	u8 tcp_flags_mask, tcp_flags;
 
 	if (!is_last) {
 		st->packet_space = skb_shinfo(skb)->gso_size;
@@ -388,82 +303,44 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue,
 		tcp_flags_mask = 0x00;
 	}
 
-	if (!st->header_unmap_len) {
-		/* Allocate and insert a DMA-mapped header buffer. */
-		struct tcphdr *tsoh_th;
-		unsigned int ip_length;
-		u8 *header;
-		int rc;
-
-		header = efx_tsoh_get_buffer(tx_queue, buffer, st->header_len);
-		if (!header)
-			return -ENOMEM;
-
-		tsoh_th = (struct tcphdr *)(header + st->tcp_off);
-
-		/* Copy and update the headers. */
-		memcpy(header, skb->data, st->header_len);
-
-		tsoh_th->seq = htonl(st->seqnum);
-		((u8 *)tsoh_th)[TCP_FLAGS_OFFSET] &= ~tcp_flags_mask;
-
-		ip_length = st->ip_base_len + st->packet_space;
-
-		if (st->protocol == htons(ETH_P_IP)) {
-			struct iphdr *tsoh_iph =
-				(struct iphdr *)(header + st->ip_off);
-
-			tsoh_iph->tot_len = htons(ip_length);
-			tsoh_iph->id = htons(st->ipv4_id);
-		} else {
-			struct ipv6hdr *tsoh_iph =
-				(struct ipv6hdr *)(header + st->ip_off);
-
-			tsoh_iph->payload_len = htons(ip_length);
-		}
+	if (WARN_ON(!st->header_unmap_len))
+		return -EINVAL;
+	/* Send the original headers with a TSO option descriptor
+	 * in front
+	 */
+	tcp_flags = ((u8 *)tcp_hdr(skb))[TCP_FLAGS_OFFSET] & ~tcp_flags_mask;
+
+	buffer->flags = EFX_TX_BUF_OPTION;
+	buffer->len = 0;
+	buffer->unmap_len = 0;
+	EFX_POPULATE_QWORD_5(buffer->option,
+			     ESF_DZ_TX_DESC_IS_OPT, 1,
+			     ESF_DZ_TX_OPTION_TYPE,
+			     ESE_DZ_TX_OPTION_DESC_TSO,
+			     ESF_DZ_TX_TSO_TCP_FLAGS, tcp_flags,
+			     ESF_DZ_TX_TSO_IP_ID, st->ipv4_id,
+			     ESF_DZ_TX_TSO_TCP_SEQNO, st->seqnum);
+	++tx_queue->insert_count;
 
-		rc = efx_tso_put_header(tx_queue, buffer, header);
-		if (unlikely(rc))
-			return rc;
-	} else {
-		/* Send the original headers with a TSO option descriptor
-		 * in front
+	/* We mapped the headers in tso_start().  Unmap them
+	 * when the last segment is completed.
+	 */
+	buffer = efx_tx_queue_get_insert_buffer(tx_queue);
+	buffer->dma_addr = st->header_dma_addr;
+	buffer->len = st->header_len;
+	if (is_last) {
+		buffer->flags = EFX_TX_BUF_CONT | EFX_TX_BUF_MAP_SINGLE;
+		buffer->unmap_len = st->header_unmap_len;
+		buffer->dma_offset = 0;
+		/* Ensure we only unmap them once in case of a
+		 * later DMA mapping error and rollback
 		 */
-		u8 tcp_flags = ((u8 *)tcp_hdr(skb))[TCP_FLAGS_OFFSET] &
-				~tcp_flags_mask;
-
-		buffer->flags = EFX_TX_BUF_OPTION;
-		buffer->len = 0;
+		st->header_unmap_len = 0;
+	} else {
+		buffer->flags = EFX_TX_BUF_CONT;
 		buffer->unmap_len = 0;
-		EFX_POPULATE_QWORD_5(buffer->option,
-				     ESF_DZ_TX_DESC_IS_OPT, 1,
-				     ESF_DZ_TX_OPTION_TYPE,
-				     ESE_DZ_TX_OPTION_DESC_TSO,
-				     ESF_DZ_TX_TSO_TCP_FLAGS, tcp_flags,
-				     ESF_DZ_TX_TSO_IP_ID, st->ipv4_id,
-				     ESF_DZ_TX_TSO_TCP_SEQNO, st->seqnum);
-		++tx_queue->insert_count;
-
-		/* We mapped the headers in tso_start().  Unmap them
-		 * when the last segment is completed.
-		 */
-		buffer = efx_tx_queue_get_insert_buffer(tx_queue);
-		buffer->dma_addr = st->header_dma_addr;
-		buffer->len = st->header_len;
-		if (is_last) {
-			buffer->flags = EFX_TX_BUF_CONT | EFX_TX_BUF_MAP_SINGLE;
-			buffer->unmap_len = st->header_unmap_len;
-			buffer->dma_offset = 0;
-			/* Ensure we only unmap them once in case of a
-			 * later DMA mapping error and rollback
-			 */
-			st->header_unmap_len = 0;
-		} else {
-			buffer->flags = EFX_TX_BUF_CONT;
-			buffer->unmap_len = 0;
-		}
-		++tx_queue->insert_count;
 	}
+	++tx_queue->insert_count;
 
 	st->seqnum += skb_shinfo(skb)->gso_size;
 
@@ -483,8 +360,8 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue,
  * Context: You must hold netif_tx_lock() to call this function.
  *
  * Add socket buffer @skb to @tx_queue, doing TSO or return != 0 if
- * @skb was not enqueued.  In all cases @skb is consumed.  Return
- * %NETDEV_TX_OK.
+ * @skb was not enqueued.  @skb is consumed unless return value is
+ * %EINVAL.
  */
 int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
 			struct sk_buff *skb,
@@ -494,6 +371,9 @@ int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
 	int frag_i, rc;
 	struct tso_state state;
 
+	if (tx_queue->tso_version != 1)
+		return -EINVAL;
+
 	prefetch(skb->data);
 
 	/* Find the packet protocol and sanity-check it */
@@ -503,7 +383,7 @@ int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
 
 	rc = tso_start(&state, efx, tx_queue, skb);
 	if (rc)
-		goto mem_err;
+		goto fail;
 
 	if (likely(state.in_len == 0)) {
 		/* Grab the first payload fragment. */
@@ -512,14 +392,15 @@ int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
 		rc = tso_get_fragment(&state, efx,
 				      skb_shinfo(skb)->frags + frag_i);
 		if (rc)
-			goto mem_err;
+			goto fail;
 	} else {
 		/* Payload starts in the header area. */
 		frag_i = -1;
 	}
 
-	if (tso_start_new_packet(tx_queue, skb, &state) < 0)
-		goto mem_err;
+	rc = tso_start_new_packet(tx_queue, skb, &state);
+	if (rc)
+		goto fail;
 
 	prefetch_ptr(tx_queue);
 
@@ -534,37 +415,38 @@ int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
 			rc = tso_get_fragment(&state, efx,
 					      skb_shinfo(skb)->frags + frag_i);
 			if (rc)
-				goto mem_err;
+				goto fail;
 		}
 
 		/* Start at new packet? */
-		if (state.packet_space == 0 &&
-		    tso_start_new_packet(tx_queue, skb, &state) < 0)
-			goto mem_err;
+		if (state.packet_space == 0) {
+			rc = tso_start_new_packet(tx_queue, skb, &state);
+			if (rc)
+				goto fail;
+		}
 	}
 
 	*data_mapped = true;
 
 	return 0;
 
- mem_err:
-	netif_err(efx, tx_err, efx->net_dev,
-		  "Out of memory for TSO headers, or DMA mapping error\n");
+fail:
+	if (rc == -ENOMEM)
+		netif_err(efx, tx_err, efx->net_dev,
+			  "Out of memory for TSO headers, or DMA mapping error\n");
+	else
+		netif_err(efx, tx_err, efx->net_dev, "TSO failed, rc = %d\n", rc);
 
 	/* Free the DMA mapping we were in the process of writing out */
 	if (state.unmap_len) {
-		if (state.dma_flags & EFX_TX_BUF_MAP_SINGLE)
-			dma_unmap_single(&efx->pci_dev->dev, state.unmap_addr,
-					 state.unmap_len, DMA_TO_DEVICE);
-		else
-			dma_unmap_page(&efx->pci_dev->dev, state.unmap_addr,
-				       state.unmap_len, DMA_TO_DEVICE);
+		dma_unmap_page(&efx->pci_dev->dev, state.unmap_addr,
+			       state.unmap_len, DMA_TO_DEVICE);
 	}
 
-	/* Free the header DMA mapping, if using option descriptors */
+	/* Free the header DMA mapping */
 	if (state.header_unmap_len)
 		dma_unmap_single(&efx->pci_dev->dev, state.header_dma_addr,
 				 state.header_unmap_len, DMA_TO_DEVICE);
 
-	return -ENOMEM;
+	return rc;
 }

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox