diff options
Diffstat (limited to 'drivers/net/ethernet/broadcom')
18 files changed, 649 insertions, 223 deletions
| diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index f8a168b73307..cb88ffb8f12f 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -54,7 +54,7 @@ config B44_PCI  config BCM4908_ENET  	tristate "Broadcom BCM4908 internal mac support"  	depends on ARCH_BCM4908 || COMPILE_TEST -	default y +	default y if ARCH_BCM4908  	help  	  This driver supports Ethernet controller integrated into Broadcom  	  BCM4908 family SoCs. diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c index 98cf82dea3e4..60d908507f51 100644 --- a/drivers/net/ethernet/broadcom/bcm4908_enet.c +++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c @@ -9,6 +9,7 @@  #include <linux/interrupt.h>  #include <linux/module.h>  #include <linux/of.h> +#include <linux/of_net.h>  #include <linux/platform_device.h>  #include <linux/slab.h>  #include <linux/string.h> @@ -53,6 +54,7 @@ struct bcm4908_enet_dma_ring {  	int length;  	u16 cfg_block;  	u16 st_ram_block; +	struct napi_struct napi;  	union {  		void *cpu_addr; @@ -66,8 +68,8 @@ struct bcm4908_enet_dma_ring {  struct bcm4908_enet {  	struct device *dev;  	struct net_device *netdev; -	struct napi_struct napi;  	void __iomem *base; +	int irq_tx;  	struct bcm4908_enet_dma_ring tx_ring;  	struct bcm4908_enet_dma_ring rx_ring; @@ -122,24 +124,31 @@ static void enet_umac_set(struct bcm4908_enet *enet, u16 offset, u32 set)   * Helpers   */ -static void bcm4908_enet_intrs_on(struct bcm4908_enet *enet) +static void bcm4908_enet_set_mtu(struct bcm4908_enet *enet, int mtu)  { -	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_MASK, ENET_DMA_INT_DEFAULTS); +	enet_umac_write(enet, UMAC_MAX_FRAME_LEN, mtu + ENET_MAX_ETH_OVERHEAD);  } -static void bcm4908_enet_intrs_off(struct bcm4908_enet *enet) +/*** + * DMA ring ops + */ + +static void bcm4908_enet_dma_ring_intrs_on(struct bcm4908_enet *enet, +					   struct bcm4908_enet_dma_ring *ring)  { -	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_MASK, 0); +	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG_INT_MASK, ENET_DMA_INT_DEFAULTS);  } -static void bcm4908_enet_intrs_ack(struct bcm4908_enet *enet) +static void bcm4908_enet_dma_ring_intrs_off(struct bcm4908_enet *enet, +					    struct bcm4908_enet_dma_ring *ring)  { -	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_STAT, ENET_DMA_INT_DEFAULTS); +	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG_INT_MASK, 0);  } -static void bcm4908_enet_set_mtu(struct bcm4908_enet *enet, int mtu) +static void bcm4908_enet_dma_ring_intrs_ack(struct bcm4908_enet *enet, +					    struct bcm4908_enet_dma_ring *ring)  { -	enet_umac_write(enet, UMAC_MAX_FRAME_LEN, mtu + ENET_MAX_ETH_OVERHEAD); +	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG_INT_STAT, ENET_DMA_INT_DEFAULTS);  }  /*** @@ -172,6 +181,7 @@ static int bcm4908_dma_alloc_buf_descs(struct bcm4908_enet *enet,  err_free_buf_descs:  	dma_free_coherent(dev, size, ring->cpu_addr, ring->dma_addr); +	ring->cpu_addr = NULL;  	return -ENOMEM;  } @@ -413,11 +423,14 @@ static void bcm4908_enet_gmac_init(struct bcm4908_enet *enet)  static irqreturn_t bcm4908_enet_irq_handler(int irq, void *dev_id)  {  	struct bcm4908_enet *enet = dev_id; +	struct bcm4908_enet_dma_ring *ring; -	bcm4908_enet_intrs_off(enet); -	bcm4908_enet_intrs_ack(enet); +	ring = (irq == enet->irq_tx) ? &enet->tx_ring : &enet->rx_ring; -	napi_schedule(&enet->napi); +	bcm4908_enet_dma_ring_intrs_off(enet, ring); +	bcm4908_enet_dma_ring_intrs_ack(enet, ring); + +	napi_schedule(&ring->napi);  	return IRQ_HANDLED;  } @@ -425,6 +438,8 @@ static irqreturn_t bcm4908_enet_irq_handler(int irq, void *dev_id)  static int bcm4908_enet_open(struct net_device *netdev)  {  	struct bcm4908_enet *enet = netdev_priv(netdev); +	struct bcm4908_enet_dma_ring *tx_ring = &enet->tx_ring; +	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;  	struct device *dev = enet->dev;  	int err; @@ -434,6 +449,17 @@ static int bcm4908_enet_open(struct net_device *netdev)  		return err;  	} +	if (enet->irq_tx > 0) { +		err = request_irq(enet->irq_tx, bcm4908_enet_irq_handler, 0, +				  "tx", enet); +		if (err) { +			dev_err(dev, "Failed to request IRQ %d: %d\n", +				enet->irq_tx, err); +			free_irq(netdev->irq, enet); +			return err; +		} +	} +  	bcm4908_enet_gmac_init(enet);  	bcm4908_enet_dma_reset(enet);  	bcm4908_enet_dma_init(enet); @@ -442,14 +468,19 @@ static int bcm4908_enet_open(struct net_device *netdev)  	enet_set(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN);  	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_FLOWC_CH1_EN, 0); -	bcm4908_enet_dma_rx_ring_enable(enet, &enet->rx_ring); -	napi_enable(&enet->napi); +	if (enet->irq_tx > 0) { +		napi_enable(&tx_ring->napi); +		bcm4908_enet_dma_ring_intrs_ack(enet, tx_ring); +		bcm4908_enet_dma_ring_intrs_on(enet, tx_ring); +	} + +	bcm4908_enet_dma_rx_ring_enable(enet, rx_ring); +	napi_enable(&rx_ring->napi);  	netif_carrier_on(netdev);  	netif_start_queue(netdev); - -	bcm4908_enet_intrs_ack(enet); -	bcm4908_enet_intrs_on(enet); +	bcm4908_enet_dma_ring_intrs_ack(enet, rx_ring); +	bcm4908_enet_dma_ring_intrs_on(enet, rx_ring);  	return 0;  } @@ -457,16 +488,20 @@ static int bcm4908_enet_open(struct net_device *netdev)  static int bcm4908_enet_stop(struct net_device *netdev)  {  	struct bcm4908_enet *enet = netdev_priv(netdev); +	struct bcm4908_enet_dma_ring *tx_ring = &enet->tx_ring; +	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;  	netif_stop_queue(netdev);  	netif_carrier_off(netdev); -	napi_disable(&enet->napi); +	napi_disable(&rx_ring->napi); +	napi_disable(&tx_ring->napi);  	bcm4908_enet_dma_rx_ring_disable(enet, &enet->rx_ring);  	bcm4908_enet_dma_tx_ring_disable(enet, &enet->tx_ring);  	bcm4908_enet_dma_uninit(enet); +	free_irq(enet->irq_tx, enet);  	free_irq(enet->netdev->irq, enet);  	return 0; @@ -483,25 +518,19 @@ static int bcm4908_enet_start_xmit(struct sk_buff *skb, struct net_device *netde  	u32 tmp;  	/* Free transmitted skbs */ -	while (ring->read_idx != ring->write_idx) { -		buf_desc = &ring->buf_desc[ring->read_idx]; -		if (le32_to_cpu(buf_desc->ctl) & DMA_CTL_STATUS_OWN) -			break; -		slot = &ring->slots[ring->read_idx]; - -		dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_TO_DEVICE); -		dev_kfree_skb(slot->skb); -		if (++ring->read_idx == ring->length) -			ring->read_idx = 0; -	} +	if (enet->irq_tx < 0 && +	    !(le32_to_cpu(ring->buf_desc[ring->read_idx].ctl) & DMA_CTL_STATUS_OWN)) +		napi_schedule(&enet->tx_ring.napi);  	/* Don't use the last empty buf descriptor */  	if (ring->read_idx <= ring->write_idx)  		free_buf_descs = ring->read_idx - ring->write_idx + ring->length;  	else  		free_buf_descs = ring->read_idx - ring->write_idx; -	if (free_buf_descs < 2) +	if (free_buf_descs < 2) { +		netif_stop_queue(netdev);  		return NETDEV_TX_BUSY; +	}  	/* Hardware removes OWN bit after sending data */  	buf_desc = &ring->buf_desc[ring->write_idx]; @@ -538,9 +567,10 @@ static int bcm4908_enet_start_xmit(struct sk_buff *skb, struct net_device *netde  	return NETDEV_TX_OK;  } -static int bcm4908_enet_poll(struct napi_struct *napi, int weight) +static int bcm4908_enet_poll_rx(struct napi_struct *napi, int weight)  { -	struct bcm4908_enet *enet = container_of(napi, struct bcm4908_enet, napi); +	struct bcm4908_enet_dma_ring *rx_ring = container_of(napi, struct bcm4908_enet_dma_ring, napi); +	struct bcm4908_enet *enet = container_of(rx_ring, struct bcm4908_enet, rx_ring);  	struct device *dev = enet->dev;  	int handled = 0; @@ -589,7 +619,7 @@ static int bcm4908_enet_poll(struct napi_struct *napi, int weight)  	if (handled < weight) {  		napi_complete_done(napi, handled); -		bcm4908_enet_intrs_on(enet); +		bcm4908_enet_dma_ring_intrs_on(enet, rx_ring);  	}  	/* Hardware could disable ring if it run out of descriptors */ @@ -598,6 +628,42 @@ static int bcm4908_enet_poll(struct napi_struct *napi, int weight)  	return handled;  } +static int bcm4908_enet_poll_tx(struct napi_struct *napi, int weight) +{ +	struct bcm4908_enet_dma_ring *tx_ring = container_of(napi, struct bcm4908_enet_dma_ring, napi); +	struct bcm4908_enet *enet = container_of(tx_ring, struct bcm4908_enet, tx_ring); +	struct bcm4908_enet_dma_ring_bd *buf_desc; +	struct bcm4908_enet_dma_ring_slot *slot; +	struct device *dev = enet->dev; +	unsigned int bytes = 0; +	int handled = 0; + +	while (handled < weight && tx_ring->read_idx != tx_ring->write_idx) { +		buf_desc = &tx_ring->buf_desc[tx_ring->read_idx]; +		if (le32_to_cpu(buf_desc->ctl) & DMA_CTL_STATUS_OWN) +			break; +		slot = &tx_ring->slots[tx_ring->read_idx]; + +		dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_TO_DEVICE); +		dev_kfree_skb(slot->skb); +		bytes += slot->len; +		if (++tx_ring->read_idx == tx_ring->length) +			tx_ring->read_idx = 0; + +		handled++; +	} + +	if (handled < weight) { +		napi_complete_done(napi, handled); +		bcm4908_enet_dma_ring_intrs_on(enet, tx_ring); +	} + +	if (netif_queue_stopped(enet->netdev)) +		netif_wake_queue(enet->netdev); + +	return handled; +} +  static int bcm4908_enet_change_mtu(struct net_device *netdev, int new_mtu)  {  	struct bcm4908_enet *enet = netdev_priv(netdev); @@ -640,6 +706,8 @@ static int bcm4908_enet_probe(struct platform_device *pdev)  	if (netdev->irq < 0)  		return netdev->irq; +	enet->irq_tx = platform_get_irq_byname(pdev, "tx"); +  	dma_set_coherent_mask(dev, DMA_BIT_MASK(32));  	err = bcm4908_enet_dma_alloc(enet); @@ -647,12 +715,15 @@ static int bcm4908_enet_probe(struct platform_device *pdev)  		return err;  	SET_NETDEV_DEV(netdev, &pdev->dev); -	eth_hw_addr_random(netdev); +	err = of_get_mac_address(dev->of_node, netdev->dev_addr); +	if (err) +		eth_hw_addr_random(netdev);  	netdev->netdev_ops = &bcm4908_enet_netdev_ops;  	netdev->min_mtu = ETH_ZLEN;  	netdev->mtu = ETH_DATA_LEN;  	netdev->max_mtu = ENET_MTU_MAX; -	netif_napi_add(netdev, &enet->napi, bcm4908_enet_poll, 64); +	netif_tx_napi_add(netdev, &enet->tx_ring.napi, bcm4908_enet_poll_tx, NAPI_POLL_WEIGHT); +	netif_napi_add(netdev, &enet->rx_ring.napi, bcm4908_enet_poll_rx, NAPI_POLL_WEIGHT);  	err = register_netdev(netdev);  	if (err) { @@ -670,7 +741,8 @@ static int bcm4908_enet_remove(struct platform_device *pdev)  	struct bcm4908_enet *enet = platform_get_drvdata(pdev);  	unregister_netdev(enet->netdev); -	netif_napi_del(&enet->napi); +	netif_napi_del(&enet->rx_ring.napi); +	netif_napi_del(&enet->tx_ring.napi);  	bcm4908_enet_dma_free(enet);  	return 0; diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 777bbf6d2586..d9f0f0df8f7b 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -2457,7 +2457,6 @@ static int bcm_sysport_probe(struct platform_device *pdev)  	struct bcm_sysport_priv *priv;  	struct device_node *dn;  	struct net_device *dev; -	const void *macaddr;  	u32 txq, rxq;  	int ret; @@ -2552,12 +2551,10 @@ static int bcm_sysport_probe(struct platform_device *pdev)  	}  	/* Initialize netdevice members */ -	macaddr = of_get_mac_address(dn); -	if (IS_ERR(macaddr)) { +	ret = of_get_mac_address(dn, dev->dev_addr); +	if (ret) {  		dev_warn(&pdev->dev, "using random Ethernet MAC\n");  		eth_hw_addr_random(dev); -	} else { -		ether_addr_copy(dev->dev_addr, macaddr);  	}  	SET_NETDEV_DEV(dev, &pdev->dev); diff --git a/drivers/net/ethernet/broadcom/bgmac-bcma.c b/drivers/net/ethernet/broadcom/bgmac-bcma.c index a5fd161ab5ee..85fa0ab7201c 100644 --- a/drivers/net/ethernet/broadcom/bgmac-bcma.c +++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c @@ -115,7 +115,7 @@ static int bgmac_probe(struct bcma_device *core)  	struct ssb_sprom *sprom = &core->bus->sprom;  	struct mii_bus *mii_bus;  	struct bgmac *bgmac; -	const u8 *mac = NULL; +	const u8 *mac;  	int err;  	bgmac = bgmac_alloc(&core->dev); @@ -128,11 +128,10 @@ static int bgmac_probe(struct bcma_device *core)  	bcma_set_drvdata(core, bgmac); -	if (bgmac->dev->of_node) -		mac = of_get_mac_address(bgmac->dev->of_node); +	err = of_get_mac_address(bgmac->dev->of_node, bgmac->net_dev->dev_addr);  	/* If no MAC address assigned via device tree, check SPROM */ -	if (IS_ERR_OR_NULL(mac)) { +	if (err) {  		switch (core->core_unit) {  		case 0:  			mac = sprom->et0mac; @@ -149,10 +148,9 @@ static int bgmac_probe(struct bcma_device *core)  			err = -ENOTSUPP;  			goto err;  		} +		ether_addr_copy(bgmac->net_dev->dev_addr, mac);  	} -	ether_addr_copy(bgmac->net_dev->dev_addr, mac); -  	/* On BCM4706 we need common core to access PHY */  	if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&  	    !core->bus->drv_gmac_cmn.core) { diff --git a/drivers/net/ethernet/broadcom/bgmac-platform.c b/drivers/net/ethernet/broadcom/bgmac-platform.c index f37f1c58f368..9834b77cf4b6 100644 --- a/drivers/net/ethernet/broadcom/bgmac-platform.c +++ b/drivers/net/ethernet/broadcom/bgmac-platform.c @@ -173,7 +173,7 @@ static int bgmac_probe(struct platform_device *pdev)  	struct device_node *np = pdev->dev.of_node;  	struct bgmac *bgmac;  	struct resource *regs; -	const u8 *mac_addr; +	int ret;  	bgmac = bgmac_alloc(&pdev->dev);  	if (!bgmac) @@ -192,11 +192,10 @@ static int bgmac_probe(struct platform_device *pdev)  	bgmac->dev = &pdev->dev;  	bgmac->dma_dev = &pdev->dev; -	mac_addr = of_get_mac_address(np); -	if (!IS_ERR(mac_addr)) -		ether_addr_copy(bgmac->net_dev->dev_addr, mac_addr); -	else -		dev_warn(&pdev->dev, "MAC address not present in device tree\n"); +	ret = of_get_mac_address(np, bgmac->net_dev->dev_addr); +	if (ret) +		dev_warn(&pdev->dev, +			 "MAC address not present in device tree\n");  	bgmac->irq = platform_get_irq(pdev, 0);  	if (bgmac->irq < 0) diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 3e8a179f39db..c0986096c701 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -8057,7 +8057,7 @@ bnx2_read_vpd_fw_ver(struct bnx2 *bp)  		data[i + 3] = data[i + BNX2_VPD_LEN];  	} -	i = pci_vpd_find_tag(data, 0, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA); +	i = pci_vpd_find_tag(data, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA);  	if (i < 0)  		goto vpd_done; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index b652ed72a621..281b1c2e04a7 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -1395,7 +1395,6 @@ int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, u32 poll_cnt)  	u32 op_gen_command = 0;  	u32 comp_addr = BAR_CSTRORM_INTMEM +  			CSTORM_FINAL_CLEANUP_COMPLETE_OFFSET(clnup_func); -	int ret = 0;  	if (REG_RD(bp, comp_addr)) {  		BNX2X_ERR("Cleanup complete was not 0 before sending\n"); @@ -1420,7 +1419,7 @@ int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, u32 poll_cnt)  	/* Zero completion for next FLR */  	REG_WR(bp, comp_addr, 0); -	return ret; +	return 0;  }  u8 bnx2x_is_pcie_pending(struct pci_dev *dev) @@ -12207,8 +12206,7 @@ static void bnx2x_read_fwinfo(struct bnx2x *bp)  	/* VPD RO tag should be first tag after identifier string, hence  	 * we should be able to find it in first BNX2X_VPD_LEN chars  	 */ -	i = pci_vpd_find_tag(vpd_start, 0, BNX2X_VPD_LEN, -			     PCI_VPD_LRDT_RO_DATA); +	i = pci_vpd_find_tag(vpd_start, BNX2X_VPD_LEN, PCI_VPD_LRDT_RO_DATA);  	if (i < 0)  		goto out_not_found; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index b53a0d87371a..2985844634c8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -122,7 +122,10 @@ enum board_idx {  	NETXTREME_E_VF,  	NETXTREME_C_VF,  	NETXTREME_S_VF, +	NETXTREME_C_VF_HV, +	NETXTREME_E_VF_HV,  	NETXTREME_E_P5_VF, +	NETXTREME_E_P5_VF_HV,  };  /* indexed by enum above */ @@ -170,7 +173,10 @@ static const struct {  	[NETXTREME_E_VF] = { "Broadcom NetXtreme-E Ethernet Virtual Function" },  	[NETXTREME_C_VF] = { "Broadcom NetXtreme-C Ethernet Virtual Function" },  	[NETXTREME_S_VF] = { "Broadcom NetXtreme-S Ethernet Virtual Function" }, +	[NETXTREME_C_VF_HV] = { "Broadcom NetXtreme-C Virtual Function for Hyper-V" }, +	[NETXTREME_E_VF_HV] = { "Broadcom NetXtreme-E Virtual Function for Hyper-V" },  	[NETXTREME_E_P5_VF] = { "Broadcom BCM5750X NetXtreme-E Ethernet Virtual Function" }, +	[NETXTREME_E_P5_VF_HV] = { "Broadcom BCM5750X NetXtreme-E Virtual Function for Hyper-V" },  };  static const struct pci_device_id bnxt_pci_tbl[] = { @@ -222,15 +228,25 @@ static const struct pci_device_id bnxt_pci_tbl[] = {  	{ PCI_VDEVICE(BROADCOM, 0xd804), .driver_data = BCM58804 },  #ifdef CONFIG_BNXT_SRIOV  	{ PCI_VDEVICE(BROADCOM, 0x1606), .driver_data = NETXTREME_E_VF }, +	{ PCI_VDEVICE(BROADCOM, 0x1607), .driver_data = NETXTREME_E_VF_HV }, +	{ PCI_VDEVICE(BROADCOM, 0x1608), .driver_data = NETXTREME_E_VF_HV },  	{ PCI_VDEVICE(BROADCOM, 0x1609), .driver_data = NETXTREME_E_VF }, +	{ PCI_VDEVICE(BROADCOM, 0x16bd), .driver_data = NETXTREME_E_VF_HV },  	{ PCI_VDEVICE(BROADCOM, 0x16c1), .driver_data = NETXTREME_E_VF }, +	{ PCI_VDEVICE(BROADCOM, 0x16c2), .driver_data = NETXTREME_C_VF_HV }, +	{ PCI_VDEVICE(BROADCOM, 0x16c3), .driver_data = NETXTREME_C_VF_HV }, +	{ PCI_VDEVICE(BROADCOM, 0x16c4), .driver_data = NETXTREME_E_VF_HV }, +	{ PCI_VDEVICE(BROADCOM, 0x16c5), .driver_data = NETXTREME_E_VF_HV },  	{ PCI_VDEVICE(BROADCOM, 0x16cb), .driver_data = NETXTREME_C_VF },  	{ PCI_VDEVICE(BROADCOM, 0x16d3), .driver_data = NETXTREME_E_VF },  	{ PCI_VDEVICE(BROADCOM, 0x16dc), .driver_data = NETXTREME_E_VF },  	{ PCI_VDEVICE(BROADCOM, 0x16e1), .driver_data = NETXTREME_C_VF },  	{ PCI_VDEVICE(BROADCOM, 0x16e5), .driver_data = NETXTREME_C_VF }, +	{ PCI_VDEVICE(BROADCOM, 0x16e6), .driver_data = NETXTREME_C_VF_HV },  	{ PCI_VDEVICE(BROADCOM, 0x1806), .driver_data = NETXTREME_E_P5_VF },  	{ PCI_VDEVICE(BROADCOM, 0x1807), .driver_data = NETXTREME_E_P5_VF }, +	{ PCI_VDEVICE(BROADCOM, 0x1808), .driver_data = NETXTREME_E_P5_VF_HV }, +	{ PCI_VDEVICE(BROADCOM, 0x1809), .driver_data = NETXTREME_E_P5_VF_HV },  	{ PCI_VDEVICE(BROADCOM, 0xd800), .driver_data = NETXTREME_S_VF },  #endif  	{ 0 } @@ -265,7 +281,8 @@ static struct workqueue_struct *bnxt_pf_wq;  static bool bnxt_vf_pciid(enum board_idx idx)  {  	return (idx == NETXTREME_C_VF || idx == NETXTREME_E_VF || -		idx == NETXTREME_S_VF || idx == NETXTREME_E_P5_VF); +		idx == NETXTREME_S_VF || idx == NETXTREME_C_VF_HV || +		idx == NETXTREME_E_VF_HV || idx == NETXTREME_E_P5_VF);  }  #define DB_CP_REARM_FLAGS	(DB_KEY_CP | DB_IDX_VALID) @@ -358,6 +375,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)  	struct pci_dev *pdev = bp->pdev;  	struct bnxt_tx_ring_info *txr;  	struct bnxt_sw_tx_bd *tx_buf; +	__le32 lflags = 0;  	i = skb_get_queue_mapping(skb);  	if (unlikely(i >= bp->tx_nr_rings)) { @@ -399,6 +417,11 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)  			vlan_tag_flags |= 1 << TX_BD_CFA_META_TPID_SHIFT;  	} +	if (unlikely(skb->no_fcs)) { +		lflags |= cpu_to_le32(TX_BD_FLAGS_NO_CRC); +		goto normal_tx; +	} +  	if (free_size == bp->tx_ring_size && length <= bp->tx_push_thresh) {  		struct tx_push_buffer *tx_push_buf = txr->tx_push;  		struct tx_push_bd *tx_push = &tx_push_buf->push_bd; @@ -500,7 +523,7 @@ normal_tx:  	txbd1 = (struct tx_bd_ext *)  		&txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)]; -	txbd1->tx_bd_hsize_lflags = 0; +	txbd1->tx_bd_hsize_lflags = lflags;  	if (skb_is_gso(skb)) {  		u32 hdr_len; @@ -512,14 +535,14 @@ normal_tx:  			hdr_len = skb_transport_offset(skb) +  				tcp_hdrlen(skb); -		txbd1->tx_bd_hsize_lflags = cpu_to_le32(TX_BD_FLAGS_LSO | +		txbd1->tx_bd_hsize_lflags |= cpu_to_le32(TX_BD_FLAGS_LSO |  					TX_BD_FLAGS_T_IPID |  					(hdr_len << (TX_BD_HSIZE_SHIFT - 1)));  		length = skb_shinfo(skb)->gso_size;  		txbd1->tx_bd_mss = cpu_to_le32(length);  		length += hdr_len;  	} else if (skb->ip_summed == CHECKSUM_PARTIAL) { -		txbd1->tx_bd_hsize_lflags = +		txbd1->tx_bd_hsize_lflags |=  			cpu_to_le32(TX_BD_FLAGS_TCP_UDP_CHKSUM);  		txbd1->tx_bd_mss = 0;  	} @@ -1732,14 +1755,16 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,  	cons = rxcmp->rx_cmp_opaque;  	if (unlikely(cons != rxr->rx_next_cons)) { -		int rc1 = bnxt_discard_rx(bp, cpr, raw_cons, rxcmp); +		int rc1 = bnxt_discard_rx(bp, cpr, &tmp_raw_cons, rxcmp);  		/* 0xffff is forced error, don't print it */  		if (rxr->rx_next_cons != 0xffff)  			netdev_warn(bp->dev, "RX cons %x != expected cons %x\n",  				    cons, rxr->rx_next_cons);  		bnxt_sched_reset(bp, rxr); -		return rc1; +		if (rc1) +			return rc1; +		goto next_rx_no_prod_no_len;  	}  	rx_buf = &rxr->rx_buf_ring[cons];  	data = rx_buf->data; @@ -4145,7 +4170,7 @@ static void bnxt_free_mem(struct bnxt *bp, bool irq_re_init)  	bnxt_free_ntp_fltrs(bp, irq_re_init);  	if (irq_re_init) {  		bnxt_free_ring_stats(bp); -		if (!(bp->fw_cap & BNXT_FW_CAP_PORT_STATS_NO_RESET) || +		if (!(bp->phy_flags & BNXT_PHY_FL_PORT_STATS_NO_RESET) ||  		    test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))  			bnxt_free_port_stats(bp);  		bnxt_free_ring_grps(bp); @@ -4470,7 +4495,7 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,  	writel(1, bp->bar0 + doorbell_offset);  	if (!pci_is_enabled(bp->pdev)) -		return 0; +		return -ENODEV;  	if (!timeout)  		timeout = DFLT_HWRM_CMD_TIMEOUT; @@ -4500,12 +4525,15 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,  			if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state))  				return -EBUSY;  			/* on first few passes, just barely sleep */ -			if (i < HWRM_SHORT_TIMEOUT_COUNTER) +			if (i < HWRM_SHORT_TIMEOUT_COUNTER) {  				usleep_range(HWRM_SHORT_MIN_TIMEOUT,  					     HWRM_SHORT_MAX_TIMEOUT); -			else +			} else { +				if (HWRM_WAIT_MUST_ABORT(bp, req)) +					break;  				usleep_range(HWRM_MIN_TIMEOUT,  					     HWRM_MAX_TIMEOUT); +			}  		}  		if (bp->hwrm_intr_seq_id != (u16)~seq_id) { @@ -4530,15 +4558,19 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,  			if (len)  				break;  			/* on first few passes, just barely sleep */ -			if (i < HWRM_SHORT_TIMEOUT_COUNTER) +			if (i < HWRM_SHORT_TIMEOUT_COUNTER) {  				usleep_range(HWRM_SHORT_MIN_TIMEOUT,  					     HWRM_SHORT_MAX_TIMEOUT); -			else +			} else { +				if (HWRM_WAIT_MUST_ABORT(bp, req)) +					goto timeout_abort;  				usleep_range(HWRM_MIN_TIMEOUT,  					     HWRM_MAX_TIMEOUT); +			}  		}  		if (i >= tmo_count) { +timeout_abort:  			if (!silent)  				netdev_err(bp->dev, "Error (timeout: %d) msg {0x%x 0x%x} len:%d\n",  					   HWRM_TOTAL_TIMEOUT(i), @@ -7540,6 +7572,32 @@ static void __bnxt_map_fw_health_reg(struct bnxt *bp, u32 reg)  					 BNXT_FW_HEALTH_WIN_MAP_OFF);  } +bool bnxt_is_fw_healthy(struct bnxt *bp) +{ +	if (bp->fw_health && bp->fw_health->status_reliable) { +		u32 fw_status; + +		fw_status = bnxt_fw_health_readl(bp, BNXT_FW_HEALTH_REG); +		if (fw_status && !BNXT_FW_IS_HEALTHY(fw_status)) +			return false; +	} + +	return true; +} + +static void bnxt_inv_fw_health_reg(struct bnxt *bp) +{ +	struct bnxt_fw_health *fw_health = bp->fw_health; +	u32 reg_type; + +	if (!fw_health || !fw_health->status_reliable) +		return; + +	reg_type = BNXT_FW_HEALTH_REG_TYPE(fw_health->regs[BNXT_FW_HEALTH_REG]); +	if (reg_type == BNXT_FW_HEALTH_REG_TYPE_GRC) +		fw_health->status_reliable = false; +} +  static void bnxt_try_map_fw_health_reg(struct bnxt *bp)  {  	void __iomem *hs; @@ -7547,6 +7605,9 @@ static void bnxt_try_map_fw_health_reg(struct bnxt *bp)  	u32 reg_type;  	u32 sig; +	if (bp->fw_health) +		bp->fw_health->status_reliable = false; +  	__bnxt_map_fw_health_reg(bp, HCOMM_STATUS_STRUCT_LOC);  	hs = bp->bar0 + BNXT_FW_HEALTH_WIN_OFF(HCOMM_STATUS_STRUCT_LOC); @@ -7558,11 +7619,9 @@ static void bnxt_try_map_fw_health_reg(struct bnxt *bp)  					     BNXT_FW_HEALTH_WIN_BASE +  					     BNXT_GRC_REG_CHIP_NUM);  		} -		if (!BNXT_CHIP_P5(bp)) { -			if (bp->fw_health) -				bp->fw_health->status_reliable = false; +		if (!BNXT_CHIP_P5(bp))  			return; -		} +  		status_loc = BNXT_GRC_REG_STATUS_P5 |  			     BNXT_FW_HEALTH_REG_TYPE_BAR0;  	} else { @@ -7592,6 +7651,7 @@ static int bnxt_map_fw_health_regs(struct bnxt *bp)  	u32 reg_base = 0xffffffff;  	int i; +	bp->fw_health->status_reliable = false;  	/* Only pre-map the monitoring GRC registers using window 3 */  	for (i = 0; i < 4; i++) {  		u32 reg = fw_health->regs[i]; @@ -7604,6 +7664,7 @@ static int bnxt_map_fw_health_regs(struct bnxt *bp)  			return -ERANGE;  		fw_health->mapped_regs[i] = BNXT_FW_HEALTH_WIN_OFF(reg);  	} +	bp->fw_health->status_reliable = true;  	if (reg_base == 0xffffffff)  		return 0; @@ -8304,11 +8365,11 @@ static int bnxt_alloc_rfs_vnics(struct bnxt *bp)  #endif  } -/* Allow PF and VF with default VLAN to be in promiscuous mode */ +/* Allow PF, trusted VFs and VFs with default VLAN to be in promiscuous mode */  static bool bnxt_promisc_ok(struct bnxt *bp)  {  #ifdef CONFIG_BNXT_SRIOV -	if (BNXT_VF(bp) && !bp->vf.vlan) +	if (BNXT_VF(bp) && !bp->vf.vlan && !bnxt_is_trusted_vf(bp, &bp->vf))  		return false;  #endif  	return true; @@ -8405,7 +8466,7 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)  	if (bp->dev->flags & IFF_BROADCAST)  		vnic->rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_BCAST; -	if ((bp->dev->flags & IFF_PROMISC) && bnxt_promisc_ok(bp)) +	if (bp->dev->flags & IFF_PROMISC)  		vnic->rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS;  	if (bp->dev->flags & IFF_ALLMULTI) { @@ -9039,8 +9100,9 @@ static char *bnxt_report_fec(struct bnxt_link_info *link_info)  static void bnxt_report_link(struct bnxt *bp)  {  	if (bp->link_info.link_up) { -		const char *duplex; +		const char *signal = "";  		const char *flow_ctrl; +		const char *duplex;  		u32 speed;  		u16 fec; @@ -9062,9 +9124,24 @@ static void bnxt_report_link(struct bnxt *bp)  			flow_ctrl = "ON - receive";  		else  			flow_ctrl = "none"; -		netdev_info(bp->dev, "NIC Link is Up, %u Mbps %s duplex, Flow control: %s\n", -			    speed, duplex, flow_ctrl); -		if (bp->flags & BNXT_FLAG_EEE_CAP) +		if (bp->link_info.phy_qcfg_resp.option_flags & +		    PORT_PHY_QCFG_RESP_OPTION_FLAGS_SIGNAL_MODE_KNOWN) { +			u8 sig_mode = bp->link_info.active_fec_sig_mode & +				      PORT_PHY_QCFG_RESP_SIGNAL_MODE_MASK; +			switch (sig_mode) { +			case PORT_PHY_QCFG_RESP_SIGNAL_MODE_NRZ: +				signal = "(NRZ) "; +				break; +			case PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4: +				signal = "(PAM4) "; +				break; +			default: +				break; +			} +		} +		netdev_info(bp->dev, "NIC Link is Up, %u Mbps %s%s duplex, Flow control: %s\n", +			    speed, signal, duplex, flow_ctrl); +		if (bp->phy_flags & BNXT_PHY_FL_EEE_CAP)  			netdev_info(bp->dev, "EEE is %s\n",  				    bp->eee.eee_active ? "active" :  							 "not active"); @@ -9096,10 +9173,6 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp)  	struct hwrm_port_phy_qcaps_output *resp = bp->hwrm_cmd_resp_addr;  	struct bnxt_link_info *link_info = &bp->link_info; -	bp->flags &= ~BNXT_FLAG_EEE_CAP; -	if (bp->test_info) -		bp->test_info->flags &= ~(BNXT_TEST_FL_EXT_LPBK | -					  BNXT_TEST_FL_AN_PHY_LPBK);  	if (bp->hwrm_spec_code < 0x10201)  		return 0; @@ -9110,31 +9183,17 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp)  	if (rc)  		goto hwrm_phy_qcaps_exit; +	bp->phy_flags = resp->flags;  	if (resp->flags & PORT_PHY_QCAPS_RESP_FLAGS_EEE_SUPPORTED) {  		struct ethtool_eee *eee = &bp->eee;  		u16 fw_speeds = le16_to_cpu(resp->supported_speeds_eee_mode); -		bp->flags |= BNXT_FLAG_EEE_CAP;  		eee->supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0);  		bp->lpi_tmr_lo = le32_to_cpu(resp->tx_lpi_timer_low) &  				 PORT_PHY_QCAPS_RESP_TX_LPI_TIMER_LOW_MASK;  		bp->lpi_tmr_hi = le32_to_cpu(resp->valid_tx_lpi_timer_high) &  				 PORT_PHY_QCAPS_RESP_TX_LPI_TIMER_HIGH_MASK;  	} -	if (resp->flags & PORT_PHY_QCAPS_RESP_FLAGS_EXTERNAL_LPBK_SUPPORTED) { -		if (bp->test_info) -			bp->test_info->flags |= BNXT_TEST_FL_EXT_LPBK; -	} -	if (resp->flags & PORT_PHY_QCAPS_RESP_FLAGS_AUTONEG_LPBK_SUPPORTED) { -		if (bp->test_info) -			bp->test_info->flags |= BNXT_TEST_FL_AN_PHY_LPBK; -	} -	if (resp->flags & PORT_PHY_QCAPS_RESP_FLAGS_SHARED_PHY_CFG_SUPPORTED) { -		if (BNXT_PF(bp)) -			bp->fw_cap |= BNXT_FW_CAP_SHARED_PORT_CFG; -	} -	if (resp->flags & PORT_PHY_QCAPS_RESP_FLAGS_CUMULATIVE_COUNTERS_ON_RESET) -		bp->fw_cap |= BNXT_FW_CAP_PORT_STATS_NO_RESET;  	if (bp->hwrm_spec_code >= 0x10a01) {  		if (bnxt_phy_qcaps_no_speed(resp)) { @@ -9225,7 +9284,7 @@ int bnxt_update_link(struct bnxt *bp, bool chng_link_state)  			      PORT_PHY_QCFG_RESP_PHY_ADDR_MASK;  	link_info->module_status = resp->module_status; -	if (bp->flags & BNXT_FLAG_EEE_CAP) { +	if (bp->phy_flags & BNXT_PHY_FL_EEE_CAP) {  		struct ethtool_eee *eee = &bp->eee;  		u16 fw_speeds; @@ -9461,7 +9520,8 @@ static int bnxt_hwrm_shutdown_link(struct bnxt *bp)  	if (!BNXT_SINGLE_PF(bp))  		return 0; -	if (pci_num_vf(bp->pdev)) +	if (pci_num_vf(bp->pdev) && +	    !(bp->phy_flags & BNXT_PHY_FL_FW_MANAGED_LKDN))  		return 0;  	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_CFG, -1, -1); @@ -9494,9 +9554,10 @@ static int bnxt_try_recover_fw(struct bnxt *bp)  		mutex_lock(&bp->hwrm_cmd_lock);  		do { -			rc = __bnxt_hwrm_ver_get(bp, true);  			sts = bnxt_fw_health_readl(bp, BNXT_FW_HEALTH_REG); -			if (!sts || !BNXT_FW_IS_BOOTING(sts)) +			rc = __bnxt_hwrm_ver_get(bp, true); +			if (!BNXT_FW_IS_BOOTING(sts) && +			    !BNXT_FW_IS_RECOVERING(sts))  				break;  			retry++;  		} while (rc == -EBUSY && retry < BNXT_FW_RETRY); @@ -9556,13 +9617,17 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)  	if (rc)  		return rc; -	if (!up) +	if (!up) { +		bnxt_inv_fw_health_reg(bp);  		return 0; +	}  	if (flags & FUNC_DRV_IF_CHANGE_RESP_FLAGS_RESC_CHANGE)  		resc_reinit = true;  	if (flags & FUNC_DRV_IF_CHANGE_RESP_FLAGS_HOT_FW_RESET_DONE)  		fw_reset = true; +	else if (bp->fw_health && !bp->fw_health->status_reliable) +		bnxt_try_map_fw_health_reg(bp);  	if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state) && !fw_reset) {  		netdev_err(bp->dev, "RESET_DONE not set during FW reset.\n"); @@ -9571,6 +9636,7 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)  	}  	if (resc_reinit || fw_reset) {  		if (fw_reset) { +			set_bit(BNXT_STATE_FW_RESET_DET, &bp->state);  			if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))  				bnxt_ulp_stop(bp);  			bnxt_free_ctx_mem(bp); @@ -9579,21 +9645,25 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)  			bnxt_dcb_free(bp);  			rc = bnxt_fw_init_one(bp);  			if (rc) { +				clear_bit(BNXT_STATE_FW_RESET_DET, &bp->state);  				set_bit(BNXT_STATE_ABORT_ERR, &bp->state);  				return rc;  			}  			bnxt_clear_int_mode(bp);  			rc = bnxt_init_int_mode(bp);  			if (rc) { +				clear_bit(BNXT_STATE_FW_RESET_DET, &bp->state);  				netdev_err(bp->dev, "init int mode failed\n");  				return rc;  			} -			set_bit(BNXT_STATE_FW_RESET_DET, &bp->state);  		}  		if (BNXT_NEW_RM(bp)) {  			struct bnxt_hw_resc *hw_resc = &bp->hw_resc;  			rc = bnxt_hwrm_func_resc_qcaps(bp, true); +			if (rc) +				netdev_err(bp->dev, "resc_qcaps failed\n"); +  			hw_resc->resv_cp_rings = 0;  			hw_resc->resv_stat_ctxs = 0;  			hw_resc->resv_irqs = 0; @@ -9607,7 +9677,7 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)  			}  		}  	} -	return 0; +	return rc;  }  static int bnxt_hwrm_port_led_qcaps(struct bnxt *bp) @@ -9736,7 +9806,9 @@ static ssize_t bnxt_show_temp(struct device *dev,  	if (!rc)  		len = sprintf(buf, "%u\n", resp->temp * 1000); /* display millidegree */  	mutex_unlock(&bp->hwrm_cmd_lock); -	return rc ?: len; +	if (rc) +		return rc; +	return len;  }  static SENSOR_DEVICE_ATTR(temp1_input, 0444, bnxt_show_temp, NULL, 0); @@ -9793,7 +9865,7 @@ static bool bnxt_eee_config_ok(struct bnxt *bp)  	struct ethtool_eee *eee = &bp->eee;  	struct bnxt_link_info *link_info = &bp->link_info; -	if (!(bp->flags & BNXT_FLAG_EEE_CAP)) +	if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP))  		return true;  	if (eee->eee_enabled) { @@ -10440,7 +10512,7 @@ static void bnxt_set_rx_mode(struct net_device *dev)  		  CFA_L2_SET_RX_MASK_REQ_MASK_ALL_MCAST |  		  CFA_L2_SET_RX_MASK_REQ_MASK_BCAST); -	if ((dev->flags & IFF_PROMISC) && bnxt_promisc_ok(bp)) +	if (dev->flags & IFF_PROMISC)  		mask |= CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS;  	uc_update = bnxt_uc_list_updated(bp); @@ -10516,6 +10588,9 @@ static int bnxt_cfg_rx_mode(struct bnxt *bp)  	}  skip_uc: +	if ((vnic->rx_mask & CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS) && +	    !bnxt_promisc_ok(bp)) +		vnic->rx_mask &= ~CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS;  	rc = bnxt_hwrm_cfa_l2_set_rx_mask(bp, 0);  	if (rc && vnic->mc_list_count) {  		netdev_info(bp->dev, "Failed setting MC filters rc: %d, turning on ALL_MCAST mode\n", @@ -10710,6 +10785,40 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features)  	return rc;  } +static netdev_features_t bnxt_features_check(struct sk_buff *skb, +					     struct net_device *dev, +					     netdev_features_t features) +{ +	struct bnxt *bp; +	__be16 udp_port; +	u8 l4_proto = 0; + +	features = vlan_features_check(skb, features); +	if (!skb->encapsulation) +		return features; + +	switch (vlan_get_protocol(skb)) { +	case htons(ETH_P_IP): +		l4_proto = ip_hdr(skb)->protocol; +		break; +	case htons(ETH_P_IPV6): +		l4_proto = ipv6_hdr(skb)->nexthdr; +		break; +	default: +		return features; +	} + +	if (l4_proto != IPPROTO_UDP) +		return features; + +	bp = netdev_priv(dev); +	/* For UDP, we can only handle 1 Vxlan port and 1 Geneve port. */ +	udp_port = udp_hdr(skb)->dest; +	if (udp_port == bp->vxlan_port || udp_port == bp->nge_port) +		return features; +	return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); +} +  int bnxt_dbg_hwrm_rd_reg(struct bnxt *bp, u32 reg_off, u16 num_words,  			 u32 *reg_buf)  { @@ -11035,6 +11144,7 @@ static void bnxt_fw_reset_close(struct bnxt *bp)  		pci_disable_device(bp->pdev);  	}  	__bnxt_close_nic(bp, true, false); +	bnxt_vf_reps_free(bp);  	bnxt_clear_int_mode(bp);  	bnxt_hwrm_func_drv_unrgtr(bp);  	if (pci_is_enabled(bp->pdev)) @@ -11640,7 +11750,7 @@ static void bnxt_reset_all(struct bnxt *bp)  		req.selfrst_status = FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP;  		req.flags = FW_RESET_REQ_FLAGS_RESET_GRACEFUL;  		rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); -		if (rc) +		if (rc != -ENODEV)  			netdev_warn(bp->dev, "Unable to reset FW rc=%d\n", rc);  	}  	bp->fw_reset_timestamp = jiffies; @@ -11723,28 +11833,20 @@ static void bnxt_fw_reset_task(struct work_struct *work)  		bnxt_queue_fw_reset_work(bp, bp->fw_reset_min_dsecs * HZ / 10);  		return;  	case BNXT_FW_RESET_STATE_ENABLE_DEV: -		if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state)) { -			u32 val; - -			if (!bp->fw_reset_min_dsecs) { -				u16 val; - -				pci_read_config_word(bp->pdev, PCI_SUBSYSTEM_ID, -						     &val); -				if (val == 0xffff) { -					if (bnxt_fw_reset_timeout(bp)) { -						netdev_err(bp->dev, "Firmware reset aborted, PCI config space invalid\n"); -						goto fw_reset_abort; -					} -					bnxt_queue_fw_reset_work(bp, HZ / 1000); -					return; +		bnxt_inv_fw_health_reg(bp); +		if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state) && +		    !bp->fw_reset_min_dsecs) { +			u16 val; + +			pci_read_config_word(bp->pdev, PCI_SUBSYSTEM_ID, &val); +			if (val == 0xffff) { +				if (bnxt_fw_reset_timeout(bp)) { +					netdev_err(bp->dev, "Firmware reset aborted, PCI config space invalid\n"); +					goto fw_reset_abort;  				} +				bnxt_queue_fw_reset_work(bp, HZ / 1000); +				return;  			} -			val = bnxt_fw_health_readl(bp, -						   BNXT_FW_RESET_INPROG_REG); -			if (val) -				netdev_warn(bp->dev, "FW reset inprog %x after min wait time.\n", -					    val);  		}  		clear_bit(BNXT_STATE_FW_FATAL_COND, &bp->state);  		if (pci_enable_device(bp->pdev)) { @@ -11787,6 +11889,8 @@ static void bnxt_fw_reset_task(struct work_struct *work)  		bnxt_ulp_start(bp, rc);  		if (!rc)  			bnxt_reenable_sriov(bp); +		bnxt_vf_reps_alloc(bp); +		bnxt_vf_reps_open(bp);  		bnxt_dl_health_recovery_done(bp);  		bnxt_dl_health_status_update(bp, true);  		rtnl_unlock(); @@ -12222,10 +12326,13 @@ static int bnxt_udp_tunnel_sync(struct net_device *netdev, unsigned int table)  	unsigned int cmd;  	udp_tunnel_nic_get_port(netdev, table, 0, &ti); -	if (ti.type == UDP_TUNNEL_TYPE_VXLAN) +	if (ti.type == UDP_TUNNEL_TYPE_VXLAN) { +		bp->vxlan_port = ti.port;  		cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN; -	else +	} else { +		bp->nge_port = ti.port;  		cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GENEVE; +	}  	if (ti.port)  		return bnxt_hwrm_tunnel_dst_port_alloc(bp, ti.port, cmd); @@ -12325,6 +12432,7 @@ static const struct net_device_ops bnxt_netdev_ops = {  	.ndo_change_mtu		= bnxt_change_mtu,  	.ndo_fix_features	= bnxt_fix_features,  	.ndo_set_features	= bnxt_set_features, +	.ndo_features_check	= bnxt_features_check,  	.ndo_tx_timeout		= bnxt_tx_timeout,  #ifdef CONFIG_BNXT_SRIOV  	.ndo_get_vf_config	= bnxt_get_vf_config, @@ -12393,12 +12501,17 @@ static int bnxt_probe_phy(struct bnxt *bp, bool fw_dflt)  	int rc = 0;  	struct bnxt_link_info *link_info = &bp->link_info; +	bp->phy_flags = 0;  	rc = bnxt_hwrm_phy_qcaps(bp);  	if (rc) {  		netdev_err(bp->dev, "Probe phy can't get phy capabilities (rc: %x)\n",  			   rc);  		return rc;  	} +	if (bp->phy_flags & BNXT_PHY_FL_NO_FCS) +		bp->dev->priv_flags |= IFF_SUPP_NOFCS; +	else +		bp->dev->priv_flags &= ~IFF_SUPP_NOFCS;  	if (!fw_dflt)  		return 0; @@ -12681,7 +12794,7 @@ static void bnxt_vpd_read_info(struct bnxt *bp)  		goto exit;  	} -	i = pci_vpd_find_tag(vpd_data, 0, vpd_size, PCI_VPD_LRDT_RO_DATA); +	i = pci_vpd_find_tag(vpd_data, vpd_size, PCI_VPD_LRDT_RO_DATA);  	if (i < 0) {  		netdev_err(bp->dev, "VPD READ-Only not found\n");  		goto exit; @@ -12872,8 +12985,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	if (!BNXT_CHIP_P4_PLUS(bp))  		bp->flags |= BNXT_FLAG_DOUBLE_DB; -	bp->ulp_probe = bnxt_ulp_probe; -  	rc = bnxt_init_mac_addr(bp);  	if (rc) {  		dev_err(&pdev->dev, "Unable to initialize mac address.\n"); @@ -12934,6 +13045,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  				   rc);  	} +	bnxt_inv_fw_health_reg(bp);  	bnxt_dl_register(bp);  	rc = register_netdev(dev); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 1259e68cba2a..98e0cef4532c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -671,6 +671,10 @@ struct nqe_cn {  #define HWRM_MIN_TIMEOUT		25  #define HWRM_MAX_TIMEOUT		40 +#define HWRM_WAIT_MUST_ABORT(bp, req)					\ +	(le16_to_cpu((req)->req_type) != HWRM_VER_GET &&		\ +	 !bnxt_is_fw_healthy(bp)) +  #define HWRM_TOTAL_TIMEOUT(n)	(((n) <= HWRM_SHORT_TIMEOUT_COUNTER) ?	\  	((n) * HWRM_SHORT_MIN_TIMEOUT) :				\  	(HWRM_SHORT_TIMEOUT_COUNTER * HWRM_SHORT_MIN_TIMEOUT +		\ @@ -1337,9 +1341,6 @@ struct bnxt_led_info {  struct bnxt_test_info {  	u8 offline_mask; -	u8 flags; -#define BNXT_TEST_FL_EXT_LPBK		0x1 -#define BNXT_TEST_FL_AN_PHY_LPBK	0x2  	u16 timeout;  	char string[BNXT_MAX_TEST][ETH_GSTRING_LEN];  }; @@ -1560,6 +1561,7 @@ struct bnxt_fw_reporter_ctx {  #define BNXT_FW_STATUS_HEALTH_MSK	0xffff  #define BNXT_FW_STATUS_HEALTHY		0x8000  #define BNXT_FW_STATUS_SHUTDOWN		0x100000 +#define BNXT_FW_STATUS_RECOVERING	0x400000  #define BNXT_FW_IS_HEALTHY(sts)		(((sts) & BNXT_FW_STATUS_HEALTH_MSK) ==\  					 BNXT_FW_STATUS_HEALTHY) @@ -1570,6 +1572,9 @@ struct bnxt_fw_reporter_ctx {  #define BNXT_FW_IS_ERR(sts)		(((sts) & BNXT_FW_STATUS_HEALTH_MSK) > \  					 BNXT_FW_STATUS_HEALTHY) +#define BNXT_FW_IS_RECOVERING(sts)	(BNXT_FW_IS_ERR(sts) &&		       \ +					 ((sts) & BNXT_FW_STATUS_RECOVERING)) +  #define BNXT_FW_RETRY			5  #define BNXT_FW_IF_RETRY		10 @@ -1685,7 +1690,6 @@ struct bnxt {  	#define BNXT_FLAG_SHARED_RINGS	0x200  	#define BNXT_FLAG_PORT_STATS	0x400  	#define BNXT_FLAG_UDP_RSS_CAP	0x800 -	#define BNXT_FLAG_EEE_CAP	0x1000  	#define BNXT_FLAG_NEW_RSS_CAP	0x2000  	#define BNXT_FLAG_WOL_CAP	0x4000  	#define BNXT_FLAG_ROCEV1_CAP	0x8000 @@ -1712,8 +1716,10 @@ struct bnxt {  #define BNXT_NPAR(bp)		((bp)->port_partition_type)  #define BNXT_MH(bp)		((bp)->flags & BNXT_FLAG_MULTI_HOST)  #define BNXT_SINGLE_PF(bp)	(BNXT_PF(bp) && !BNXT_NPAR(bp) && !BNXT_MH(bp)) +#define BNXT_SH_PORT_CFG_OK(bp)	(BNXT_PF(bp) &&				\ +				 ((bp)->phy_flags & BNXT_PHY_FL_SHARED_PORT_CFG))  #define BNXT_PHY_CFG_ABLE(bp)	((BNXT_SINGLE_PF(bp) ||			\ -				  ((bp)->fw_cap & BNXT_FW_CAP_SHARED_PORT_CFG)) && \ +				  BNXT_SH_PORT_CFG_OK(bp)) &&		\  				 (bp)->link_info.phy_state == BNXT_PHY_STATE_ENABLED)  #define BNXT_CHIP_TYPE_NITRO_A0(bp) ((bp)->flags & BNXT_FLAG_CHIP_NITRO_A0)  #define BNXT_RX_PAGE_MODE(bp)	((bp)->flags & BNXT_FLAG_RX_PAGE_MODE) @@ -1745,7 +1751,6 @@ struct bnxt {  	(BNXT_CHIP_P4(bp) || BNXT_CHIP_P5(bp))  	struct bnxt_en_dev	*edev; -	struct bnxt_en_dev *	(*ulp_probe)(struct net_device *);  	struct bnxt_napi	**bnapi; @@ -1863,11 +1868,9 @@ struct bnxt {  	#define BNXT_FW_CAP_EXT_STATS_SUPPORTED		0x00040000  	#define BNXT_FW_CAP_ERR_RECOVER_RELOAD		0x00100000  	#define BNXT_FW_CAP_HOT_RESET			0x00200000 -	#define BNXT_FW_CAP_SHARED_PORT_CFG		0x00400000  	#define BNXT_FW_CAP_VLAN_RX_STRIP		0x01000000  	#define BNXT_FW_CAP_VLAN_TX_INSERT		0x02000000  	#define BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED	0x04000000 -	#define BNXT_FW_CAP_PORT_STATS_NO_RESET		0x10000000  	#define BNXT_FW_CAP_RING_MONITOR		0x40000000  #define BNXT_NEW_RM(bp)		((bp)->fw_cap & BNXT_FW_CAP_NEW_RM) @@ -1910,6 +1913,8 @@ struct bnxt {  	u16			vxlan_fw_dst_port_id;  	u16			nge_fw_dst_port_id; +	__be16			vxlan_port; +	__be16			nge_port;  	u8			port_partition_type;  	u8			port_count;  	u16			br_mode; @@ -2002,6 +2007,17 @@ struct bnxt {  	u32			lpi_tmr_lo;  	u32			lpi_tmr_hi; +	/* copied from flags in hwrm_port_phy_qcaps_output */ +	u8			phy_flags; +#define BNXT_PHY_FL_EEE_CAP		PORT_PHY_QCAPS_RESP_FLAGS_EEE_SUPPORTED +#define BNXT_PHY_FL_EXT_LPBK		PORT_PHY_QCAPS_RESP_FLAGS_EXTERNAL_LPBK_SUPPORTED +#define BNXT_PHY_FL_AN_PHY_LPBK		PORT_PHY_QCAPS_RESP_FLAGS_AUTONEG_LPBK_SUPPORTED +#define BNXT_PHY_FL_SHARED_PORT_CFG	PORT_PHY_QCAPS_RESP_FLAGS_SHARED_PHY_CFG_SUPPORTED +#define BNXT_PHY_FL_PORT_STATS_NO_RESET	PORT_PHY_QCAPS_RESP_FLAGS_CUMULATIVE_COUNTERS_ON_RESET +#define BNXT_PHY_FL_NO_PHY_LPBK		PORT_PHY_QCAPS_RESP_FLAGS_LOCAL_LPBK_NOT_SUPPORTED +#define BNXT_PHY_FL_FW_MANAGED_LKDN	PORT_PHY_QCAPS_RESP_FLAGS_FW_MANAGED_LINK_DOWN +#define BNXT_PHY_FL_NO_FCS		PORT_PHY_QCAPS_RESP_FLAGS_NO_FCS +  	u8			num_tests;  	struct bnxt_test_info	*test_info; @@ -2228,6 +2244,7 @@ int bnxt_hwrm_set_link_setting(struct bnxt *, bool, bool);  int bnxt_hwrm_alloc_wol_fltr(struct bnxt *bp);  int bnxt_hwrm_free_wol_fltr(struct bnxt *bp);  int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp, bool all); +bool bnxt_is_fw_healthy(struct bnxt *bp);  int bnxt_hwrm_fw_set_time(struct bnxt *);  int bnxt_open_nic(struct bnxt *, bool, bool);  int bnxt_half_open_nic(struct bnxt *bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 2f8b193a772d..c664ec52ebcf 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1930,6 +1930,20 @@ static int bnxt_get_fecparam(struct net_device *dev,  	return 0;  } +static void bnxt_get_fec_stats(struct net_device *dev, +			       struct ethtool_fec_stats *fec_stats) +{ +	struct bnxt *bp = netdev_priv(dev); +	u64 *rx; + +	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) +		return; + +	rx = bp->rx_port_stats_ext.sw_stats; +	fec_stats->corrected_bits.total = +		*(rx + BNXT_RX_STATS_EXT_OFFSET(rx_corrected_bits)); +} +  static u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info,  					 u32 fec)  { @@ -2898,7 +2912,7 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata)  	if (!BNXT_PHY_CFG_ABLE(bp))  		return -EOPNOTSUPP; -	if (!(bp->flags & BNXT_FLAG_EEE_CAP)) +	if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP))  		return -EOPNOTSUPP;  	mutex_lock(&bp->link_lock); @@ -2949,7 +2963,7 @@ static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata)  {  	struct bnxt *bp = netdev_priv(dev); -	if (!(bp->flags & BNXT_FLAG_EEE_CAP)) +	if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP))  		return -EOPNOTSUPP;  	*edata = bp->eee; @@ -3201,7 +3215,7 @@ static int bnxt_disable_an_for_lpbk(struct bnxt *bp,  	int rc;  	if (!link_info->autoneg || -	    (bp->test_info->flags & BNXT_TEST_FL_AN_PHY_LPBK)) +	    (bp->phy_flags & BNXT_PHY_FL_AN_PHY_LPBK))  		return 0;  	rc = bnxt_query_force_speeds(bp, &fw_advertising); @@ -3402,7 +3416,7 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest,  	}  	if ((etest->flags & ETH_TEST_FL_EXTERNAL_LB) && -	    (bp->test_info->flags & BNXT_TEST_FL_EXT_LPBK)) +	    (bp->phy_flags & BNXT_PHY_FL_EXT_LPBK))  		do_ext_lpbk = true;  	if (etest->flags & ETH_TEST_FL_OFFLINE) { @@ -3976,6 +3990,133 @@ ethtool_init_exit:  	mutex_unlock(&bp->hwrm_cmd_lock);  } +static void bnxt_get_eth_phy_stats(struct net_device *dev, +				   struct ethtool_eth_phy_stats *phy_stats) +{ +	struct bnxt *bp = netdev_priv(dev); +	u64 *rx; + +	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) +		return; + +	rx = bp->rx_port_stats_ext.sw_stats; +	phy_stats->SymbolErrorDuringCarrier = +		*(rx + BNXT_RX_STATS_EXT_OFFSET(rx_pcs_symbol_err)); +} + +static void bnxt_get_eth_mac_stats(struct net_device *dev, +				   struct ethtool_eth_mac_stats *mac_stats) +{ +	struct bnxt *bp = netdev_priv(dev); +	u64 *rx, *tx; + +	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) +		return; + +	rx = bp->port_stats.sw_stats; +	tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; + +	mac_stats->FramesReceivedOK = +		BNXT_GET_RX_PORT_STATS64(rx, rx_good_frames); +	mac_stats->FramesTransmittedOK = +		BNXT_GET_TX_PORT_STATS64(tx, tx_good_frames); +	mac_stats->FrameCheckSequenceErrors = +		BNXT_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames); +	mac_stats->AlignmentErrors = +		BNXT_GET_RX_PORT_STATS64(rx, rx_align_err_frames); +	mac_stats->OutOfRangeLengthField = +		BNXT_GET_RX_PORT_STATS64(rx, rx_oor_len_frames); +} + +static void bnxt_get_eth_ctrl_stats(struct net_device *dev, +				    struct ethtool_eth_ctrl_stats *ctrl_stats) +{ +	struct bnxt *bp = netdev_priv(dev); +	u64 *rx; + +	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) +		return; + +	rx = bp->port_stats.sw_stats; +	ctrl_stats->MACControlFramesReceived = +		BNXT_GET_RX_PORT_STATS64(rx, rx_ctrl_frames); +} + +static const struct ethtool_rmon_hist_range bnxt_rmon_ranges[] = { +	{    0,    64 }, +	{   65,   127 }, +	{  128,   255 }, +	{  256,   511 }, +	{  512,  1023 }, +	{ 1024,  1518 }, +	{ 1519,  2047 }, +	{ 2048,  4095 }, +	{ 4096,  9216 }, +	{ 9217, 16383 }, +	{} +}; + +static void bnxt_get_rmon_stats(struct net_device *dev, +				struct ethtool_rmon_stats *rmon_stats, +				const struct ethtool_rmon_hist_range **ranges) +{ +	struct bnxt *bp = netdev_priv(dev); +	u64 *rx, *tx; + +	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) +		return; + +	rx = bp->port_stats.sw_stats; +	tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; + +	rmon_stats->jabbers = +		BNXT_GET_RX_PORT_STATS64(rx, rx_jbr_frames); +	rmon_stats->oversize_pkts = +		BNXT_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames); +	rmon_stats->undersize_pkts = +		BNXT_GET_RX_PORT_STATS64(rx, rx_undrsz_frames); + +	rmon_stats->hist[0] = BNXT_GET_RX_PORT_STATS64(rx, rx_64b_frames); +	rmon_stats->hist[1] = BNXT_GET_RX_PORT_STATS64(rx, rx_65b_127b_frames); +	rmon_stats->hist[2] = BNXT_GET_RX_PORT_STATS64(rx, rx_128b_255b_frames); +	rmon_stats->hist[3] = BNXT_GET_RX_PORT_STATS64(rx, rx_256b_511b_frames); +	rmon_stats->hist[4] = +		BNXT_GET_RX_PORT_STATS64(rx, rx_512b_1023b_frames); +	rmon_stats->hist[5] = +		BNXT_GET_RX_PORT_STATS64(rx, rx_1024b_1518b_frames); +	rmon_stats->hist[6] = +		BNXT_GET_RX_PORT_STATS64(rx, rx_1519b_2047b_frames); +	rmon_stats->hist[7] = +		BNXT_GET_RX_PORT_STATS64(rx, rx_2048b_4095b_frames); +	rmon_stats->hist[8] = +		BNXT_GET_RX_PORT_STATS64(rx, rx_4096b_9216b_frames); +	rmon_stats->hist[9] = +		BNXT_GET_RX_PORT_STATS64(rx, rx_9217b_16383b_frames); + +	rmon_stats->hist_tx[0] = +		BNXT_GET_TX_PORT_STATS64(tx, tx_64b_frames); +	rmon_stats->hist_tx[1] = +		BNXT_GET_TX_PORT_STATS64(tx, tx_65b_127b_frames); +	rmon_stats->hist_tx[2] = +		BNXT_GET_TX_PORT_STATS64(tx, tx_128b_255b_frames); +	rmon_stats->hist_tx[3] = +		BNXT_GET_TX_PORT_STATS64(tx, tx_256b_511b_frames); +	rmon_stats->hist_tx[4] = +		BNXT_GET_TX_PORT_STATS64(tx, tx_512b_1023b_frames); +	rmon_stats->hist_tx[5] = +		BNXT_GET_TX_PORT_STATS64(tx, tx_1024b_1518b_frames); +	rmon_stats->hist_tx[6] = +		BNXT_GET_TX_PORT_STATS64(tx, tx_1519b_2047b_frames); +	rmon_stats->hist_tx[7] = +		BNXT_GET_TX_PORT_STATS64(tx, tx_2048b_4095b_frames); +	rmon_stats->hist_tx[8] = +		BNXT_GET_TX_PORT_STATS64(tx, tx_4096b_9216b_frames); +	rmon_stats->hist_tx[9] = +		BNXT_GET_TX_PORT_STATS64(tx, tx_9217b_16383b_frames); + +	*ranges = bnxt_rmon_ranges; +} +  void bnxt_ethtool_free(struct bnxt *bp)  {  	kfree(bp->test_info); @@ -3991,6 +4132,7 @@ const struct ethtool_ops bnxt_ethtool_ops = {  				     ETHTOOL_COALESCE_USE_ADAPTIVE_RX,  	.get_link_ksettings	= bnxt_get_link_ksettings,  	.set_link_ksettings	= bnxt_set_link_ksettings, +	.get_fec_stats		= bnxt_get_fec_stats,  	.get_fecparam		= bnxt_get_fecparam,  	.set_fecparam		= bnxt_set_fecparam,  	.get_pause_stats	= bnxt_get_pause_stats, @@ -4034,4 +4176,8 @@ const struct ethtool_ops bnxt_ethtool_ops = {  	.set_dump		= bnxt_set_dump,  	.get_dump_flag		= bnxt_get_dump_flag,  	.get_dump_data		= bnxt_get_dump_data, +	.get_eth_phy_stats	= bnxt_get_eth_phy_stats, +	.get_eth_mac_stats	= bnxt_get_eth_mac_stats, +	.get_eth_ctrl_stats	= bnxt_get_eth_ctrl_stats, +	.get_rmon_stats		= bnxt_get_rmon_stats,  }; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c index a217316228f4..eb00a219aa51 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c @@ -49,10 +49,6 @@ static int bnxt_hwrm_fwd_async_event_cmpl(struct bnxt *bp,  static int bnxt_vf_ndo_prep(struct bnxt *bp, int vf_id)  { -	if (!test_bit(BNXT_STATE_OPEN, &bp->state)) { -		netdev_err(bp->dev, "vf ndo called though PF is down\n"); -		return -EINVAL; -	}  	if (!bp->pf.active_vfs) {  		netdev_err(bp->dev, "vf ndo called though sriov is disabled\n");  		return -EINVAL; @@ -113,7 +109,7 @@ static int bnxt_hwrm_func_qcfg_flags(struct bnxt *bp, struct bnxt_vf_info *vf)  	int rc;  	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QCFG, -1, -1); -	req.fid = cpu_to_le16(vf->fw_fid); +	req.fid = cpu_to_le16(BNXT_PF(bp) ? vf->fw_fid : 0xffff);  	mutex_lock(&bp->hwrm_cmd_lock);  	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);  	if (rc) { @@ -125,9 +121,9 @@ static int bnxt_hwrm_func_qcfg_flags(struct bnxt *bp, struct bnxt_vf_info *vf)  	return 0;  } -static bool bnxt_is_trusted_vf(struct bnxt *bp, struct bnxt_vf_info *vf) +bool bnxt_is_trusted_vf(struct bnxt *bp, struct bnxt_vf_info *vf)  { -	if (!(bp->fw_cap & BNXT_FW_CAP_TRUSTED_VF)) +	if (BNXT_PF(bp) && !(bp->fw_cap & BNXT_FW_CAP_TRUSTED_VF))  		return !!(vf->flags & BNXT_VF_TRUST);  	bnxt_hwrm_func_qcfg_flags(bp, vf); @@ -1120,10 +1116,38 @@ void bnxt_hwrm_exec_fwd_req(struct bnxt *bp)  	}  } +int bnxt_approve_mac(struct bnxt *bp, u8 *mac, bool strict) +{ +	struct hwrm_func_vf_cfg_input req = {0}; +	int rc = 0; + +	if (!BNXT_VF(bp)) +		return 0; + +	if (bp->hwrm_spec_code < 0x10202) { +		if (is_valid_ether_addr(bp->vf.mac_addr)) +			rc = -EADDRNOTAVAIL; +		goto mac_done; +	} +	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_CFG, -1, -1); +	req.enables = cpu_to_le32(FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR); +	memcpy(req.dflt_mac_addr, mac, ETH_ALEN); +	rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); +mac_done: +	if (rc && strict) { +		rc = -EADDRNOTAVAIL; +		netdev_warn(bp->dev, "VF MAC address %pM not approved by the PF\n", +			    mac); +		return rc; +	} +	return 0; +} +  void bnxt_update_vf_mac(struct bnxt *bp)  {  	struct hwrm_func_qcaps_input req = {0};  	struct hwrm_func_qcaps_output *resp = bp->hwrm_cmd_resp_addr; +	bool inform_pf = false;  	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QCAPS, -1, -1);  	req.fid = cpu_to_le16(0xffff); @@ -1139,42 +1163,24 @@ void bnxt_update_vf_mac(struct bnxt *bp)  	 *    default but the stored zero MAC will allow the VF user to change  	 *    the random MAC address using ndo_set_mac_address() if he wants.  	 */ -	if (!ether_addr_equal(resp->mac_address, bp->vf.mac_addr)) +	if (!ether_addr_equal(resp->mac_address, bp->vf.mac_addr)) {  		memcpy(bp->vf.mac_addr, resp->mac_address, ETH_ALEN); +		/* This means we are now using our own MAC address, let +		 * the PF know about this MAC address. +		 */ +		if (!is_valid_ether_addr(bp->vf.mac_addr)) +			inform_pf = true; +	}  	/* overwrite netdev dev_addr with admin VF MAC */  	if (is_valid_ether_addr(bp->vf.mac_addr))  		memcpy(bp->dev->dev_addr, bp->vf.mac_addr, ETH_ALEN);  update_vf_mac_exit:  	mutex_unlock(&bp->hwrm_cmd_lock); +	if (inform_pf) +		bnxt_approve_mac(bp, bp->dev->dev_addr, false);  } -int bnxt_approve_mac(struct bnxt *bp, u8 *mac, bool strict) -{ -	struct hwrm_func_vf_cfg_input req = {0}; -	int rc = 0; - -	if (!BNXT_VF(bp)) -		return 0; - -	if (bp->hwrm_spec_code < 0x10202) { -		if (is_valid_ether_addr(bp->vf.mac_addr)) -			rc = -EADDRNOTAVAIL; -		goto mac_done; -	} -	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_CFG, -1, -1); -	req.enables = cpu_to_le32(FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR); -	memcpy(req.dflt_mac_addr, mac, ETH_ALEN); -	rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); -mac_done: -	if (rc && strict) { -		rc = -EADDRNOTAVAIL; -		netdev_warn(bp->dev, "VF MAC address %pM not approved by the PF\n", -			    mac); -		return rc; -	} -	return 0; -}  #else  int bnxt_cfg_hw_sriov(struct bnxt *bp, int *num_vfs, bool reset) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.h index 629641bf6fc5..995535e4c11b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.h @@ -34,6 +34,7 @@ int bnxt_set_vf_vlan(struct net_device *, int, u16, u8, __be16);  int bnxt_set_vf_bw(struct net_device *, int, int, int);  int bnxt_set_vf_link_state(struct net_device *, int, int);  int bnxt_set_vf_spoofchk(struct net_device *, int, bool); +bool bnxt_is_trusted_vf(struct bnxt *bp, struct bnxt_vf_info *vf);  int bnxt_set_vf_trust(struct net_device *dev, int vf_id, bool trust);  int bnxt_sriov_configure(struct pci_dev *pdev, int num_vfs);  int bnxt_cfg_hw_sriov(struct bnxt *bp, int *num_vfs, bool reset); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c index 64dbbb04b043..a918e374f3c5 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c @@ -491,3 +491,4 @@ struct bnxt_en_dev *bnxt_ulp_probe(struct net_device *dev)  	}  	return bp->edev;  } +EXPORT_SYMBOL(bnxt_ulp_probe); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c index 4b5c8fd76a51..dd66302343a2 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c @@ -284,8 +284,26 @@ void bnxt_vf_reps_open(struct bnxt *bp)  	if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV)  		return; -	for (i = 0; i < pci_num_vf(bp->pdev); i++) -		bnxt_vf_rep_open(bp->vf_reps[i]->dev); +	for (i = 0; i < pci_num_vf(bp->pdev); i++) { +		/* Open the VF-Rep only if it is allocated in the FW */ +		if (bp->vf_reps[i]->tx_cfa_action != CFA_HANDLE_INVALID) +			bnxt_vf_rep_open(bp->vf_reps[i]->dev); +	} +} + +static void __bnxt_free_one_vf_rep(struct bnxt *bp, struct bnxt_vf_rep *vf_rep) +{ +	if (!vf_rep) +		return; + +	if (vf_rep->dst) { +		dst_release((struct dst_entry *)vf_rep->dst); +		vf_rep->dst = NULL; +	} +	if (vf_rep->tx_cfa_action != CFA_HANDLE_INVALID) { +		hwrm_cfa_vfr_free(bp, vf_rep->vf_idx); +		vf_rep->tx_cfa_action = CFA_HANDLE_INVALID; +	}  }  static void __bnxt_vf_reps_destroy(struct bnxt *bp) @@ -297,11 +315,7 @@ static void __bnxt_vf_reps_destroy(struct bnxt *bp)  	for (i = 0; i < num_vfs; i++) {  		vf_rep = bp->vf_reps[i];  		if (vf_rep) { -			dst_release((struct dst_entry *)vf_rep->dst); - -			if (vf_rep->tx_cfa_action != CFA_HANDLE_INVALID) -				hwrm_cfa_vfr_free(bp, vf_rep->vf_idx); - +			__bnxt_free_one_vf_rep(bp, vf_rep);  			if (vf_rep->dev) {  				/* if register_netdev failed, then netdev_ops  				 * would have been set to NULL @@ -350,6 +364,80 @@ void bnxt_vf_reps_destroy(struct bnxt *bp)  	__bnxt_vf_reps_destroy(bp);  } +/* Free the VF-Reps in firmware, during firmware hot-reset processing. + * Note that the VF-Rep netdevs are still active (not unregistered) during + * this process. As the mode transition from SWITCHDEV to LEGACY happens + * under the rtnl_lock() this routine is safe under the rtnl_lock(). + */ +void bnxt_vf_reps_free(struct bnxt *bp) +{ +	u16 num_vfs = pci_num_vf(bp->pdev); +	int i; + +	if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) +		return; + +	for (i = 0; i < num_vfs; i++) +		__bnxt_free_one_vf_rep(bp, bp->vf_reps[i]); +} + +static int bnxt_alloc_vf_rep(struct bnxt *bp, struct bnxt_vf_rep *vf_rep, +			     u16 *cfa_code_map) +{ +	/* get cfa handles from FW */ +	if (hwrm_cfa_vfr_alloc(bp, vf_rep->vf_idx, &vf_rep->tx_cfa_action, +			       &vf_rep->rx_cfa_code)) +		return -ENOLINK; + +	cfa_code_map[vf_rep->rx_cfa_code] = vf_rep->vf_idx; +	vf_rep->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, GFP_KERNEL); +	if (!vf_rep->dst) +		return -ENOMEM; + +	/* only cfa_action is needed to mux a packet while TXing */ +	vf_rep->dst->u.port_info.port_id = vf_rep->tx_cfa_action; +	vf_rep->dst->u.port_info.lower_dev = bp->dev; + +	return 0; +} + +/* Allocate the VF-Reps in firmware, during firmware hot-reset processing. + * Note that the VF-Rep netdevs are still active (not unregistered) during + * this process. As the mode transition from SWITCHDEV to LEGACY happens + * under the rtnl_lock() this routine is safe under the rtnl_lock(). + */ +int bnxt_vf_reps_alloc(struct bnxt *bp) +{ +	u16 *cfa_code_map = bp->cfa_code_map, num_vfs = pci_num_vf(bp->pdev); +	struct bnxt_vf_rep *vf_rep; +	int rc, i; + +	if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) +		return 0; + +	if (!cfa_code_map) +		return -EINVAL; + +	for (i = 0; i < MAX_CFA_CODE; i++) +		cfa_code_map[i] = VF_IDX_INVALID; + +	for (i = 0; i < num_vfs; i++) { +		vf_rep = bp->vf_reps[i]; +		vf_rep->vf_idx = i; + +		rc = bnxt_alloc_vf_rep(bp, vf_rep, cfa_code_map); +		if (rc) +			goto err; +	} + +	return 0; + +err: +	netdev_info(bp->dev, "%s error=%d\n", __func__, rc); +	bnxt_vf_reps_free(bp); +	return rc; +} +  /* Use the OUI of the PF's perm addr and report the same mac addr   * for the same VF-rep each time   */ @@ -428,25 +516,9 @@ static int bnxt_vf_reps_create(struct bnxt *bp)  		vf_rep->vf_idx = i;  		vf_rep->tx_cfa_action = CFA_HANDLE_INVALID; -		/* get cfa handles from FW */ -		rc = hwrm_cfa_vfr_alloc(bp, vf_rep->vf_idx, -					&vf_rep->tx_cfa_action, -					&vf_rep->rx_cfa_code); -		if (rc) { -			rc = -ENOLINK; +		rc = bnxt_alloc_vf_rep(bp, vf_rep, cfa_code_map); +		if (rc)  			goto err; -		} -		cfa_code_map[vf_rep->rx_cfa_code] = vf_rep->vf_idx; - -		vf_rep->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, -						 GFP_KERNEL); -		if (!vf_rep->dst) { -			rc = -ENOMEM; -			goto err; -		} -		/* only cfa_action is needed to mux a packet while TXing */ -		vf_rep->dst->u.port_info.port_id = vf_rep->tx_cfa_action; -		vf_rep->dst->u.port_info.lower_dev = bp->dev;  		bnxt_vf_rep_netdev_init(bp, vf_rep, dev);  		rc = register_netdev(dev); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h index d7287651422f..5637a84884d7 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h @@ -19,6 +19,8 @@ void bnxt_vf_reps_close(struct bnxt *bp);  void bnxt_vf_reps_open(struct bnxt *bp);  void bnxt_vf_rep_rx(struct bnxt *bp, struct sk_buff *skb);  struct net_device *bnxt_get_vf_rep(struct bnxt *bp, u16 cfa_code); +int bnxt_vf_reps_alloc(struct bnxt *bp); +void bnxt_vf_reps_free(struct bnxt *bp);  static inline u16 bnxt_vf_rep_get_fid(struct net_device *dev)  { @@ -61,5 +63,15 @@ static inline bool bnxt_dev_is_vf_rep(struct net_device *dev)  {  	return false;  } + +static inline int bnxt_vf_reps_alloc(struct bnxt *bp) +{ +	return 0; +} + +static inline void bnxt_vf_reps_free(struct bnxt *bp) +{ +} +  #endif /* CONFIG_BNXT_SRIOV */  #endif /* BNXT_VFR_H */ diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 641303894341..ec9564e584e0 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -217,7 +217,7 @@ int bnxt_xdp_xmit(struct net_device *dev, int num_frames,  	struct pci_dev *pdev = bp->pdev;  	struct bnxt_tx_ring_info *txr;  	dma_addr_t mapping; -	int drops = 0; +	int nxmit = 0;  	int ring;  	int i; @@ -233,21 +233,17 @@ int bnxt_xdp_xmit(struct net_device *dev, int num_frames,  		struct xdp_frame *xdp = frames[i];  		if (!txr || !bnxt_tx_avail(bp, txr) || -		    !(bp->bnapi[ring]->flags & BNXT_NAPI_FLAG_XDP)) { -			xdp_return_frame_rx_napi(xdp); -			drops++; -			continue; -		} +		    !(bp->bnapi[ring]->flags & BNXT_NAPI_FLAG_XDP)) +			break;  		mapping = dma_map_single(&pdev->dev, xdp->data, xdp->len,  					 DMA_TO_DEVICE); -		if (dma_mapping_error(&pdev->dev, mapping)) { -			xdp_return_frame_rx_napi(xdp); -			drops++; -			continue; -		} +		if (dma_mapping_error(&pdev->dev, mapping)) +			break; +  		__bnxt_xmit_xdp_redirect(bp, txr, mapping, xdp->len, xdp); +		nxmit++;  	}  	if (flags & XDP_XMIT_FLUSH) { @@ -256,7 +252,7 @@ int bnxt_xdp_xmit(struct net_device *dev, int num_frames,  		bnxt_db_write(bp, &txr->tx_db, txr->tx_prod);  	} -	return num_frames - drops; +	return nxmit;  }  /* Under rtnl_lock */ diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c index 1c86eddb1b51..facde824bcaa 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c @@ -18,7 +18,6 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/clk.h> -#include <linux/version.h>  #include <linux/platform_device.h>  #include <net/arp.h> diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index d2381929931b..b0e49643f483 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -13016,7 +13016,7 @@ static int tg3_test_nvram(struct tg3 *tp)  	if (!buf)  		return -ENOMEM; -	i = pci_vpd_find_tag((u8 *)buf, 0, len, PCI_VPD_LRDT_RO_DATA); +	i = pci_vpd_find_tag((u8 *)buf, len, PCI_VPD_LRDT_RO_DATA);  	if (i > 0) {  		j = pci_vpd_lrdt_size(&((u8 *)buf)[i]);  		if (j < 0) @@ -15629,7 +15629,7 @@ static void tg3_read_vpd(struct tg3 *tp)  	if (!vpd_data)  		goto out_no_vpd; -	i = pci_vpd_find_tag(vpd_data, 0, vpdlen, PCI_VPD_LRDT_RO_DATA); +	i = pci_vpd_find_tag(vpd_data, vpdlen, PCI_VPD_LRDT_RO_DATA);  	if (i < 0)  		goto out_not_found; | 
