From: Jian Shen shenjian15@huawei.com
mainline inclusion from mainline-v5.12-rc1 commit ae9e492a366433b97be414d2e90a2e24f8446abf category: bugfix bugzilla: NA CVE: NA
----------------------------
Since the real tx queue number and real rx queue number always be updated when netdev opens, it's redundant to call hclge_client_setup_tc to do the same thing. So remove it.
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Huazhong Tan tanhuazhong@huawei.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 - .../net/ethernet/hisilicon/hns3/hns3_enet.c | 15 --------- .../hisilicon/hns3/hns3pf/hclge_dcb.c | 31 ------------------- 3 files changed, 47 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index e407343fd0954..2e4b5c099fb4e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -216,7 +216,6 @@ struct hnae3_client_ops { int (*init_instance)(struct hnae3_handle *handle); void (*uninit_instance)(struct hnae3_handle *handle, bool reset); void (*link_status_change)(struct hnae3_handle *handle, bool state); - int (*setup_tc)(struct hnae3_handle *handle, u8 tc); int (*reset_notify)(struct hnae3_handle *handle, enum hnae3_reset_notify_type type); void (*process_hw_error)(struct hnae3_handle *handle, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index e409633748a90..1db68d60794dd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -4240,20 +4240,6 @@ static void hns3_link_status_change(struct hnae3_handle *handle, bool linkup) } }
-static int hns3_client_setup_tc(struct hnae3_handle *handle, u8 tc) -{ - struct hnae3_knic_private_info *kinfo = &handle->kinfo; - struct net_device *ndev = kinfo->netdev; - - if (tc > HNAE3_MAX_TC) - return -EINVAL; - - if (!ndev) - return -ENODEV; - - return hns3_nic_set_real_num_queue(ndev); -} - static void hns3_clear_tx_ring(struct hns3_enet_ring *ring) { while (ring->next_to_clean != ring->next_to_use) { @@ -4682,7 +4668,6 @@ const struct hnae3_client_ops client_ops = { .init_instance = hns3_client_init, .uninit_instance = hns3_client_uninit, .link_status_change = hns3_link_status_change, - .setup_tc = hns3_client_setup_tc, .reset_notify = hns3_reset_notify, .process_hw_error = hns3_process_hw_error, }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index 174a0bde8fe73..bf2f43281fda1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c @@ -175,29 +175,6 @@ static int hclge_map_update(struct hclge_dev *hdev) return hclge_rss_init_hw(hdev); }
-static int hclge_client_setup_tc(struct hclge_dev *hdev) -{ - struct hclge_vport *vport = hdev->vport; - struct hnae3_client *client; - struct hnae3_handle *handle; - int ret; - u32 i; - - for (i = 0; i < hdev->num_vmdq_vport + 1; i++) { - handle = &vport[i].nic; - client = handle->client; - - if (!client || !client->ops || !client->ops->setup_tc) - continue; - - ret = client->ops->setup_tc(handle, hdev->tm_info.num_tc); - if (ret) - return ret; - } - - return 0; -} - static int hclge_notify_down_uinit(struct hclge_dev *hdev) { int ret; @@ -257,10 +234,6 @@ static int hclge_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets) if (ret) goto err_out;
- ret = hclge_client_setup_tc(hdev); - if (ret) - goto err_out; - ret = hclge_notify_init_up(hdev); if (ret) return ret; @@ -424,10 +397,6 @@ static int hclge_setup_tc(struct hnae3_handle *h, u8 tc, u8 *prio_tc) if (ret) goto err_out;
- ret = hclge_client_setup_tc(hdev); - if (ret) - goto err_out; - hdev->flag &= ~HCLGE_FLAG_DCB_ENABLE;
if (tc > 1)
From: Jian Shen shenjian15@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
If client is unregistered, it's shouldn't change the tc mqprio configuration, which may cause uninit ring fail.
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index bf2f43281fda1..ef264a80b1871 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c @@ -379,6 +379,13 @@ static int hclge_setup_tc(struct hnae3_handle *h, u8 tc, u8 *prio_tc) struct hclge_dev *hdev = vport->back; int ret;
+ /* if client unregistered, it's not allowed to change + * mqprio configuration, which may cause uninit ring + * fail. + */ + if (!test_bit(HCLGE_STATE_NIC_REGISTERED, &hdev->state)) + return -EBUSY; + if (hdev->flag & HCLGE_FLAG_DCB_ENABLE) return -EINVAL;
From: Guangbin Huang huangguangbin2@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
Function hclge_setup_tc() will modify tc number, as all queues are equally allocated to each tc, queues number of each tc will be changed. As rss indirection table is just for one tc, so it needs to be changed too.
Signed-off-by: Guangbin Huang huangguangbin2@huawei.com Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index ef264a80b1871..d9b69a9c707d7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c @@ -404,6 +404,11 @@ static int hclge_setup_tc(struct hnae3_handle *h, u8 tc, u8 *prio_tc) if (ret) goto err_out;
+ hclge_rss_indir_init_cfg(hdev); + ret = hclge_rss_init_hw(hdev); + if (ret) + goto err_out; + hdev->flag &= ~HCLGE_FLAG_DCB_ENABLE;
if (tc > 1)
From: Barry Song song.bao.hua@hisilicon.com
mainline inclusion from mainline-v5.9-rc1 commit e99a308da3c1518009a740c4d3962f616edeb642 category: bugfix bugzilla: NA CVE: NA
----------------------------
disable_irq() after request_irq() is still risk as there is a chance irq can come after request_irq() and before disable_irq(). this should be done by IRQ_NOAUTOEN flag.
Signed-off-by: Barry Song song.bao.hua@hisilicon.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 1db68d60794dd..6ff3ddcf06209 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -6,6 +6,7 @@ #include <linux/interrupt.h> #include <linux/cpu_rmap.h> #include <linux/if_vlan.h> +#include <linux/irq.h> #include <linux/ip.h> #include <linux/ipv6.h> #include <linux/module.h> @@ -155,6 +156,7 @@ static int hns3_nic_init_irq(struct hns3_nic_priv *priv)
tqp_vectors->name[HNAE3_INT_NAME_LEN - 1] = '\0';
+ irq_set_status_flags(tqp_vectors->vector_irq, IRQ_NOAUTOEN); ret = request_irq(tqp_vectors->vector_irq, hns3_irq_handle, 0, tqp_vectors->name, tqp_vectors); if (ret) { @@ -164,8 +166,6 @@ static int hns3_nic_init_irq(struct hns3_nic_priv *priv) return ret; }
- disable_irq(tqp_vectors->vector_irq); - irq_set_affinity_hint(tqp_vectors->vector_irq, &tqp_vectors->affinity_mask);
From: Jian Shen shenjian15@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
Currently, the netdevice is registered before client initializing complete. So there is a timewindow between netdevice available and usable. In this case, if user try to change the channel number or ring param, it may cause the hns3_set_rx_cpu_rmap() being called twice, and report bug.
[47199.416502] hns3 0000:35:00.0 eth1: set channels: tqp_num=1, rxfh=0 [47199.430340] hns3 0000:35:00.0 eth1: already uninitialized [47199.438554] hns3 0000:35:00.0: rss changes from 4 to 1 [47199.511854] hns3 0000:35:00.0: Channels changed, rss_size from 4 to 1, tqps from 4 to 1 [47200.163524] ------------[ cut here ]------------ [47200.171674] kernel BUG at lib/cpu_rmap.c:142! [47200.177847] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP [47200.185259] Modules linked in: hclge(+) hns3(-) hns3_cae(O) hns_roce_hw_v2 hnae3 vfio_iommu_type1 vfio_pci vfio_virqfd vfio pv680_mii(O) [last unloaded: hclge] [47200.205912] CPU: 1 PID: 8260 Comm: ethtool Tainted: G O 5.11.0-rc3+ #1 [47200.215601] Hardware name: , xxxxxx 02/04/2021 [47200.223052] pstate: 60400009 (nZCv daif +PAN -UAO -TCO BTYPE=--) [47200.230188] pc : cpu_rmap_add+0x38/0x40 [47200.237472] lr : irq_cpu_rmap_add+0x84/0x140 [47200.243291] sp : ffff800010e93a30 [47200.247295] x29: ffff800010e93a30 x28: ffff082100584880 [47200.254155] x27: 0000000000000000 x26: 0000000000000000 [47200.260712] x25: 0000000000000000 x24: 0000000000000004 [47200.267241] x23: ffff08209ba03000 x22: ffff08209ba038c0 [47200.273789] x21: 000000000000003f x20: ffff0820e2bc1680 [47200.280400] x19: ffff0820c970ec80 x18: 00000000000000c0 [47200.286944] x17: 0000000000000000 x16: ffffb43debe4a0d0 [47200.293456] x15: fffffc2082990600 x14: dead000000000122 [47200.300059] x13: ffffffffffffffff x12: 000000000000003e [47200.306606] x11: ffff0820815b8080 x10: ffff53e411988000 [47200.313171] x9 : 0000000000000000 x8 : ffff0820e2bc1700 [47200.319682] x7 : 0000000000000000 x6 : 000000000000003f [47200.326170] x5 : 0000000000000040 x4 : ffff800010e93a20 [47200.332656] x3 : 0000000000000004 x2 : ffff0820c970ec80 [47200.339168] x1 : ffff0820e2bc1680 x0 : 0000000000000004 [47200.346058] Call trace: [47200.349324] cpu_rmap_add+0x38/0x40 [47200.354300] hns3_set_rx_cpu_rmap+0x6c/0xe0 [hns3] [47200.362294] hns3_reset_notify_init_enet+0x1cc/0x340 [hns3] [47200.370049] hns3_change_channels+0x40/0xb0 [hns3] [47200.376770] hns3_set_channels+0x12c/0x2a0 [hns3] [47200.383353] ethtool_set_channels+0x140/0x250 [47200.389772] dev_ethtool+0x714/0x23d0 [47200.394440] dev_ioctl+0x4cc/0x640 [47200.399277] sock_do_ioctl+0x100/0x2a0 [47200.404574] sock_ioctl+0x28c/0x470 [47200.409079] __arm64_sys_ioctl+0xb4/0x100 [47200.415217] el0_svc_common.constprop.0+0x84/0x210 [47200.422088] do_el0_svc+0x28/0x34 [47200.426387] el0_svc+0x28/0x70 [47200.431308] el0_sync_handler+0x1a4/0x1b0 [47200.436477] el0_sync+0x174/0x180 [47200.441562] Code: 11000405 79000c45 f8247861 d65f03c0 (d4210000) [47200.448869] ---[ end trace a01efe4ce42e5f34 ]---
The process is like below: excuting hns3_client_init | register_netdev() | hns3_set_channels() | | hns3_set_rx_cpu_rmap() hns3_reset_notify_uninit_enet() | | | quit without calling function | hns3_free_rx_cpu_rmap for flag | HNS3_NIC_STATE_INITED is unset. | | | hns3_reset_notify_init_enet() | | set HNS3_NIC_STATE_INITED call hns3_set_rx_cpu_rmap()-- crash
Fix it by calling register_netdev() at the end of function hns3_client_init().
Fixes: 08a100689d4b ("net: hns3: re-organize vector handle")
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 6ff3ddcf06209..263cb76f7e3f9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -4051,6 +4051,13 @@ static void hns3_info_show(struct hns3_nic_priv *priv) dev_info(priv->dev, "Max mtu size: %u\n", priv->netdev->max_mtu); }
+static void hns3_state_uninit(struct hnae3_handle *handle) +{ + struct hns3_nic_priv *priv = handle->priv; + + clear_bit(HNS3_NIC_STATE_INITED, &priv->state); +} + static int hns3_client_init(struct hnae3_handle *handle) { struct pci_dev *pdev = handle->pdev; @@ -4118,12 +4125,6 @@ static int hns3_client_init(struct hnae3_handle *handle) if (ret) goto out_init_phy;
- ret = register_netdev(netdev); - if (ret) { - dev_err(priv->dev, "probe register netdev fail!\n"); - goto out_reg_netdev_fail; - } - /* the device can work without cpu rmap, only aRFS needs it */ ret = hns3_set_rx_cpu_rmap(netdev); if (ret) @@ -4153,17 +4154,25 @@ static int hns3_client_init(struct hnae3_handle *handle)
set_bit(HNS3_NIC_STATE_INITED, &priv->state);
+ ret = register_netdev(netdev); + if (ret) { + dev_err(priv->dev, "probe register netdev fail!\n"); + goto out_reg_netdev_fail; + } + if (netif_msg_drv(handle)) hns3_info_show(priv);
return ret;
+out_reg_netdev_fail: + hns3_state_uninit(handle); + hns3_dbg_uninit(handle); + hns3_client_stop(handle); out_client_start: hns3_free_rx_cpu_rmap(netdev); hns3_nic_uninit_irq(priv); out_init_irq_fail: - unregister_netdev(netdev); -out_reg_netdev_fail: hns3_uninit_phy(netdev); out_init_phy: hns3_uninit_all_ring(priv);
From: Yufeng Mo moyufeng@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
According to the UM, the error configuration of the igu_egu_hw_err is that the type and enable status should be configured separately. The error type is also changed by mistake when we disable it currently. The correct way is to configure these two parameters separately.
Signed-off-by: Yufeng Mo moyufeng@huawei.com Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c | 3 ++- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c index 9bb6900639f6f..9338f030842cb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c @@ -753,8 +753,9 @@ static int hclge_config_igu_egu_hw_err_int(struct hclge_dev *hdev, bool en)
/* configure IGU,EGU error interrupts */ hclge_cmd_setup_basic_desc(&desc, HCLGE_IGU_COMMON_INT_EN, false); + desc.data[0] = cpu_to_le32(HCLGE_IGU_ERR_INT_TYPE); if (en) - desc.data[0] = cpu_to_le32(HCLGE_IGU_ERR_INT_EN); + desc.data[0] |= cpu_to_le32(HCLGE_IGU_ERR_INT_EN);
desc.data[1] = cpu_to_le32(HCLGE_IGU_ERR_INT_EN_MASK);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h index 359270c652c10..67e972a25f47b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h @@ -36,7 +36,8 @@ #define HCLGE_TQP_ECC_ERR_INT_EN_MASK 0x0FFF #define HCLGE_MSIX_SRAM_ECC_ERR_INT_EN_MASK 0x0F000000 #define HCLGE_MSIX_SRAM_ECC_ERR_INT_EN 0x0F000000 -#define HCLGE_IGU_ERR_INT_EN 0x0000066F +#define HCLGE_IGU_ERR_INT_EN 0x0000000F +#define HCLGE_IGU_ERR_INT_TYPE 0x00000660 #define HCLGE_IGU_ERR_INT_EN_MASK 0x000F #define HCLGE_IGU_TNL_ERR_INT_EN 0x0002AABF #define HCLGE_IGU_TNL_ERR_INT_EN_MASK 0x003F
From: Yonglong Liu liuyonglong@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
This patch adds missing header guard to the hns3_cae_pfc_storm.h.
Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- .../ethernet/hisilicon/hns3/hns3_cae/hns3_cae_pfc_storm.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_pfc_storm.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_pfc_storm.h index ff0cc359bf07c..2d3f5e866ac64 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_pfc_storm.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_pfc_storm.h @@ -1,6 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* Copyright (c) 2016-2019 Hisilicon Limited. */
+#ifndef __HNS3_CAE_PFC_STORM_H__ +#define __HNS3_CAE_PFC_STORM_H__ + #include "hns3_cae_cmd.h" #include "hns3_enet.h"
@@ -27,3 +30,5 @@ struct cmd_pfc_storm_param { int hns3_cae_pfc_storm_cfg(const struct hns3_nic_priv *net_priv, void *buf_in, u32 in_size, void *buf_out, u32 out_size); + +#endif
From: Yonglong Liu liuyonglong@huawei.com
driver inclusion category: cleanup bugzilla: NA CVE: NA
----------------------------
Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 635f72af3e4df..9b3e69d01685d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -1649,7 +1649,7 @@ static int hclge_map_tqp(struct hclge_dev *hdev) u16 i, num_vport;
num_vport = hdev->num_vmdq_vport + hdev->num_req_vfs + 1; - for (i = 0; i < num_vport; i++) { + for (i = 0; i < num_vport; i++) { int ret;
ret = hclge_map_tqp_to_vport(hdev, vport);
From: Yonglong Liu liuyonglong@huawei.com
driver inclusion category: cleanup bugzilla: NA CVE: NA
----------------------------
Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_cmd.c | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_init.c | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_cmd.c index 345d351fd0faa..10ae1eee1ab90 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_cmd.c @@ -171,7 +171,7 @@ int hns3_cae_cmd_send(struct hclge_dev *hdev, struct hclge_desc *desc, int num) bool complete = false; u32 timeout = 0; int handle = 0; - int retval = 0; + int retval; int ntc;
csq = &hdev->hw.cmq.csq; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_init.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_init.c index 1e012917e0102..b84c85913d465 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_init.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_init.c @@ -413,7 +413,7 @@ static const struct file_operations fifo_operations = { static int if_hns3_cae_exist(void) { struct file *fp = NULL; - int exist = 0; + int exist;
fp = filp_open("/dev/nic_dev", O_RDONLY, 0); if (IS_ERR(fp)) { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index 5fe7b26a00352..a297653d452aa 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -19,7 +19,7 @@ static int hns3_dbg_queue_info(struct hnae3_handle *h, struct hns3_enet_ring *ring; u32 base_add_l, base_add_h; u32 queue_num, queue_max; - u32 value, i = 0; + u32 value, i; int cnt;
if (!priv->ring) { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c index d37cc190fd230..1e2aee01c8ff6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c @@ -279,7 +279,7 @@ int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num) bool complete = false; u32 timeout = 0; int handle = 0; - int retval = 0; + int retval; int ntc;
spin_lock_bh(&hw->cmq.csq.lock); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 9b3e69d01685d..d35c23e8e10cb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -620,7 +620,7 @@ static u8 *hclge_tqps_get_strings(struct hnae3_handle *handle, u8 *data) { struct hnae3_knic_private_info *kinfo = &handle->kinfo; u8 *buff = data; - int i = 0; + int i;
for (i = 0; i < kinfo->num_tqps; i++) { struct hclge_tqp *tqp = container_of(handle->kinfo.tqp[i], diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index b0a01ec866502..dbfb6a71824ce 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -172,7 +172,7 @@ static u8 *hclgevf_tqps_get_strings(struct hnae3_handle *handle, u8 *data) { struct hnae3_knic_private_info *kinfo = &handle->kinfo; u8 *buff = data; - int i = 0; + int i;
for (i = 0; i < kinfo->num_tqps; i++) { struct hclgevf_tqp *tqp = container_of(kinfo->tqp[i], @@ -1815,7 +1815,7 @@ static int hclgevf_reset_prepare_wait(struct hclgevf_dev *hdev)
if (hdev->reset_type == HNAE3_VF_FUNC_RESET) { struct hclge_vf_to_pf_msg send_msg; - int ret = 0; + int ret;
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_RESET, 0); ret = hclgevf_send_mbx_msg(hdev, &send_msg, true, NULL, 0);
From: Jian Shen shenjian15@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
The vf id from ethtool is added 1 before configured to driver. So it's necessary to minus 1 when printing it, in order to keep consistent with user's configuration.
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index d35c23e8e10cb..f9c1a18498c53 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5937,10 +5937,13 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle, u8 vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie); u16 tqps;
+ /* To keep consistent with user's configuration, minus 1 when + * printing 'vf', because vf id from ethtool is added 1 for vf. + */ if (vf > hdev->num_req_vfs) { dev_err(&hdev->pdev->dev, - "Error: vf id (%u) > max vf num (%u)\n", - vf, hdev->num_req_vfs); + "Error: vf id (%u) should be less than %u\n", + vf - 1, hdev->num_req_vfs); return -EINVAL; }
From: Jian Shen shenjian15@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
When user change rss 'hfunc' without set rss 'hkey' by ethtool -X command, the driver will ignore the 'hfunc' for the hkey is NULL. It's unreasonable. So fix it.
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- .../hisilicon/hns3/hns3pf/hclge_main.c | 47 +++++++++++------ .../hisilicon/hns3/hns3vf/hclgevf_main.c | 52 ++++++++++++------- 2 files changed, 65 insertions(+), 34 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index f9c1a18498c53..ce82da661c46f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4443,6 +4443,24 @@ static int hclge_get_rss(struct hnae3_handle *handle, u32 *indir, return 0; }
+static int hclge_parse_rss_hfunc(struct hclge_vport *vport, const u8 hfunc, + u8 *hash_algo) +{ + switch (hfunc) { + case ETH_RSS_HASH_TOP: + *hash_algo = HCLGE_RSS_HASH_ALGO_TOEPLITZ; + return 0; + case ETH_RSS_HASH_XOR: + *hash_algo = HCLGE_RSS_HASH_ALGO_SIMPLE; + return 0; + case ETH_RSS_HASH_NO_CHANGE: + *hash_algo = vport->rss_algo; + return 0; + default: + return -EINVAL; + } +} + static int hclge_set_rss(struct hnae3_handle *handle, const u32 *indir, const u8 *key, const u8 hfunc) { @@ -4451,30 +4469,27 @@ static int hclge_set_rss(struct hnae3_handle *handle, const u32 *indir, u8 hash_algo; int ret, i;
+ ret = hclge_parse_rss_hfunc(vport, hfunc, &hash_algo); + if (ret) { + dev_err(&hdev->pdev->dev, "invalid hfunc type %u\n", hfunc); + return ret; + } + /* Set the RSS Hash Key if specififed by the user */ if (key) { - switch (hfunc) { - case ETH_RSS_HASH_TOP: - hash_algo = HCLGE_RSS_HASH_ALGO_TOEPLITZ; - break; - case ETH_RSS_HASH_XOR: - hash_algo = HCLGE_RSS_HASH_ALGO_SIMPLE; - break; - case ETH_RSS_HASH_NO_CHANGE: - hash_algo = vport->rss_algo; - break; - default: - return -EINVAL; - } - ret = hclge_set_rss_algo_key(hdev, hash_algo, key); if (ret) return ret;
/* Update the shadow RSS key with user specified qids */ - memcpy(vport->rss_hash_key, key, HCLGE_RSS_KEY_SIZE); - vport->rss_algo = hash_algo; + memcpy(vport->rss_hash_key, key, sizeof(vport->rss_hash_key)); + } else { + ret = hclge_set_rss_algo_key(hdev, hash_algo, + vport->rss_hash_key); + if (ret) + return ret; } + vport->rss_algo = hash_algo;
/* Update the shadow RSS table with user specified qids */ for (i = 0; i < HCLGE_RSS_IND_TBL_SIZE; i++) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index dbfb6a71824ce..0ec7ac022b293 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -780,40 +780,56 @@ static int hclgevf_get_rss(struct hnae3_handle *handle, u32 *indir, u8 *key, return 0; }
+static int hclgevf_parse_rss_hfunc(struct hclgevf_dev *hdev, const u8 hfunc, + u8 *hash_algo) +{ + switch (hfunc) { + case ETH_RSS_HASH_TOP: + *hash_algo = HCLGEVF_RSS_HASH_ALGO_TOEPLITZ; + return 0; + case ETH_RSS_HASH_XOR: + *hash_algo = HCLGEVF_RSS_HASH_ALGO_SIMPLE; + return 0; + case ETH_RSS_HASH_NO_CHANGE: + *hash_algo = hdev->rss_cfg.hash_algo; + return 0; + default: + return -EINVAL; + } +} + static int hclgevf_set_rss(struct hnae3_handle *handle, const u32 *indir, const u8 *key, const u8 hfunc) { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); struct hclgevf_rss_cfg *rss_cfg = &hdev->rss_cfg; + u8 hash_algo; int ret, i;
if (handle->pdev->revision >= HNAE3_REVISION_ID_21) { + ret = hclgevf_parse_rss_hfunc(hdev, hfunc, &hash_algo); + if (ret) + return ret; + /* Set the RSS Hash Key if specififed by the user */ if (key) { - switch (hfunc) { - case ETH_RSS_HASH_TOP: - rss_cfg->hash_algo = - HCLGEVF_RSS_HASH_ALGO_TOEPLITZ; - break; - case ETH_RSS_HASH_XOR: - rss_cfg->hash_algo = - HCLGEVF_RSS_HASH_ALGO_SIMPLE; - break; - case ETH_RSS_HASH_NO_CHANGE: - break; - default: - return -EINVAL; - } - - ret = hclgevf_set_rss_algo_key(hdev, rss_cfg->hash_algo, - key); - if (ret) + ret = hclgevf_set_rss_algo_key(hdev, hash_algo, key); + if (ret) { + dev_err(&hdev->pdev->dev, + "invalid hfunc type %u\n", hfunc); return ret; + }
/* Update the shadow RSS key with user specified qids */ memcpy(rss_cfg->rss_hash_key, key, HCLGEVF_RSS_KEY_SIZE); + } else { + ret = hclgevf_set_rss_algo_key(hdev, hash_algo, + rss_cfg->rss_hash_key); + if (ret) + return ret; } + rss_cfg->hash_algo = hash_algo; }
/* update the shadow RSS table with user specified qids */
From: Guangbin Huang huangguangbin2@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
Currently, the firmware compatible features are enabled in PF driver initialization process, but they are not disabled in PF driver deinitialization process and firmware keeps these features in enabled status.
In this case, if load an old PF driver (for example, in VM) which not support the firmware compatible features, firmware will still send mailbox message to PF when link status changed and PF will print "un-supported mailbox message, code = 201".
To fix this problem, disable these firmware compatible features in PF driver deinitialization process.
Signed-off-by: Guangbin Huang huangguangbin2@huawei.com Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- .../ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c index 1e2aee01c8ff6..90d4d6ee3a8b0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c @@ -407,7 +407,7 @@ int hclge_cmd_queue_init(struct hclge_dev *hdev) }
/* ask the firmware to enable some features, driver can work without it. */ -static int hclge_firmware_compat_config(struct hclge_dev *hdev) +static int hclge_firmware_compat_config(struct hclge_dev *hdev, bool en) { struct hclge_firmware_compat_cmd *req; struct hclge_desc desc; @@ -415,11 +415,13 @@ static int hclge_firmware_compat_config(struct hclge_dev *hdev)
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_M7_COMPAT_CFG, false);
- req = (struct hclge_firmware_compat_cmd *)desc.data; + if (en) { + req = (struct hclge_firmware_compat_cmd *)desc.data;
- hnae3_set_bit(compat, HCLGE_LINK_EVENT_REPORT_EN_B, 1); - hnae3_set_bit(compat, HCLGE_NCSI_ERROR_REPORT_EN_B, 1); - req->compat = cpu_to_le32(compat); + hnae3_set_bit(compat, HCLGE_LINK_EVENT_REPORT_EN_B, 1); + hnae3_set_bit(compat, HCLGE_NCSI_ERROR_REPORT_EN_B, 1); + req->compat = cpu_to_le32(compat); + }
return hclge_cmd_send(&hdev->hw, &desc, 1); } @@ -473,7 +475,7 @@ int hclge_cmd_init(struct hclge_dev *hdev) /* ask the firmware to enable some features, driver can work without * it. */ - ret = hclge_firmware_compat_config(hdev); + ret = hclge_firmware_compat_config(hdev, true); if (ret) dev_warn(&hdev->pdev->dev, "Firmware compatible features not enabled(%d).\n", @@ -489,6 +491,8 @@ int hclge_cmd_init(struct hclge_dev *hdev)
void hclge_cmd_uninit(struct hclge_dev *hdev) { + hclge_firmware_compat_config(hdev, false); + spin_lock_bh(&hdev->hw.cmq.csq.lock); spin_lock(&hdev->hw.cmq.crq.lock); set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state);
From: Yufeng Mo moyufeng@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
After the cmdq registers are cleared, the firmware may take time to clear out possible left over commands in the cmdq. Driver must release cmdq memory only after firmware has completed processing of left over commands.
Signed-off-by: Yufeng Mo moyufeng@huawei.com Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c | 6 +++++- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 1 + drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c | 7 ++++++- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h | 1 + 4 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c index 90d4d6ee3a8b0..ea220cc88224c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c @@ -493,9 +493,13 @@ void hclge_cmd_uninit(struct hclge_dev *hdev) { hclge_firmware_compat_config(hdev, false);
+ set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state); + /* wait to ensure that the firmware completes the possible left + * over commands. + */ + msleep(HCLGE_CMDQ_CLEAR_WAIT_TIME); spin_lock_bh(&hdev->hw.cmq.csq.lock); spin_lock(&hdev->hw.cmq.crq.lock); - set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state); hclge_cmd_clear_regs(&hdev->hw); spin_unlock(&hdev->hw.cmq.crq.lock); spin_unlock_bh(&hdev->hw.cmq.csq.lock); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 362cca8ab127f..fd9368db3d3d9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -9,6 +9,7 @@ #include "hnae3.h"
#define HCLGE_CMDQ_TX_TIMEOUT 30000 +#define HCLGE_CMDQ_CLEAR_WAIT_TIME 200 #define HCLGE_DESC_DATA_LEN 6
struct hclge_dev; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c index 286d2291e5247..84f54a7c2e4d8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c @@ -448,12 +448,17 @@ int hclgevf_cmd_init(struct hclgevf_dev *hdev)
void hclgevf_cmd_uninit(struct hclgevf_dev *hdev) { + set_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state); + /* wait to ensure that the firmware completes the possible left + * over commands. + */ + msleep(HCLGEVF_CMDQ_CLEAR_WAIT_TIME); spin_lock_bh(&hdev->hw.cmq.csq.lock); spin_lock(&hdev->hw.cmq.crq.lock); - set_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state); hclgevf_cmd_clear_regs(&hdev->hw); spin_unlock(&hdev->hw.cmq.crq.lock); spin_unlock_bh(&hdev->hw.cmq.csq.lock); + hclgevf_free_cmd_desc(&hdev->hw.cmq.csq); hclgevf_free_cmd_desc(&hdev->hw.cmq.crq); } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h index 1f1500665e036..b2f5760b0b07e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h @@ -8,6 +8,7 @@ #include "hnae3.h"
#define HCLGEVF_CMDQ_TX_TIMEOUT 30000 +#define HCLGEVF_CMDQ_CLEAR_WAIT_TIME 200 #define HCLGEVF_CMDQ_RX_INVLD_B 0 #define HCLGEVF_CMDQ_RX_OUTVLD_B 1
From: Jian Shen shenjian15@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
In a small chance, a VF reset failed, and the VF device was not initialized. In the time window before it retry, if another task calls hns3_reset_notify_up_enet(), it will access uninitialized ring memory, and calltrace. So add check for HNS3_NIC_STATE_INITED before calling hns3_nic_net_open() in hns3_reset_notify_up_enet().
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 263cb76f7e3f9..212e1ceb15675 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -4426,6 +4426,11 @@ static int hns3_reset_notify_up_enet(struct hnae3_handle *handle) struct hns3_nic_priv *priv = netdev_priv(kinfo->netdev); int ret = 0;
+ if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state)) { + netdev_err(kinfo->netdev, "device is not initialized yet\n"); + return -EFAULT; + } + clear_bit(HNS3_NIC_STATE_RESETTING, &priv->state);
if (netif_running(kinfo->netdev)) {
From: Jian Shen shenjian15@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
Currently, when configure flow director rule, the driver uses the total queue number of each function, rather than the active queue number, as the upper limit value. It's inconsistent with the value query from "ethtool -u". So fixes it.
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index ce82da661c46f..f3d728aa54bf3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5963,7 +5963,7 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle, }
dst_vport_id = vf ? hdev->vport[vf].vport_id : vport->vport_id; - tqps = vf ? hdev->vport[vf].alloc_tqps : vport->alloc_tqps; + tqps = hdev->vport[vf].nic.kinfo.num_tqps;
if (ring >= tqps) { dev_err(&hdev->pdev->dev,
From: Jiaran Zhang zhangjiaran@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
In the hclge_mbx_handler function, if there are two consecutive mailbox messages that require resp_msg, the first message's resp_msg is not cleared after being processed, causing the second resp_msg data is incorrect.
Fix it by clearing the resp_msg before processing every mailbox message.
Fixes: bb5790b71bad ("net: hns3: refactor mailbox response scheme between PF and VF")
Signed-off-by: Jiaran Zhang zhangjiaran@huawei.com Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index ae1039f262478..6273f08fe2347 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -788,7 +788,6 @@ void hclge_mbx_handler(struct hclge_dev *hdev) unsigned int flag; int ret = 0;
- memset(&resp_msg, 0, sizeof(resp_msg)); /* handle all the mailbox requests in the queue */ while (!hclge_cmd_crq_empty(&hdev->hw)) { if (test_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state)) { @@ -816,6 +815,9 @@ void hclge_mbx_handler(struct hclge_dev *hdev)
trace_hclge_pf_mbx_get(hdev, req);
+ /* clear the resp_msg before processing every mailbox message */ + memset(&resp_msg, 0, sizeof(resp_msg)); + switch (req->msg.code) { case HCLGE_MBX_MAP_RING_TO_VECTOR: ret = hclge_map_unmap_ring_to_vf_vector(vport, true,
From: Chengwen Feng fengchengwen@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
Currently, the mailbox synchronous communication between VF and PF use the following fields to maintain communication: 1. Origin_mbx_msg which was combined by message code and subcode, used to match request and response. 2. Received_resp which means whether received response.
There may possible mismatches of the following situation: 1. VF sends message A with code=1 subcode=1. 2. PF was blocked about 500ms when processing the message A. 3. VF will detect message A timeout because it can't get the response within 500ms. 4. VF sends message B with code=1 subcode=1 which equal message A. 5. PF processes the first message A and send the response message to VF. 6. VF will identify the response matched the message B because the code/subcode is the same. This will lead to mismatch of request and response.
To fix the above bug, we use the following scheme: 1. The message sent from VF was labelled with match_id which was a unique 16-bit non-zero value. 2. The response sent from PF will label with match_id which got from the request. 3. The VF uses the match_id to match request and response message.
As for PF driver, it only needs to copy the match_id from request to response.
Fixes: dde1a86e93ca ("net: hns3: Add mailbox support to PF driver")
Signed-off-by: Chengwen Feng fengchengwen@huawei.com Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h | 6 ++++-- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 1 + 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index f273a8c30d56e..ace2b12252850 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -140,7 +140,8 @@ struct hclge_mbx_vf_to_pf_cmd { u8 mbx_need_resp; u8 rsv1[1]; u8 msg_len; - u8 rsv2[3]; + u8 rsv2; + u16 match_id; struct hclge_vf_to_pf_msg msg; };
@@ -150,7 +151,8 @@ struct hclge_mbx_pf_to_vf_cmd { u8 dest_vfid; u8 rsv[3]; u8 msg_len; - u8 rsv1[3]; + u8 rsv1; + u16 match_id; struct hclge_pf_to_vf_msg msg; };
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index 6273f08fe2347..e998322d59aae 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -70,6 +70,7 @@ static int hclge_gen_resp_to_vf(struct hclge_vport *vport,
resp_pf_to_vf->dest_vfid = vf_to_pf_req->mbx_src_vfid; resp_pf_to_vf->msg_len = vf_to_pf_req->msg_len; + resp_pf_to_vf->match_id = vf_to_pf_req->match_id; resp_pf_to_vf->msg.code = HCLGE_MBX_PF_VF_RESP; resp_pf_to_vf->msg.vf_mbx_msg_code = vf_to_pf_req->msg.code; resp_pf_to_vf->msg.vf_mbx_msg_subcode = vf_to_pf_req->msg.subcode;
From: Peng Li lipeng321@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------
When VF need response from PF, VF will wait (1us - 1s) to receive the response, or it will wait timeout and the VF action fails. If VF do not receive response in 1st action because timeout, the 2nd action may receive response for the 1st action, and get incorrect response data.VF must reciveve the right response from PF,or it will cause unexpected error.
This patch adds match_id to check mailbox response from PF to VF, to make sure VF get the right response: 1. The message sent from VF was labelled with match_id which was a unique 16-bit non-zero value. 2. The response sent from PF will label with match_id which got from the request. 3. The VF uses the match_id to match request and response message.
This scheme depends on the PF driver, if the PF driver don't support then VF will uses the original scheme.
PF driver adds match_id by the patch 430acf6 ("net: hns3: fix possible mismatches resp of mailbox").
Signed-off-by: Peng Li lipeng321@huawei.com Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- .../net/ethernet/hisilicon/hns3/hclge_mbx.h | 1 + .../hisilicon/hns3/hns3vf/hclgevf_mbx.c | 20 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index ace2b12252850..0234b676b9bd8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -91,6 +91,7 @@ struct hclgevf_mbx_resp_status { u32 origin_mbx_msg; bool received_resp; int resp_status; + u16 match_id; u8 additional_info[HCLGE_MBX_MAX_RESP_DATA_SIZE]; };
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c index 76fb37116cada..1af4d3a2348c2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c @@ -35,6 +35,7 @@ static int hclgevf_resp_to_errno(u16 resp_code) return -EIO; }
+#define HCLGEVF_MBX_MATCH_ID_START 1 static void hclgevf_reset_mbx_resp_status(struct hclgevf_dev *hdev) { /* this function should be called with mbx_resp.mbx_mutex held @@ -43,6 +44,10 @@ static void hclgevf_reset_mbx_resp_status(struct hclgevf_dev *hdev) hdev->mbx_resp.received_resp = false; hdev->mbx_resp.origin_mbx_msg = 0; hdev->mbx_resp.resp_status = 0; + hdev->mbx_resp.match_id++; + /* Update match_id and ensure the value of match_id is not zero */ + if (hdev->mbx_resp.match_id == 0) + hdev->mbx_resp.match_id = HCLGEVF_MBX_MATCH_ID_START; memset(hdev->mbx_resp.additional_info, 0, HCLGE_MBX_MAX_RESP_DATA_SIZE); }
@@ -137,6 +142,7 @@ int hclgevf_send_mbx_msg(struct hclgevf_dev *hdev, if (need_resp) { mutex_lock(&hdev->mbx_resp.mbx_mutex); hclgevf_reset_mbx_resp_status(hdev); + req->match_id = hdev->mbx_resp.match_id; status = hclgevf_cmd_send(&hdev->hw, &desc, 1); if (status) { dev_err(&hdev->pdev->dev, @@ -220,7 +226,6 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) dev_warn(&hdev->pdev->dev, "VF mbx resp flag not clear(%u)\n", req->msg.vf_mbx_msg_code); - resp->received_resp = true;
resp->origin_mbx_msg = (req->msg.vf_mbx_msg_code << 16); @@ -233,6 +238,19 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) resp->additional_info[i] = *temp; temp++; } + + if (req->match_id) { + /* If match_id is not zero, it means PF support + * match_id. If the match_id is right, VF get + * the right response, orignore the response, + * and driver will clear hdev->mbx_resp when + * send next message which need response. + */ + if (req->match_id == resp->match_id) + resp->received_resp = true; + } else { + resp->received_resp = true; + } break; case HCLGE_MBX_LINK_STAT_CHANGE: case HCLGE_MBX_ASSERTING_RESET:
From: Yonglong Liu liuyonglong@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
-----------------------------
This patch is used to update driver version to 1.9.38.12.
Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: li yongxin liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_version.h | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3_enet.h | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 2e4b5c099fb4e..e9fe1e6662905 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -30,7 +30,7 @@ #include <linux/pci.h> #include <linux/types.h>
-#define HNAE3_MOD_VERSION "1.9.38.11" +#define HNAE3_MOD_VERSION "1.9.38.12"
#define HNAE3_MIN_VECTOR_NUM 2 /* first one for misc, another for IO */
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_version.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_version.h index 20892a86599ab..7cbcf1485eadc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_version.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_version.h @@ -4,7 +4,7 @@ #ifndef __HNS3_CAE_VERSION_H__ #define __HNS3_CAE_VERSION_H__
-#define HNS3_CAE_MOD_VERSION "1.9.38.11" +#define HNS3_CAE_MOD_VERSION "1.9.38.12"
#define CMT_ID_LEN 8 #define RESV_LEN 3 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 88c843d562d0d..c984f0ebe1615 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -8,7 +8,7 @@
#include "hnae3.h"
-#define HNS3_MOD_VERSION "1.9.38.11" +#define HNS3_MOD_VERSION "1.9.38.12"
extern char hns3_driver_version[];
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index b84c2bdbdb3b2..8e7dff25cbfd5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -12,7 +12,7 @@ #include "hclge_cmd.h" #include "hnae3.h"
-#define HCLGE_MOD_VERSION "1.9.38.11" +#define HCLGE_MOD_VERSION "1.9.38.12" #define HCLGE_DRIVER_NAME "hclge"
#define HCLGE_MAX_PF_NUM 8 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index 17cf19719b151..786d73ed7042c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -10,7 +10,7 @@ #include "hclgevf_cmd.h" #include "hnae3.h"
-#define HCLGEVF_MOD_VERSION "1.9.38.11" +#define HCLGEVF_MOD_VERSION "1.9.38.12" #define HCLGEVF_DRIVER_NAME "hclgevf"
#define HCLGEVF_MAX_VLAN_ID 4095
From: Yu'an Wang wangyuan46@huawei.com
hulk inclusion category: Feature bugzilla: NA CVE: NA
Put all the code for the memory allocation into the QM initialization process. Before, The qp memory was allocated when the qp was created, and released when the qp was released, It is now changed to allocate all the qp memory once.
Signed-off-by: Yu'an Wang wangyuan46@huawei.com Signed-off-by: Weili Qian qianweili@huawei.com Signed-off-by: Shukun Tan tanshukun1@huawei.com Reviewed-by: Zhou Wang wangzhou1@hisilicon.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/crypto/hisilicon/hpre/hpre_main.c | 8 +- drivers/crypto/hisilicon/qm.c | 497 ++++++++++++---------- drivers/crypto/hisilicon/qm.h | 8 +- drivers/crypto/hisilicon/sec2/sec_main.c | 28 +- drivers/crypto/hisilicon/zip/zip_main.c | 24 +- 5 files changed, 289 insertions(+), 276 deletions(-)
diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 2ede8d78d222b..3732a5ffe1606 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -878,7 +878,8 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (!hpre) return -ENOMEM; qm = &hpre->qm; - qm->fun_type = pdev->is_physfn ? QM_HW_PF : QM_HW_VF; + qm->fun_type = (pdev->device == HPRE_PCI_DEVICE_ID) ? + QM_HW_PF : QM_HW_VF;
ret = hpre_qm_pre_init(qm, pdev); if (ret) @@ -896,11 +897,6 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_err(pdev, "Failed to init pf probe (%d)!\n", ret); goto err_with_qm_init; } - } else if (qm->fun_type == QM_HW_VF && qm->ver == QM_HW_V2) { - /* v2 starts to support get vft by mailbox */ - ret = hisi_qm_get_vft(qm, &qm->qp_base, &qm->qp_num); - if (ret) - goto err_with_qm_init; }
ret = hisi_qm_start(qm); diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 4d9429b34a152..410ca0e7a11ee 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -6,6 +6,7 @@ #include <linux/bitmap.h> #include <linux/debugfs.h> #include <linux/dma-mapping.h> +#include <linux/idr.h> #include <linux/io.h> #include <linux/irqreturn.h> #include <linux/log2.h> @@ -494,11 +495,6 @@ static u32 qm_get_irq_num_v2(struct hisi_qm *qm) return QM_IRQ_NUM_VF_V2; }
-static struct hisi_qp *qm_to_hisi_qp(struct hisi_qm *qm, struct qm_eqe *eqe) -{ - return qm->qp_array[le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK]; -} - static void qm_sq_head_update(struct hisi_qp *qp) { if (qp->qp_status.sq_head == QM_Q_DEPTH - 1) @@ -570,9 +566,8 @@ static void qm_work_process(struct work_struct *work)
while (QM_EQE_PHASE(eqe) == qm->status.eqc_phase) { eqe_num++; - qp = qm_to_hisi_qp(qm, eqe); - if (qp) - qm_poll_qp(qp, qm); + qp = &qm->qp_array[le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK]; + qm_poll_qp(qp, qm);
if (qm->status.eq_head == QM_EQ_DEPTH - 1) { qm->status.eqc_phase = !qm->status.eqc_phase; @@ -738,6 +733,8 @@ static void qm_init_qp_status(struct hisi_qp *qp) qp_status->sq_head = 0; qp_status->cq_head = 0; qp_status->cqc_phase = true; + atomic_set(&qp_status->used, 0); + atomic_set(&qp_status->send_ref, 0); }
static void qm_vft_data_cfg(struct hisi_qm *qm, enum vft_type type, u32 base, @@ -1250,62 +1247,54 @@ static void *qm_get_avail_sqe(struct hisi_qp *qp) return qp->sqe + sq_tail * qp->qm->sqe_size; }
+static void hisi_qm_unset_hw_reset(struct hisi_qp *qp) +{ + u64 *addr; + + /* Use last 32 bits of DUS to reset status. */ + addr = (u64 *)(qp->qdma.va + qp->qdma.size) - QM_RESET_STOP_TX_OFFSET; + *addr = 0; +} + static struct hisi_qp *hisi_qm_create_qp_nolock(struct hisi_qm *qm, u8 alg_type) { struct device *dev = &qm->pdev->dev; struct hisi_qp *qp; - int qp_id, ret; + int qp_id;
if (!qm_qp_avail_state(qm, NULL, QP_INIT)) return ERR_PTR(-EPERM);
- qp = kzalloc(sizeof(*qp), GFP_KERNEL); - if (!qp) - return ERR_PTR(-ENOMEM); - - qp_id = find_first_zero_bit(qm->qp_bitmap, qm->qp_num); - if (qp_id >= qm->qp_num) { - dev_info_ratelimited(&qm->pdev->dev, - "All %u queues of QM are busy!\n", - qm->qp_num); - ret = -EBUSY; - goto err_free_qp; + if (!qm->free_qp_num) { + dev_info_ratelimited(dev, "All %u queues of QM are busy!\n", + qm->qp_num); + return ERR_PTR(-EBUSY); } - set_bit(qp_id, qm->qp_bitmap); - qm->qp_array[qp_id] = qp; - qp->qm = qm;
- /* allocate qp dma memory, uacce uses dus region for this */ - qp->qdma.size = qm->sqe_size * QM_Q_DEPTH + - sizeof(struct cqe) * QM_Q_DEPTH; - /* one more page for device or qp statuses */ - qp->qdma.size = PAGE_ALIGN(qp->qdma.size) + PAGE_SIZE; - qp->qdma.va = dma_alloc_coherent(dev, qp->qdma.size, - &qp->qdma.dma, - GFP_KERNEL); - if (!qp->qdma.va) { - ret = -ENOMEM; - goto err_clear_bit; + qp_id = idr_alloc_cyclic(&qm->qp_idr, NULL, + 0, qm->qp_num, GFP_ATOMIC); + if (qp_id < 0) { + dev_info_ratelimited(dev, "All %u queues of QM are busy!\n", + qm->qp_num); + return ERR_PTR(-EBUSY); }
- dev_dbg(dev, "allocate qp dma buf size=%zx\n", qp->qdma.size); + qp = &qm->qp_array[qp_id]; + if (!qp->is_in_kernel) + hisi_qm_unset_hw_reset(qp);
- qp->qp_id = qp_id; + memset(qp->cqe, 0, sizeof(struct qm_cqe) * QM_Q_DEPTH); + qp->event_cb = NULL; + qp->req_cb = NULL; qp->alg_type = alg_type; qp->c_flag = 1; qp->is_in_kernel = true; init_completion(&qp->completion); + qm->free_qp_num--; atomic_set(&qp->qp_status.flags, QP_INIT);
return qp; - -err_clear_bit: - qm->qp_array[qp_id] = NULL; - clear_bit(qp_id, qm->qp_bitmap); -err_free_qp: - kfree(qp); - return ERR_PTR(ret); }
/** @@ -1337,22 +1326,14 @@ EXPORT_SYMBOL_GPL(hisi_qm_create_qp); void hisi_qm_release_qp(struct hisi_qp *qp) { struct hisi_qm *qm = qp->qm; - struct qm_dma *qdma = &qp->qdma; - struct device *dev = &qm->pdev->dev;
down_write(&qm->qps_lock); if (!qm_qp_avail_state(qm, qp, QP_CLOSE)) { up_write(&qm->qps_lock); return; } - if (qdma->va) - dma_free_coherent(dev, qdma->size, qdma->va, qdma->dma); - - dev_dbg(dev, "release qp %d\n", qp->qp_id); - qm->qp_array[qp->qp_id] = NULL; - clear_bit(qp->qp_id, qm->qp_bitmap); - - kfree(qp); + qm->free_qp_num++; + idr_remove(&qm->qp_idr, qp->qp_id); up_write(&qm->qps_lock); } EXPORT_SYMBOL_GPL(hisi_qm_release_qp); @@ -1454,32 +1435,11 @@ static int hisi_qm_start_qp_nolock(struct hisi_qp *qp, unsigned long arg) struct device *dev = &qm->pdev->dev; int qp_id = qp->qp_id; int pasid = arg; - size_t off = 0; int ret;
if (!qm_qp_avail_state(qm, qp, QP_START)) return -EPERM;
-#define QP_INIT_BUF(qp, type, size) do { \ - (qp)->type = ((qp)->qdma.va + (off)); \ - (qp)->type##_dma = (qp)->qdma.dma + (off); \ - off += (size); \ -} while (0) - - if (!qp->qdma.dma) { - dev_err(dev, "cannot get qm dma buffer\n"); - return -EINVAL; - } - - /* sq need 128 bytes alignment */ - if (qp->qdma.dma & QM_SQE_DATA_ALIGN_MASK) { - dev_err(dev, "qm sq is not aligned to 128 byte\n"); - return -EINVAL; - } - - QP_INIT_BUF(qp, sqe, qm->sqe_size * QM_Q_DEPTH); - QP_INIT_BUF(qp, cqe, sizeof(struct cqe) * QM_Q_DEPTH); - ret = qm_qp_ctx_cfg(qp, qp_id, pasid); if (ret) return ret; @@ -1708,12 +1668,10 @@ static void hisi_qm_cache_wb(struct hisi_qm *qm)
int hisi_qm_get_free_qp_num(struct hisi_qm *qm) { - int i, ret; + int ret;
down_read(&qm->qps_lock); - for (i = 0, ret = 0; i < qm->qp_num; i++) - if (!qm->qp_array[i]) - ret++; + ret = qm->free_qp_num; up_read(&qm->qps_lock);
return ret; @@ -1738,8 +1696,8 @@ static void hisi_qm_set_hw_reset(struct hisi_qm *qm, int offset) int i;
for (i = 0; i < qm->qp_num; i++) { - qp = qm->qp_array[i]; - if (qp) { + qp = &qm->qp_array[i]; + if (!qp->is_in_kernel) { /* Use last 32 bits of DUS to save reset status. */ addr = (u32 *)(qp->qdma.va + qp->qdma.size) - offset; *addr = 1; @@ -1914,6 +1872,27 @@ static enum uacce_dev_state hisi_qm_get_state(struct uacce *uacce) return UACCE_DEV_NORMAL; }
+static void hisi_qm_uacce_memory_init(struct hisi_qm *qm) +{ + unsigned long dus_page_nr, mmio_page_nr; + struct uacce *uacce = &qm->uacce; + + /* Add one more page for device or qp status */ + dus_page_nr = (PAGE_SIZE - 1 + qm->sqe_size * QM_Q_DEPTH + + sizeof(struct cqe) * QM_Q_DEPTH + PAGE_SIZE) >> + PAGE_SHIFT; + + if (qm->ver == QM_HW_V2) + mmio_page_nr = QM_DOORBELL_PAGE_NR + + QM_V2_DOORBELL_OFFSET / PAGE_SIZE; + else + mmio_page_nr = QM_DOORBELL_PAGE_NR; + + uacce->qf_pg_start[UACCE_QFRT_MMIO] = 0; + uacce->qf_pg_start[UACCE_QFRT_DUS] = mmio_page_nr; + uacce->qf_pg_start[UACCE_QFRT_SS] = mmio_page_nr + dus_page_nr; +} + /* * the device is set the UACCE_DEV_SVA, but it will be cut if SVA patch is not * available @@ -2005,22 +1984,22 @@ static int qm_unregister_uacce(struct hisi_qm *qm) */ static int hisi_qm_frozen(struct hisi_qm *qm) { - int count, i; - down_write(&qm->qps_lock); - for (i = 0, count = 0; i < qm->qp_num; i++) - if (!qm->qp_array[i]) - count++; + if (qm->is_frozen) { + up_write(&qm->qps_lock); + return 0; + }
- if (count == qm->qp_num) { - bitmap_set(qm->qp_bitmap, 0, qm->qp_num); - } else { + if (qm->free_qp_num == qm->qp_num) { + qm->free_qp_num = 0; + qm->is_frozen = true; up_write(&qm->qps_lock); - return -EBUSY; + return 0; } + up_write(&qm->qps_lock);
- return 0; + return -EBUSY; }
static int qm_try_frozen_vfs(struct pci_dev *pdev, @@ -2064,51 +2043,123 @@ void hisi_qm_remove_wait_delay(struct hisi_qm *qm, } EXPORT_SYMBOL_GPL(hisi_qm_remove_wait_delay);
-/** - * hisi_qm_init() - Initialize configures about qm. - * @qm: The qm needed init. - * - * This function init qm, then we can call hisi_qm_start to put qm into work. - */ -int hisi_qm_init(struct hisi_qm *qm) +static void hisi_qp_memory_uninit(struct hisi_qm *qm, int num) { - struct pci_dev *pdev = qm->pdev; - struct device *dev = &pdev->dev; - unsigned int num_vec; - int ret; + struct device *dev = &qm->pdev->dev; + struct qm_dma *qdma; + int i;
- switch (qm->ver) { - case QM_HW_V1: - qm->ops = &qm_hw_ops_v1; - break; - case QM_HW_V2: - qm->ops = &qm_hw_ops_v2; - break; - default: - return -EINVAL; + for (i = num - 1; i >= 0; i--) { + qdma = &qm->qp_array[i].qdma; + dma_free_coherent(dev, qdma->size, qdma->va, qdma->dma); }
+ kfree(qm->qp_array); +} + +static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id) +{ + struct device *dev = &qm->pdev->dev; + size_t off = qm->sqe_size * QM_Q_DEPTH; + struct hisi_qp *qp; + + qp = &qm->qp_array[id]; + qp->qdma.va = dma_alloc_coherent(dev, dma_size, + &qp->qdma.dma, GFP_KERNEL); + if (!qp->qdma.va) + return -ENOMEM; + + qp->sqe = qp->qdma.va; + qp->sqe_dma = qp->qdma.dma; + qp->cqe = qp->qdma.va + off; + qp->cqe_dma = qp->qdma.dma + off; + qp->qdma.size = dma_size; + qp->qm = qm; + qp->qp_id = id; + + return 0; +} + +static int hisi_qm_memory_init(struct hisi_qm *qm) +{ + struct device *dev = &qm->pdev->dev; + size_t qp_dma_size; + size_t off = 0; + int ret = 0; + int i; + +#define QM_INIT_BUF(qm, type, num) do { \ + (qm)->type = ((qm)->qdma.va + (off)); \ + (qm)->type##_dma = (qm)->qdma.dma + (off); \ + off += QMC_ALIGN(sizeof(struct qm_##type) * (num)); \ +} while (0) + + #ifdef CONFIG_CRYPTO_QM_UACCE - if (qm->use_uacce) { - dev_info(dev, "qm register to uacce\n"); - ret = qm_register_uacce(qm); - if (ret < 0) { - dev_err(dev, "fail to register uacce (%d)\n", ret); - return ret; - } - } + if (qm->use_uacce) + hisi_qm_uacce_memory_init(qm); #endif
+ idr_init(&qm->qp_idr); + qm->qdma.size = QMC_ALIGN(sizeof(struct qm_eqe) * QM_EQ_DEPTH) + + QMC_ALIGN(sizeof(struct qm_aeqe) * QM_Q_DEPTH) + + QMC_ALIGN(sizeof(struct qm_sqc) * qm->qp_num) + + QMC_ALIGN(sizeof(struct qm_cqc) * qm->qp_num); + qm->qdma.va = dma_alloc_coherent(dev, qm->qdma.size, + &qm->qdma.dma, GFP_ATOMIC | __GFP_ZERO); + dev_dbg(dev, "allocate qm dma buf size=%zx)\n", qm->qdma.size); + if (!qm->qdma.va) + return -ENOMEM; + + QM_INIT_BUF(qm, eqe, QM_EQ_DEPTH); + QM_INIT_BUF(qm, aeqe, QM_Q_DEPTH); + QM_INIT_BUF(qm, sqc, qm->qp_num); + QM_INIT_BUF(qm, cqc, qm->qp_num); + + qm->qp_array = kcalloc(qm->qp_num, sizeof(struct hisi_qp), GFP_KERNEL); + if (!qm->qp_array) { + ret = -ENOMEM; + goto err_alloc_qp_array; + } + + /* one more page for device or qp statuses */ + qp_dma_size = qm->sqe_size * QM_Q_DEPTH + + sizeof(struct cqe) * QM_Q_DEPTH; + qp_dma_size = PAGE_ALIGN(qp_dma_size) + PAGE_SIZE; + for (i = 0; i < qm->qp_num; i++) { + ret = hisi_qp_memory_init(qm, qp_dma_size, i); + if (ret) + goto err_init_qp_mem; + + dev_dbg(dev, "allocate qp dma buf size=%zx)\n", qp_dma_size); + } + + return ret; +err_init_qp_mem: + hisi_qp_memory_uninit(qm, i); +err_alloc_qp_array: + dma_free_coherent(dev, qm->qdma.size, + qm->qdma.va, qm->qdma.dma); + return ret; +} + +static int hisi_qm_pci_init(struct hisi_qm *qm) +{ + struct pci_dev *pdev = qm->pdev; + struct device *dev = &pdev->dev; + unsigned int num_vec; + int ret; + ret = pci_enable_device_mem(pdev); if (ret < 0) { dev_err(&pdev->dev, "Failed to enable device mem!\n"); - goto err_unregister_uacce; + return ret; }
ret = pci_request_mem_regions(pdev, qm->dev_name); if (ret < 0) { dev_err(&pdev->dev, "Failed to request mem regions!\n"); - goto err_disable_pcidev; + goto err_request_mem_regions; }
#ifdef CONFIG_CRYPTO_QM_UACCE @@ -2119,13 +2170,13 @@ int hisi_qm_init(struct hisi_qm *qm) pci_resource_len(qm->pdev, PCI_BAR_2)); if (!qm->io_base) { ret = -EIO; - goto err_release_mem_regions; + goto err_ioremap; }
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); if (ret < 0) { dev_err(dev, "Failed to set 64 bit dma mask %d", ret); - goto err_iounmap; + goto err_set_mask_and_coherent; } pci_set_master(pdev);
@@ -2133,14 +2184,88 @@ int hisi_qm_init(struct hisi_qm *qm) ret = pci_alloc_irq_vectors(pdev, num_vec, num_vec, PCI_IRQ_MSI); if (ret < 0) { dev_err(dev, "Failed to enable MSI vectors!\n"); - goto err_iounmap; + goto err_set_mask_and_coherent; }
+ return 0; + +err_set_mask_and_coherent: + devm_iounmap(dev, qm->io_base); +err_ioremap: + pci_release_mem_regions(pdev); +err_request_mem_regions: + pci_disable_device(pdev); + return ret; +} + +static void hisi_qm_pci_uninit(struct hisi_qm *qm) +{ + struct pci_dev *pdev = qm->pdev; + struct device *dev = &pdev->dev; + + pci_free_irq_vectors(pdev); + devm_iounmap(dev, qm->io_base); + pci_release_mem_regions(pdev); + pci_disable_device(pdev); +} + +/** + * hisi_qm_init() - Initialize configures about qm. + * @qm: The qm needed init. + * + * This function init qm, then we can call hisi_qm_start to put qm into work. + */ +int hisi_qm_init(struct hisi_qm *qm) +{ + struct pci_dev *pdev = qm->pdev; + struct device *dev = &pdev->dev; + int ret; + + switch (qm->ver) { + case QM_HW_V1: + qm->ops = &qm_hw_ops_v1; + break; + case QM_HW_V2: + qm->ops = &qm_hw_ops_v2; + break; + default: + return -EINVAL; + } + +#ifdef CONFIG_CRYPTO_QM_UACCE + if (qm->use_uacce) { + dev_info(dev, "qm register to uacce\n"); + ret = qm_register_uacce(qm); + if (ret < 0) { + dev_err(dev, "fail to register uacce (%d)\n", ret); + return ret; + } + } +#endif + + ret = hisi_qm_pci_init(qm); + if (ret) + goto err_pci_init; + ret = qm_irq_register(qm); if (ret) - goto err_free_irq_vectors; + goto err_irq_register;
mutex_init(&qm->mailbox_lock); + if (qm->fun_type == QM_HW_VF && qm->ver == QM_HW_V2) { + /* v2 or v3 starts to support get vft by mailbox */ + ret = hisi_qm_get_vft(qm, &qm->qp_base, &qm->qp_num); + if (ret) + goto err_get_vft; + } + + ret = hisi_qm_memory_init(qm); + if (ret) + goto err_get_vft; + + qm->free_qp_num = qm->qp_num; + qm->is_frozen = false; + init_rwsem(&qm->qps_lock); atomic_set(&qm->status.flags, QM_INIT); INIT_WORK(&qm->work, qm_work_process); @@ -2149,15 +2274,11 @@ int hisi_qm_init(struct hisi_qm *qm)
return 0;
-err_free_irq_vectors: - pci_free_irq_vectors(pdev); -err_iounmap: - devm_iounmap(dev, qm->io_base); -err_release_mem_regions: - pci_release_mem_regions(pdev); -err_disable_pcidev: - pci_disable_device(pdev); -err_unregister_uacce: +err_get_vft: + qm_irq_unregister(qm); +err_irq_register: + hisi_qm_pci_uninit(qm); +err_pci_init: #ifdef CONFIG_CRYPTO_QM_UACCE if (qm->use_uacce) qm_unregister_uacce(qm); @@ -2183,6 +2304,10 @@ void hisi_qm_uninit(struct hisi_qm *qm) up_write(&qm->qps_lock); return; } + + hisi_qp_memory_uninit(qm, qm->qp_num); + idr_destroy(&qm->qp_idr); + /* qm hardware buffer free on put_queue if no dma api */ if (qm->qdma.va) { hisi_qm_cache_wb(qm); @@ -2192,15 +2317,14 @@ void hisi_qm_uninit(struct hisi_qm *qm) }
qm_irq_unregister(qm); - pci_free_irq_vectors(pdev); - pci_release_mem_regions(pdev); - pci_disable_device(pdev); + hisi_qm_pci_uninit(qm); + + up_write(&qm->qps_lock);
#ifdef CONFIG_CRYPTO_QM_UACCE if (qm->use_uacce) uacce_unregister(&qm->uacce); #endif - up_write(&qm->qps_lock); } EXPORT_SYMBOL_GPL(hisi_qm_uninit);
@@ -2358,15 +2482,8 @@ static int qm_eq_aeq_ctx_cfg(struct hisi_qm *qm)
static int __hisi_qm_start(struct hisi_qm *qm) { - size_t off = 0; int ret;
-#define QM_INIT_BUF(qm, type, num) do { \ - (qm)->type = ((qm)->qdma.va + (off)); \ - (qm)->type##_dma = (qm)->qdma.dma + (off); \ - off += QMC_ALIGN(sizeof(struct qm_##type) * (num)); \ -} while (0) - /* dma must be ready before start, nomatter by init or by uacce mmap */ WARN_ON(!qm->qdma.dma);
@@ -2383,11 +2500,6 @@ static int __hisi_qm_start(struct hisi_qm *qm) return ret; }
- QM_INIT_BUF(qm, eqe, QM_EQ_DEPTH); - QM_INIT_BUF(qm, aeqe, QM_Q_DEPTH); - QM_INIT_BUF(qm, sqc, qm->qp_num); - QM_INIT_BUF(qm, cqc, qm->qp_num); - ret = qm_eq_aeq_ctx_cfg(qm); if (ret) return ret; @@ -2419,9 +2531,9 @@ int hisi_qm_restart(struct hisi_qm *qm)
down_write(&qm->qps_lock); for (i = 0; i < qm->qp_num; i++) { - qp = qm->qp_array[i]; + qp = &qm->qp_array[i];
- if (qp && atomic_read(&qp->qp_status.flags) == QP_STOP && + if (atomic_read(&qp->qp_status.flags) == QP_STOP && qp->is_resetting && qp->is_in_kernel) { ret = hisi_qm_start_qp_nolock(qp, 0); if (ret < 0) { @@ -2447,14 +2559,6 @@ EXPORT_SYMBOL_GPL(hisi_qm_restart); */ int hisi_qm_start(struct hisi_qm *qm) { - struct device *dev = &qm->pdev->dev; - -#ifdef CONFIG_CRYPTO_QM_UACCE - struct uacce *uacce = &qm->uacce; - unsigned long dus_page_nr = 0; - unsigned long dko_page_nr = 0; - unsigned long mmio_page_nr; -#endif int ret;
down_write(&qm->qps_lock); @@ -2464,77 +2568,10 @@ int hisi_qm_start(struct hisi_qm *qm) return -EPERM; }
-#ifdef CONFIG_CRYPTO_QM_UACCE - if (qm->use_uacce) { - /* Add one more page for device or qp status */ - dus_page_nr = (PAGE_SIZE - 1 + qm->sqe_size * QM_Q_DEPTH + - sizeof(struct cqe) * QM_Q_DEPTH + PAGE_SIZE) >> - PAGE_SHIFT; - dko_page_nr = (PAGE_SIZE - 1 + - QMC_ALIGN(sizeof(struct qm_eqe) * QM_EQ_DEPTH) + - QMC_ALIGN(sizeof(struct qm_aeqe) * QM_Q_DEPTH) + - QMC_ALIGN(sizeof(struct qm_sqc) * qm->qp_num) + - QMC_ALIGN(sizeof(struct qm_cqc) * qm->qp_num) + - /* let's reserve one page for possible usage */ - PAGE_SIZE) >> PAGE_SHIFT; - } -#endif - - dev_dbg(dev, "qm start with %d queue pairs\n", qm->qp_num); - - if (!qm->qp_num) { - dev_err(dev, "qp_num should not be 0\n"); - ret = -EINVAL; - goto err_unlock; - } - - /* reset qfr definition */ -#ifdef CONFIG_CRYPTO_QM_UACCE - if (qm->ver == QM_HW_V2) - mmio_page_nr = QM_DOORBELL_PAGE_NR + - QM_V2_DOORBELL_OFFSET / PAGE_SIZE; - else - mmio_page_nr = QM_DOORBELL_PAGE_NR; - - if (qm->use_uacce) { - uacce->qf_pg_start[UACCE_QFRT_MMIO] = 0; - uacce->qf_pg_start[UACCE_QFRT_DUS] = mmio_page_nr; - uacce->qf_pg_start[UACCE_QFRT_SS] = mmio_page_nr + dus_page_nr; - } -#endif - - if (!qm->qp_bitmap) { - qm->qp_bitmap = devm_kcalloc(dev, BITS_TO_LONGS(qm->qp_num), - sizeof(long), GFP_ATOMIC); - qm->qp_array = devm_kcalloc(dev, qm->qp_num, - sizeof(struct hisi_qp *), - GFP_ATOMIC); - if (!qm->qp_bitmap || !qm->qp_array) { - ret = -ENOMEM; - goto err_unlock; - } - } - - if (!qm->qdma.va) { - qm->qdma.size = QMC_ALIGN(sizeof(struct qm_eqe) * QM_EQ_DEPTH) + - QMC_ALIGN(sizeof(struct qm_aeqe) * QM_Q_DEPTH) + - QMC_ALIGN(sizeof(struct qm_sqc) * qm->qp_num) + - QMC_ALIGN(sizeof(struct qm_cqc) * qm->qp_num); - qm->qdma.va = dma_alloc_coherent(dev, qm->qdma.size, - &qm->qdma.dma, - GFP_ATOMIC | __GFP_ZERO); - dev_dbg(dev, "allocate qm dma buf size=%zx\n", qm->qdma.size); - if (!qm->qdma.va) { - ret = -ENOMEM; - goto err_unlock; - } - } - ret = __hisi_qm_start(qm); if (!ret) atomic_set(&qm->status.flags, QM_START);
-err_unlock: up_write(&qm->qps_lock); return ret; } @@ -2548,8 +2585,8 @@ static int qm_stop_started_qp(struct hisi_qm *qm) int i, ret;
for (i = 0; i < qm->qp_num; i++) { - qp = qm->qp_array[i]; - if (qp && atomic_read(&qp->qp_status.flags) == QP_START) { + qp = &qm->qp_array[i]; + if (atomic_read(&qp->qp_status.flags) == QP_START) { qp->is_resetting = true; ret = hisi_qm_stop_qp_nolock(qp); if (ret < 0) { @@ -2575,8 +2612,8 @@ static void qm_clear_queues(struct hisi_qm *qm) int i;
for (i = 0; i < qm->qp_num; i++) { - qp = qm->qp_array[i]; - if (qp && qp->is_in_kernel) + qp = &qm->qp_array[i]; + if (qp->is_in_kernel && qp->is_resetting) /* device state use the last page */ memset(qp->qdma.va, 0, qp->qdma.size - PAGE_SIZE); } diff --git a/drivers/crypto/hisilicon/qm.h b/drivers/crypto/hisilicon/qm.h index 79e29ee6219a9..06ad9f0694498 100644 --- a/drivers/crypto/hisilicon/qm.h +++ b/drivers/crypto/hisilicon/qm.h @@ -97,6 +97,7 @@ enum qm_stop_reason { QM_SOFT_RESET, QM_FLR, }; + enum qm_state { QM_INIT = 0, QM_START, @@ -287,6 +288,7 @@ struct hisi_qm { u32 qp_num; u32 ctrl_q_num; u32 vfs_num; + u32 free_qp_num; struct list_head list; struct hisi_qm_list *qm_list; struct qm_dma qdma; @@ -302,8 +304,8 @@ struct hisi_qm { struct hisi_qm_status status; struct hisi_qm_err_ini err_ini; struct rw_semaphore qps_lock; - unsigned long *qp_bitmap; - struct hisi_qp **qp_array; + struct idr qp_idr; + struct hisi_qp *qp_array;
struct mutex mailbox_lock;
@@ -316,6 +318,7 @@ struct hisi_qm { unsigned long hw_status; bool use_uacce; /* register to uacce */ bool use_sva; + bool is_frozen;
#ifdef CONFIG_CRYPTO_QM_UACCE resource_size_t phys_base; @@ -332,6 +335,7 @@ struct hisi_qm {
struct hisi_qp_status { atomic_t used; + atomic_t send_ref; u16 sq_tail; u16 sq_head; u16 cq_head; diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index 561c99284efba..b50ed43a6ef6f 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -790,25 +790,6 @@ static int sec_probe_init(struct hisi_qm *qm) ret = sec_pf_probe_init(qm); if (ret) goto err_probe_uninit; - } else if (qm->fun_type == QM_HW_VF) { - /* - * have no way to get qm configure in VM in v1 hardware, - * so currently force PF to uses SEC_PF_DEF_Q_NUM, and force - * to trigger only one VF in v1 hardware. - * v2 hardware has no such problem. - */ - if (qm->ver == QM_HW_V1) { - qm->qp_base = SEC_PF_DEF_Q_NUM; - qm->qp_num = SEC_QUEUE_NUM_V1 - SEC_PF_DEF_Q_NUM; - } else if (qm->ver == QM_HW_V2) { - /* v2 starts to support get vft by mailbox */ - ret = hisi_qm_get_vft(qm, &qm->qp_base, &qm->qp_num); - if (ret) - goto err_probe_uninit; - } - } else { - ret = -ENODEV; - goto err_probe_uninit; }
return 0; @@ -873,7 +854,8 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM;
qm = &sec->qm; - qm->fun_type = pdev->is_physfn ? QM_HW_PF : QM_HW_VF; + qm->fun_type = (pdev->device == SEC_PF_PCI_DEVICE_ID) ? + QM_HW_PF : QM_HW_VF;
ret = sec_qm_pre_init(qm, pdev); if (ret) @@ -881,6 +863,12 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sec->ctx_q_num = ctx_q_num; sec_iommu_used_check(sec); + + if (qm->fun_type == QM_HW_VF && qm->ver == QM_HW_V1) { + qm->qp_base = SEC_PF_DEF_Q_NUM; + qm->qp_num = SEC_QUEUE_NUM_V1 - SEC_PF_DEF_Q_NUM; + } + ret = hisi_qm_init(qm); if (ret) { pci_err(pdev, "Failed to init qm (%d)!\n", ret); diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 15ba6d360db3f..0a6a95a0ad080 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -836,13 +836,18 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM;
qm = &zip->qm; - qm->fun_type = pdev->is_physfn ? QM_HW_PF : QM_HW_VF; + qm->fun_type = (pdev->device == PCI_DEVICE_ID_ZIP_PF) ? + QM_HW_PF : QM_HW_VF;
ret = hisi_zip_qm_pre_init(qm, pdev); if (ret) return ret;
hisi_qm_add_to_list(qm, &zip_devices); + if (qm->fun_type == QM_HW_VF && qm->ver == QM_HW_V1) { + qm->qp_base = HZIP_PF_DEF_Q_NUM; + qm->qp_num = HZIP_QUEUE_NUM_V1 - HZIP_PF_DEF_Q_NUM; + }
ret = hisi_qm_init(qm); if (ret) { @@ -856,23 +861,6 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_err(pdev, "Failed to init pf probe (%d)!\n", ret); goto err_remove_from_list; } - } else if (qm->fun_type == QM_HW_VF) { - /* - * have no way to get qm configure in VM in v1 hardware, - * so currently force PF to uses HZIP_PF_DEF_Q_NUM, and force - * to trigger only one VF in v1 hardware. - * - * v2 hardware has no such problem. - */ - if (qm->ver == QM_HW_V1) { - qm->qp_base = HZIP_PF_DEF_Q_NUM; - qm->qp_num = HZIP_QUEUE_NUM_V1 - HZIP_PF_DEF_Q_NUM; - } else if (qm->ver == QM_HW_V2) { - /* v2 starts to support get vft by mailbox */ - ret = hisi_qm_get_vft(qm, &qm->qp_base, &qm->qp_num); - if (ret) - goto err_remove_from_list; - } }
ret = hisi_qm_start(qm);
From: Yu'an Wang wangyuan46@huawei.com
hulk inclusion category: Feature bugzilla: NA CVE: NA
add DebugFS for xQC and xQE dump, user can use cmd to dump information of SQC/CQC/EQC/AEQC/SQE/CQE/EQE/AEQE.
Signed-off-by: Yu'an Wang wangyuan46@huawei.com Signed-off-by: Shukun Tan tanshukun1@huawei.com Reviewed-by: Zhou Wang wangzhou1@hisilicon.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/crypto/hisilicon/hpre/hpre_main.c | 5 + drivers/crypto/hisilicon/qm.c | 560 +++++++++++++++++++++- drivers/crypto/hisilicon/qm.h | 13 + drivers/crypto/hisilicon/rde/rde.h | 2 +- drivers/crypto/hisilicon/rde/rde_api.h | 6 +- drivers/crypto/hisilicon/sec2/sec_main.c | 5 + drivers/crypto/hisilicon/zip/zip_main.c | 5 + drivers/crypto/hisilicon/zip/zip_usr_if.h | 2 +- 8 files changed, 591 insertions(+), 7 deletions(-)
diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 3732a5ffe1606..22f623945b0b0 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -89,6 +89,9 @@ #define HPRE_QM_PM_FLR BIT(11) #define HPRE_QM_SRIOV_FLR BIT(12)
+#define HPRE_SQE_MASK_OFFSET 8 +#define HPRE_SQE_MASK_LEN 24 + /* function index: * 1 for hpre bypass mode, * 2 for RDE bypass mode; @@ -752,6 +755,8 @@ static int hpre_debugfs_init(struct hisi_qm *qm) qm->debug.debug_root = debugfs_create_dir(dev_name(dev), hpre_debugfs_root);
+ qm->debug.sqe_mask_offset = HPRE_SQE_MASK_OFFSET; + qm->debug.sqe_mask_len = HPRE_SQE_MASK_LEN; ret = hisi_qm_debug_init(qm); if (ret) goto failed_to_create; diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 410ca0e7a11ee..91cd64e09c74d 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -173,7 +173,7 @@ #define WAIT_PERIOD_US_MAX 200 #define WAIT_PERIOD_US_MIN 100 #define REMOVE_WAIT_DELAY 10 -#define MAX_WAIT_COUNTS 1000 +#define MAX_WAIT_COUNTS 10000 #define QM_DEV_RESET_STATUS 0 #define QM_RESET_WAIT_TIMEOUT 400 #define QM_PCI_COMMAND_INVALID 0xFFFFFFFF @@ -255,6 +255,19 @@ struct hisi_qm_hw_ops { pci_ers_result_t (*hw_error_handle)(struct hisi_qm *qm); };
+struct qm_dfx_item { + const char *name; + u32 offset; +}; + +static struct qm_dfx_item qm_dfx_files[] = { + {"qm_err_irq", offsetof(struct qm_dfx, qm_err_irq_cnt)}, + {"aeq_irq", offsetof(struct qm_dfx, aeq_irq_cnt)}, + {"abnormal_irq", offsetof(struct qm_dfx, abnormal_irq_cnt)}, + {"qp_err", offsetof(struct qm_dfx, qp_err_cnt)}, + {"mb_err", offsetof(struct qm_dfx, mb_err_cnt)}, +}; + static const char * const qm_debug_file_name[] = { [CURRENT_Q] = "current_q", [CLEAR_ENABLE] = "clear_enable", @@ -429,7 +442,8 @@ static int qm_mb(struct hisi_qm *qm, u8 cmd, dma_addr_t dma_addr, u16 queue,
busy_unlock: mutex_unlock(&qm->mailbox_lock); - + if (ret) + atomic64_inc(&qm->debug.dfx.mb_err_cnt); return ret; }
@@ -606,6 +620,7 @@ static irqreturn_t qm_irq(int irq, void *data) if (readl(qm->io_base + QM_VF_EQ_INT_SOURCE)) return do_qm_irq(irq, data);
+ atomic64_inc(&qm->debug.dfx.qm_err_irq_cnt); dev_err(&qm->pdev->dev, "invalid int source\n"); qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0); return IRQ_NONE; @@ -617,6 +632,7 @@ static irqreturn_t qm_aeq_irq(int irq, void *data) struct qm_aeqe *aeqe = qm->aeqe + qm->status.aeq_head; u32 type;
+ atomic64_inc(&qm->debug.dfx.aeq_irq_cnt); if (!readl(qm->io_base + QM_VF_AEQ_INT_SOURCE)) return IRQ_NONE;
@@ -651,6 +667,7 @@ static irqreturn_t qm_abnormal_irq(int irq, void *data) struct device *dev = &qm->pdev->dev; u32 error_status, tmp;
+ atomic64_inc(&qm->debug.dfx.abnormal_irq_cnt); if (qm->abnormal_fix) { qm->abnormal_fix(qm); return IRQ_HANDLED; @@ -1060,6 +1077,28 @@ static const struct file_operations qm_regs_fops = { .release = single_release, };
+static ssize_t qm_cmd_read(struct file *filp, char __user *buffer, + size_t count, loff_t *pos) +{ + char buf[QM_DBG_READ_LEN]; + int uncopy_bytes, len; + + if (*pos) + return 0; + + if (count < QM_DBG_READ_LEN) + return -ENOSPC; + + len = snprintf(buf, QM_DBG_READ_LEN, "%s\n", + "Please echo help to cmd to get help information"); + + uncopy_bytes = copy_to_user(buffer, buf, len); + if (uncopy_bytes) + return -EFAULT; + + return (*pos = len); +} + static void *qm_ctx_alloc(struct hisi_qm *qm, size_t ctx_size, dma_addr_t *dma_addr) { @@ -1089,6 +1128,41 @@ static void qm_ctx_free(struct hisi_qm *qm, size_t ctx_size, kfree(ctx_addr); }
+static int dump_show(struct hisi_qm *qm, void *info, + unsigned int info_size, char *info_name) +{ + struct device *dev = &qm->pdev->dev; + u8 *info_curr = info; + u8 *info_buf; + u32 i; +#define BYTE_PER_DW 4 + + info_buf = kzalloc(info_size, GFP_KERNEL); + if (!info_buf) + return -ENOMEM; + + for (i = 0; i < info_size; i++, info_curr++) { + if (i % BYTE_PER_DW == 0) + info_buf[i + 3UL] = *info_curr; + else if (i % BYTE_PER_DW == 1) + info_buf[i + 1UL] = *info_curr; + else if (i % BYTE_PER_DW == 2) + info_buf[i - 1] = *info_curr; + else if (i % BYTE_PER_DW == 3) + info_buf[i - 3] = *info_curr; + } + + dev_info(dev, "%s DUMP\n", info_name); + for (i = 0; i < info_size; i += BYTE_PER_DW) { + pr_info("DW%d: %02X%02X %02X%02X\n", i / BYTE_PER_DW, + info_buf[i], info_buf[i + 1UL], + info_buf[i + 2UL], info_buf[i + 3UL]); + } + + kfree(info_buf); + return 0; +} + static int qm_dump_sqc_raw(struct hisi_qm *qm, dma_addr_t dma_addr, u16 qp_id) { return qm_mb(qm, QM_MB_CMD_SQC, dma_addr, qp_id, 1); @@ -1099,6 +1173,418 @@ static int qm_dump_cqc_raw(struct hisi_qm *qm, dma_addr_t dma_addr, u16 qp_id) return qm_mb(qm, QM_MB_CMD_CQC, dma_addr, qp_id, 1); }
+static int qm_sqc_dump(struct hisi_qm *qm, const char *s) +{ + struct device *dev = &qm->pdev->dev; + struct qm_sqc *sqc, *sqc_curr; + dma_addr_t sqc_dma; + u32 qp_id; + int ret; + + if (!s) + return -EINVAL; + + ret = kstrtou32(s, 0, &qp_id); + if (ret || qp_id >= qm->qp_num) { + dev_err(dev, "Please input qp num (0-%d)", qm->qp_num - 1); + return -EINVAL; + } + + sqc = qm_ctx_alloc(qm, sizeof(struct qm_sqc), &sqc_dma); + if (IS_ERR(sqc)) + return PTR_ERR(sqc); + + ret = qm_dump_sqc_raw(qm, sqc_dma, qp_id); + if (ret) { + down_read(&qm->qps_lock); + if (qm->sqc) { + sqc_curr = qm->sqc + qp_id; + + ret = dump_show(qm, sqc_curr, sizeof(struct qm_sqc), + "SOFT SQC"); + if (ret) + dev_info(dev, "Show soft sqc failed!\n"); + } + up_read(&qm->qps_lock); + + goto mailbox_fail; + } + + ret = dump_show(qm, sqc, sizeof(struct qm_sqc), "SQC"); + if (ret) + dev_info(dev, "Show hw sqc failed!\n"); + +mailbox_fail: + qm_ctx_free(qm, sizeof(struct qm_sqc), sqc, &sqc_dma); + return ret; +} + +static int qm_cqc_dump(struct hisi_qm *qm, const char *s) +{ + struct device *dev = &qm->pdev->dev; + struct qm_cqc *cqc, *cqc_curr; + dma_addr_t cqc_dma; + u32 qp_id; + int ret; + + if (!s) + return -EINVAL; + + ret = kstrtou32(s, 0, &qp_id); + if (ret || qp_id >= qm->qp_num) { + dev_err(dev, "Please input qp num (0-%d)", qm->qp_num - 1); + return -EINVAL; + } + + cqc = qm_ctx_alloc(qm, sizeof(struct qm_cqc), &cqc_dma); + if (IS_ERR(cqc)) + return PTR_ERR(cqc); + + ret = qm_dump_cqc_raw(qm, cqc_dma, qp_id); + if (ret) { + down_read(&qm->qps_lock); + if (qm->cqc) { + cqc_curr = qm->cqc + qp_id; + + ret = dump_show(qm, cqc_curr, sizeof(struct qm_cqc), + "SOFT CQC"); + if (ret) + dev_info(dev, "Show soft cqc failed!\n"); + } + up_read(&qm->qps_lock); + + goto mailbox_fail; + } + + ret = dump_show(qm, cqc, sizeof(struct qm_cqc), "CQC"); + if (ret) + dev_info(dev, "Show hw cqc failed!\n"); + +mailbox_fail: + qm_ctx_free(qm, sizeof(struct qm_cqc), cqc, &cqc_dma); + return ret; +} + +static int qm_eqc_dump(struct hisi_qm *qm, char *s) +{ + struct device *dev = &qm->pdev->dev; + struct qm_eqc *eqc; + dma_addr_t eqc_dma; + int ret; + + if (strsep(&s, " ")) { + dev_err(dev, "Please do not input extra characters!\n"); + return -EINVAL; + } + + eqc = qm_ctx_alloc(qm, sizeof(struct qm_eqc), &eqc_dma); + if (IS_ERR(eqc)) + return PTR_ERR(eqc); + + ret = qm_mb(qm, QM_MB_CMD_EQC, eqc_dma, 0, 1); + if (ret) + goto mailbox_fail; + + ret = dump_show(qm, eqc, sizeof(struct qm_eqc), "EQC"); + if (ret) + dev_info(dev, "Show eqc failed!\n"); + +mailbox_fail: + qm_ctx_free(qm, sizeof(struct qm_eqc), eqc, &eqc_dma); + return ret; +} + +static int qm_aeqc_dump(struct hisi_qm *qm, char *s) +{ + struct device *dev = &qm->pdev->dev; + struct qm_aeqc *aeqc; + dma_addr_t aeqc_dma; + int ret; + + if (strsep(&s, " ")) { + dev_err(dev, "Please do not input extra characters!\n"); + return -EINVAL; + } + + aeqc = qm_ctx_alloc(qm, sizeof(struct qm_aeqc), &aeqc_dma); + if (IS_ERR(aeqc)) + return PTR_ERR(aeqc); + + ret = qm_mb(qm, QM_MB_CMD_AEQC, aeqc_dma, 0, 1); + if (ret) + goto mailbox_fail; + + ret = dump_show(qm, aeqc, sizeof(struct qm_aeqc), "AEQC"); + if (ret) + dev_info(dev, "Show hw aeqc failed!\n"); + +mailbox_fail: + qm_ctx_free(qm, sizeof(struct qm_aeqc), aeqc, &aeqc_dma); + return ret; +} + +static int q_dump_param_parse(struct hisi_qm *qm, char *s, + u32 *e_id, u32 *q_id) +{ + struct device *dev = &qm->pdev->dev; + unsigned int qp_num = qm->qp_num; + char *presult; + int ret; + + presult = strsep(&s, " "); + if (!presult) { + dev_err(dev, "Please input qp number!\n"); + return -EINVAL; + } + + ret = kstrtou32(presult, 0, q_id); + if (ret || *q_id >= qp_num) { + dev_err(dev, "Please input qp num (0-%d)", qp_num - 1); + return -EINVAL; + } + + presult = strsep(&s, " "); + if (!presult) { + dev_err(dev, "Please input sqe number!\n"); + return -EINVAL; + } + + ret = kstrtou32(presult, 0, e_id); + if (ret || *e_id >= QM_Q_DEPTH) { + dev_err(dev, "Please input sqe num (0-%d)", QM_Q_DEPTH - 1); + return -EINVAL; + } + + if (strsep(&s, " ")) { + dev_err(dev, "Please do not input extra characters!\n"); + return -EINVAL; + } + + return 0; +} + +static int qm_sq_dump(struct hisi_qm *qm, char *s) +{ + struct device *dev = &qm->pdev->dev; + struct hisi_qp *qp; + u32 qp_id, sqe_id; + void *sqe_curr; + int ret; + + ret = q_dump_param_parse(qm, s, &sqe_id, &qp_id); + if (ret) + return ret; + + qp = &qm->qp_array[qp_id]; + sqe_curr = qp->sqe + (u32)(sqe_id * qm->sqe_size); + memset(sqe_curr + qm->debug.sqe_mask_offset, SQE_ADDR_MASK, + qm->debug.sqe_mask_len); + + ret = dump_show(qm, sqe_curr, qm->sqe_size, "SQE"); + if (ret) + dev_info(dev, "Show sqe failed!\n"); + + return ret; +} + +static int qm_cq_dump(struct hisi_qm *qm, char *s) +{ + struct device *dev = &qm->pdev->dev; + struct qm_cqe *cqe_curr; + struct hisi_qp *qp; + u32 qp_id, cqe_id; + int ret; + + ret = q_dump_param_parse(qm, s, &cqe_id, &qp_id); + if (ret) + return ret; + + qp = &qm->qp_array[qp_id]; + cqe_curr = qp->cqe + cqe_id; + ret = dump_show(qm, cqe_curr, sizeof(struct qm_cqe), "CQE"); + if (ret) + dev_info(dev, "Show cqe failed!\n"); + + return ret; +} + +static int qm_eq_dump(struct hisi_qm *qm, const char *s) +{ + struct device *dev = &qm->pdev->dev; + struct qm_eqe *eqe; + u32 eqe_id; + int ret; + + if (!s) + return -EINVAL; + + ret = kstrtou32(s, 0, &eqe_id); + if (ret || eqe_id >= QM_EQ_DEPTH) { + dev_err(dev, "Please input eqe num (0-%d)", QM_EQ_DEPTH - 1); + return -EINVAL; + } + + down_read(&qm->qps_lock); + if (qm->eqe) { + eqe = qm->eqe + eqe_id; + ret = dump_show(qm, eqe, sizeof(struct qm_eqe), "EQE"); + if (ret) + dev_info(dev, "Show eqe failed!\n"); + } + up_read(&qm->qps_lock); + + return ret; +} + +static int qm_aeq_dump(struct hisi_qm *qm, const char *s) +{ + struct device *dev = &qm->pdev->dev; + struct qm_aeqe *aeqe; + u32 aeqe_id; + int ret; + + if (!s) + return -EINVAL; + + ret = kstrtou32(s, 0, &aeqe_id); + if (ret || aeqe_id >= QM_Q_DEPTH) { + dev_err(dev, "Please input aeqe num (0-%d)", QM_Q_DEPTH - 1); + return -EINVAL; + } + + down_read(&qm->qps_lock); + if (qm->aeqe) { + aeqe = qm->aeqe + aeqe_id; + ret = dump_show(qm, aeqe, sizeof(struct qm_aeqe), "AEQE"); + if (ret) + dev_info(dev, "Show aeqe failed!\n"); + } + up_read(&qm->qps_lock); + + return ret; +} + +static int qm_dbg_help(struct hisi_qm *qm, char *s) +{ + struct device *dev = &qm->pdev->dev; + + if (strsep(&s, " ")) { + dev_err(dev, "Please do not input extra characters!\n"); + return -EINVAL; + } + + dev_info(dev, "available commands\n"); + dev_info(dev, "sqc <num>\n"); + dev_info(dev, "cqc <num>\n"); + dev_info(dev, "eqc\n"); + dev_info(dev, "aeqc\n"); + dev_info(dev, "sq <num> <e>\n"); + dev_info(dev, "cq <num> <e>\n"); + dev_info(dev, "eq <e>\n"); + dev_info(dev, "aeq <e>\n"); + + return 0; +} + +static int qm_cmd_write_dump(struct hisi_qm *qm, const char *cmd_buf) +{ + struct device *dev = &qm->pdev->dev; + char *presult, *s, *s_tmp; + int ret; + + s = kstrdup(cmd_buf, GFP_KERNEL); + if (!s) + return -ENOMEM; + + s_tmp = s; + presult = strsep(&s, " "); + if (!presult) { + kfree(s_tmp); + return -EINVAL; + } + + if (!strcmp(presult, "sqc")) + ret = qm_sqc_dump(qm, s); + else if (!strcmp(presult, "cqc")) + ret = qm_cqc_dump(qm, s); + else if (!strcmp(presult, "eqc")) + ret = qm_eqc_dump(qm, s); + else if (!strcmp(presult, "aeqc")) + ret = qm_aeqc_dump(qm, s); + else if (!strcmp(presult, "sq")) + ret = qm_sq_dump(qm, s); + else if (!strcmp(presult, "cq")) + ret = qm_cq_dump(qm, s); + else if (!strcmp(presult, "eq")) + ret = qm_eq_dump(qm, s); + else if (!strcmp(presult, "aeq")) + ret = qm_aeq_dump(qm, s); + else if (!strcmp(presult, "help")) + ret = qm_dbg_help(qm, s); + else + ret = -EINVAL; + + if (ret) + dev_info(dev, "Please echo help\n"); + + kfree(s_tmp); + + return ret; +} + +static ssize_t qm_cmd_write(struct file *filp, const char __user *buffer, + size_t count, loff_t *pos) +{ + struct hisi_qm *qm = filp->private_data; + char *cmd_buf, *cmd_buf_tmp; + int uncopied_bytes; + int ret; + + if (*pos) + return 0; + + /* Judge if the instance is being reset. */ + if (unlikely(atomic_read(&qm->status.flags) == QM_STOP)) + return 0; + + if (count > QM_DBG_WRITE_LEN) + return -ENOSPC; + + cmd_buf = kzalloc(count + 1, GFP_KERNEL); + if (!cmd_buf) + return -ENOMEM; + + uncopied_bytes = copy_from_user(cmd_buf, buffer, count); + if (uncopied_bytes) { + kfree(cmd_buf); + return -EFAULT; + } + + cmd_buf[count] = '\0'; + + cmd_buf_tmp = strchr(cmd_buf, '\n'); + if (cmd_buf_tmp) { + *cmd_buf_tmp = '\0'; + count = cmd_buf_tmp - cmd_buf + 1; + } + + ret = qm_cmd_write_dump(qm, cmd_buf); + if (ret) { + kfree(cmd_buf); + return ret; + } + + kfree(cmd_buf); + return count; +} + +static const struct file_operations qm_cmd_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = qm_cmd_read, + .write = qm_cmd_write, +}; + static int qm_create_debugfs_file(struct hisi_qm *qm, enum qm_debug_file index) { struct dentry *qm_d = qm->debug.qm_d, *tmp; @@ -1269,6 +1755,7 @@ static struct hisi_qp *hisi_qm_create_qp_nolock(struct hisi_qm *qm, if (!qm->free_qp_num) { dev_info_ratelimited(dev, "All %u queues of QM are busy!\n", qm->qp_num); + atomic64_inc(&qm->debug.dfx.qp_err_cnt); return ERR_PTR(-EBUSY); }
@@ -1277,6 +1764,7 @@ static struct hisi_qp *hisi_qm_create_qp_nolock(struct hisi_qm *qm, if (qp_id < 0) { dev_info_ratelimited(dev, "All %u queues of QM are busy!\n", qm->qp_num); + atomic64_inc(&qm->debug.dfx.qp_err_cnt); return ERR_PTR(-EBUSY); }
@@ -2707,6 +3195,58 @@ void hisi_qm_debug_regs_clear(struct hisi_qm *qm) } EXPORT_SYMBOL_GPL(hisi_qm_debug_regs_clear);
+static ssize_t qm_status_read(struct file *filp, char __user *buffer, + size_t count, loff_t *pos) +{ + struct hisi_qm *qm = filp->private_data; + char buf[QM_DBG_READ_LEN]; + int val, cp_len, len; + + if (*pos) + return 0; + + if (count < QM_DBG_READ_LEN) + return -ENOSPC; + + val = atomic_read(&qm->status.flags); + len = snprintf(buf, QM_DBG_READ_LEN, "%s\n", qm_s[val]); + if (!len) + return -EFAULT; + + cp_len = copy_to_user(buffer, buf, len); + if (cp_len) + return -EFAULT; + + return (*pos = len); +} + + +static const struct file_operations qm_status_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = qm_status_read, +}; + +static int qm_debugfs_atomic64_set(void *data, u64 val) +{ + if (!val) + atomic64_set((atomic64_t *)data, 0); + else + return -EINVAL; + + return 0; +} + +static int qm_debugfs_atomic64_get(void *data, u64 *val) +{ + *val = atomic64_read((atomic64_t *)data); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(qm_atomic64_ops, qm_debugfs_atomic64_get, + qm_debugfs_atomic64_set, "%llu\n"); + /** * hisi_qm_debug_init() - Initialize qm related debugfs files. * @qm: The qm for which we want to add debugfs files. @@ -2715,7 +3255,9 @@ EXPORT_SYMBOL_GPL(hisi_qm_debug_regs_clear); */ int hisi_qm_debug_init(struct hisi_qm *qm) { + struct qm_dfx *dfx = &qm->debug.dfx; struct dentry *qm_d; + void *data; int i, ret;
qm_d = debugfs_create_dir("qm", qm->debug.debug_root); @@ -2733,6 +3275,20 @@ int hisi_qm_debug_init(struct hisi_qm *qm)
debugfs_create_file("regs", 0444, qm->debug.qm_d, qm, &qm_regs_fops);
+ debugfs_create_file("cmd", 0444, qm->debug.qm_d, qm, &qm_cmd_fops); + + debugfs_create_file("status", 0444, qm->debug.qm_d, qm, + &qm_status_fops); + + for (i = 0; i < ARRAY_SIZE(qm_dfx_files); i++) { + data = (atomic64_t *)((uintptr_t)dfx + qm_dfx_files[i].offset); + debugfs_create_file(qm_dfx_files[i].name, + 0644, + qm_d, + data, + &qm_atomic64_ops); + } + return 0;
failed_to_create: diff --git a/drivers/crypto/hisilicon/qm.h b/drivers/crypto/hisilicon/qm.h index 06ad9f0694498..73e231fac1a6c 100644 --- a/drivers/crypto/hisilicon/qm.h +++ b/drivers/crypto/hisilicon/qm.h @@ -90,6 +90,8 @@ #define CURRENT_FUN_MASK GENMASK(5, 0) #define CURRENT_Q_MASK GENMASK(31, 16)
+#define SQE_ADDR_MASK GENMASK(7, 0) + #define PCI_BAR_2 2
enum qm_stop_reason { @@ -130,6 +132,14 @@ enum qm_debug_file { DEBUG_FILE_NUM, };
+struct qm_dfx { + atomic64_t qm_err_irq_cnt; + atomic64_t aeq_irq_cnt; + atomic64_t abnormal_irq_cnt; + atomic64_t qp_err_cnt; + atomic64_t mb_err_cnt; +}; + struct debugfs_file { enum qm_debug_file index; struct mutex lock; @@ -137,7 +147,10 @@ struct debugfs_file { };
struct qm_debug { + u32 sqe_mask_len; + u32 sqe_mask_offset; u32 curr_qm_qp_num; + struct qm_dfx dfx; struct dentry *debug_root; struct dentry *qm_d; struct debugfs_file files[DEBUG_FILE_NUM]; diff --git a/drivers/crypto/hisilicon/rde/rde.h b/drivers/crypto/hisilicon/rde/rde.h index e06efc76bf9af..b481a0d8fc6b5 100644 --- a/drivers/crypto/hisilicon/rde/rde.h +++ b/drivers/crypto/hisilicon/rde/rde.h @@ -203,7 +203,7 @@ enum { NO_REF = 0, /* no REF domain */ REF = 1, /* REF domain without checking */ REF_CHECK_LBA = 2, /* REF domain checking with lab */ - REF_CHECK_PRI = 3, /* REF domain checking with private infoformation */ + REF_CHECK_PRI = 3, /* REF domain checking with individual information*/ };
/* RDE IO abort switch */ diff --git a/drivers/crypto/hisilicon/rde/rde_api.h b/drivers/crypto/hisilicon/rde/rde_api.h index 167607ee812b6..b284a5b112c1b 100644 --- a/drivers/crypto/hisilicon/rde/rde_api.h +++ b/drivers/crypto/hisilicon/rde/rde_api.h @@ -72,7 +72,7 @@ enum DIF_APP_GEN_CTRL_E { enum DIF_REF_GEN_CTRL_E { DIF_REF_GEN_NONE = 0x0, DIF_REF_GEN_FROM_INPUT_LBA = 0x1, - DIF_REF_GEN_FROM_PRIVATE_INFO = 0x2, + DIF_REF_GEN_FROM_INDIVIDUAL_INFO = 0x2, DIF_REF_GEN_FROM_ZERO = 0x3, DIF_REF_GEN_FROM_SOURCE_DATA = 0x4, DIF_REF_GEN_FROM_RAID_OR_EC = 0x5, @@ -86,7 +86,7 @@ enum DIF_VERIFY_CTRL_E { DIF_VERIFY_NONE = 0x0, DIF_VERIFY_DO_NOT_VERIFY = 0x1, DIF_VERIFY_ALL_BLOCK = 0x2, - DIF_VERIFY_BY_PRIVATE_INFO = 0x3, + DIF_VERIFY_BY_INDIVIDUAL_INFO = 0x3, DIF_VERIFY_BUTT };
@@ -283,7 +283,7 @@ struct dif_ctrl { /** * @brief general dif structure. * @lba: lba for dif ref field - * @priv: private info for dif ref field + * @priv: individual info for dif ref field * @ver: 8bit version * @app: 8bit application information field * @note diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index b50ed43a6ef6f..e3b21ef4d0c82 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -81,6 +81,9 @@ #define SEC_DBGFS_VAL_MAX_LEN 20 #define SEC_SINGLE_PORT_MAX_TRANS 0x2060
+#define SEC_SQE_MASK_OFFSET 64 +#define SEC_SQE_MASK_LEN 48 + #define SEC_ADDR(qm, offset) ((qm)->io_base + (offset) + \ SEC_ENGINE_PF_CFG_OFF + SEC_ACC_COMMON_REG_OFF)
@@ -663,6 +666,8 @@ static int sec_debugfs_init(struct hisi_qm *qm)
qm->debug.debug_root = debugfs_create_dir(dev_name(dev), sec_debugfs_root); + qm->debug.sqe_mask_offset = SEC_SQE_MASK_OFFSET; + qm->debug.sqe_mask_len = SEC_SQE_MASK_LEN; ret = hisi_qm_debug_init(qm); if (ret) goto failed_to_create; diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 0a6a95a0ad080..49dbf90daa980 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -98,6 +98,9 @@ #define HZIP_BUF_SIZE 22 #define FORMAT_DECIMAL 10
+#define HZIP_SQE_MASK_OFFSET 64 +#define HZIP_SQE_MASK_LEN 48 + #define HZIP_CNT_CLR_CE_EN BIT(0) #define HZIP_RO_CNT_CLR_CE_EN BIT(2) #define HZIP_RD_CNT_CLR_CE_EN (HZIP_CNT_CLR_CE_EN | \ @@ -663,6 +666,8 @@ static int hisi_zip_debugfs_init(struct hisi_qm *qm) if (!dev_d) return -ENOENT;
+ qm->debug.sqe_mask_offset = HZIP_SQE_MASK_OFFSET; + qm->debug.sqe_mask_len = HZIP_SQE_MASK_LEN; qm->debug.debug_root = dev_d; ret = hisi_qm_debug_init(qm); if (ret) diff --git a/drivers/crypto/hisilicon/zip/zip_usr_if.h b/drivers/crypto/hisilicon/zip/zip_usr_if.h index 74e59e970bf8d..d5dbaa844ed03 100644 --- a/drivers/crypto/hisilicon/zip/zip_usr_if.h +++ b/drivers/crypto/hisilicon/zip/zip_usr_if.h @@ -24,7 +24,7 @@ struct hisi_zip_sqe { __u32 dw8; __u32 dw9; __u32 dw10; - __u32 priv_info; + __u32 dif_info; __u32 dw12; __u32 tag; __u32 dest_avail_out;
From: Yu'an Wang wangyuan46@huawei.com
hulk inclusion category: Bugfix bugzilla: NA CVE: NA
When a BD is delivered, the RAS resets occasionally clear the BD that is being delivered. The count send_ref ensures that the RAS process does not perform operations on this QP when the BD is delivered.
Signed-off-by: Yu'an Wang wangyuan46@huawei.com Signed-off-by: Weili Qian qianweili@huawei.com Reviewed-by: Zibo Xu xuzaibo@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/crypto/hisilicon/qm.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 91cd64e09c74d..a6bf95cb7baf6 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -2049,7 +2049,9 @@ static int hisi_qm_stop_qp_nolock(struct hisi_qp *qp) flush_work(&qp->qm->work);
/* waiting for increase used count in qp send and last poll qp finish */ - udelay(WAIT_PERIOD); + while (atomic_read(&qp->qp_status.send_ref)) + udelay(WAIT_PERIOD); + if (unlikely(qp->is_resetting && atomic_read(&qp->qp_status.used))) qp_stop_fail_cb(qp);
@@ -2094,25 +2096,27 @@ EXPORT_SYMBOL_GPL(hisi_qm_stop_qp); int hisi_qp_send(struct hisi_qp *qp, const void *msg) { struct hisi_qp_status *qp_status = &qp->qp_status; - u16 sq_tail = qp_status->sq_tail; - u16 sq_tail_next = (sq_tail + 1) % QM_Q_DEPTH; - void *sqe = qm_get_avail_sqe(qp); + void *sqe;
if (unlikely(atomic_read(&qp->qp_status.flags) == QP_STOP || atomic_read(&qp->qm->status.flags) == QM_STOP) || qp->is_resetting) { - dev_info_ratelimited(&qp->qm->pdev->dev, "QM resetting...\n"); + dev_info_ratelimited(&qp->qm->pdev->dev, "QP is stopped or resetting\n"); return -EAGAIN; }
- if (!sqe) + atomic_inc(&qp->qp_status.send_ref); + sqe = qm_get_avail_sqe(qp); + if (!sqe) { + atomic_dec(&qp->qp_status.send_ref); return -EBUSY; + }
memcpy(sqe, msg, qp->qm->sqe_size); - - qm_db(qp->qm, qp->qp_id, QM_DOORBELL_CMD_SQ, sq_tail_next, 0); + qp_status->sq_tail = (qp_status->sq_tail + 1) % QM_Q_DEPTH; + qm_db(qp->qm, qp->qp_id, QM_DOORBELL_CMD_SQ, qp_status->sq_tail, 0); atomic_inc(&qp->qp_status.used); - qp_status->sq_tail = sq_tail_next; + atomic_dec(&qp->qp_status.send_ref);
return 0; }
From: Yu'an Wang wangyuan46@huawei.com
hulk inclusion category: Bugfix bugzilla: NA CVE: NA
When running the hpre kernel state task, a ras error occurred. After the driver actively called back the incomplete task to recycle the sqe resources, the hardware wrote back the sqe and caused the kernel calltrace.
Signed-off-by: Yu'an Wang wangyuan46@huawei.com Signed-off-by: Hui Tang tanghui20@huawei.com Reviewed-by: Zibo Xu xuzaibo@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/crypto/hisilicon/hpre/hpre.h | 1 + drivers/crypto/hisilicon/hpre/hpre_crypto.c | 10 +++++++++- drivers/crypto/hisilicon/hpre/hpre_main.c | 3 ++- 3 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/crypto/hisilicon/hpre/hpre.h b/drivers/crypto/hisilicon/hpre/hpre.h index 203eb2ac1e67d..14d60b48afc1f 100644 --- a/drivers/crypto/hisilicon/hpre/hpre.h +++ b/drivers/crypto/hisilicon/hpre/hpre.h @@ -32,6 +32,7 @@ enum hpre_dfx_dbgfs_file { HPRE_SEND_BUSY_CNT, HPRE_OVER_THRHLD_CNT, HPRE_OVERTIME_THRHLD, + HPRE_INVALID_REQ_CNT, HPRE_DFX_FILE_NUM };
diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c index b68b30c886adb..5031d64789e68 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c +++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c @@ -414,9 +414,17 @@ static void hpre_rsa_cb(struct hpre_ctx *ctx, void *resp) static void hpre_alg_cb(struct hisi_qp *qp, void *resp) { struct hpre_ctx *ctx = qp->qp_ctx; + struct hpre_dfx *dfx = ctx->hpre->debug.dfx; struct hpre_sqe *sqe = resp; + struct hpre_asym_request *req = ctx->req_list[le16_to_cpu(sqe->tag)]; + + + if (unlikely(!req)) { + atomic64_inc(&dfx[HPRE_INVALID_REQ_CNT].value); + return; + }
- ctx->req_list[le16_to_cpu(sqe->tag)]->cb(ctx, resp); + req->cb(ctx, resp); }
static int hpre_ctx_init(struct hpre_ctx *ctx) diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 22f623945b0b0..6c5dc53c92fa6 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -178,7 +178,8 @@ static const char *hpre_dfx_files[HPRE_DFX_FILE_NUM] = { "send_fail_cnt", "send_busy_cnt", "over_thrhld_cnt", - "overtime_thrhld" + "overtime_thrhld", + "invalid_req_cnt" };
#ifdef CONFIG_CRYPTO_QM_UACCE
From: Yu'an Wang wangyuan46@huawei.com
hulk inclusion category: Feature bugzilla: NA CVE: NA
The function hisi_acc_create_sg_pool may allocate a block of memory of size PAGE_SIZE * 2^(MAX_ORDER - 1). This value may exceed 2^31 on ia64, which would overflow the u32. This patch caps it at 2^31.
Signed-off-by: Yu'an Wang wangyuan46@huawei.com Signed-off-by: Zibo Xu xuzaibo@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/crypto/hisilicon/sgl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/crypto/hisilicon/sgl.c b/drivers/crypto/hisilicon/sgl.c index badb95d99e03e..7aca6f79dcfc8 100644 --- a/drivers/crypto/hisilicon/sgl.c +++ b/drivers/crypto/hisilicon/sgl.c @@ -9,6 +9,7 @@ #define HISI_ACC_SGL_NR_MAX 256 #define HISI_ACC_SGL_ALIGN_SIZE 64 #define HISI_ACC_MEM_BLOCK_NR 5 +#define HISI_ACC_BLOCK_SIZE_MAX_SHIFT 31
struct acc_hw_sge { dma_addr_t buf; @@ -66,7 +67,9 @@ struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev,
sgl_size = sizeof(struct acc_hw_sge) * sge_nr + sizeof(struct hisi_acc_hw_sgl); - block_size = PAGE_SIZE * (1 << (MAX_ORDER - 1)); + block_size = 1 << (PAGE_SHIFT + MAX_ORDER <= 32 ? + PAGE_SHIFT + MAX_ORDER - 1 : + HISI_ACC_BLOCK_SIZE_MAX_SHIFT); sgl_num_per_block = block_size / sgl_size; block_num = count / sgl_num_per_block; remain_sgl = count % sgl_num_per_block; @@ -230,6 +233,7 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev, dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL); return ERR_PTR(-ENOMEM); } + curr_hw_sgl->entry_length_in_sgl = cpu_to_le16(pool->sge_nr); curr_hw_sge = curr_hw_sgl->sge_entries;
From: Yu'an Wang wangyuan46@huawei.com
hulk inclusion category: Feature bugzilla: NA CVE: NA
backport uacce from mainline, it moved uacce.c to misc/uacce and update Kconfig and Makefile. At the same time, uacce.h is moved from /uapi/linux to /uapi/misc/uacce.
Signed-off-by: Yu'an Wang wangyuan46@huawei.com Signed-off-by: Kai Ye yekai13@huawei.com Reviewed-by: Zhou Wang wangzhou1@hisilicon.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/Kconfig | 2 - drivers/Makefile | 1 - drivers/misc/Kconfig | 1 + drivers/misc/Makefile | 1 + drivers/misc/uacce/Kconfig | 14 + drivers/{ => misc}/uacce/Makefile | 1 - drivers/{ => misc}/uacce/uacce.c | 36 +- drivers/uacce/Kconfig | 37 -- drivers/uacce/dummy_drv/Makefile | 5 - drivers/uacce/dummy_drv/dummy_hw_usr_if.h | 47 -- drivers/uacce/dummy_drv/dummy_wd_dev.c | 430 ----------------- drivers/uacce/dummy_drv/dummy_wd_v2.c | 522 --------------------- drivers/uacce/dummy_drv/wd_dummy_usr_if.h | 30 -- include/linux/uacce.h | 8 +- include/uapi/misc/uacce/hisi_qm.h | 51 ++ include/uapi/{linux => misc/uacce}/uacce.h | 0 16 files changed, 74 insertions(+), 1112 deletions(-) create mode 100644 drivers/misc/uacce/Kconfig rename drivers/{ => misc}/uacce/Makefile (64%) rename drivers/{ => misc}/uacce/uacce.c (97%) delete mode 100644 drivers/uacce/Kconfig delete mode 100644 drivers/uacce/dummy_drv/Makefile delete mode 100644 drivers/uacce/dummy_drv/dummy_hw_usr_if.h delete mode 100644 drivers/uacce/dummy_drv/dummy_wd_dev.c delete mode 100644 drivers/uacce/dummy_drv/dummy_wd_v2.c delete mode 100644 drivers/uacce/dummy_drv/wd_dummy_usr_if.h create mode 100644 include/uapi/misc/uacce/hisi_qm.h rename include/uapi/{linux => misc/uacce}/uacce.h (100%)
diff --git a/drivers/Kconfig b/drivers/Kconfig index 017f0a304dd21..ab4d43923c4dd 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -217,8 +217,6 @@ source "drivers/visorbus/Kconfig"
source "drivers/siox/Kconfig"
-source "drivers/uacce/Kconfig" - source "drivers/slimbus/Kconfig"
endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 752e6a1f9b185..578f469f72fbb 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -186,4 +186,3 @@ obj-$(CONFIG_MULTIPLEXER) += mux/ obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/ obj-$(CONFIG_SIOX) += siox/ obj-$(CONFIG_GNSS) += gnss/ -obj-y += uacce/ diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 3726eacdf65de..74f7c79d50997 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -527,4 +527,5 @@ source "drivers/misc/echo/Kconfig" source "drivers/misc/cxl/Kconfig" source "drivers/misc/ocxl/Kconfig" source "drivers/misc/cardreader/Kconfig" +source "drivers/misc/uacce/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index af22bbc3d00cb..ebc68dd8a4ed5 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -58,3 +58,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o obj-$(CONFIG_OCXL) += ocxl/ obj-$(CONFIG_MISC_RTSX) += cardreader/ +obj-$(CONFIG_UACCE) += uacce/ diff --git a/drivers/misc/uacce/Kconfig b/drivers/misc/uacce/Kconfig new file mode 100644 index 0000000000000..f0d02be5a057a --- /dev/null +++ b/drivers/misc/uacce/Kconfig @@ -0,0 +1,14 @@ +menuconfig UACCE + tristate "Accelerator Framework for User Land" + depends on IOMMU_API + select ANON_INODES + help + UACCE provides interface for the user process to access the hardware + without interaction with the kernel space in data path. + + The user-space interface is described in + include/uapi/misc/uacce/uacce.h + + See Documentation/misc-devices/uacce.rst for more details. + + If you don't know what to do here, say N. diff --git a/drivers/uacce/Makefile b/drivers/misc/uacce/Makefile similarity index 64% rename from drivers/uacce/Makefile rename to drivers/misc/uacce/Makefile index b1cade5120fcc..5b4374e8b5f21 100644 --- a/drivers/uacce/Makefile +++ b/drivers/misc/uacce/Makefile @@ -1,3 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-or-later obj-$(CONFIG_UACCE) += uacce.o -obj-$(CONFIG_WD_DUMMY_DEV) += dummy_drv/ diff --git a/drivers/uacce/uacce.c b/drivers/misc/uacce/uacce.c similarity index 97% rename from drivers/uacce/uacce.c rename to drivers/misc/uacce/uacce.c index 5b48a688768df..49fc5dbf40157 100644 --- a/drivers/uacce/uacce.c +++ b/drivers/misc/uacce/uacce.c @@ -699,10 +699,7 @@ static void uacce_queue_drain(struct uacce_queue *q) if (is_to_free_region) uacce_destroy_region(q, qfr); } -#ifdef CONFIG_IOMMU_SVA2 - if (uacce->flags & UACCE_DEV_SVA) - iommu_sva_unbind_device(uacce->pdev, q->pasid); -#endif + if (state && uacce->ops->put_queue) uacce->ops->put_queue(q);
@@ -749,16 +746,6 @@ static int uacce_get_queue(struct uacce *uacce, struct file *filep) int ret; int pasid = 0;
-#ifdef CONFIG_IOMMU_SVA2 - if (uacce->flags & UACCE_DEV_PASID) { - ret = iommu_sva_bind_device(uacce->pdev, current->mm, &pasid, - IOMMU_SVA_FEAT_IOPF, NULL); - if (ret) { - dev_err(uacce->pdev, "iommu SVA binds fail!\n"); - return ret; - } - } -#endif uacce_qs_wlock();
ret = uacce->ops->get_queue(uacce, pasid, &q); @@ -782,10 +769,7 @@ static int uacce_get_queue(struct uacce *uacce, struct file *filep) return 0;
err_unbind: -#ifdef CONFIG_IOMMU_SVA2 - if (uacce->flags & UACCE_DEV_PASID) - iommu_sva_unbind_device(uacce->pdev, pasid); -#endif + return ret; }
@@ -1297,19 +1281,8 @@ int uacce_register(struct uacce *uacce) return ret; }
- if (uacce->flags & UACCE_DEV_PASID) { -#ifdef CONFIG_IOMMU_SVA2 - ret = iommu_sva_init_device(uacce->pdev, IOMMU_SVA_FEAT_IOPF, - 0, 0, NULL); - if (ret) { - dev_err(dev, "uacce sva init fail!\n"); - uacce_destroy_chrdev(uacce); - return ret; - } -#else + if (uacce->flags & UACCE_DEV_PASID) uacce->flags &= ~(UACCE_DEV_FAULT_FROM_DEV | UACCE_DEV_PASID); -#endif - }
dev_dbg(&uacce->dev, "register to uacce!\n"); atomic_set(&uacce->ref, 0); @@ -1333,9 +1306,6 @@ int uacce_unregister(struct uacce *uacce) return -EAGAIN; }
-#ifdef CONFIG_IOMMU_SVA2 - iommu_sva_shutdown_device(uacce->pdev); -#endif uacce_hw_err_destroy(uacce); uacce_destroy_chrdev(uacce);
diff --git a/drivers/uacce/Kconfig b/drivers/uacce/Kconfig deleted file mode 100644 index 8c4a381962cdb..0000000000000 --- a/drivers/uacce/Kconfig +++ /dev/null @@ -1,37 +0,0 @@ -menuconfig UACCE - tristate "Accelerator Framework for User Land" - depends on IOMMU_API - select ANON_INODES - help - UACCE provides interface for the user process to access the hardware - without interaction with the kernel space in data path. - - See Documentation/warpdrive/warpdrive.rst for more details. - - If you don't know what to do here, say N. - -config WD_DUMMY_DEV - tristate "Support for WrapDrive Dummy Device" - depends on UACCE - help - Support for WarpDrive test driver with devices (NOT for upstream). - - If you don't know what to do here, say N. - -config WD_DUMMY_V1 - tristate "Support for WrapDrive Dummy Device V1" - depends on WD_DUMMY_DEV - help - Support for WarpDrive test driver (NOT for upstream). - The device is simulated with os - - If you don't know what to do here, say N. - -config WD_DUMMY_V2 - tristate "Support for WrapDrive Dummy Device V2" - depends on WD_DUMMY_DEV - help - Support for WarpDrive test driver (NOT for upstream). - The device is simulated with qemu - - If you don't know what to do here, say N. diff --git a/drivers/uacce/dummy_drv/Makefile b/drivers/uacce/dummy_drv/Makefile deleted file mode 100644 index 8f3a1f30b64b4..0000000000000 --- a/drivers/uacce/dummy_drv/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -obj-$(CONFIG_WD_DUMMY_V1) += wd_dummy.o -wd_dummy-objs := dummy_wd_dev.o - -obj-$(CONFIG_WD_DUMMY_V2) += wd_dummy2.o -wd_dummy2-objs := dummy_wd_v2.o diff --git a/drivers/uacce/dummy_drv/dummy_hw_usr_if.h b/drivers/uacce/dummy_drv/dummy_hw_usr_if.h deleted file mode 100644 index f925aabeabab5..0000000000000 --- a/drivers/uacce/dummy_drv/dummy_hw_usr_if.h +++ /dev/null @@ -1,47 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* Copyright (c) 2018-2019 HiSilicon Limited. */ -/* - * This file defines the dummy hardware/driver interface between the user and - * kernel space - */ - -#ifndef __DUMMY_HW_USR_IF_H -#define __DUMMY_HW_USR_IF_H - -#include <linux/types.h> - -#define DUMMY_WD "dummy_wd" - -#define Q_BDS 16 -#define DUMMY_HW_TAG_SZ 8 -#define DUMMY_HW_TAG "WDDUMMY" - -/* the format of the device ring space, which is of drv */ -#define ring_bd wd_dummy_cpy_msg - -/* the format of the device io space, which is of drv */ -struct dummy_hw_queue_reg { - char hw_tag[DUMMY_HW_TAG_SZ]; /* should be "WDDUMMY\0" */ - struct ring_bd ring[Q_BDS]; /* - * in real hardware, this is good to be - * in memory space, and will be fast - * for communication. here we keep it - * in io space just to make it simple - */ - __u32 ring_bd_num; /* - * ring_bd_num, now it is Q_BDS until - * we use a memory ring - */ - __u32 head; /* - * assume int is atomical. it should be - * fine as a dummy and test function. - * head is for the writer(user) while - * tail is for the reader(kernel). - * head==tail means the queue is empty - */ - __u32 tail; -}; - -#define DUMMY_CMD_FLUSH _IO('d', 0) - -#endif diff --git a/drivers/uacce/dummy_drv/dummy_wd_dev.c b/drivers/uacce/dummy_drv/dummy_wd_dev.c deleted file mode 100644 index fa684c893ae41..0000000000000 --- a/drivers/uacce/dummy_drv/dummy_wd_dev.c +++ /dev/null @@ -1,430 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* Copyright (c) 2018-2019 HiSilicon Limited. */ -/** - * This module is used to test the framework of WarpDrive. - * - * It creates MAX_DEV platform devices with MAX_QUEUE queue for each. When the - * queue is gotten, a kernel thread is created and handle request put into the - * queue by the user application. - */ - -#include <asm/page.h> -#include <linux/dma-mapping.h> -#include <linux/kthread.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> -#include <linux/printk.h> -#include <linux/slab.h> -#include <linux/uacce.h> -#include <linux/uaccess.h> - -#include "wd_dummy_usr_if.h" -#include "dummy_hw_usr_if.h" - -#define MAX_DEV 3 -#define MAX_QUEUE 4 -#define QUEUE_YEILD_MS 50 -#define VERBOSE_LOG - -#define MODE_MMIO 0 /* use mmio region for bd */ -#define MODE_DSU 1 /* use dsu region for bd */ -static int mode = MODE_DSU; -module_param(mode, int, 0); - -static DEFINE_MUTEX(qsmutex); - -struct dummy_hw; - -struct dummy_hw_queue { - bool used; - struct task_struct *tsk; - __u32 tail; - struct uacce_qfile_region *ss_qfr; - - struct uacce_queue wdq; - struct dummy_hw_queue_reg *reg; - struct dummy_hw *hw; - struct task_struct *work_thread; - struct mutex mutex; - int is_updated; - int devid, qid; -}; - -static struct dummy_hw { - int max_copy_size; - int aflags; - struct dummy_hw_queue qs[MAX_QUEUE]; - struct platform_device *pdev; -} hws[MAX_DEV]; - -static int _do_copy(struct uacce_queue *q, void *tgt, void *src, size_t len) -{ - struct uacce_qfile_region *ss_qfr = q->qfrs[UACCE_QFRT_SS]; - int ret = 0; - size_t iova_base = q->qfrs[UACCE_QFRT_SS]->iova; - size_t ktgt = (unsigned long)tgt - iova_base; - size_t ksrc = (unsigned long)src - iova_base; - size_t range = ss_qfr->nr_pages << PAGE_SHIFT; - - if (ktgt + len > range) { - dev_dbg(&q->uacce->dev, "ktgt(%lx, %lx) not in range(%lx)\n", - ktgt, len, range); - ret = -EINVAL; - goto out; - } - - if (ksrc + len > range) { - dev_dbg(&q->uacce->dev, "ksrc(%lx, %lx) not in range(%lx)\n", - ksrc, len, range); - ret = -EINVAL; - goto out; - } - - ktgt += (unsigned long)ss_qfr->kaddr; - ksrc += (unsigned long)ss_qfr->kaddr; - memcpy((void *)ktgt, (void *)ksrc, len); - -out: - return ret; -} - -static void _queue_work(struct dummy_hw_queue *hwq) -{ - int bd_num; - __u32 head; - __u32 tail; - struct device *dev = &hwq->wdq.uacce->dev; - - mutex_lock(&hwq->mutex); - - bd_num = hwq->reg->ring_bd_num; - head = readl(&hwq->reg->head); - - if (head >= bd_num) { - dev_err(dev, "dummy_wd io error, head=%d\n", head); - mutex_unlock(&hwq->mutex); - return; - } - - tail = hwq->tail; - while (hwq->tail != head) { - if (hwq->reg->ring[hwq->tail].size > hwq->hw->max_copy_size) - hwq->reg->ring[hwq->tail].ret = -EINVAL; - else - hwq->reg->ring[hwq->tail].ret = _do_copy(&hwq->wdq, - hwq->reg->ring[hwq->tail].tgt_addr, - hwq->reg->ring[hwq->tail].src_addr, - hwq->reg->ring[hwq->tail].size); - dev_dbg(dev, "memcpy(%pK, %pK, %ld) = %d", - hwq->reg->ring[hwq->tail].tgt_addr, - hwq->reg->ring[hwq->tail].src_addr, - hwq->reg->ring[hwq->tail].size, - hwq->reg->ring[hwq->tail].ret); - hwq->tail = (hwq->tail+1)%bd_num; - } - - if (tail != hwq->tail) { - dev_dbg(dev, "write back tail %d\n", hwq->tail); - writel(hwq->tail, &hwq->reg->tail); - hwq->is_updated = 1; - uacce_wake_up(&hwq->wdq); - } - - mutex_unlock(&hwq->mutex); -} - -static int dummy_is_q_updated(struct uacce_queue *q) -{ - struct dummy_hw_queue *hwq = q->priv; - int updated; - - mutex_lock(&hwq->mutex); - - updated = hwq->is_updated; - hwq->is_updated = 0; - - mutex_unlock(&hwq->mutex); - - dev_dbg(&q->uacce->dev, "check q updated: %d\n", updated); - - return updated; -} - -static int dummy_get_queue(struct uacce *uacce, unsigned long arg, - struct uacce_queue **q) -{ - int i; - struct dummy_hw *hw = (struct dummy_hw *)uacce->priv; - struct dummy_hw_queue *devqs = hw->qs; - - WARN_ON(!devqs); - - mutex_lock(&qsmutex); - for (i = 0; i < MAX_QUEUE; i++) { - if (!devqs[i].used) { - devqs[i].used = 1; - devqs[i].reg->head = 0; - devqs[i].reg->tail = 0; - devqs[i].tail = 0; - devqs[i].is_updated = 0; - *q = &devqs[i].wdq; - devqs[i].wdq.priv = &devqs[i]; - dev_dbg(uacce->pdev, "allocate hw q %d\n", i); - break; - } - } - mutex_unlock(&qsmutex); - - if (i < MAX_QUEUE) - return 0; - - return -ENODEV; -} - -static void dummy_put_queue(struct uacce_queue *q) -{ - struct dummy_hw_queue *hwq = (struct dummy_hw_queue *)q->priv; - - mutex_lock(&qsmutex); - hwq->used = 0; - mutex_unlock(&qsmutex); -} - -static int dummy_mmap(struct uacce_queue *q, struct vm_area_struct *vma, - struct uacce_qfile_region *qfr) -{ - struct dummy_hw_queue *hwq = (struct dummy_hw_queue *)q->priv; - struct page *page = virt_to_page(hwq->reg); - - dev_dbg(&q->uacce->dev, "mmap mmio space (ref=%d)\n", - page_ref_count(page)); - if (vma->vm_pgoff != 0 || qfr->nr_pages > 1 || - !(vma->vm_flags & VM_SHARED)) - return -EINVAL; - - return remap_pfn_range(vma, vma->vm_start, __pa(hwq->reg)>>PAGE_SHIFT, - PAGE_SIZE, vma->vm_page_prot); -} - -static long dummy_ioctl(struct uacce_queue *q, unsigned int cmd, - unsigned long arg) -{ - struct dummy_hw_queue *hwq = q->priv; - - switch (cmd) { - case DUMMY_CMD_FLUSH: - _queue_work(hwq); - return 0; - - default: - return -EINVAL; - } -} - -static void dummy_mask_notify(struct uacce_queue *q, int event_mask) -{ - dev_dbg(&q->uacce->dev, "mask notify: %x\n", event_mask); -} - -int queue_worker(void *data) -{ - struct dummy_hw_queue *hwq = data; - - do { - _queue_work(hwq); - schedule_timeout_interruptible( - msecs_to_jiffies(QUEUE_YEILD_MS)); - } while (!kthread_should_stop()); - hwq->work_thread = NULL; - - return 0; -} - -static int dummy_start_queue(struct uacce_queue *q) -{ - struct dummy_hw_queue *hwq = q->priv; - - hwq->work_thread = kthread_run(queue_worker, hwq, - "dummy_queue_worker %d-%d", - hwq->devid, hwq->qid); - if (PTR_ERR_OR_ZERO(hwq->work_thread)) - return PTR_ERR(hwq->work_thread); - - dev_dbg(&q->uacce->dev, "queue start\n"); - return 0; -} - -void dummy_stop_queue(struct uacce_queue *q) -{ - struct dummy_hw_queue *hwq = q->priv; - - if (hwq->work_thread) - kthread_stop(hwq->work_thread); - -} - -static int dummy_get_available_instances(struct uacce *uacce) -{ - int i, ret; - struct dummy_hw *hw = (struct dummy_hw *)uacce->priv; - struct dummy_hw_queue *devqs = hw->qs; - - mutex_lock(&qsmutex); - for (i = 0, ret = 0; i < MAX_QUEUE; i++) { - if (!devqs[i].used) - ret++; - } - mutex_unlock(&qsmutex); - - return ret; -} - -static struct uacce_ops dummy_ops = { - .get_queue = dummy_get_queue, - .put_queue = dummy_put_queue, - .start_queue = dummy_start_queue, - .stop_queue = dummy_stop_queue, - .is_q_updated = dummy_is_q_updated, - .mmap = dummy_mmap, - .ioctl = dummy_ioctl, - .mask_notify = dummy_mask_notify, - .get_available_instances = dummy_get_available_instances, -}; - -static int dummy_wd_probe(struct platform_device *pdev) -{ - struct uacce *uacce; - struct dummy_hw *hw; - int i, ret; - - if (pdev->id >= MAX_DEV) { - dev_err(&pdev->dev, "invalid id (%d) for dummy_wd\n", pdev->id); - return -EINVAL; - } - - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); - if (ret < 0) - return -EINVAL; - - hw = &hws[pdev->id]; - hw->aflags = 0; - hw->max_copy_size = 4096; - - uacce = devm_kzalloc(&pdev->dev, sizeof(struct uacce), GFP_KERNEL); - if (!uacce) - return -ENOMEM; - - platform_set_drvdata(pdev, uacce); - uacce->name = DUMMY_WD; - uacce->pdev = &pdev->dev; - uacce->priv = hw; - uacce->ops = &dummy_ops; - uacce->drv_name = DUMMY_WD; - uacce->algs = "memcpy\n"; - uacce->api_ver = "dummy_v1"; - uacce->flags = UACCE_DEV_NOIOMMU; - uacce->qf_pg_start[UACCE_QFRT_MMIO] = 0; - uacce->qf_pg_start[UACCE_QFRT_DUS] = UACCE_QFR_NA; - uacce->qf_pg_start[UACCE_QFRT_SS] = 1; - -#ifdef CONFIG_NUMA - /* - * Emulate numa id if there's no platform dummy device. - * Try to bind each dummy device to each numa node. If there're more - * dummy devices than numa nodes, the numa_node should be binded to - * the last numa node. - */ - if (uacce->pdev->numa_node < 0) { - if (cpu_to_node(nr_cpu_ids - 1) > pdev->id) - uacce->pdev->numa_node = pdev->id; - else - uacce->pdev->numa_node = cpu_to_node(nr_cpu_ids - 1); - } -#endif - - for (i = 0; i < MAX_QUEUE; i++) { - hw->qs[i].wdq.uacce = uacce; - hw->qs[i].hw = hw; - hw->qs[i].reg = (struct dummy_hw_queue_reg *) - __get_free_page(GFP_KERNEL); - memcpy(hw->qs[i].reg->hw_tag, DUMMY_HW_TAG, DUMMY_HW_TAG_SZ); - hw->qs[i].reg->ring_bd_num = Q_BDS; - hw->qs[i].reg->head = 0; - hw->qs[i].reg->tail = 0; - hw->qs[i].tail = 0; - hw->qs[i].is_updated = 0; - hw->qs[i].devid = pdev->id; - hw->qs[i].qid = i; - - mutex_init(&hw->qs[i].mutex); - } - - return uacce_register(uacce); -} - -static int dummy_wd_remove(struct platform_device *pdev) -{ - struct uacce *uacce = (struct uacce *)pdev->dev.driver_data; - struct dummy_hw *hw = &hws[pdev->id]; - int i; - - uacce_unregister(uacce); - for (i = 0; i < MAX_QUEUE; i++) - free_page((unsigned long)hw->qs[i].reg); - return 0; -} - -static struct platform_driver dummy_pdrv = { - .probe = dummy_wd_probe, - .remove = dummy_wd_remove, - .driver = { - .name = DUMMY_WD, - }, -}; - -static int __init dummy_uacce_init(void) -{ - int i, j; - int ret = platform_driver_register(&dummy_pdrv); - - if (ret) - return ret; - - for (i = 0; i < MAX_DEV; i++) { - hws[i].pdev = platform_device_alloc(DUMMY_WD, i); - WARN_ON(!hws[i].pdev); - ret = platform_device_add(hws[i].pdev); - if (ret) - goto dev_reg_fail; - } - - return 0; - - -dev_reg_fail: - for (j = i - 1; j >= 0; j--) { - if (hws[i].pdev) - platform_device_put(hws[i].pdev); - } - - platform_driver_unregister(&dummy_pdrv); - - return ret; -} - -static void __exit dummy_uacce_exit(void) -{ - int i; - - for (i = MAX_DEV - 1; i >= 0; i--) - platform_device_unregister(hws[i].pdev); - - platform_driver_unregister(&dummy_pdrv); -} - -module_init(dummy_uacce_init); -module_exit(dummy_uacce_exit); - -MODULE_AUTHOR("Kenneth Leeliguozhu@hisilicon.com"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/uacce/dummy_drv/dummy_wd_v2.c b/drivers/uacce/dummy_drv/dummy_wd_v2.c deleted file mode 100644 index 7c5c4861fd801..0000000000000 --- a/drivers/uacce/dummy_drv/dummy_wd_v2.c +++ /dev/null @@ -1,522 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* Copyright (c) 2018-2019 HiSilicon Limited. */ -/** - * This module is used to test the framework of WarpDrive. - * - * It support a simular device as dummy_wd_dev in qemu and do almost the same. - * But it is a "real" hardware to the OS, so we can test the iommu feature - */ - -#include <asm/page.h> -#include <linux/dma-mapping.h> -#include <linux/kthread.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> -#include <linux/printk.h> -#include <linux/slab.h> -#include <linux/uacce.h> -#include <linux/uaccess.h> - -#include "wd_dummy_usr_if.h" -#include "dummy_hw_usr_if.h" - -#define DUMMY2_WD "dummy_wd2" -#define MAX_PT_ENTRIES 64 -#define RING_NUM 3 -#define HEADER_WORDS 12 /* reseved words in page 0 */ -#define DUMMY2_DMA_PAGE_SHIFT 12 -#define DUMMY2_DMA_PAGE_SIZE (1<<DUMMY2_DMA_PAGE_SHIFT) - -#define DUMMY2_IO_TAG 0 -#define DUMMY2_IO_PTPA (sizeof(uint64_t)) -#define DUMMY2_IO_PTSZ (sizeof(uint64_t) * 2) -#define DUMMY2_IO_MAX_COPY_SIZE (sizeof(uint64_t) * 4) -#define DUMMY2_IO_RING_BEGIN (sizeof(uint64_t) * HEADER_WORDS) - -struct pt_entry { - uint64_t asid; /* - *-1 means entry invalid, 0 means kernel, - *others are valid pasid. - */ - uint64_t iova; - /*-1 means entry invalid */ - uint64_t pa; -}; - -/* ring io struct in hardware mmio space */ -struct ring_io { - uint64_t rbpa; - uint64_t rbsz; - uint64_t asid; -}; - -struct dummy_wd2_hw; - -struct dummy_wd2_iommu_domain { - struct iommu_domain domain; - struct dummy_wd2_hw *hw; - uint64_t asid; -}; -#define to_dummy_wd2_iommu_domain(d) \ - container_of(d, struct dummy_wd2_iommu_domain, domain) - -struct dummy_wd2_hw_queue { - bool used; - struct dummy_wd2_hw *hw; - struct uacce_queue q; - void __iomem *db_pa; - void *ring_io_base; - - dma_addr_t bd_dma; -}; - -struct dummy_wd2_hw { - int max_copy_size; - int ver; - struct dummy_wd2_hw_queue qs[RING_NUM]; - struct platform_device *pdev; - struct mutex mutex; - struct device dummy_wd2_dev; - struct iommu_group *iommu_group; - - void *io_base; - struct pt_entry *pt; - dma_addr_t pt_dma; -}; - -static int dummy_wd2_bus_probe(struct device *dev) -{ - dev_info(dev, "bus probe dev\n"); - return 0; -} - -static int dummy_wd2_bus_remove(struct device *dev) -{ - dev_info(dev, "bus remove dev"); - return 0; -} - -static bool dummy_wd2_iommu_capable(enum iommu_cap cap) -{ - switch (cap) { - case IOMMU_CAP_CACHE_COHERENCY: - return true; - default: - return false; - } -} - -static struct iommu_domain *dummy_wd2_iommu_domain_alloc( - unsigned int iommu_domain_type); -static void dummy_wd2_iommu_domain_free(struct iommu_domain *domain); - -static int dummy_wd2_iommu_attach_dev(struct iommu_domain *domain, - struct device *dev) -{ - struct dummy_wd2_iommu_domain *d = to_dummy_wd2_iommu_domain(domain); - - pr_info("%s\n", __func__); - d->hw = dev_get_drvdata(dev); - d->asid = 0; - - if (d->hw) - return 0; - else - return -ENODEV; -} - -static void dummy_wd2_iommu_detach_dev(struct iommu_domain *domain, - struct device *dev) -{ - struct dummy_wd2_iommu_domain *d = to_dummy_wd2_iommu_domain(domain); - - d->hw = NULL; - d->asid = (u64)-1; - pr_info("%s\n", __func__); -} - -static int dummy_wd2_iommu_map(struct iommu_domain *domain, unsigned long iova, - phys_addr_t paddr, size_t size, int prot) -{ - struct dummy_wd2_iommu_domain *d = to_dummy_wd2_iommu_domain(domain); - int i; - - if (size != 4096) - return -EIO; - - for (i = 0; i < MAX_PT_ENTRIES; i++) { - if (d->hw->pt[i].asid == (uint64_t)-1) { - d->hw->pt[i].asid = d->asid; - d->hw->pt[i].iova = iova; - d->hw->pt[i].pa = paddr; - dev_dbg(&d->hw->dummy_wd2_dev, - "iommu_map %d asid=%lld, %llx=>%llx\n", i, - d->hw->pt[i].asid, - d->hw->pt[i].iova, - d->hw->pt[i].pa); - /* flush to hardware */ - writeq(MAX_PT_ENTRIES, - d->hw->io_base + DUMMY2_IO_PTSZ); - return 0; - } - } - - return -EBUSY; -} - -static size_t dummy_wd2_iommu_unmap(struct iommu_domain *domain, - unsigned long iova, size_t size) -{ - struct dummy_wd2_iommu_domain *d = to_dummy_wd2_iommu_domain(domain); - int i; - - if (size != DUMMY2_DMA_PAGE_SHIFT) - return 0; - - for (i = 0; i < MAX_PT_ENTRIES; i++) { - if (d->hw->pt[i].asid == d->asid && d->hw->pt[i].iova == iova) { - dev_dbg(&d->hw->dummy_wd2_dev, - "iommu_unmap %d asid=%lld, %llx=>%llx\n", i, - d->hw->pt[i].asid, - d->hw->pt[i].iova, - d->hw->pt[i].pa); - d->hw->pt[i].asid = (uint64_t)-1; - /* flush to hardware */ - writeq(MAX_PT_ENTRIES, - d->hw->io_base + DUMMY2_IO_PTSZ); - return DUMMY2_DMA_PAGE_SIZE; - } - } - - return 0; -} - -static struct iommu_ops dummy_wd2_iommu_ops = { - .capable = dummy_wd2_iommu_capable, - .domain_alloc = dummy_wd2_iommu_domain_alloc, - .domain_free = dummy_wd2_iommu_domain_free, - .attach_dev = dummy_wd2_iommu_attach_dev, - .detach_dev = dummy_wd2_iommu_detach_dev, - .map = dummy_wd2_iommu_map, - .unmap = dummy_wd2_iommu_unmap, - .pgsize_bitmap = SZ_4K, -}; - -static struct iommu_domain *dummy_wd2_iommu_domain_alloc( - unsigned int iommu_domain_type) -{ - struct dummy_wd2_iommu_domain *domain = kzalloc( - sizeof(struct iommu_domain), GFP_KERNEL); - - if (!domain) - return NULL; - - domain->domain.ops = &dummy_wd2_iommu_ops; - - return &domain->domain; -} - -static void dummy_wd2_iommu_domain_free(struct iommu_domain *domain) -{ - struct dummy_wd2_iommu_domain *d = to_dummy_wd2_iommu_domain(domain); - - kfree(d); -} - -static struct bus_type dummy_wd2_bus_type = { - .name = "dummy_wd2_bus", - .probe = dummy_wd2_bus_probe, - .remove = dummy_wd2_bus_remove, - .iommu_ops = &dummy_wd2_iommu_ops, -}; - -static int dummy_wd2_is_q_updated(struct uacce_queue *q) -{ - return 0; -} - -static int dummy_wd2_get_queue(struct uacce *uacce, unsigned long arg, - struct uacce_queue **q) -{ - int i; - struct dummy_wd2_hw *hw = (struct dummy_wd2_hw *)uacce->priv; - - mutex_lock(&hw->mutex); - for (i = 0; i < RING_NUM; i++) { - if (!hw->qs[i].used) { - hw->qs[i].used = true; - *q = &hw->qs[i].q; - dev_dbg(uacce->pdev, "allocate hw q %d\n", i); - break; - } - } - mutex_unlock(&hw->mutex); - - if (i < RING_NUM) - return 0; - - return -ENODEV; -} - -static void dummy_wd2_put_queue(struct uacce_queue *q) -{ - struct dummy_wd2_hw_queue *hwq = (struct dummy_wd2_hw_queue *)q->priv; - struct dummy_wd2_hw *hw = hwq->hw; - - mutex_lock(&hw->mutex); - hwq->used = false; - mutex_unlock(&hw->mutex); -} - -static int dummy_wd2_mmap(struct uacce_queue *q, struct vm_area_struct *vma, - struct uacce_qfile_region *qfr) -{ - struct dummy_wd2_hw_queue *hwq = (struct dummy_wd2_hw_queue *)q->priv; - - if (vma->vm_pgoff != 0 || qfr->nr_pages > 1 || - !(vma->vm_flags & VM_SHARED)) - return -EINVAL; - - return remap_pfn_range(vma, vma->vm_start, - (u64)hwq->db_pa >> PAGE_SHIFT, - DUMMY2_DMA_PAGE_SIZE, - pgprot_noncached(vma->vm_page_prot)); -} - -static void dummy_wd2_mask_notify(struct uacce_queue *q, int event_mask) -{ - dev_dbg(&q->uacce->dev, "mask notify: %x\n", event_mask); -} - -static inline void dummy_wd2_hw_set_rb(struct dummy_wd2_hw_queue *hwq, - uint64_t rbpa, uint64_t rbsz, - uint64_t asid) -{ -#define ring_io_off(member) offsetof(struct ring_io, member) - writeq(rbpa, hwq->ring_io_base + ring_io_off(rbpa)); - writeq(rbsz, hwq->ring_io_base + ring_io_off(rbsz)); - writeq(asid, hwq->ring_io_base + ring_io_off(asid)); -} - -static int dummy_wd2_start_queue(struct uacce_queue *q) -{ - struct dummy_wd2_hw_queue *hwq = (struct dummy_wd2_hw_queue *)q->priv; - - dev_dbg(&q->uacce->dev, "queue start\n"); - - hwq->bd_dma = q->qfrs[UACCE_QFRT_DUS]->iova; - if (!hwq->bd_dma) { - dev_err(&q->uacce->dev, "DUS is not created\n"); - return -EINVAL; - } - - if (!hwq->ring_io_base) { - dev_err(&q->uacce->dev, "ring_iobase is not set\n"); - return -EINVAL; - } - - dummy_wd2_hw_set_rb(hwq, hwq->bd_dma, Q_BDS, 0); - - return 0; -} - -void dummy_wd2_stop_queue(struct uacce_queue *q) -{ - struct dummy_wd2_hw_queue *hwq = (struct dummy_wd2_hw_queue *)q->priv; - - dev_dbg(&q->uacce->dev, "stop queue\n"); - dummy_wd2_hw_set_rb(hwq, 0, 0, (uint64_t)-1); -} - -static int dummy_wd2_get_available_instances(struct uacce *uacce) -{ - int i, ret; - struct dummy_wd2_hw *hw = (struct dummy_wd2_hw *)uacce->priv; - - mutex_lock(&hw->mutex); - for (i = 0, ret = 0; i < RING_NUM; i++) { - if (!hw->qs[i].used) - ret++; - } - mutex_unlock(&hw->mutex); - - return ret; -} - -static struct uacce_ops dummy_wd2_ops = { - .get_queue = dummy_wd2_get_queue, - .put_queue = dummy_wd2_put_queue, - .start_queue = dummy_wd2_start_queue, - .stop_queue = dummy_wd2_stop_queue, - .is_q_updated = dummy_wd2_is_q_updated, - .mmap = dummy_wd2_mmap, - .mask_notify = dummy_wd2_mask_notify, - .get_available_instances = dummy_wd2_get_available_instances, -}; - -static void dummy_wd2_dev_release(struct device *dev) -{ - dev_info(dev, "dummy_wd2 dev release\n"); -} - -static int dummy_wd2_probe(struct platform_device *pdev) -{ - struct uacce *uacce; - struct device *dev = &pdev->dev; - struct dummy_wd2_hw *hw; - struct resource *res; - int i, ret; - - if (!of_device_is_compatible(dev->of_node, "warpdrive,wd_dummy_v2")) - return -EINVAL; - - hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); - if (!hw) - return -ENOMEM; - - hw->ver = 2; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "cannot find io space!\n"); - return -ENODEV; - } - hw->io_base = devm_ioremap_resource(dev, res); - if (IS_ERR(hw->io_base)) - return PTR_ERR(hw->io_base); - - hw->pt = dmam_alloc_coherent(dev, - sizeof(struct pt_entry) * MAX_PT_ENTRIES, - &hw->pt_dma, GFP_KERNEL); - if (!hw->pt) - return -ENOMEM; - - hw->max_copy_size = (int)readq(hw->io_base + DUMMY2_IO_MAX_COPY_SIZE); - mutex_init(&hw->mutex); - - for (i = 0; i < MAX_PT_ENTRIES; i++) { - hw->pt[i].asid = (uint64_t)-1; - hw->pt[i].iova = 0x1111222233334444; - hw->pt[i].pa = 0x5555666677778888; - } - - dev_info(dev, "v2 device (%llx, %llx), header: %llx\n", - (u64)hw->pt, hw->pt_dma, readq(hw->io_base + DUMMY2_IO_TAG)); - - /* set page tables */ - writeq(hw->pt_dma, hw->io_base + DUMMY2_IO_PTPA); - writeq(MAX_PT_ENTRIES, hw->io_base + DUMMY2_IO_PTSZ); - for (i = 0; i < RING_NUM; i++) { - hw->qs[i].used = false; - hw->qs[i].db_pa = (void __iomem *)res->start + - ((i+1)<<DUMMY2_DMA_PAGE_SHIFT); - hw->qs[i].ring_io_base = hw->io_base + DUMMY2_IO_RING_BEGIN + - sizeof(struct ring_io) * i; - hw->qs[i].hw = hw; - hw->qs[i].q.priv = &hw->qs[i]; - } - - hw->dummy_wd2_dev.parent = dev; - hw->dummy_wd2_dev.bus = &dummy_wd2_bus_type; - hw->dummy_wd2_dev.release = dummy_wd2_dev_release; - /* assume I have only one device now */ - dev_set_name(&hw->dummy_wd2_dev, "dummy_wd2-%d", 0); - dev_set_drvdata(&hw->dummy_wd2_dev, hw); - ret = device_register(&hw->dummy_wd2_dev); - if (ret) { - /* device_register have 2 steps, the first one always success - * and set refcount to 1 - */ - goto err_with_device; - } - - hw->iommu_group = iommu_group_alloc(); - if (IS_ERR(hw->iommu_group)) { - ret = -ENOMEM; - goto err_with_device; - } - - iommu_group_set_name(hw->iommu_group, "dummy_hw2_iommu"); - iommu_group_set_iommudata(hw->iommu_group, &hw, NULL); - ret = iommu_group_add_device(hw->iommu_group, &hw->dummy_wd2_dev); - if (ret) - goto err_with_group; - - uacce = devm_kzalloc(&pdev->dev, sizeof(struct uacce), GFP_KERNEL); - if (!uacce) { - ret = -ENOMEM; - goto err_with_group; - } - - platform_set_drvdata(pdev, uacce); - uacce->name = DUMMY2_WD; - uacce->pdev = &hw->dummy_wd2_dev; - uacce->priv = hw; - uacce->ops = &dummy_wd2_ops; - uacce->drv_name = DUMMY2_WD; - uacce->algs = "memcpy\n"; - uacce->api_ver = "dummy_v2"; - uacce->flags = 0; - uacce->qf_pg_start[UACCE_QFRT_MMIO] = 0; - uacce->qf_pg_start[UACCE_QFRT_DUS] = 1; - uacce->qf_pg_start[UACCE_QFRT_SS] = 2; - - ret = uacce_register(uacce); - if (ret) { - dev_warn(uacce->pdev, "uacce register fail %d\n", ret); - goto err_with_group; - } - - return 0; - -err_with_group: - iommu_group_put(hw->iommu_group); -err_with_device: - put_device(&hw->dummy_wd2_dev); - return ret; -} - -static int dummy_wd2_remove(struct platform_device *pdev) -{ - struct uacce *uacce = (struct uacce *)pdev->dev.driver_data; - - uacce_unregister(uacce); - return 0; -} - -static struct platform_driver dummy_wd2_pdrv = { - .probe = dummy_wd2_probe, - .remove = dummy_wd2_remove, - .driver = { - .name = DUMMY2_WD, - }, -}; - -static int __init dummy_wd2_init(void) -{ - int ret; - - ret = bus_register(&dummy_wd2_bus_type); - if (ret) - return ret; - - ret = platform_driver_register(&dummy_wd2_pdrv); - if (ret) { - bus_unregister(&dummy_wd2_bus_type); - return ret; - } - - return 0; -} - -static void __exit dummy_wd2_exit(void) -{ - platform_driver_unregister(&dummy_wd2_pdrv); - bus_unregister(&dummy_wd2_bus_type); -} - -module_init(dummy_wd2_init); -module_exit(dummy_wd2_exit); - -MODULE_AUTHOR("Kenneth Leeliguozhu@hisilicon.com"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/uacce/dummy_drv/wd_dummy_usr_if.h b/drivers/uacce/dummy_drv/wd_dummy_usr_if.h deleted file mode 100644 index 50ad81fd00c4f..0000000000000 --- a/drivers/uacce/dummy_drv/wd_dummy_usr_if.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* Copyright (c) 2018-2019 HiSilicon Limited. */ -/* - * This file defines the dummy algo interface between the user and kernel space - */ - -#ifndef __DUMMY_USR_IF_H -#define __DUMMY_USR_IF_H - - -/* Algorithm name */ -#define AN_DUMMY_MEMCPY "memcopy" - -#define AAN_AFLAGS "aflags" -#define AAN_MAX_COPY_SIZE "max_copy_size" - -struct wd_dummy_cpy_param { - int flags; - int max_copy_size; -}; - -struct wd_dummy_cpy_msg { - char *src_addr; - char *tgt_addr; - size_t size; - void *ptr; - __u32 ret; -}; - -#endif diff --git a/include/linux/uacce.h b/include/linux/uacce.h index 4171a5b3cd3a8..43737c3f7f525 100644 --- a/include/linux/uacce.h +++ b/include/linux/uacce.h @@ -1,14 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* Copyright (c) 2018-2019 HiSilicon Limited. */ -#ifndef __UACCE_H -#define __UACCE_H +#ifndef _LINUX_UACCE_H +#define _LINUX_UACCE_H
#include <linux/cdev.h> #include <linux/device.h> #include <linux/fs.h> #include <linux/list.h> #include <linux/iommu.h> -#include <uapi/linux/uacce.h> +#include <uapi/misc/uacce/uacce.h>
struct uacce_queue; struct uacce; @@ -132,4 +132,4 @@ const char *uacce_qfrt_str(struct uacce_qfile_region *qfr); struct uacce *dev_to_uacce(struct device *dev); int uacce_hw_err_isolate(struct uacce *uacce);
-#endif +#endif /* _LINUX_UACCE_H */ diff --git a/include/uapi/misc/uacce/hisi_qm.h b/include/uapi/misc/uacce/hisi_qm.h new file mode 100644 index 0000000000000..90e602412a9c3 --- /dev/null +++ b/include/uapi/misc/uacce/hisi_qm.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +#ifndef _UAPI_HISI_QM_H +#define _UAPI_HISI_QM_H + +#include <linux/types.h> + +#define QM_CQE_SIZE 16 + +/* default queue depth for sq/cq/eq */ +#define QM_Q_DEPTH 1024 + +/* page number for queue file region */ +#define QM_DOORBELL_PAGE_NR 1 +#define QM_DKO_PAGE_NR 4 +#define QM_DUS_PAGE_NR 36 + +#define QM_DOORBELL_PG_START 0 +#define QM_DKO_PAGE_START (QM_DOORBELL_PG_START + QM_DOORBELL_PAGE_NR) +#define QM_DUS_PAGE_START (QM_DKO_PAGE_START + QM_DKO_PAGE_NR) +#define QM_SS_PAGE_START (QM_DUS_PAGE_START + QM_DUS_PAGE_NR) + +#define QM_DOORBELL_OFFSET 0x340 +#define QM_V2_DOORBELL_OFFSET 0x1000 + +struct cqe { + __le32 rsvd0; + __le16 cmd_id; + __le16 rsvd1; + __le16 sq_head; + __le16 sq_num; + __le16 rsvd2; + __le16 w7; +}; + +/** + * struct hisi_qp_ctx - User data for hisi qp. + * @id: qp_index return to user space + * @qc_type: Accelerator algorithm type + */ +struct hisi_qp_ctx { + __u16 id; + __u16 qc_type; +}; + +#define HISI_QM_API_VER_BASE "hisi_qm_v1" +#define HISI_QM_API_VER2_BASE "hisi_qm_v2" + +/* UACCE_CMD_QM_SET_QP_CTX: Set qp algorithm type */ +#define UACCE_CMD_QM_SET_QP_CTX _IOWR('H', 10, struct hisi_qp_ctx) + +#endif diff --git a/include/uapi/linux/uacce.h b/include/uapi/misc/uacce/uacce.h similarity index 100% rename from include/uapi/linux/uacce.h rename to include/uapi/misc/uacce/uacce.h
From: Al Viro viro@zeniv.linux.org.uk
mainline inclusion from mainline-v5.0-rc1 commit 6a0440e5b7562512c021aa1b5a706fcc545773db category: bugfix bugzilla: NA CVE: NA
--------------------------------
* if mount(2) passes something like "context=foo" with MS_REMOUNT in flags (/sbin/mount.nfs will _not_ do that - you need to issue the syscall manually), you'll get leaked copies for LSM options. The reason is that instead of nfs_{alloc,free}_parsed_mount_data() nfs_remount() uses kzalloc/kfree, which lacks the needed cleanup.
* selinux options are not changed on remount (as for any other fs), but in case of NFS the failure is quiet - they are not compared to what we used to have, with complaint in case of attempted changes. Trivially fixed by converting to use of security_sb_remount().
Reviewed-by: David Howells dhowells@redhat.com Signed-off-by: Al Viro viro@zeniv.linux.org.uk
Conflict: fs/nfs/super.c
Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 5db7aceb41907..fe107348aabe6 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2272,7 +2272,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) options->version <= 6)))) return 0;
- data = kzalloc(sizeof(*data), GFP_KERNEL); + data = nfs_alloc_parsed_mount_data(); if (data == NULL) return -ENOMEM;
@@ -2312,7 +2312,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) /* compare new mount options with old ones */ error = nfs_compare_remount_data(nfss, data); out: - kfree(data); + nfs_free_parsed_mount_data(data); return error; } EXPORT_SYMBOL_GPL(nfs_remount);
From: Trond Myklebust trond.myklebust@hammerspace.com
mainline inclusion from mainline-v5.0-rc1 commit 875bc3fbf2724134234ddb3069c8e9862b0b19b3 category: bugfix bugzilla: NA CVE: NA
--------------------------------
All the allocations that we can hit in the NFS layer and sunrpc layers themselves are already marked as GFP_NOFS, but we need to ensure that any calls to generic kernel functionality do the right thing as well.
Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/write.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index d419d89b91f7c..5ae98c0cde04c 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -26,6 +26,7 @@ #include <linux/iversion.h>
#include <linux/uaccess.h> +#include <linux/sched/mm.h>
#include "delegation.h" #include "internal.h" @@ -727,11 +728,13 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) { struct inode *inode = mapping->host; struct nfs_pageio_descriptor pgio; - struct nfs_io_completion *ioc = nfs_io_completion_alloc(GFP_NOFS); + struct nfs_io_completion *ioc; + unsigned int pflags = memalloc_nofs_save(); int err;
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
+ ioc = nfs_io_completion_alloc(GFP_NOFS); if (ioc) nfs_io_completion_init(ioc, nfs_io_completion_commit, inode);
@@ -742,6 +745,8 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) nfs_pageio_complete(&pgio); nfs_io_completion_put(ioc);
+ memalloc_nofs_restore(pflags); + if (err < 0) goto out_err; err = pgio.pg_error;
From: Trond Myklebust trond.myklebust@hammerspace.com
mainline inclusion from mainline-v5.0-rc1 commit c71c46f0157348a6c1c66f7d382c770ffc212724 category: bugfix bugzilla: NA CVE: NA
--------------------------------
Ensure that if we call nfs41_sequence_process() a second time for the same rpc_task, then we only process the results once.
Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/nfs4proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 283e4ed1aca19..c138dd107d4a3 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -770,7 +770,7 @@ static int nfs41_sequence_process(struct rpc_task *task, if (slot == NULL) goto out_noaction; /* don't increment the sequence number if the task wasn't sent */ - if (!RPC_WAS_SENT(task)) + if (!RPC_WAS_SENT(task) || slot->seq_done) goto out;
session = slot->table->session;
From: Trond Myklebust trond.myklebust@hammerspace.com
mainline inclusion from mainline-v5.3-rc4 commit 27a30cf64a5cbe2105e4ff9613246b32d584766a category: bugfix bugzilla: NA CVE: NA
--------------------------------
The logic for checking in nfs41_check_open_stateid() whether the state is supported by a delegation is inverted. In addition, it makes more sense to perform that check before we check for expired locks.
Fixes: 8a64c4ef106d1 ("NFSv4.1: Even if the stateid is OK,...") Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com
Conflicts: fs/nfs/nfs4proc.c
Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/nfs4proc.c | 65 +++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 27 deletions(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index c138dd107d4a3..959cffd7db266 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1642,6 +1642,14 @@ static void nfs_state_set_open_stateid(struct nfs4_state *state, write_sequnlock(&state->seqlock); }
+static void nfs_state_clear_open_state_flags(struct nfs4_state *state) +{ + clear_bit(NFS_O_RDWR_STATE, &state->flags); + clear_bit(NFS_O_WRONLY_STATE, &state->flags); + clear_bit(NFS_O_RDONLY_STATE, &state->flags); + clear_bit(NFS_OPEN_STATE, &state->flags); +} + static void nfs_state_set_delegation(struct nfs4_state *state, const nfs4_stateid *deleg_stateid, fmode_t fmode) @@ -2014,13 +2022,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * { int ret;
- /* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */ - clear_bit(NFS_O_RDWR_STATE, &state->flags); - clear_bit(NFS_O_WRONLY_STATE, &state->flags); - clear_bit(NFS_O_RDONLY_STATE, &state->flags); /* memory barrier prior to reading state->n_* */ - clear_bit(NFS_DELEGATED_STATE, &state->flags); - clear_bit(NFS_OPEN_STATE, &state->flags); smp_rmb(); ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE); if (ret != 0) @@ -2096,6 +2098,8 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta ctx = nfs4_state_find_open_context(state); if (IS_ERR(ctx)) return -EAGAIN; + clear_bit(NFS_DELEGATED_STATE, &state->flags); + nfs_state_clear_open_state_flags(state); ret = nfs4_do_open_reclaim(ctx, state); put_nfs_open_context(ctx); return ret; @@ -2637,6 +2641,7 @@ static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st { /* NFSv4.0 doesn't allow for delegation recovery on open expire */ nfs40_clear_delegation_stateid(state); + nfs_state_clear_open_state_flags(state); return nfs4_open_expired(sp, state); }
@@ -2679,13 +2684,13 @@ static int nfs41_test_and_free_expired_stateid(struct nfs_server *server, return -NFS4ERR_EXPIRED; }
-static void nfs41_check_delegation_stateid(struct nfs4_state *state) +static int nfs41_check_delegation_stateid(struct nfs4_state *state) { struct nfs_server *server = NFS_SERVER(state->inode); nfs4_stateid stateid; struct nfs_delegation *delegation; struct rpc_cred *cred; - int status; + int status, ret = NFS_OK;
/* Get the delegation credential for use by test/free_stateid */ rcu_read_lock(); @@ -2693,20 +2698,15 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state) if (delegation == NULL) { rcu_read_unlock(); nfs_state_clear_delegation(state); - return; + return NFS_OK; }
nfs4_stateid_copy(&stateid, &delegation->stateid); - if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) { - rcu_read_unlock(); - nfs_state_clear_delegation(state); - return; - }
if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags)) { rcu_read_unlock(); - return; + return NFS_OK; }
cred = get_rpccred(delegation->cred); @@ -2715,8 +2715,24 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state) trace_nfs4_test_delegation_stateid(state, NULL, status); if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) nfs_finish_clear_delegation_stateid(state, &stateid); + else + ret = status;
put_rpccred(cred); + return ret; +} + +static void nfs41_delegation_recover_stateid(struct nfs4_state *state) +{ + nfs4_stateid tmp; + + if (test_bit(NFS_DELEGATED_STATE, &state->flags) && + nfs4_copy_delegation_stateid(state->inode, state->state, + &tmp, NULL) && + nfs4_stateid_match_other(&state->stateid, &tmp)) + nfs_state_set_delegation(state, &tmp, state->state); + else + nfs_state_clear_delegation(state); }
/** @@ -2786,21 +2802,12 @@ static int nfs41_check_open_stateid(struct nfs4_state *state) struct rpc_cred *cred = state->owner->so_cred; int status;
- if (test_bit(NFS_OPEN_STATE, &state->flags) == 0) { - if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) { - if (nfs4_have_delegation(state->inode, state->state)) - return NFS_OK; - return -NFS4ERR_OPENMODE; - } + if (test_bit(NFS_OPEN_STATE, &state->flags) == 0) return -NFS4ERR_BAD_STATEID; - } status = nfs41_test_and_free_expired_stateid(server, stateid, cred); trace_nfs4_test_open_stateid(state, NULL, status); if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) { - clear_bit(NFS_O_RDONLY_STATE, &state->flags); - clear_bit(NFS_O_WRONLY_STATE, &state->flags); - clear_bit(NFS_O_RDWR_STATE, &state->flags); - clear_bit(NFS_OPEN_STATE, &state->flags); + nfs_state_clear_open_state_flags(state); stateid->type = NFS4_INVALID_STATEID_TYPE; return status; } @@ -2813,7 +2820,11 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st { int status;
- nfs41_check_delegation_stateid(state); + status = nfs41_check_delegation_stateid(state); + if (status != NFS_OK) + return status; + nfs41_delegation_recover_stateid(state); + status = nfs41_check_expired_locks(state); if (status != NFS_OK) return status;
From: Trond Myklebust trond.myklebust@hammerspace.com
mainline inclusion from mainline-v5.3-rc4 commit ad11408970df79d5f481aa9964e91f183133424c category: bugfix bugzilla: NA CVE: NA
--------------------------------
Fix nfs_reap_expired_delegations() to ensure that we only reap delegations that are actually expired, rather than triggering on random errors.
Fixes: 45870d6909d5a ("NFSv4.1: Test delegation stateids when server...") Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com
Conflicts: fs/nfs/delegation.c
Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/delegation.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index b0c0c2fc2fbac..9a91a1c9fb4eb 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -1044,6 +1044,21 @@ void nfs_mark_test_expired_all_delegations(struct nfs_client *clp) rcu_read_unlock(); }
+static void +nfs_delegation_test_free_expired(struct inode *inode, + nfs4_stateid *stateid, struct rpc_cred *cred) +{ + struct nfs_server *server = NFS_SERVER(inode); + const struct nfs4_minor_version_ops *ops = server->nfs_client->cl_mvops; + int status; + + if (!cred) + return; + status = ops->test_and_free_expired(server, stateid, cred); + if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) + nfs_remove_bad_delegation(inode, stateid); +} + /** * nfs_reap_expired_delegations - reap expired delegations * @clp: nfs_client to process @@ -1055,7 +1070,6 @@ void nfs_mark_test_expired_all_delegations(struct nfs_client *clp) */ void nfs_reap_expired_delegations(struct nfs_client *clp) { - const struct nfs4_minor_version_ops *ops = clp->cl_mvops; struct nfs_delegation *delegation; struct nfs_server *server; struct inode *inode; @@ -1086,11 +1100,7 @@ void nfs_reap_expired_delegations(struct nfs_client *clp) nfs4_stateid_copy(&stateid, &delegation->stateid); clear_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags); rcu_read_unlock(); - if (cred != NULL && - ops->test_and_free_expired(server, &stateid, cred) < 0) { - nfs_revoke_delegation(inode, &stateid); - nfs_inode_find_state_and_recover(inode, &stateid); - } + nfs_delegation_test_free_expired(inode, &stateid, cred); put_rpccred(cred); if (nfs4_server_rebooted(clp)) { nfs_inode_mark_test_expired_delegation(server,inode);
From: Trond Myklebust trond.myklebust@hammerspace.com
mainline inclusion from mainline-v5.5-rc1 commit 5c441544f045e679afd6c3c6d9f7aaf5fa5f37b0 category: bugfix bugzilla: NA CVE: NA
--------------------------------
If the server returns a bad or dead session error, the we don't want to update the session slot number, but just immediately schedule recovery and allow it to proceed.
We can/should then remove handling in other places
Fixes: 3453d5708b33 ("NFSv4.1: Avoid false retries when RPC calls are interrupted") Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/nfs4proc.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 959cffd7db266..06faf2f37ad63 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -504,9 +504,7 @@ static int nfs4_do_handle_exception(struct nfs_server *server, case -NFS4ERR_DEADSESSION: case -NFS4ERR_SEQ_FALSE_RETRY: case -NFS4ERR_SEQ_MISORDERED: - dprintk("%s ERROR: %d Reset session\n", __func__, - errorcode); - nfs4_schedule_session_recovery(clp->cl_session, errorcode); + /* Handled in nfs41_sequence_process() */ goto wait_on_recovery; #endif /* defined(CONFIG_NFS_V4_1) */ case -NFS4ERR_FILE_OPEN: @@ -765,6 +763,7 @@ static int nfs41_sequence_process(struct rpc_task *task, struct nfs4_session *session; struct nfs4_slot *slot = res->sr_slot; struct nfs_client *clp; + int status; int ret = 1;
if (slot == NULL) @@ -776,8 +775,13 @@ static int nfs41_sequence_process(struct rpc_task *task, session = slot->table->session;
trace_nfs4_sequence_done(session, res); + + status = res->sr_status; + if (task->tk_status == -NFS4ERR_DEADSESSION) + status = -NFS4ERR_DEADSESSION; + /* Check the SEQUENCE operation status */ - switch (res->sr_status) { + switch (status) { case 0: /* Mark this sequence number as having been acked */ nfs4_slot_sequence_acked(slot, slot->seq_nr); @@ -849,6 +853,10 @@ static int nfs41_sequence_process(struct rpc_task *task, */ slot->seq_nr = slot->seq_nr_highest_sent; goto out_retry; + case -NFS4ERR_BADSESSION: + case -NFS4ERR_DEADSESSION: + case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: + goto session_recover; default: /* Just update the slot sequence no. */ slot->seq_done = 1; @@ -859,8 +867,10 @@ static int nfs41_sequence_process(struct rpc_task *task, out_noaction: return ret; session_recover: - nfs4_schedule_session_recovery(session, res->sr_status); - goto retry_nowait; + nfs4_schedule_session_recovery(session, status); + dprintk("%s ERROR: %d Reset session\n", __func__, status); + nfs41_sequence_free_slot(res); + goto out; retry_new_seq: ++slot->seq_nr; retry_nowait: @@ -2121,7 +2131,6 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct case -NFS4ERR_BAD_HIGH_SLOT: case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: case -NFS4ERR_DEADSESSION: - nfs4_schedule_session_recovery(server->nfs_client->cl_session, err); return -EAGAIN; case -NFS4ERR_STALE_CLIENTID: case -NFS4ERR_STALE_STATEID: @@ -7706,6 +7715,15 @@ nfs41_same_server_scope(struct nfs41_server_scope *a, static void nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata) { + struct nfs41_bind_conn_to_session_args *args = task->tk_msg.rpc_argp; + struct nfs_client *clp = args->client; + + switch (task->tk_status) { + case -NFS4ERR_BADSESSION: + case -NFS4ERR_DEADSESSION: + nfs4_schedule_session_recovery(clp->cl_session, + task->tk_status); + } }
static const struct rpc_call_ops nfs4_bind_one_conn_to_session_ops = { @@ -8756,8 +8774,6 @@ static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nf case -NFS4ERR_BADSESSION: case -NFS4ERR_DEADSESSION: case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: - nfs4_schedule_session_recovery(clp->cl_session, - task->tk_status); break; default: nfs4_schedule_lease_recovery(clp);
From: Su Yanjun suyanjun218@gmail.com
mainline inclusion from mainline-v5.6-rc1 commit fe1e8dbec11fcad3ae7a34e95fe483d4a2b018fc category: bugfix bugzilla: NA CVE: NA
--------------------------------
We find a bug when running test under nfsv3 as below. 1) chacl u::r--,g::rwx,o:rw- file1 2) chmod u+w file1 3) chacl -l file1
We expect u::rw-, but it shows u::r--, more likely it returns the cached acl in inode.
We dig the code find that the code path is different.
chacl->..->__nfs3_proc_setacls->nfs_zap_acl_cache Then nfs_zap_acl_cache clears the NFS_INO_INVALID_ACL in NFS_I(inode)->cache_validity.
chmod->..->nfs3_proc_setattr Because NFS_INO_INVALID_ACL has been cleared by chacl path, nfs_zap_acl_cache wont be called.
nfs_setattr_update_inode will set NFS_INO_INVALID_ACL so let it before nfs_zap_acl_cache call.
Signed-off-by: Su Yanjun suyanjun218@gmail.com Signed-off-by: Anna Schumaker Anna.Schumaker@Netapp.com Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/nfs3proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 1cd2488ff2cd0..37b5e2ba1448e 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -140,9 +140,9 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (status == 0) { + nfs_setattr_update_inode(inode, sattr, fattr); if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) nfs_zap_acl_cache(inode); - nfs_setattr_update_inode(inode, sattr, fattr); } dprintk("NFS reply setattr: %d\n", status); return status;
From: Trond Myklebust trondmy@gmail.com
mainline inclusion from mainline-v5.6-rc1 commit 3803d6721baff3d5dd6cd6b8c7294e54d124bc41 category: bugfix bugzilla: NA CVE: NA
--------------------------------
The directory strings stored in the readdir cache may be used with printk(), so it is better to ensure they are nul-terminated.
Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com Reviewed-by: Benjamin Coddington bcodding@redhat.com Signed-off-by: Anna Schumaker Anna.Schumaker@Netapp.com Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index d1234a7a42144..3908ff8672af1 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -198,7 +198,7 @@ static int nfs_readdir_make_qstr(struct qstr *string, const char *name, unsigned int len) { string->len = len; - string->name = kmemdup(name, len, GFP_KERNEL); + string->name = kmemdup_nul(name, len, GFP_KERNEL); if (string->name == NULL) return -ENOMEM; /*
From: Robert Milkowski rmilkowski@gmail.com
mainline inclusion from mainline-v5.6-rc1 commit 7dc2993a9e51dd2eee955944efec65bef90265b7 category: bugfix bugzilla: NA CVE: NA
--------------------------------
Currently, each time nfs4_do_fsinfo() is called it will do an implicit NFS4 lease renewal, which is not compliant with the NFS4 specification. This can result in a lease being expired by an NFS server.
Commit 83ca7f5ab31f ("NFS: Avoid PUTROOTFH when managing leases") introduced implicit client lease renewal in nfs4_do_fsinfo(), which can result in the NFSv4.0 lease to expire on a server side, and servers returning NFS4ERR_EXPIRED or NFS4ERR_STALE_CLIENTID.
This can easily be reproduced by frequently unmounting a sub-mount, then stat'ing it to get it mounted again, which will delay or even completely prevent client from sending RENEW operations if no other NFS operations are issued. Eventually nfs server will expire client's lease and return an error on file access or next RENEW.
This can also happen when a sub-mount is automatically unmounted due to inactivity (after nfs_mountpoint_expiry_timeout), then it is mounted again via stat(). This can result in a short window during which client's lease will expire on a server but not on a client. This specific case was observed on production systems.
This patch removes the implicit lease renewal from nfs4_do_fsinfo().
Fixes: 83ca7f5ab31f ("NFS: Avoid PUTROOTFH when managing leases") Signed-off-by: Robert Milkowski rmilkowski@gmail.com Signed-off-by: Anna Schumaker Anna.Schumaker@Netapp.com
Conflicts: fs/nfs/nfs4proc.c
Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/nfs4_fs.h | 4 +--- fs/nfs/nfs4proc.c | 12 ++++++++---- fs/nfs/nfs4renewd.c | 5 +---- fs/nfs/nfs4state.c | 4 +--- 4 files changed, 11 insertions(+), 14 deletions(-)
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 6476688b04376..a6b0b544c82d9 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -444,9 +444,7 @@ extern void nfs4_schedule_state_renewal(struct nfs_client *); extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); extern void nfs4_kill_renewd(struct nfs_client *); extern void nfs4_renew_state(struct work_struct *); -extern void nfs4_set_lease_period(struct nfs_client *clp, - unsigned long lease, - unsigned long lastrenewed); +extern void nfs4_set_lease_period(struct nfs_client *clp, unsigned long lease);
/* nfs4state.c */ diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 06faf2f37ad63..926a75d6a4ed6 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -4916,16 +4916,13 @@ static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, str struct nfs4_exception exception = { .interruptible = true, }; - unsigned long now = jiffies; int err;
do { err = _nfs4_do_fsinfo(server, fhandle, fsinfo); trace_nfs4_fsinfo(server, fhandle, fsinfo->fattr, err); if (err == 0) { - nfs4_set_lease_period(server->nfs_client, - fsinfo->lease_time * HZ, - now); + nfs4_set_lease_period(server->nfs_client, fsinfo->lease_time * HZ); break; } err = nfs4_handle_exception(server, err, &exception); @@ -5989,6 +5986,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, .callback_data = &setclientid, .flags = RPC_TASK_TIMEOUT, }; + unsigned long now = jiffies; int status;
/* nfs_client_id4 */ @@ -6026,6 +6024,9 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, put_rpccred(setclientid.sc_cred); } rpc_put_task(task); + + if (status == 0) + do_renew_lease(clp, now); out: trace_nfs4_setclientid(clp, status); dprintk("NFS reply setclientid: %d\n", status); @@ -8083,6 +8084,7 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred, struct rpc_task *task; struct nfs41_exchange_id_args *argp; struct nfs41_exchange_id_res *resp; + unsigned long now = jiffies; int status;
task = nfs4_run_exchange_id(clp, cred, sp4_how, NULL); @@ -8104,6 +8106,8 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred, if (status != 0) goto out;
+ do_renew_lease(clp, now); + clp->cl_clientid = resp->clientid; clp->cl_exchange_flags = resp->flags; clp->cl_seqid = resp->seqid; diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 1f8c2ae43a8df..3da65e1180cdf 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c @@ -141,15 +141,12 @@ nfs4_kill_renewd(struct nfs_client *clp) * * @clp: pointer to nfs_client * @lease: new value for lease period - * @lastrenewed: time at which lease was last renewed */ void nfs4_set_lease_period(struct nfs_client *clp, - unsigned long lease, - unsigned long lastrenewed) + unsigned long lease) { spin_lock(&clp->cl_lock); clp->cl_lease_time = lease; - clp->cl_last_renewal = lastrenewed; spin_unlock(&clp->cl_lock);
/* Cap maximum reconnect timeout at 1/2 lease period */ diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 09c84308eff29..5ff5161046993 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -91,17 +91,15 @@ static int nfs4_setup_state_renewal(struct nfs_client *clp) { int status; struct nfs_fsinfo fsinfo; - unsigned long now;
if (!test_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state)) { nfs4_schedule_state_renewal(clp); return 0; }
- now = jiffies; status = nfs4_proc_get_lease_time(clp, &fsinfo); if (status == 0) { - nfs4_set_lease_period(clp, fsinfo.lease_time * HZ, now); + nfs4_set_lease_period(clp, fsinfo.lease_time * HZ); nfs4_schedule_state_renewal(clp); }
From: Trond Myklebust trond.myklebust@hammerspace.com
mainline inclusion from mainline-v5.7-rc1 commit 244fcd2f9a904523f1b8c1a6c94749e230ac053a category: bugfix bugzilla: NA CVE: NA
--------------------------------
We can't allow delegreturn to hold up nfs4_evict_inode() forever, since that can cause the memory shrinkers to block. This patch therefore ensures that we eventually time out, and complete the reclaim of the inode.
Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/nfs4proc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 926a75d6a4ed6..e30df289e9610 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -6133,6 +6133,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) /* Fallthrough */ case -NFS4ERR_BAD_STATEID: case -NFS4ERR_STALE_STATEID: + case -ETIMEDOUT: task->tk_status = 0; break; case -NFS4ERR_OLD_STATEID: @@ -6221,7 +6222,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co .rpc_client = server->client, .rpc_message = &msg, .callback_ops = &nfs4_delegreturn_ops, - .flags = RPC_TASK_ASYNC, + .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT, }; int status = 0;
From: Anna Schumaker Anna.Schumaker@Netapp.com
mainline inclusion from mainline-v5.8-rc6 commit 913fadc5b105c3619d9e8d0fe8899ff1593cc737 category: bugfix bugzilla: NA CVE: NA
--------------------------------
We used to do this before 3453d5708b33, but this was changed to better handle the NFS4ERR_SEQ_MISORDERED error code. This commit fixed the slot re-use case when the server doesn't receive the interrupted operation, but if the server does receive the operation then it could still end up replying to the client with mis-matched operations from the reply cache.
We can fix this by sending a SEQUENCE to the server while recovering from a SEQ_MISORDERED error when we detect that we are in an interrupted slot situation.
Fixes: 3453d5708b33 (NFSv4.1: Avoid false retries when RPC calls are interrupted) Signed-off-by: Anna Schumaker Anna.Schumaker@Netapp.com
Conflicts: fs/nfs/nfs4proc.c
Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/nfs4proc.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e30df289e9610..ffb7a6e7f5664 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -757,6 +757,15 @@ static void nfs4_slot_sequence_acked(struct nfs4_slot *slot, slot->seq_nr_last_acked = seqnr; }
+static void nfs4_probe_sequence(struct nfs_client *client, + struct rpc_cred *cred, + struct nfs4_slot *slot) +{ + struct rpc_task *task = _nfs41_proc_sequence(client, cred, slot, true); + if (!IS_ERR(task)) + rpc_put_task_async(task); +} + static int nfs41_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res) { @@ -773,6 +782,7 @@ static int nfs41_sequence_process(struct rpc_task *task, goto out;
session = slot->table->session; + clp = session->clp;
trace_nfs4_sequence_done(session, res);
@@ -787,7 +797,6 @@ static int nfs41_sequence_process(struct rpc_task *task, nfs4_slot_sequence_acked(slot, slot->seq_nr); /* Update the slot's sequence and clientid lease timer */ slot->seq_done = 1; - clp = session->clp; do_renew_lease(clp, res->sr_timestamp); /* Check sequence flags */ nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags, @@ -835,10 +844,18 @@ static int nfs41_sequence_process(struct rpc_task *task, /* * Were one or more calls using this slot interrupted? * If the server never received the request, then our - * transmitted slot sequence number may be too high. + * transmitted slot sequence number may be too high. However, + * if the server did receive the request then it might + * accidentally give us a reply with a mismatched operation. + * We can sort this out by sending a lone sequence operation + * to the server on the same slot. */ if ((s32)(slot->seq_nr - slot->seq_nr_last_acked) > 1) { slot->seq_nr--; + if (task->tk_msg.rpc_proc != &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE]) { + nfs4_probe_sequence(clp, task->tk_msg.rpc_cred, slot); + res->sr_slot = NULL; + } goto retry_nowait; } /*
From: Chengguang Xu cgxu519@mykernel.net
mainline inclusion from mainline-v5.10-rc1 commit 82c596ebaa104f994d25256523ae2f9047323fe7 category: bugfix bugzilla: NA CVE: NA
--------------------------------
The variable error is ssize_t, which is signed and will cast to unsigned when comapre with variable size, so add a check to avoid unexpected result in case of negative value of error.
Signed-off-by: Chengguang Xu cgxu519@mykernel.net Signed-off-by: Anna Schumaker Anna.Schumaker@Netapp.com Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/nfs4proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ffb7a6e7f5664..ba68138a0c0e5 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -7246,7 +7246,7 @@ nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) { len = security_inode_listsecurity(inode, list, list_len); - if (list_len && len > list_len) + if (len >= 0 && list_len && len > list_len) return -ERANGE; } return len;
From: Trond Myklebust trond.myklebust@hammerspace.com
mainline inclusion from mainline-v5.11-rc4 commit 113aac6d567bda783af36d08f73bfda47d8e9a40 category: bugfix bugzilla: NA CVE: NA
--------------------------------
Before referencing the inode, we must ensure that the superblock can be referenced. Otherwise, we can end up with iput() calling superblock operations that are no longer valid or accessible.
Fixes: e39d8a186ed0 ("NFSv4: Fix an Oops during delegation callbacks") Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/delegation.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 9a91a1c9fb4eb..8517f0d5cf26b 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -861,21 +861,23 @@ nfs_delegation_find_inode_server(struct nfs_server *server, const struct nfs_fh *fhandle) { struct nfs_delegation *delegation; - struct inode *freeme, *res = NULL; + struct super_block *freeme = NULL; + struct inode *res = NULL;
list_for_each_entry_rcu(delegation, &server->delegations, super_list) { spin_lock(&delegation->lock); if (delegation->inode != NULL && nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) { - freeme = igrab(delegation->inode); - if (freeme && nfs_sb_active(freeme->i_sb)) - res = freeme; + if (nfs_sb_active(server->super)) { + freeme = server->super; + res = igrab(delegation->inode); + } spin_unlock(&delegation->lock); if (res != NULL) return res; if (freeme) { rcu_read_unlock(); - iput(freeme); + nfs_sb_deactive(freeme); rcu_read_lock(); } return ERR_PTR(-EAGAIN);
From: Trond Myklebust trond.myklebust@hammerspace.com
mainline inclusion from mainline-v5.12-rc3 commit 82e7ca1334ab16e2e04fafded1cab9dfcdc11b40 category: bugfix bugzilla: NA CVE: NA
--------------------------------
There should be no reason to expect the directory permissions to change just because the directory contents changed or a negative lookup timed out. So let's avoid doing a full call to nfs_mark_for_revalidate() in that case. Furthermore, if this is a negative dentry, and we haven't actually done a new lookup, then we have no reason yet to believe the directory has changed at all. So let's remove the gratuitous directory inode invalidation altogether when called from nfs_lookup_revalidate_negative().
Reported-by: Geert Jansen gerardu@amazon.com Fixes: 5ceb9d7fdaaf ("NFS: Refactor nfs_lookup_revalidate()") Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com Signed-off-by: Anna Schumaker Anna.Schumaker@Netapp.com Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/dir.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 3908ff8672af1..a4655edf43630 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1072,6 +1072,15 @@ int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags) goto out; }
+static void nfs_mark_dir_for_revalidate(struct inode *inode) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + spin_lock(&inode->i_lock); + nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; + spin_unlock(&inode->i_lock); +} + /* * We judge how long we want to trust negative * dentries by looking at the parent inode mtime. @@ -1106,7 +1115,6 @@ nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry, __func__, dentry); return 1; case 0: - nfs_mark_for_revalidate(dir); if (inode && S_ISDIR(inode->i_mode)) { /* Purge readdir caches. */ nfs_zap_caches(inode); @@ -1187,6 +1195,13 @@ nfs_lookup_revalidate_dentry(struct inode *dir, struct dentry *dentry, nfs_free_fattr(fattr); nfs_free_fhandle(fhandle); nfs4_label_free(label); + + /* + * If the lookup failed despite the dentry change attribute being + * a match, then we should revalidate the directory cache. + */ + if (!ret && nfs_verify_change_attribute(dir, dentry->d_time)) + nfs_mark_dir_for_revalidate(dir); return nfs_lookup_revalidate_done(dir, dentry, inode, ret); }
@@ -1229,7 +1244,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry, error = nfs_lookup_verify_inode(inode, flags); if (error) { if (error == -ESTALE) - nfs_zap_caches(dir); + nfs_mark_dir_for_revalidate(dir); goto out_bad; } nfs_advise_use_readdirplus(dir); @@ -1724,7 +1739,6 @@ nfs_add_or_obtain(struct dentry *dentry, struct nfs_fh *fhandle, dput(parent); return d; out_error: - nfs_mark_for_revalidate(dir); d = ERR_PTR(error); goto out; }
From: Trond Myklebust trond.myklebust@hammerspace.com
mainline inclusion from mainline-v5.12-rc3 commit 47397915ede0192235474b145ebcd81b37b03624 category: bugfix bugzilla: NA CVE: NA
--------------------------------
The fact that the lookup revalidation failed, does not mean that the inode contents have changed.
Fixes: 5ceb9d7fdaaf ("NFS: Refactor nfs_lookup_revalidate()") Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com Signed-off-by: Anna Schumaker Anna.Schumaker@Netapp.com Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/dir.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index a4655edf43630..ff9129c0572d9 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1115,18 +1115,14 @@ nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry, __func__, dentry); return 1; case 0: - if (inode && S_ISDIR(inode->i_mode)) { - /* Purge readdir caches. */ - nfs_zap_caches(inode); - /* - * We can't d_drop the root of a disconnected tree: - * its d_hash is on the s_anon list and d_drop() would hide - * it from shrink_dcache_for_unmount(), leading to busy - * inodes on unmount and further oopses. - */ - if (IS_ROOT(dentry)) - return 1; - } + /* + * We can't d_drop the root of a disconnected tree: + * its d_hash is on the s_anon list and d_drop() would hide + * it from shrink_dcache_for_unmount(), leading to busy + * inodes on unmount and further oopses. + */ + if (inode && IS_ROOT(dentry)) + return 1; dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n", __func__, dentry); return 0;
From: Olga Kornievskaia olga.kornievskaia@gmail.com
mainline inclusion from mainline-v5.7-rc4 commit dff58530c4ca8ce7ee5a74db431c6e35362cf682 category: bugfix bugzilla: NA CVE: NA
--------------------------------
Currently, if the client sends BIND_CONN_TO_SESSION with NFS4_CDFC4_FORE_OR_BOTH but only gets NFS4_CDFS4_FORE back it ignores that it wasn't able to enable a backchannel.
To make sure, the client sends BIND_CONN_TO_SESSION as the first operation on the connections (ie., no other session compounds haven't been sent before), and if the client's request to bind the backchannel is not satisfied, then reset the connection and retry.
Cc: stable@vger.kernel.org Signed-off-by: Olga Kornievskaia kolga@netapp.com Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com
Conflicts: include/linux/sunrpc/clnt.h
Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/nfs/nfs4proc.c | 8 ++++++++ include/linux/nfs_xdr.h | 2 ++ include/linux/sunrpc/clnt.h | 5 +++++ 3 files changed, 15 insertions(+)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ba68138a0c0e5..35a60c3ed023f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -7735,6 +7735,7 @@ static void nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata) { struct nfs41_bind_conn_to_session_args *args = task->tk_msg.rpc_argp; + struct nfs41_bind_conn_to_session_res *res = task->tk_msg.rpc_resp; struct nfs_client *clp = args->client;
switch (task->tk_status) { @@ -7743,6 +7744,12 @@ nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata) nfs4_schedule_session_recovery(clp->cl_session, task->tk_status); } + if (args->dir == NFS4_CDFC4_FORE_OR_BOTH && + res->dir != NFS4_CDFS4_BOTH) { + rpc_task_close_connection(task); + if (args->retries++ < MAX_BIND_CONN_TO_SESSION_RETRIES) + rpc_restart_call(task); + } }
static const struct rpc_call_ops nfs4_bind_one_conn_to_session_ops = { @@ -7765,6 +7772,7 @@ int nfs4_proc_bind_one_conn_to_session(struct rpc_clnt *clnt, struct nfs41_bind_conn_to_session_args args = { .client = clp, .dir = NFS4_CDFC4_FORE_OR_BOTH, + .retries = 0, }; struct nfs41_bind_conn_to_session_res res; struct rpc_message msg = { diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index cab24a127feb3..62cf39e74a303 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1261,11 +1261,13 @@ struct nfs41_impl_id { struct nfstime4 date; };
+#define MAX_BIND_CONN_TO_SESSION_RETRIES 3 struct nfs41_bind_conn_to_session_args { struct nfs_client *client; struct nfs4_sessionid sessionid; u32 dir; bool use_conn_in_rdma_mode; + int retries; };
struct nfs41_bind_conn_to_session_res { diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 60b6489e5ac1b..10bcbea6e952e 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -226,5 +226,10 @@ static inline int rpc_reply_expected(struct rpc_task *task) (task->tk_msg.rpc_proc->p_decode != NULL); }
+static inline void rpc_task_close_connection(struct rpc_task *task) +{ + if (task->tk_xprt) + xprt_force_disconnect(task->tk_xprt); +} #endif /* __KERNEL__ */ #endif /* _LINUX_SUNRPC_CLNT_H */