Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crypto: hisilicon/qm - save capability registers in qm init process

In previous capability register implementation, qm irq related values
were read from capability registers dynamically when needed. But in
abnormal scenario, e.g. the core is timeout and the device needs to
soft reset and reset failed after disabling the MSE, the device can
not be removed normally, causing the following call trace:

| Call trace:
| pci_irq_vector+0xfc/0x140
| hisi_qm_uninit+0x278/0x3b0 [hisi_qm]
| hpre_remove+0x16c/0x1c0 [hisi_hpre]
| pci_device_remove+0x6c/0x264
| device_release_driver_internal+0x1ec/0x3e0
| device_release_driver+0x3c/0x60
| pci_stop_bus_device+0xfc/0x22c
| pci_stop_and_remove_bus_device+0x38/0x70
| pci_iov_remove_virtfn+0x108/0x1c0
| sriov_disable+0x7c/0x1e4
| pci_disable_sriov+0x4c/0x6c
| hisi_qm_sriov_disable+0x90/0x160 [hisi_qm]
| hpre_remove+0x1a8/0x1c0 [hisi_hpre]
| pci_device_remove+0x6c/0x264
| device_release_driver_internal+0x1ec/0x3e0
| driver_detach+0x168/0x2d0
| bus_remove_driver+0xc0/0x230
| driver_unregister+0x58/0xdc
| pci_unregister_driver+0x40/0x220
| hpre_exit+0x34/0x64 [hisi_hpre]
| __arm64_sys_delete_module+0x374/0x620
[...]

| Call trace:
| free_msi_irqs+0x25c/0x300
| pci_disable_msi+0x19c/0x264
| pci_free_irq_vectors+0x4c/0x70
| hisi_qm_pci_uninit+0x44/0x90 [hisi_qm]
| hisi_qm_uninit+0x28c/0x3b0 [hisi_qm]
| hpre_remove+0x16c/0x1c0 [hisi_hpre]
| pci_device_remove+0x6c/0x264
[...]

The reason for this call trace is that when the MSE is disabled, the value
of capability registers in the BAR space become invalid. This will make the
subsequent unregister process get the wrong irq vector through capability
registers and get the wrong irq number by pci_irq_vector().

So add a capability table structure to pre-store the valid value of the irq
information capability register in qm init process, avoid obtaining invalid
capability register value after the MSE is disabled.

Fixes: 3536cc55cada ("crypto: hisilicon/qm - support get device irq information from hardware registers")
Signed-off-by: Zhiqi Song <songzhiqi1@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Zhiqi Song and committed by
Herbert Xu
cabe13d0 f76f0d7f

