From 12185dfe44360f814ac4ead9d22ad2af7511b2e9 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Tue, 16 Jul 2019 17:25:10 -0500 Subject: bonding: Force slave speed check after link state recovery for 802.3ad The following scenario was encountered during testing of logical partition mobility on pseries partitions with bonded ibmvnic adapters in LACP mode. 1. Driver receives a signal that the device has been swapped, and it needs to reset to initialize the new device. 2. Driver reports loss of carrier and begins initialization. 3. Bonding driver receives NETDEV_CHANGE notifier and checks the slave's current speed and duplex settings. Because these are unknown at the time, the bond sets its link state to BOND_LINK_FAIL and handles the speed update, clearing AD_PORT_LACP_ENABLE. 4. Driver finishes recovery and reports that the carrier is on. 5. Bond receives a new notification and checks the speed again. The speeds are valid but miimon has not altered the link state yet. AD_PORT_LACP_ENABLE remains off. Because the slave's link state is still BOND_LINK_FAIL, no further port checks are made when it recovers. Though the slave devices are operational and have valid speed and duplex settings, the bond will not send LACPDU's. The simplest fix I can see is to force another speed check in bond_miimon_commit. This way the bond will update AD_PORT_LACP_ENABLE if needed when transitioning from BOND_LINK_FAIL to BOND_LINK_UP. CC: Jarod Wilson CC: Jay Vosburgh CC: Veaceslav Falico CC: Andy Gospodarek Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 9b7016abca2f..02fd7822c14a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2196,6 +2196,15 @@ static void bond_miimon_commit(struct bonding *bond) bond_for_each_slave(bond, slave, iter) { switch (slave->new_link) { case BOND_LINK_NOCHANGE: + /* For 802.3ad mode, check current slave speed and + * duplex again in case its port was disabled after + * invalid speed/duplex reporting but recovered before + * link monitoring could make a decision on the actual + * link status + */ + if (BOND_MODE(bond) == BOND_MODE_8023AD && + slave->link == BOND_LINK_UP) + bond_3ad_adapter_speed_duplex_changed(slave); continue; case BOND_LINK_UP: -- cgit v1.2.3-59-g8ed1b From bba18318e7d1d5c8b0bbafd65010a0cee3c65608 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Fri, 19 Jul 2019 16:38:48 +0200 Subject: net: mvpp2: Don't check for 3 consecutive Idle frames for 10G links PPv2's XLGMAC can wait for 3 idle frames before triggering a link up event. This can cause the link to be stuck low when there's traffic on the interface, so disable this feature. Fixes: 4bb043262878 ("net: mvpp2: phylink support") Signed-off-by: Maxime Chevallier Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index c51f1d5b550b..b6591ea0c6d6 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -4739,9 +4739,9 @@ static void mvpp2_xlg_config(struct mvpp2_port *port, unsigned int mode, else ctrl0 &= ~MVPP22_XLG_CTRL0_RX_FLOW_CTRL_EN; - ctrl4 &= ~MVPP22_XLG_CTRL4_MACMODSELECT_GMAC; - ctrl4 |= MVPP22_XLG_CTRL4_FWD_FC | MVPP22_XLG_CTRL4_FWD_PFC | - MVPP22_XLG_CTRL4_EN_IDLE_CHECK; + ctrl4 &= ~(MVPP22_XLG_CTRL4_MACMODSELECT_GMAC | + MVPP22_XLG_CTRL4_EN_IDLE_CHECK); + ctrl4 |= MVPP22_XLG_CTRL4_FWD_FC | MVPP22_XLG_CTRL4_FWD_PFC; if (old_ctrl0 != ctrl0) writel(ctrl0, port->base + MVPP22_XLG_CTRL0_REG); -- cgit v1.2.3-59-g8ed1b From f4e5f775db5a4631300dccd0de5eafb50a77c131 Mon Sep 17 00:00:00 2001 From: Yonglong Liu Date: Mon, 22 Jul 2019 13:59:12 +0800 Subject: net: hns: fix LED configuration for marvell phy Since commit(net: phy: marvell: change default m88e1510 LED configuration), the active LED of Hip07 devices is always off, because Hip07 just use 2 LEDs. This patch adds a phy_register_fixup_for_uid() for m88e1510 to correct the LED configuration. Fixes: 077772468ec1 ("net: phy: marvell: change default m88e1510 LED configuration") Signed-off-by: Yonglong Liu Reviewed-by: linyunsheng Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index 2235dd55fab2..5b213eb4f825 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -1149,6 +1150,13 @@ static void hns_nic_adjust_link(struct net_device *ndev) } } +static int hns_phy_marvell_fixup(struct phy_device *phydev) +{ + phydev->dev_flags |= MARVELL_PHY_LED0_LINK_LED1_ACTIVE; + + return 0; +} + /** *hns_nic_init_phy - init phy *@ndev: net device @@ -1174,6 +1182,16 @@ int hns_nic_init_phy(struct net_device *ndev, struct hnae_handle *h) if (h->phy_if != PHY_INTERFACE_MODE_XGMII) { phy_dev->dev_flags = 0; + /* register the PHY fixup (for Marvell 88E1510) */ + ret = phy_register_fixup_for_uid(MARVELL_PHY_ID_88E1510, + MARVELL_PHY_ID_MASK, + hns_phy_marvell_fixup); + /* we can live without it, so just issue a warning */ + if (ret) + netdev_warn(ndev, + "Cannot register PHY fixup, ret=%d\n", + ret); + ret = phy_connect_direct(ndev, phy_dev, hns_nic_adjust_link, h->phy_if); } else { @@ -2430,8 +2448,11 @@ static int hns_nic_dev_remove(struct platform_device *pdev) hns_nic_uninit_ring_data(priv); priv->ring_data = NULL; - if (ndev->phydev) + if (ndev->phydev) { + phy_unregister_fixup_for_uid(MARVELL_PHY_ID_88E1510, + MARVELL_PHY_ID_MASK); phy_disconnect(ndev->phydev); + } if (!IS_ERR_OR_NULL(priv->ae_handle)) hnae_put_handle(priv->ae_handle); -- cgit v1.2.3-59-g8ed1b From cbcf0999ae33e7a8e1dba7ca935556634f679ccf Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Mon, 22 Jul 2019 10:39:30 +0200 Subject: net: stmmac: RX Descriptors need to be clean before setting buffers RX Descriptors are being cleaned after setting the buffers which may lead to buffer addresses being wiped out. Fix this by clearing earlier the RX Descriptors. Fixes: 2af6106ae949 ("net: stmmac: Introducing support for Page Pool") Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index c7c9e5f162e6..5f1294ce0216 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1295,6 +1295,8 @@ static int init_dma_rx_desc_rings(struct net_device *dev, gfp_t flags) "(%s) dma_rx_phy=0x%08x\n", __func__, (u32)rx_q->dma_rx_phy); + stmmac_clear_rx_descriptors(priv, queue); + for (i = 0; i < DMA_RX_SIZE; i++) { struct dma_desc *p; @@ -1312,8 +1314,6 @@ static int init_dma_rx_desc_rings(struct net_device *dev, gfp_t flags) rx_q->cur_rx = 0; rx_q->dirty_rx = (unsigned int)(i - DMA_RX_SIZE); - stmmac_clear_rx_descriptors(priv, queue); - /* Setup the chained descriptor addresses */ if (priv->mode == STMMAC_CHAIN_MODE) { if (priv->extend_desc) -- cgit v1.2.3-59-g8ed1b From ec5e5ce1e18b44d0c4779619de3552e0afa5a11d Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Mon, 22 Jul 2019 10:39:31 +0200 Subject: net: stmmac: Use kcalloc() instead of kmalloc_array() We need the memory to be zeroed upon allocation so use kcalloc() instead. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 5f1294ce0216..0ac79f3e2cee 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1555,9 +1555,8 @@ static int alloc_dma_rx_desc_resources(struct stmmac_priv *priv) goto err_dma; } - rx_q->buf_pool = kmalloc_array(DMA_RX_SIZE, - sizeof(*rx_q->buf_pool), - GFP_KERNEL); + rx_q->buf_pool = kcalloc(DMA_RX_SIZE, sizeof(*rx_q->buf_pool), + GFP_KERNEL); if (!rx_q->buf_pool) goto err_dma; @@ -1608,15 +1607,15 @@ static int alloc_dma_tx_desc_resources(struct stmmac_priv *priv) tx_q->queue_index = queue; tx_q->priv_data = priv; - tx_q->tx_skbuff_dma = kmalloc_array(DMA_TX_SIZE, - sizeof(*tx_q->tx_skbuff_dma), - GFP_KERNEL); + tx_q->tx_skbuff_dma = kcalloc(DMA_TX_SIZE, + sizeof(*tx_q->tx_skbuff_dma), + GFP_KERNEL); if (!tx_q->tx_skbuff_dma) goto err_dma; - tx_q->tx_skbuff = kmalloc_array(DMA_TX_SIZE, - sizeof(struct sk_buff *), - GFP_KERNEL); + tx_q->tx_skbuff = kcalloc(DMA_TX_SIZE, + sizeof(struct sk_buff *), + GFP_KERNEL); if (!tx_q->tx_skbuff) goto err_dma; -- cgit v1.2.3-59-g8ed1b From df7699c70c1bc1d9333d610fdc91fbbad84b59f2 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Mon, 22 Jul 2019 16:07:21 +0200 Subject: net: stmmac: Do not cut down 1G modes Some glue logic drivers support 1G without having GMAC/GMAC4/XGMAC. Let's allow this speed by default. Reported-by: Ondrej Jirman Tested-by: Ondrej Jirman Fixes: 5b0d7d7da64b ("net: stmmac: Add the missing speeds that XGMAC supports") Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 0ac79f3e2cee..98b1a5c6d537 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -814,20 +814,15 @@ static void stmmac_validate(struct phylink_config *config, phylink_set(mac_supported, 10baseT_Full); phylink_set(mac_supported, 100baseT_Half); phylink_set(mac_supported, 100baseT_Full); + phylink_set(mac_supported, 1000baseT_Half); + phylink_set(mac_supported, 1000baseT_Full); + phylink_set(mac_supported, 1000baseKX_Full); phylink_set(mac_supported, Autoneg); phylink_set(mac_supported, Pause); phylink_set(mac_supported, Asym_Pause); phylink_set_port_modes(mac_supported); - if (priv->plat->has_gmac || - priv->plat->has_gmac4 || - priv->plat->has_xgmac) { - phylink_set(mac_supported, 1000baseT_Half); - phylink_set(mac_supported, 1000baseT_Full); - phylink_set(mac_supported, 1000baseKX_Full); - } - /* Cut down 1G if asked to */ if ((max_speed > 0) && (max_speed < 1000)) { phylink_set(mask, 1000baseT_Full); -- cgit v1.2.3-59-g8ed1b From b3e487c0cf425369a48049251af75593a5652dc1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 22 Jul 2019 20:44:48 -0700 Subject: Revert "net: hns: fix LED configuration for marvell phy" This reverts commit f4e5f775db5a4631300dccd0de5eafb50a77c131. Andrew Lunn says this should be handled another way. Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index 5b213eb4f825..2235dd55fab2 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -1150,13 +1149,6 @@ static void hns_nic_adjust_link(struct net_device *ndev) } } -static int hns_phy_marvell_fixup(struct phy_device *phydev) -{ - phydev->dev_flags |= MARVELL_PHY_LED0_LINK_LED1_ACTIVE; - - return 0; -} - /** *hns_nic_init_phy - init phy *@ndev: net device @@ -1182,16 +1174,6 @@ int hns_nic_init_phy(struct net_device *ndev, struct hnae_handle *h) if (h->phy_if != PHY_INTERFACE_MODE_XGMII) { phy_dev->dev_flags = 0; - /* register the PHY fixup (for Marvell 88E1510) */ - ret = phy_register_fixup_for_uid(MARVELL_PHY_ID_88E1510, - MARVELL_PHY_ID_MASK, - hns_phy_marvell_fixup); - /* we can live without it, so just issue a warning */ - if (ret) - netdev_warn(ndev, - "Cannot register PHY fixup, ret=%d\n", - ret); - ret = phy_connect_direct(ndev, phy_dev, hns_nic_adjust_link, h->phy_if); } else { @@ -2448,11 +2430,8 @@ static int hns_nic_dev_remove(struct platform_device *pdev) hns_nic_uninit_ring_data(priv); priv->ring_data = NULL; - if (ndev->phydev) { - phy_unregister_fixup_for_uid(MARVELL_PHY_ID_88E1510, - MARVELL_PHY_ID_MASK); + if (ndev->phydev) phy_disconnect(ndev->phydev); - } if (!IS_ERR_OR_NULL(priv->ae_handle)) hnae_put_handle(priv->ae_handle); -- cgit v1.2.3-59-g8ed1b From 78e420408d12eddd0e72613fc717f7994736ea9a Mon Sep 17 00:00:00 2001 From: Nishka Dasgupta Date: Tue, 23 Jul 2019 16:13:07 +0530 Subject: net: dsa: mv88e6xxx: chip: Add of_node_put() before return Each iteration of for_each_available_child_of_node puts the previous node, but in the case of a return from the middle of the loop, there is no put, thus causing a memory leak. Hence add an of_node_put before the return. Issue found with Coccinelle. Signed-off-by: Nishka Dasgupta Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 6b17cd961d06..c97dea4599a8 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2721,6 +2721,7 @@ static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, err = mv88e6xxx_mdio_register(chip, child, true); if (err) { mv88e6xxx_mdios_unregister(chip); + of_node_put(child); return err; } } -- cgit v1.2.3-59-g8ed1b From 7ba771e3e246fa8787abf2cce9064ec8c9b38133 Mon Sep 17 00:00:00 2001 From: Nishka Dasgupta Date: Tue, 23 Jul 2019 16:14:48 +0530 Subject: net: dsa: sja1105: sja1105_main: Add of_node_put() Each iteration of for_each_child_of_node puts the previous node, but in the case of a return from the middle of the loop, there is no put, thus causing a memory leak. Hence add an of_node_put before the return. Issue found with Coccinelle. Signed-off-by: Nishka Dasgupta Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 32bf3a7cc3b6..6ed5f1e35789 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -625,6 +625,7 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv, if (of_property_read_u32(child, "reg", &index) < 0) { dev_err(dev, "Port number not defined in device tree " "(property \"reg\")\n"); + of_node_put(child); return -ENODEV; } @@ -634,6 +635,7 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv, dev_err(dev, "Failed to read phy-mode or " "phy-interface-type property for port %d\n", index); + of_node_put(child); return -ENODEV; } ports[index].phy_mode = phy_mode; @@ -643,6 +645,7 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv, if (!of_phy_is_fixed_link(child)) { dev_err(dev, "phy-handle or fixed-link " "properties missing!\n"); + of_node_put(child); return -ENODEV; } /* phy-handle is missing, but fixed-link isn't. -- cgit v1.2.3-59-g8ed1b From a261e3797506bd561700be643fe1a85bf81e9661 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 23 Jul 2019 17:15:25 +0200 Subject: sky2: Disable MSI on ASUS P6T The onboard sky2 NIC on ASUS P6T WS PRO doesn't work after PM resume due to the infamous IRQ problem. Disabling MSI works around it, so let's add it to the blacklist. Unfortunately the BIOS on the machine doesn't fill the standard DMI_SYS_* entry, so we pick up DMI_BOARD_* entries instead. BugLink: https://bugzilla.suse.com/show_bug.cgi?id=1142496 Reported-and-tested-by: Marcus Seyfarth Signed-off-by: Takashi Iwai Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/sky2.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index f518312ffe69..a01c75ede871 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -4924,6 +4924,13 @@ static const struct dmi_system_id msi_blacklist[] = { DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"), }, }, + { + .ident = "ASUS P6T", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "P6T"), + }, + }, {} }; -- cgit v1.2.3-59-g8ed1b From d86afb89305de205b0d2f20c2160adf039e9508d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Jul 2019 23:03:43 +0300 Subject: net: thunderx: Use fwnode_get_mac_address() Replace the custom implementation with fwnode_get_mac_address, which works on both DT and ACPI platforms. While here, replace memcpy() by ether_addr_copy(). Signed-off-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index ad22554857bf..acb016834f04 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -1381,24 +1381,18 @@ static int acpi_get_mac_address(struct device *dev, struct acpi_device *adev, u8 *dst) { u8 mac[ETH_ALEN]; - int ret; + u8 *addr; - ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev), - "mac-address", mac, ETH_ALEN); - if (ret) - goto out; - - if (!is_valid_ether_addr(mac)) { + addr = fwnode_get_mac_address(acpi_fwnode_handle(adev), mac, ETH_ALEN); + if (!addr) { dev_err(dev, "MAC address invalid: %pM\n", mac); - ret = -EINVAL; - goto out; + return -EINVAL; } dev_info(dev, "MAC address set to: %pM\n", mac); - memcpy(dst, mac, ETH_ALEN); -out: - return ret; + ether_addr_copy(dst, mac); + return 0; } /* Currently only sets the MAC address. */ -- cgit v1.2.3-59-g8ed1b From c63845609c4700488e5eacd6ab4d06d5d420e5ef Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Mon, 24 Jun 2019 08:34:13 +0000 Subject: can: dev: call netif_carrier_off() in register_candev() CONFIG_CAN_LEDS is deprecated. When trying to use the generic netdev trigger as suggested, there's a small inconsistency with the link property: The LED is on initially, stays on when the device is brought up, and then turns off (as expected) when the device is brought down. Make sure the LED always reflects the state of the CAN device. Signed-off-by: Rasmus Villemoes Acked-by: Willem de Bruijn Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index b6b93a2d93a5..483d270664cc 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -1249,6 +1249,8 @@ int register_candev(struct net_device *dev) return -EINVAL; dev->rtnl_link_ops = &can_link_ops; + netif_carrier_off(dev); + return register_netdev(dev); } EXPORT_SYMBOL_GPL(register_candev); -- cgit v1.2.3-59-g8ed1b From d4b890aec4bea7334ca2ca56fd3b12fb48a00cd1 Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Wed, 26 Jun 2019 16:08:48 +0300 Subject: can: rcar_canfd: fix possible IRQ storm on high load We have observed rcar_canfd driver entering IRQ storm under high load, with following scenario: - rcar_canfd_global_interrupt() in entered due to Rx available, - napi_schedule_prep() is called, and sets NAPIF_STATE_SCHED in state - Rx fifo interrupts are masked, - rcar_canfd_global_interrupt() is entered again, this time due to error interrupt (e.g. due to overflow), - since scheduled napi poller has not yet executed, condition for calling napi_schedule_prep() from rcar_canfd_global_interrupt() remains true, thus napi_schedule_prep() gets called and sets NAPIF_STATE_MISSED flag in state, - later, napi poller function rcar_canfd_rx_poll() gets executed, and calls napi_complete_done(), - due to NAPIF_STATE_MISSED flag in state, this call does not clear NAPIF_STATE_SCHED flag from state, - on return from napi_complete_done(), rcar_canfd_rx_poll() unmasks Rx interrutps, - Rx interrupt happens, rcar_canfd_global_interrupt() gets called and calls napi_schedule_prep(), - since NAPIF_STATE_SCHED is set in state at this time, this call returns false, - due to that false return, rcar_canfd_global_interrupt() returns without masking Rx interrupt - and this results into IRQ storm: unmasked Rx interrupt happens again and again is misprocessed in the same way. This patch fixes that scenario by unmasking Rx interrupts only when napi_complete_done() returns true, which means it has cleared NAPIF_STATE_SCHED in state. Fixes: dd3bd23eb438 ("can: rcar_canfd: Add Renesas R-Car CAN FD driver") Signed-off-by: Nikita Yushchenko Cc: linux-stable Signed-off-by: Marc Kleine-Budde --- drivers/net/can/rcar/rcar_canfd.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index 05410008aa6b..de34a4b82d4a 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -1508,10 +1508,11 @@ static int rcar_canfd_rx_poll(struct napi_struct *napi, int quota) /* All packets processed */ if (num_pkts < quota) { - napi_complete_done(napi, num_pkts); - /* Enable Rx FIFO interrupts */ - rcar_canfd_set_bit(priv->base, RCANFD_RFCC(ridx), - RCANFD_RFCC_RFIE); + if (napi_complete_done(napi, num_pkts)) { + /* Enable Rx FIFO interrupts */ + rcar_canfd_set_bit(priv->base, RCANFD_RFCC(ridx), + RCANFD_RFCC_RFIE); + } } return num_pkts; } -- cgit v1.2.3-59-g8ed1b From 375f755899b8fc21196197e02aab26257df26e85 Mon Sep 17 00:00:00 2001 From: Weitao Hou Date: Tue, 25 Jun 2019 20:50:48 +0800 Subject: can: mcp251x: add error check when wq alloc failed add error check when workqueue alloc failed, and remove redundant code to make it clear. Fixes: e0000163e30e ("can: Driver for the Microchip MCP251x SPI CAN controllers") Signed-off-by: Weitao Hou Acked-by: Willem de Bruijn Tested-by: Sean Nyekjaer Signed-off-by: Marc Kleine-Budde --- drivers/net/can/spi/mcp251x.c | 49 +++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index 44e99e3d7134..2aec934fab0c 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -664,17 +664,6 @@ static int mcp251x_power_enable(struct regulator *reg, int enable) return regulator_disable(reg); } -static void mcp251x_open_clean(struct net_device *net) -{ - struct mcp251x_priv *priv = netdev_priv(net); - struct spi_device *spi = priv->spi; - - free_irq(spi->irq, priv); - mcp251x_hw_sleep(spi); - mcp251x_power_enable(priv->transceiver, 0); - close_candev(net); -} - static int mcp251x_stop(struct net_device *net) { struct mcp251x_priv *priv = netdev_priv(net); @@ -940,37 +929,43 @@ static int mcp251x_open(struct net_device *net) flags | IRQF_ONESHOT, DEVICE_NAME, priv); if (ret) { dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq); - mcp251x_power_enable(priv->transceiver, 0); - close_candev(net); - goto open_unlock; + goto out_close; } priv->wq = alloc_workqueue("mcp251x_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM, 0); + if (!priv->wq) { + ret = -ENOMEM; + goto out_clean; + } INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler); INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler); ret = mcp251x_hw_reset(spi); - if (ret) { - mcp251x_open_clean(net); - goto open_unlock; - } + if (ret) + goto out_free_wq; ret = mcp251x_setup(net, spi); - if (ret) { - mcp251x_open_clean(net); - goto open_unlock; - } + if (ret) + goto out_free_wq; ret = mcp251x_set_normal_mode(spi); - if (ret) { - mcp251x_open_clean(net); - goto open_unlock; - } + if (ret) + goto out_free_wq; can_led_event(net, CAN_LED_EVENT_OPEN); netif_wake_queue(net); + mutex_unlock(&priv->mcp_lock); -open_unlock: + return 0; + +out_free_wq: + destroy_workqueue(priv->wq); +out_clean: + free_irq(spi->irq, priv); + mcp251x_hw_sleep(spi); +out_close: + mcp251x_power_enable(priv->transceiver, 0); + close_candev(net); mutex_unlock(&priv->mcp_lock); return ret; } -- cgit v1.2.3-59-g8ed1b From e9f2a856e102fa27715b94bcc2240f686536d29b Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Sat, 6 Jul 2019 11:37:20 +0800 Subject: can: flexcan: fix an use-after-free in flexcan_setup_stop_mode() The gpr_np variable is still being used in dev_dbg() after the of_node_put() call, which may result in use-after-free. Fixes: de3578c198c6 ("can: flexcan: add self wakeup support") Signed-off-by: Wen Yang Cc: linux-stable # >= v5.0 Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index f2fe344593d5..33ce45d51e15 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -1437,10 +1437,10 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev) priv = netdev_priv(dev); priv->stm.gpr = syscon_node_to_regmap(gpr_np); - of_node_put(gpr_np); if (IS_ERR(priv->stm.gpr)) { dev_dbg(&pdev->dev, "could not find gpr regmap\n"); - return PTR_ERR(priv->stm.gpr); + ret = PTR_ERR(priv->stm.gpr); + goto out_put_node; } priv->stm.req_gpr = out_val[1]; @@ -1455,7 +1455,9 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev) device_set_wakeup_capable(&pdev->dev, true); - return 0; +out_put_node: + of_node_put(gpr_np); + return ret; } static const struct of_device_id flexcan_of_match[] = { -- cgit v1.2.3-59-g8ed1b From 5f186c257fa4808bb7f14e643b9fba3e11f08a30 Mon Sep 17 00:00:00 2001 From: Joakim Zhang Date: Tue, 2 Jul 2019 01:45:41 +0000 Subject: can: flexcan: fix stop mode acknowledgment To enter stop mode, the CPU should manually assert a global Stop Mode request and check the acknowledgment asserted by FlexCAN. The CPU must only consider the FlexCAN in stop mode when both request and acknowledgment conditions are satisfied. Fixes: de3578c198c6 ("can: flexcan: add self wakeup support") Reported-by: Marc Kleine-Budde Signed-off-by: Joakim Zhang Cc: linux-stable # >= v5.0 Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 33ce45d51e15..fcec8bcb53d6 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -400,9 +400,10 @@ static void flexcan_enable_wakeup_irq(struct flexcan_priv *priv, bool enable) priv->write(reg_mcr, ®s->mcr); } -static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv) +static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->regs; + unsigned int ackval; u32 reg_mcr; reg_mcr = priv->read(®s->mcr); @@ -412,20 +413,37 @@ static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv) /* enable stop request */ regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, 1 << priv->stm.req_bit, 1 << priv->stm.req_bit); + + /* get stop acknowledgment */ + if (regmap_read_poll_timeout(priv->stm.gpr, priv->stm.ack_gpr, + ackval, ackval & (1 << priv->stm.ack_bit), + 0, FLEXCAN_TIMEOUT_US)) + return -ETIMEDOUT; + + return 0; } -static inline void flexcan_exit_stop_mode(struct flexcan_priv *priv) +static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->regs; + unsigned int ackval; u32 reg_mcr; /* remove stop request */ regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, 1 << priv->stm.req_bit, 0); + /* get stop acknowledgment */ + if (regmap_read_poll_timeout(priv->stm.gpr, priv->stm.ack_gpr, + ackval, !(ackval & (1 << priv->stm.ack_bit)), + 0, FLEXCAN_TIMEOUT_US)) + return -ETIMEDOUT; + reg_mcr = priv->read(®s->mcr); reg_mcr &= ~FLEXCAN_MCR_SLF_WAK; priv->write(reg_mcr, ®s->mcr); + + return 0; } static inline void flexcan_error_irq_enable(const struct flexcan_priv *priv) @@ -1614,7 +1632,9 @@ static int __maybe_unused flexcan_suspend(struct device *device) */ if (device_may_wakeup(device)) { enable_irq_wake(dev->irq); - flexcan_enter_stop_mode(priv); + err = flexcan_enter_stop_mode(priv); + if (err) + return err; } else { err = flexcan_chip_disable(priv); if (err) @@ -1664,10 +1684,13 @@ static int __maybe_unused flexcan_noirq_resume(struct device *device) { struct net_device *dev = dev_get_drvdata(device); struct flexcan_priv *priv = netdev_priv(dev); + int err; if (netif_running(dev) && device_may_wakeup(device)) { flexcan_enable_wakeup_irq(priv, false); - flexcan_exit_stop_mode(priv); + err = flexcan_exit_stop_mode(priv); + if (err) + return err; } return 0; -- cgit v1.2.3-59-g8ed1b From fee6a8923ae0d318a7f7950c6c6c28a96cea099b Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Fri, 5 Jul 2019 15:32:16 +0200 Subject: can: peak_usb: fix potential double kfree_skb() When closing the CAN device while tx skbs are inflight, echo skb could be released twice. By calling close_candev() before unlinking all pending tx urbs, then the internal echo_skb[] array is fully and correctly cleared before the USB write callback and, therefore, can_get_echo_skb() are called, for each aborted URB. Fixes: bb4785551f64 ("can: usb: PEAK-System Technik USB adapters driver core") Signed-off-by: Stephane Grosjean Cc: linux-stable Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 458154c9b482..22b9c8e6d040 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -568,16 +568,16 @@ static int peak_usb_ndo_stop(struct net_device *netdev) dev->state &= ~PCAN_USB_STATE_STARTED; netif_stop_queue(netdev); + close_candev(netdev); + + dev->can.state = CAN_STATE_STOPPED; + /* unlink all pending urbs and free used memory */ peak_usb_unlink_all_urbs(dev); if (dev->adapter->dev_stop) dev->adapter->dev_stop(dev); - close_candev(netdev); - - dev->can.state = CAN_STATE_STOPPED; - /* can set bus off now */ if (dev->adapter->dev_set_bus) { int err = dev->adapter->dev_set_bus(dev, 0); -- cgit v1.2.3-59-g8ed1b From c7fa7f567cab6532be285a5df104617d80bce245 Mon Sep 17 00:00:00 2001 From: Arseny Solokha Date: Wed, 24 Jul 2019 20:31:39 +0700 Subject: net: phylink: don't start and stop SGMII PHYs in SFP modules twice SFP modules connected using the SGMII interface have their own PHYs which are handled by the struct phylink's phydev field. On the other hand, for the modules connected using 1000Base-X interface that field is not set. Since commit ce0aa27ff3f6 ("sfp: add sfp-bus to bridge between network devices and sfp cages") phylink_start() ends up setting the phydev field using the sfp-bus infrastructure, which eventually calls phy_start() on it, and then calling phy_start() again on the same phydev from phylink_start() itself. Similar call sequence holds for phylink_stop(), only in the reverse order. This results in WARNs during network interface bringup and shutdown when a copper SFP module is connected, as phy_start() and phy_stop() are called twice in a row for the same phy_device: % ip link set up dev eth0 ------------[ cut here ]------------ called from state UP WARNING: CPU: 1 PID: 155 at drivers/net/phy/phy.c:895 phy_start+0x74/0xc0 Modules linked in: CPU: 1 PID: 155 Comm: backend Not tainted 5.2.0+ #1 NIP: c0227bf0 LR: c0227bf0 CTR: c004d224 REGS: df547720 TRAP: 0700 Not tainted (5.2.0+) MSR: 00029000 CR: 24002822 XER: 00000000 GPR00: c0227bf0 df5477d8 df5d7080 00000014 df9d2370 df9d5ac4 1f4eb000 00000001 GPR08: c061fe58 00000000 00000000 df5477d8 0000003c 100c8768 00000000 00000000 GPR16: df486a00 c046f1c8 c046eea0 00000000 c046e904 c0239604 db68449c 00000000 GPR24: e9083204 00000000 00000001 db684460 e9083404 00000000 db6dce00 db6dcc00 NIP [c0227bf0] phy_start+0x74/0xc0 LR [c0227bf0] phy_start+0x74/0xc0 Call Trace: [df5477d8] [c0227bf0] phy_start+0x74/0xc0 (unreliable) [df5477e8] [c023cad0] startup_gfar+0x398/0x3f4 [df547828] [c023cf08] gfar_enet_open+0x364/0x374 [df547898] [c029d870] __dev_open+0xe4/0x140 [df5478c8] [c029db70] __dev_change_flags+0xf0/0x188 [df5478f8] [c029dc28] dev_change_flags+0x20/0x54 [df547918] [c02ae304] do_setlink+0x310/0x818 [df547a08] [c02b1eb8] __rtnl_newlink+0x384/0x6b0 [df547c28] [c02b222c] rtnl_newlink+0x48/0x68 [df547c48] [c02ad7c8] rtnetlink_rcv_msg+0x240/0x27c [df547c98] [c02cc068] netlink_rcv_skb+0x8c/0xf0 [df547cd8] [c02cba3c] netlink_unicast+0x114/0x19c [df547d08] [c02cbd74] netlink_sendmsg+0x2b0/0x2c0 [df547d58] [c027b668] sock_sendmsg_nosec+0x20/0x40 [df547d68] [c027d080] ___sys_sendmsg+0x17c/0x1dc [df547e98] [c027df7c] __sys_sendmsg+0x68/0x84 [df547ef8] [c027e430] sys_socketcall+0x1a0/0x204 [df547f38] [c000d1d8] ret_from_syscall+0x0/0x38 --- interrupt: c01 at 0xfd4e030 LR = 0xfd4e010 Instruction dump: 813f0188 38800000 2b890005 419d0014 3d40c046 5529103a 394aa208 7c8a482e 3c60c046 3863a1b8 4cc63182 4be009a1 <0fe00000> 48000030 3c60c046 3863a1d0 ---[ end trace d4c095aeaf6ea998 ]--- and % ip link set down dev eth0 ------------[ cut here ]------------ called from state HALTED WARNING: CPU: 1 PID: 184 at drivers/net/phy/phy.c:858 phy_stop+0x3c/0x88 <...> Call Trace: [df581788] [c0228450] phy_stop+0x3c/0x88 (unreliable) [df581798] [c022d548] sfp_sm_phy_detach+0x1c/0x44 [df5817a8] [c022e8cc] sfp_sm_event+0x4b0/0x87c [df581848] [c022f04c] sfp_upstream_stop+0x34/0x44 [df581858] [c0225608] phylink_stop+0x7c/0xe4 [df581868] [c023c57c] stop_gfar+0x7c/0x94 [df581888] [c023c5b8] gfar_close+0x24/0x94 [df5818a8] [c0298688] __dev_close_many+0xdc/0xf8 [df5818c8] [c029db58] __dev_change_flags+0xd8/0x188 [df5818f8] [c029dc28] dev_change_flags+0x20/0x54 [df581918] [c02ae304] do_setlink+0x310/0x818 [df581a08] [c02b1eb8] __rtnl_newlink+0x384/0x6b0 [df581c28] [c02b222c] rtnl_newlink+0x48/0x68 [df581c48] [c02ad7c8] rtnetlink_rcv_msg+0x240/0x27c [df581c98] [c02cc068] netlink_rcv_skb+0x8c/0xf0 [df581cd8] [c02cba3c] netlink_unicast+0x114/0x19c [df581d08] [c02cbd74] netlink_sendmsg+0x2b0/0x2c0 [df581d58] [c027b668] sock_sendmsg_nosec+0x20/0x40 [df581d68] [c027d080] ___sys_sendmsg+0x17c/0x1dc [df581e98] [c027df7c] __sys_sendmsg+0x68/0x84 [df581ef8] [c027e430] sys_socketcall+0x1a0/0x204 [df581f38] [c000d1d8] ret_from_syscall+0x0/0x38 <...> ---[ end trace d4c095aeaf6ea999 ]--- SFP modules with the 1000Base-X interface are not affected. Place explicit calls to phy_start() and phy_stop() before enabling or after disabling an attached SFP module, where phydev is not yet set (or is already unset), so they will be made only from the inside of sfp-bus, if needed. Fixes: 217962615662 ("net: phy: warn if phy_start is called from invalid state") Signed-off-by: Arseny Solokha Acked-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/phylink.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 5d0af041b8f9..b45862465c4d 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -990,10 +990,10 @@ void phylink_start(struct phylink *pl) } if (pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state) mod_timer(&pl->link_poll, jiffies + HZ); - if (pl->sfp_bus) - sfp_upstream_start(pl->sfp_bus); if (pl->phydev) phy_start(pl->phydev); + if (pl->sfp_bus) + sfp_upstream_start(pl->sfp_bus); } EXPORT_SYMBOL_GPL(phylink_start); @@ -1010,10 +1010,10 @@ void phylink_stop(struct phylink *pl) { ASSERT_RTNL(); - if (pl->phydev) - phy_stop(pl->phydev); if (pl->sfp_bus) sfp_upstream_stop(pl->sfp_bus); + if (pl->phydev) + phy_stop(pl->phydev); del_timer_sync(&pl->link_poll); if (pl->link_irq) { free_irq(pl->link_irq, pl); -- cgit v1.2.3-59-g8ed1b From f972037e71246c5e0916eef835174d58ffc517e4 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Wed, 24 Jul 2019 17:32:57 +0200 Subject: net: phy: mscc: initialize stats array The memory allocated for the stats array may contain arbitrary data. Fixes: e4f9ba642f0b ("net: phy: mscc: add support for VSC8514 PHY.") Fixes: 00d70d8e0e78 ("net: phy: mscc: add support for VSC8574 PHY") Fixes: a5afc1678044 ("net: phy: mscc: add support for VSC8584 PHY") Fixes: f76178dc5218 ("net: phy: mscc: add ethtool statistics counters") Signed-off-by: Andreas Schwab Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 28676af97b42..645d354ffb48 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -2226,8 +2226,8 @@ static int vsc8514_probe(struct phy_device *phydev) vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES; vsc8531->hw_stats = vsc85xx_hw_stats; vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats); - vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats, - sizeof(u64), GFP_KERNEL); + vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats, + sizeof(u64), GFP_KERNEL); if (!vsc8531->stats) return -ENOMEM; @@ -2251,8 +2251,8 @@ static int vsc8574_probe(struct phy_device *phydev) vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES; vsc8531->hw_stats = vsc8584_hw_stats; vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats); - vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats, - sizeof(u64), GFP_KERNEL); + vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats, + sizeof(u64), GFP_KERNEL); if (!vsc8531->stats) return -ENOMEM; @@ -2281,8 +2281,8 @@ static int vsc8584_probe(struct phy_device *phydev) vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES; vsc8531->hw_stats = vsc8584_hw_stats; vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats); - vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats, - sizeof(u64), GFP_KERNEL); + vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats, + sizeof(u64), GFP_KERNEL); if (!vsc8531->stats) return -ENOMEM; @@ -2311,8 +2311,8 @@ static int vsc85xx_probe(struct phy_device *phydev) vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES; vsc8531->hw_stats = vsc85xx_hw_stats; vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats); - vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats, - sizeof(u64), GFP_KERNEL); + vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats, + sizeof(u64), GFP_KERNEL); if (!vsc8531->stats) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From f06d0ca45827a5790d7508de4759aed976933d4d Mon Sep 17 00:00:00 2001 From: Yamin Friedman Date: Tue, 23 Jul 2019 10:22:47 +0300 Subject: linux/dim: Fix overflow in dim calculation While using net_dim, a dim_sample was used without ever initializing the comps value. Added use of DIV_ROUND_DOWN_ULL() to prevent potential overflow, it should not be a problem to save the final result in an int because after the division by epms the value should not be larger than a few thousand. [ 1040.127124] UBSAN: Undefined behaviour in lib/dim/dim.c:78:23 [ 1040.130118] signed integer overflow: [ 1040.131643] 134718714 * 100 cannot be represented in type 'int' Fixes: 398c2b05bbee ("linux/dim: Add completions count to dim_sample") Signed-off-by: Yamin Friedman Signed-off-by: Leon Romanovsky Acked-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 +- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c | 4 ++-- lib/dim/dim.c | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index b9c5cea8db16..9483553ce444 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -992,7 +992,7 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget) { struct bcm_sysport_priv *priv = container_of(napi, struct bcm_sysport_priv, napi); - struct dim_sample dim_sample; + struct dim_sample dim_sample = {}; unsigned int work_done = 0; work_done = bcm_sysport_desc_rx(priv, budget); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 7134d2c3eb1c..7070349915bc 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2136,7 +2136,7 @@ static int bnxt_poll(struct napi_struct *napi, int budget) } } if (bp->flags & BNXT_FLAG_DIM) { - struct dim_sample dim_sample; + struct dim_sample dim_sample = {}; dim_update_sample(cpr->event_ctr, cpr->rx_packets, diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index a2b57807453b..d3a0b614dbfa 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1895,7 +1895,7 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget) { struct bcmgenet_rx_ring *ring = container_of(napi, struct bcmgenet_rx_ring, napi); - struct dim_sample dim_sample; + struct dim_sample dim_sample = {}; unsigned int work_done; work_done = bcmgenet_desc_rx(ring, budget); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c index c50b6f0769c8..49b06b256c92 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c @@ -49,7 +49,7 @@ static inline bool mlx5e_channel_no_affinity_change(struct mlx5e_channel *c) static void mlx5e_handle_tx_dim(struct mlx5e_txqsq *sq) { struct mlx5e_sq_stats *stats = sq->stats; - struct dim_sample dim_sample; + struct dim_sample dim_sample = {}; if (unlikely(!test_bit(MLX5E_SQ_STATE_AM, &sq->state))) return; @@ -61,7 +61,7 @@ static void mlx5e_handle_tx_dim(struct mlx5e_txqsq *sq) static void mlx5e_handle_rx_dim(struct mlx5e_rq *rq) { struct mlx5e_rq_stats *stats = rq->stats; - struct dim_sample dim_sample; + struct dim_sample dim_sample = {}; if (unlikely(!test_bit(MLX5E_RQ_STATE_AM, &rq->state))) return; diff --git a/lib/dim/dim.c b/lib/dim/dim.c index 439d641ec796..38045d6d0538 100644 --- a/lib/dim/dim.c +++ b/lib/dim/dim.c @@ -74,8 +74,8 @@ void dim_calc_stats(struct dim_sample *start, struct dim_sample *end, delta_us); curr_stats->cpms = DIV_ROUND_UP(ncomps * USEC_PER_MSEC, delta_us); if (curr_stats->epms != 0) - curr_stats->cpe_ratio = - (curr_stats->cpms * 100) / curr_stats->epms; + curr_stats->cpe_ratio = DIV_ROUND_DOWN_ULL( + curr_stats->cpms * 100, curr_stats->epms); else curr_stats->cpe_ratio = 0; -- cgit v1.2.3-59-g8ed1b From 4b663366246be1d1d4b1b8b01245b2e88ad9e706 Mon Sep 17 00:00:00 2001 From: Alexis Bauvin Date: Tue, 23 Jul 2019 16:23:01 +0200 Subject: tun: mark small packets as owned by the tap sock - v1 -> v2: Move skb_set_owner_w to __tun_build_skb to reduce patch size Small packets going out of a tap device go through an optimized code path that uses build_skb() rather than sock_alloc_send_pskb(). The latter calls skb_set_owner_w(), but the small packet code path does not. The net effect is that small packets are not owned by the userland application's socket (e.g. QEMU), while large packets are. This can be seen with a TCP session, where packets are not owned when the window size is small enough (around PAGE_SIZE), while they are once the window grows (note that this requires the host to support virtio tso for the guest to offload segmentation). All this leads to inconsistent behaviour in the kernel, especially on netfilter modules that uses sk->socket (e.g. xt_owner). Fixes: 66ccbc9c87c2 ("tap: use build_skb() for small packet") Signed-off-by: Alexis Bauvin Acked-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3d443597bd04..db16d7a13e00 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1599,7 +1599,8 @@ static bool tun_can_build_skb(struct tun_struct *tun, struct tun_file *tfile, return true; } -static struct sk_buff *__tun_build_skb(struct page_frag *alloc_frag, char *buf, +static struct sk_buff *__tun_build_skb(struct tun_file *tfile, + struct page_frag *alloc_frag, char *buf, int buflen, int len, int pad) { struct sk_buff *skb = build_skb(buf, buflen); @@ -1609,6 +1610,7 @@ static struct sk_buff *__tun_build_skb(struct page_frag *alloc_frag, char *buf, skb_reserve(skb, pad); skb_put(skb, len); + skb_set_owner_w(skb, tfile->socket.sk); get_page(alloc_frag->page); alloc_frag->offset += buflen; @@ -1686,7 +1688,8 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, */ if (hdr->gso_type || !xdp_prog) { *skb_xdp = 1; - return __tun_build_skb(alloc_frag, buf, buflen, len, pad); + return __tun_build_skb(tfile, alloc_frag, buf, buflen, len, + pad); } *skb_xdp = 0; @@ -1723,7 +1726,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, rcu_read_unlock(); local_bh_enable(); - return __tun_build_skb(alloc_frag, buf, buflen, len, pad); + return __tun_build_skb(tfile, alloc_frag, buf, buflen, len, pad); err_xdp: put_page(alloc_frag->page); -- cgit v1.2.3-59-g8ed1b From 83fbae60fd3885c6e8da5863582d0317731c5528 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 24 Jul 2019 11:35:01 +1200 Subject: fsl/fman: Remove comment referring to non-existent function fm_set_max_frm() existed in the Freescale SDK as a callback for an early_param. When this code was ported to the upstream kernel the early_param was converted to a module_param making the reference to the function incorrect. The rest of the comment already does a good job of explaining the parameter so removing the reference to the non-existent function seems like the best thing to do. Signed-off-by: Chris Packham Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fman/fman.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c index e80fedb27cee..210749bf1eac 100644 --- a/drivers/net/ethernet/freescale/fman/fman.c +++ b/drivers/net/ethernet/freescale/fman/fman.c @@ -2439,9 +2439,6 @@ MODULE_PARM_DESC(fsl_fm_rx_extra_headroom, "Extra headroom for Rx buffers"); * buffers when not using jumbo frames. * Must be large enough to accommodate the network MTU, but small enough * to avoid wasting skb memory. - * - * Could be overridden once, at boot-time, via the - * fm_set_max_frm() callback. */ static int fsl_fm_max_frm = FSL_FM_MAX_FRAME_SIZE; module_param(fsl_fm_max_frm, int, 0); -- cgit v1.2.3-59-g8ed1b From 08aa5e7da6bce1a1963f63cf32c2e7ad434ad578 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Tue, 9 Jul 2019 05:37:12 +0300 Subject: net/mlx5: Use reversed order when unregister devices When lag is active, which is controlled by the bonded mlx5e netdev, mlx5 interface unregestering must happen in the reverse order where rdma is unregistered (unloaded) first, to guarantee all references to the lag context in hardware is removed, then remove mlx5e netdev interface which will cleanup the lag context from hardware. Without this fix during destroy of LAG interface, we observed following errors: * mlx5_cmd_check:752:(pid 12556): DESTROY_LAG(0x843) op_mod(0x0) failed, status bad parameter(0x3), syndrome (0xe4ac33) * mlx5_cmd_check:752:(pid 12556): DESTROY_LAG(0x843) op_mod(0x0) failed, status bad parameter(0x3), syndrome (0xa5aee8). Fixes: a31208b1e11d ("net/mlx5_core: New init and exit flow for mlx5_core") Reviewed-by: Parav Pandit Reviewed-by: Leon Romanovsky Signed-off-by: Mark Zhang Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c index 5bb6a26ea267..50862275544e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c @@ -213,7 +213,7 @@ void mlx5_unregister_device(struct mlx5_core_dev *dev) struct mlx5_interface *intf; mutex_lock(&mlx5_intf_mutex); - list_for_each_entry(intf, &intf_list, list) + list_for_each_entry_reverse(intf, &intf_list, list) mlx5_remove_device(intf, priv); list_del(&priv->dev_list); mutex_unlock(&mlx5_intf_mutex); -- cgit v1.2.3-59-g8ed1b From 987f6c69dd923069d443f6a37225f5b1630a30f2 Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Sun, 14 Jul 2019 11:33:07 +0300 Subject: net/mlx5: Add missing RDMA_RX capabilities New flow table type RDMA_RX was added but the MLX5_CAP_FLOW_TABLE_TYPE didn't handle this new flow table type. This means that MLX5_CAP_FLOW_TABLE_TYPE returns an empty capability to this flow table type. Update both the macro and the maximum supported flow table type to RDMA_RX. Fixes: d83eb50e29de ("net/mlx5: Add support in RDMA RX steering") Signed-off-by: Maor Gottlieb Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index c48c382f926f..c1252d6be0ef 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -68,7 +68,7 @@ enum fs_flow_table_type { FS_FT_SNIFFER_RX = 0X5, FS_FT_SNIFFER_TX = 0X6, FS_FT_RDMA_RX = 0X7, - FS_FT_MAX_TYPE = FS_FT_SNIFFER_TX, + FS_FT_MAX_TYPE = FS_FT_RDMA_RX, }; enum fs_flow_table_op_mod { @@ -275,7 +275,8 @@ void mlx5_cleanup_fs(struct mlx5_core_dev *dev); (type == FS_FT_FDB) ? MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, cap) : \ (type == FS_FT_SNIFFER_RX) ? MLX5_CAP_FLOWTABLE_SNIFFER_RX(mdev, cap) : \ (type == FS_FT_SNIFFER_TX) ? MLX5_CAP_FLOWTABLE_SNIFFER_TX(mdev, cap) : \ - (BUILD_BUG_ON_ZERO(FS_FT_SNIFFER_TX != FS_FT_MAX_TYPE))\ + (type == FS_FT_RDMA_RX) ? MLX5_CAP_FLOWTABLE_RDMA_RX(mdev, cap) : \ + (BUILD_BUG_ON_ZERO(FS_FT_RDMA_RX != FS_FT_MAX_TYPE))\ ) #endif -- cgit v1.2.3-59-g8ed1b From 694826e366349d5b27599f591d3bd3a53512306e Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Sun, 14 Jul 2019 11:43:43 +0300 Subject: net/mlx5e: Fix wrong max num channels indication No XSK support in the enhanced IPoIB driver and representors. Add a profile property to specify this, and enhance the logic that calculates the max number of channels to take it into account. Fixes: db05815b36cb ("net/mlx5e: Add XSK zero-copy support") Signed-off-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 12 ++------ .../net/ethernet/mellanox/mlx5/core/en/params.h | 5 +-- .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 2 +- .../ethernet/mellanox/mlx5/core/en_fs_ethtool.c | 3 +- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 36 ++++++++++------------ drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 2 ++ drivers/net/ethernet/mellanox/mlx5/core/en_stats.c | 8 ++--- .../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 7 ++--- .../ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c | 1 + 9 files changed, 35 insertions(+), 41 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 79d93d6c7d7a..ce1be2a84231 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -159,7 +159,7 @@ do { \ enum mlx5e_rq_group { MLX5E_RQ_GROUP_REGULAR, MLX5E_RQ_GROUP_XSK, - MLX5E_NUM_RQ_GROUPS /* Keep last. */ +#define MLX5E_NUM_RQ_GROUPS(g) (1 + MLX5E_RQ_GROUP_##g) }; static inline u16 mlx5_min_rx_wqes(int wq_type, u32 wq_size) @@ -182,14 +182,6 @@ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev) min_t(int, mlx5_comp_vectors_count(mdev), MLX5E_MAX_NUM_CHANNELS); } -/* Use this function to get max num channels after netdev was created */ -static inline int mlx5e_get_netdev_max_channels(struct net_device *netdev) -{ - return min_t(unsigned int, - netdev->num_rx_queues / MLX5E_NUM_RQ_GROUPS, - netdev->num_tx_queues); -} - struct mlx5e_tx_wqe { struct mlx5_wqe_ctrl_seg ctrl; struct mlx5_wqe_eth_seg eth; @@ -830,6 +822,7 @@ struct mlx5e_priv { struct net_device *netdev; struct mlx5e_stats stats; struct mlx5e_channel_stats channel_stats[MLX5E_MAX_NUM_CHANNELS]; + u16 max_nch; u8 max_opened_tc; struct hwtstamp_config tstamp; u16 q_counter; @@ -871,6 +864,7 @@ struct mlx5e_profile { mlx5e_fp_handle_rx_cqe handle_rx_cqe_mpwqe; } rx_handlers; int max_tc; + u8 rq_groups; }; void mlx5e_build_ptys2ethtool_map(void); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h index bd882b5ee9a7..3a615d663d84 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h @@ -66,9 +66,10 @@ static inline void mlx5e_qid_get_ch_and_group(struct mlx5e_params *params, *group = qid / nch; } -static inline bool mlx5e_qid_validate(struct mlx5e_params *params, u64 qid) +static inline bool mlx5e_qid_validate(const struct mlx5e_profile *profile, + struct mlx5e_params *params, u64 qid) { - return qid < params->num_channels * MLX5E_NUM_RQ_GROUPS; + return qid < params->num_channels * profile->rq_groups; } /* Parameter calculations */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 126ec4181286..ed25757ac5bd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -391,7 +391,7 @@ void mlx5e_ethtool_get_channels(struct mlx5e_priv *priv, { mutex_lock(&priv->state_lock); - ch->max_combined = mlx5e_get_netdev_max_channels(priv->netdev); + ch->max_combined = priv->max_nch; ch->combined_count = priv->channels.params.num_channels; if (priv->xsk.refcnt) { /* The upper half are XSK queues. */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c index ea3a490b569a..94304abc49e9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c @@ -611,7 +611,8 @@ static int validate_flow(struct mlx5e_priv *priv, return -ENOSPC; if (fs->ring_cookie != RX_CLS_FLOW_DISC) - if (!mlx5e_qid_validate(&priv->channels.params, fs->ring_cookie)) + if (!mlx5e_qid_validate(priv->profile, &priv->channels.params, + fs->ring_cookie)) return -EINVAL; switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 47eea6b3a1c3..570c42b7eeea 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1677,10 +1677,10 @@ static int mlx5e_open_sqs(struct mlx5e_channel *c, struct mlx5e_channel_param *cparam) { struct mlx5e_priv *priv = c->priv; - int err, tc, max_nch = mlx5e_get_netdev_max_channels(priv->netdev); + int err, tc; for (tc = 0; tc < params->num_tc; tc++) { - int txq_ix = c->ix + tc * max_nch; + int txq_ix = c->ix + tc * priv->max_nch; err = mlx5e_open_txqsq(c, c->priv->tisn[tc], txq_ix, params, &cparam->sq, &c->sq[tc], tc); @@ -2438,11 +2438,10 @@ int mlx5e_create_indirect_rqt(struct mlx5e_priv *priv) int mlx5e_create_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs) { - const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); int err; int ix; - for (ix = 0; ix < max_nch; ix++) { + for (ix = 0; ix < priv->max_nch; ix++) { err = mlx5e_create_rqt(priv, 1 /*size */, &tirs[ix].rqt); if (unlikely(err)) goto err_destroy_rqts; @@ -2460,10 +2459,9 @@ err_destroy_rqts: void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs) { - const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); int i; - for (i = 0; i < max_nch; i++) + for (i = 0; i < priv->max_nch; i++) mlx5e_destroy_rqt(priv, &tirs[i].rqt); } @@ -2557,7 +2555,7 @@ static void mlx5e_redirect_rqts(struct mlx5e_priv *priv, mlx5e_redirect_rqt(priv, rqtn, MLX5E_INDIR_RQT_SIZE, rrp); } - for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) { + for (ix = 0; ix < priv->max_nch; ix++) { struct mlx5e_redirect_rqt_param direct_rrp = { .is_rss = false, { @@ -2758,7 +2756,7 @@ static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv) goto free_in; } - for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) { + for (ix = 0; ix < priv->max_nch; ix++) { err = mlx5_core_modify_tir(mdev, priv->direct_tir[ix].tirn, in, inlen); if (err) @@ -2858,12 +2856,11 @@ static void mlx5e_netdev_set_tcs(struct net_device *netdev) static void mlx5e_build_tc2txq_maps(struct mlx5e_priv *priv) { - int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); int i, tc; - for (i = 0; i < max_nch; i++) + for (i = 0; i < priv->max_nch; i++) for (tc = 0; tc < priv->profile->max_tc; tc++) - priv->channel_tc2txq[i][tc] = i + tc * max_nch; + priv->channel_tc2txq[i][tc] = i + tc * priv->max_nch; } static void mlx5e_build_tx2sq_maps(struct mlx5e_priv *priv) @@ -2884,7 +2881,7 @@ static void mlx5e_build_tx2sq_maps(struct mlx5e_priv *priv) void mlx5e_activate_priv_channels(struct mlx5e_priv *priv) { int num_txqs = priv->channels.num * priv->channels.params.num_tc; - int num_rxqs = priv->channels.num * MLX5E_NUM_RQ_GROUPS; + int num_rxqs = priv->channels.num * priv->profile->rq_groups; struct net_device *netdev = priv->netdev; mlx5e_netdev_set_tcs(netdev); @@ -3306,7 +3303,6 @@ err_destroy_inner_tirs: int mlx5e_create_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs) { - const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); struct mlx5e_tir *tir; void *tirc; int inlen; @@ -3319,7 +3315,7 @@ int mlx5e_create_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs) if (!in) return -ENOMEM; - for (ix = 0; ix < max_nch; ix++) { + for (ix = 0; ix < priv->max_nch; ix++) { memset(in, 0, inlen); tir = &tirs[ix]; tirc = MLX5_ADDR_OF(create_tir_in, in, ctx); @@ -3358,10 +3354,9 @@ void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc) void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs) { - const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); int i; - for (i = 0; i < max_nch; i++) + for (i = 0; i < priv->max_nch; i++) mlx5e_destroy_tir(priv->mdev, &tirs[i]); } @@ -3487,7 +3482,7 @@ void mlx5e_fold_sw_stats64(struct mlx5e_priv *priv, struct rtnl_link_stats64 *s) { int i; - for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++) { + for (i = 0; i < priv->max_nch; i++) { struct mlx5e_channel_stats *channel_stats = &priv->channel_stats[i]; struct mlx5e_rq_stats *xskrq_stats = &channel_stats->xskrq; struct mlx5e_rq_stats *rq_stats = &channel_stats->rq; @@ -4960,8 +4955,7 @@ static int mlx5e_nic_init(struct mlx5_core_dev *mdev, return err; mlx5e_build_nic_params(mdev, &priv->xsk, rss, &priv->channels.params, - mlx5e_get_netdev_max_channels(netdev), - netdev->mtu); + priv->max_nch, netdev->mtu); mlx5e_timestamp_init(priv); @@ -5164,6 +5158,7 @@ static const struct mlx5e_profile mlx5e_nic_profile = { .rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe, .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq, .max_tc = MLX5E_MAX_NUM_TC, + .rq_groups = MLX5E_NUM_RQ_GROUPS(XSK), }; /* mlx5e generic netdev management API (move to en_common.c) */ @@ -5181,6 +5176,7 @@ int mlx5e_netdev_init(struct net_device *netdev, priv->profile = profile; priv->ppriv = ppriv; priv->msglevel = MLX5E_MSG_LEVEL; + priv->max_nch = netdev->num_rx_queues / max_t(u8, profile->rq_groups, 1); priv->max_opened_tc = 1; mutex_init(&priv->state_lock); @@ -5218,7 +5214,7 @@ struct net_device *mlx5e_create_netdev(struct mlx5_core_dev *mdev, netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv), nch * profile->max_tc, - nch * MLX5E_NUM_RQ_GROUPS); + nch * profile->rq_groups); if (!netdev) { mlx5_core_err(mdev, "alloc_etherdev_mqs() failed\n"); return NULL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 7245d287633d..731819a26a0c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1702,6 +1702,7 @@ static const struct mlx5e_profile mlx5e_rep_profile = { .rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe_rep, .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq, .max_tc = 1, + .rq_groups = MLX5E_NUM_RQ_GROUPS(REGULAR), }; static const struct mlx5e_profile mlx5e_uplink_rep_profile = { @@ -1719,6 +1720,7 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = { .rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe_rep, .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq, .max_tc = MLX5E_MAX_NUM_TC, + .rq_groups = MLX5E_NUM_RQ_GROUPS(REGULAR), }; static bool diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c index 539b4d3656da..57f9f346d213 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c @@ -172,7 +172,7 @@ static void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv) memset(s, 0, sizeof(*s)); - for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++) { + for (i = 0; i < priv->max_nch; i++) { struct mlx5e_channel_stats *channel_stats = &priv->channel_stats[i]; struct mlx5e_xdpsq_stats *xdpsq_red_stats = &channel_stats->xdpsq; @@ -1395,7 +1395,7 @@ static const struct counter_desc ch_stats_desc[] = { static int mlx5e_grp_channels_get_num_stats(struct mlx5e_priv *priv) { - int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); + int max_nch = priv->max_nch; return (NUM_RQ_STATS * max_nch) + (NUM_CH_STATS * max_nch) + @@ -1409,8 +1409,8 @@ static int mlx5e_grp_channels_get_num_stats(struct mlx5e_priv *priv) static int mlx5e_grp_channels_fill_strings(struct mlx5e_priv *priv, u8 *data, int idx) { - int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); bool is_xsk = priv->xsk.ever_used; + int max_nch = priv->max_nch; int i, j, tc; for (i = 0; i < max_nch; i++) @@ -1452,8 +1452,8 @@ static int mlx5e_grp_channels_fill_strings(struct mlx5e_priv *priv, u8 *data, static int mlx5e_grp_channels_fill_stats(struct mlx5e_priv *priv, u64 *data, int idx) { - int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); bool is_xsk = priv->xsk.ever_used; + int max_nch = priv->max_nch; int i, j, tc; for (i = 0; i < max_nch; i++) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 6bfaaab362dc..1a2560e3bf7c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -88,8 +88,7 @@ int mlx5i_init(struct mlx5_core_dev *mdev, netdev->mtu = netdev->max_mtu; mlx5e_build_nic_params(mdev, NULL, &priv->rss_params, &priv->channels.params, - mlx5e_get_netdev_max_channels(netdev), - netdev->mtu); + priv->max_nch, netdev->mtu); mlx5i_build_nic_params(mdev, &priv->channels.params); mlx5e_timestamp_init(priv); @@ -118,11 +117,10 @@ void mlx5i_cleanup(struct mlx5e_priv *priv) static void mlx5i_grp_sw_update_stats(struct mlx5e_priv *priv) { - int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); struct mlx5e_sw_stats s = { 0 }; int i, j; - for (i = 0; i < max_nch; i++) { + for (i = 0; i < priv->max_nch; i++) { struct mlx5e_channel_stats *channel_stats; struct mlx5e_rq_stats *rq_stats; @@ -436,6 +434,7 @@ static const struct mlx5e_profile mlx5i_nic_profile = { .rx_handlers.handle_rx_cqe = mlx5i_handle_rx_cqe, .rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */ .max_tc = MLX5I_MAX_NUM_TC, + .rq_groups = MLX5E_NUM_RQ_GROUPS(REGULAR), }; /* mlx5i netdev NDos */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c index 6e56fa769d2e..c5a491e22e55 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c @@ -355,6 +355,7 @@ static const struct mlx5e_profile mlx5i_pkey_nic_profile = { .rx_handlers.handle_rx_cqe = mlx5i_handle_rx_cqe, .rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */ .max_tc = MLX5I_MAX_NUM_TC, + .rq_groups = MLX5E_NUM_RQ_GROUPS(REGULAR), }; const struct mlx5e_profile *mlx5i_pkey_get_profile(void) -- cgit v1.2.3-59-g8ed1b From 4b95840a6ced0634082f6d962ba9aa0ce797f12f Mon Sep 17 00:00:00 2001 From: Aya Levin Date: Sun, 16 Jun 2019 13:20:29 +0300 Subject: net/mlx5e: Fix matching of speed to PRM link modes Speed translation is performed based on legacy or extended PTYS register. Translate speed with respect to: 1) Capability bit of extended PTYS table. 2) User request: a) When auto-negotiation is turned on, inspect advertisement whether it contains extended link modes. b) When auto-negotiation is turned off, speed > 100Gbps (maximal speed supported in legacy mode). With both conditions fulfilled translation is done with extended PTYS table otherwise use legacy PTYS table. Without this patch 25/50/100 Gbps speed cannot be set, since try to configure in extended mode but read from legacy mode. Fixes: dd1b9e09c12b ("net/mlx5: ethtool, Allow legacy link-modes configuration via non-extended ptys") Signed-off-by: Aya Levin Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en/port.c | 27 ++++++--- drivers/net/ethernet/mellanox/mlx5/core/en/port.h | 6 +- .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 67 +++++++++++++++------- 3 files changed, 68 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c index d5e5afbdca6d..f777994f3005 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c @@ -78,9 +78,10 @@ static const u32 mlx5e_ext_link_speed[MLX5E_EXT_LINK_MODES_NUMBER] = { }; static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev, - const u32 **arr, u32 *size) + const u32 **arr, u32 *size, + bool force_legacy) { - bool ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet); + bool ext = force_legacy ? false : MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet); *size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) : ARRAY_SIZE(mlx5e_link_speed); @@ -152,7 +153,8 @@ int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable, sizeof(out), MLX5_REG_PTYS, 0, 1); } -u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper) +u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper, + bool force_legacy) { unsigned long temp = eth_proto_oper; const u32 *table; @@ -160,7 +162,7 @@ u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper) u32 max_size; int i; - mlx5e_port_get_speed_arr(mdev, &table, &max_size); + mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy); i = find_first_bit(&temp, max_size); if (i < max_size) speed = table[i]; @@ -170,6 +172,7 @@ u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper) int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) { struct mlx5e_port_eth_proto eproto; + bool force_legacy = false; bool ext; int err; @@ -177,8 +180,13 @@ int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto); if (err) goto out; - - *speed = mlx5e_port_ptys2speed(mdev, eproto.oper); + if (ext && !eproto.admin) { + force_legacy = true; + err = mlx5_port_query_eth_proto(mdev, 1, false, &eproto); + if (err) + goto out; + } + *speed = mlx5e_port_ptys2speed(mdev, eproto.oper, force_legacy); if (!(*speed)) err = -EINVAL; @@ -201,7 +209,7 @@ int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) if (err) return err; - mlx5e_port_get_speed_arr(mdev, &table, &max_size); + mlx5e_port_get_speed_arr(mdev, &table, &max_size, false); for (i = 0; i < max_size; ++i) if (eproto.cap & MLX5E_PROT_MASK(i)) max_speed = max(max_speed, table[i]); @@ -210,14 +218,15 @@ int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) return 0; } -u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed) +u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed, + bool force_legacy) { u32 link_modes = 0; const u32 *table; u32 max_size; int i; - mlx5e_port_get_speed_arr(mdev, &table, &max_size); + mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy); for (i = 0; i < max_size; ++i) { if (table[i] == speed) link_modes |= MLX5E_PROT_MASK(i); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port.h b/drivers/net/ethernet/mellanox/mlx5/core/en/port.h index 70f536ec51c4..4a7f4497692b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/port.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port.h @@ -48,10 +48,12 @@ void mlx5_port_query_eth_autoneg(struct mlx5_core_dev *dev, u8 *an_status, u8 *an_disable_cap, u8 *an_disable_admin); int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable, u32 proto_admin, bool ext); -u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper); +u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper, + bool force_legacy); int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed); int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed); -u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed); +u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed, + bool force_legacy); int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out); int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index ed25757ac5bd..03bed714bac3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -785,7 +785,7 @@ static void ptys2ethtool_supported_advertised_port(struct ethtool_link_ksettings } static void get_speed_duplex(struct net_device *netdev, - u32 eth_proto_oper, + u32 eth_proto_oper, bool force_legacy, struct ethtool_link_ksettings *link_ksettings) { struct mlx5e_priv *priv = netdev_priv(netdev); @@ -795,7 +795,7 @@ static void get_speed_duplex(struct net_device *netdev, if (!netif_carrier_ok(netdev)) goto out; - speed = mlx5e_port_ptys2speed(priv->mdev, eth_proto_oper); + speed = mlx5e_port_ptys2speed(priv->mdev, eth_proto_oper, force_legacy); if (!speed) { speed = SPEED_UNKNOWN; goto out; @@ -914,8 +914,8 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv, /* Fields: eth_proto_admin and ext_eth_proto_admin are * mutually exclusive. Hence try reading legacy advertising * when extended advertising is zero. - * admin_ext indicates how eth_proto_admin should be - * interpreted + * admin_ext indicates which proto_admin (ext vs. legacy) + * should be read and interpreted */ admin_ext = ext; if (ext && !eth_proto_admin) { @@ -924,7 +924,7 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv, admin_ext = false; } - eth_proto_oper = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, + eth_proto_oper = MLX5_GET_ETH_PROTO(ptys_reg, out, admin_ext, eth_proto_oper); eth_proto_lp = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise); an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin); @@ -939,7 +939,8 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv, get_supported(mdev, eth_proto_cap, link_ksettings); get_advertising(eth_proto_admin, tx_pause, rx_pause, link_ksettings, admin_ext); - get_speed_duplex(priv->netdev, eth_proto_oper, link_ksettings); + get_speed_duplex(priv->netdev, eth_proto_oper, !admin_ext, + link_ksettings); eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap; @@ -1016,45 +1017,69 @@ static u32 mlx5e_ethtool2ptys_ext_adver_link(const unsigned long *link_modes) return ptys_modes; } +static bool ext_link_mode_requested(const unsigned long *adver) +{ +#define MLX5E_MIN_PTYS_EXT_LINK_MODE_BIT ETHTOOL_LINK_MODE_50000baseKR_Full_BIT + int size = __ETHTOOL_LINK_MODE_MASK_NBITS - MLX5E_MIN_PTYS_EXT_LINK_MODE_BIT; + __ETHTOOL_DECLARE_LINK_MODE_MASK(modes); + + bitmap_set(modes, MLX5E_MIN_PTYS_EXT_LINK_MODE_BIT, size); + return bitmap_intersects(modes, adver, __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +static bool ext_speed_requested(u32 speed) +{ +#define MLX5E_MAX_PTYS_LEGACY_SPEED 100000 + return !!(speed > MLX5E_MAX_PTYS_LEGACY_SPEED); +} + +static bool ext_requested(u8 autoneg, const unsigned long *adver, u32 speed) +{ + bool ext_link_mode = ext_link_mode_requested(adver); + bool ext_speed = ext_speed_requested(speed); + + return autoneg == AUTONEG_ENABLE ? ext_link_mode : ext_speed; +} + int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv, const struct ethtool_link_ksettings *link_ksettings) { struct mlx5_core_dev *mdev = priv->mdev; struct mlx5e_port_eth_proto eproto; + const unsigned long *adver; bool an_changes = false; u8 an_disable_admin; bool ext_supported; - bool ext_requested; u8 an_disable_cap; bool an_disable; u32 link_modes; u8 an_status; + u8 autoneg; u32 speed; + bool ext; int err; u32 (*ethtool2ptys_adver_func)(const unsigned long *adver); -#define MLX5E_PTYS_EXT ((1ULL << ETHTOOL_LINK_MODE_50000baseKR_Full_BIT) - 1) + adver = link_ksettings->link_modes.advertising; + autoneg = link_ksettings->base.autoneg; + speed = link_ksettings->base.speed; - ext_requested = !!(link_ksettings->link_modes.advertising[0] > - MLX5E_PTYS_EXT || - link_ksettings->link_modes.advertising[1]); + ext = ext_requested(autoneg, adver, speed), ext_supported = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet); - ext_requested &= ext_supported; + if (!ext_supported && ext) + return -EOPNOTSUPP; - speed = link_ksettings->base.speed; - ethtool2ptys_adver_func = ext_requested ? - mlx5e_ethtool2ptys_ext_adver_link : + ethtool2ptys_adver_func = ext ? mlx5e_ethtool2ptys_ext_adver_link : mlx5e_ethtool2ptys_adver_link; - err = mlx5_port_query_eth_proto(mdev, 1, ext_requested, &eproto); + err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto); if (err) { netdev_err(priv->netdev, "%s: query port eth proto failed: %d\n", __func__, err); goto out; } - link_modes = link_ksettings->base.autoneg == AUTONEG_ENABLE ? - ethtool2ptys_adver_func(link_ksettings->link_modes.advertising) : - mlx5e_port_speed2linkmodes(mdev, speed); + link_modes = autoneg == AUTONEG_ENABLE ? ethtool2ptys_adver_func(adver) : + mlx5e_port_speed2linkmodes(mdev, speed, !ext); link_modes = link_modes & eproto.cap; if (!link_modes) { @@ -1067,14 +1092,14 @@ int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv, mlx5_port_query_eth_autoneg(mdev, &an_status, &an_disable_cap, &an_disable_admin); - an_disable = link_ksettings->base.autoneg == AUTONEG_DISABLE; + an_disable = autoneg == AUTONEG_DISABLE; an_changes = ((!an_disable && an_disable_admin) || (an_disable && !an_disable_admin)); if (!an_changes && link_modes == eproto.admin) goto out; - mlx5_port_set_eth_ptys(mdev, an_disable, link_modes, ext_requested); + mlx5_port_set_eth_ptys(mdev, an_disable, link_modes, ext); mlx5_toggle_port_link(mdev); out: -- cgit v1.2.3-59-g8ed1b From 90bb769291161cf25a818d69cf608c181654473e Mon Sep 17 00:00:00 2001 From: Ariel Levkovich Date: Sat, 6 Jul 2019 18:06:15 +0300 Subject: net/mlx5e: Prevent encap flow counter update async to user query This patch prevents a race between user invoked cached counters query and a neighbor last usage updater. The cached flow counter stats can be queried by calling "mlx5_fc_query_cached" which provides the number of bytes and packets that passed via this flow since the last time this counter was queried. It does so by reducting the last saved stats from the current, cached stats and then updating the last saved stats with the cached stats. It also provide the lastuse value for that flow. Since "mlx5e_tc_update_neigh_used_value" needs to retrieve the last usage time of encapsulation flows, it calls the flow counter query method periodically and async to user queries of the flow counter using cls_flower. This call is causing the driver to update the last reported bytes and packets from the cache and therefore, future user queries of the flow stats will return lower than expected number for bytes and packets since the last saved stats in the driver was updated async to the last saved stats in cls_flower. This causes wrong stats presentation of encapsulation flows to user. Since the neighbor usage updater only needs the lastuse stats from the cached counter, the fix is to use a dedicated lastuse query call that returns the lastuse value without synching between the cached stats and the last saved stats. Fixes: f6dfb4c3f216 ("net/mlx5e: Update neighbour 'used' state using HW flow rules counters") Signed-off-by: Ariel Levkovich Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c | 5 +++++ include/linux/mlx5/fs.h | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index cc096f6011d9..7ecfc53cf5f6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1230,13 +1230,13 @@ static struct mlx5_fc *mlx5e_tc_get_counter(struct mlx5e_tc_flow *flow) void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe) { struct mlx5e_neigh *m_neigh = &nhe->m_neigh; - u64 bytes, packets, lastuse = 0; struct mlx5e_tc_flow *flow; struct mlx5e_encap_entry *e; struct mlx5_fc *counter; struct neigh_table *tbl; bool neigh_used = false; struct neighbour *n; + u64 lastuse; if (m_neigh->family == AF_INET) tbl = &arp_tbl; @@ -1256,7 +1256,7 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe) encaps[efi->index]); if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) { counter = mlx5e_tc_get_counter(flow); - mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse); + lastuse = mlx5_fc_query_lastuse(counter); if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) { neigh_used = true; break; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c index b3762123a69c..1834d9f3aa1c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c @@ -369,6 +369,11 @@ int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter, } EXPORT_SYMBOL(mlx5_fc_query); +u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter) +{ + return counter->cache.lastuse; +} + void mlx5_fc_query_cached(struct mlx5_fc *counter, u64 *bytes, u64 *packets, u64 *lastuse) { diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index 04a569568eac..f049af3f3cd8 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -220,6 +220,7 @@ int mlx5_modify_rule_destination(struct mlx5_flow_handle *handler, struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging); void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter); +u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter); void mlx5_fc_query_cached(struct mlx5_fc *counter, u64 *bytes, u64 *packets, u64 *lastuse); int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter, -- cgit v1.2.3-59-g8ed1b From 304ecc9a34b81a8b03b685f4460d0f9c1d6d4df9 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 18 Jul 2019 16:32:31 +0300 Subject: net/mlx5e: kTLS, Call WARN_ONCE on netdev mismatch A netdev mismatch in the processed TLS SKB should not occur, and indicates a kernel bug. Add WARN_ONCE to spot such cases. Fixes: d2ead1f360e8 ("net/mlx5e: Add kTLS TX HW offload support") Suggested-by: Jakub Kicinski Signed-off-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c index ea032f54197e..3766545ce259 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c @@ -412,7 +412,7 @@ struct sk_buff *mlx5e_ktls_handle_tx_skb(struct net_device *netdev, goto out; tls_ctx = tls_get_ctx(skb->sk); - if (unlikely(tls_ctx->netdev != netdev)) + if (unlikely(WARN_ON_ONCE(tls_ctx->netdev != netdev))) goto err_out; priv_tx = mlx5e_get_ktls_tx_priv_ctx(tls_ctx); -- cgit v1.2.3-59-g8ed1b From 4ea52e25089724abf7ee2d6c0c52064e49252b64 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 18 Jul 2019 16:34:05 +0300 Subject: nfp: tls: rename tls packet counters Align to the naming convention in TLS documentation. Fixes: 51a5e563298d ("nfp: tls: add basic statistics") Suggested-by: Jakub Kicinski Signed-off-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index d9cbe84ac6ad..1b840ee47339 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -444,12 +444,12 @@ static u8 *nfp_vnic_get_sw_stats_strings(struct net_device *netdev, u8 *data) data = nfp_pr_et(data, "hw_rx_csum_complete"); data = nfp_pr_et(data, "hw_rx_csum_err"); data = nfp_pr_et(data, "rx_replace_buf_alloc_fail"); - data = nfp_pr_et(data, "rx_tls_decrypted"); + data = nfp_pr_et(data, "rx_tls_decrypted_packets"); data = nfp_pr_et(data, "hw_tx_csum"); data = nfp_pr_et(data, "hw_tx_inner_csum"); data = nfp_pr_et(data, "tx_gather"); data = nfp_pr_et(data, "tx_lso"); - data = nfp_pr_et(data, "tx_tls_encrypted"); + data = nfp_pr_et(data, "tx_tls_encrypted_packets"); data = nfp_pr_et(data, "tx_tls_ooo"); data = nfp_pr_et(data, "tx_tls_drop_no_sync_data"); -- cgit v1.2.3-59-g8ed1b From d1f0b5dce8fda09a7f5f04c1878f181d548e42f5 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Tue, 23 Jul 2019 19:32:41 -0700 Subject: bnx2x: Disable multi-cos feature. Commit 3968d38917eb ("bnx2x: Fix Multi-Cos.") which enabled multi-cos feature after prolonged time in driver added some regression causing numerous issues (sudden reboots, tx timeout etc.) reported by customers. We plan to backout this commit and submit proper fix once we have root cause of issues reported with this feature enabled. Fixes: 3968d38917eb ("bnx2x: Fix Multi-Cos.") Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Manish Chopra Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index e2be5a685130..e47ea92e2ae3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1934,8 +1934,7 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb, } /* select a non-FCoE queue */ - return netdev_pick_tx(dev, skb, NULL) % - (BNX2X_NUM_ETH_QUEUES(bp) * bp->max_cos); + return netdev_pick_tx(dev, skb, NULL) % (BNX2X_NUM_ETH_QUEUES(bp)); } void bnx2x_set_num_queues(struct bnx2x *bp) -- cgit v1.2.3-59-g8ed1b From 9a07406b00cdc6ec689dc142540739575c717f3c Mon Sep 17 00:00:00 2001 From: Bob Ham Date: Wed, 24 Jul 2019 07:52:27 -0700 Subject: net: usb: qmi_wwan: Add the BroadMobi BM818 card The BroadMobi BM818 M.2 card uses the QMI protocol Signed-off-by: Bob Ham Signed-off-by: Angus Ainslie (Purism) Signed-off-by: David S. Miller --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 69e0a2acfcb0..b6dc5d714b5e 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1295,6 +1295,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x2001, 0x7e3d, 4)}, /* D-Link DWM-222 A2 */ {QMI_FIXED_INTF(0x2020, 0x2031, 4)}, /* Olicard 600 */ {QMI_FIXED_INTF(0x2020, 0x2033, 4)}, /* BroadMobi BM806U */ + {QMI_FIXED_INTF(0x2020, 0x2060, 4)}, /* BroadMobi BM818 */ {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)}, /* Sierra Wireless MC7700 */ {QMI_FIXED_INTF(0x114f, 0x68a2, 8)}, /* Sierra Wireless MC7750 */ {QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */ -- cgit v1.2.3-59-g8ed1b From 81af04b432fdfabcdbd2c06be2ee647e3ca41a22 Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Thu, 25 Jul 2019 13:59:55 +0300 Subject: qed: RDMA - Fix the hw_ver returned in device attributes The hw_ver field was initialized to zero. Return the chip revision. This is relevant for rdma driver. Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_rdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c b/drivers/net/ethernet/qlogic/qed/qed_rdma.c index 17c64e43d6c3..158ac0738911 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c @@ -442,7 +442,7 @@ static void qed_rdma_init_devinfo(struct qed_hwfn *p_hwfn, /* Vendor specific information */ dev->vendor_id = cdev->vendor_id; dev->vendor_part_id = cdev->device_id; - dev->hw_ver = 0; + dev->hw_ver = cdev->chip_rev; dev->fw_ver = (FW_MAJOR_VERSION << 24) | (FW_MINOR_VERSION << 16) | (FW_REVISION_VERSION << 8) | (FW_ENGINEERING_VERSION); -- cgit v1.2.3-59-g8ed1b From c5d139697d5d9ecf9c7cd92d7d7838a173508900 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Thu, 25 Jul 2019 16:33:18 +0300 Subject: ocelot: Cancel delayed work before wq destruction Make sure the delayed work for stats update is not pending before wq destruction. This fixes the module unload path. The issue is there since day 1. Fixes: a556c76adc05 ("net: mscc: Add initial Ocelot switch support") Signed-off-by: Claudiu Manoil Reviewed-by: Alexandre Belloni Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index b71e4ecbe469..6932e615d4b0 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1818,6 +1818,7 @@ EXPORT_SYMBOL(ocelot_init); void ocelot_deinit(struct ocelot *ocelot) { + cancel_delayed_work(&ocelot->stats_work); destroy_workqueue(ocelot->stats_queue); mutex_destroy(&ocelot->stats_lock); ocelot_ace_deinit(); -- cgit v1.2.3-59-g8ed1b From a7cf3d24ee6081930feb4c830a7f6f16ebe31c49 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Thu, 25 Jul 2019 12:07:12 -0600 Subject: net: qualcomm: rmnet: Fix incorrect UL checksum offload logic The udp_ip4_ind bit is set only for IPv4 UDP non-fragmented packets so that the hardware can flip the checksum to 0xFFFF if the computed checksum is 0 per RFC768. However, this bit had to be set for IPv6 UDP non fragmented packets as well per hardware requirements. Otherwise, IPv6 UDP packets with computed checksum as 0 were transmitted by hardware and were dropped in the network. In addition to setting this bit for IPv6 UDP, the field is also appropriately renamed to udp_ind as part of this change. Fixes: 5eb5f8608ef1 ("net: qualcomm: rmnet: Add support for TX checksum offload") Cc: Sean Tranchetti Signed-off-by: Subash Abhinov Kasiviswanathan Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c | 13 +++++++++---- include/linux/if_rmnet.h | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c index 60189923737a..21d38167f961 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c @@ -206,9 +206,9 @@ rmnet_map_ipv4_ul_csum_header(void *iphdr, ul_header->csum_insert_offset = skb->csum_offset; ul_header->csum_enabled = 1; if (ip4h->protocol == IPPROTO_UDP) - ul_header->udp_ip4_ind = 1; + ul_header->udp_ind = 1; else - ul_header->udp_ip4_ind = 0; + ul_header->udp_ind = 0; /* Changing remaining fields to network order */ hdr++; @@ -239,6 +239,7 @@ rmnet_map_ipv6_ul_csum_header(void *ip6hdr, struct rmnet_map_ul_csum_header *ul_header, struct sk_buff *skb) { + struct ipv6hdr *ip6h = (struct ipv6hdr *)ip6hdr; __be16 *hdr = (__be16 *)ul_header, offset; offset = htons((__force u16)(skb_transport_header(skb) - @@ -246,7 +247,11 @@ rmnet_map_ipv6_ul_csum_header(void *ip6hdr, ul_header->csum_start_offset = offset; ul_header->csum_insert_offset = skb->csum_offset; ul_header->csum_enabled = 1; - ul_header->udp_ip4_ind = 0; + + if (ip6h->nexthdr == IPPROTO_UDP) + ul_header->udp_ind = 1; + else + ul_header->udp_ind = 0; /* Changing remaining fields to network order */ hdr++; @@ -419,7 +424,7 @@ sw_csum: ul_header->csum_start_offset = 0; ul_header->csum_insert_offset = 0; ul_header->csum_enabled = 0; - ul_header->udp_ip4_ind = 0; + ul_header->udp_ind = 0; priv->stats.csum_sw++; } diff --git a/include/linux/if_rmnet.h b/include/linux/if_rmnet.h index b4f5403383fc..9661416a9bb4 100644 --- a/include/linux/if_rmnet.h +++ b/include/linux/if_rmnet.h @@ -41,11 +41,11 @@ struct rmnet_map_ul_csum_header { __be16 csum_start_offset; #if defined(__LITTLE_ENDIAN_BITFIELD) u16 csum_insert_offset:14; - u16 udp_ip4_ind:1; + u16 udp_ind:1; u16 csum_enabled:1; #elif defined (__BIG_ENDIAN_BITFIELD) u16 csum_enabled:1; - u16 udp_ip4_ind:1; + u16 udp_ind:1; u16 csum_insert_offset:14; #else #error "Please fix " -- cgit v1.2.3-59-g8ed1b From 8aace4f3eba2a3ceb431e18683ea0e1ecbade5cd Mon Sep 17 00:00:00 2001 From: René van Dorst Date: Sat, 27 Jul 2019 11:40:11 +0200 Subject: net: phylink: Fix flow control for fixed-link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In phylink_parse_fixedlink() the pl->link_config.advertising bits are AND with pl->supported, pl->supported is zeroed and only the speed/duplex modes and MII bits are set. So pl->link_config.advertising always loses the flow control/pause bits. By setting Pause and Asym_Pause bits in pl->supported, the flow control work again when devicetree "pause" is set in fixes-link node and the MAC advertise that is supports pause. Results with this patch. Legend: - DT = 'Pause' is set in the fixed-link in devicetree. - validate() = ‘Yes’ means phylink_set(mask, Pause) is set in the validate(). - flow = results reported my link is Up line. +-----+------------+-------+ | DT | validate() | flow | +-----+------------+-------+ | Yes | Yes | rx/tx | | No | Yes | off | | Yes | No | off | +-----+------------+-------+ Fixes: 9525ae83959b ("phylink: add phylink infrastructure") Signed-off-by: René van Dorst Acked-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/phylink.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index b45862465c4d..a45c5de96ab1 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -216,6 +216,8 @@ static int phylink_parse_fixedlink(struct phylink *pl, pl->supported, true); linkmode_zero(pl->supported); phylink_set(pl->supported, MII); + phylink_set(pl->supported, Pause); + phylink_set(pl->supported, Asym_Pause); if (s) { __set_bit(s->bit, pl->supported); } else { -- cgit v1.2.3-59-g8ed1b From 66058b1ca5651c7671bf2ba27fcf6907fb20bd0b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 27 Jul 2019 12:32:28 +0200 Subject: Revert ("r8169: remove 1000/Half from supported modes") This reverts commit a6851c613fd7fccc5d1f28d5d8a0cbe9b0f4e8cc. It was reported that RTL8111b successfully finishes 1000/Full autoneg but no data flows. Reverting the original patch fixes the issue. It seems to be a HW issue with the integrated RTL8211B PHY. This PHY version used also e.g. on RTL8168d, so better revert the original patch. Reported-by: Bernhard Held Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 6272115b2848..a71dd669a728 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -6136,10 +6136,7 @@ static int r8169_phy_connect(struct rtl8169_private *tp) if (ret) return ret; - if (tp->supports_gmii) - phy_remove_link_mode(phydev, - ETHTOOL_LINK_MODE_1000baseT_Half_BIT); - else + if (!tp->supports_gmii) phy_set_max_speed(phydev, SPEED_100); phy_support_asym_pause(phydev); -- cgit v1.2.3-59-g8ed1b From 003bd5b4a7b4a94b501e3a1e2e7c9df6b2a94ed4 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 27 Jul 2019 12:43:31 +0200 Subject: r8169: don't use MSI before RTL8168d MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was reported that after resuming from suspend network fails with error "do_IRQ: 3.38 No irq handler for vector", see [0]. Enabling WoL can work around the issue, but the only actual fix is to disable MSI. So let's mimic the behavior of the vendor driver and disable MSI on all chip versions before RTL8168d. [0] https://bugzilla.kernel.org/show_bug.cgi?id=204079 Fixes: 6c6aa15fdea5 ("r8169: improve interrupt handling") Reported-by: DuÅ¡an Dragić Tested-by: DuÅ¡an Dragić Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index a71dd669a728..e1dd6ea60d67 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -6586,13 +6586,18 @@ static int rtl_alloc_irq(struct rtl8169_private *tp) { unsigned int flags; - if (tp->mac_version <= RTL_GIGA_MAC_VER_06) { + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: rtl_unlock_config_regs(tp); RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~MSIEnable); rtl_lock_config_regs(tp); + /* fall through */ + case RTL_GIGA_MAC_VER_07 ... RTL_GIGA_MAC_VER_24: flags = PCI_IRQ_LEGACY; - } else { + break; + default: flags = PCI_IRQ_ALL_TYPES; + break; } return pci_alloc_irq_vectors(tp->pci_dev, 1, 1, flags); -- cgit v1.2.3-59-g8ed1b From b55f3b841099e641bdb2701d361a4c304e2dbd6f Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Mon, 29 Jul 2019 16:23:32 +0800 Subject: mac80211_hwsim: Fix possible null-pointer dereferences in hwsim_dump_radio_nl() In hwsim_dump_radio_nl(), when genlmsg_put() on line 3617 fails, hdr is assigned to NULL. Then hdr is used on lines 3622 and 3623: genl_dump_check_consistent(cb, hdr); genlmsg_end(skb, hdr); Thus, possible null-pointer dereferences may occur. To fix these bugs, hdr is used here when it is not NULL. This bug is found by a static analysis tool STCheck written by us. Signed-off-by: Jia-Ju Bai Link: https://lore.kernel.org/r/20190729082332.28895-1-baijiaju1990@gmail.com [put braces on all branches] Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 519b4ee88c5c..772e54f0696f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3617,10 +3617,12 @@ static int hwsim_dump_radio_nl(struct sk_buff *skb, hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, &hwsim_genl_family, NLM_F_MULTI, HWSIM_CMD_GET_RADIO); - if (!hdr) + if (hdr) { + genl_dump_check_consistent(cb, hdr); + genlmsg_end(skb, hdr); + } else { res = -EMSGSIZE; - genl_dump_check_consistent(cb, hdr); - genlmsg_end(skb, hdr); + } } done: -- cgit v1.2.3-59-g8ed1b From f3eb2c334a6d3f5e704ecd0b150d5cfe6e3aca40 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Jul 2019 06:09:53 -0500 Subject: arcnet: com90xx: Mark expected switch fall-throughs Mark switch cases where we are expecting to fall through. This patch fixes the following warnings (Building: powerpc allyesconfig): drivers/net/arcnet/com90xx.c: In function 'com90xx_setup': include/linux/printk.h:304:2: warning: this statement may fall through [-Wimplicit-fallthrough=] printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/net/arcnet/com90xx.c:695:3: note: in expansion of macro 'pr_err' pr_err("Too many arguments\n"); ^~~~~~ drivers/net/arcnet/com90xx.c:696:2: note: here case 3: /* Mem address */ ^~~~ drivers/net/arcnet/com90xx.c:697:9: warning: this statement may fall through [-Wimplicit-fallthrough=] shmem = ints[3]; ~~~~~~^~~~~~~~~ drivers/net/arcnet/com90xx.c:698:2: note: here case 2: /* IRQ */ ^~~~ drivers/net/arcnet/com90xx.c:699:7: warning: this statement may fall through [-Wimplicit-fallthrough=] irq = ints[2]; ~~~~^~~~~~~~~ drivers/net/arcnet/com90xx.c:700:2: note: here case 1: /* IO address */ ^~~~ Reported-by: Stephen Rothwell Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/arcnet/com90xx.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c index ca4a57c30bf8..bd75d06ad7df 100644 --- a/drivers/net/arcnet/com90xx.c +++ b/drivers/net/arcnet/com90xx.c @@ -693,10 +693,13 @@ static int __init com90xx_setup(char *s) switch (ints[0]) { default: /* ERROR */ pr_err("Too many arguments\n"); + /* Fall through */ case 3: /* Mem address */ shmem = ints[3]; + /* Fall through */ case 2: /* IRQ */ irq = ints[2]; + /* Fall through */ case 1: /* IO address */ io = ints[1]; } -- cgit v1.2.3-59-g8ed1b From 56f37a3fa2190732957882e10ec20adf83c6cb93 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Jul 2019 06:13:20 -0500 Subject: arcnet: com90io: Mark expected switch fall-throughs Mark switch cases where we are expecting to fall through. This patch fixes the following warnings (Building: powerpc allyesconfig): drivers/net/arcnet/com90io.c: In function 'com90io_setup': include/linux/printk.h:304:2: warning: this statement may fall through [-Wimplicit-fallthrough=] printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/net/arcnet/com90io.c:365:3: note: in expansion of macro 'pr_err' pr_err("Too many arguments\n"); ^~~~~~ drivers/net/arcnet/com90io.c:366:2: note: here case 2: /* IRQ */ ^~~~ drivers/net/arcnet/com90io.c:367:7: warning: this statement may fall through [-Wimplicit-fallthrough=] irq = ints[2]; ~~~~^~~~~~~~~ drivers/net/arcnet/com90io.c:368:2: note: here case 1: /* IO address */ ^~~~ Reported-by: Stephen Rothwell Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/arcnet/com90io.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c index 2c546013a980..186bbf87bc84 100644 --- a/drivers/net/arcnet/com90io.c +++ b/drivers/net/arcnet/com90io.c @@ -363,8 +363,10 @@ static int __init com90io_setup(char *s) switch (ints[0]) { default: /* ERROR */ pr_err("Too many arguments\n"); + /* Fall through */ case 2: /* IRQ */ irq = ints[2]; + /* Fall through */ case 1: /* IO address */ io = ints[1]; } -- cgit v1.2.3-59-g8ed1b From 26027f4243c1a23399b85a3cff9b0b89e405be59 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Jul 2019 06:15:50 -0500 Subject: arcnet: arc-rimi: Mark expected switch fall-throughs Mark switch cases where we are expecting to fall through. This patch fixes the following warnings (Building: powerpc allyesconfig): drivers/net/arcnet/arc-rimi.c: In function 'arcrimi_setup': include/linux/printk.h:304:2: warning: this statement may fall through [-Wimplicit-fallthrough=] printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/net/arcnet/arc-rimi.c:365:3: note: in expansion of macro 'pr_err' pr_err("Too many arguments\n"); ^~~~~~ drivers/net/arcnet/arc-rimi.c:366:2: note: here case 3: /* Node ID */ ^~~~ drivers/net/arcnet/arc-rimi.c:367:8: warning: this statement may fall through [-Wimplicit-fallthrough=] node = ints[3]; ~~~~~^~~~~~~~~ drivers/net/arcnet/arc-rimi.c:368:2: note: here case 2: /* IRQ */ ^~~~ drivers/net/arcnet/arc-rimi.c:369:7: warning: this statement may fall through [-Wimplicit-fallthrough=] irq = ints[2]; ~~~~^~~~~~~~~ drivers/net/arcnet/arc-rimi.c:370:2: note: here case 1: /* IO address */ ^~~~ Reported-by: Stephen Rothwell Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/arcnet/arc-rimi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c index 11c5bad95226..14a5fb378145 100644 --- a/drivers/net/arcnet/arc-rimi.c +++ b/drivers/net/arcnet/arc-rimi.c @@ -363,10 +363,13 @@ static int __init arcrimi_setup(char *s) switch (ints[0]) { default: /* ERROR */ pr_err("Too many arguments\n"); + /* Fall through */ case 3: /* Node ID */ node = ints[3]; + /* Fall through */ case 2: /* IRQ */ irq = ints[2]; + /* Fall through */ case 1: /* IO address */ io = ints[1]; } -- cgit v1.2.3-59-g8ed1b From e1ab2431ebee2634b9868013d3fefd03c800e510 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Jul 2019 09:25:03 -0500 Subject: arcnet: com20020-isa: Mark expected switch fall-throughs Mark switch cases where we are expecting to fall through. This patch fixes the following warnings: drivers/net/arcnet/com20020-isa.c: warning: this statement may fall through [-Wimplicit-fallthrough=]: => 205:13, 203:10, 209:7, 201:11, 207:8 Reported-by: Geert Uytterhoeven Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/arcnet/com20020-isa.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c index 28510e33924f..cd27fdc1059b 100644 --- a/drivers/net/arcnet/com20020-isa.c +++ b/drivers/net/arcnet/com20020-isa.c @@ -197,16 +197,22 @@ static int __init com20020isa_setup(char *s) switch (ints[0]) { default: /* ERROR */ pr_info("Too many arguments\n"); + /* Fall through */ case 6: /* Timeout */ timeout = ints[6]; + /* Fall through */ case 5: /* CKP value */ clockp = ints[5]; + /* Fall through */ case 4: /* Backplane flag */ backplane = ints[4]; + /* Fall through */ case 3: /* Node ID */ node = ints[3]; + /* Fall through */ case 2: /* IRQ */ irq = ints[2]; + /* Fall through */ case 1: /* IO address */ io = ints[1]; } -- cgit v1.2.3-59-g8ed1b From 195b2919ccd7ffcaf6b6bbcb39444a53ab8308c7 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 27 Jul 2019 21:21:37 +0200 Subject: net: stmmac: manage errors returned by of_get_mac_address() Commit d01f449c008a ("of_net: add NVMEM support to of_get_mac_address") added support for reading the MAC address from an nvmem-cell. This required changing the logic to return an error pointer upon failure. If stmmac is loaded before the nvmem provider driver then of_get_mac_address() return an error pointer with -EPROBE_DEFER. Propagate this error so the stmmac driver will be probed again after the nvmem provider driver is loaded. Default to a random generated MAC address in case of any other error, instead of using the error pointer as MAC address. Fixes: d01f449c008a ("of_net: add NVMEM support to of_get_mac_address") Signed-off-by: Martin Blumenstingl Reviewed-by: Neil Armstrong Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 73fc2524372e..154daf4d1072 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -370,6 +370,13 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) return ERR_PTR(-ENOMEM); *mac = of_get_mac_address(np); + if (IS_ERR(*mac)) { + if (PTR_ERR(*mac) == -EPROBE_DEFER) + return ERR_CAST(*mac); + + *mac = NULL; + } + plat->interface = of_get_phy_mode(np); /* Some wrapper drivers still rely on phy_node. Let's save it while -- cgit v1.2.3-59-g8ed1b From 011f175428d46461f94a65dacb9a416529d08dda Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 28 Jul 2019 00:37:26 +0100 Subject: rocker: fix memory leaks of fib_work on two error return paths Currently there are two error return paths that leak memory allocated to fib_work. Fix this by kfree'ing fib_work before returning. Addresses-Coverity: ("Resource leak") Fixes: 19a9d136f198 ("ipv4: Flag fib_info with a fib_nh using IPv6 gateway") Fixes: dbcc4fa718ee ("rocker: Fail attempts to use routes with nexthop objects") Signed-off-by: Colin Ian King Reviewed-by: David Ahern Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 079f459c73a5..2c5d3f5b84dd 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -2208,10 +2208,12 @@ static int rocker_router_fib_event(struct notifier_block *nb, if (fen_info->fi->fib_nh_is_v6) { NL_SET_ERR_MSG_MOD(info->extack, "IPv6 gateway with IPv4 route is not supported"); + kfree(fib_work); return notifier_from_errno(-EINVAL); } if (fen_info->fi->nh) { NL_SET_ERR_MSG_MOD(info->extack, "IPv4 route with nexthop objects is not supported"); + kfree(fib_work); return notifier_from_errno(-EINVAL); } } -- cgit v1.2.3-59-g8ed1b From 230bd958c2c846ee292aa38bc6b006296c24ca01 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Sun, 28 Jul 2019 02:46:45 +0200 Subject: mvpp2: refactor MTU change code The MTU change code can call napi_disable() with the device already down, leading to a deadlock. Also, lot of code is duplicated unnecessarily. Rework mvpp2_change_mtu() to avoid the deadlock and remove duplicated code. Fixes: 3f518509dedc ("ethernet: Add new driver for Marvell Armada 375 network unit") Signed-off-by: Matteo Croce Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 41 ++++++++----------------- 1 file changed, 13 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index b6591ea0c6d6..68fa2d563f0d 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -3700,6 +3700,7 @@ static int mvpp2_set_mac_address(struct net_device *dev, void *p) static int mvpp2_change_mtu(struct net_device *dev, int mtu) { struct mvpp2_port *port = netdev_priv(dev); + bool running = netif_running(dev); int err; if (!IS_ALIGNED(MVPP2_RX_PKT_SIZE(mtu), 8)) { @@ -3708,40 +3709,24 @@ static int mvpp2_change_mtu(struct net_device *dev, int mtu) mtu = ALIGN(MVPP2_RX_PKT_SIZE(mtu), 8); } - if (!netif_running(dev)) { - err = mvpp2_bm_update_mtu(dev, mtu); - if (!err) { - port->pkt_size = MVPP2_RX_PKT_SIZE(mtu); - return 0; - } - - /* Reconfigure BM to the original MTU */ - err = mvpp2_bm_update_mtu(dev, dev->mtu); - if (err) - goto log_error; - } - - mvpp2_stop_dev(port); + if (running) + mvpp2_stop_dev(port); err = mvpp2_bm_update_mtu(dev, mtu); - if (!err) { + if (err) { + netdev_err(dev, "failed to change MTU\n"); + /* Reconfigure BM to the original MTU */ + mvpp2_bm_update_mtu(dev, dev->mtu); + } else { port->pkt_size = MVPP2_RX_PKT_SIZE(mtu); - goto out_start; } - /* Reconfigure BM to the original MTU */ - err = mvpp2_bm_update_mtu(dev, dev->mtu); - if (err) - goto log_error; - -out_start: - mvpp2_start_dev(port); - mvpp2_egress_enable(port); - mvpp2_ingress_enable(port); + if (running) { + mvpp2_start_dev(port); + mvpp2_egress_enable(port); + mvpp2_ingress_enable(port); + } - return 0; -log_error: - netdev_err(dev, "failed to change MTU\n"); return err; } -- cgit v1.2.3-59-g8ed1b From d66503c43c0036d8db526d6c47c149bb971ac0b9 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Sun, 28 Jul 2019 19:35:49 +0200 Subject: mvpp2: refactor the HW checksum setup The hardware can only offload checksum calculation on first port due to the Tx FIFO size limitation, and has a maximum L3 offset of 128 bytes. Document this in a comment and move duplicated code in a function. Fixes: 576193f2d579 ("net: mvpp2: jumbo frames support") Signed-off-by: Matteo Croce Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 35 ++++++++++++++++--------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 68fa2d563f0d..e2e61a4a9000 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -811,6 +811,26 @@ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port) return 0; } +static void mvpp2_set_hw_csum(struct mvpp2_port *port, + enum mvpp2_bm_pool_log_num new_long_pool) +{ + const netdev_features_t csums = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + + /* Update L4 checksum when jumbo enable/disable on port. + * Only port 0 supports hardware checksum offload due to + * the Tx FIFO size limitation. + * Also, don't set NETIF_F_HW_CSUM because L3_offset in TX descriptor + * has 7 bits, so the maximum L3 offset is 128. + */ + if (new_long_pool == MVPP2_BM_JUMBO && port->id != 0) { + port->dev->features &= ~csums; + port->dev->hw_features &= ~csums; + } else { + port->dev->features |= csums; + port->dev->hw_features |= csums; + } +} + static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu) { struct mvpp2_port *port = netdev_priv(dev); @@ -843,15 +863,7 @@ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu) /* Add port to new short & long pool */ mvpp2_swf_bm_pool_init(port); - /* Update L4 checksum when jumbo enable/disable on port */ - if (new_long_pool == MVPP2_BM_JUMBO && port->id != 0) { - dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - dev->hw_features &= ~(NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM); - } else { - dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - } + mvpp2_set_hw_csum(port, new_long_pool); } dev->mtu = mtu; @@ -5193,10 +5205,7 @@ static int mvpp2_port_probe(struct platform_device *pdev, dev->features |= NETIF_F_NTUPLE; } - if (port->pool_long->id == MVPP2_BM_JUMBO && port->id != 0) { - dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - dev->hw_features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - } + mvpp2_set_hw_csum(port, port->pool_long->id); dev->vlan_features |= features; dev->gso_max_segs = MVPP2_MAX_TSO_SEGS; -- cgit v1.2.3-59-g8ed1b From 6f315c42d4120303d4cd6520f67889ff7f42736e Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sun, 28 Jul 2019 19:30:09 -0500 Subject: net: ehea: Mark expected switch fall-through Mark switch cases where we are expecting to fall through. This patch fixes the following warning: drivers/net/ethernet/ibm/ehea/ehea_main.c: In function 'ehea_mem_notifier': include/linux/printk.h:311:2: warning: this statement may fall through [-Wimplicit-fallthrough=] printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/net/ethernet/ibm/ehea/ehea_main.c:3253:3: note: in expansion of macro 'pr_info' pr_info("memory offlining canceled"); ^~~~~~~ drivers/net/ethernet/ibm/ehea/ehea_main.c:3256:2: note: here case MEM_ONLINE: ^~~~ Notice that, in this particular case, the code comment is modified in accordance with what GCC is expecting to find. Reported-by: Stephen Rothwell Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ehea/ehea_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index 4138a8480347..cca71ba7a74a 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -3251,7 +3251,7 @@ static int ehea_mem_notifier(struct notifier_block *nb, switch (action) { case MEM_CANCEL_OFFLINE: pr_info("memory offlining canceled"); - /* Fall through: re-add canceled memory block */ + /* Fall through - re-add canceled memory block */ case MEM_ONLINE: pr_info("memory is going online"); -- cgit v1.2.3-59-g8ed1b From 52023a53993061b524f6ba1de68858c472f52aad Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sun, 28 Jul 2019 19:32:51 -0500 Subject: net: spider_net: Mark expected switch fall-through Mark switch cases where we are expecting to fall through. This patch fixes the following warning: drivers/net/ethernet/toshiba/spider_net.c: In function 'spider_net_release_tx_chain': drivers/net/ethernet/toshiba/spider_net.c:783:7: warning: this statement may fall through [-Wimplicit-fallthrough=] if (!brutal) { ^ drivers/net/ethernet/toshiba/spider_net.c:792:3: note: here case SPIDER_NET_DESCR_RESPONSE_ERROR: ^~~~ Notice that, in this particular case, the code comment is modified in accordance with what GCC is expecting to find. Reported-by: Stephen Rothwell Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/ethernet/toshiba/spider_net.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/toshiba/spider_net.c b/drivers/net/ethernet/toshiba/spider_net.c index 5b196ebfed49..0f346761a2b2 100644 --- a/drivers/net/ethernet/toshiba/spider_net.c +++ b/drivers/net/ethernet/toshiba/spider_net.c @@ -788,6 +788,7 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) /* fallthrough, if we release the descriptors * brutally (then we don't care about * SPIDER_NET_DESCR_CARDOWNED) */ + /* Fall through */ case SPIDER_NET_DESCR_RESPONSE_ERROR: case SPIDER_NET_DESCR_PROTECTION_ERROR: -- cgit v1.2.3-59-g8ed1b From c6b36bdd04b5c22b2705f7ae561d4f3b4d8a0ac3 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 29 Jul 2019 18:26:14 +0000 Subject: mlxsw: spectrum_ptp: Increase parsing depth when PTP is enabled Spectrum systems have a configurable limit on how far into the packet they parse. By default, the limit is 96 bytes. An IPv6 PTP packet is layered as Ethernet/IPv6/UDP (14+40+8 bytes), and sequence ID of a PTP event is only available 32 bytes into payload, for a total of 94 bytes. When an additional 802.1q header is present as well (such as when ptp4l is running on a VLAN port), the parsing limit is exceeded. Such packets are not recognized as PTP, and are not timestamped. Therefore generalize the current VXLAN-specific parsing depth setting to allow reference-counted requests from other modules as well. Keep it in the VXLAN module, because the MPRS register also configures UDP destination port number used for VXLAN, and is thus closely tied to the VXLAN code anyway. Then invoke the new interfaces from both VXLAN (in obvious places), as well as from PTP code, when the (global) timestamping configuration changes from disabled to enabled or vice versa. Fixes: 8748642751ed ("mlxsw: spectrum: PTP: Support SIOCGHWTSTAMP, SIOCSHWTSTAMP ioctls") Signed-off-by: Petr Machata Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 4 ++ drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c | 1 + drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h | 1 + .../ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c | 76 +++++++++++++++++----- drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c | 17 +++++ 5 files changed, 82 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 131f62ce9297..6664119fb0c8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -951,4 +951,8 @@ void mlxsw_sp_port_nve_fini(struct mlxsw_sp_port *mlxsw_sp_port); int mlxsw_sp_nve_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_nve_fini(struct mlxsw_sp *mlxsw_sp); +/* spectrum_nve_vxlan.c */ +int mlxsw_sp_nve_inc_parsing_depth_get(struct mlxsw_sp *mlxsw_sp); +void mlxsw_sp_nve_inc_parsing_depth_put(struct mlxsw_sp *mlxsw_sp); + #endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c index 1df164a4b06d..17f334b46c40 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c @@ -775,6 +775,7 @@ static void mlxsw_sp_nve_tunnel_fini(struct mlxsw_sp *mlxsw_sp) ops->fini(nve); mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, nve->tunnel_index); + memset(&nve->config, 0, sizeof(nve->config)); } nve->num_nve_tunnels--; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h index 0035640156a1..12f664f42f21 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h @@ -29,6 +29,7 @@ struct mlxsw_sp_nve { unsigned int num_max_mc_entries[MLXSW_SP_L3_PROTO_MAX]; u32 tunnel_index; u16 ul_rif_index; /* Reserved for Spectrum */ + unsigned int inc_parsing_depth_refs; }; struct mlxsw_sp_nve_ops { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c index 93ccd9fc2266..05517c7feaa5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c @@ -103,9 +103,9 @@ static void mlxsw_sp_nve_vxlan_config(const struct mlxsw_sp_nve *nve, config->udp_dport = cfg->dst_port; } -static int mlxsw_sp_nve_parsing_set(struct mlxsw_sp *mlxsw_sp, - unsigned int parsing_depth, - __be16 udp_dport) +static int __mlxsw_sp_nve_parsing_set(struct mlxsw_sp *mlxsw_sp, + unsigned int parsing_depth, + __be16 udp_dport) { char mprs_pl[MLXSW_REG_MPRS_LEN]; @@ -113,6 +113,56 @@ static int mlxsw_sp_nve_parsing_set(struct mlxsw_sp *mlxsw_sp, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl); } +static int mlxsw_sp_nve_parsing_set(struct mlxsw_sp *mlxsw_sp, + __be16 udp_dport) +{ + int parsing_depth = mlxsw_sp->nve->inc_parsing_depth_refs ? + MLXSW_SP_NVE_VXLAN_PARSING_DEPTH : + MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH; + + return __mlxsw_sp_nve_parsing_set(mlxsw_sp, parsing_depth, udp_dport); +} + +static int +__mlxsw_sp_nve_inc_parsing_depth_get(struct mlxsw_sp *mlxsw_sp, + __be16 udp_dport) +{ + int err; + + mlxsw_sp->nve->inc_parsing_depth_refs++; + + err = mlxsw_sp_nve_parsing_set(mlxsw_sp, udp_dport); + if (err) + goto err_nve_parsing_set; + return 0; + +err_nve_parsing_set: + mlxsw_sp->nve->inc_parsing_depth_refs--; + return err; +} + +static void +__mlxsw_sp_nve_inc_parsing_depth_put(struct mlxsw_sp *mlxsw_sp, + __be16 udp_dport) +{ + mlxsw_sp->nve->inc_parsing_depth_refs--; + mlxsw_sp_nve_parsing_set(mlxsw_sp, udp_dport); +} + +int mlxsw_sp_nve_inc_parsing_depth_get(struct mlxsw_sp *mlxsw_sp) +{ + __be16 udp_dport = mlxsw_sp->nve->config.udp_dport; + + return __mlxsw_sp_nve_inc_parsing_depth_get(mlxsw_sp, udp_dport); +} + +void mlxsw_sp_nve_inc_parsing_depth_put(struct mlxsw_sp *mlxsw_sp) +{ + __be16 udp_dport = mlxsw_sp->nve->config.udp_dport; + + __mlxsw_sp_nve_inc_parsing_depth_put(mlxsw_sp, udp_dport); +} + static void mlxsw_sp_nve_vxlan_config_prepare(char *tngcr_pl, const struct mlxsw_sp_nve_config *config) @@ -176,9 +226,7 @@ static int mlxsw_sp1_nve_vxlan_init(struct mlxsw_sp_nve *nve, struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp; int err; - err = mlxsw_sp_nve_parsing_set(mlxsw_sp, - MLXSW_SP_NVE_VXLAN_PARSING_DEPTH, - config->udp_dport); + err = __mlxsw_sp_nve_inc_parsing_depth_get(mlxsw_sp, config->udp_dport); if (err) return err; @@ -203,8 +251,7 @@ err_promote_decap: err_rtdp_set: mlxsw_sp1_nve_vxlan_config_clear(mlxsw_sp); err_config_set: - mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH, - config->udp_dport); + __mlxsw_sp_nve_inc_parsing_depth_put(mlxsw_sp, 0); return err; } @@ -216,8 +263,7 @@ static void mlxsw_sp1_nve_vxlan_fini(struct mlxsw_sp_nve *nve) mlxsw_sp_router_nve_demote_decap(mlxsw_sp, config->ul_tb_id, config->ul_proto, &config->ul_sip); mlxsw_sp1_nve_vxlan_config_clear(mlxsw_sp); - mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH, - config->udp_dport); + __mlxsw_sp_nve_inc_parsing_depth_put(mlxsw_sp, 0); } static int @@ -320,9 +366,7 @@ static int mlxsw_sp2_nve_vxlan_init(struct mlxsw_sp_nve *nve, struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp; int err; - err = mlxsw_sp_nve_parsing_set(mlxsw_sp, - MLXSW_SP_NVE_VXLAN_PARSING_DEPTH, - config->udp_dport); + err = __mlxsw_sp_nve_inc_parsing_depth_get(mlxsw_sp, config->udp_dport); if (err) return err; @@ -348,8 +392,7 @@ err_promote_decap: err_rtdp_set: mlxsw_sp2_nve_vxlan_config_clear(mlxsw_sp); err_config_set: - mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH, - config->udp_dport); + __mlxsw_sp_nve_inc_parsing_depth_put(mlxsw_sp, 0); return err; } @@ -361,8 +404,7 @@ static void mlxsw_sp2_nve_vxlan_fini(struct mlxsw_sp_nve *nve) mlxsw_sp_router_nve_demote_decap(mlxsw_sp, config->ul_tb_id, config->ul_proto, &config->ul_sip); mlxsw_sp2_nve_vxlan_config_clear(mlxsw_sp); - mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH, - config->udp_dport); + __mlxsw_sp_nve_inc_parsing_depth_put(mlxsw_sp, 0); } const struct mlxsw_sp_nve_ops mlxsw_sp2_nve_vxlan_ops = { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c index bd9c2bc2d5d6..98c5ba3200bc 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c @@ -979,6 +979,9 @@ static int mlxsw_sp1_ptp_mtpppc_update(struct mlxsw_sp_port *mlxsw_sp_port, { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp_port *tmp; + u16 orig_ing_types = 0; + u16 orig_egr_types = 0; + int err; int i; /* MTPPPC configures timestamping globally, not per port. Find the @@ -986,12 +989,26 @@ static int mlxsw_sp1_ptp_mtpppc_update(struct mlxsw_sp_port *mlxsw_sp_port, */ for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++) { tmp = mlxsw_sp->ports[i]; + if (tmp) { + orig_ing_types |= tmp->ptp.ing_types; + orig_egr_types |= tmp->ptp.egr_types; + } if (tmp && tmp != mlxsw_sp_port) { ing_types |= tmp->ptp.ing_types; egr_types |= tmp->ptp.egr_types; } } + if ((ing_types || egr_types) && !(orig_egr_types || orig_egr_types)) { + err = mlxsw_sp_nve_inc_parsing_depth_get(mlxsw_sp); + if (err) { + netdev_err(mlxsw_sp_port->dev, "Failed to increase parsing depth"); + return err; + } + } + if (!(ing_types || egr_types) && (orig_egr_types || orig_egr_types)) + mlxsw_sp_nve_inc_parsing_depth_put(mlxsw_sp); + return mlxsw_sp1_ptp_mtpppc_set(mlxsw_sp_port->mlxsw_sp, ing_types, egr_types); } -- cgit v1.2.3-59-g8ed1b From 0bc10ad3a42a1c8ef2cef6e158cc40b87c46352d Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Jul 2019 15:01:39 -0500 Subject: net: wan: sdla: Mark expected switch fall-through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark switch cases where we are expecting to fall through. This patch fixes the following warning (Building: i386): drivers/net/wan/sdla.c: In function ‘sdla_errors’: drivers/net/wan/sdla.c:414:7: warning: this statement may fall through [-Wimplicit-fallthrough=] if (cmd == SDLA_INFORMATION_WRITE) ^ drivers/net/wan/sdla.c:417:3: note: here default: ^~~~~~~ Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/net/wan/sdla.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index a9ac3f37b904..e2e679a01b65 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -413,6 +413,7 @@ static void sdla_errors(struct net_device *dev, int cmd, int dlci, int ret, int case SDLA_RET_NO_BUFS: if (cmd == SDLA_INFORMATION_WRITE) break; + /* Else, fall through */ default: netdev_dbg(dev, "Cmd 0x%02X generated return code 0x%02X\n", -- cgit v1.2.3-59-g8ed1b From 7bd6ba4ef4b29db7464da496963081f5fdc88300 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Jul 2019 15:12:31 -0500 Subject: net: hamradio: baycom_epp: Mark expected switch fall-through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark switch cases where we are expecting to fall through. This patch fixes the following warning (Building: i386): drivers/net/hamradio/baycom_epp.c: In function ‘transmit’: drivers/net/hamradio/baycom_epp.c:491:7: warning: this statement may fall through [-Wimplicit-fallthrough=] if (i) { ^ drivers/net/hamradio/baycom_epp.c:504:3: note: here default: /* fall through */ ^~~~~~~ Notice that, in this particular case, the code comment is modified in accordance with what GCC is expecting to find. Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/net/hamradio/baycom_epp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index daab2c07d891..9303aeb2595f 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -500,8 +500,9 @@ static int transmit(struct baycom_state *bc, int cnt, unsigned char stat) } break; } + /* fall through */ - default: /* fall through */ + default: if (bc->hdlctx.calibrate <= 0) return 0; i = min_t(int, cnt, bc->hdlctx.calibrate); -- cgit v1.2.3-59-g8ed1b From a20961cc9493be46b5c4f565b925284a90c7864c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Jul 2019 17:10:16 -0500 Subject: net: smc911x: Mark expected switch fall-through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark switch cases where we are expecting to fall through. This patch fixes the following warning (Building: arm): drivers/net/ethernet/smsc/smc911x.c: In function ‘smc911x_phy_detect’: drivers/net/ethernet/smsc/smc911x.c:677:7: warning: this statement may fall through [-Wimplicit-fallthrough=] if (cfg & HW_CFG_EXT_PHY_DET_) { ^ drivers/net/ethernet/smsc/smc911x.c:715:3: note: here default: ^~~~~~~ Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/net/ethernet/smsc/smc911x.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c index bd14803545de..8d88e4083456 100644 --- a/drivers/net/ethernet/smsc/smc911x.c +++ b/drivers/net/ethernet/smsc/smc911x.c @@ -712,6 +712,7 @@ static void smc911x_phy_detect(struct net_device *dev) /* Found an external PHY */ break; } + /* Else, fall through */ default: /* Internal media only */ SMC_GET_PHY_ID1(lp, 1, id1); -- cgit v1.2.3-59-g8ed1b From df612421fe2566654047769c6852ffae1a31df16 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 24 Jul 2019 12:46:34 -0700 Subject: mwifiex: fix 802.11n/WPA detection Commit 63d7ef36103d ("mwifiex: Don't abort on small, spec-compliant vendor IEs") adjusted the ieee_types_vendor_header struct, which inadvertently messed up the offsets used in mwifiex_is_wpa_oui_present(). Add that offset back in, mirroring mwifiex_is_rsn_oui_present(). As it stands, commit 63d7ef36103d breaks compatibility with WPA (not WPA2) 802.11n networks, since we hit the "info: Disable 11n if AES is not supported by AP" case in mwifiex_is_network_compatible(). Fixes: 63d7ef36103d ("mwifiex: Don't abort on small, spec-compliant vendor IEs") Cc: Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/main.h | 1 + drivers/net/wireless/marvell/mwifiex/scan.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 3e442c7f7882..095837fba300 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -124,6 +124,7 @@ enum { #define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S) +#define WPA_GTK_OUI_OFFSET 2 #define RSN_GTK_OUI_OFFSET 2 #define MWIFIEX_OUI_NOT_PRESENT 0 diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index 0d6d41727037..21dda385f6c6 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -181,7 +181,8 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) u8 ret = MWIFIEX_OUI_NOT_PRESENT; if (has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)) { - iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data; + iebody = (struct ie_body *)((u8 *)bss_desc->bcn_wpa_ie->data + + WPA_GTK_OUI_OFFSET); oui = &mwifiex_wpa_oui[cipher][0]; ret = mwifiex_search_oui_in_ie(iebody, oui); if (ret) -- cgit v1.2.3-59-g8ed1b From cfb21b11b891b08b79be07be57c40a85bb926668 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 12 Jun 2019 11:09:58 +0200 Subject: iwlwifi: mvm: disable TX-AMSDU on older NICs On older NICs, we occasionally see issues with A-MSDU support, where the commands in the FIFO get confused and then we see an assert EDC because the next command in the FIFO isn't TX. We've tried to isolate this issue and understand where it comes from, but haven't found any errors in building the A-MSDU in software. At least for now, disable A-MSDU support on older hardware so that users can use it again without fearing the assert. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=203315. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 55cd49ccbf0b..99fa440bc639 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -474,7 +474,19 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); ieee80211_hw_set(hw, BUFF_MMPDU_TXQ); ieee80211_hw_set(hw, STA_MMPDU_TXQ); - ieee80211_hw_set(hw, TX_AMSDU); + /* + * On older devices, enabling TX A-MSDU occasionally leads to + * something getting messed up, the command read from the FIFO + * gets out of sync and isn't a TX command, so that we have an + * assert EDC. + * + * It's not clear where the bug is, but since we didn't used to + * support A-MSDU until moving the mac80211 iTXQs, just leave it + * for older devices. We also don't see this issue on any newer + * devices. + */ + if (mvm->cfg->device_family >= IWL_DEVICE_FAMILY_9000) + ieee80211_hw_set(hw, TX_AMSDU); ieee80211_hw_set(hw, TX_FRAG_LIST); if (iwl_mvm_has_tlc_offload(mvm)) { -- cgit v1.2.3-59-g8ed1b From 0f8084cdc1f9d4a6693ef4168167febb0918c6f6 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Thu, 13 Jun 2019 16:34:07 +0300 Subject: iwlwifi: mvm: avoid races in rate init and rate perform Rate perform uses the lq_sta table to calculate the next rate to scale while rate init resets the same table, Rate perform is done in soft irq context in parallel to rate init that can be called in case we are doing changes like AP changes BW or moving state for auth to assoc. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 42 +++++++++++++++++++++++++--- drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 7 ++++- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 6 ++++ drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 1 + 4 files changed, 51 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 8c9069f28a58..02b4ef92543f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1197,6 +1197,27 @@ static u8 rs_get_tid(struct ieee80211_hdr *hdr) return tid; } +void iwl_mvm_rs_init_wk(struct work_struct *wk) +{ + struct iwl_mvm_sta *mvmsta = container_of(wk, struct iwl_mvm_sta, + rs_init_wk); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); + struct ieee80211_sta *sta; + + rcu_read_lock(); + + sta = rcu_dereference(mvmvif->mvm->fw_id_to_mac_id[mvmsta->sta_id]); + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { + rcu_read_unlock(); + return; + } + + iwl_mvm_rs_rate_init(mvmvif->mvm, sta, mvmvif->phy_ctxt->channel->band, + true); + + rcu_read_unlock(); +} + void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, struct ieee80211_tx_info *info, bool ndp) { @@ -1269,7 +1290,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, (unsigned long)(lq_sta->last_tx + (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) { IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); - iwl_mvm_rs_rate_init(mvm, sta, info->band, true); + schedule_work(&mvmsta->rs_init_wk); return; } lq_sta->last_tx = jiffies; @@ -1442,16 +1463,24 @@ static void rs_drv_mac80211_tx_status(void *mvm_r, struct iwl_op_mode *op_mode = mvm_r; struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - if (!iwl_mvm_sta_from_mac80211(sta)->vif) + if (!mvmsta->vif) return; if (!ieee80211_is_data(hdr->frame_control) || info->flags & IEEE80211_TX_CTL_NO_ACK) return; + /* If it's locked we are in middle of init flow + * just wait for next tx status to update the lq_sta data + */ + if (!mutex_trylock(&mvmsta->lq_sta.rs_drv.mutex)) + return; + iwl_mvm_rs_tx_status(mvm, sta, rs_get_tid(hdr), info, ieee80211_is_qos_nullfunc(hdr->frame_control)); + mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex); } /* @@ -4132,10 +4161,15 @@ static const struct rate_control_ops rs_mvm_ops_drv = { void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum nl80211_band band, bool update) { - if (iwl_mvm_has_tlc_offload(mvm)) + if (iwl_mvm_has_tlc_offload(mvm)) { rs_fw_rate_init(mvm, sta, band, update); - else + } else { + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + + mutex_lock(&mvmsta->lq_sta.rs_drv.mutex); rs_drv_rate_init(mvm, sta, band, update); + mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex); + } } int iwl_mvm_rate_control_register(void) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index f7eb60dbaf20..086f47e2a4f0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -4,7 +4,7 @@ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * Contact Information: * Intel Linux Wireless @@ -376,6 +376,9 @@ struct iwl_lq_sta { /* tx power reduce for this sta */ int tpc_reduce; + /* avoid races of reinit and update table from rx_tx */ + struct mutex mutex; + /* persistent fields - initialized only once - keep last! */ struct lq_sta_pers { #ifdef CONFIG_MAC80211_DEBUGFS @@ -440,6 +443,8 @@ struct iwl_mvm_sta; int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool enable); +void iwl_mvm_rs_init_wk(struct work_struct *wk); + #ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm); #endif diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index f545a737a92d..ac9bc65c4d15 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1684,6 +1684,10 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, */ if (iwl_mvm_has_tlc_offload(mvm)) iwl_mvm_rs_add_sta(mvm, mvm_sta); + else + mutex_init(&mvm_sta->lq_sta.rs_drv.mutex); + + INIT_WORK(&mvm_sta->rs_init_wk, iwl_mvm_rs_init_wk); iwl_mvm_toggle_tx_ant(mvm, &mvm_sta->tx_ant); @@ -1846,6 +1850,8 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, if (ret) return ret; + cancel_work_sync(&mvm_sta->rs_init_wk); + /* flush its queues here since we are freeing mvm_sta */ ret = iwl_mvm_flush_sta(mvm, mvm_sta, false, 0); if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 4487cc3e07c1..84139fc38c34 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -424,6 +424,7 @@ struct iwl_mvm_sta { struct iwl_lq_sta_rs_fw rs_fw; struct iwl_lq_sta rs_drv; } lq_sta; + struct work_struct rs_init_wk; struct ieee80211_vif *vif; struct iwl_mvm_key_pn __rcu *ptk_pn[4]; struct iwl_mvm_rxq_dup_data *dup_data; -- cgit v1.2.3-59-g8ed1b From 39bd984c203e86f3109b49c2a2e20677c4d3ab65 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 24 Jun 2019 22:29:33 +0300 Subject: iwlwifi: mvm: don't send GEO_TX_POWER_LIMIT on version < 41 Firmware versions before 41 don't support the GEO_TX_POWER_LIMIT command, and sending it to the firmware will cause a firmware crash. We allow this via debugfs, so we need to return an error value in case it's not supported. This had already been fixed during init, when we send the command if the ACPI WGDS table is present. Fix it also for the other, userspace-triggered case. Cc: stable@vger.kernel.org Fixes: 7fe90e0e3d60 ("iwlwifi: mvm: refactor geo init") Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 1d608e9e9101..a837cf40afde 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -880,6 +880,17 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); } +static bool iwl_mvm_sar_geo_support(struct iwl_mvm *mvm) +{ + /* + * The GEO_TX_POWER_LIMIT command is not supported on earlier + * firmware versions. Unfortunately, we don't have a TLV API + * flag to rely on, so rely on the major version which is in + * the first byte of ucode_ver. + */ + return IWL_UCODE_SERIAL(mvm->fw->ucode_ver) >= 41; +} + int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) { struct iwl_geo_tx_power_profiles_resp *resp; @@ -909,6 +920,9 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) .data = { data }, }; + if (!iwl_mvm_sar_geo_support(mvm)) + return -EOPNOTSUPP; + ret = iwl_mvm_send_cmd(mvm, &cmd); if (ret) { IWL_ERR(mvm, "Failed to get geographic profile info %d\n", ret); @@ -934,13 +948,7 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) int ret, i, j; u16 cmd_wide_id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT); - /* - * This command is not supported on earlier firmware versions. - * Unfortunately, we don't have a TLV API flag to rely on, so - * rely on the major version which is in the first byte of - * ucode_ver. - */ - if (IWL_UCODE_SERIAL(mvm->fw->ucode_ver) < 41) + if (!iwl_mvm_sar_geo_support(mvm)) return 0; ret = iwl_mvm_sar_get_wgds_table(mvm); -- cgit v1.2.3-59-g8ed1b From 6b2dbce549bb513316823af34e92f0bb2e0dbd55 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 24 Jun 2019 13:41:13 +0300 Subject: iwlwifi: mvm: prepare the ground for more RSS notifications We will need a new type of synchronization message going through all the RSS queues. Prepare the ground for this. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index ac9bc65c4d15..23fd3108adb9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2427,7 +2427,7 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) static void iwl_mvm_sync_rxq_del_ba(struct iwl_mvm *mvm, u8 baid) { - struct iwl_mvm_delba_notif notif = { + struct iwl_mvm_rss_sync_notif notif = { .metadata.type = IWL_MVM_RXQ_NOTIF_DEL_BA, .metadata.sync = 1, .delba.baid = baid, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 84139fc38c34..79d655b3fce0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -343,9 +343,11 @@ struct iwl_mvm_delba_data { u32 baid; } __packed; -struct iwl_mvm_delba_notif { +struct iwl_mvm_rss_sync_notif { struct iwl_mvm_internal_rxq_notif metadata; - struct iwl_mvm_delba_data delba; + union { + struct iwl_mvm_delba_data delba; + }; } __packed; /** -- cgit v1.2.3-59-g8ed1b From c61b655a88a54d8690c1e134c47bc3f6d40d2dc3 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 24 Jun 2019 13:57:34 +0300 Subject: iwlwifi: mvm: add a new RSS sync notification for NSSN sync We will soon be using a new notification that will be initiated by the driver, sent to the firmware and sent back to all the RSS queues by the firmware. This new notification will be useful to synchronize the NSSN across all the queues. For now, don't send the notification, just add the code to handle it. Later patch will add the code to actually send it. While at it, validate the baid coming from the firmware to avoid accessing an array with a bad index in the driver. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 2 + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 84 ++++++++++++++++---------- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 6 ++ 5 files changed, 64 insertions(+), 36 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index d55312ef58c9..ed69eec4fcd9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -812,10 +812,12 @@ struct iwl_rxq_sync_notification { * * @IWL_MVM_RXQ_EMPTY: empty sync notification * @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA + * @IWL_MVM_RXQ_NSSN_SYNC: notify all the RSS queues with the new NSSN */ enum iwl_mvm_rxq_notif_type { IWL_MVM_RXQ_EMPTY, IWL_MVM_RXQ_NOTIF_DEL_BA, + IWL_MVM_RXQ_NSSN_SYNC, }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 48c77af54e99..c1e8b4766b0c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1665,8 +1665,8 @@ void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue); int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, const u8 *data, u32 count); -void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - int queue); +void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct napi_struct *napi, + struct iwl_rx_cmd_buffer *rxb, int queue); void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index d7d6f3398f86..4888054dc3d8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1088,7 +1088,7 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode, iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, 0); else if (unlikely(cmd == WIDE_ID(DATA_PATH_GROUP, RX_QUEUES_NOTIFICATION))) - iwl_mvm_rx_queue_notif(mvm, rxb, 0); + iwl_mvm_rx_queue_notif(mvm, napi, rxb, 0); else if (cmd == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE)) iwl_mvm_rx_frame_release(mvm, napi, rxb, 0); else if (cmd == WIDE_ID(DATA_PATH_GROUP, RX_NO_DATA_NOTIF)) @@ -1812,7 +1812,7 @@ static void iwl_mvm_rx_mq_rss(struct iwl_op_mode *op_mode, iwl_mvm_rx_frame_release(mvm, napi, rxb, queue); else if (unlikely(cmd == WIDE_ID(DATA_PATH_GROUP, RX_QUEUES_NOTIFICATION))) - iwl_mvm_rx_queue_notif(mvm, rxb, queue); + iwl_mvm_rx_queue_notif(mvm, napi, rxb, queue); else if (likely(cmd == WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD))) iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, queue); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 64f950501287..bf097329efa2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -665,8 +665,51 @@ out: rcu_read_unlock(); } -void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - int queue) +static void iwl_mvm_release_frames_from_notif(struct iwl_mvm *mvm, + struct napi_struct *napi, + u8 baid, u16 nssn, int queue) +{ + struct ieee80211_sta *sta; + struct iwl_mvm_reorder_buffer *reorder_buf; + struct iwl_mvm_baid_data *ba_data; + + IWL_DEBUG_HT(mvm, "Frame release notification for BAID %u, NSSN %d\n", + baid, nssn); + + if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID || + baid >= ARRAY_SIZE(mvm->baid_map))) + return; + + rcu_read_lock(); + + ba_data = rcu_dereference(mvm->baid_map[baid]); + if (WARN_ON_ONCE(!ba_data)) + goto out; + + sta = rcu_dereference(mvm->fw_id_to_mac_id[ba_data->sta_id]); + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) + goto out; + + reorder_buf = &ba_data->reorder_buf[queue]; + + spin_lock_bh(&reorder_buf->lock); + iwl_mvm_release_frames(mvm, sta, napi, ba_data, reorder_buf, nssn); + spin_unlock_bh(&reorder_buf->lock); + +out: + rcu_read_unlock(); +} + +static void iwl_mvm_nssn_sync(struct iwl_mvm *mvm, + struct napi_struct *napi, int queue, + const struct iwl_mvm_nssn_sync_data *data) +{ + iwl_mvm_release_frames_from_notif(mvm, napi, data->baid, + data->nssn, queue); +} + +void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct napi_struct *napi, + struct iwl_rx_cmd_buffer *rxb, int queue) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rxq_sync_notification *notif; @@ -687,6 +730,10 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, case IWL_MVM_RXQ_NOTIF_DEL_BA: iwl_mvm_del_ba(mvm, queue, (void *)internal_notif->data); break; + case IWL_MVM_RXQ_NSSN_SYNC: + iwl_mvm_nssn_sync(mvm, napi, queue, + (void *)internal_notif->data); + break; default: WARN_ONCE(1, "Invalid identifier %d", internal_notif->type); } @@ -1840,40 +1887,13 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, out: rcu_read_unlock(); } + void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_frame_release *release = (void *)pkt->data; - struct ieee80211_sta *sta; - struct iwl_mvm_reorder_buffer *reorder_buf; - struct iwl_mvm_baid_data *ba_data; - - int baid = release->baid; - IWL_DEBUG_HT(mvm, "Frame release notification for BAID %u, NSSN %d\n", - release->baid, le16_to_cpu(release->nssn)); - - if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID)) - return; - - rcu_read_lock(); - - ba_data = rcu_dereference(mvm->baid_map[baid]); - if (WARN_ON_ONCE(!ba_data)) - goto out; - - sta = rcu_dereference(mvm->fw_id_to_mac_id[ba_data->sta_id]); - if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) - goto out; - - reorder_buf = &ba_data->reorder_buf[queue]; - - spin_lock_bh(&reorder_buf->lock); - iwl_mvm_release_frames(mvm, sta, napi, ba_data, reorder_buf, - le16_to_cpu(release->nssn)); - spin_unlock_bh(&reorder_buf->lock); - -out: - rcu_read_unlock(); + iwl_mvm_release_frames_from_notif(mvm, napi, release->baid, + le16_to_cpu(release->nssn), queue); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 79d655b3fce0..4823c06e6909 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -343,10 +343,16 @@ struct iwl_mvm_delba_data { u32 baid; } __packed; +struct iwl_mvm_nssn_sync_data { + u32 baid; + u32 nssn; +} __packed; + struct iwl_mvm_rss_sync_notif { struct iwl_mvm_internal_rxq_notif metadata; union { struct iwl_mvm_delba_data delba; + struct iwl_mvm_nssn_sync_data nssn_sync; }; } __packed; -- cgit v1.2.3-59-g8ed1b From 521dc6c7c74e88fbd02947e4e50a5cb0d49b4395 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 25 Jun 2019 09:14:14 +0300 Subject: iwlwiif: mvm: refactor iwl_mvm_notify_rx_queue Instead of allocating memory for which we have an upper limit, use a small buffer on stack. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 1 - drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 17 +++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index ed69eec4fcd9..9b0bb89599fc 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -776,7 +776,6 @@ struct iwl_rss_config_cmd { u8 indirection_table[IWL_RSS_INDIRECTION_TABLE_SIZE]; } __packed; /* RSS_CONFIG_CMD_API_S_VER_1 */ -#define IWL_MULTI_QUEUE_SYNC_MSG_MAX_SIZE 128 #define IWL_MULTI_QUEUE_SYNC_SENDER_POS 0 #define IWL_MULTI_QUEUE_SYNC_SENDER_MSK 0xf diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index bf097329efa2..16078aa7c95f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -465,18 +465,20 @@ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, const u8 *data, u32 count) { - struct iwl_rxq_sync_cmd *cmd; + u8 buf[sizeof(struct iwl_rxq_sync_cmd) + + sizeof(struct iwl_mvm_rss_sync_notif)]; + struct iwl_rxq_sync_cmd *cmd = (void *)buf; u32 data_size = sizeof(*cmd) + count; int ret; - /* should be DWORD aligned */ - if (WARN_ON(count & 3 || count > IWL_MULTI_QUEUE_SYNC_MSG_MAX_SIZE)) + /* + * size must be a multiple of DWORD + * Ensure we don't overflow buf + */ + if (WARN_ON(count & 3 || + count > sizeof(struct iwl_mvm_rss_sync_notif))) return -EINVAL; - cmd = kzalloc(data_size, GFP_KERNEL); - if (!cmd) - return -ENOMEM; - cmd->rxq_mask = cpu_to_le32(rxq_mask); cmd->count = cpu_to_le32(count); cmd->flags = 0; @@ -487,7 +489,6 @@ int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, TRIGGER_RX_QUEUES_NOTIF_CMD), 0, data_size, cmd); - kfree(cmd); return ret; } -- cgit v1.2.3-59-g8ed1b From 3c514bf831ac12356b695ff054bef641b9e99593 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 24 Jun 2019 16:26:24 +0300 Subject: iwlwifi: mvm: add a loose synchronization of the NSSN across Rx queues In order to support MSI-X efficiently, we want to avoid communication across Rx queues. Each Rx queue should have all the data it needs to process a packet. The reordering buffer is a challenge in the MSI-X world since we can have a single BA session whose packets are directed to different queues. This is why each queue has its own reordering buffer. The hardware is able to hint the driver whether we have a hole or not, which allows the driver to know whether it can release a packet or not. This indication is called NSSN. Roughly, if the packet's SN is lower than the NSSN, we can release the packet to the stack. The NSSN is the SN of the newest packet received without any holes + 1. This is working as long as we don't have packets that we release because of a timeout. When that happens, we could have taken the decision to release a packet after we have been waiting for its predecessor for too long. If this predecessor comes later, we have to drop it because we can't release packets out of order. In that case, the hardware will give us an indication that we can we release the packet (SN < NSSN), but the packet still needs to be dropped. This is why we sometimes need to ignore the NSSN and we track the head_sn in software. Here is a specific example of this: 1) Rx queue 1 got packets: 480, 482, 483 2) We release 480 to to the stack and wait for 481 3) NSSN is now 481 4) The timeout expires 5) We release 482 and 483, NSSN is still 480 6) 481 arrives its NSSN is 484. We need to drop 481 even if 481 < 484. This is why we'll update the head_sn to 484 at step 2. The flow now is: 1) Rx queue 1 got packets: 480, 482, 483 2) We release 480 to to the stack and wait for 481 3) NSSN is now 481 / head_sn is 481 4) The timeout expires 5) We release 482 and 483, NSSN is still 480 but head_sn is 484. 6) 481 arrives its NSSN is 484, but head_sn is 484 and we drop it. This code introduces another problem in case all the traffic goes well (no hole, no timeout): Rx queue 1: 0 -> 483 (head_sn = 484) Rx queue 2: 501 -> 4095 (head_sn = 0) Rx queue 2: 0 -> 480 (head_sn = 481) Rx queue 1: 481 but head_sn = 484 and we drop it. At this point, the SN of queue 1 is far behind: more than 4040 packets behind. Queue 1 will consider 481 "old" because 481 is in [501-64:501] whereas it is a very new packet. In order to fix that, send an Rx notification from time to time (twice across the full set of 4096 packets) to make sure no Rx queue is lagging too far behind. What will happen then is: Rx queue 1: 0 -> 483 (head_sn = 484) Rx queue 2: 501 -> 2047 (head_sn = 2048) Rx queue 1: Sync nofication (head_sn = 2048) Rx queue 2: 2048 -> 4095 (head_sn = 0) Rx queue 1: Sync notification (head_sn = 0) Rx queue 2: 1 -> 481 (head_sn = 482) Rx queue 1: 481 and head_sn = 0. In queue 1's data, head_sn is now 0, the packet coming in is 481, it'll understand that the new packet is new and it won't be dropped. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 5 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 64 ++++++++++++++++++----- 3 files changed, 56 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 99fa440bc639..982682ec74fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -5053,7 +5053,6 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, u32 qmask = BIT(mvm->trans->num_rx_queues) - 1; int ret; - lockdep_assert_held(&mvm->mutex); if (!iwl_mvm_has_new_rx_api(mvm)) return; @@ -5064,13 +5063,15 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, atomic_set(&mvm->queue_sync_counter, mvm->trans->num_rx_queues); - ret = iwl_mvm_notify_rx_queue(mvm, qmask, (u8 *)notif, size); + ret = iwl_mvm_notify_rx_queue(mvm, qmask, (u8 *)notif, + size, !notif->sync); if (ret) { IWL_ERR(mvm, "Failed to trigger RX queues sync (%d)\n", ret); goto out; } if (notif->sync) { + lockdep_assert_held(&mvm->mutex); ret = wait_event_timeout(mvm->rx_sync_waitq, atomic_read(&mvm->queue_sync_counter) == 0 || iwl_mvm_is_radio_killed(mvm), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index c1e8b4766b0c..fd1764df592f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1664,7 +1664,7 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue); int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, - const u8 *data, u32 count); + const u8 *data, u32 count, bool async); void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue); void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 16078aa7c95f..4f4fdaf49eef 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -463,7 +463,7 @@ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, } int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, - const u8 *data, u32 count) + const u8 *data, u32 count, bool async) { u8 buf[sizeof(struct iwl_rxq_sync_cmd) + sizeof(struct iwl_mvm_rss_sync_notif)]; @@ -487,7 +487,7 @@ int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(DATA_PATH_GROUP, TRIGGER_RX_QUEUES_NOTIF_CMD), - 0, data_size, cmd); + async ? CMD_ASYNC : 0, data_size, cmd); return ret; } @@ -504,6 +504,18 @@ static bool iwl_mvm_is_sn_less(u16 sn1, u16 sn2, u16 buffer_size) !ieee80211_sn_less(sn1, sn2 - buffer_size); } +static void iwl_mvm_sync_nssn(struct iwl_mvm *mvm, u8 baid, u16 nssn) +{ + struct iwl_mvm_rss_sync_notif notif = { + .metadata.type = IWL_MVM_RXQ_NSSN_SYNC, + .metadata.sync = 0, + .nssn_sync.baid = baid, + .nssn_sync.nssn = nssn, + }; + + iwl_mvm_sync_rx_queues_internal(mvm, (void *)¬if, sizeof(notif)); +} + #define RX_REORDER_BUF_TIMEOUT_MQ (HZ / 10) static void iwl_mvm_release_frames(struct iwl_mvm *mvm, @@ -511,7 +523,7 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_mvm_baid_data *baid_data, struct iwl_mvm_reorder_buffer *reorder_buf, - u16 nssn) + u16 nssn, bool sync_rss) { struct iwl_mvm_reorder_buf_entry *entries = &baid_data->entries[reorder_buf->queue * @@ -530,6 +542,8 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm, struct sk_buff *skb; ssn = ieee80211_sn_inc(ssn); + if (sync_rss && (ssn == 2048 || ssn == 0)) + iwl_mvm_sync_nssn(mvm, baid_data->baid, ssn); /* * Empty the list. Will have more than one frame for A-MSDU. @@ -616,7 +630,8 @@ void iwl_mvm_reorder_timer_expired(struct timer_list *t) sta_id, sn); iwl_mvm_event_frame_timeout_callback(buf->mvm, mvmsta->vif, sta, baid_data->tid); - iwl_mvm_release_frames(buf->mvm, sta, NULL, baid_data, buf, sn); + iwl_mvm_release_frames(buf->mvm, sta, NULL, baid_data, + buf, sn, true); rcu_read_unlock(); } else { /* @@ -658,7 +673,8 @@ static void iwl_mvm_del_ba(struct iwl_mvm *mvm, int queue, spin_lock_bh(&reorder_buf->lock); iwl_mvm_release_frames(mvm, sta, NULL, ba_data, reorder_buf, ieee80211_sn_add(reorder_buf->head_sn, - reorder_buf->buf_size)); + reorder_buf->buf_size), + false); spin_unlock_bh(&reorder_buf->lock); del_timer_sync(&reorder_buf->reorder_timer); @@ -694,7 +710,8 @@ static void iwl_mvm_release_frames_from_notif(struct iwl_mvm *mvm, reorder_buf = &ba_data->reorder_buf[queue]; spin_lock_bh(&reorder_buf->lock); - iwl_mvm_release_frames(mvm, sta, napi, ba_data, reorder_buf, nssn); + iwl_mvm_release_frames(mvm, sta, napi, ba_data, + reorder_buf, nssn, false); spin_unlock_bh(&reorder_buf->lock); out: @@ -833,7 +850,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, } if (ieee80211_is_back_req(hdr->frame_control)) { - iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer, nssn); + iwl_mvm_release_frames(mvm, sta, napi, baid_data, + buffer, nssn, false); goto drop; } @@ -842,7 +860,10 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, * If the SN is smaller than the NSSN it might need to first go into * the reorder buffer, in which case we just release up to it and the * rest of the function will take care of storing it and releasing up to - * the nssn + * the nssn. + * This should not happen. This queue has been lagging and it should + * have been updated by a IWL_MVM_RXQ_NSSN_SYNC notification. Be nice + * and update the other queues. */ if (!iwl_mvm_is_sn_less(nssn, buffer->head_sn + buffer->buf_size, buffer->buf_size) || @@ -850,7 +871,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, u16 min_sn = ieee80211_sn_less(sn, nssn) ? sn : nssn; iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer, - min_sn); + min_sn, true); } /* drop any oudated packets */ @@ -861,8 +882,23 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) { if (iwl_mvm_is_sn_less(buffer->head_sn, nssn, buffer->buf_size) && - (!amsdu || last_subframe)) + (!amsdu || last_subframe)) { + /* + * If we crossed the 2048 or 0 SN, notify all the + * queues. This is done in order to avoid having a + * head_sn that lags behind for too long. When that + * happens, we can get to a situation where the head_sn + * is within the interval [nssn - buf_size : nssn] + * which will make us think that the nssn is a packet + * that we already freed because of the reordering + * buffer and we will ignore it. So maintain the + * head_sn somewhat updated across all the queues: + * when it crosses 0 and 2048. + */ + if (sn == 2048 || sn == 0) + iwl_mvm_sync_nssn(mvm, baid, sn); buffer->head_sn = nssn; + } /* No need to update AMSDU last SN - we are moving the head */ spin_unlock_bh(&buffer->lock); return false; @@ -877,8 +913,11 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, * while technically there is no hole and we can move forward. */ if (!buffer->num_stored && sn == buffer->head_sn) { - if (!amsdu || last_subframe) + if (!amsdu || last_subframe) { + if (sn == 2048 || sn == 0) + iwl_mvm_sync_nssn(mvm, baid, sn); buffer->head_sn = ieee80211_sn_inc(buffer->head_sn); + } /* No need to update AMSDU last SN - we are moving the head */ spin_unlock_bh(&buffer->lock); return false; @@ -923,7 +962,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, * release notification with up to date NSSN. */ if (!amsdu || last_subframe) - iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer, nssn); + iwl_mvm_release_frames(mvm, sta, napi, baid_data, + buffer, nssn, true); spin_unlock_bh(&buffer->lock); return true; -- cgit v1.2.3-59-g8ed1b From 23babdf06779482a65c5072a145d826a62979534 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 25 Jun 2019 11:42:49 +0300 Subject: iwlwifi: mvm: add a wrapper around rs_tx_status to handle locks iwl_mvm_rs_tx_status can be called from two places in the code, but the mutex is taken only on one of the calls. Split it into a wrapper taking locks and an internal __iwl_mvm_rs_tx_status function. Signed-off-by: Gregory Greenman Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 02b4ef92543f..b50a47e86ef0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1218,8 +1218,10 @@ void iwl_mvm_rs_init_wk(struct work_struct *wk) rcu_read_unlock(); } -void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int tid, struct ieee80211_tx_info *info, bool ndp) +static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + int tid, struct ieee80211_tx_info *info, + bool ndp) { int legacy_success; int retries; @@ -1451,6 +1453,21 @@ done: rs_rate_scale_perform(mvm, sta, lq_sta, tid, ndp); } +void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, + int tid, struct ieee80211_tx_info *info, bool ndp) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + + /* If it's locked we are in middle of init flow + * just wait for next tx status to update the lq_sta data + */ + if (!mutex_trylock(&mvmsta->lq_sta.rs_drv.mutex)) + return; + + __iwl_mvm_rs_tx_status(mvm, sta, tid, info, ndp); + mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex); +} + /* * mac80211 sends us Tx status */ @@ -1472,15 +1489,8 @@ static void rs_drv_mac80211_tx_status(void *mvm_r, info->flags & IEEE80211_TX_CTL_NO_ACK) return; - /* If it's locked we are in middle of init flow - * just wait for next tx status to update the lq_sta data - */ - if (!mutex_trylock(&mvmsta->lq_sta.rs_drv.mutex)) - return; - iwl_mvm_rs_tx_status(mvm, sta, rs_get_tid(hdr), info, ieee80211_is_qos_nullfunc(hdr->frame_control)); - mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex); } /* -- cgit v1.2.3-59-g8ed1b From 072b30642f90b01d139131ec7bf763778a3a3f41 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Thu, 13 Jun 2019 15:08:24 +0300 Subject: iwlwifi: dbg_ini: move iwl_dbg_tlv_load_bin out of debug override ifdef ini debug mode should work even if debug override is not defined. Signed-off-by: Shahar S Matityahu Fixes: 68f6f492c4fa ("iwlwifi: trans: support loading ini TLVs from external file") Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 57d09049e615..d91686b9a540 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1640,6 +1640,8 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans) init_completion(&drv->request_firmware_complete); INIT_LIST_HEAD(&drv->list); + iwl_load_fw_dbg_tlv(drv->trans->dev, drv->trans); + #ifdef CONFIG_IWLWIFI_DEBUGFS /* Create the device debugfs entries. */ drv->dbgfs_drv = debugfs_create_dir(dev_name(trans->dev), -- cgit v1.2.3-59-g8ed1b From abcbef5977df1fb61026ba429964cd6b9a085699 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Thu, 13 Jun 2019 15:11:24 +0300 Subject: iwlwifi: dbg_ini: move iwl_dbg_tlv_free outside of debugfs ifdef The driver should call iwl_dbg_tlv_free even if debugfs is not defined since ini mode does not depend on debugfs ifdef. Signed-off-by: Shahar S Matityahu Fixes: 68f6f492c4fa ("iwlwifi: trans: support loading ini TLVs from external file") Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index d91686b9a540..38672dd5aae9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1662,8 +1662,8 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans) err_fw: #ifdef CONFIG_IWLWIFI_DEBUGFS debugfs_remove_recursive(drv->dbgfs_drv); - iwl_fw_dbg_free(drv->trans); #endif + iwl_fw_dbg_free(drv->trans); kfree(drv); err: return ERR_PTR(ret); -- cgit v1.2.3-59-g8ed1b From 6569e7d36773956298ec1d5f4e6a2487913d2752 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 27 Jun 2019 09:44:50 +0200 Subject: iwlwifi: fix locking in delayed GTK setting This code clearly never could have worked, since it locks while already locked. Add an unlocked __iwl_mvm_mac_set_key() variant that doesn't do locking to fix that. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 39 +++++++++++++++-------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 982682ec74fd..1c904b5226aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -207,11 +207,11 @@ static const struct cfg80211_pmsr_capabilities iwl_mvm_pmsr_capa = { }, }; -static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, - enum set_key_cmd cmd, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key); +static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, + enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) { @@ -2738,7 +2738,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, mvmvif->ap_early_keys[i] = NULL; - ret = iwl_mvm_mac_set_key(hw, SET_KEY, vif, NULL, key); + ret = __iwl_mvm_mac_set_key(hw, SET_KEY, vif, NULL, key); if (ret) goto out_quota_failed; } @@ -3506,11 +3506,11 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, return ret; } -static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, - enum set_key_cmd cmd, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) +static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, + enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -3565,8 +3565,6 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, return -EOPNOTSUPP; } - mutex_lock(&mvm->mutex); - switch (cmd) { case SET_KEY: if ((vif->type == NL80211_IFTYPE_ADHOC || @@ -3712,7 +3710,22 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ret = -EINVAL; } + return ret; +} + +static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, + enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int ret; + + mutex_lock(&mvm->mutex); + ret = __iwl_mvm_mac_set_key(hw, cmd, vif, sta, key); mutex_unlock(&mvm->mutex); + return ret; } -- cgit v1.2.3-59-g8ed1b From b6cf28796756246f9e317eed6f63f1e2981e9817 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 1 Jul 2019 17:26:57 +0100 Subject: iwlwifi: mvm: fix comparison of u32 variable with less than zero The comparison of the u32 variable wgds_tbl_idx with less than zero is always going to be false because it is unsigned. Fix this by making wgds_tbl_idx a plain signed int. Addresses-Coverity: ("Unsigned compared against 0") Fixes: 4fd445a2c855 ("iwlwifi: mvm: Add log information about SAR status") Signed-off-by: Colin Ian King Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 719f793b3487..a9bb43a2f27b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -620,7 +620,7 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, enum iwl_mcc_source src; char mcc[3]; struct ieee80211_regdomain *regd; - u32 wgds_tbl_idx; + int wgds_tbl_idx; lockdep_assert_held(&mvm->mutex); -- cgit v1.2.3-59-g8ed1b From cd4d6b0bcd51580efda9ae54ab7b2d630b4147dc Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Sun, 30 Jun 2019 09:18:15 +0300 Subject: iwlwifi: mvm: send LQ command always ASYNC The only place where the command was sent as SYNC is during init and this is not really critical. This change is required for replacing RS mutex with a spinlock (in the subsequent patch), since SYNC comamnd requres sleeping and thus the flow cannot be done when holding a spinlock. Signed-off-by: Gregory Greenman Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 23 ++++++++++++----------- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 4 ++-- 4 files changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index fd1764df592f..a263cc629d75 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1813,7 +1813,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) #endif /* CONFIG_IWLWIFI_DEBUGFS */ /* rate scaling */ -int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool sync); +int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq); void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg); int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate); void rs_update_last_rssi(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index b50a47e86ef0..bd977ec8629b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1328,7 +1328,7 @@ static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, IWL_DEBUG_RATE(mvm, "Too many rates mismatch. Send sync LQ. rs_state %d\n", lq_sta->rs_state); - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); + iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq); } /* Regardless, ignore this status info for outdated rate */ return; @@ -1390,7 +1390,8 @@ static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, if (info->status.ampdu_ack_len == 0) info->status.ampdu_len = 1; - rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl, tx_resp_rate.index, + rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl, + tx_resp_rate.index, info->status.ampdu_len, info->status.ampdu_ack_len); @@ -1833,7 +1834,7 @@ static void rs_update_rate_tbl(struct iwl_mvm *mvm, struct iwl_scale_tbl_info *tbl) { rs_fill_lq_cmd(mvm, sta, lq_sta, &tbl->rate); - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); + iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq); } static bool rs_tweak_rate_tbl(struct iwl_mvm *mvm, @@ -2935,7 +2936,7 @@ void rs_update_last_rssi(struct iwl_mvm *mvm, static void rs_initialize_lq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, - enum nl80211_band band, bool update) + enum nl80211_band band) { struct iwl_scale_tbl_info *tbl; struct rs_rate *rate; @@ -2965,7 +2966,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, rs_set_expected_tpt_table(lq_sta, tbl); rs_fill_lq_cmd(mvm, sta, lq_sta, rate); /* TODO restore station should remember the lq cmd */ - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, !update); + iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq); } static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta, @@ -3214,7 +3215,7 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg) * Called after adding a new station to initialize rate scaling */ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - enum nl80211_band band, bool update) + enum nl80211_band band) { int i, j; struct ieee80211_hw *hw = mvm->hw; @@ -3294,7 +3295,7 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, #ifdef CONFIG_IWLWIFI_DEBUGFS iwl_mvm_reset_frame_stats(mvm); #endif - rs_initialize_lq(mvm, sta, lq_sta, band, update); + rs_initialize_lq(mvm, sta, lq_sta, band); } static void rs_drv_rate_update(void *mvm_r, @@ -3608,7 +3609,7 @@ static void rs_set_lq_ss_params(struct iwl_mvm *mvm, bfersta_ss_params &= ~LQ_SS_BFER_ALLOWED; bfersta_lq_cmd->ss_params = cpu_to_le32(bfersta_ss_params); - iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd, false); + iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd); ss_params |= LQ_SS_BFER_ALLOWED; IWL_DEBUG_RATE(mvm, @@ -3774,7 +3775,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm, if (lq_sta->pers.dbg_fixed_rate) { rs_fill_lq_cmd(mvm, NULL, lq_sta, NULL); - iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq, false); + iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq); } } @@ -4177,7 +4178,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); mutex_lock(&mvmsta->lq_sta.rs_drv.mutex); - rs_drv_rate_init(mvm, sta, band, update); + rs_drv_rate_init(mvm, sta, band); mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex); } } @@ -4209,7 +4210,7 @@ static int rs_drv_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, lq->flags &= ~LQ_FLAG_USE_RTS_MSK; } - return iwl_mvm_send_lq_cmd(mvm, lq, false); + return iwl_mvm_send_lq_cmd(mvm, lq); } /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 23fd3108adb9..88d16b5442e7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2978,7 +2978,7 @@ out: IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n", sta->addr, tid); - return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.rs_drv.lq, false); + return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.rs_drv.lq); } static void iwl_mvm_unreserve_agg_queue(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 9ecd5f09615a..b8e20a01c192 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -653,12 +653,12 @@ int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, * this case to clear the state indicating that station creation is in * progress. */ -int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool sync) +int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq) { struct iwl_host_cmd cmd = { .id = LQ_CMD, .len = { sizeof(struct iwl_lq_cmd), }, - .flags = sync ? 0 : CMD_ASYNC, + .flags = CMD_ASYNC, .data = { lq, }, }; -- cgit v1.2.3-59-g8ed1b From f5d88fa334e6c8e2d840512ffbb30e3cb58d065b Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Sun, 30 Jun 2019 09:42:57 +0300 Subject: iwlwifi: mvm: replace RS mutex with a spin_lock The solution with the worker still had a bug, as in order to get sta, rcu_read_lock should be used and thus no mutex can be used inside iwl_mvm_rs_rate_init. Also, spin_lock is a simpler solution, no need to spawn a dedicated worker. Signed-off-by: Gregory Greenman Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 530 +++++++++++++-------------- drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 6 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 6 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 1 - 4 files changed, 258 insertions(+), 285 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index bd977ec8629b..3fa50b1955bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1197,278 +1197,6 @@ static u8 rs_get_tid(struct ieee80211_hdr *hdr) return tid; } -void iwl_mvm_rs_init_wk(struct work_struct *wk) -{ - struct iwl_mvm_sta *mvmsta = container_of(wk, struct iwl_mvm_sta, - rs_init_wk); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); - struct ieee80211_sta *sta; - - rcu_read_lock(); - - sta = rcu_dereference(mvmvif->mvm->fw_id_to_mac_id[mvmsta->sta_id]); - if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { - rcu_read_unlock(); - return; - } - - iwl_mvm_rs_rate_init(mvmvif->mvm, sta, mvmvif->phy_ctxt->channel->band, - true); - - rcu_read_unlock(); -} - -static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, - struct ieee80211_sta *sta, - int tid, struct ieee80211_tx_info *info, - bool ndp) -{ - int legacy_success; - int retries; - int i; - struct iwl_lq_cmd *table; - u32 lq_hwrate; - struct rs_rate lq_rate, tx_resp_rate; - struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; - u32 tlc_info = (uintptr_t)info->status.status_driver_data[0]; - u8 reduced_txp = tlc_info & RS_DRV_DATA_TXP_MSK; - u8 lq_color = RS_DRV_DATA_LQ_COLOR_GET(tlc_info); - u32 tx_resp_hwrate = (uintptr_t)info->status.status_driver_data[1]; - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta.rs_drv; - - /* Treat uninitialized rate scaling data same as non-existing. */ - if (!lq_sta) { - IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n"); - return; - } else if (!lq_sta->pers.drv) { - IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n"); - return; - } - - /* This packet was aggregated but doesn't carry status info */ - if ((info->flags & IEEE80211_TX_CTL_AMPDU) && - !(info->flags & IEEE80211_TX_STAT_AMPDU)) - return; - - if (rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, - &tx_resp_rate)) { - WARN_ON_ONCE(1); - return; - } - -#ifdef CONFIG_MAC80211_DEBUGFS - /* Disable last tx check if we are debugging with fixed rate but - * update tx stats */ - if (lq_sta->pers.dbg_fixed_rate) { - int index = tx_resp_rate.index; - enum rs_column column; - int attempts, success; - - column = rs_get_column_from_rate(&tx_resp_rate); - if (WARN_ONCE(column == RS_COLUMN_INVALID, - "Can't map rate 0x%x to column", - tx_resp_hwrate)) - return; - - if (info->flags & IEEE80211_TX_STAT_AMPDU) { - attempts = info->status.ampdu_len; - success = info->status.ampdu_ack_len; - } else { - attempts = info->status.rates[0].count; - success = !!(info->flags & IEEE80211_TX_STAT_ACK); - } - - lq_sta->pers.tx_stats[column][index].total += attempts; - lq_sta->pers.tx_stats[column][index].success += success; - - IWL_DEBUG_RATE(mvm, "Fixed rate 0x%x success %d attempts %d\n", - tx_resp_hwrate, success, attempts); - return; - } -#endif - - if (time_after(jiffies, - (unsigned long)(lq_sta->last_tx + - (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) { - IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); - schedule_work(&mvmsta->rs_init_wk); - return; - } - lq_sta->last_tx = jiffies; - - /* Ignore this Tx frame response if its initial rate doesn't match - * that of latest Link Quality command. There may be stragglers - * from a previous Link Quality command, but we're no longer interested - * in those; they're either from the "active" mode while we're trying - * to check "search" mode, or a prior "search" mode after we've moved - * to a new "search" mode (which might become the new "active" mode). - */ - table = &lq_sta->lq; - lq_hwrate = le32_to_cpu(table->rs_table[0]); - if (rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate)) { - WARN_ON_ONCE(1); - return; - } - - /* Here we actually compare this rate to the latest LQ command */ - if (lq_color != LQ_FLAG_COLOR_GET(table->flags)) { - IWL_DEBUG_RATE(mvm, - "tx resp color 0x%x does not match 0x%x\n", - lq_color, LQ_FLAG_COLOR_GET(table->flags)); - - /* - * Since rates mis-match, the last LQ command may have failed. - * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with - * ... driver. - */ - lq_sta->missed_rate_counter++; - if (lq_sta->missed_rate_counter > IWL_MVM_RS_MISSED_RATE_MAX) { - lq_sta->missed_rate_counter = 0; - IWL_DEBUG_RATE(mvm, - "Too many rates mismatch. Send sync LQ. rs_state %d\n", - lq_sta->rs_state); - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq); - } - /* Regardless, ignore this status info for outdated rate */ - return; - } else - /* Rate did match, so reset the missed_rate_counter */ - lq_sta->missed_rate_counter = 0; - - if (!lq_sta->search_better_tbl) { - curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); - } else { - curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); - other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - } - - if (WARN_ON_ONCE(!rs_rate_column_match(&lq_rate, &curr_tbl->rate))) { - IWL_DEBUG_RATE(mvm, - "Neither active nor search matches tx rate\n"); - tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE"); - tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); - rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH"); - rs_dump_rate(mvm, &lq_rate, "ACTUAL"); - - /* - * no matching table found, let's by-pass the data collection - * and continue to perform rate scale to find the rate table - */ - rs_stay_in_table(lq_sta, true); - goto done; - } - - /* - * Updating the frame history depends on whether packets were - * aggregated. - * - * For aggregation, all packets were transmitted at the same rate, the - * first index into rate scale table. - */ - if (info->flags & IEEE80211_TX_STAT_AMPDU) { - rs_collect_tpc_data(mvm, lq_sta, curr_tbl, tx_resp_rate.index, - info->status.ampdu_len, - info->status.ampdu_ack_len, - reduced_txp); - - /* ampdu_ack_len = 0 marks no BA was received. For TLC, treat - * it as a single frame loss as we don't want the success ratio - * to dip too quickly because a BA wasn't received. - * For TPC, there's no need for this optimisation since we want - * to recover very quickly from a bad power reduction and, - * therefore we'd like the success ratio to get an immediate hit - * when failing to get a BA, so we'd switch back to a lower or - * zero power reduction. When FW transmits agg with a rate - * different from the initial rate, it will not use reduced txp - * and will send BA notification twice (one empty with reduced - * txp equal to the value from LQ and one with reduced txp 0). - * We need to update counters for each txp level accordingly. - */ - if (info->status.ampdu_ack_len == 0) - info->status.ampdu_len = 1; - - rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl, - tx_resp_rate.index, - info->status.ampdu_len, - info->status.ampdu_ack_len); - - /* Update success/fail counts if not searching for new mode */ - if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { - lq_sta->total_success += info->status.ampdu_ack_len; - lq_sta->total_failed += (info->status.ampdu_len - - info->status.ampdu_ack_len); - } - } else { - /* For legacy, update frame history with for each Tx retry. */ - retries = info->status.rates[0].count - 1; - /* HW doesn't send more than 15 retries */ - retries = min(retries, 15); - - /* The last transmission may have been successful */ - legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK); - /* Collect data for each rate used during failed TX attempts */ - for (i = 0; i <= retries; ++i) { - lq_hwrate = le32_to_cpu(table->rs_table[i]); - if (rs_rate_from_ucode_rate(lq_hwrate, info->band, - &lq_rate)) { - WARN_ON_ONCE(1); - return; - } - - /* - * Only collect stats if retried rate is in the same RS - * table as active/search. - */ - if (rs_rate_column_match(&lq_rate, &curr_tbl->rate)) - tmp_tbl = curr_tbl; - else if (rs_rate_column_match(&lq_rate, - &other_tbl->rate)) - tmp_tbl = other_tbl; - else - continue; - - rs_collect_tpc_data(mvm, lq_sta, tmp_tbl, - tx_resp_rate.index, 1, - i < retries ? 0 : legacy_success, - reduced_txp); - rs_collect_tlc_data(mvm, mvmsta, tid, tmp_tbl, - tx_resp_rate.index, 1, - i < retries ? 0 : legacy_success); - } - - /* Update success/fail counts if not searching for new mode */ - if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { - lq_sta->total_success += legacy_success; - lq_sta->total_failed += retries + (1 - legacy_success); - } - } - /* The last TX rate is cached in lq_sta; it's set in if/else above */ - lq_sta->last_rate_n_flags = lq_hwrate; - IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp); -done: - /* See if there's a better rate or modulation mode to try. */ - if (sta->supp_rates[info->band]) - rs_rate_scale_perform(mvm, sta, lq_sta, tid, ndp); -} - -void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int tid, struct ieee80211_tx_info *info, bool ndp) -{ - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - - /* If it's locked we are in middle of init flow - * just wait for next tx status to update the lq_sta data - */ - if (!mutex_trylock(&mvmsta->lq_sta.rs_drv.mutex)) - return; - - __iwl_mvm_rs_tx_status(mvm, sta, tid, info, ndp); - mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex); -} - /* * mac80211 sends us Tx status */ @@ -3226,6 +2954,8 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct ieee80211_supported_band *sband; unsigned long supp; /* must be unsigned long for for_each_set_bit */ + lockdep_assert_held(&mvmsta->lq_sta.rs_drv.pers.lock); + /* clear all non-persistent lq data */ memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers)); @@ -3318,6 +3048,258 @@ static void rs_drv_rate_update(void *mvm_r, iwl_mvm_rs_rate_init(mvm, sta, sband->band, true); } +static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + int tid, struct ieee80211_tx_info *info, + bool ndp) +{ + int legacy_success; + int retries; + int i; + struct iwl_lq_cmd *table; + u32 lq_hwrate; + struct rs_rate lq_rate, tx_resp_rate; + struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; + u32 tlc_info = (uintptr_t)info->status.status_driver_data[0]; + u8 reduced_txp = tlc_info & RS_DRV_DATA_TXP_MSK; + u8 lq_color = RS_DRV_DATA_LQ_COLOR_GET(tlc_info); + u32 tx_resp_hwrate = (uintptr_t)info->status.status_driver_data[1]; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta.rs_drv; + + /* Treat uninitialized rate scaling data same as non-existing. */ + if (!lq_sta) { + IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n"); + return; + } else if (!lq_sta->pers.drv) { + IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n"); + return; + } + + /* This packet was aggregated but doesn't carry status info */ + if ((info->flags & IEEE80211_TX_CTL_AMPDU) && + !(info->flags & IEEE80211_TX_STAT_AMPDU)) + return; + + if (rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, + &tx_resp_rate)) { + WARN_ON_ONCE(1); + return; + } + +#ifdef CONFIG_MAC80211_DEBUGFS + /* Disable last tx check if we are debugging with fixed rate but + * update tx stats + */ + if (lq_sta->pers.dbg_fixed_rate) { + int index = tx_resp_rate.index; + enum rs_column column; + int attempts, success; + + column = rs_get_column_from_rate(&tx_resp_rate); + if (WARN_ONCE(column == RS_COLUMN_INVALID, + "Can't map rate 0x%x to column", + tx_resp_hwrate)) + return; + + if (info->flags & IEEE80211_TX_STAT_AMPDU) { + attempts = info->status.ampdu_len; + success = info->status.ampdu_ack_len; + } else { + attempts = info->status.rates[0].count; + success = !!(info->flags & IEEE80211_TX_STAT_ACK); + } + + lq_sta->pers.tx_stats[column][index].total += attempts; + lq_sta->pers.tx_stats[column][index].success += success; + + IWL_DEBUG_RATE(mvm, "Fixed rate 0x%x success %d attempts %d\n", + tx_resp_hwrate, success, attempts); + return; + } +#endif + + if (time_after(jiffies, + (unsigned long)(lq_sta->last_tx + + (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) { + IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); + /* reach here only in case of driver RS, call directly + * the unlocked version + */ + rs_drv_rate_init(mvm, sta, info->band); + return; + } + lq_sta->last_tx = jiffies; + + /* Ignore this Tx frame response if its initial rate doesn't match + * that of latest Link Quality command. There may be stragglers + * from a previous Link Quality command, but we're no longer interested + * in those; they're either from the "active" mode while we're trying + * to check "search" mode, or a prior "search" mode after we've moved + * to a new "search" mode (which might become the new "active" mode). + */ + table = &lq_sta->lq; + lq_hwrate = le32_to_cpu(table->rs_table[0]); + if (rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate)) { + WARN_ON_ONCE(1); + return; + } + + /* Here we actually compare this rate to the latest LQ command */ + if (lq_color != LQ_FLAG_COLOR_GET(table->flags)) { + IWL_DEBUG_RATE(mvm, + "tx resp color 0x%x does not match 0x%x\n", + lq_color, LQ_FLAG_COLOR_GET(table->flags)); + + /* Since rates mis-match, the last LQ command may have failed. + * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with + * ... driver. + */ + lq_sta->missed_rate_counter++; + if (lq_sta->missed_rate_counter > IWL_MVM_RS_MISSED_RATE_MAX) { + lq_sta->missed_rate_counter = 0; + IWL_DEBUG_RATE(mvm, + "Too many rates mismatch. Send sync LQ. rs_state %d\n", + lq_sta->rs_state); + iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq); + } + /* Regardless, ignore this status info for outdated rate */ + return; + } + + /* Rate did match, so reset the missed_rate_counter */ + lq_sta->missed_rate_counter = 0; + + if (!lq_sta->search_better_tbl) { + curr_tbl = &lq_sta->lq_info[lq_sta->active_tbl]; + other_tbl = &lq_sta->lq_info[1 - lq_sta->active_tbl]; + } else { + curr_tbl = &lq_sta->lq_info[1 - lq_sta->active_tbl]; + other_tbl = &lq_sta->lq_info[lq_sta->active_tbl]; + } + + if (WARN_ON_ONCE(!rs_rate_column_match(&lq_rate, &curr_tbl->rate))) { + IWL_DEBUG_RATE(mvm, + "Neither active nor search matches tx rate\n"); + tmp_tbl = &lq_sta->lq_info[lq_sta->active_tbl]; + rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE"); + tmp_tbl = &lq_sta->lq_info[1 - lq_sta->active_tbl]; + rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH"); + rs_dump_rate(mvm, &lq_rate, "ACTUAL"); + + /* no matching table found, let's by-pass the data collection + * and continue to perform rate scale to find the rate table + */ + rs_stay_in_table(lq_sta, true); + goto done; + } + + /* Updating the frame history depends on whether packets were + * aggregated. + * + * For aggregation, all packets were transmitted at the same rate, the + * first index into rate scale table. + */ + if (info->flags & IEEE80211_TX_STAT_AMPDU) { + rs_collect_tpc_data(mvm, lq_sta, curr_tbl, tx_resp_rate.index, + info->status.ampdu_len, + info->status.ampdu_ack_len, + reduced_txp); + + /* ampdu_ack_len = 0 marks no BA was received. For TLC, treat + * it as a single frame loss as we don't want the success ratio + * to dip too quickly because a BA wasn't received. + * For TPC, there's no need for this optimisation since we want + * to recover very quickly from a bad power reduction and, + * therefore we'd like the success ratio to get an immediate hit + * when failing to get a BA, so we'd switch back to a lower or + * zero power reduction. When FW transmits agg with a rate + * different from the initial rate, it will not use reduced txp + * and will send BA notification twice (one empty with reduced + * txp equal to the value from LQ and one with reduced txp 0). + * We need to update counters for each txp level accordingly. + */ + if (info->status.ampdu_ack_len == 0) + info->status.ampdu_len = 1; + + rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl, + tx_resp_rate.index, + info->status.ampdu_len, + info->status.ampdu_ack_len); + + /* Update success/fail counts if not searching for new mode */ + if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { + lq_sta->total_success += info->status.ampdu_ack_len; + lq_sta->total_failed += (info->status.ampdu_len - + info->status.ampdu_ack_len); + } + } else { + /* For legacy, update frame history with for each Tx retry. */ + retries = info->status.rates[0].count - 1; + /* HW doesn't send more than 15 retries */ + retries = min(retries, 15); + + /* The last transmission may have been successful */ + legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK); + /* Collect data for each rate used during failed TX attempts */ + for (i = 0; i <= retries; ++i) { + lq_hwrate = le32_to_cpu(table->rs_table[i]); + if (rs_rate_from_ucode_rate(lq_hwrate, info->band, + &lq_rate)) { + WARN_ON_ONCE(1); + return; + } + + /* Only collect stats if retried rate is in the same RS + * table as active/search. + */ + if (rs_rate_column_match(&lq_rate, &curr_tbl->rate)) + tmp_tbl = curr_tbl; + else if (rs_rate_column_match(&lq_rate, + &other_tbl->rate)) + tmp_tbl = other_tbl; + else + continue; + + rs_collect_tpc_data(mvm, lq_sta, tmp_tbl, + tx_resp_rate.index, 1, + i < retries ? 0 : legacy_success, + reduced_txp); + rs_collect_tlc_data(mvm, mvmsta, tid, tmp_tbl, + tx_resp_rate.index, 1, + i < retries ? 0 : legacy_success); + } + + /* Update success/fail counts if not searching for new mode */ + if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { + lq_sta->total_success += legacy_success; + lq_sta->total_failed += retries + (1 - legacy_success); + } + } + /* The last TX rate is cached in lq_sta; it's set in if/else above */ + lq_sta->last_rate_n_flags = lq_hwrate; + IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp); +done: + /* See if there's a better rate or modulation mode to try. */ + if (sta->supp_rates[info->band]) + rs_rate_scale_perform(mvm, sta, lq_sta, tid, ndp); +} + +void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, + int tid, struct ieee80211_tx_info *info, bool ndp) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + + /* If it's locked we are in middle of init flow + * just wait for next tx status to update the lq_sta data + */ + if (!spin_trylock(&mvmsta->lq_sta.rs_drv.pers.lock)) + return; + + __iwl_mvm_rs_tx_status(mvm, sta, tid, info, ndp); + spin_unlock(&mvmsta->lq_sta.rs_drv.pers.lock); +} + #ifdef CONFIG_MAC80211_DEBUGFS static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq_cmd, @@ -4177,9 +4159,9 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, } else { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - mutex_lock(&mvmsta->lq_sta.rs_drv.mutex); + spin_lock(&mvmsta->lq_sta.rs_drv.pers.lock); rs_drv_rate_init(mvm, sta, band); - mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex); + spin_unlock(&mvmsta->lq_sta.rs_drv.pers.lock); } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index 086f47e2a4f0..428642e66658 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -376,9 +376,6 @@ struct iwl_lq_sta { /* tx power reduce for this sta */ int tpc_reduce; - /* avoid races of reinit and update table from rx_tx */ - struct mutex mutex; - /* persistent fields - initialized only once - keep last! */ struct lq_sta_pers { #ifdef CONFIG_MAC80211_DEBUGFS @@ -393,6 +390,7 @@ struct iwl_lq_sta { s8 last_rssi; struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; struct iwl_mvm *drv; + spinlock_t lock; /* for races in reinit/update table */ } pers; }; @@ -443,8 +441,6 @@ struct iwl_mvm_sta; int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool enable); -void iwl_mvm_rs_init_wk(struct work_struct *wk); - #ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm); #endif diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 88d16b5442e7..10f18536dd0d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1685,9 +1685,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, if (iwl_mvm_has_tlc_offload(mvm)) iwl_mvm_rs_add_sta(mvm, mvm_sta); else - mutex_init(&mvm_sta->lq_sta.rs_drv.mutex); - - INIT_WORK(&mvm_sta->rs_init_wk, iwl_mvm_rs_init_wk); + spin_lock_init(&mvm_sta->lq_sta.rs_drv.pers.lock); iwl_mvm_toggle_tx_ant(mvm, &mvm_sta->tx_ant); @@ -1850,8 +1848,6 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, if (ret) return ret; - cancel_work_sync(&mvm_sta->rs_init_wk); - /* flush its queues here since we are freeing mvm_sta */ ret = iwl_mvm_flush_sta(mvm, mvm_sta, false, 0); if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 4823c06e6909..8d70093847cb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -432,7 +432,6 @@ struct iwl_mvm_sta { struct iwl_lq_sta_rs_fw rs_fw; struct iwl_lq_sta rs_drv; } lq_sta; - struct work_struct rs_init_wk; struct ieee80211_vif *vif; struct iwl_mvm_key_pn __rcu *ptk_pn[4]; struct iwl_mvm_rxq_dup_data *dup_data; -- cgit v1.2.3-59-g8ed1b From ecd09ddc1d14cca4f874151aed51a7feee3f765b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 27 Jun 2019 21:50:24 +0300 Subject: iwlwifi: mvm: fix frame drop from the reordering buffer An earlier patch made sure that the queues are not lagging too far behind. This means that iwl_mvm_release_frames should not be called with a head_sn too far behind NSSN. Don't take the risk to change completely the entry condition to iwl_mvm_release_frames, but don't update the head_sn is the NSSN is more than 2048 packets ahead of us. Since this just cannot be right. This means that the scenario described here happened. We are queue 0. Q:0 Q:1 head_sn: 0 -> 2047 head_sn: 2048 Lots of packets arrive: head_sn: 2047 -> 2150 send NSSN_SYNC notification Handle notification from the firmware and do NOT move the head_sn back to 2048 Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 44 ++++++++++++++++++++------- 1 file changed, 33 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 4f4fdaf49eef..854edd7d7103 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -518,12 +518,17 @@ static void iwl_mvm_sync_nssn(struct iwl_mvm *mvm, u8 baid, u16 nssn) #define RX_REORDER_BUF_TIMEOUT_MQ (HZ / 10) +enum iwl_mvm_release_flags { + IWL_MVM_RELEASE_SEND_RSS_SYNC = BIT(0), + IWL_MVM_RELEASE_FROM_RSS_SYNC = BIT(1), +}; + static void iwl_mvm_release_frames(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct napi_struct *napi, struct iwl_mvm_baid_data *baid_data, struct iwl_mvm_reorder_buffer *reorder_buf, - u16 nssn, bool sync_rss) + u16 nssn, u32 flags) { struct iwl_mvm_reorder_buf_entry *entries = &baid_data->entries[reorder_buf->queue * @@ -532,6 +537,18 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm, lockdep_assert_held(&reorder_buf->lock); + /* + * We keep the NSSN not too far behind, if we are sync'ing it and it + * is more than 2048 ahead of us, it must be behind us. Discard it. + * This can happen if the queue that hit the 0 / 2048 seqno was lagging + * behind and this queue already processed packets. The next if + * would have caught cases where this queue would have processed less + * than 64 packets, but it may have processed more than 64 packets. + */ + if ((flags & IWL_MVM_RELEASE_FROM_RSS_SYNC) && + ieee80211_sn_less(nssn, ssn)) + goto set_timer; + /* ignore nssn smaller than head sn - this can happen due to timeout */ if (iwl_mvm_is_sn_less(nssn, ssn, reorder_buf->buf_size)) goto set_timer; @@ -542,7 +559,8 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm, struct sk_buff *skb; ssn = ieee80211_sn_inc(ssn); - if (sync_rss && (ssn == 2048 || ssn == 0)) + if ((flags & IWL_MVM_RELEASE_SEND_RSS_SYNC) && + (ssn == 2048 || ssn == 0)) iwl_mvm_sync_nssn(mvm, baid_data->baid, ssn); /* @@ -631,7 +649,7 @@ void iwl_mvm_reorder_timer_expired(struct timer_list *t) iwl_mvm_event_frame_timeout_callback(buf->mvm, mvmsta->vif, sta, baid_data->tid); iwl_mvm_release_frames(buf->mvm, sta, NULL, baid_data, - buf, sn, true); + buf, sn, IWL_MVM_RELEASE_SEND_RSS_SYNC); rcu_read_unlock(); } else { /* @@ -674,7 +692,7 @@ static void iwl_mvm_del_ba(struct iwl_mvm *mvm, int queue, iwl_mvm_release_frames(mvm, sta, NULL, ba_data, reorder_buf, ieee80211_sn_add(reorder_buf->head_sn, reorder_buf->buf_size), - false); + 0); spin_unlock_bh(&reorder_buf->lock); del_timer_sync(&reorder_buf->reorder_timer); @@ -684,7 +702,8 @@ out: static void iwl_mvm_release_frames_from_notif(struct iwl_mvm *mvm, struct napi_struct *napi, - u8 baid, u16 nssn, int queue) + u8 baid, u16 nssn, int queue, + u32 flags) { struct ieee80211_sta *sta; struct iwl_mvm_reorder_buffer *reorder_buf; @@ -711,7 +730,7 @@ static void iwl_mvm_release_frames_from_notif(struct iwl_mvm *mvm, spin_lock_bh(&reorder_buf->lock); iwl_mvm_release_frames(mvm, sta, napi, ba_data, - reorder_buf, nssn, false); + reorder_buf, nssn, flags); spin_unlock_bh(&reorder_buf->lock); out: @@ -723,7 +742,8 @@ static void iwl_mvm_nssn_sync(struct iwl_mvm *mvm, const struct iwl_mvm_nssn_sync_data *data) { iwl_mvm_release_frames_from_notif(mvm, napi, data->baid, - data->nssn, queue); + data->nssn, queue, + IWL_MVM_RELEASE_FROM_RSS_SYNC); } void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct napi_struct *napi, @@ -851,7 +871,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, if (ieee80211_is_back_req(hdr->frame_control)) { iwl_mvm_release_frames(mvm, sta, napi, baid_data, - buffer, nssn, false); + buffer, nssn, 0); goto drop; } @@ -871,7 +891,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, u16 min_sn = ieee80211_sn_less(sn, nssn) ? sn : nssn; iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer, - min_sn, true); + min_sn, IWL_MVM_RELEASE_SEND_RSS_SYNC); } /* drop any oudated packets */ @@ -963,7 +983,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, */ if (!amsdu || last_subframe) iwl_mvm_release_frames(mvm, sta, napi, baid_data, - buffer, nssn, true); + buffer, nssn, + IWL_MVM_RELEASE_SEND_RSS_SYNC); spin_unlock_bh(&buffer->lock); return true; @@ -1936,5 +1957,6 @@ void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_frame_release *release = (void *)pkt->data; iwl_mvm_release_frames_from_notif(mvm, napi, release->baid, - le16_to_cpu(release->nssn), queue); + le16_to_cpu(release->nssn), + queue, 0); } -- cgit v1.2.3-59-g8ed1b From 514ea05b0743435bf181c41f48d83aac050cc6fa Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Mon, 8 Jul 2019 09:07:42 +0300 Subject: iwlwifi: mvm: fix possible out-of-bounds read when accessing lq_info lq_info is an arary of size 2, active_tbl index is u8. When accessing lq_info[1 - active_tbl], theoretically it's possible that the access will be made to a negative index value. Signed-off-by: Gregory Greenman Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 3fa50b1955bb..d3f04acfbacb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1352,6 +1352,18 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, tbl->expected_tpt = rs_get_expected_tpt_table(lq_sta, column, rate->bw); } +/* rs uses two tables, one is active and the second is for searching better + * configuration. This function, according to the index of the currently + * active table returns the search table, which is located at the + * index complementary to 1 according to the active table (active = 1, + * search = 0 or active = 0, search = 1). + * Since lq_info is an arary of size 2, make sure index cannot be out of bounds. + */ +static inline u8 rs_search_tbl(u8 active_tbl) +{ + return (active_tbl ^ 1) & 1; +} + static s32 rs_get_best_rate(struct iwl_mvm *mvm, struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl, /* "search" */ @@ -1699,9 +1711,9 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum rs_column col_id) { - struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); + struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl]; struct iwl_scale_tbl_info *search_tbl = - &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); + &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; struct rs_rate *rate = &search_tbl->rate; const struct rs_tx_column *column = &rs_tx_columns[col_id]; const struct rs_tx_column *curr_column = &rs_tx_columns[tbl->column]; @@ -2109,7 +2121,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, if (!lq_sta->search_better_tbl) active_tbl = lq_sta->active_tbl; else - active_tbl = 1 - lq_sta->active_tbl; + active_tbl = rs_search_tbl(lq_sta->active_tbl); tbl = &(lq_sta->lq_info[active_tbl]); rate = &tbl->rate; @@ -2333,7 +2345,7 @@ lq_update: /* If new "search" mode was selected, set up in uCode table */ if (lq_sta->search_better_tbl) { /* Access the "search" table, clear its history. */ - tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); + tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; rs_rate_scale_clear_tbl_windows(mvm, tbl); /* Use new "search" start rate */ @@ -2676,7 +2688,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, if (!lq_sta->search_better_tbl) active_tbl = lq_sta->active_tbl; else - active_tbl = 1 - lq_sta->active_tbl; + active_tbl = rs_search_tbl(lq_sta->active_tbl); tbl = &(lq_sta->lq_info[active_tbl]); rate = &tbl->rate; @@ -3172,9 +3184,9 @@ static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, if (!lq_sta->search_better_tbl) { curr_tbl = &lq_sta->lq_info[lq_sta->active_tbl]; - other_tbl = &lq_sta->lq_info[1 - lq_sta->active_tbl]; + other_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; } else { - curr_tbl = &lq_sta->lq_info[1 - lq_sta->active_tbl]; + curr_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; other_tbl = &lq_sta->lq_info[lq_sta->active_tbl]; } @@ -3183,7 +3195,7 @@ static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, "Neither active nor search matches tx rate\n"); tmp_tbl = &lq_sta->lq_info[lq_sta->active_tbl]; rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE"); - tmp_tbl = &lq_sta->lq_info[1 - lq_sta->active_tbl]; + tmp_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH"); rs_dump_rate(mvm, &lq_rate, "ACTUAL"); -- cgit v1.2.3-59-g8ed1b From 03a0995ccc0717ca0c0c7454a033c260872d45ae Mon Sep 17 00:00:00 2001 From: Ihab Zhaika Date: Mon, 15 Jul 2019 15:30:48 +0300 Subject: iwlwifi: add 3 new IDs for the 9000 series (iwl9260_2ac_160_cfg) Add a few PCI ID'S for 9000 series. Signed-off-by: Ihab Zhaika Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index ea2a03d4bf55..de711c1160d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -604,10 +604,13 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2526, 0x40A4, iwl9460_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x6010, iwl9260_2ac_160_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x6014, iwl9260_2ac_160_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x8014, iwl9260_2ac_160_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x8010, iwl9260_2ac_160_cfg)}, {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0xE010, iwl9260_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0xE014, iwl9260_2ac_160_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0010, iwl9160_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0014, iwl9160_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0210, iwl9160_2ac_cfg)}, -- cgit v1.2.3-59-g8ed1b From f5a47fae6aa3eb06f100e701d2342ee56b857bee Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 19 Jul 2019 12:21:59 +0300 Subject: iwlwifi: mvm: fix version check for GEO_TX_POWER_LIMIT support We erroneously added a check for FW API version 41 before sending GEO_TX_POWER_LIMIT, but this was already implemented in version 38. Additionally, it was cherry-picked to older versions, namely 17, 26 and 29, so check for those as well. Cc: stable@vger.kernel.org Fixes: eca1e56ceedd ("iwlwifi: mvm: don't send GEO_TX_POWER_LIMIT to old firmwares") Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index a837cf40afde..00c89bcfdf6a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -886,9 +886,14 @@ static bool iwl_mvm_sar_geo_support(struct iwl_mvm *mvm) * The GEO_TX_POWER_LIMIT command is not supported on earlier * firmware versions. Unfortunately, we don't have a TLV API * flag to rely on, so rely on the major version which is in - * the first byte of ucode_ver. + * the first byte of ucode_ver. This was implemented + * initially on version 38 and then backported to 36, 29 and + * 17. */ - return IWL_UCODE_SERIAL(mvm->fw->ucode_ver) >= 41; + return IWL_UCODE_SERIAL(mvm->fw->ucode_ver) >= 38 || + IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 36 || + IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 29 || + IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 17; } int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) -- cgit v1.2.3-59-g8ed1b From 87e7e25aee6b59fef740856f4e86d4b60496c9e1 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 21 Jul 2019 14:02:27 +0300 Subject: iwlwifi: don't unmap as page memory that was mapped as single In order to remember how to unmap a memory (as single or as page), we maintain a bit per Transmit Buffer (TBs) in the meta data (structure iwl_cmd_meta). We maintain a bitmap: 1 bit per TB. If the TB is set, we will free the memory as a page. This bitmap was never cleared. Fix this. Cc: stable@vger.kernel.org Fixes: 3cd1980b0cdf ("iwlwifi: pcie: introduce new tfd and tb formats") Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index fa4245d0d4a8..2f0ba7ef53b8 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -435,6 +435,8 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, DMA_TO_DEVICE); } + meta->tbs = 0; + if (trans->cfg->use_tfh) { struct iwl_tfh_tfd *tfd_fh = (void *)tfd; -- cgit v1.2.3-59-g8ed1b From ba3224db78034435e9ff0247277cce7c7bb1756c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 22 Jul 2019 12:47:27 +0300 Subject: iwlwifi: mvm: fix an out-of-bound access The index for the elements of the ACPI object we dereference was static. This means that if we called the function twice we wouldn't start from 3 again, but rather from the latest index we reached in the previous call. This was dutifully reported by KASAN. Fix this. Cc: stable@vger.kernel.org Fixes: 6996490501ed ("iwlwifi: mvm: add support for EWRD (Dynamic SAR) ACPI table") Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 00c89bcfdf6a..5de54d1559dd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -755,7 +755,7 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) for (i = 0; i < n_profiles; i++) { /* the tables start at element 3 */ - static int pos = 3; + int pos = 3; /* The EWRD profiles officially go from 2 to 4, but we * save them in sar_profiles[1-3] (because we don't -- cgit v1.2.3-59-g8ed1b From 71b256f8f7a5c09810d2c3ed6165629c2cc0a652 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 22 Jul 2019 13:02:25 +0300 Subject: iwlwifi: mvm: fix a use-after-free bug in iwl_mvm_tx_tso_segment Accessing the hdr of an skb that was consumed already isn't a good idea. First ask if the skb is a QoS packet, then keep that data on stack, and then consume the skb. This was spotted by KASAN. Cc: stable@vger.kernel.org Fixes: 08f7d8b69aaf ("iwlwifi: mvm: bring back mvm GSO code") Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index a3e5d88f1c07..6ac114a393cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -831,6 +831,7 @@ iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes, unsigned int tcp_payload_len; unsigned int mss = skb_shinfo(skb)->gso_size; bool ipv4 = (skb->protocol == htons(ETH_P_IP)); + bool qos = ieee80211_is_data_qos(hdr->frame_control); u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0; skb_shinfo(skb)->gso_size = num_subframes * mss; @@ -864,7 +865,7 @@ iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes, if (tcp_payload_len > mss) { skb_shinfo(tmp)->gso_size = mss; } else { - if (ieee80211_is_data_qos(hdr->frame_control)) { + if (qos) { u8 *qc; if (ipv4) -- cgit v1.2.3-59-g8ed1b From ab98c008ac761752cdc27f9eb053419feadeb2f7 Mon Sep 17 00:00:00 2001 From: Hubert Feurstein Date: Tue, 30 Jul 2019 11:46:23 +0200 Subject: net: phy: fixed_phy: print gpio error only if gpio node is present It is perfectly ok to not have an gpio attached to the fixed-link node. So the driver should not throw an error message when the gpio is missing. Fixes: 5468e82f7034 ("net: phy: fixed-phy: Drop GPIO from fixed_phy_add()") Signed-off-by: Hubert Feurstein Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/fixed_phy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index 3ffe46df249e..7c5265fd2b94 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -216,8 +216,10 @@ static struct gpio_desc *fixed_phy_get_gpiod(struct device_node *np) if (IS_ERR(gpiod)) { if (PTR_ERR(gpiod) == -EPROBE_DEFER) return gpiod; - pr_err("error getting GPIO for fixed link %pOF, proceed without\n", - fixed_link_node); + + if (PTR_ERR(gpiod) != -ENOENT) + pr_err("error getting GPIO for fixed link %pOF, proceed without\n", + fixed_link_node); gpiod = NULL; } -- cgit v1.2.3-59-g8ed1b From 43c8e0ae76bdcb5c00b381c294c176b373316c8d Mon Sep 17 00:00:00 2001 From: Hubert Feurstein Date: Tue, 30 Jul 2019 12:11:42 +0200 Subject: net: dsa: mv88e6xxx: use link-down-define instead of plain value Using the define here makes the code more expressive. Signed-off-by: Hubert Feurstein Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index c97dea4599a8..a0f288efcc12 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -430,7 +430,7 @@ int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link, return 0; /* Port's MAC control must not be changed unless the link is down */ - err = chip->info->ops->port_set_link(chip, port, 0); + err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN); if (err) return err; -- cgit v1.2.3-59-g8ed1b From 2ad07086a557efdd80dd036f7b843bd3c51b81c2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 30 Jul 2019 12:47:52 +0100 Subject: mlxsw: spectrum_ptp: fix duplicated check on orig_egr_types Currently are duplicated checks on orig_egr_types which are redundant, I believe this is a typo and should actually be orig_ing_types || orig_egr_types instead of the expression orig_egr_types || orig_egr_types. Fix these. Addresses-Coverity: ("Same on both sides") Fixes: c6b36bdd04b5 ("mlxsw: spectrum_ptp: Increase parsing depth when PTP is enabled") Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c index 98c5ba3200bc..63b07edd9d81 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c @@ -999,14 +999,14 @@ static int mlxsw_sp1_ptp_mtpppc_update(struct mlxsw_sp_port *mlxsw_sp_port, } } - if ((ing_types || egr_types) && !(orig_egr_types || orig_egr_types)) { + if ((ing_types || egr_types) && !(orig_ing_types || orig_egr_types)) { err = mlxsw_sp_nve_inc_parsing_depth_get(mlxsw_sp); if (err) { netdev_err(mlxsw_sp_port->dev, "Failed to increase parsing depth"); return err; } } - if (!(ing_types || egr_types) && (orig_egr_types || orig_egr_types)) + if (!(ing_types || egr_types) && (orig_ing_types || orig_egr_types)) mlxsw_sp_nve_inc_parsing_depth_put(mlxsw_sp); return mlxsw_sp1_ptp_mtpppc_set(mlxsw_sp_port->mlxsw_sp, -- cgit v1.2.3-59-g8ed1b From 3caa61c208753492fe59efb20e06f7c608eb8db2 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Tue, 30 Jul 2019 15:57:16 +0200 Subject: net: stmmac: Sync RX Buffer upon allocation With recent changes that introduced support for Page Pool in stmmac, Jon reported that NFS boot was no longer working on an ARM64 based platform that had the IP behind an IOMMU. As Page Pool API does not guarantee DMA syncing because of the use of DMA_ATTR_SKIP_CPU_SYNC flag, we have to explicit sync the whole buffer upon re-allocation because we are always re-using same pages. In fact, ARM64 code invalidates the DMA area upon two situations [1]: - sync_single_for_cpu(): Invalidates if direction != DMA_TO_DEVICE - sync_single_for_device(): Invalidates if direction == DMA_FROM_DEVICE So, as we must invalidate both the current RX buffer and the newly allocated buffer we propose this fix. [1] arch/arm64/mm/cache.S Reported-by: Jon Hunter Tested-by: Jon Hunter Fixes: 2af6106ae949 ("net: stmmac: Introducing support for Page Pool") Signed-off-by: Jose Abreu Tested-by: Ezequiel Garcia Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 98b1a5c6d537..9a4a56ad35cd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -3271,9 +3271,11 @@ static inline int stmmac_rx_threshold_count(struct stmmac_rx_queue *rx_q) static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) { struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; - int dirty = stmmac_rx_dirty(priv, queue); + int len, dirty = stmmac_rx_dirty(priv, queue); unsigned int entry = rx_q->dirty_rx; + len = DIV_ROUND_UP(priv->dma_buf_sz, PAGE_SIZE) * PAGE_SIZE; + while (dirty-- > 0) { struct stmmac_rx_buffer *buf = &rx_q->buf_pool[entry]; struct dma_desc *p; @@ -3291,6 +3293,13 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) } buf->addr = page_pool_get_dma_addr(buf->page); + + /* Sync whole allocation to device. This will invalidate old + * data. + */ + dma_sync_single_for_device(priv->device, buf->addr, len, + DMA_FROM_DEVICE); + stmmac_set_desc_addr(priv, p, buf->addr); stmmac_refill_desc3(priv, rx_q, p); @@ -3425,8 +3434,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) skb_copy_to_linear_data(skb, page_address(buf->page), frame_len); skb_put(skb, frame_len); - dma_sync_single_for_device(priv->device, buf->addr, - frame_len, DMA_FROM_DEVICE); if (netif_msg_pktdata(priv)) { netdev_dbg(priv->dev, "frame received (%dbytes)", -- cgit v1.2.3-59-g8ed1b From 5f4e4203add2b860d2345312509a160f8292063b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 30 Jul 2019 22:29:59 +0800 Subject: enetc: Fix build error without PHYLIB If PHYLIB is not set, build enetc will fails: drivers/net/ethernet/freescale/enetc/enetc.o: In function `enetc_open': enetc.c: undefined reference to `phy_disconnect' enetc.c: undefined reference to `phy_start' drivers/net/ethernet/freescale/enetc/enetc.o: In function `enetc_close': enetc.c: undefined reference to `phy_stop' enetc.c: undefined reference to `phy_disconnect' drivers/net/ethernet/freescale/enetc/enetc_ethtool.o: undefined reference to `phy_ethtool_get_link_ksettings' drivers/net/ethernet/freescale/enetc/enetc_ethtool.o: undefined reference to `phy_ethtool_set_link_ksettings' drivers/net/ethernet/freescale/enetc/enetc_mdio.o: In function `enetc_mdio_probe': enetc_mdio.c: undefined reference to `mdiobus_alloc_size' enetc_mdio.c: undefined reference to `mdiobus_free' Reported-by: Hulk Robot Fixes: d4fd0404c1c9 ("enetc: Introduce basic PF and VF ENETC ethernet drivers") Signed-off-by: YueHaibing Acked-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig index ed0d010c7cf2..46fdf36bfece 100644 --- a/drivers/net/ethernet/freescale/enetc/Kconfig +++ b/drivers/net/ethernet/freescale/enetc/Kconfig @@ -2,6 +2,7 @@ config FSL_ENETC tristate "ENETC PF driver" depends on PCI && PCI_MSI && (ARCH_LAYERSCAPE || COMPILE_TEST) + select PHYLIB help This driver supports NXP ENETC gigabit ethernet controller PCIe physical function (PF) devices, managing ENETC Ports at a privileged -- cgit v1.2.3-59-g8ed1b From 055d88242a6046a1ceac3167290f054c72571cd9 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 30 Jul 2019 21:25:20 +0200 Subject: compat_ioctl: pppoe: fix PPPOEIOCSFWD handling Support for handling the PPPOEIOCSFWD ioctl in compat mode was added in linux-2.5.69 along with hundreds of other commands, but was always broken sincen only the structure is compatible, but the command number is not, due to the size being sizeof(size_t), or at first sizeof(sizeof((struct sockaddr_pppox)), which is different on 64-bit architectures. Guillaume Nault adds: And the implementation was broken until 2016 (see 29e73269aa4d ("pppoe: fix reference counting in PPPoE proxy")), and nobody ever noticed. I should probably have removed this ioctl entirely instead of fixing it. Clearly, it has never been used. Fix it by adding a compat_ioctl handler for all pppoe variants that translates the command number and then calls the regular ioctl function. All other ioctl commands handled by pppoe are compatible between 32-bit and 64-bit, and require compat_ptr() conversion. This should apply to all stable kernels. Acked-by: Guillaume Nault Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ppp/pppoe.c | 3 +++ drivers/net/ppp/pppox.c | 13 +++++++++++++ drivers/net/ppp/pptp.c | 3 +++ fs/compat_ioctl.c | 3 --- include/linux/if_pppox.h | 3 +++ net/l2tp/l2tp_ppp.c | 3 +++ 6 files changed, 25 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 1d902ecb4aa8..a44dd3c8af63 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -1115,6 +1115,9 @@ static const struct proto_ops pppoe_ops = { .recvmsg = pppoe_recvmsg, .mmap = sock_no_mmap, .ioctl = pppox_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = pppox_compat_ioctl, +#endif }; static const struct pppox_proto pppoe_proto = { diff --git a/drivers/net/ppp/pppox.c b/drivers/net/ppp/pppox.c index 5ef422a43d70..08364f10a43f 100644 --- a/drivers/net/ppp/pppox.c +++ b/drivers/net/ppp/pppox.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -98,6 +99,18 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) EXPORT_SYMBOL(pppox_ioctl); +#ifdef CONFIG_COMPAT +int pppox_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + if (cmd == PPPOEIOCSFWD32) + cmd = PPPOEIOCSFWD; + + return pppox_ioctl(sock, cmd, (unsigned long)compat_ptr(arg)); +} + +EXPORT_SYMBOL(pppox_compat_ioctl); +#endif + static int pppox_create(struct net *net, struct socket *sock, int protocol, int kern) { diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index a8e52c8e4128..734de7de03f7 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -623,6 +623,9 @@ static const struct proto_ops pptp_ops = { .recvmsg = sock_no_recvmsg, .mmap = sock_no_mmap, .ioctl = pppox_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = pppox_compat_ioctl, +#endif }; static const struct pppox_proto pppox_pptp_proto = { diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 6e30949d9f77..a7ec2d3dff92 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -638,9 +638,6 @@ COMPATIBLE_IOCTL(PPPIOCDISCONN) COMPATIBLE_IOCTL(PPPIOCATTCHAN) COMPATIBLE_IOCTL(PPPIOCGCHAN) COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS) -/* PPPOX */ -COMPATIBLE_IOCTL(PPPOEIOCSFWD) -COMPATIBLE_IOCTL(PPPOEIOCDFWD) /* Big A */ /* sparc only */ /* Big Q for sound/OSS */ diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h index 8b728750a625..69e813bcb947 100644 --- a/include/linux/if_pppox.h +++ b/include/linux/if_pppox.h @@ -80,6 +80,9 @@ extern int register_pppox_proto(int proto_num, const struct pppox_proto *pp); extern void unregister_pppox_proto(int proto_num); extern void pppox_unbind_sock(struct sock *sk);/* delete ppp-channel binding */ extern int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); +extern int pppox_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); + +#define PPPOEIOCSFWD32 _IOW(0xB1 ,0, compat_size_t) /* PPPoX socket states */ enum { diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 1d0e5904dedf..c54cb59593ef 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -1681,6 +1681,9 @@ static const struct proto_ops pppol2tp_ops = { .recvmsg = pppol2tp_recvmsg, .mmap = sock_no_mmap, .ioctl = pppox_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = pppox_compat_ioctl, +#endif }; static const struct pppox_proto pppol2tp_proto = { -- cgit v1.2.3-59-g8ed1b From abb48f801396ba312e95f3c11072425221ce7401 Mon Sep 17 00:00:00 2001 From: xiaofeis Date: Sun, 28 Jul 2019 08:57:50 +0800 Subject: net: dsa: qca8k: enable port flow control Set phy device advertising to enable MAC flow control. Signed-off-by: Xiaofei Shen Signed-off-by: David S. Miller --- drivers/net/dsa/qca8k.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 232e8cc96f6d..e429e92dedf4 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2009 Felix Fietkau * Copyright (C) 2011-2012 Gabor Juhos - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2016 John Crispin */ @@ -935,6 +935,8 @@ qca8k_port_enable(struct dsa_switch *ds, int port, qca8k_port_set_status(priv, port, 1); priv->port_sts[port].enabled = 1; + phy_support_asym_pause(phy); + return 0; } -- cgit v1.2.3-59-g8ed1b From 28fe79000e9b0a6f99959869947f1ca305f14599 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 31 Jul 2019 09:33:14 +0300 Subject: mlxsw: spectrum: Fix error path in mlxsw_sp_module_init() In case of sp2 pci driver registration fail, fix the error path to start with sp1 pci driver unregister. Fixes: c3ab435466d5 ("mlxsw: spectrum: Extend to support Spectrum-2 ASIC") Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 650638152bbc..eda9c23e87b2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -6330,7 +6330,7 @@ static int __init mlxsw_sp_module_init(void) return 0; err_sp2_pci_driver_register: - mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver); + mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver); err_sp1_pci_driver_register: mlxsw_core_driver_unregister(&mlxsw_sp2_driver); err_sp2_core_driver_register: -- cgit v1.2.3-59-g8ed1b From 744ad9a357280d03d567538cee7e1e457dedd481 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 31 Jul 2019 09:33:15 +0300 Subject: mlxsw: spectrum_buffers: Further reduce pool size on Spectrum-2 In commit e891ce1dd2a5 ("mlxsw: spectrum_buffers: Reduce pool size on Spectrum-2"), pool size was reduced to mitigate a problem in port buffer usage of ports split four ways. It turns out that this work around does not solve the issue, and a further reduction is required. Thus reduce the size of pool 0 by another 2.7 MiB, and round down to the whole number of cells. Fixes: e891ce1dd2a5 ("mlxsw: spectrum_buffers: Reduce pool size on Spectrum-2") Signed-off-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index 1537f70bc26d..888ba4300bcc 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -437,8 +437,8 @@ static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = { MLXSW_SP1_SB_PR_CPU_SIZE, true, false), }; -#define MLXSW_SP2_SB_PR_INGRESS_SIZE 38128752 -#define MLXSW_SP2_SB_PR_EGRESS_SIZE 38128752 +#define MLXSW_SP2_SB_PR_INGRESS_SIZE 35297568 +#define MLXSW_SP2_SB_PR_EGRESS_SIZE 35297568 #define MLXSW_SP2_SB_PR_CPU_SIZE (256 * 1000) /* Order according to mlxsw_sp2_sb_pool_dess */ -- cgit v1.2.3-59-g8ed1b From 47b69bf74f16b20a3bb95b1fe27e5347dd34b683 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 31 Jul 2019 09:38:42 +0200 Subject: net: ethernet: et131x: Use GFP_KERNEL instead of GFP_ATOMIC when allocating tx_ring->tcb_ring There is no good reason to use GFP_ATOMIC here. Other memory allocations are performed with GFP_KERNEL (see other 'dma_alloc_coherent()' below and 'kzalloc()' in 'et131x_rx_dma_memory_alloc()') Use GFP_KERNEL which should be enough. Signed-off-by: Christophe JAILLET Signed-off-by: David S. Miller --- drivers/net/ethernet/agere/et131x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c index ea34bcb868b5..edbb4b3604c7 100644 --- a/drivers/net/ethernet/agere/et131x.c +++ b/drivers/net/ethernet/agere/et131x.c @@ -2362,7 +2362,7 @@ static int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter) /* Allocate memory for the TCB's (Transmit Control Block) */ tx_ring->tcb_ring = kcalloc(NUM_TCB, sizeof(struct tcb), - GFP_ATOMIC | GFP_DMA); + GFP_KERNEL | GFP_DMA); if (!tx_ring->tcb_ring) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 246902bdf562d45ea3475fac64c93048a7a39f01 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 31 Jul 2019 10:06:48 +0200 Subject: net: ag71xx: Use GFP_KERNEL instead of GFP_ATOMIC in 'ag71xx_rings_init()' There is no need to use GFP_ATOMIC here, GFP_KERNEL should be enough. The 'kcalloc()' just a few lines above, already uses GFP_KERNEL. Signed-off-by: Christophe JAILLET Signed-off-by: David S. Miller --- drivers/net/ethernet/atheros/ag71xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/atheros/ag71xx.c b/drivers/net/ethernet/atheros/ag71xx.c index 8b69d0d7e726..6703960c7cf5 100644 --- a/drivers/net/ethernet/atheros/ag71xx.c +++ b/drivers/net/ethernet/atheros/ag71xx.c @@ -1141,7 +1141,7 @@ static int ag71xx_rings_init(struct ag71xx *ag) tx->descs_cpu = dma_alloc_coherent(&ag->pdev->dev, ring_size * AG71XX_DESC_SIZE, - &tx->descs_dma, GFP_ATOMIC); + &tx->descs_dma, GFP_KERNEL); if (!tx->descs_cpu) { kfree(tx->buf); tx->buf = NULL; -- cgit v1.2.3-59-g8ed1b From c6349f8807324e270c5214920a1309481dd89ba4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 31 Jul 2019 15:12:02 +0200 Subject: net: mediatek: Drop unneeded dependency on NET_VENDOR_MEDIATEK The whole block is protected by "if NET_VENDOR_MEDIATEK", so there is no need for individual driver config symbols to duplicate this dependency. Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mediatek/Kconfig b/drivers/net/ethernet/mediatek/Kconfig index 263cd0909fe0..1f7fff81f24d 100644 --- a/drivers/net/ethernet/mediatek/Kconfig +++ b/drivers/net/ethernet/mediatek/Kconfig @@ -9,7 +9,6 @@ if NET_VENDOR_MEDIATEK config NET_MEDIATEK_SOC tristate "MediaTek SoC Gigabit Ethernet support" - depends on NET_VENDOR_MEDIATEK select PHYLIB ---help--- This driver supports the gigabit ethernet MACs in the -- cgit v1.2.3-59-g8ed1b From 271da132e29b5341c31eca6ba6a72ea1302ebac8 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Tue, 30 Jul 2019 16:08:13 +0800 Subject: net: phy: phy_led_triggers: Fix a possible null-pointer dereference in phy_led_trigger_change_speed() In phy_led_trigger_change_speed(), there is an if statement on line 48 to check whether phy->last_triggered is NULL: if (!phy->last_triggered) When phy->last_triggered is NULL, it is used on line 52: led_trigger_event(&phy->last_triggered->trigger, LED_OFF); Thus, a possible null-pointer dereference may occur. To fix this bug, led_trigger_event(&phy->last_triggered->trigger, LED_OFF) is called when phy->last_triggered is not NULL. This bug is found by a static analysis tool STCheck written by the OSLAB group in Tsinghua University. Signed-off-by: Jia-Ju Bai Signed-off-by: David S. Miller --- drivers/net/phy/phy_led_triggers.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/phy_led_triggers.c b/drivers/net/phy/phy_led_triggers.c index b86a4b2116f8..59a94e07e7c5 100644 --- a/drivers/net/phy/phy_led_triggers.c +++ b/drivers/net/phy/phy_led_triggers.c @@ -48,8 +48,9 @@ void phy_led_trigger_change_speed(struct phy_device *phy) if (!phy->last_triggered) led_trigger_event(&phy->led_link_trigger->trigger, LED_FULL); + else + led_trigger_event(&phy->last_triggered->trigger, LED_OFF); - led_trigger_event(&phy->last_triggered->trigger, LED_OFF); led_trigger_event(&plt->trigger, LED_FULL); phy->last_triggered = plt; } -- cgit v1.2.3-59-g8ed1b From 4d97972b45f080db4c6d27cc0b54321d9cd7be17 Mon Sep 17 00:00:00 2001 From: Frode Isaksen Date: Tue, 30 Jul 2019 13:38:14 +0200 Subject: net: stmmac: Use netif_tx_napi_add() for TX polling function This variant of netif_napi_add() should be used from drivers using NAPI to exclusively poll a TX queue. Signed-off-by: Frode Isaksen Tested-by: Bartosz Golaszewski Signed-off-by: Bartosz Golaszewski Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 9a4a56ad35cd..fd54c7c87485 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4320,8 +4320,9 @@ int stmmac_dvr_probe(struct device *device, NAPI_POLL_WEIGHT); } if (queue < priv->plat->tx_queues_to_use) { - netif_napi_add(ndev, &ch->tx_napi, stmmac_napi_poll_tx, - NAPI_POLL_WEIGHT); + netif_tx_napi_add(ndev, &ch->tx_napi, + stmmac_napi_poll_tx, + NAPI_POLL_WEIGHT); } } -- cgit v1.2.3-59-g8ed1b From 1f66072503316134873060b24b7895dbbcccf00e Mon Sep 17 00:00:00 2001 From: Mauro Rossi Date: Thu, 1 Aug 2019 09:04:34 +0200 Subject: iwlwifi: dbg_ini: fix compile time assert build errors This patch fixes and preserves existing code style, and readability, for IWL_ERR() and IWL_WARN() macros invocations recently added in dbg.c Fixes the following build errors with Android build system: /home/utente/pie-x86_kernel/kernel/drivers/net/wireless/intel/iwlwifi/fw/dbg.c: In function '_iwl_fw_dbg_apply_point': /home/utente/pie-x86_kernel/kernel/drivers/net/wireless/intel/iwlwifi/fw/dbg.c:2445:3: error: call to '__compiletime_assert_2446' declared with attribute error: BUILD_BUG_ON failed: err_str[sizeof(err_str) - 2] != '\n' /home/utente/pie-x86_kernel/kernel/drivers/net/wireless/intel/iwlwifi/fw/dbg.c:2451:3: error: call to '__compiletime_assert_2452' declared with attribute error: BUILD_BUG_ON failed: err_str[sizeof(err_str) - 2] != '\n' ... /home/utente/pie-x86_kernel/kernel/drivers/net/wireless/intel/iwlwifi/fw/dbg.c:2789:5: error: call to '__compiletime_assert_2790' declared with attribute error: BUILD_BUG_ON failed: invalid_ap_str[sizeof(invalid_ap_str) - 2] != '\n' /home/utente/pie-x86_kernel/kernel/drivers/net/wireless/intel/iwlwifi/fw/dbg.c:2800:5: error: call to '__compiletime_assert_2801' declared with attribute error: BUILD_BUG_ON failed: invalid_ap_str[sizeof(invalid_ap_str) - 2] != '\n' Fixes: 427ab6385cf3 ("iwlwifi: dbg_ini: enforce apply point early on buffer allocation tlv") Fixes: 57d88b116175 ("iwlwifi: dbg_ini: support debug info TLV") Signed-off-by: Mauro Rossi Signed-off-by: Johannes Berg Reviewed-by: Nathan Chancellor Tested-by: Nathan Chancellor Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index e411ac98290d..4d81776f576d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2438,17 +2438,19 @@ static void iwl_fw_dbg_info_apply(struct iwl_fw_runtime *fwrt, { u32 img_name_len = le32_to_cpu(dbg_info->img_name_len); u32 dbg_cfg_name_len = le32_to_cpu(dbg_info->dbg_cfg_name_len); - const char err_str[] = - "WRT: ext=%d. Invalid %s name length %d, expected %d\n"; if (img_name_len != IWL_FW_INI_MAX_IMG_NAME_LEN) { - IWL_WARN(fwrt, err_str, ext, "image", img_name_len, + IWL_WARN(fwrt, + "WRT: ext=%d. Invalid image name length %d, expected %d\n", + ext, img_name_len, IWL_FW_INI_MAX_IMG_NAME_LEN); return; } if (dbg_cfg_name_len != IWL_FW_INI_MAX_DBG_CFG_NAME_LEN) { - IWL_WARN(fwrt, err_str, ext, "debug cfg", dbg_cfg_name_len, + IWL_WARN(fwrt, + "WRT: ext=%d. Invalid debug cfg name length %d, expected %d\n", + ext, dbg_cfg_name_len, IWL_FW_INI_MAX_DBG_CFG_NAME_LEN); return; } @@ -2775,8 +2777,6 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt, struct iwl_ucode_tlv *tlv = iter; void *ini_tlv = (void *)tlv->data; u32 type = le32_to_cpu(tlv->type); - const char invalid_ap_str[] = - "WRT: ext=%d. Invalid apply point %d for %s\n"; switch (type) { case IWL_UCODE_TLV_TYPE_DEBUG_INFO: @@ -2786,8 +2786,9 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt, struct iwl_fw_ini_allocation_data *buf_alloc = ini_tlv; if (pnt != IWL_FW_INI_APPLY_EARLY) { - IWL_ERR(fwrt, invalid_ap_str, ext, pnt, - "buffer allocation"); + IWL_ERR(fwrt, + "WRT: ext=%d. Invalid apply point %d for buffer allocation\n", + ext, pnt); goto next; } @@ -2797,8 +2798,9 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt, } case IWL_UCODE_TLV_TYPE_HCMD: if (pnt < IWL_FW_INI_APPLY_AFTER_ALIVE) { - IWL_ERR(fwrt, invalid_ap_str, ext, pnt, - "host command"); + IWL_ERR(fwrt, + "WRT: ext=%d. Invalid apply point %d for host command\n", + ext, pnt); goto next; } iwl_fw_dbg_send_hcmd(fwrt, tlv, ext); -- cgit v1.2.3-59-g8ed1b From 944a83a2669ae8aa2c7664e79376ca7468eb0a2b Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Thu, 1 Aug 2019 14:13:30 +0200 Subject: mvpp2: fix panic on module removal mvpp2 uses a delayed workqueue to gather traffic statistics. On module removal the workqueue can be destroyed before calling cancel_delayed_work_sync() on its works. Fix it by moving the destroy_workqueue() call after mvpp2_port_remove(). Also remove an unneeded call to flush_workqueue() # rmmod mvpp2 [ 2743.311722] mvpp2 f4000000.ethernet eth1: phy link down 10gbase-kr/10Gbps/Full [ 2743.320063] mvpp2 f4000000.ethernet eth1: Link is Down [ 2743.572263] mvpp2 f4000000.ethernet eth2: phy link down sgmii/1Gbps/Full [ 2743.580076] mvpp2 f4000000.ethernet eth2: Link is Down [ 2744.102169] mvpp2 f2000000.ethernet eth0: phy link down 10gbase-kr/10Gbps/Full [ 2744.110441] mvpp2 f2000000.ethernet eth0: Link is Down [ 2744.115614] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 [ 2744.115615] Mem abort info: [ 2744.115616] ESR = 0x96000005 [ 2744.115617] Exception class = DABT (current EL), IL = 32 bits [ 2744.115618] SET = 0, FnV = 0 [ 2744.115619] EA = 0, S1PTW = 0 [ 2744.115620] Data abort info: [ 2744.115621] ISV = 0, ISS = 0x00000005 [ 2744.115622] CM = 0, WnR = 0 [ 2744.115624] user pgtable: 4k pages, 39-bit VAs, pgdp=0000000422681000 [ 2744.115626] [0000000000000000] pgd=0000000000000000, pud=0000000000000000 [ 2744.115630] Internal error: Oops: 96000005 [#1] SMP [ 2744.115632] Modules linked in: mvpp2(-) algif_hash af_alg nls_iso8859_1 nls_cp437 vfat fat xhci_plat_hcd m25p80 spi_nor xhci_hcd mtd usbcore i2c_mv64xxx sfp usb_common marvell10g phy_generic spi_orion mdio_i2c i2c_core mvmdio phylink sbsa_gwdt ip_tables x_tables autofs4 [last unloaded: mvpp2] [ 2744.115654] CPU: 3 PID: 8357 Comm: kworker/3:2 Not tainted 5.3.0-rc2 #1 [ 2744.115655] Hardware name: Marvell 8040 MACCHIATOBin Double-shot (DT) [ 2744.115665] Workqueue: events_power_efficient phylink_resolve [phylink] [ 2744.115669] pstate: a0000085 (NzCv daIf -PAN -UAO) [ 2744.115675] pc : __queue_work+0x9c/0x4d8 [ 2744.115677] lr : __queue_work+0x170/0x4d8 [ 2744.115678] sp : ffffff801001bd50 [ 2744.115680] x29: ffffff801001bd50 x28: ffffffc422597600 [ 2744.115684] x27: ffffff80109ae6f0 x26: ffffff80108e4018 [ 2744.115688] x25: 0000000000000003 x24: 0000000000000004 [ 2744.115691] x23: ffffff80109ae6e0 x22: 0000000000000017 [ 2744.115694] x21: ffffffc42c030000 x20: ffffffc42209e8f8 [ 2744.115697] x19: 0000000000000000 x18: 0000000000000000 [ 2744.115699] x17: 0000000000000000 x16: 0000000000000000 [ 2744.115701] x15: 0000000000000010 x14: ffffffffffffffff [ 2744.115702] x13: ffffff8090e2b95f x12: ffffff8010e2b967 [ 2744.115704] x11: ffffff8010906000 x10: 0000000000000040 [ 2744.115706] x9 : ffffff80109223b8 x8 : ffffff80109223b0 [ 2744.115707] x7 : ffffffc42bc00068 x6 : 0000000000000000 [ 2744.115709] x5 : ffffffc42bc00000 x4 : 0000000000000000 [ 2744.115710] x3 : 0000000000000000 x2 : 0000000000000000 [ 2744.115712] x1 : 0000000000000008 x0 : ffffffc42c030000 [ 2744.115714] Call trace: [ 2744.115716] __queue_work+0x9c/0x4d8 [ 2744.115718] delayed_work_timer_fn+0x28/0x38 [ 2744.115722] call_timer_fn+0x3c/0x180 [ 2744.115723] expire_timers+0x60/0x168 [ 2744.115724] run_timer_softirq+0xbc/0x1e8 [ 2744.115727] __do_softirq+0x128/0x320 [ 2744.115731] irq_exit+0xa4/0xc0 [ 2744.115734] __handle_domain_irq+0x70/0xc0 [ 2744.115735] gic_handle_irq+0x58/0xa8 [ 2744.115737] el1_irq+0xb8/0x140 [ 2744.115738] console_unlock+0x3a0/0x568 [ 2744.115740] vprintk_emit+0x200/0x2a0 [ 2744.115744] dev_vprintk_emit+0x1c8/0x1e4 [ 2744.115747] dev_printk_emit+0x6c/0x7c [ 2744.115751] __netdev_printk+0x104/0x1d8 [ 2744.115752] netdev_printk+0x60/0x70 [ 2744.115756] phylink_resolve+0x38c/0x3c8 [phylink] [ 2744.115758] process_one_work+0x1f8/0x448 [ 2744.115760] worker_thread+0x54/0x500 [ 2744.115762] kthread+0x12c/0x130 [ 2744.115764] ret_from_fork+0x10/0x1c [ 2744.115768] Code: aa1403e0 97fffbbe aa0003f5 b4000700 (f9400261) Fixes: 118d6298f6f0 ("net: mvpp2: add ethtool GOP statistics") Signed-off-by: Lorenzo Bianconi Signed-off-by: Matteo Croce Acked-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index e2e61a4a9000..ccdd47f3b8fb 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -5753,9 +5753,6 @@ static int mvpp2_remove(struct platform_device *pdev) mvpp2_dbgfs_cleanup(priv); - flush_workqueue(priv->stats_queue); - destroy_workqueue(priv->stats_queue); - fwnode_for_each_available_child_node(fwnode, port_fwnode) { if (priv->port_list[i]) { mutex_destroy(&priv->port_list[i]->gather_stats_lock); @@ -5764,6 +5761,8 @@ static int mvpp2_remove(struct platform_device *pdev) i++; } + destroy_workqueue(priv->stats_queue); + for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) { struct mvpp2_bm_pool *bm_pool = &priv->bm_pools[i]; -- cgit v1.2.3-59-g8ed1b From 14f1c0f2ff156c89b14fa4c52605e7586436ffb8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 31 Jul 2019 15:22:09 +0200 Subject: net: 8390: Fix manufacturer name in Kconfig help text The help text refers to Western Digital instead of National Semiconductor 8390, presumably because it was copied from the former. Fixes: 644570b830266ff3 ("8390: Move the 8390 related drivers") Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/8390/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig index 2a3e2450968e..a9478577b495 100644 --- a/drivers/net/ethernet/8390/Kconfig +++ b/drivers/net/ethernet/8390/Kconfig @@ -12,8 +12,8 @@ config NET_VENDOR_8390 Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all - the questions about Western Digital cards. If you say Y, you will be - asked for your specific card in the following questions. + the questions about National Semiconductor 8390 cards. If you say Y, + you will be asked for your specific card in the following questions. if NET_VENDOR_8390 -- cgit v1.2.3-59-g8ed1b From 93ae6d2d2e0eef6973d634dd6e1a19ba1b031c30 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 31 Jul 2019 15:22:10 +0200 Subject: net: amd: Spelling s/case/cause/ Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index de4950d2022e..9f965cdfff5c 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -14,7 +14,7 @@ config NET_VENDOR_AMD say Y. Note that the answer to this question does not directly affect - the kernel: saying N will just case the configurator to skip all + the kernel: saying N will just cause the configurator to skip all the questions regarding AMD chipsets. If you say Y, you will be asked for your specific chipset/driver in the following questions. -- cgit v1.2.3-59-g8ed1b From ac0e3f20c7a9fbace30d38e7d306ab15f3e6fd31 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 31 Jul 2019 15:22:11 +0200 Subject: net: apple: Fix manufacturer name in Kconfig help text The help text refers to IBM instead of Apple, presumably because it was copied from the former. Fixes: 8fb6b0908176704a ("bmac/mace/macmace/mac89x0/cs89x0: Move the Macintosh (Apple) drivers") Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/apple/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/apple/Kconfig b/drivers/net/ethernet/apple/Kconfig index fde7ae33e302..f78b9c841296 100644 --- a/drivers/net/ethernet/apple/Kconfig +++ b/drivers/net/ethernet/apple/Kconfig @@ -11,8 +11,8 @@ config NET_VENDOR_APPLE If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about IBM devices. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about Apple devices. If you say Y, you will be asked for your specific card in the following questions. if NET_VENDOR_APPLE -- cgit v1.2.3-59-g8ed1b From aca3432a607b6f9db2a9fe34f4b87d01cd99a68a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 31 Jul 2019 15:22:12 +0200 Subject: net: broadcom: Fix manufacturer name in Kconfig help text The help text refers to AMD instead of Broadcom, presumably because it was copied from the former. Fixes: adfc5217e9db68d3 ("broadcom: Move the Broadcom drivers") Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index e9017caf024d..e24f5d2b6afe 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -14,9 +14,9 @@ config NET_VENDOR_BROADCOM say Y. Note that the answer to this question does not directly affect - the kernel: saying N will just case the configurator to skip all - the questions regarding AMD chipsets. If you say Y, you will be asked - for your specific chipset/driver in the following questions. + the kernel: saying N will just cause the configurator to skip all + the questions regarding Broadcom chipsets. If you say Y, you will + be asked for your specific chipset/driver in the following questions. if NET_VENDOR_BROADCOM -- cgit v1.2.3-59-g8ed1b From cec754cc7813f300d286b1d7e14480f82f7f2ffa Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 31 Jul 2019 15:22:13 +0200 Subject: net: ixp4xx: Spelling s/XSacle/XScale/ Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/xscale/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/xscale/Kconfig b/drivers/net/ethernet/xscale/Kconfig index 2f354ba029a6..cd0a8f46e7c6 100644 --- a/drivers/net/ethernet/xscale/Kconfig +++ b/drivers/net/ethernet/xscale/Kconfig @@ -13,7 +13,7 @@ config NET_VENDOR_XSCALE Note that the answer to this question does not directly affect the kernel: saying N will just cause the configurator to skip all - the questions about XSacle IXP devices. If you say Y, you will be + the questions about XScale IXP devices. If you say Y, you will be asked for your specific card in the following questions. if NET_VENDOR_XSCALE -- cgit v1.2.3-59-g8ed1b From 85aee0a793ba223c48fd2cfe534edf83729deef6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 31 Jul 2019 15:22:14 +0200 Subject: net: nixge: Spelling s/Instrument/Instruments/ Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/ni/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ni/Kconfig b/drivers/net/ethernet/ni/Kconfig index 70b1a03c0953..01229190132d 100644 --- a/drivers/net/ethernet/ni/Kconfig +++ b/drivers/net/ethernet/ni/Kconfig @@ -11,7 +11,7 @@ config NET_VENDOR_NI Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all - the questions about National Instrument devices. + the questions about National Instruments devices. If you say Y, you will be asked for your specific device in the following questions. -- cgit v1.2.3-59-g8ed1b From 1583d448ea84a5b8b98c8d250200ce768b6ced38 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 31 Jul 2019 15:22:15 +0200 Subject: net: packetengines: Fix manufacturer spelling and capitalization Use "Packet Engines" consistently. Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/packetengines/Kconfig | 6 +++--- drivers/net/ethernet/packetengines/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/packetengines/Kconfig b/drivers/net/ethernet/packetengines/Kconfig index 8161e308e64b..ead3750b4489 100644 --- a/drivers/net/ethernet/packetengines/Kconfig +++ b/drivers/net/ethernet/packetengines/Kconfig @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only # -# Packet engine device configuration +# Packet Engines device configuration # config NET_VENDOR_PACKET_ENGINES - bool "Packet Engine devices" + bool "Packet Engines devices" default y depends on PCI ---help--- @@ -12,7 +12,7 @@ config NET_VENDOR_PACKET_ENGINES Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all - the questions about packet engine devices. If you say Y, you will + the questions about Packet Engines devices. If you say Y, you will be asked for your specific card in the following questions. if NET_VENDOR_PACKET_ENGINES diff --git a/drivers/net/ethernet/packetengines/Makefile b/drivers/net/ethernet/packetengines/Makefile index 1553c9cfc254..cf054b796d11 100644 --- a/drivers/net/ethernet/packetengines/Makefile +++ b/drivers/net/ethernet/packetengines/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only # -# Makefile for the Packet Engine network device drivers. +# Makefile for the Packet Engines network device drivers. # obj-$(CONFIG_HAMACHI) += hamachi.o -- cgit v1.2.3-59-g8ed1b From 509b0538bc28870164903f5683e4c3f3b1eca965 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 31 Jul 2019 15:22:16 +0200 Subject: net: samsung: Spelling s/case/cause/ Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/samsung/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/samsung/Kconfig b/drivers/net/ethernet/samsung/Kconfig index 027938017579..e92a178a76df 100644 --- a/drivers/net/ethernet/samsung/Kconfig +++ b/drivers/net/ethernet/samsung/Kconfig @@ -11,7 +11,7 @@ config NET_VENDOR_SAMSUNG say Y. Note that the answer to this question does not directly affect - the kernel: saying N will just case the configurator to skip all + the kernel: saying N will just cause the configurator to skip all the questions about Samsung chipsets. If you say Y, you will be asked for your specific chipset/driver in the following questions. -- cgit v1.2.3-59-g8ed1b From 224c04973db1125fcebefffd86115f99f50f8277 Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Tue, 30 Jul 2019 15:13:57 +0200 Subject: net: usb: pegasus: fix improper read if get_registers() fail get_registers() may fail with -ENOMEM and in this case we can read a garbage from the status variable tmp. Reported-by: syzbot+3499a83b2d062ae409d4@syzkaller.appspotmail.com Signed-off-by: Denis Kirjanov Signed-off-by: David S. Miller --- drivers/net/usb/pegasus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 6d25dea5ad4b..f7d117d80cfb 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -282,7 +282,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc, int val) static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata) { int i; - __u8 tmp; + __u8 tmp = 0; __le16 retdatai; int ret; -- cgit v1.2.3-59-g8ed1b From cd28aa2e056cd1ea79fc5f24eed0ce868c6cab5c Mon Sep 17 00:00:00 2001 From: Wang Xiayang Date: Wed, 31 Jul 2019 15:31:14 +0800 Subject: can: sja1000: force the string buffer NULL-terminated strncpy() does not ensure NULL-termination when the input string size equals to the destination buffer size IFNAMSIZ. The output string 'name' is passed to dev_info which relies on NULL-termination. Use strlcpy() instead. This issue is identified by a Coccinelle script. Signed-off-by: Wang Xiayang Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/peak_pcmcia.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c index 185c7f7d38a4..5e0d5e8101c8 100644 --- a/drivers/net/can/sja1000/peak_pcmcia.c +++ b/drivers/net/can/sja1000/peak_pcmcia.c @@ -479,7 +479,7 @@ static void pcan_free_channels(struct pcan_pccard *card) if (!netdev) continue; - strncpy(name, netdev->name, IFNAMSIZ); + strlcpy(name, netdev->name, IFNAMSIZ); unregister_sja1000dev(netdev); -- cgit v1.2.3-59-g8ed1b From e787f19373b8a5fa24087800ed78314fd17b984a Mon Sep 17 00:00:00 2001 From: Wang Xiayang Date: Wed, 31 Jul 2019 15:25:59 +0800 Subject: can: peak_usb: force the string buffer NULL-terminated strncpy() does not ensure NULL-termination when the input string size equals to the destination buffer size IFNAMSIZ. The output string is passed to dev_info() which relies on the NULL-termination. Use strlcpy() instead. This issue is identified by a Coccinelle script. Signed-off-by: Wang Xiayang Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 22b9c8e6d040..65dce642b86b 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -855,7 +855,7 @@ static void peak_usb_disconnect(struct usb_interface *intf) dev_prev_siblings = dev->prev_siblings; dev->state &= ~PCAN_USB_STATE_CONNECTED; - strncpy(name, netdev->name, IFNAMSIZ); + strlcpy(name, netdev->name, IFNAMSIZ); unregister_netdev(netdev); -- cgit v1.2.3-59-g8ed1b From 30a8beeb3042f49d0537b7050fd21b490166a3d9 Mon Sep 17 00:00:00 2001 From: Tomas Bortoli Date: Wed, 31 Jul 2019 10:54:47 -0400 Subject: can: peak_usb: pcan_usb_fd: Fix info-leaks to USB devices Uninitialized Kernel memory can leak to USB devices. Fix by using kzalloc() instead of kmalloc() on the affected buffers. Signed-off-by: Tomas Bortoli Reported-by: syzbot+513e4d0985298538bf9b@syzkaller.appspotmail.com Fixes: 0a25e1f4f185 ("can: peak_usb: add support for PEAK new CANFD USB adapters") Cc: linux-stable Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index 34761c3a6286..47cc1ff5b88e 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -841,7 +841,7 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev) goto err_out; /* allocate command buffer once for all for the interface */ - pdev->cmd_buffer_addr = kmalloc(PCAN_UFD_CMD_BUFFER_SIZE, + pdev->cmd_buffer_addr = kzalloc(PCAN_UFD_CMD_BUFFER_SIZE, GFP_KERNEL); if (!pdev->cmd_buffer_addr) goto err_out_1; -- cgit v1.2.3-59-g8ed1b From ead16e53c2f0ed946d82d4037c630e2f60f4ab69 Mon Sep 17 00:00:00 2001 From: Tomas Bortoli Date: Wed, 31 Jul 2019 10:54:47 -0400 Subject: can: peak_usb: pcan_usb_pro: Fix info-leaks to USB devices Uninitialized Kernel memory can leak to USB devices. Fix by using kzalloc() instead of kmalloc() on the affected buffers. Signed-off-by: Tomas Bortoli Reported-by: syzbot+d6a5a1a3657b596ef132@syzkaller.appspotmail.com Fixes: f14e22435a27 ("net: can: peak_usb: Do not do dma on the stack") Cc: linux-stable Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 178bb7cff0c1..53cb2f72bdd0 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -494,7 +494,7 @@ static int pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded) u8 *buffer; int err; - buffer = kmalloc(PCAN_USBPRO_FCT_DRVLD_REQ_LEN, GFP_KERNEL); + buffer = kzalloc(PCAN_USBPRO_FCT_DRVLD_REQ_LEN, GFP_KERNEL); if (!buffer) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 3690c8c9a8edff0db077a38783112d8fe12a7dd2 Mon Sep 17 00:00:00 2001 From: Wang Xiayang Date: Wed, 31 Jul 2019 16:15:42 +0800 Subject: net/ethernet/qlogic/qed: force the string buffer NULL-terminated strncpy() does not ensure NULL-termination when the input string size equals to the destination buffer size 30. The output string is passed to qed_int_deassertion_aeu_bit() which calls DP_INFO() and relies NULL-termination. Use strlcpy instead. The other conditional branch above strncpy() needs no fix as snprintf() ensures NULL-termination. This issue is identified by a Coccinelle script. Signed-off-by: Wang Xiayang Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_int.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 4e8118a08654..9f5113639eaf 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -1093,7 +1093,7 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, snprintf(bit_name, 30, p_aeu->bit_name, num); else - strncpy(bit_name, + strlcpy(bit_name, p_aeu->bit_name, 30); /* We now need to pass bitmask in its -- cgit v1.2.3-59-g8ed1b From 2802d2cf24b1ca7ea4c54dde266ded6a16020eb5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 1 Aug 2019 09:24:19 +0800 Subject: enetc: Select PHYLIB while CONFIG_FSL_ENETC_VF is set Like FSL_ENETC, when CONFIG_FSL_ENETC_VF is set, we should select PHYLIB, otherwise building still fails: drivers/net/ethernet/freescale/enetc/enetc.o: In function `enetc_open': enetc.c:(.text+0x2744): undefined reference to `phy_start' enetc.c:(.text+0x282c): undefined reference to `phy_disconnect' drivers/net/ethernet/freescale/enetc/enetc.o: In function `enetc_close': enetc.c:(.text+0x28f8): undefined reference to `phy_stop' enetc.c:(.text+0x2904): undefined reference to `phy_disconnect' drivers/net/ethernet/freescale/enetc/enetc_ethtool.o:(.rodata+0x3f8): undefined reference to `phy_ethtool_get_link_ksettings' drivers/net/ethernet/freescale/enetc/enetc_ethtool.o:(.rodata+0x400): undefined reference to `phy_ethtool_set_link_ksettings' Reported-by: Hulk Robot Fixes: d4fd0404c1c9 ("enetc: Introduce basic PF and VF ENETC ethernet drivers") Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig index 46fdf36bfece..04a59db03f2b 100644 --- a/drivers/net/ethernet/freescale/enetc/Kconfig +++ b/drivers/net/ethernet/freescale/enetc/Kconfig @@ -13,6 +13,7 @@ config FSL_ENETC config FSL_ENETC_VF tristate "ENETC VF driver" depends on PCI && PCI_MSI && (ARCH_LAYERSCAPE || COMPILE_TEST) + select PHYLIB help This driver supports NXP ENETC gigabit ethernet controller PCIe virtual function (VF) devices enabled by the ENETC PF driver. -- cgit v1.2.3-59-g8ed1b From aa6b1956158f1afc52761137620d4b3f8a058d24 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 31 Jul 2019 23:05:10 +0200 Subject: net: phy: fix race in genphy_update_link In phy_start_aneg() autoneg is started, and immediately after that link and autoneg status are read. As reported in [0] it can happen that at time of this read the PHY has reset the "aneg complete" bit but not yet the "link up" bit, what can result in a false link-up detection. To fix this don't report link as up if we're in aneg mode and PHY doesn't signal "aneg complete". [0] https://marc.info/?t=156413509900003&r=1&w=2 Fixes: 4950c2ba49cc ("net: phy: fix autoneg mismatch case in genphy_read_status") Reported-by: liuyonglong Tested-by: liuyonglong Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 6b5cb87f3866..7ddd91df99e3 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1774,6 +1774,12 @@ done: phydev->link = status & BMSR_LSTATUS ? 1 : 0; phydev->autoneg_complete = status & BMSR_ANEGCOMPLETE ? 1 : 0; + /* Consider the case that autoneg was started and "aneg complete" + * bit has been reset, but "link up" bit not yet. + */ + if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete) + phydev->link = 0; + return 0; } EXPORT_SYMBOL(genphy_update_link); -- cgit v1.2.3-59-g8ed1b From 59c0b47a1e11b5e81ab1dfd13579c9fbdb02f0b4 Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Thu, 1 Aug 2019 11:29:38 +0800 Subject: r8152: fix typo in register name It is likely that PAL_BDC_CR should be PLA_BDC_CR. Signed-off-by: Kevin Lo Acked-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 39e0768d734d..0cc03a9ff545 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -50,7 +50,7 @@ #define PLA_TEREDO_WAKE_BASE 0xc0c4 #define PLA_MAR 0xcd00 #define PLA_BACKUP 0xd000 -#define PAL_BDC_CR 0xd1a0 +#define PLA_BDC_CR 0xd1a0 #define PLA_TEREDO_TIMER 0xd2cc #define PLA_REALWOW_TIMER 0xd2e8 #define PLA_SUSPEND_FLAG 0xd38a @@ -274,7 +274,7 @@ #define TEREDO_RS_EVENT_MASK 0x00fe #define OOB_TEREDO_EN 0x0001 -/* PAL_BDC_CR */ +/* PLA_BDC_CR */ #define ALDPS_PROXY_MODE 0x0001 /* PLA_EFUSE_CMD */ @@ -3191,9 +3191,9 @@ static void r8152b_enter_oob(struct r8152 *tp) rtl_rx_vlan_en(tp, true); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR); + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BDC_CR); ocp_data |= ALDPS_PROXY_MODE; - ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_BDC_CR, ocp_data); ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; @@ -3577,9 +3577,9 @@ static void r8153_enter_oob(struct r8152 *tp) rtl_rx_vlan_en(tp, true); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR); + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BDC_CR); ocp_data |= ALDPS_PROXY_MODE; - ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_BDC_CR, ocp_data); ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; -- cgit v1.2.3-59-g8ed1b From 7fb5a711545d7d25fe9726a9ad277474dd83bd06 Mon Sep 17 00:00:00 2001 From: Hubert Feurstein Date: Wed, 31 Jul 2019 17:42:39 +0200 Subject: net: dsa: mv88e6xxx: drop adjust_link to enabled phylink We have to drop the adjust_link callback in order to finally migrate to phylink. Otherwise we get the following warning during startup: "mv88e6xxx 2188000.ethernet-1:10: Using legacy PHYLIB callbacks. Please migrate to PHYLINK!" The warning is generated in the function dsa_port_link_register_of in dsa/port.c: int dsa_port_link_register_of(struct dsa_port *dp) { struct dsa_switch *ds = dp->ds; if (!ds->ops->adjust_link) return dsa_port_phylink_register(dp); dev_warn(ds->dev, "Using legacy PHYLIB callbacks. Please migrate to PHYLINK!\n"); [...] } Signed-off-by: Hubert Feurstein Reviewed-by: Andrew Lunn Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index a0f288efcc12..d0a97eb73a37 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -482,30 +481,6 @@ static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) return port < chip->info->num_internal_phys; } -/* We expect the switch to perform auto negotiation if there is a real - * phy. However, in the case of a fixed link phy, we force the port - * settings from the fixed link settings. - */ -static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, - struct phy_device *phydev) -{ - struct mv88e6xxx_chip *chip = ds->priv; - int err; - - if (!phy_is_pseudo_fixed_link(phydev) && - mv88e6xxx_phy_is_internal(ds, port)) - return; - - mv88e6xxx_reg_lock(chip); - err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed, - phydev->duplex, phydev->pause, - phydev->interface); - mv88e6xxx_reg_unlock(chip); - - if (err && err != -EOPNOTSUPP) - dev_err(ds->dev, "p%d: failed to configure MAC\n", port); -} - static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port, unsigned long *mask, struct phylink_link_state *state) @@ -4639,7 +4614,6 @@ static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port, static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .get_tag_protocol = mv88e6xxx_get_tag_protocol, .setup = mv88e6xxx_setup, - .adjust_link = mv88e6xxx_adjust_link, .phylink_validate = mv88e6xxx_validate, .phylink_mac_link_state = mv88e6xxx_link_state, .phylink_mac_config = mv88e6xxx_mac_config, -- cgit v1.2.3-59-g8ed1b From 60d60c8fbd8d1acf25b041ecd72ae4fa16e9405b Mon Sep 17 00:00:00 2001 From: Qian Cai Date: Thu, 1 Aug 2019 09:52:54 -0400 Subject: net/mlx5e: always initialize frag->last_in_page The commit 069d11465a80 ("net/mlx5e: RX, Enhance legacy Receive Queue memory scheme") introduced an undefined behaviour below due to "frag->last_in_page" is only initialized in mlx5e_init_frags_partition() when, if (next_frag.offset + frag_info[f].frag_stride > PAGE_SIZE) or after bailed out the loop, for (i = 0; i < mlx5_wq_cyc_get_size(&rq->wqe.wq); i++) As the result, there could be some "frag" have uninitialized value of "last_in_page". Later, get_frag() obtains those "frag" and check "frag->last_in_page" in mlx5e_put_rx_frag() and triggers the error during boot. Fix it by always initializing "frag->last_in_page" to "false" in mlx5e_init_frags_partition(). UBSAN: Undefined behaviour in drivers/net/ethernet/mellanox/mlx5/core/en_rx.c:325:12 load of value 170 is not a valid value for type 'bool' (aka '_Bool') Call trace: dump_backtrace+0x0/0x264 show_stack+0x20/0x2c dump_stack+0xb0/0x104 __ubsan_handle_load_invalid_value+0x104/0x128 mlx5e_handle_rx_cqe+0x8e8/0x12cc [mlx5_core] mlx5e_poll_rx_cq+0xca8/0x1a94 [mlx5_core] mlx5e_napi_poll+0x17c/0xa30 [mlx5_core] net_rx_action+0x248/0x940 __do_softirq+0x350/0x7b8 irq_exit+0x200/0x26c __handle_domain_irq+0xc8/0x128 gic_handle_irq+0x138/0x228 el1_irq+0xb8/0x140 arch_cpu_idle+0x1a4/0x348 do_idle+0x114/0x1b0 cpu_startup_entry+0x24/0x28 rest_init+0x1ac/0x1dc arch_call_rest_init+0x10/0x18 start_kernel+0x4d4/0x57c Fixes: 069d11465a80 ("net/mlx5e: RX, Enhance legacy Receive Queue memory scheme") Signed-off-by: Qian Cai Reviewed-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 570c42b7eeea..6c712c5be4d8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -331,12 +331,11 @@ static inline u64 mlx5e_get_mpwqe_offset(struct mlx5e_rq *rq, u16 wqe_ix) static void mlx5e_init_frags_partition(struct mlx5e_rq *rq) { - struct mlx5e_wqe_frag_info next_frag, *prev; + struct mlx5e_wqe_frag_info next_frag = {}; + struct mlx5e_wqe_frag_info *prev = NULL; int i; next_frag.di = &rq->wqe.di[0]; - next_frag.offset = 0; - prev = NULL; for (i = 0; i < mlx5_wq_cyc_get_size(&rq->wqe.wq); i++) { struct mlx5e_rq_frag_info *frag_info = &rq->wqe.info.arr[0]; -- cgit v1.2.3-59-g8ed1b From 438b43bdb95d3189e0098919f321c014ed71f410 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Thu, 1 Aug 2019 16:07:31 -0700 Subject: gve: Fix case where desc_cnt and data_cnt can get out of sync desc_cnt and data_cnt should always be equal. In the case of a dropped packet desc_cnt was still getting updated (correctly), data_cnt was not. To eliminate this bug and prevent it from recurring this patch combines them into one ring level cnt. Signed-off-by: Catherine Sullivan Reviewed-by: Sagi Shahar Signed-off-by: David S. Miller --- drivers/net/ethernet/google/gve/gve.h | 8 +++---- drivers/net/ethernet/google/gve/gve_ethtool.c | 4 ++-- drivers/net/ethernet/google/gve/gve_rx.c | 34 ++++++++++++--------------- 3 files changed, 20 insertions(+), 26 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index 92372dc43be8..ebc37e256922 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -31,9 +31,6 @@ struct gve_rx_desc_queue { struct gve_rx_desc *desc_ring; /* the descriptor ring */ dma_addr_t bus; /* the bus for the desc_ring */ - u32 cnt; /* free-running total number of completed packets */ - u32 fill_cnt; /* free-running total number of descriptors posted */ - u32 mask; /* masks the cnt to the size of the ring */ u8 seqno; /* the next expected seqno for this desc*/ }; @@ -60,8 +57,6 @@ struct gve_rx_data_queue { dma_addr_t data_bus; /* dma mapping of the slots */ struct gve_rx_slot_page_info *page_info; /* page info of the buffers */ struct gve_queue_page_list *qpl; /* qpl assigned to this queue */ - u32 mask; /* masks the cnt to the size of the ring */ - u32 cnt; /* free-running total number of completed packets */ }; struct gve_priv; @@ -73,6 +68,9 @@ struct gve_rx_ring { struct gve_rx_data_queue data; u64 rbytes; /* free-running bytes received */ u64 rpackets; /* free-running packets received */ + u32 cnt; /* free-running total number of completed packets */ + u32 fill_cnt; /* free-running total number of descs and buffs posted */ + u32 mask; /* masks the cnt and fill_cnt to the size of the ring */ u32 q_num; /* queue index */ u32 ntfy_id; /* notification block index */ struct gve_queue_resources *q_resources; /* head and tail pointer idx */ diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c index 26540b856541..d8fa816f4473 100644 --- a/drivers/net/ethernet/google/gve/gve_ethtool.c +++ b/drivers/net/ethernet/google/gve/gve_ethtool.c @@ -138,8 +138,8 @@ gve_get_ethtool_stats(struct net_device *netdev, for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) { struct gve_rx_ring *rx = &priv->rx[ring]; - data[i++] = rx->desc.cnt; - data[i++] = rx->desc.fill_cnt; + data[i++] = rx->cnt; + data[i++] = rx->fill_cnt; } } else { i += priv->rx_cfg.num_queues * NUM_GVE_RX_CNTS; diff --git a/drivers/net/ethernet/google/gve/gve_rx.c b/drivers/net/ethernet/google/gve/gve_rx.c index 1914b8350da7..59564ac99d2a 100644 --- a/drivers/net/ethernet/google/gve/gve_rx.c +++ b/drivers/net/ethernet/google/gve/gve_rx.c @@ -37,7 +37,7 @@ static void gve_rx_free_ring(struct gve_priv *priv, int idx) rx->data.qpl = NULL; kvfree(rx->data.page_info); - slots = rx->data.mask + 1; + slots = rx->mask + 1; bytes = sizeof(*rx->data.data_ring) * slots; dma_free_coherent(dev, bytes, rx->data.data_ring, rx->data.data_bus); @@ -64,7 +64,7 @@ static int gve_prefill_rx_pages(struct gve_rx_ring *rx) /* Allocate one page per Rx queue slot. Each page is split into two * packet buffers, when possible we "page flip" between the two. */ - slots = rx->data.mask + 1; + slots = rx->mask + 1; rx->data.page_info = kvzalloc(slots * sizeof(*rx->data.page_info), GFP_KERNEL); @@ -111,7 +111,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) rx->q_num = idx; slots = priv->rx_pages_per_qpl; - rx->data.mask = slots - 1; + rx->mask = slots - 1; /* alloc rx data ring */ bytes = sizeof(*rx->data.data_ring) * slots; @@ -125,7 +125,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) err = -ENOMEM; goto abort_with_slots; } - rx->desc.fill_cnt = filled_pages; + rx->fill_cnt = filled_pages; /* Ensure data ring slots (packet buffers) are visible. */ dma_wmb(); @@ -156,8 +156,8 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) err = -ENOMEM; goto abort_with_q_resources; } - rx->desc.mask = slots - 1; - rx->desc.cnt = 0; + rx->mask = slots - 1; + rx->cnt = 0; rx->desc.seqno = 1; gve_rx_add_to_block(priv, idx); @@ -213,7 +213,7 @@ void gve_rx_write_doorbell(struct gve_priv *priv, struct gve_rx_ring *rx) { u32 db_idx = be32_to_cpu(rx->q_resources->db_index); - iowrite32be(rx->desc.fill_cnt, &priv->db_bar2[db_idx]); + iowrite32be(rx->fill_cnt, &priv->db_bar2[db_idx]); } static enum pkt_hash_types gve_rss_type(__be16 pkt_flags) @@ -273,7 +273,7 @@ static void gve_rx_flip_buff(struct gve_rx_slot_page_info *page_info, } static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc, - netdev_features_t feat) + netdev_features_t feat, u32 idx) { struct gve_rx_slot_page_info *page_info; struct gve_priv *priv = rx->gve; @@ -282,14 +282,12 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc, struct sk_buff *skb; int pagecount; u16 len; - u32 idx; /* drop this packet */ if (unlikely(rx_desc->flags_seq & GVE_RXF_ERR)) return true; len = be16_to_cpu(rx_desc->len) - GVE_RX_PAD; - idx = rx->data.cnt & rx->data.mask; page_info = &rx->data.page_info[idx]; /* gvnic can only receive into registered segments. If the buffer @@ -340,8 +338,6 @@ have_skb: if (!skb) return true; - rx->data.cnt++; - if (likely(feat & NETIF_F_RXCSUM)) { /* NIC passes up the partial sum */ if (rx_desc->csum) @@ -370,7 +366,7 @@ static bool gve_rx_work_pending(struct gve_rx_ring *rx) __be16 flags_seq; u32 next_idx; - next_idx = rx->desc.cnt & rx->desc.mask; + next_idx = rx->cnt & rx->mask; desc = rx->desc.desc_ring + next_idx; flags_seq = desc->flags_seq; @@ -385,8 +381,8 @@ bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget, { struct gve_priv *priv = rx->gve; struct gve_rx_desc *desc; - u32 cnt = rx->desc.cnt; - u32 idx = cnt & rx->desc.mask; + u32 cnt = rx->cnt; + u32 idx = cnt & rx->mask; u32 work_done = 0; u64 bytes = 0; @@ -401,10 +397,10 @@ bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget, rx->q_num, GVE_SEQNO(desc->flags_seq), rx->desc.seqno); bytes += be16_to_cpu(desc->len) - GVE_RX_PAD; - if (!gve_rx(rx, desc, feat)) + if (!gve_rx(rx, desc, feat, idx)) gve_schedule_reset(priv); cnt++; - idx = cnt & rx->desc.mask; + idx = cnt & rx->mask; desc = rx->desc.desc_ring + idx; rx->desc.seqno = gve_next_seqno(rx->desc.seqno); work_done++; @@ -417,8 +413,8 @@ bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget, rx->rpackets += work_done; rx->rbytes += bytes; u64_stats_update_end(&rx->statss); - rx->desc.cnt = cnt; - rx->desc.fill_cnt += work_done; + rx->cnt = cnt; + rx->fill_cnt += work_done; /* restock desc ring slots */ dma_wmb(); /* Ensure descs are visible before ringing doorbell */ -- cgit v1.2.3-59-g8ed1b From d934423ac26ed373dfe089734d505dca5ff679b6 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard (Rtp)" Date: Fri, 2 Aug 2019 10:32:40 +0200 Subject: drivers/net/ethernet/marvell/mvmdio.c: Fix non OF case Orion5.x systems are still using machine files and not device-tree. Commit 96cb4342382290c9 ("net: mvmdio: allow up to three clocks to be specified for orion-mdio") has replaced devm_clk_get() with of_clk_get(), leading to a oops at boot and not working network, as reported in https://lists.debian.org/debian-arm/2019/07/msg00088.html and possibly in https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=908712. Link: https://lists.debian.org/debian-arm/2019/07/msg00088.html Fixes: 96cb4342382290c9 ("net: mvmdio: allow up to three clocks to be specified for orion-mdio") Signed-off-by: Arnaud Patard Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index f660cc2b8258..0b9e851f3da4 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -319,20 +319,33 @@ static int orion_mdio_probe(struct platform_device *pdev) init_waitqueue_head(&dev->smi_busy_wait); - for (i = 0; i < ARRAY_SIZE(dev->clk); i++) { - dev->clk[i] = of_clk_get(pdev->dev.of_node, i); - if (PTR_ERR(dev->clk[i]) == -EPROBE_DEFER) { + if (pdev->dev.of_node) { + for (i = 0; i < ARRAY_SIZE(dev->clk); i++) { + dev->clk[i] = of_clk_get(pdev->dev.of_node, i); + if (PTR_ERR(dev->clk[i]) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto out_clk; + } + if (IS_ERR(dev->clk[i])) + break; + clk_prepare_enable(dev->clk[i]); + } + + if (!IS_ERR(of_clk_get(pdev->dev.of_node, + ARRAY_SIZE(dev->clk)))) + dev_warn(&pdev->dev, + "unsupported number of clocks, limiting to the first " + __stringify(ARRAY_SIZE(dev->clk)) "\n"); + } else { + dev->clk[0] = clk_get(&pdev->dev, NULL); + if (PTR_ERR(dev->clk[0]) == -EPROBE_DEFER) { ret = -EPROBE_DEFER; goto out_clk; } - if (IS_ERR(dev->clk[i])) - break; - clk_prepare_enable(dev->clk[i]); + if (!IS_ERR(dev->clk[0])) + clk_prepare_enable(dev->clk[0]); } - if (!IS_ERR(of_clk_get(pdev->dev.of_node, ARRAY_SIZE(dev->clk)))) - dev_warn(&pdev->dev, "unsupported number of clocks, limiting to the first " - __stringify(ARRAY_SIZE(dev->clk)) "\n"); dev->err_interrupt = platform_get_irq(pdev, 0); if (dev->err_interrupt > 0 && -- cgit v1.2.3-59-g8ed1b From 5c4e2e1af345426f63410a50e2a678673574aa02 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 6 Aug 2019 15:35:39 +0800 Subject: net: ethernet: sun4i-emac: Support phy-handle property for finding PHYs The sun4i-emac uses the "phy" property to find the PHY it's supposed to use. This property was deprecated in favor of "phy-handle" in commit 8c5b09447625 ("dt-bindings: net: sun4i-emac: Convert the binding to a schemas"). Add support for this new property name, and fall back to the old one in case the device tree hasn't been updated. Signed-off-by: Chen-Yu Tsai Signed-off-by: David S. Miller --- drivers/net/ethernet/allwinner/sun4i-emac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c index 3434730a7699..0537df06a9b5 100644 --- a/drivers/net/ethernet/allwinner/sun4i-emac.c +++ b/drivers/net/ethernet/allwinner/sun4i-emac.c @@ -860,7 +860,9 @@ static int emac_probe(struct platform_device *pdev) goto out_clk_disable_unprepare; } - db->phy_node = of_parse_phandle(np, "phy", 0); + db->phy_node = of_parse_phandle(np, "phy-handle", 0); + if (!db->phy_node) + db->phy_node = of_parse_phandle(np, "phy", 0); if (!db->phy_node) { dev_err(&pdev->dev, "no associated PHY\n"); ret = -ENODEV; -- cgit v1.2.3-59-g8ed1b From debea2cd3193ac868289e8893c3a719c265b0612 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 6 Aug 2019 10:55:12 +0200 Subject: net: cxgb3_main: Fix a resource leak in a error path in 'init_one()' A call to 'kfree_skb()' is missing in the error handling path of 'init_one()'. This is already present in 'remove_one()' but is missing here. Signed-off-by: Christophe JAILLET Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index 1e82b9efe447..58f89f6a040f 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -3269,7 +3269,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!adapter->regs) { dev_err(&pdev->dev, "cannot map device registers\n"); err = -ENOMEM; - goto out_free_adapter; + goto out_free_adapter_nofail; } adapter->pdev = pdev; @@ -3397,6 +3397,9 @@ out_free_dev: if (adapter->port[i]) free_netdev(adapter->port[i]); +out_free_adapter_nofail: + kfree_skb(adapter->nofail_skb); + out_free_adapter: kfree(adapter); -- cgit v1.2.3-59-g8ed1b From d0d006a43e9a7a796f6f178839c92fcc222c564d Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Tue, 6 Aug 2019 12:51:11 +0200 Subject: be2net: disable bh with spin_lock in be_process_mcc be_process_mcc() is invoked in 3 different places and always with BHs disabled except the be_poll function but since it's invoked from softirq with BHs disabled it won't hurt. v1->v2: added explanation to the patch v2->v3: add a missing call from be_cmds.c Signed-off-by: Denis Kirjanov Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 6 ++---- drivers/net/ethernet/emulex/benet/be_main.c | 2 -- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index ef5d61d57597..323976c811e9 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -550,7 +550,7 @@ int be_process_mcc(struct be_adapter *adapter) int num = 0, status = 0; struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; - spin_lock(&adapter->mcc_cq_lock); + spin_lock_bh(&adapter->mcc_cq_lock); while ((compl = be_mcc_compl_get(adapter))) { if (compl->flags & CQE_FLAGS_ASYNC_MASK) { @@ -566,7 +566,7 @@ int be_process_mcc(struct be_adapter *adapter) if (num) be_cq_notify(adapter, mcc_obj->cq.id, mcc_obj->rearm_cq, num); - spin_unlock(&adapter->mcc_cq_lock); + spin_unlock_bh(&adapter->mcc_cq_lock); return status; } @@ -581,9 +581,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) if (be_check_error(adapter, BE_ERROR_ANY)) return -EIO; - local_bh_disable(); status = be_process_mcc(adapter); - local_bh_enable(); if (atomic_read(&mcc_obj->q.used) == 0) break; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 2edb86ec9fe9..4d8e40ac66d2 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -5630,9 +5630,7 @@ static void be_worker(struct work_struct *work) * mcc completions */ if (!netif_running(adapter->netdev)) { - local_bh_disable(); be_process_mcc(adapter); - local_bh_enable(); goto reschedule; } -- cgit v1.2.3-59-g8ed1b From 0efedbf11f07adee555e0c4ba9c6eb58760aa94f Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Tue, 6 Aug 2019 15:16:16 +0200 Subject: net: stmmac: xgmac: Fix XGMAC selftests Fixup the XGMAC selftests by correctly finishing the implementation of set_filter callback. Result: $ ethtool -t enp4s0 The test result is PASS The test extra info: 1. MAC Loopback 0 2. PHY Loopback -95 3. MMC Counters -95 4. EEE -95 5. Hash Filter MC 0 6. Perfect Filter UC 0 7. MC Filter 0 8. UC Filter 0 9. Flow Control 0 Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h | 7 +- .../net/ethernet/stmicro/stmmac/dwxgmac2_core.c | 83 +++++++++++++++++++--- 2 files changed, 79 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h index 7f86dffb264d..3174b701aa90 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h @@ -44,11 +44,13 @@ #define XGMAC_CORE_INIT_RX 0 #define XGMAC_PACKET_FILTER 0x00000008 #define XGMAC_FILTER_RA BIT(31) +#define XGMAC_FILTER_HPF BIT(10) #define XGMAC_FILTER_PCF BIT(7) #define XGMAC_FILTER_PM BIT(4) #define XGMAC_FILTER_HMC BIT(2) #define XGMAC_FILTER_PR BIT(0) #define XGMAC_HASH_TABLE(x) (0x00000010 + (x) * 4) +#define XGMAC_MAX_HASH_TABLE 8 #define XGMAC_RXQ_CTRL0 0x000000a0 #define XGMAC_RXQEN(x) GENMASK((x) * 2 + 1, (x) * 2) #define XGMAC_RXQEN_SHIFT(x) ((x) * 2) @@ -99,11 +101,12 @@ #define XGMAC_MDIO_ADDR 0x00000200 #define XGMAC_MDIO_DATA 0x00000204 #define XGMAC_MDIO_C22P 0x00000220 -#define XGMAC_ADDR0_HIGH 0x00000300 +#define XGMAC_ADDRx_HIGH(x) (0x00000300 + (x) * 0x8) +#define XGMAC_ADDR_MAX 32 #define XGMAC_AE BIT(31) #define XGMAC_DCS GENMASK(19, 16) #define XGMAC_DCS_SHIFT 16 -#define XGMAC_ADDR0_LOW 0x00000304 +#define XGMAC_ADDRx_LOW(x) (0x00000304 + (x) * 0x8) #define XGMAC_ARP_ADDR 0x00000c10 #define XGMAC_TIMESTAMP_STATUS 0x00000d20 #define XGMAC_TXTSC BIT(15) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 0a32c96a7854..03a6a59650ca 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -4,6 +4,8 @@ * stmmac XGMAC support. */ +#include +#include #include "stmmac.h" #include "dwxgmac2.h" @@ -278,10 +280,10 @@ static void dwxgmac2_set_umac_addr(struct mac_device_info *hw, u32 value; value = (addr[5] << 8) | addr[4]; - writel(value | XGMAC_AE, ioaddr + XGMAC_ADDR0_HIGH); + writel(value | XGMAC_AE, ioaddr + XGMAC_ADDRx_HIGH(reg_n)); value = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; - writel(value, ioaddr + XGMAC_ADDR0_LOW); + writel(value, ioaddr + XGMAC_ADDRx_LOW(reg_n)); } static void dwxgmac2_get_umac_addr(struct mac_device_info *hw, @@ -291,8 +293,8 @@ static void dwxgmac2_get_umac_addr(struct mac_device_info *hw, u32 hi_addr, lo_addr; /* Read the MAC address from the hardware */ - hi_addr = readl(ioaddr + XGMAC_ADDR0_HIGH); - lo_addr = readl(ioaddr + XGMAC_ADDR0_LOW); + hi_addr = readl(ioaddr + XGMAC_ADDRx_HIGH(reg_n)); + lo_addr = readl(ioaddr + XGMAC_ADDRx_LOW(reg_n)); /* Extract the MAC address from the high and low words */ addr[0] = lo_addr & 0xff; @@ -303,19 +305,82 @@ static void dwxgmac2_get_umac_addr(struct mac_device_info *hw, addr[5] = (hi_addr >> 8) & 0xff; } +static void dwxgmac2_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits, + int mcbitslog2) +{ + int numhashregs, regs; + + switch (mcbitslog2) { + case 6: + numhashregs = 2; + break; + case 7: + numhashregs = 4; + break; + case 8: + numhashregs = 8; + break; + default: + return; + } + + for (regs = 0; regs < numhashregs; regs++) + writel(mcfilterbits[regs], ioaddr + XGMAC_HASH_TABLE(regs)); +} + static void dwxgmac2_set_filter(struct mac_device_info *hw, struct net_device *dev) { void __iomem *ioaddr = (void __iomem *)dev->base_addr; - u32 value = XGMAC_FILTER_RA; + u32 value = readl(ioaddr + XGMAC_PACKET_FILTER); + int mcbitslog2 = hw->mcast_bits_log2; + u32 mc_filter[8]; + int i; + + value &= ~(XGMAC_FILTER_PR | XGMAC_FILTER_HMC | XGMAC_FILTER_PM); + value |= XGMAC_FILTER_HPF; + + memset(mc_filter, 0, sizeof(mc_filter)); if (dev->flags & IFF_PROMISC) { - value |= XGMAC_FILTER_PR | XGMAC_FILTER_PCF; + value |= XGMAC_FILTER_PR; + value |= XGMAC_FILTER_PCF; } else if ((dev->flags & IFF_ALLMULTI) || - (netdev_mc_count(dev) > HASH_TABLE_SIZE)) { + (netdev_mc_count(dev) > hw->multicast_filter_bins)) { value |= XGMAC_FILTER_PM; - writel(~0x0, ioaddr + XGMAC_HASH_TABLE(0)); - writel(~0x0, ioaddr + XGMAC_HASH_TABLE(1)); + + for (i = 0; i < XGMAC_MAX_HASH_TABLE; i++) + writel(~0x0, ioaddr + XGMAC_HASH_TABLE(i)); + } else if (!netdev_mc_empty(dev)) { + struct netdev_hw_addr *ha; + + value |= XGMAC_FILTER_HMC; + + netdev_for_each_mc_addr(ha, dev) { + int nr = (bitrev32(~crc32_le(~0, ha->addr, 6)) >> + (32 - mcbitslog2)); + mc_filter[nr >> 5] |= (1 << (nr & 0x1F)); + } + } + + dwxgmac2_set_mchash(ioaddr, mc_filter, mcbitslog2); + + /* Handle multiple unicast addresses */ + if (netdev_uc_count(dev) > XGMAC_ADDR_MAX) { + value |= XGMAC_FILTER_PR; + } else { + struct netdev_hw_addr *ha; + int reg = 1; + + netdev_for_each_uc_addr(ha, dev) { + dwxgmac2_set_umac_addr(hw, ha->addr, reg); + reg++; + } + + for ( ; reg < XGMAC_ADDR_MAX; reg++) { + writel(0, ioaddr + XGMAC_ADDRx_HIGH(reg)); + writel(0, ioaddr + XGMAC_ADDRx_LOW(reg)); + } } writel(value, ioaddr + XGMAC_PACKET_FILTER); -- cgit v1.2.3-59-g8ed1b From e8df7e8c233a18d2704e37ecff47583b494789d3 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Tue, 6 Aug 2019 15:16:17 +0200 Subject: net: stmmac: Fix issues when number of Queues >= 4 When queues >= 4 we use different registers but we were not subtracting the offset of 4. Fix this. Found out by Coverity. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 4 ++++ drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 01c2e2d83e76..fc9954e4a772 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -85,6 +85,8 @@ static void dwmac4_rx_queue_priority(struct mac_device_info *hw, u32 value; base_register = (queue < 4) ? GMAC_RXQ_CTRL2 : GMAC_RXQ_CTRL3; + if (queue >= 4) + queue -= 4; value = readl(ioaddr + base_register); @@ -102,6 +104,8 @@ static void dwmac4_tx_queue_priority(struct mac_device_info *hw, u32 value; base_register = (queue < 4) ? GMAC_TXQ_PRTY_MAP0 : GMAC_TXQ_PRTY_MAP1; + if (queue >= 4) + queue -= 4; value = readl(ioaddr + base_register); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 03a6a59650ca..85c68b7ee8c6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -108,6 +108,8 @@ static void dwxgmac2_rx_queue_prio(struct mac_device_info *hw, u32 prio, u32 value, reg; reg = (queue < 4) ? XGMAC_RXQ_CTRL2 : XGMAC_RXQ_CTRL3; + if (queue >= 4) + queue -= 4; value = readl(ioaddr + reg); value &= ~XGMAC_PSRQ(queue); @@ -171,6 +173,8 @@ static void dwxgmac2_map_mtl_to_dma(struct mac_device_info *hw, u32 queue, u32 value, reg; reg = (queue < 4) ? XGMAC_MTL_RXQ_DMA_MAP0 : XGMAC_MTL_RXQ_DMA_MAP1; + if (queue >= 4) + queue -= 4; value = readl(ioaddr + reg); value &= ~XGMAC_QxMDMACH(queue); -- cgit v1.2.3-59-g8ed1b From 4a6a1385a4db5f42258a40fcd497cbfd22075968 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Tue, 6 Aug 2019 15:16:18 +0200 Subject: net: stmmac: tc: Do not return a fragment entry Do not try to return a fragment entry from TC list. Otherwise we may not clean properly allocated entries. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 58ea18af9813..37c0bc699cd9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -37,7 +37,7 @@ static struct stmmac_tc_entry *tc_find_entry(struct stmmac_priv *priv, entry = &priv->tc_entries[i]; if (!entry->in_use && !first && free) first = entry; - if (entry->handle == loc && !free) + if ((entry->handle == loc) && !free && !entry->is_frag) dup = entry; } -- cgit v1.2.3-59-g8ed1b From 1a2c070ae805910a853b4a14818481ed2e17c727 Mon Sep 17 00:00:00 2001 From: Jiangfeng Xiao Date: Sat, 3 Aug 2019 20:31:39 +0800 Subject: net: hisilicon: make hip04_tx_reclaim non-reentrant If hip04_tx_reclaim is interrupted while it is running and then __napi_schedule continues to execute hip04_rx_poll->hip04_tx_reclaim, reentrancy occurs and oops is generated. So you need to mask the interrupt during the hip04_tx_reclaim run. The kernel oops exception stack is as follows: Unable to handle kernel NULL pointer dereference at virtual address 00000050 pgd = c0003000 [00000050] *pgd=80000000a04003, *pmd=00000000 Internal error: Oops: 206 [#1] SMP ARM Modules linked in: hip04_eth mtdblock mtd_blkdevs mtd ohci_platform ehci_platform ohci_hcd ehci_hcd vfat fat sd_mod usb_storage scsi_mod usbcore usb_common CPU: 0 PID: 0 Comm: swapper/0 Tainted: G O 4.4.185 #1 Hardware name: Hisilicon A15 task: c0a250e0 task.stack: c0a00000 PC is at hip04_tx_reclaim+0xe0/0x17c [hip04_eth] LR is at hip04_tx_reclaim+0x30/0x17c [hip04_eth] pc : [] lr : [] psr: 600e0313 sp : c0a01d88 ip : 00000000 fp : c0601f9c r10: 00000000 r9 : c3482380 r8 : 00000001 r7 : 00000000 r6 : 000000e1 r5 : c3482000 r4 : 0000000c r3 : f2209800 r2 : 00000000 r1 : 00000000 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 32c5387d Table: 03d28c80 DAC: 55555555 Process swapper/0 (pid: 0, stack limit = 0xc0a00190) Stack: (0xc0a01d88 to 0xc0a02000) [] (hip04_tx_reclaim [hip04_eth]) from [] (hip04_rx_poll+0x88/0x368 [hip04_eth]) [] (hip04_rx_poll [hip04_eth]) from [] (net_rx_action+0x114/0x34c) [] (net_rx_action) from [] (__do_softirq+0x218/0x318) [] (__do_softirq) from [] (irq_exit+0x88/0xac) [] (irq_exit) from [] (msa_irq_exit+0x11c/0x1d4) [] (msa_irq_exit) from [] (__handle_domain_irq+0x110/0x148) [] (__handle_domain_irq) from [] (gic_handle_irq+0xd4/0x118) [] (gic_handle_irq) from [] (__irq_svc+0x40/0x58) Exception stack(0xc0a01f30 to 0xc0a01f78) 1f20: c0ae8b40 00000000 00000000 00000000 1f40: 00000002 ffffe000 c0601f9c 00000000 ffffffff c0a2257c c0a22440 c0831a38 1f60: c0a01ec4 c0a01f80 c0203714 c0203718 600e0213 ffffffff [] (__irq_svc) from [] (arch_cpu_idle+0x20/0x3c) [] (arch_cpu_idle) from [] (cpu_startup_entry+0x244/0x29c) [] (cpu_startup_entry) from [] (rest_init+0xc8/0x10c) [] (rest_init) from [] (start_kernel+0x468/0x514) Code: a40599e5 016086e2 018088e2 7660efe6 (503090e5) ---[ end trace 1db21d6d09c49d74 ]--- Kernel panic - not syncing: Fatal exception in interrupt CPU3: stopping CPU: 3 PID: 0 Comm: swapper/3 Tainted: G D O 4.4.185 #1 Signed-off-by: Jiangfeng Xiao Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hip04_eth.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index d60452845539..1e1b154ed2ec 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -585,6 +585,9 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget) u16 len; u32 err; + /* clean up tx descriptors */ + tx_remaining = hip04_tx_reclaim(ndev, false); + while (cnt && !last) { buf = priv->rx_buf[priv->rx_head]; skb = build_skb(buf, priv->rx_buf_size); @@ -645,8 +648,7 @@ refill: } napi_complete_done(napi, rx); done: - /* clean up tx descriptors and start a new timer if necessary */ - tx_remaining = hip04_tx_reclaim(ndev, false); + /* start a new timer if necessary */ if (rx < budget && tx_remaining) hip04_start_tx_timer(priv); -- cgit v1.2.3-59-g8ed1b From f2243b82785942be519016067ee6c55a063bbfe2 Mon Sep 17 00:00:00 2001 From: Jiangfeng Xiao Date: Sat, 3 Aug 2019 20:31:40 +0800 Subject: net: hisilicon: fix hip04-xmit never return TX_BUSY TX_DESC_NUM is 256, in tx_count, the maximum value of mod(TX_DESC_NUM - 1) is 254, the variable "count" in the hip04_mac_start_xmit function is never equal to (TX_DESC_NUM - 1), so hip04_mac_start_xmit never return NETDEV_TX_BUSY. tx_count is modified to mod(TX_DESC_NUM) so that the maximum value of tx_count can reach (TX_DESC_NUM - 1), then hip04_mac_start_xmit can reurn NETDEV_TX_BUSY. Signed-off-by: Jiangfeng Xiao Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hip04_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index 1e1b154ed2ec..d775b980f1bb 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -248,7 +248,7 @@ struct hip04_priv { static inline unsigned int tx_count(unsigned int head, unsigned int tail) { - return (head - tail) % (TX_DESC_NUM - 1); + return (head - tail) % TX_DESC_NUM; } static void hip04_config_port(struct net_device *ndev, u32 speed, u32 duplex) -- cgit v1.2.3-59-g8ed1b From 96a50c0d907ac8f5c3d6b051031a19eb8a2b53e3 Mon Sep 17 00:00:00 2001 From: Jiangfeng Xiao Date: Sat, 3 Aug 2019 20:31:41 +0800 Subject: net: hisilicon: Fix dma_map_single failed on arm64 On the arm64 platform, executing "ifconfig eth0 up" will fail, returning "ifconfig: SIOCSIFFLAGS: Input/output error." ndev->dev is not initialized, dma_map_single->get_dma_ops-> dummy_dma_ops->__dummy_map_page will return DMA_ERROR_CODE directly, so when we use dma_map_single, the first parameter is to use the device of platform_device. Signed-off-by: Jiangfeng Xiao Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hip04_eth.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index d775b980f1bb..c84167447abe 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -220,6 +220,7 @@ struct hip04_priv { unsigned int reg_inten; struct napi_struct napi; + struct device *dev; struct net_device *ndev; struct tx_desc *tx_desc; @@ -465,7 +466,7 @@ static int hip04_tx_reclaim(struct net_device *ndev, bool force) } if (priv->tx_phys[tx_tail]) { - dma_unmap_single(&ndev->dev, priv->tx_phys[tx_tail], + dma_unmap_single(priv->dev, priv->tx_phys[tx_tail], priv->tx_skb[tx_tail]->len, DMA_TO_DEVICE); priv->tx_phys[tx_tail] = 0; @@ -516,8 +517,8 @@ hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NETDEV_TX_BUSY; } - phys = dma_map_single(&ndev->dev, skb->data, skb->len, DMA_TO_DEVICE); - if (dma_mapping_error(&ndev->dev, phys)) { + phys = dma_map_single(priv->dev, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(priv->dev, phys)) { dev_kfree_skb(skb); return NETDEV_TX_OK; } @@ -596,7 +597,7 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget) goto refill; } - dma_unmap_single(&ndev->dev, priv->rx_phys[priv->rx_head], + dma_unmap_single(priv->dev, priv->rx_phys[priv->rx_head], RX_BUF_SIZE, DMA_FROM_DEVICE); priv->rx_phys[priv->rx_head] = 0; @@ -625,9 +626,9 @@ refill: buf = netdev_alloc_frag(priv->rx_buf_size); if (!buf) goto done; - phys = dma_map_single(&ndev->dev, buf, + phys = dma_map_single(priv->dev, buf, RX_BUF_SIZE, DMA_FROM_DEVICE); - if (dma_mapping_error(&ndev->dev, phys)) + if (dma_mapping_error(priv->dev, phys)) goto done; priv->rx_buf[priv->rx_head] = buf; priv->rx_phys[priv->rx_head] = phys; @@ -730,9 +731,9 @@ static int hip04_mac_open(struct net_device *ndev) for (i = 0; i < RX_DESC_NUM; i++) { dma_addr_t phys; - phys = dma_map_single(&ndev->dev, priv->rx_buf[i], + phys = dma_map_single(priv->dev, priv->rx_buf[i], RX_BUF_SIZE, DMA_FROM_DEVICE); - if (dma_mapping_error(&ndev->dev, phys)) + if (dma_mapping_error(priv->dev, phys)) return -EIO; priv->rx_phys[i] = phys; @@ -766,7 +767,7 @@ static int hip04_mac_stop(struct net_device *ndev) for (i = 0; i < RX_DESC_NUM; i++) { if (priv->rx_phys[i]) { - dma_unmap_single(&ndev->dev, priv->rx_phys[i], + dma_unmap_single(priv->dev, priv->rx_phys[i], RX_BUF_SIZE, DMA_FROM_DEVICE); priv->rx_phys[i] = 0; } @@ -909,6 +910,7 @@ static int hip04_mac_probe(struct platform_device *pdev) return -ENOMEM; priv = netdev_priv(ndev); + priv->dev = d; priv->ndev = ndev; platform_set_drvdata(pdev, ndev); SET_NETDEV_DEV(ndev, &pdev->dev); -- cgit v1.2.3-59-g8ed1b From f26e0cca14c9494c863d8fa6825b10bd12dc9eaa Mon Sep 17 00:00:00 2001 From: Nishka Dasgupta Date: Sun, 4 Aug 2019 21:00:18 +0530 Subject: net: dsa: qca8k: Add of_node_put() in qca8k_setup_mdio_bus() Each iteration of for_each_available_child_of_node() puts the previous node, but in the case of a return from the middle of the loop, there is no put, thus causing a memory leak. Hence add an of_node_put() before the return. Additionally, the local variable ports in the function qca8k_setup_mdio_bus() takes the return value of of_get_child_by_name(), which gets a node but does not put it. If the function returns without putting ports, it may cause a memory leak. Hence put ports before the mid-loop return statement, and also outside the loop after its last usage in this function. Issues found with Coccinelle. Signed-off-by: Nishka Dasgupta Signed-off-by: David S. Miller --- drivers/net/dsa/qca8k.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index e429e92dedf4..16f15c93a102 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -583,8 +583,11 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv) for_each_available_child_of_node(ports, port) { err = of_property_read_u32(port, "reg", ®); - if (err) + if (err) { + of_node_put(port); + of_node_put(ports); return err; + } if (!dsa_is_user_port(priv->ds, reg)) continue; @@ -595,6 +598,7 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv) internal_mdio_mask |= BIT(reg); } + of_node_put(ports); if (!external_mdio_mask && !internal_mdio_mask) { dev_err(priv->dev, "no PHYs are defined.\n"); return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 6d7c7d948a2e9f87b4e7726dee94c59300e1786b Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 5 Aug 2019 01:38:44 +0300 Subject: net: dsa: sja1105: Fix broken learning with vlan_filtering disabled When put under a bridge with vlan_filtering 0, the SJA1105 ports will flood all traffic as if learning was broken. This is because learning interferes with the rx_vid's configured by dsa_8021q as unique pvid's. So learning technically still *does* work, it's just that the learnt entries never get matched due to their unique VLAN ID. The setting that saves the day is Shared VLAN Learning, which on this switch family works exactly as desired: VLAN tagging still works (untagged traffic gets the correct pvid) and FDB entries are still populated with the correct contents including VID. Also, a frame cannot violate the forwarding domain restrictions enforced by its classified VLAN. It is just that the VID is ignored when looking up the FDB for taking a forwarding decision (selecting the egress port). This patch activates SVL, and the result is that frames with a learnt DMAC are no longer flooded in the scenario described above. Now exactly *because* SVL works as desired, we have to revisit some earlier patches: - It is no longer necessary to manipulate the VID of the 'bridge fdb {add,del}' command when vlan_filtering is off. This is because now, SVL is enabled for that case, so the actual VID does not matter*. - It is still desirable to hide dsa_8021q VID's in the FDB dump callback. But right now the dump callback should no longer hide duplicates (one per each front panel port's pvid, plus one for the VLAN that the CPU port is going to tag a TX frame with), because there shouldn't be any (the switch will match a single FDB entry no matter its VID anyway). * Not really... It's no longer necessary to transform a 'bridge fdb add' into 5 fdb add operations, but the user might still add a fdb entry with any vid, and all of them would appear as duplicates in 'bridge fdb show'. So force a 'bridge fdb add' to insert the VID of 0**, so that we can prune the duplicates at insertion time. ** The VID of 0 is better than 1 because it is always guaranteed to be in the ports' hardware filter. DSA also avoids putting the VID inside the netlink response message towards the bridge driver when we return this particular VID, which makes it suitable for FDB entries learnt with vlan_filtering off. Fixes: 227d07a07ef1 ("net: dsa: sja1105: Add support for traffic through standalone ports") Signed-off-by: Vladimir Oltean Signed-off-by: Georg Waibel Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_main.c | 121 +++++++++++++++------------------ 1 file changed, 55 insertions(+), 66 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 6ed5f1e35789..b6d8ef0ab879 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -218,7 +218,7 @@ static int sja1105_init_l2_lookup_params(struct sja1105_private *priv) /* This selects between Independent VLAN Learning (IVL) and * Shared VLAN Learning (SVL) */ - .shared_learn = false, + .shared_learn = true, /* Don't discard management traffic based on ENFPORT - * we don't perform SMAC port enforcement anyway, so * what we are setting here doesn't matter. @@ -1092,8 +1092,13 @@ int sja1105pqrs_fdb_add(struct dsa_switch *ds, int port, l2_lookup.vlanid = vid; l2_lookup.iotag = SJA1105_S_TAG; l2_lookup.mask_macaddr = GENMASK_ULL(ETH_ALEN * 8 - 1, 0); - l2_lookup.mask_vlanid = VLAN_VID_MASK; - l2_lookup.mask_iotag = BIT(0); + if (dsa_port_is_vlan_filtering(&ds->ports[port])) { + l2_lookup.mask_vlanid = VLAN_VID_MASK; + l2_lookup.mask_iotag = BIT(0); + } else { + l2_lookup.mask_vlanid = 0; + l2_lookup.mask_iotag = 0; + } l2_lookup.destports = BIT(port); rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP, @@ -1150,8 +1155,13 @@ int sja1105pqrs_fdb_del(struct dsa_switch *ds, int port, l2_lookup.vlanid = vid; l2_lookup.iotag = SJA1105_S_TAG; l2_lookup.mask_macaddr = GENMASK_ULL(ETH_ALEN * 8 - 1, 0); - l2_lookup.mask_vlanid = VLAN_VID_MASK; - l2_lookup.mask_iotag = BIT(0); + if (dsa_port_is_vlan_filtering(&ds->ports[port])) { + l2_lookup.mask_vlanid = VLAN_VID_MASK; + l2_lookup.mask_iotag = BIT(0); + } else { + l2_lookup.mask_vlanid = 0; + l2_lookup.mask_iotag = 0; + } l2_lookup.destports = BIT(port); rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP, @@ -1181,60 +1191,31 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid) { struct sja1105_private *priv = ds->priv; - u16 rx_vid, tx_vid; - int rc, i; - if (dsa_port_is_vlan_filtering(&ds->ports[port])) - return priv->info->fdb_add_cmd(ds, port, addr, vid); - - /* Since we make use of VLANs even when the bridge core doesn't tell us - * to, translate these FDB entries into the correct dsa_8021q ones. - * The basic idea (also repeats for removal below) is: - * - Each of the other front-panel ports needs to be able to forward a - * pvid-tagged (aka tagged with their rx_vid) frame that matches this - * DMAC. - * - The CPU port (aka the tx_vid of this port) needs to be able to - * send a frame matching this DMAC to the specified port. - * For a better picture see net/dsa/tag_8021q.c. + /* dsa_8021q is in effect when the bridge's vlan_filtering isn't, + * so the switch still does some VLAN processing internally. + * But Shared VLAN Learning (SVL) is also active, and it will take + * care of autonomous forwarding between the unique pvid's of each + * port. Here we just make sure that users can't add duplicate FDB + * entries when in this mode - the actual VID doesn't matter except + * for what gets printed in 'bridge fdb show'. In the case of zero, + * no VID gets printed at all. */ - for (i = 0; i < SJA1105_NUM_PORTS; i++) { - if (i == port) - continue; - if (i == dsa_upstream_port(priv->ds, port)) - continue; + if (!dsa_port_is_vlan_filtering(&ds->ports[port])) + vid = 0; - rx_vid = dsa_8021q_rx_vid(ds, i); - rc = priv->info->fdb_add_cmd(ds, port, addr, rx_vid); - if (rc < 0) - return rc; - } - tx_vid = dsa_8021q_tx_vid(ds, port); - return priv->info->fdb_add_cmd(ds, port, addr, tx_vid); + return priv->info->fdb_add_cmd(ds, port, addr, vid); } static int sja1105_fdb_del(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid) { struct sja1105_private *priv = ds->priv; - u16 rx_vid, tx_vid; - int rc, i; - if (dsa_port_is_vlan_filtering(&ds->ports[port])) - return priv->info->fdb_del_cmd(ds, port, addr, vid); + if (!dsa_port_is_vlan_filtering(&ds->ports[port])) + vid = 0; - for (i = 0; i < SJA1105_NUM_PORTS; i++) { - if (i == port) - continue; - if (i == dsa_upstream_port(priv->ds, port)) - continue; - - rx_vid = dsa_8021q_rx_vid(ds, i); - rc = priv->info->fdb_del_cmd(ds, port, addr, rx_vid); - if (rc < 0) - return rc; - } - tx_vid = dsa_8021q_tx_vid(ds, port); - return priv->info->fdb_del_cmd(ds, port, addr, tx_vid); + return priv->info->fdb_del_cmd(ds, port, addr, vid); } static int sja1105_fdb_dump(struct dsa_switch *ds, int port, @@ -1288,24 +1269,9 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port, l2_lookup.lockeds = (match >= 0); } - /* We need to hide the dsa_8021q VLANs from the user. This - * basically means hiding the duplicates and only showing - * the pvid that is supposed to be active in standalone and - * non-vlan_filtering modes (aka 1). - * - For statically added FDB entries (bridge fdb add), we - * can convert the TX VID (coming from the CPU port) into the - * pvid and ignore the RX VIDs of the other ports. - * - For dynamically learned FDB entries, a single entry with - * no duplicates is learned - that which has the real port's - * pvid, aka RX VID. - */ - if (!dsa_port_is_vlan_filtering(&ds->ports[port])) { - if (l2_lookup.vlanid == tx_vid || - l2_lookup.vlanid == rx_vid) - l2_lookup.vlanid = 1; - else - continue; - } + /* We need to hide the dsa_8021q VLANs from the user. */ + if (!dsa_port_is_vlan_filtering(&ds->ports[port])) + l2_lookup.vlanid = 0; cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data); } return 0; @@ -1597,6 +1563,7 @@ static int sja1105_vlan_prepare(struct dsa_switch *ds, int port, */ static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) { + struct sja1105_l2_lookup_params_entry *l2_lookup_params; struct sja1105_general_params_entry *general_params; struct sja1105_private *priv = ds->priv; struct sja1105_table *table; @@ -1625,6 +1592,28 @@ static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) general_params->incl_srcpt1 = enabled; general_params->incl_srcpt0 = enabled; + /* VLAN filtering => independent VLAN learning. + * No VLAN filtering => shared VLAN learning. + * + * In shared VLAN learning mode, untagged traffic still gets + * pvid-tagged, and the FDB table gets populated with entries + * containing the "real" (pvid or from VLAN tag) VLAN ID. + * However the switch performs a masked L2 lookup in the FDB, + * effectively only looking up a frame's DMAC (and not VID) for the + * forwarding decision. + * + * This is extremely convenient for us, because in modes with + * vlan_filtering=0, dsa_8021q actually installs unique pvid's into + * each front panel port. This is good for identification but breaks + * learning badly - the VID of the learnt FDB entry is unique, aka + * no frames coming from any other port are going to have it. So + * for forwarding purposes, this is as though learning was broken + * (all frames get flooded). + */ + table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS]; + l2_lookup_params = table->entries; + l2_lookup_params->shared_learn = !enabled; + rc = sja1105_static_config_reload(priv); if (rc) dev_err(ds->dev, "Failed to change VLAN Ethertype\n"); -- cgit v1.2.3-59-g8ed1b From 4b7da3d808f91cdad3e34059cd68ba3dfe4c3695 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 5 Aug 2019 01:38:45 +0300 Subject: net: dsa: sja1105: Use the LOCKEDS bit for SJA1105 E/T as well It looks like the FDB dump taken from first-generation switches also contains information on whether entries are static or not. So use that instead of searching through the driver's tables. Fixes: d763778224ea ("net: dsa: sja1105: Implement is_static for FDB entries on E/T") Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_dynamic_config.c | 14 +++++++++++++- drivers/net/dsa/sja1105/sja1105_main.c | 15 --------------- 2 files changed, 13 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c index 6bfb1696a6f2..9988c9d18567 100644 --- a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c +++ b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c @@ -277,6 +277,18 @@ sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, SJA1105ET_SIZE_L2_LOOKUP_ENTRY, op); } +static size_t sja1105et_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr, + enum packing_op op) +{ + struct sja1105_l2_lookup_entry *entry = entry_ptr; + u8 *cmd = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY; + const int size = SJA1105_SIZE_DYN_CMD; + + sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op); + + return sja1105et_l2_lookup_entry_packing(buf, entry_ptr, op); +} + static void sja1105et_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, enum packing_op op) @@ -477,7 +489,7 @@ sja1105et_general_params_entry_packing(void *buf, void *entry_ptr, /* SJA1105E/T: First generation */ struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = { [BLK_IDX_L2_LOOKUP] = { - .entry_packing = sja1105et_l2_lookup_entry_packing, + .entry_packing = sja1105et_dyn_l2_lookup_entry_packing, .cmd_packing = sja1105et_l2_lookup_cmd_packing, .access = (OP_READ | OP_WRITE | OP_DEL), .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT, diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index b6d8ef0ab879..a573ae136ebd 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1254,21 +1254,6 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port, continue; u64_to_ether_addr(l2_lookup.macaddr, macaddr); - /* On SJA1105 E/T, the switch doesn't implement the LOCKEDS - * bit, so it doesn't tell us whether a FDB entry is static - * or not. - * But, of course, we can find out - we're the ones who added - * it in the first place. - */ - if (priv->info->device_id == SJA1105E_DEVICE_ID || - priv->info->device_id == SJA1105T_DEVICE_ID) { - int match; - - match = sja1105_find_static_fdb_entry(priv, port, - &l2_lookup); - l2_lookup.lockeds = (match >= 0); - } - /* We need to hide the dsa_8021q VLANs from the user. */ if (!dsa_port_is_vlan_filtering(&ds->ports[port])) l2_lookup.vlanid = 0; -- cgit v1.2.3-59-g8ed1b From 6cb0abbdf90c180e1310976c47399f57477e0e53 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 5 Aug 2019 01:38:46 +0300 Subject: net: dsa: sja1105: Really fix panic on unregistering PTP clock The IS_ERR_OR_NULL(priv->clock) check inside sja1105_ptp_clock_unregister() is preventing cancel_delayed_work_sync from actually being run. Additionally, sja1105_ptp_clock_unregister() does not actually get run, when placed in sja1105_remove(). The DSA switch gets torn down, but the sja1105 module does not get unregistered. So sja1105_ptp_clock_unregister needs to be moved to sja1105_teardown, to be symmetrical with sja1105_ptp_clock_register which is called from the DSA sja1105_setup. It is strange to fix a "fixes" patch, but the probe failure can only be seen when the attached PHY does not respond to MDIO (issue which I can't pinpoint the reason to) and it goes away after I power-cycle the board. This time the patch was validated on a failing board, and the kernel panic from the fixed commit's message can no longer be seen. Fixes: 29dd908d355f ("net: dsa: sja1105: Cancel PTP delayed work on unregister") Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_main.c | 4 ++-- drivers/net/dsa/sja1105/sja1105_ptp.c | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index a573ae136ebd..d073baffc20b 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1728,6 +1728,8 @@ static void sja1105_teardown(struct dsa_switch *ds) cancel_work_sync(&priv->tagger_data.rxtstamp_work); skb_queue_purge(&priv->tagger_data.skb_rxtstamp_queue); + sja1105_ptp_clock_unregister(priv); + sja1105_static_config_free(&priv->static_config); } static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot, @@ -2185,9 +2187,7 @@ static int sja1105_remove(struct spi_device *spi) { struct sja1105_private *priv = spi_get_drvdata(spi); - sja1105_ptp_clock_unregister(priv); dsa_unregister_switch(priv->ds); - sja1105_static_config_free(&priv->static_config); return 0; } diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index d19cfdf681af..d8e8dd59f3d1 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -369,16 +369,15 @@ int sja1105_ptp_clock_register(struct sja1105_private *priv) .mult = SJA1105_CC_MULT, }; mutex_init(&priv->ptp_lock); - INIT_DELAYED_WORK(&priv->refresh_work, sja1105_ptp_overflow_check); - - schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL); - priv->ptp_caps = sja1105_ptp_caps; priv->clock = ptp_clock_register(&priv->ptp_caps, ds->dev); if (IS_ERR_OR_NULL(priv->clock)) return PTR_ERR(priv->clock); + INIT_DELAYED_WORK(&priv->refresh_work, sja1105_ptp_overflow_check); + schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL); + return sja1105_ptp_reset(priv); } -- cgit v1.2.3-59-g8ed1b