--- /dev/null
+From b1670b113b0c23315d3fc95af7f119378084459d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Feb 2021 17:14:09 +0200
+Subject: ath11k: fix AP mode for QCA6390
+
+From: Kalle Valo <kvalo@codeaurora.org>
+
+[ Upstream commit 77d7e87128d4dfb400df4208b2812160e999c165 ]
+
+Commit c134d1f8c436 ("ath11k: Handle errors if peer creation fails") completely
+broke AP mode on QCA6390:
+
+kernel: [ 151.230734] ath11k_pci 0000:06:00.0: failed to create peer after vdev start delay: -22
+wpa_supplicant[2307]: Failed to set beacon parameters
+wpa_supplicant[2307]: Interface initialization failed
+wpa_supplicant[2307]: wlan0: interface state UNINITIALIZED->DISABLED
+wpa_supplicant[2307]: wlan0: AP-DISABLED
+wpa_supplicant[2307]: wlan0: Unable to setup interface.
+wpa_supplicant[2307]: Failed to initialize AP interface
+
+This was because commit c134d1f8c436 ("ath11k: Handle errors if peer creation
+fails") added error handling for ath11k_peer_create(), which had been failing
+all along but was unnoticed due to the missing error handling. The actual bug
+was introduced already in commit aa44b2f3ecd4 ("ath11k: start vdev if a bss peer is
+already created").
+
+ath11k_peer_create() was failing because for AP mode the peer is created
+already earlier op_add_interface() and we should skip creation here, but the
+check for modes was wrong. Fixing that makes AP mode work again.
+
+This shouldn't affect IPQ8074 nor QCN9074 as they have hw_params.vdev_start_delay disabled.
+
+Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
+
+Fixes: c134d1f8c436 ("ath11k: Handle errors if peer creation fails")
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Link: https://lore.kernel.org/r/1614006849-25764-1-git-send-email-kvalo@codeaurora.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath11k/mac.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
+index f3c5023f8a45..ee0edd918560 100644
+--- a/drivers/net/wireless/ath/ath11k/mac.c
++++ b/drivers/net/wireless/ath/ath11k/mac.c
+@@ -5262,8 +5262,8 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
+ }
+
+ if (ab->hw_params.vdev_start_delay &&
+- (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
+- arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)) {
++ arvif->vdev_type != WMI_VDEV_TYPE_AP &&
++ arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) {
+ param.vdev_id = arvif->vdev_id;
+ param.peer_type = WMI_PEER_TYPE_DEFAULT;
+ param.peer_addr = ar->mac_addr;
+--
+2.30.1
+
--- /dev/null
+From 0f24b33cc67c55b0f1bc65b8c35475ac6c4e7eb6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Nov 2020 17:59:14 +0200
+Subject: ath11k: peer delete synchronization with firmware
+
+From: Ritesh Singh <ritesi@codeaurora.org>
+
+[ Upstream commit 690ace20ff790f443c3cbaf12e1769e4eb0072db ]
+
+Peer creation in firmware fails, if last peer deletion
+is still in progress.
+Hence, add wait for the event after deleting every peer
+from host driver to synchronize with firmware.
+
+Signed-off-by: Ritesh Singh <ritesi@codeaurora.org>
+Signed-off-by: Maharaja Kennadyrajan <mkenna@codeaurora.org>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Link: https://lore.kernel.org/r/1605514143-17652-3-git-send-email-mkenna@codeaurora.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath11k/core.c | 1 +
+ drivers/net/wireless/ath/ath11k/core.h | 1 +
+ drivers/net/wireless/ath/ath11k/mac.c | 17 +++++++++-
+ drivers/net/wireless/ath/ath11k/peer.c | 44 ++++++++++++++++++++++++--
+ drivers/net/wireless/ath/ath11k/peer.h | 2 ++
+ drivers/net/wireless/ath/ath11k/wmi.c | 17 ++++++++--
+ 6 files changed, 75 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
+index ebd6886a8c18..a68fe3a45a74 100644
+--- a/drivers/net/wireless/ath/ath11k/core.c
++++ b/drivers/net/wireless/ath/ath11k/core.c
+@@ -774,6 +774,7 @@ static void ath11k_core_restart(struct work_struct *work)
+ complete(&ar->scan.started);
+ complete(&ar->scan.completed);
+ complete(&ar->peer_assoc_done);
++ complete(&ar->peer_delete_done);
+ complete(&ar->install_key_done);
+ complete(&ar->vdev_setup_done);
+ complete(&ar->bss_survey_done);
+diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
+index 5a7915f75e1e..c8e36251068c 100644
+--- a/drivers/net/wireless/ath/ath11k/core.h
++++ b/drivers/net/wireless/ath/ath11k/core.h
+@@ -502,6 +502,7 @@ struct ath11k {
+ u8 lmac_id;
+
+ struct completion peer_assoc_done;
++ struct completion peer_delete_done;
+
+ int install_key_status;
+ struct completion install_key_done;
+diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
+index b5bd9b06da89..c8f1b786e746 100644
+--- a/drivers/net/wireless/ath/ath11k/mac.c
++++ b/drivers/net/wireless/ath/ath11k/mac.c
+@@ -4589,8 +4589,22 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
+
+ err_peer_del:
+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
++ reinit_completion(&ar->peer_delete_done);
++
++ ret = ath11k_wmi_send_peer_delete_cmd(ar, vif->addr,
++ arvif->vdev_id);
++ if (ret) {
++ ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
++ arvif->vdev_id, vif->addr);
++ return ret;
++ }
++
++ ret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id,
++ vif->addr);
++ if (ret)
++ return ret;
++
+ ar->num_peers--;
+- ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, arvif->vdev_id);
+ }
+
+ err_vdev_del:
+@@ -6413,6 +6427,7 @@ int ath11k_mac_allocate(struct ath11k_base *ab)
+ mutex_init(&ar->conf_mutex);
+ init_completion(&ar->vdev_setup_done);
+ init_completion(&ar->peer_assoc_done);
++ init_completion(&ar->peer_delete_done);
+ init_completion(&ar->install_key_done);
+ init_completion(&ar->bss_survey_done);
+ init_completion(&ar->scan.started);
+diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c
+index 61ad9300eafb..1866d82678fa 100644
+--- a/drivers/net/wireless/ath/ath11k/peer.c
++++ b/drivers/net/wireless/ath/ath11k/peer.c
+@@ -177,12 +177,36 @@ static int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8
+ return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, false);
+ }
+
++int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id,
++ const u8 *addr)
++{
++ int ret;
++ unsigned long time_left;
++
++ ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr);
++ if (ret) {
++ ath11k_warn(ar->ab, "failed wait for peer deleted");
++ return ret;
++ }
++
++ time_left = wait_for_completion_timeout(&ar->peer_delete_done,
++ 3 * HZ);
++ if (time_left == 0) {
++ ath11k_warn(ar->ab, "Timeout in receiving peer delete response\n");
++ return -ETIMEDOUT;
++ }
++
++ return 0;
++}
++
+ int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
+ {
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
++ reinit_completion(&ar->peer_delete_done);
++
+ ret = ath11k_wmi_send_peer_delete_cmd(ar, addr, vdev_id);
+ if (ret) {
+ ath11k_warn(ar->ab,
+@@ -191,7 +215,7 @@ int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
+ return ret;
+ }
+
+- ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr);
++ ret = ath11k_wait_for_peer_delete_done(ar, vdev_id, addr);
+ if (ret)
+ return ret;
+
+@@ -247,8 +271,22 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
+ spin_unlock_bh(&ar->ab->base_lock);
+ ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n",
+ param->peer_addr, param->vdev_id);
+- ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr,
+- param->vdev_id);
++
++ reinit_completion(&ar->peer_delete_done);
++
++ ret = ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr,
++ param->vdev_id);
++ if (ret) {
++ ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
++ param->vdev_id, param->peer_addr);
++ return ret;
++ }
++
++ ret = ath11k_wait_for_peer_delete_done(ar, param->vdev_id,
++ param->peer_addr);
++ if (ret)
++ return ret;
++
+ return -ENOENT;
+ }
+
+diff --git a/drivers/net/wireless/ath/ath11k/peer.h b/drivers/net/wireless/ath/ath11k/peer.h
+index 5d125ce8984e..bba2e00b6944 100644
+--- a/drivers/net/wireless/ath/ath11k/peer.h
++++ b/drivers/net/wireless/ath/ath11k/peer.h
+@@ -41,5 +41,7 @@ void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id);
+ int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr);
+ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
+ struct ieee80211_sta *sta, struct peer_create_params *param);
++int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id,
++ const u8 *addr);
+
+ #endif /* _PEER_H_ */
+diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
+index 04b8b002edfe..173ab6ceed1f 100644
+--- a/drivers/net/wireless/ath/ath11k/wmi.c
++++ b/drivers/net/wireless/ath/ath11k/wmi.c
+@@ -5532,15 +5532,26 @@ static int ath11k_ready_event(struct ath11k_base *ab, struct sk_buff *skb)
+ static void ath11k_peer_delete_resp_event(struct ath11k_base *ab, struct sk_buff *skb)
+ {
+ struct wmi_peer_delete_resp_event peer_del_resp;
++ struct ath11k *ar;
+
+ if (ath11k_pull_peer_del_resp_ev(ab, skb, &peer_del_resp) != 0) {
+ ath11k_warn(ab, "failed to extract peer delete resp");
+ return;
+ }
+
+- /* TODO: Do we need to validate whether ath11k_peer_find() return NULL
+- * Why this is needed when there is HTT event for peer delete
+- */
++ rcu_read_lock();
++ ar = ath11k_mac_get_ar_by_vdev_id(ab, peer_del_resp.vdev_id);
++ if (!ar) {
++ ath11k_warn(ab, "invalid vdev id in peer delete resp ev %d",
++ peer_del_resp.vdev_id);
++ rcu_read_unlock();
++ return;
++ }
++
++ complete(&ar->peer_delete_done);
++ rcu_read_unlock();
++ ath11k_dbg(ab, ATH11K_DBG_WMI, "peer delete resp for vdev id %d addr %pM\n",
++ peer_del_resp.vdev_id, peer_del_resp.peer_macaddr.addr);
+ }
+
+ static inline const char *ath11k_wmi_vdev_resp_print(u32 vdev_resp_status)
+--
+2.30.1
+
--- /dev/null
+From fa7bf57f7938aea2770df6d7b069b36da3cce238 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 11 Dec 2020 00:13:58 -0500
+Subject: ath11k: start vdev if a bss peer is already created
+
+From: Carl Huang <cjhuang@codeaurora.org>
+
+[ Upstream commit aa44b2f3ecd41f90b7e477158036648a49d21a32 ]
+
+For QCA6390, bss peer must be created before vdev is to start. This
+change is to start vdev if a bss peer is created. Otherwise, ath11k
+delays to start vdev.
+
+This fixes an issue in a case where HT/VHT/HE settings change between
+authentication and association, e.g., due to the user space request
+to disable HT.
+
+Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
+
+Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Link: https://lore.kernel.org/r/20201211051358.9191-1-cjhuang@codeaurora.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath11k/mac.c | 8 ++++++--
+ drivers/net/wireless/ath/ath11k/peer.c | 17 +++++++++++++++++
+ drivers/net/wireless/ath/ath11k/peer.h | 2 ++
+ 3 files changed, 25 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
+index c8f1b786e746..f3c5023f8a45 100644
+--- a/drivers/net/wireless/ath/ath11k/mac.c
++++ b/drivers/net/wireless/ath/ath11k/mac.c
+@@ -2986,6 +2986,7 @@ static int ath11k_mac_station_add(struct ath11k *ar,
+ }
+
+ if (ab->hw_params.vdev_start_delay &&
++ !arvif->is_started &&
+ arvif->vdev_type != WMI_VDEV_TYPE_AP) {
+ ret = ath11k_start_vdev_delay(ar->hw, vif);
+ if (ret) {
+@@ -5248,7 +5249,8 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
+ /* for QCA6390 bss peer must be created before vdev_start */
+ if (ab->hw_params.vdev_start_delay &&
+ arvif->vdev_type != WMI_VDEV_TYPE_AP &&
+- arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) {
++ arvif->vdev_type != WMI_VDEV_TYPE_MONITOR &&
++ !ath11k_peer_find_by_vdev_id(ab, arvif->vdev_id)) {
+ memcpy(&arvif->chanctx, ctx, sizeof(*ctx));
+ ret = 0;
+ goto out;
+@@ -5259,7 +5261,9 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
+ goto out;
+ }
+
+- if (ab->hw_params.vdev_start_delay) {
++ if (ab->hw_params.vdev_start_delay &&
++ (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
++ arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)) {
+ param.vdev_id = arvif->vdev_id;
+ param.peer_type = WMI_PEER_TYPE_DEFAULT;
+ param.peer_addr = ar->mac_addr;
+diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c
+index 1866d82678fa..b69e7ebfa930 100644
+--- a/drivers/net/wireless/ath/ath11k/peer.c
++++ b/drivers/net/wireless/ath/ath11k/peer.c
+@@ -76,6 +76,23 @@ struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab,
+ return NULL;
+ }
+
++struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab,
++ int vdev_id)
++{
++ struct ath11k_peer *peer;
++
++ spin_lock_bh(&ab->base_lock);
++
++ list_for_each_entry(peer, &ab->peers, list) {
++ if (vdev_id == peer->vdev_id) {
++ spin_unlock_bh(&ab->base_lock);
++ return peer;
++ }
++ }
++ spin_unlock_bh(&ab->base_lock);
++ return NULL;
++}
++
+ void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id)
+ {
+ struct ath11k_peer *peer;
+diff --git a/drivers/net/wireless/ath/ath11k/peer.h b/drivers/net/wireless/ath/ath11k/peer.h
+index bba2e00b6944..8553ed061aea 100644
+--- a/drivers/net/wireless/ath/ath11k/peer.h
++++ b/drivers/net/wireless/ath/ath11k/peer.h
+@@ -43,5 +43,7 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
+ struct ieee80211_sta *sta, struct peer_create_params *param);
+ int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id,
+ const u8 *addr);
++struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab,
++ int vdev_id);
+
+ #endif /* _PEER_H_ */
+--
+2.30.1
+
--- /dev/null
+From 46e5105d05a088a29ea70d9ecb80904fdb711c4b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 4 Dec 2020 14:08:00 +0200
+Subject: enetc: Fix unused var build warning for CONFIG_OF
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+[ Upstream commit 4560b2a3ecdd5d587c4c6eea4339899f173a559a ]
+
+When CONFIG_OF is disabled, there is a harmless warning about
+an unused variable:
+
+enetc_pf.c: In function 'enetc_phylink_create':
+enetc_pf.c:981:17: error: unused variable 'dev' [-Werror=unused-variable]
+
+Slightly rearrange the code to pass around the of_node as a
+function argument, which avoids the problem without hurting
+readability.
+
+Fixes: 71b77a7a27a3 ("enetc: Migrate to PHYLINK and PCS_LYNX")
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Link: https://lore.kernel.org/r/20201204120800.17193-1-claudiu.manoil@nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/freescale/enetc/enetc_pf.c | 21 +++++++++----------
+ 1 file changed, 10 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+index b35096455293..f29058dddb36 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -859,13 +859,12 @@ static bool enetc_port_has_pcs(struct enetc_pf *pf)
+ pf->if_mode == PHY_INTERFACE_MODE_USXGMII);
+ }
+
+-static int enetc_mdiobus_create(struct enetc_pf *pf)
++static int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node)
+ {
+- struct device *dev = &pf->si->pdev->dev;
+ struct device_node *mdio_np;
+ int err;
+
+- mdio_np = of_get_child_by_name(dev->of_node, "mdio");
++ mdio_np = of_get_child_by_name(node, "mdio");
+ if (mdio_np) {
+ err = enetc_mdio_probe(pf, mdio_np);
+
+@@ -1009,18 +1008,17 @@ static const struct phylink_mac_ops enetc_mac_phylink_ops = {
+ .mac_link_down = enetc_pl_mac_link_down,
+ };
+
+-static int enetc_phylink_create(struct enetc_ndev_priv *priv)
++static int enetc_phylink_create(struct enetc_ndev_priv *priv,
++ struct device_node *node)
+ {
+ struct enetc_pf *pf = enetc_si_priv(priv->si);
+- struct device *dev = &pf->si->pdev->dev;
+ struct phylink *phylink;
+ int err;
+
+ pf->phylink_config.dev = &priv->ndev->dev;
+ pf->phylink_config.type = PHYLINK_NETDEV;
+
+- phylink = phylink_create(&pf->phylink_config,
+- of_fwnode_handle(dev->of_node),
++ phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node),
+ pf->if_mode, &enetc_mac_phylink_ops);
+ if (IS_ERR(phylink)) {
+ err = PTR_ERR(phylink);
+@@ -1086,13 +1084,14 @@ static int enetc_init_port_rss_memory(struct enetc_si *si)
+ static int enetc_pf_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+ {
++ struct device_node *node = pdev->dev.of_node;
+ struct enetc_ndev_priv *priv;
+ struct net_device *ndev;
+ struct enetc_si *si;
+ struct enetc_pf *pf;
+ int err;
+
+- if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) {
++ if (node && !of_device_is_available(node)) {
+ dev_info(&pdev->dev, "device is disabled, skipping\n");
+ return -ENODEV;
+ }
+@@ -1161,12 +1160,12 @@ static int enetc_pf_probe(struct pci_dev *pdev,
+ goto err_alloc_msix;
+ }
+
+- if (!of_get_phy_mode(pdev->dev.of_node, &pf->if_mode)) {
+- err = enetc_mdiobus_create(pf);
++ if (!of_get_phy_mode(node, &pf->if_mode)) {
++ err = enetc_mdiobus_create(pf, node);
+ if (err)
+ goto err_mdiobus_create;
+
+- err = enetc_phylink_create(priv);
++ err = enetc_phylink_create(priv, node);
+ if (err)
+ goto err_phylink_create;
+ }
+--
+2.30.1
+
--- /dev/null
+From 50eae04e8a832e98e0f281eedc80769c52c8475f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 8 Mar 2021 10:24:47 +0100
+Subject: MIPS: kernel: Reserve exception base early to prevent corruption
+
+From: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+
+[ Upstream commit bd67b711bfaa02cf19e88aa2d9edae5c1c1d2739 ]
+
+BMIPS is one of the few platforms that do change the exception base.
+After commit 2dcb39645441 ("memblock: do not start bottom-up allocations
+with kernel_end") we started seeing BMIPS boards fail to boot with the
+built-in FDT being corrupted.
+
+Before the cited commit, early allocations would be in the [kernel_end,
+RAM_END] range, but after commit they would be within [RAM_START +
+PAGE_SIZE, RAM_END].
+
+The custom exception base handler that is installed by
+bmips_ebase_setup() done for BMIPS5000 CPUs ends-up trampling on the
+memory region allocated by unflatten_and_copy_device_tree() thus
+corrupting the FDT used by the kernel.
+
+To fix this, we need to perform an early reservation of the custom
+exception space. Additional we reserve the first 4k (1k for R3k) for
+either normal exception vector space (legacy CPUs) or special vectors
+like cache exceptions.
+
+Huge thanks to Serge for analysing and proposing a solution to this
+issue.
+
+Fixes: 2dcb39645441 ("memblock: do not start bottom-up allocations with kernel_end")
+Reported-by: Kamal Dasu <kdasu.kdev@gmail.com>
+Debugged-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
+Acked-by: Mike Rapoport <rppt@linux.ibm.com>
+Tested-by: Florian Fainelli <f.fainelli@gmail.com>
+Reviewed-by: Serge Semin <fancer.lancer@gmail.com>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/mips/include/asm/traps.h | 3 +++
+ arch/mips/kernel/cpu-probe.c | 6 ++++++
+ arch/mips/kernel/cpu-r3k-probe.c | 3 +++
+ arch/mips/kernel/traps.c | 10 +++++-----
+ 4 files changed, 17 insertions(+), 5 deletions(-)
+
+diff --git a/arch/mips/include/asm/traps.h b/arch/mips/include/asm/traps.h
+index 6a0864bb604d..9038b91e2d8c 100644
+--- a/arch/mips/include/asm/traps.h
++++ b/arch/mips/include/asm/traps.h
+@@ -24,6 +24,9 @@ extern void (*board_ebase_setup)(void);
+ extern void (*board_cache_error_setup)(void);
+
+ extern int register_nmi_notifier(struct notifier_block *nb);
++extern void reserve_exception_space(phys_addr_t addr, unsigned long size);
++
++#define VECTORSPACING 0x100 /* for EI/VI mode */
+
+ #define nmi_notifier(fn, pri) \
+ ({ \
+diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
+index 31cb9199197c..21794db53c05 100644
+--- a/arch/mips/kernel/cpu-probe.c
++++ b/arch/mips/kernel/cpu-probe.c
+@@ -26,6 +26,7 @@
+ #include <asm/elf.h>
+ #include <asm/pgtable-bits.h>
+ #include <asm/spram.h>
++#include <asm/traps.h>
+ #include <linux/uaccess.h>
+
+ #include "fpu-probe.h"
+@@ -1619,6 +1620,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
+ c->cputype = CPU_BMIPS3300;
+ __cpu_name[cpu] = "Broadcom BMIPS3300";
+ set_elf_platform(cpu, "bmips3300");
++ reserve_exception_space(0x400, VECTORSPACING * 64);
+ break;
+ case PRID_IMP_BMIPS43XX: {
+ int rev = c->processor_id & PRID_REV_MASK;
+@@ -1629,6 +1631,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
+ __cpu_name[cpu] = "Broadcom BMIPS4380";
+ set_elf_platform(cpu, "bmips4380");
+ c->options |= MIPS_CPU_RIXI;
++ reserve_exception_space(0x400, VECTORSPACING * 64);
+ } else {
+ c->cputype = CPU_BMIPS4350;
+ __cpu_name[cpu] = "Broadcom BMIPS4350";
+@@ -1645,6 +1648,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
+ __cpu_name[cpu] = "Broadcom BMIPS5000";
+ set_elf_platform(cpu, "bmips5000");
+ c->options |= MIPS_CPU_ULRI | MIPS_CPU_RIXI;
++ reserve_exception_space(0x1000, VECTORSPACING * 64);
+ break;
+ }
+ }
+@@ -2124,6 +2128,8 @@ void cpu_probe(void)
+ if (cpu == 0)
+ __ua_limit = ~((1ull << cpu_vmbits) - 1);
+ #endif
++
++ reserve_exception_space(0, 0x1000);
+ }
+
+ void cpu_report(void)
+diff --git a/arch/mips/kernel/cpu-r3k-probe.c b/arch/mips/kernel/cpu-r3k-probe.c
+index abdbbe8c5a43..af654771918c 100644
+--- a/arch/mips/kernel/cpu-r3k-probe.c
++++ b/arch/mips/kernel/cpu-r3k-probe.c
+@@ -21,6 +21,7 @@
+ #include <asm/fpu.h>
+ #include <asm/mipsregs.h>
+ #include <asm/elf.h>
++#include <asm/traps.h>
+
+ #include "fpu-probe.h"
+
+@@ -158,6 +159,8 @@ void cpu_probe(void)
+ cpu_set_fpu_opts(c);
+ else
+ cpu_set_nofpu_opts(c);
++
++ reserve_exception_space(0, 0x400);
+ }
+
+ void cpu_report(void)
+diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
+index e0352958e2f7..808b8b61ded1 100644
+--- a/arch/mips/kernel/traps.c
++++ b/arch/mips/kernel/traps.c
+@@ -2009,13 +2009,16 @@ void __noreturn nmi_exception_handler(struct pt_regs *regs)
+ nmi_exit();
+ }
+
+-#define VECTORSPACING 0x100 /* for EI/VI mode */
+-
+ unsigned long ebase;
+ EXPORT_SYMBOL_GPL(ebase);
+ unsigned long exception_handlers[32];
+ unsigned long vi_handlers[64];
+
++void reserve_exception_space(phys_addr_t addr, unsigned long size)
++{
++ memblock_reserve(addr, size);
++}
++
+ void __init *set_except_vector(int n, void *addr)
+ {
+ unsigned long handler = (unsigned long) addr;
+@@ -2367,10 +2370,7 @@ void __init trap_init(void)
+
+ if (!cpu_has_mips_r2_r6) {
+ ebase = CAC_BASE;
+- ebase_pa = virt_to_phys((void *)ebase);
+ vec_size = 0x400;
+-
+- memblock_reserve(ebase_pa, vec_size);
+ } else {
+ if (cpu_has_veic || cpu_has_vint)
+ vec_size = 0x200 + VECTORSPACING*64;
+--
+2.30.1
+
--- /dev/null
+From 7f0929f5432f121f49716d56319a9cc7465269ae Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Nov 2020 21:16:09 +0200
+Subject: net: dsa: implement a central TX reallocation procedure
+
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+[ Upstream commit a3b0b6479700a5b0af2c631cb2ec0fb7a0d978f2 ]
+
+At the moment, taggers are left with the task of ensuring that the skb
+headers are writable (which they aren't, if the frames were cloned for
+TX timestamping, for flooding by the bridge, etc), and that there is
+enough space in the skb data area for the DSA tag to be pushed.
+
+Moreover, the life of tail taggers is even harder, because they need to
+ensure that short frames have enough padding, a problem that normal
+taggers don't have.
+
+The principle of the DSA framework is that everything except for the
+most intimate hardware specifics (like in this case, the actual packing
+of the DSA tag bits) should be done inside the core, to avoid having
+code paths that are very rarely tested.
+
+So provide a TX reallocation procedure that should cover the known needs
+of DSA today.
+
+Note that this patch also gives the network stack a good hint about the
+headroom/tailroom it's going to need. Up till now it wasn't doing that.
+So the reallocation procedure should really be there only for the
+exceptional cases, and for cloned packets which need to be unshared.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Tested-by: Christian Eggers <ceggers@arri.de> # For tail taggers only
+Tested-by: Kurt Kanzenbach <kurt@linutronix.de>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dsa/slave.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 45 insertions(+)
+
+diff --git a/net/dsa/slave.c b/net/dsa/slave.c
+index 3bc5ca40c9fb..c6806eef906f 100644
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -548,6 +548,30 @@ netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev)
+ }
+ EXPORT_SYMBOL_GPL(dsa_enqueue_skb);
+
++static int dsa_realloc_skb(struct sk_buff *skb, struct net_device *dev)
++{
++ int needed_headroom = dev->needed_headroom;
++ int needed_tailroom = dev->needed_tailroom;
++
++ /* For tail taggers, we need to pad short frames ourselves, to ensure
++ * that the tail tag does not fail at its role of being at the end of
++ * the packet, once the master interface pads the frame. Account for
++ * that pad length here, and pad later.
++ */
++ if (unlikely(needed_tailroom && skb->len < ETH_ZLEN))
++ needed_tailroom += ETH_ZLEN - skb->len;
++ /* skb_headroom() returns unsigned int... */
++ needed_headroom = max_t(int, needed_headroom - skb_headroom(skb), 0);
++ needed_tailroom = max_t(int, needed_tailroom - skb_tailroom(skb), 0);
++
++ if (likely(!needed_headroom && !needed_tailroom && !skb_cloned(skb)))
++ /* No reallocation needed, yay! */
++ return 0;
++
++ return pskb_expand_head(skb, needed_headroom, needed_tailroom,
++ GFP_ATOMIC);
++}
++
+ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct dsa_slave_priv *p = netdev_priv(dev);
+@@ -567,6 +591,17 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
+ */
+ dsa_skb_tx_timestamp(p, skb);
+
++ if (dsa_realloc_skb(skb, dev)) {
++ dev_kfree_skb_any(skb);
++ return NETDEV_TX_OK;
++ }
++
++ /* needed_tailroom should still be 'warm' in the cache line from
++ * dsa_realloc_skb(), which has also ensured that padding is safe.
++ */
++ if (dev->needed_tailroom)
++ eth_skb_pad(skb);
++
+ /* Transmit function may have to reallocate the original SKB,
+ * in which case it must have freed it. Only free it here on error.
+ */
+@@ -1791,6 +1826,16 @@ int dsa_slave_create(struct dsa_port *port)
+ slave_dev->netdev_ops = &dsa_slave_netdev_ops;
+ if (ds->ops->port_max_mtu)
+ slave_dev->max_mtu = ds->ops->port_max_mtu(ds, port->index);
++ if (cpu_dp->tag_ops->tail_tag)
++ slave_dev->needed_tailroom = cpu_dp->tag_ops->overhead;
++ else
++ slave_dev->needed_headroom = cpu_dp->tag_ops->overhead;
++ /* Try to save one extra realloc later in the TX path (in the master)
++ * by also inheriting the master's needed headroom and tailroom.
++ * The 8021q driver also does this.
++ */
++ slave_dev->needed_headroom += master->needed_headroom;
++ slave_dev->needed_tailroom += master->needed_tailroom;
+ SET_NETDEV_DEVTYPE(slave_dev, &dsa_type);
+
+ netdev_for_each_tx_queue(slave_dev, dsa_slave_set_lockdep_class_one,
+--
+2.30.1
+
--- /dev/null
+From 1cf4673ba62477fd972a8369f7b126c735916840 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Nov 2020 21:16:20 +0200
+Subject: net: dsa: tag_ar9331: let DSA core deal with TX reallocation
+
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+[ Upstream commit 86c4ad9a7876777c12fd5a7010152e4141fcb94d ]
+
+Now that we have a central TX reallocation procedure that accounts for
+the tagger's needed headroom in a generic way, we can remove the
+skb_cow_head call.
+
+Cc: Per Forlin <per.forlin@axis.com>
+Cc: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Tested-by: Oleksij Rempel <linux@rempel-privat.de>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dsa/tag_ar9331.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/net/dsa/tag_ar9331.c b/net/dsa/tag_ar9331.c
+index 55b00694cdba..002cf7f952e2 100644
+--- a/net/dsa/tag_ar9331.c
++++ b/net/dsa/tag_ar9331.c
+@@ -31,9 +31,6 @@ static struct sk_buff *ar9331_tag_xmit(struct sk_buff *skb,
+ __le16 *phdr;
+ u16 hdr;
+
+- if (skb_cow_head(skb, AR9331_HDR_LEN) < 0)
+- return NULL;
+-
+ phdr = skb_push(skb, AR9331_HDR_LEN);
+
+ hdr = FIELD_PREP(AR9331_HDR_VERSION_MASK, AR9331_HDR_VERSION);
+--
+2.30.1
+
--- /dev/null
+From d48532018497a8df115f2537952b25cb6a8defd1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Nov 2020 21:16:17 +0200
+Subject: net: dsa: tag_brcm: let DSA core deal with TX reallocation
+
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+[ Upstream commit 2f0d030c5ffec6660f79a32b4f522155f75a9d71 ]
+
+Now that we have a central TX reallocation procedure that accounts for
+the tagger's needed headroom in a generic way, we can remove the
+skb_cow_head call.
+
+Cc: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dsa/tag_brcm.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
+index ad72dff8d524..e934dace3922 100644
+--- a/net/dsa/tag_brcm.c
++++ b/net/dsa/tag_brcm.c
+@@ -66,9 +66,6 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,
+ u16 queue = skb_get_queue_mapping(skb);
+ u8 *brcm_tag;
+
+- if (skb_cow_head(skb, BRCM_TAG_LEN) < 0)
+- return NULL;
+-
+ /* The Ethernet switch we are interfaced with needs packets to be at
+ * least 64 bytes (including FCS) otherwise they will be discarded when
+ * they enter the switch port logic. When Broadcom tags are enabled, we
+--
+2.30.1
+
--- /dev/null
+From 3559a2edd20071b42af22d3cda506372e4bfa7c1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Nov 2020 21:16:18 +0200
+Subject: net: dsa: tag_dsa: let DSA core deal with TX reallocation
+
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+[ Upstream commit 952a06345015867e3bd37f8d9045fc1429637d43 ]
+
+Now that we have a central TX reallocation procedure that accounts for
+the tagger's needed headroom in a generic way, we can remove the
+skb_cow_head call.
+
+Similar to the EtherType DSA tagger, the old Marvell tagger can
+transform an 802.1Q header if present into a DSA tag, so there is no
+headroom required in that case. But we are ensuring that it exists,
+regardless (practically speaking, the headroom must be 4 bytes larger
+than it needs to be).
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dsa/tag_dsa.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
+index 0b756fae68a5..63d690a0fca6 100644
+--- a/net/dsa/tag_dsa.c
++++ b/net/dsa/tag_dsa.c
+@@ -23,9 +23,6 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev)
+ * the ethertype field for untagged packets.
+ */
+ if (skb->protocol == htons(ETH_P_8021Q)) {
+- if (skb_cow_head(skb, 0) < 0)
+- return NULL;
+-
+ /*
+ * Construct tagged FROM_CPU DSA tag from 802.1q tag.
+ */
+@@ -41,8 +38,6 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev)
+ dsa_header[2] &= ~0x10;
+ }
+ } else {
+- if (skb_cow_head(skb, DSA_HLEN) < 0)
+- return NULL;
+ skb_push(skb, DSA_HLEN);
+
+ memmove(skb->data, skb->data + DSA_HLEN, 2 * ETH_ALEN);
+--
+2.30.1
+
--- /dev/null
+From d4c3878b0c48f4aa059c239b02198848bf3faa7b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Nov 2020 21:16:16 +0200
+Subject: net: dsa: tag_edsa: let DSA core deal with TX reallocation
+
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+[ Upstream commit c6c4e1237dfe731644e79fa06d073625f28cd945 ]
+
+Now that we have a central TX reallocation procedure that accounts for
+the tagger's needed headroom in a generic way, we can remove the
+skb_cow_head call.
+
+Note that the VLAN code path needs a smaller extra headroom than the
+regular EtherType DSA path. That isn't a problem, because this tagger
+declares the larger tag length (8 bytes vs 4) as the protocol overhead,
+so we are covered in both cases.
+
+Cc: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dsa/tag_edsa.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
+index 120614240319..abf70a29deb4 100644
+--- a/net/dsa/tag_edsa.c
++++ b/net/dsa/tag_edsa.c
+@@ -35,8 +35,6 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev)
+ * current ethertype field if the packet is untagged.
+ */
+ if (skb->protocol == htons(ETH_P_8021Q)) {
+- if (skb_cow_head(skb, DSA_HLEN) < 0)
+- return NULL;
+ skb_push(skb, DSA_HLEN);
+
+ memmove(skb->data, skb->data + DSA_HLEN, 2 * ETH_ALEN);
+@@ -60,8 +58,6 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev)
+ edsa_header[6] &= ~0x10;
+ }
+ } else {
+- if (skb_cow_head(skb, EDSA_HLEN) < 0)
+- return NULL;
+ skb_push(skb, EDSA_HLEN);
+
+ memmove(skb->data, skb->data + EDSA_HLEN, 2 * ETH_ALEN);
+--
+2.30.1
+
--- /dev/null
+From f5e9219ce4606a568cf76d4650aed661d642288a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Nov 2020 21:16:19 +0200
+Subject: net: dsa: tag_gswip: let DSA core deal with TX reallocation
+
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+[ Upstream commit 9b9826ae117f211bcbdc75db844d5fd8b159fc59 ]
+
+Now that we have a central TX reallocation procedure that accounts for
+the tagger's needed headroom in a generic way, we can remove the
+skb_cow_head call.
+
+This one is interesting, the DSA tag is 8 bytes on RX and 4 bytes on TX.
+Because DSA is unaware of asymmetrical tag lengths, the overhead/needed
+headroom is declared as 8 bytes and therefore 4 bytes larger than it
+needs to be. If this becomes a problem, and the GSWIP driver can't be
+converted to a uniform header length, we might need to make DSA aware of
+separate RX/TX overhead values.
+
+Cc: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dsa/tag_gswip.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/net/dsa/tag_gswip.c b/net/dsa/tag_gswip.c
+index 408d4af390a0..2f5bd5e338ab 100644
+--- a/net/dsa/tag_gswip.c
++++ b/net/dsa/tag_gswip.c
+@@ -60,13 +60,8 @@ static struct sk_buff *gswip_tag_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+ {
+ struct dsa_port *dp = dsa_slave_to_port(dev);
+- int err;
+ u8 *gswip_tag;
+
+- err = skb_cow_head(skb, GSWIP_TX_HEADER_LEN);
+- if (err)
+- return NULL;
+-
+ skb_push(skb, GSWIP_TX_HEADER_LEN);
+
+ gswip_tag = skb->data;
+--
+2.30.1
+
--- /dev/null
+From d67d109966037a86ca61265d35db182148b43165 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Nov 2020 21:16:10 +0200
+Subject: net: dsa: tag_ksz: don't allocate additional memory for
+ padding/tagging
+
+From: Christian Eggers <ceggers@arri.de>
+
+[ Upstream commit 88fda8eefd9a7a7175bf4dad1d02cc0840581111 ]
+
+The caller (dsa_slave_xmit) guarantees that the frame length is at least
+ETH_ZLEN and that enough memory for tail tagging is available.
+
+Signed-off-by: Christian Eggers <ceggers@arri.de>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dsa/tag_ksz.c | 73 ++++++-----------------------------------------
+ 1 file changed, 9 insertions(+), 64 deletions(-)
+
+diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c
+index 0a5aa982c60d..4820dbcedfa2 100644
+--- a/net/dsa/tag_ksz.c
++++ b/net/dsa/tag_ksz.c
+@@ -14,46 +14,6 @@
+ #define KSZ_EGRESS_TAG_LEN 1
+ #define KSZ_INGRESS_TAG_LEN 1
+
+-static struct sk_buff *ksz_common_xmit(struct sk_buff *skb,
+- struct net_device *dev, int len)
+-{
+- struct sk_buff *nskb;
+- int padlen;
+-
+- padlen = (skb->len >= ETH_ZLEN) ? 0 : ETH_ZLEN - skb->len;
+-
+- if (skb_tailroom(skb) >= padlen + len) {
+- /* Let dsa_slave_xmit() free skb */
+- if (__skb_put_padto(skb, skb->len + padlen, false))
+- return NULL;
+-
+- nskb = skb;
+- } else {
+- nskb = alloc_skb(NET_IP_ALIGN + skb->len +
+- padlen + len, GFP_ATOMIC);
+- if (!nskb)
+- return NULL;
+- skb_reserve(nskb, NET_IP_ALIGN);
+-
+- skb_reset_mac_header(nskb);
+- skb_set_network_header(nskb,
+- skb_network_header(skb) - skb->head);
+- skb_set_transport_header(nskb,
+- skb_transport_header(skb) - skb->head);
+- skb_copy_and_csum_dev(skb, skb_put(nskb, skb->len));
+-
+- /* Let skb_put_padto() free nskb, and let dsa_slave_xmit() free
+- * skb
+- */
+- if (skb_put_padto(nskb, nskb->len + padlen))
+- return NULL;
+-
+- consume_skb(skb);
+- }
+-
+- return nskb;
+-}
+-
+ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb,
+ struct net_device *dev,
+ unsigned int port, unsigned int len)
+@@ -90,23 +50,18 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb,
+ static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct dsa_port *dp = dsa_slave_to_port(dev);
+- struct sk_buff *nskb;
+ u8 *tag;
+ u8 *addr;
+
+- nskb = ksz_common_xmit(skb, dev, KSZ_INGRESS_TAG_LEN);
+- if (!nskb)
+- return NULL;
+-
+ /* Tag encoding */
+- tag = skb_put(nskb, KSZ_INGRESS_TAG_LEN);
+- addr = skb_mac_header(nskb);
++ tag = skb_put(skb, KSZ_INGRESS_TAG_LEN);
++ addr = skb_mac_header(skb);
+
+ *tag = 1 << dp->index;
+ if (is_link_local_ether_addr(addr))
+ *tag |= KSZ8795_TAIL_TAG_OVERRIDE;
+
+- return nskb;
++ return skb;
+ }
+
+ static struct sk_buff *ksz8795_rcv(struct sk_buff *skb, struct net_device *dev,
+@@ -156,18 +111,13 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+ {
+ struct dsa_port *dp = dsa_slave_to_port(dev);
+- struct sk_buff *nskb;
+ __be16 *tag;
+ u8 *addr;
+ u16 val;
+
+- nskb = ksz_common_xmit(skb, dev, KSZ9477_INGRESS_TAG_LEN);
+- if (!nskb)
+- return NULL;
+-
+ /* Tag encoding */
+- tag = skb_put(nskb, KSZ9477_INGRESS_TAG_LEN);
+- addr = skb_mac_header(nskb);
++ tag = skb_put(skb, KSZ9477_INGRESS_TAG_LEN);
++ addr = skb_mac_header(skb);
+
+ val = BIT(dp->index);
+
+@@ -176,7 +126,7 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb,
+
+ *tag = cpu_to_be16(val);
+
+- return nskb;
++ return skb;
+ }
+
+ static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev,
+@@ -213,24 +163,19 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+ {
+ struct dsa_port *dp = dsa_slave_to_port(dev);
+- struct sk_buff *nskb;
+ u8 *addr;
+ u8 *tag;
+
+- nskb = ksz_common_xmit(skb, dev, KSZ_INGRESS_TAG_LEN);
+- if (!nskb)
+- return NULL;
+-
+ /* Tag encoding */
+- tag = skb_put(nskb, KSZ_INGRESS_TAG_LEN);
+- addr = skb_mac_header(nskb);
++ tag = skb_put(skb, KSZ_INGRESS_TAG_LEN);
++ addr = skb_mac_header(skb);
+
+ *tag = BIT(dp->index);
+
+ if (is_link_local_ether_addr(addr))
+ *tag |= KSZ9893_TAIL_TAG_OVERRIDE;
+
+- return nskb;
++ return skb;
+ }
+
+ static const struct dsa_device_ops ksz9893_netdev_ops = {
+--
+2.30.1
+
--- /dev/null
+From 144ccb61f5c40c1854bb165a16a2d2b3fa47abe8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Nov 2020 21:16:15 +0200
+Subject: net: dsa: tag_lan9303: let DSA core deal with TX reallocation
+
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+[ Upstream commit 6ed94135f58372cdec34cafb60f7596893b0b371 ]
+
+Now that we have a central TX reallocation procedure that accounts for
+the tagger's needed headroom in a generic way, we can remove the
+skb_cow_head call.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dsa/tag_lan9303.c | 9 ---------
+ 1 file changed, 9 deletions(-)
+
+diff --git a/net/dsa/tag_lan9303.c b/net/dsa/tag_lan9303.c
+index ccfb6f641bbf..aa1318dccaf0 100644
+--- a/net/dsa/tag_lan9303.c
++++ b/net/dsa/tag_lan9303.c
+@@ -58,15 +58,6 @@ static struct sk_buff *lan9303_xmit(struct sk_buff *skb, struct net_device *dev)
+ __be16 *lan9303_tag;
+ u16 tag;
+
+- /* insert a special VLAN tag between the MAC addresses
+- * and the current ethertype field.
+- */
+- if (skb_cow_head(skb, LAN9303_TAG_LEN) < 0) {
+- dev_dbg(&dev->dev,
+- "Cannot make room for the special tag. Dropping packet\n");
+- return NULL;
+- }
+-
+ /* provide 'LAN9303_TAG_LEN' bytes additional space */
+ skb_push(skb, LAN9303_TAG_LEN);
+
+--
+2.30.1
+
--- /dev/null
+From 431ef53c835c33faa35fb2792fa5d549b986bb58 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 2 Mar 2021 00:01:59 +0800
+Subject: net: dsa: tag_mtk: fix 802.1ad VLAN egress
+
+From: DENG Qingfang <dqfext@gmail.com>
+
+[ Upstream commit 9200f515c41f4cbaeffd8fdd1d8b6373a18b1b67 ]
+
+A different TPID bit is used for 802.1ad VLAN frames.
+
+Reported-by: Ilario Gelmetti <iochesonome@gmail.com>
+Fixes: f0af34317f4b ("net: dsa: mediatek: combine MediaTek tag with VLAN tag")
+Signed-off-by: DENG Qingfang <dqfext@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dsa/tag_mtk.c | 19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c
+index 38dcdded74c0..59748487664f 100644
+--- a/net/dsa/tag_mtk.c
++++ b/net/dsa/tag_mtk.c
+@@ -13,6 +13,7 @@
+ #define MTK_HDR_LEN 4
+ #define MTK_HDR_XMIT_UNTAGGED 0
+ #define MTK_HDR_XMIT_TAGGED_TPID_8100 1
++#define MTK_HDR_XMIT_TAGGED_TPID_88A8 2
+ #define MTK_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0)
+ #define MTK_HDR_XMIT_DP_BIT_MASK GENMASK(5, 0)
+ #define MTK_HDR_XMIT_SA_DIS BIT(6)
+@@ -21,8 +22,8 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+ {
+ struct dsa_port *dp = dsa_slave_to_port(dev);
++ u8 xmit_tpid;
+ u8 *mtk_tag;
+- bool is_vlan_skb = true;
+ unsigned char *dest = eth_hdr(skb)->h_dest;
+ bool is_multicast_skb = is_multicast_ether_addr(dest) &&
+ !is_broadcast_ether_addr(dest);
+@@ -33,10 +34,17 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
+ * the both special and VLAN tag at the same time and then look up VLAN
+ * table with VID.
+ */
+- if (!skb_vlan_tagged(skb)) {
++ switch (skb->protocol) {
++ case htons(ETH_P_8021Q):
++ xmit_tpid = MTK_HDR_XMIT_TAGGED_TPID_8100;
++ break;
++ case htons(ETH_P_8021AD):
++ xmit_tpid = MTK_HDR_XMIT_TAGGED_TPID_88A8;
++ break;
++ default:
++ xmit_tpid = MTK_HDR_XMIT_UNTAGGED;
+ skb_push(skb, MTK_HDR_LEN);
+ memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN);
+- is_vlan_skb = false;
+ }
+
+ mtk_tag = skb->data + 2 * ETH_ALEN;
+@@ -44,8 +52,7 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
+ /* Mark tag attribute on special tag insertion to notify hardware
+ * whether that's a combined special tag with 802.1Q header.
+ */
+- mtk_tag[0] = is_vlan_skb ? MTK_HDR_XMIT_TAGGED_TPID_8100 :
+- MTK_HDR_XMIT_UNTAGGED;
++ mtk_tag[0] = xmit_tpid;
+ mtk_tag[1] = (1 << dp->index) & MTK_HDR_XMIT_DP_BIT_MASK;
+
+ /* Disable SA learning for multicast frames */
+@@ -53,7 +60,7 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
+ mtk_tag[1] |= MTK_HDR_XMIT_SA_DIS;
+
+ /* Tag control information is kept for 802.1Q */
+- if (!is_vlan_skb) {
++ if (xmit_tpid == MTK_HDR_XMIT_UNTAGGED) {
+ mtk_tag[2] = 0;
+ mtk_tag[3] = 0;
+ }
+--
+2.30.1
+
--- /dev/null
+From ea0f236c1714f4d948851c74cc13bf211359efe2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Nov 2020 21:16:14 +0200
+Subject: net: dsa: tag_mtk: let DSA core deal with TX reallocation
+
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+[ Upstream commit 941f66beb7bb4e0e4726aa31336d9ccc1c3a3dc2 ]
+
+Now that we have a central TX reallocation procedure that accounts for
+the tagger's needed headroom in a generic way, we can remove the
+skb_cow_head call.
+
+Cc: DENG Qingfang <dqfext@gmail.com>
+Cc: Sean Wang <sean.wang@mediatek.com>
+Cc: John Crispin <john@phrozen.org>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dsa/tag_mtk.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c
+index 4cdd9cf428fb..38dcdded74c0 100644
+--- a/net/dsa/tag_mtk.c
++++ b/net/dsa/tag_mtk.c
+@@ -34,9 +34,6 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
+ * table with VID.
+ */
+ if (!skb_vlan_tagged(skb)) {
+- if (skb_cow_head(skb, MTK_HDR_LEN) < 0)
+- return NULL;
+-
+ skb_push(skb, MTK_HDR_LEN);
+ memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN);
+ is_vlan_skb = false;
+--
+2.30.1
+
--- /dev/null
+From 2407ba787b21c6f9d4e1a2de75d10acab9bd8f27 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Nov 2020 21:16:13 +0200
+Subject: net: dsa: tag_ocelot: let DSA core deal with TX reallocation
+
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+[ Upstream commit 9c5c3bd00557e57c1049f7861f11e5e39f0fb42d ]
+
+Now that we have a central TX reallocation procedure that accounts for
+the tagger's needed headroom in a generic way, we can remove the
+skb_cow_head call.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dsa/tag_ocelot.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/net/dsa/tag_ocelot.c b/net/dsa/tag_ocelot.c
+index 3b468aca5c53..16a1afd5b8e1 100644
+--- a/net/dsa/tag_ocelot.c
++++ b/net/dsa/tag_ocelot.c
+@@ -143,13 +143,6 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
+ struct ocelot_port *ocelot_port;
+ u8 *prefix, *injection;
+ u64 qos_class, rew_op;
+- int err;
+-
+- err = skb_cow_head(skb, OCELOT_TOTAL_TAG_LEN);
+- if (unlikely(err < 0)) {
+- netdev_err(netdev, "Cannot make room for tag.\n");
+- return NULL;
+- }
+
+ ocelot_port = ocelot->ports[dp->index];
+
+--
+2.30.1
+
--- /dev/null
+From 711716fcbb18a3f427fc231d0fc983343d289714 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Nov 2020 21:16:12 +0200
+Subject: net: dsa: tag_qca: let DSA core deal with TX reallocation
+
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+[ Upstream commit 9bbda29ae1044bc4c1c01a5b7c44688c4765785f ]
+
+Now that we have a central TX reallocation procedure that accounts for
+the tagger's needed headroom in a generic way, we can remove the
+skb_cow_head call.
+
+Cc: John Crispin <john@phrozen.org>
+Cc: Alexander Lobakin <alobakin@pm.me>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dsa/tag_qca.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c
+index 1b9e8507112b..88181b52f480 100644
+--- a/net/dsa/tag_qca.c
++++ b/net/dsa/tag_qca.c
+@@ -34,9 +34,6 @@ static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)
+ __be16 *phdr;
+ u16 hdr;
+
+- if (skb_cow_head(skb, QCA_HDR_LEN) < 0)
+- return NULL;
+-
+ skb_push(skb, QCA_HDR_LEN);
+
+ memmove(skb->data, skb->data + QCA_HDR_LEN, 2 * ETH_ALEN);
+--
+2.30.1
+
--- /dev/null
+From 42a1837d79bf5111efe55272f483d29bd6bcabca Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Nov 2020 21:16:11 +0200
+Subject: net: dsa: trailer: don't allocate additional memory for
+ padding/tagging
+
+From: Christian Eggers <ceggers@arri.de>
+
+[ Upstream commit ef3f72fee286bd270453ce2344feb7295a798508 ]
+
+The caller (dsa_slave_xmit) guarantees that the frame length is at least
+ETH_ZLEN and that enough memory for tail tagging is available.
+
+Signed-off-by: Christian Eggers <ceggers@arri.de>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dsa/tag_trailer.c | 31 ++-----------------------------
+ 1 file changed, 2 insertions(+), 29 deletions(-)
+
+diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
+index 3a1cc24a4f0a..5b97ede56a0f 100644
+--- a/net/dsa/tag_trailer.c
++++ b/net/dsa/tag_trailer.c
+@@ -13,42 +13,15 @@
+ static struct sk_buff *trailer_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct dsa_port *dp = dsa_slave_to_port(dev);
+- struct sk_buff *nskb;
+- int padlen;
+ u8 *trailer;
+
+- /*
+- * We have to make sure that the trailer ends up as the very
+- * last 4 bytes of the packet. This means that we have to pad
+- * the packet to the minimum ethernet frame size, if necessary,
+- * before adding the trailer.
+- */
+- padlen = 0;
+- if (skb->len < 60)
+- padlen = 60 - skb->len;
+-
+- nskb = alloc_skb(NET_IP_ALIGN + skb->len + padlen + 4, GFP_ATOMIC);
+- if (!nskb)
+- return NULL;
+- skb_reserve(nskb, NET_IP_ALIGN);
+-
+- skb_reset_mac_header(nskb);
+- skb_set_network_header(nskb, skb_network_header(skb) - skb->head);
+- skb_set_transport_header(nskb, skb_transport_header(skb) - skb->head);
+- skb_copy_and_csum_dev(skb, skb_put(nskb, skb->len));
+- consume_skb(skb);
+-
+- if (padlen) {
+- skb_put_zero(nskb, padlen);
+- }
+-
+- trailer = skb_put(nskb, 4);
++ trailer = skb_put(skb, 4);
+ trailer[0] = 0x80;
+ trailer[1] = 1 << dp->index;
+ trailer[2] = 0x10;
+ trailer[3] = 0x00;
+
+- return nskb;
++ return skb;
+ }
+
+ static struct sk_buff *trailer_rcv(struct sk_buff *skb, struct net_device *dev,
+--
+2.30.1
+
--- /dev/null
+From d2765886e4ca05d12d0de35ce5a45ce1f6ae9736 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 1 Mar 2021 13:18:12 +0200
+Subject: net: enetc: initialize RFS/RSS memories for unused ports too
+
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+[ Upstream commit 3222b5b613db558e9a494bbf53f3c984d90f71ea ]
+
+Michael reports that since linux-next-20210211, the AER messages for ECC
+errors have started reappearing, and this time they can be reliably
+reproduced with the first ping on one of his LS1028A boards.
+
+$ ping 1[ 33.258069] pcieport 0000:00:1f.0: AER: Multiple Corrected error received: 0000:00:00.0
+72.16.0.1
+PING [ 33.267050] pcieport 0000:00:1f.0: AER: can't find device of ID0000
+172.16.0.1 (172.16.0.1): 56 data bytes
+64 bytes from 172.16.0.1: seq=0 ttl=64 time=17.124 ms
+64 bytes from 172.16.0.1: seq=1 ttl=64 time=0.273 ms
+
+$ devmem 0x1f8010e10 32
+0xC0000006
+
+It isn't clear why this is necessary, but it seems that for the errors
+to go away, we must clear the entire RFS and RSS memory, not just for
+the ports in use.
+
+Sadly the code is structured in such a way that we can't have unified
+logic for the used and unused ports. For the minimal initialization of
+an unused port, we need just to enable and ioremap the PF memory space,
+and a control buffer descriptor ring. Unused ports must then free the
+CBDR because the driver will exit, but used ports can not pick up from
+where that code path left, since the CBDR API does not reinitialize a
+ring when setting it up, so its producer and consumer indices are out of
+sync between the software and hardware state. So a separate
+enetc_init_unused_port function was created, and it gets called right
+after the PF memory space is enabled.
+
+Fixes: 07bf34a50e32 ("net: enetc: initialize the RFS and RSS memories")
+Reported-by: Michael Walle <michael@walle.cc>
+Cc: Jesse Brandeburg <jesse.brandeburg@intel.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Tested-by: Michael Walle <michael@walle.cc>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/enetc/enetc.c | 8 ++---
+ drivers/net/ethernet/freescale/enetc/enetc.h | 4 +++
+ .../net/ethernet/freescale/enetc/enetc_pf.c | 33 ++++++++++++++++---
+ 3 files changed, 36 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
+index 019a0fa3d9a5..df4a858c8001 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc.c
+@@ -1035,7 +1035,7 @@ static void enetc_free_rxtx_rings(struct enetc_ndev_priv *priv)
+ enetc_free_tx_ring(priv->tx_ring[i]);
+ }
+
+-static int enetc_alloc_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
++int enetc_alloc_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
+ {
+ int size = cbdr->bd_count * sizeof(struct enetc_cbd);
+
+@@ -1056,7 +1056,7 @@ static int enetc_alloc_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
+ return 0;
+ }
+
+-static void enetc_free_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
++void enetc_free_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
+ {
+ int size = cbdr->bd_count * sizeof(struct enetc_cbd);
+
+@@ -1064,7 +1064,7 @@ static void enetc_free_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
+ cbdr->bd_base = NULL;
+ }
+
+-static void enetc_setup_cbdr(struct enetc_hw *hw, struct enetc_cbdr *cbdr)
++void enetc_setup_cbdr(struct enetc_hw *hw, struct enetc_cbdr *cbdr)
+ {
+ /* set CBDR cache attributes */
+ enetc_wr(hw, ENETC_SICAR2,
+@@ -1084,7 +1084,7 @@ static void enetc_setup_cbdr(struct enetc_hw *hw, struct enetc_cbdr *cbdr)
+ cbdr->cir = hw->reg + ENETC_SICBDRCIR;
+ }
+
+-static void enetc_clear_cbdr(struct enetc_hw *hw)
++void enetc_clear_cbdr(struct enetc_hw *hw)
+ {
+ enetc_wr(hw, ENETC_SICBDRMR, 0);
+ }
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
+index 6bc23f9b53fa..15d19cbd5a95 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc.h
+@@ -311,6 +311,10 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+ void enetc_set_ethtool_ops(struct net_device *ndev);
+
+ /* control buffer descriptor ring (CBDR) */
++int enetc_alloc_cbdr(struct device *dev, struct enetc_cbdr *cbdr);
++void enetc_free_cbdr(struct device *dev, struct enetc_cbdr *cbdr);
++void enetc_setup_cbdr(struct enetc_hw *hw, struct enetc_cbdr *cbdr);
++void enetc_clear_cbdr(struct enetc_hw *hw);
+ int enetc_set_mac_flt_entry(struct enetc_si *si, int index,
+ char *mac_addr, int si_map);
+ int enetc_clear_mac_flt_entry(struct enetc_si *si, int index);
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+index f29058dddb36..83187cd59fdd 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -1081,6 +1081,26 @@ static int enetc_init_port_rss_memory(struct enetc_si *si)
+ return err;
+ }
+
++static void enetc_init_unused_port(struct enetc_si *si)
++{
++ struct device *dev = &si->pdev->dev;
++ struct enetc_hw *hw = &si->hw;
++ int err;
++
++ si->cbd_ring.bd_count = ENETC_CBDR_DEFAULT_SIZE;
++ err = enetc_alloc_cbdr(dev, &si->cbd_ring);
++ if (err)
++ return;
++
++ enetc_setup_cbdr(hw, &si->cbd_ring);
++
++ enetc_init_port_rfs_memory(si);
++ enetc_init_port_rss_memory(si);
++
++ enetc_clear_cbdr(hw);
++ enetc_free_cbdr(dev, &si->cbd_ring);
++}
++
+ static int enetc_pf_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+ {
+@@ -1091,11 +1111,6 @@ static int enetc_pf_probe(struct pci_dev *pdev,
+ struct enetc_pf *pf;
+ int err;
+
+- if (node && !of_device_is_available(node)) {
+- dev_info(&pdev->dev, "device is disabled, skipping\n");
+- return -ENODEV;
+- }
+-
+ err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(*pf));
+ if (err) {
+ dev_err(&pdev->dev, "PCI probing failed\n");
+@@ -1109,6 +1124,13 @@ static int enetc_pf_probe(struct pci_dev *pdev,
+ goto err_map_pf_space;
+ }
+
++ if (node && !of_device_is_available(node)) {
++ enetc_init_unused_port(si);
++ dev_info(&pdev->dev, "device is disabled, skipping\n");
++ err = -ENODEV;
++ goto err_device_disabled;
++ }
++
+ pf = enetc_si_priv(si);
+ pf->si = si;
+ pf->total_vfs = pci_sriov_get_totalvfs(pdev);
+@@ -1191,6 +1213,7 @@ err_alloc_si_res:
+ si->ndev = NULL;
+ free_netdev(ndev);
+ err_alloc_netdev:
++err_device_disabled:
+ err_map_pf_space:
+ enetc_pci_remove(pdev);
+
+--
+2.30.1
+
--- /dev/null
+From c8605d62188d979dc64a3be89e479dcdfde25815 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 27 Feb 2021 15:24:51 +0800
+Subject: net: hns3: fix error mask definition of flow director
+
+From: Jian Shen <shenjian15@huawei.com>
+
+[ Upstream commit ae85ddda0f1b341b2d25f5a5e0eff1d42b6ef3df ]
+
+Currently, some bit filed definitions of flow director TCAM
+configuration command are incorrect. Since the wrong MSB is
+always 0, and these fields are assgined in order, so it still works.
+
+Fix it by redefine them.
+
+Fixes: 117328680288 ("net: hns3: Add input key and action config support for flow director")
+Signed-off-by: Jian Shen <shenjian15@huawei.com>
+Signed-off-by: Huazhong Tan <tanhuazhong@huawei.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
+index 096e26a2e16b..36690fc5c1af 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
+@@ -1031,16 +1031,16 @@ struct hclge_fd_tcam_config_3_cmd {
+ #define HCLGE_FD_AD_DROP_B 0
+ #define HCLGE_FD_AD_DIRECT_QID_B 1
+ #define HCLGE_FD_AD_QID_S 2
+-#define HCLGE_FD_AD_QID_M GENMASK(12, 2)
++#define HCLGE_FD_AD_QID_M GENMASK(11, 2)
+ #define HCLGE_FD_AD_USE_COUNTER_B 12
+ #define HCLGE_FD_AD_COUNTER_NUM_S 13
+ #define HCLGE_FD_AD_COUNTER_NUM_M GENMASK(20, 13)
+ #define HCLGE_FD_AD_NXT_STEP_B 20
+ #define HCLGE_FD_AD_NXT_KEY_S 21
+-#define HCLGE_FD_AD_NXT_KEY_M GENMASK(26, 21)
++#define HCLGE_FD_AD_NXT_KEY_M GENMASK(25, 21)
+ #define HCLGE_FD_AD_WR_RULE_ID_B 0
+ #define HCLGE_FD_AD_RULE_ID_S 1
+-#define HCLGE_FD_AD_RULE_ID_M GENMASK(13, 1)
++#define HCLGE_FD_AD_RULE_ID_M GENMASK(12, 1)
+
+ struct hclge_fd_ad_config_cmd {
+ u8 stage;
+--
+2.30.1
+
--- /dev/null
+From db57241ae94eceea3692871b5f238dd09606dea1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 7 Dec 2020 14:12:31 +0100
+Subject: s390/qeth: don't replace a fully completed async TX buffer
+
+From: Julian Wiedmann <jwi@linux.ibm.com>
+
+[ Upstream commit db4ffdcef7c9a842e55228c9faef7abf8b72382f ]
+
+For TX buffers that require an additional async notification via QAOB, the
+TX completion code can now manage all the necessary processing if the
+notification has already occurred (or is occurring concurrently).
+
+In such cases we can avoid replacing the metadata that is associated
+with the buffer's slot on the ring, and just keep using the current one.
+
+As qeth_clear_output_buffer() will also handle any kmem cache-allocated
+memory that was mapped into the TX buffer, qeth_qdio_handle_aob()
+doesn't need to worry about it.
+
+While at it, also remove the unneeded forward declaration for
+qeth_init_qdio_out_buf().
+
+Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/s390/net/qeth_core_main.c | 89 ++++++++++++++++++-------------
+ 1 file changed, 51 insertions(+), 38 deletions(-)
+
+diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
+index 77cd714978bd..78a866424022 100644
+--- a/drivers/s390/net/qeth_core_main.c
++++ b/drivers/s390/net/qeth_core_main.c
+@@ -75,7 +75,6 @@ static void qeth_notify_skbs(struct qeth_qdio_out_q *queue,
+ enum iucv_tx_notify notification);
+ static void qeth_tx_complete_buf(struct qeth_qdio_out_buffer *buf, bool error,
+ int budget);
+-static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int);
+
+ static void qeth_close_dev_handler(struct work_struct *work)
+ {
+@@ -517,18 +516,6 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,
+ buffer = (struct qeth_qdio_out_buffer *) aob->user1;
+ QETH_CARD_TEXT_(card, 5, "%lx", aob->user1);
+
+- /* Free dangling allocations. The attached skbs are handled by
+- * qeth_cleanup_handled_pending().
+- */
+- for (i = 0;
+- i < aob->sb_count && i < QETH_MAX_BUFFER_ELEMENTS(card);
+- i++) {
+- void *data = phys_to_virt(aob->sba[i]);
+-
+- if (data && buffer->is_header[i])
+- kmem_cache_free(qeth_core_header_cache, data);
+- }
+-
+ if (aob->aorc) {
+ QETH_CARD_TEXT_(card, 2, "aorc%02X", aob->aorc);
+ new_state = QETH_QDIO_BUF_QAOB_ERROR;
+@@ -536,10 +523,9 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,
+
+ switch (atomic_xchg(&buffer->state, new_state)) {
+ case QETH_QDIO_BUF_PRIMED:
+- /* Faster than TX completion code. */
+- notification = qeth_compute_cq_notification(aob->aorc, 0);
+- qeth_notify_skbs(buffer->q, buffer, notification);
+- atomic_set(&buffer->state, QETH_QDIO_BUF_HANDLED_DELAYED);
++ /* Faster than TX completion code, let it handle the async
++ * completion for us.
++ */
+ break;
+ case QETH_QDIO_BUF_PENDING:
+ /* TX completion code is active and will handle the async
+@@ -550,6 +536,19 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,
+ /* TX completion code is already finished. */
+ notification = qeth_compute_cq_notification(aob->aorc, 1);
+ qeth_notify_skbs(buffer->q, buffer, notification);
++
++ /* Free dangling allocations. The attached skbs are handled by
++ * qeth_cleanup_handled_pending().
++ */
++ for (i = 0;
++ i < aob->sb_count && i < QETH_MAX_BUFFER_ELEMENTS(card);
++ i++) {
++ void *data = phys_to_virt(aob->sba[i]);
++
++ if (data && buffer->is_header[i])
++ kmem_cache_free(qeth_core_header_cache, data);
++ }
++
+ atomic_set(&buffer->state, QETH_QDIO_BUF_HANDLED_DELAYED);
+ break;
+ default:
+@@ -5870,9 +5869,13 @@ static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue,
+ QDIO_OUTBUF_STATE_FLAG_PENDING)) {
+ WARN_ON_ONCE(card->options.cq != QETH_CQ_ENABLED);
+
+- if (atomic_cmpxchg(&buffer->state, QETH_QDIO_BUF_PRIMED,
+- QETH_QDIO_BUF_PENDING) ==
+- QETH_QDIO_BUF_PRIMED) {
++ QETH_CARD_TEXT_(card, 5, "pel%u", bidx);
++
++ switch (atomic_cmpxchg(&buffer->state,
++ QETH_QDIO_BUF_PRIMED,
++ QETH_QDIO_BUF_PENDING)) {
++ case QETH_QDIO_BUF_PRIMED:
++ /* We have initial ownership, no QAOB (yet): */
+ qeth_notify_skbs(queue, buffer, TX_NOTIFY_PENDING);
+
+ /* Handle race with qeth_qdio_handle_aob(): */
+@@ -5880,39 +5883,49 @@ static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue,
+ QETH_QDIO_BUF_NEED_QAOB)) {
+ case QETH_QDIO_BUF_PENDING:
+ /* No concurrent QAOB notification. */
+- break;
++
++ /* Prepare the queue slot for immediate re-use: */
++ qeth_scrub_qdio_buffer(buffer->buffer, queue->max_elements);
++ if (qeth_init_qdio_out_buf(queue, bidx)) {
++ QETH_CARD_TEXT(card, 2, "outofbuf");
++ qeth_schedule_recovery(card);
++ }
++
++ /* Skip clearing the buffer: */
++ return;
+ case QETH_QDIO_BUF_QAOB_OK:
+ qeth_notify_skbs(queue, buffer,
+ TX_NOTIFY_DELAYED_OK);
+- atomic_set(&buffer->state,
+- QETH_QDIO_BUF_HANDLED_DELAYED);
++ error = false;
+ break;
+ case QETH_QDIO_BUF_QAOB_ERROR:
+ qeth_notify_skbs(queue, buffer,
+ TX_NOTIFY_DELAYED_GENERALERROR);
+- atomic_set(&buffer->state,
+- QETH_QDIO_BUF_HANDLED_DELAYED);
++ error = true;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ }
+- }
+-
+- QETH_CARD_TEXT_(card, 5, "pel%u", bidx);
+
+- /* prepare the queue slot for re-use: */
+- qeth_scrub_qdio_buffer(buffer->buffer, queue->max_elements);
+- if (qeth_init_qdio_out_buf(queue, bidx)) {
+- QETH_CARD_TEXT(card, 2, "outofbuf");
+- qeth_schedule_recovery(card);
++ break;
++ case QETH_QDIO_BUF_QAOB_OK:
++ /* qeth_qdio_handle_aob() already received a QAOB: */
++ qeth_notify_skbs(queue, buffer, TX_NOTIFY_OK);
++ error = false;
++ break;
++ case QETH_QDIO_BUF_QAOB_ERROR:
++ /* qeth_qdio_handle_aob() already received a QAOB: */
++ qeth_notify_skbs(queue, buffer, TX_NOTIFY_GENERALERROR);
++ error = true;
++ break;
++ default:
++ WARN_ON_ONCE(1);
+ }
+-
+- return;
+- }
+-
+- if (card->options.cq == QETH_CQ_ENABLED)
++ } else if (card->options.cq == QETH_CQ_ENABLED) {
+ qeth_notify_skbs(queue, buffer,
+ qeth_compute_cq_notification(sflags, 0));
++ }
++
+ qeth_clear_output_buffer(queue, buffer, error, budget);
+ }
+
+--
+2.30.1
+
--- /dev/null
+From b693b65fee8137c86b32714fc19e6e28c1831c2f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 9 Mar 2021 17:52:21 +0100
+Subject: s390/qeth: fix notification for pending buffers during teardown
+
+From: Julian Wiedmann <jwi@linux.ibm.com>
+
+[ Upstream commit 7eefda7f353ef86ad82a2dc8329e8a3538c08ab6 ]
+
+The cited commit reworked the state machine for pending TX buffers.
+In qeth_iqd_tx_complete() it turned PENDING into a transient state, and
+uses NEED_QAOB for buffers that get parked while waiting for their QAOB
+completion.
+
+But it missed to adjust the check in qeth_tx_complete_buf(). So if
+qeth_tx_complete_pending_bufs() is called during teardown to drain
+the parked TX buffers, we no longer raise a notification for af_iucv.
+
+Instead of updating the checked state, just move this code into
+qeth_tx_complete_pending_bufs() itself. This also gets rid of the
+special-case in the common TX completion path.
+
+Fixes: 8908f36d20d8 ("s390/qeth: fix af_iucv notification race")
+Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/s390/net/qeth_core_main.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
+index db785030293b..03f96177e58e 100644
+--- a/drivers/s390/net/qeth_core_main.c
++++ b/drivers/s390/net/qeth_core_main.c
+@@ -1383,9 +1383,6 @@ static void qeth_tx_complete_buf(struct qeth_qdio_out_buffer *buf, bool error,
+ struct qeth_qdio_out_q *queue = buf->q;
+ struct sk_buff *skb;
+
+- if (atomic_read(&buf->state) == QETH_QDIO_BUF_PENDING)
+- qeth_notify_skbs(queue, buf, TX_NOTIFY_GENERALERROR);
+-
+ /* Empty buffer? */
+ if (buf->next_element_to_fill == 0)
+ return;
+@@ -1458,6 +1455,9 @@ static void qeth_tx_complete_pending_bufs(struct qeth_card *card,
+ QETH_CARD_TEXT(card, 5, "fp");
+ QETH_CARD_TEXT_(card, 5, "%lx", (long) buf);
+
++ if (drain)
++ qeth_notify_skbs(queue, buf,
++ TX_NOTIFY_GENERALERROR);
+ qeth_tx_complete_buf(buf, drain, 0);
+
+ list_del(&buf->list_entry);
+--
+2.30.1
+
--- /dev/null
+From 4478aa7a048a6bb0371c9155a0d081c8c741008b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 9 Mar 2021 17:52:19 +0100
+Subject: s390/qeth: improve completion of pending TX buffers
+
+From: Julian Wiedmann <jwi@linux.ibm.com>
+
+[ Upstream commit c20383ad1656b0f6354dd50e4acd894f9d94090d ]
+
+The current design attaches a pending TX buffer to a custom
+single-linked list, which is anchored at the buffer's slot on the
+TX ring. The buffer is then checked for final completion whenever
+this slot is processed during a subsequent TX NAPI poll cycle.
+
+But if there's insufficient traffic on the ring, we might never make
+enough progress to get back to this ring slot and discover the pending
+buffer's final TX completion. In particular if this missing TX
+completion blocks the application from sending further traffic.
+
+So convert the custom single-linked list code to a per-queue list_head,
+and scan this list on every TX NAPI cycle.
+
+Fixes: 0da9581ddb0f ("qeth: exploit asynchronous delivery of storage blocks")
+Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/s390/net/qeth_core.h | 3 +-
+ drivers/s390/net/qeth_core_main.c | 69 +++++++++++++------------------
+ 2 files changed, 30 insertions(+), 42 deletions(-)
+
+diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
+index ea969b8fe687..bf8404b0e74f 100644
+--- a/drivers/s390/net/qeth_core.h
++++ b/drivers/s390/net/qeth_core.h
+@@ -436,7 +436,7 @@ struct qeth_qdio_out_buffer {
+ int is_header[QDIO_MAX_ELEMENTS_PER_BUFFER];
+
+ struct qeth_qdio_out_q *q;
+- struct qeth_qdio_out_buffer *next_pending;
++ struct list_head list_entry;
+ };
+
+ struct qeth_card;
+@@ -500,6 +500,7 @@ struct qeth_qdio_out_q {
+ struct qdio_buffer *qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
+ struct qeth_qdio_out_buffer *bufs[QDIO_MAX_BUFFERS_PER_Q];
+ struct qdio_outbuf_state *bufstates; /* convenience pointer */
++ struct list_head pending_bufs;
+ struct qeth_out_q_stats stats;
+ spinlock_t lock;
+ unsigned int priority;
+diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
+index e2cdb5c2fc66..db785030293b 100644
+--- a/drivers/s390/net/qeth_core_main.c
++++ b/drivers/s390/net/qeth_core_main.c
+@@ -73,8 +73,6 @@ static void qeth_free_qdio_queues(struct qeth_card *card);
+ static void qeth_notify_skbs(struct qeth_qdio_out_q *queue,
+ struct qeth_qdio_out_buffer *buf,
+ enum iucv_tx_notify notification);
+-static void qeth_tx_complete_buf(struct qeth_qdio_out_buffer *buf, bool error,
+- int budget);
+
+ static void qeth_close_dev_handler(struct work_struct *work)
+ {
+@@ -465,41 +463,6 @@ static enum iucv_tx_notify qeth_compute_cq_notification(int sbalf15,
+ return n;
+ }
+
+-static void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q, int bidx,
+- int forced_cleanup)
+-{
+- if (q->card->options.cq != QETH_CQ_ENABLED)
+- return;
+-
+- if (q->bufs[bidx]->next_pending != NULL) {
+- struct qeth_qdio_out_buffer *head = q->bufs[bidx];
+- struct qeth_qdio_out_buffer *c = q->bufs[bidx]->next_pending;
+-
+- while (c) {
+- if (forced_cleanup ||
+- atomic_read(&c->state) == QETH_QDIO_BUF_EMPTY) {
+- struct qeth_qdio_out_buffer *f = c;
+-
+- QETH_CARD_TEXT(f->q->card, 5, "fp");
+- QETH_CARD_TEXT_(f->q->card, 5, "%lx", (long) f);
+- /* release here to avoid interleaving between
+- outbound tasklet and inbound tasklet
+- regarding notifications and lifecycle */
+- qeth_tx_complete_buf(c, forced_cleanup, 0);
+-
+- c = f->next_pending;
+- WARN_ON_ONCE(head->next_pending != f);
+- head->next_pending = c;
+- kmem_cache_free(qeth_qdio_outbuf_cache, f);
+- } else {
+- head = c;
+- c = c->next_pending;
+- }
+-
+- }
+- }
+-}
+-
+ static void qeth_qdio_handle_aob(struct qeth_card *card,
+ unsigned long phys_aob_addr)
+ {
+@@ -537,7 +500,7 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,
+ qeth_notify_skbs(buffer->q, buffer, notification);
+
+ /* Free dangling allocations. The attached skbs are handled by
+- * qeth_cleanup_handled_pending().
++ * qeth_tx_complete_pending_bufs().
+ */
+ for (i = 0;
+ i < aob->sb_count && i < QETH_MAX_BUFFER_ELEMENTS(card);
+@@ -1484,14 +1447,35 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
+ atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
+ }
+
++static void qeth_tx_complete_pending_bufs(struct qeth_card *card,
++ struct qeth_qdio_out_q *queue,
++ bool drain)
++{
++ struct qeth_qdio_out_buffer *buf, *tmp;
++
++ list_for_each_entry_safe(buf, tmp, &queue->pending_bufs, list_entry) {
++ if (drain || atomic_read(&buf->state) == QETH_QDIO_BUF_EMPTY) {
++ QETH_CARD_TEXT(card, 5, "fp");
++ QETH_CARD_TEXT_(card, 5, "%lx", (long) buf);
++
++ qeth_tx_complete_buf(buf, drain, 0);
++
++ list_del(&buf->list_entry);
++ kmem_cache_free(qeth_qdio_outbuf_cache, buf);
++ }
++ }
++}
++
+ static void qeth_drain_output_queue(struct qeth_qdio_out_q *q, bool free)
+ {
+ int j;
+
++ qeth_tx_complete_pending_bufs(q->card, q, true);
++
+ for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) {
+ if (!q->bufs[j])
+ continue;
+- qeth_cleanup_handled_pending(q, j, 1);
++
+ qeth_clear_output_buffer(q, q->bufs[j], true, 0);
+ if (free) {
+ kmem_cache_free(qeth_qdio_outbuf_cache, q->bufs[j]);
+@@ -2611,7 +2595,6 @@ static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *q, int bidx)
+ skb_queue_head_init(&newbuf->skb_list);
+ lockdep_set_class(&newbuf->skb_list.lock, &qdio_out_skb_queue_key);
+ newbuf->q = q;
+- newbuf->next_pending = q->bufs[bidx];
+ atomic_set(&newbuf->state, QETH_QDIO_BUF_EMPTY);
+ q->bufs[bidx] = newbuf;
+ return 0;
+@@ -2693,6 +2676,7 @@ static int qeth_alloc_qdio_queues(struct qeth_card *card)
+ card->qdio.out_qs[i] = queue;
+ queue->card = card;
+ queue->queue_no = i;
++ INIT_LIST_HEAD(&queue->pending_bufs);
+ spin_lock_init(&queue->lock);
+ timer_setup(&queue->timer, qeth_tx_completion_timer, 0);
+ queue->coalesce_usecs = QETH_TX_COALESCE_USECS;
+@@ -5890,6 +5874,8 @@ static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue,
+ qeth_schedule_recovery(card);
+ }
+
++ list_add(&buffer->list_entry,
++ &queue->pending_bufs);
+ /* Skip clearing the buffer: */
+ return;
+ case QETH_QDIO_BUF_QAOB_OK:
+@@ -5945,6 +5931,8 @@ static int qeth_tx_poll(struct napi_struct *napi, int budget)
+ unsigned int bytes = 0;
+ int completed;
+
++ qeth_tx_complete_pending_bufs(card, queue, false);
++
+ if (qeth_out_queue_is_empty(queue)) {
+ napi_complete(napi);
+ return 0;
+@@ -5977,7 +5965,6 @@ static int qeth_tx_poll(struct napi_struct *napi, int budget)
+
+ qeth_handle_send_error(card, buffer, error);
+ qeth_iqd_tx_complete(queue, bidx, error, budget);
+- qeth_cleanup_handled_pending(queue, bidx, false);
+ }
+
+ netdev_tx_completed_queue(txq, packets, bytes);
+--
+2.30.1
+
--- /dev/null
+From 384fee83b72b583c52a8f9235694c0338c5a72a2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 7 Dec 2020 14:12:32 +0100
+Subject: s390/qeth: remove QETH_QDIO_BUF_HANDLED_DELAYED state
+
+From: Julian Wiedmann <jwi@linux.ibm.com>
+
+[ Upstream commit 75cf3854dcdf7b5c583538cae12ffa054d237d93 ]
+
+Reuse the QETH_QDIO_BUF_EMPTY state to indicate that a TX buffer has
+been completed with a QAOB notification, and may be cleaned up by
+qeth_cleanup_handled_pending().
+
+Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/s390/net/qeth_core.h | 2 --
+ drivers/s390/net/qeth_core_main.c | 5 ++---
+ 2 files changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
+index 2f7e06ec9a30..ea969b8fe687 100644
+--- a/drivers/s390/net/qeth_core.h
++++ b/drivers/s390/net/qeth_core.h
+@@ -424,8 +424,6 @@ enum qeth_qdio_out_buffer_state {
+ /* Received QAOB notification on CQ: */
+ QETH_QDIO_BUF_QAOB_OK,
+ QETH_QDIO_BUF_QAOB_ERROR,
+- /* Handled via transfer pending / completion queue. */
+- QETH_QDIO_BUF_HANDLED_DELAYED,
+ };
+
+ struct qeth_qdio_out_buffer {
+diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
+index 78a866424022..e2cdb5c2fc66 100644
+--- a/drivers/s390/net/qeth_core_main.c
++++ b/drivers/s390/net/qeth_core_main.c
+@@ -477,8 +477,7 @@ static void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q, int bidx,
+
+ while (c) {
+ if (forced_cleanup ||
+- atomic_read(&c->state) ==
+- QETH_QDIO_BUF_HANDLED_DELAYED) {
++ atomic_read(&c->state) == QETH_QDIO_BUF_EMPTY) {
+ struct qeth_qdio_out_buffer *f = c;
+
+ QETH_CARD_TEXT(f->q->card, 5, "fp");
+@@ -549,7 +548,7 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,
+ kmem_cache_free(qeth_core_header_cache, data);
+ }
+
+- atomic_set(&buffer->state, QETH_QDIO_BUF_HANDLED_DELAYED);
++ atomic_set(&buffer->state, QETH_QDIO_BUF_EMPTY);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+--
+2.30.1
+
media-v4l-vsp1-fix-bru-null-pointer-access.patch
media-rc-compile-rc-cec.c-into-rc-core.patch
cifs-fix-credit-accounting-for-extra-channel.patch
+net-hns3-fix-error-mask-definition-of-flow-director.patch
+mips-kernel-reserve-exception-base-early-to-prevent-.patch
+s390-qeth-don-t-replace-a-fully-completed-async-tx-b.patch
+s390-qeth-remove-qeth_qdio_buf_handled_delayed-state.patch
+s390-qeth-improve-completion-of-pending-tx-buffers.patch
+s390-qeth-fix-notification-for-pending-buffers-durin.patch
+net-dsa-implement-a-central-tx-reallocation-procedur.patch
+net-dsa-tag_ksz-don-t-allocate-additional-memory-for.patch
+net-dsa-trailer-don-t-allocate-additional-memory-for.patch
+net-dsa-tag_qca-let-dsa-core-deal-with-tx-reallocati.patch
+net-dsa-tag_ocelot-let-dsa-core-deal-with-tx-realloc.patch
+net-dsa-tag_mtk-let-dsa-core-deal-with-tx-reallocati.patch
+net-dsa-tag_lan9303-let-dsa-core-deal-with-tx-reallo.patch
+net-dsa-tag_edsa-let-dsa-core-deal-with-tx-reallocat.patch
+net-dsa-tag_brcm-let-dsa-core-deal-with-tx-reallocat.patch
+net-dsa-tag_dsa-let-dsa-core-deal-with-tx-reallocati.patch
+net-dsa-tag_gswip-let-dsa-core-deal-with-tx-realloca.patch
+net-dsa-tag_ar9331-let-dsa-core-deal-with-tx-realloc.patch
+net-dsa-tag_mtk-fix-802.1ad-vlan-egress.patch
+enetc-fix-unused-var-build-warning-for-config_of.patch
+net-enetc-initialize-rfs-rss-memories-for-unused-por.patch
+ath11k-peer-delete-synchronization-with-firmware.patch
+ath11k-start-vdev-if-a-bss-peer-is-already-created.patch
+ath11k-fix-ap-mode-for-qca6390.patch