+64 -10
+52 -10
drivers/crypto/hisilicon/qm.c
··· 301 301 QM_VF_IRQ_NUM_CAP, 302 302 }; 303 303 304 + enum qm_pre_store_cap_idx { 305 + QM_EQ_IRQ_TYPE_CAP_IDX = 0x0, 306 + QM_AEQ_IRQ_TYPE_CAP_IDX, 307 + QM_ABN_IRQ_TYPE_CAP_IDX, 308 + QM_PF2VF_IRQ_TYPE_CAP_IDX, 309 + }; 310 + 304 311 static const struct hisi_qm_cap_info qm_cap_info_comm[] = { 305 312 {QM_SUPPORT_DB_ISOLATION, 0x30, 0, BIT(0), 0x0, 0x0, 0x0}, 306 313 {QM_SUPPORT_FUNC_QOS, 0x3100, 0, BIT(8), 0x0, 0x0, 0x1}, ··· 335 328 {QM_PF2VF_IRQ_TYPE_CAP, 0x3118, 0, GENMASK(31, 0), 0x0, 0x0, 0x10002}, 336 329 {QM_PF_IRQ_NUM_CAP, 0x311c, 16, GENMASK(15, 0), 0x1, 0x4, 0x4}, 337 330 {QM_VF_IRQ_NUM_CAP, 0x311c, 0, GENMASK(15, 0), 0x1, 0x2, 0x3}, 331 + }; 332 + 333 + static const u32 qm_pre_store_caps[] = { 334 + QM_EQ_IRQ_TYPE_CAP, 335 + QM_AEQ_IRQ_TYPE_CAP, 336 + QM_ABN_IRQ_TYPE_CAP, 337 + QM_PF2VF_IRQ_TYPE_CAP, 338 338 }; 339 339 340 340 struct qm_mailbox { ··· 4788 4774 if (qm->fun_type == QM_HW_VF) 4789 4775 return; 4790 4776 4791 - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_ABN_IRQ_TYPE_CAP, qm->cap_ver); 4777 + val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val; 4792 4778 if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK)) 4793 4779 return; 4794 4780 ··· 4805 4791 if (qm->fun_type == QM_HW_VF) 4806 4792 return 0; 4807 4793 4808 - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_ABN_IRQ_TYPE_CAP, qm->cap_ver); 4794 + val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val; 4809 4795 if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK)) 4810 4796 return 0; 4811 4797 ··· 4822 4808 struct pci_dev *pdev = qm->pdev; 4823 4809 u32 irq_vector, val; 4824 4810 4825 - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_PF2VF_IRQ_TYPE_CAP, qm->cap_ver); 4811 + val = qm->cap_tables.qm_cap_table[QM_PF2VF_IRQ_TYPE_CAP_IDX].cap_val; 4826 4812 if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) 4827 4813 return; 4828 4814 ··· 4836 4822 u32 irq_vector, val; 4837 4823 int ret; 4838 4824 4839 - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_PF2VF_IRQ_TYPE_CAP, qm->cap_ver); 4825 + val = qm->cap_tables.qm_cap_table[QM_PF2VF_IRQ_TYPE_CAP_IDX].cap_val; 4840 4826 if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) 4841 4827 return 0; 4842 4828 ··· 4853 4839 struct pci_dev *pdev = qm->pdev; 4854 4840 u32 irq_vector, val; 4855 4841 4856 - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_AEQ_IRQ_TYPE_CAP, qm->cap_ver); 4842 + val = qm->cap_tables.qm_cap_table[QM_AEQ_IRQ_TYPE_CAP_IDX].cap_val; 4857 4843 if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) 4858 4844 return; 4859 4845 ··· 4867 4853 u32 irq_vector, val; 4868 4854 int ret; 4869 4855 4870 - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_AEQ_IRQ_TYPE_CAP, qm->cap_ver); 4856 + val = qm->cap_tables.qm_cap_table[QM_AEQ_IRQ_TYPE_CAP_IDX].cap_val; 4871 4857 if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) 4872 4858 return 0; 4873 4859 ··· 4885 4871 struct pci_dev *pdev = qm->pdev; 4886 4872 u32 irq_vector, val; 4887 4873 4888 - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_EQ_IRQ_TYPE_CAP, qm->cap_ver); 4874 + val = qm->cap_tables.qm_cap_table[QM_EQ_IRQ_TYPE_CAP_IDX].cap_val; 4889 4875 if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) 4890 4876 return; 4891 4877 ··· 4899 4885 u32 irq_vector, val; 4900 4886 int ret; 4901 4887 4902 - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_EQ_IRQ_TYPE_CAP, qm->cap_ver); 4888 + val = qm->cap_tables.qm_cap_table[QM_EQ_IRQ_TYPE_CAP_IDX].cap_val; 4903 4889 if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) 4904 4890 return 0; 4905 4891 ··· 4987 4973 return 0; 4988 4974 } 4989 4975 4990 - static void qm_get_hw_caps(struct hisi_qm *qm) 4976 + static int qm_pre_store_irq_type_caps(struct hisi_qm *qm) 4977 + { 4978 + struct hisi_qm_cap_record *qm_cap; 4979 + struct pci_dev *pdev = qm->pdev; 4980 + size_t i, size; 4981 + 4982 + size = ARRAY_SIZE(qm_pre_store_caps); 4983 + qm_cap = devm_kzalloc(&pdev->dev, sizeof(*qm_cap) * size, GFP_KERNEL); 4984 + if (!qm_cap) 4985 + return -ENOMEM; 4986 + 4987 + for (i = 0; i < size; i++) { 4988 + qm_cap[i].type = qm_pre_store_caps[i]; 4989 + qm_cap[i].cap_val = hisi_qm_get_hw_info(qm, qm_basic_info, 4990 + qm_pre_store_caps[i], qm->cap_ver); 4991 + } 4992 + 4993 + qm->cap_tables.qm_cap_table = qm_cap; 4994 + 4995 + return 0; 4996 + } 4997 + 4998 + static int qm_get_hw_caps(struct hisi_qm *qm) 4991 4999 { 4992 5000 const struct hisi_qm_cap_info *cap_info = qm->fun_type == QM_HW_PF ? 4993 5001 qm_cap_info_pf : qm_cap_info_vf; ··· 5040 5004 if (val) 5041 5005 set_bit(cap_info[i].type, &qm->caps); 5042 5006 } 5007 + 5008 + /* Fetch and save the value of irq type related capability registers */ 5009 + return qm_pre_store_irq_type_caps(qm); 5043 5010 } 5044 5011 5045 5012 static int qm_get_pci_res(struct hisi_qm *qm) ··· 5064 5025 goto err_request_mem_regions; 5065 5026 } 5066 5027 5067 - qm_get_hw_caps(qm); 5028 + ret = qm_get_hw_caps(qm); 5029 + if (ret) 5030 + goto err_ioremap; 5031 + 5068 5032 if (test_bit(QM_SUPPORT_DB_ISOLATION, &qm->caps)) { 5069 5033 qm->db_interval = QM_QP_DB_INTERVAL; 5070 5034 qm->db_phys_base = pci_resource_start(pdev, PCI_BAR_4);
+12
include/linux/hisi_acc_qm.h
··· 266 266 u32 v3_val; 267 267 }; 268 268 269 + struct hisi_qm_cap_record { 270 + u32 type; 271 + u32 cap_val; 272 + }; 273 + 274 + struct hisi_qm_cap_tables { 275 + struct hisi_qm_cap_record *qm_cap_table; 276 + struct hisi_qm_cap_record *dev_cap_table; 277 + }; 278 + 269 279 struct hisi_qm_list { 270 280 struct mutex lock; 271 281 struct list_head list; ··· 386 376 u32 mb_qos; 387 377 u32 type_rate; 388 378 struct qm_err_isolate isolate_data; 379 + 380 + struct hisi_qm_cap_tables cap_tables; 389 381 }; 390 382 391 383 struct hisi_qp_status {