1d9110b0bSSrujanaChalla // SPDX-License-Identifier: GPL-2.0 2d9110b0bSSrujanaChalla /* Marvell OcteonTX CPT driver 3d9110b0bSSrujanaChalla * 4d9110b0bSSrujanaChalla * Copyright (C) 2019 Marvell International Ltd. 5d9110b0bSSrujanaChalla * 6d9110b0bSSrujanaChalla * This program is free software; you can redistribute it and/or modify 7d9110b0bSSrujanaChalla * it under the terms of the GNU General Public License version 2 as 8d9110b0bSSrujanaChalla * published by the Free Software Foundation. 9d9110b0bSSrujanaChalla */ 10d9110b0bSSrujanaChalla 11d9110b0bSSrujanaChalla #include "otx_cpt_common.h" 12d9110b0bSSrujanaChalla #include "otx_cptpf.h" 13d9110b0bSSrujanaChalla 14d9110b0bSSrujanaChalla #define DRV_NAME "octeontx-cpt" 15d9110b0bSSrujanaChalla #define DRV_VERSION "1.0" 16d9110b0bSSrujanaChalla 17d9110b0bSSrujanaChalla static void otx_cpt_disable_mbox_interrupts(struct otx_cpt_device *cpt) 18d9110b0bSSrujanaChalla { 19d9110b0bSSrujanaChalla /* Disable mbox(0) interrupts for all VFs */ 20d9110b0bSSrujanaChalla writeq(~0ull, cpt->reg_base + OTX_CPT_PF_MBOX_ENA_W1CX(0)); 21d9110b0bSSrujanaChalla } 22d9110b0bSSrujanaChalla 23d9110b0bSSrujanaChalla static void otx_cpt_enable_mbox_interrupts(struct otx_cpt_device *cpt) 24d9110b0bSSrujanaChalla { 25d9110b0bSSrujanaChalla /* Enable mbox(0) interrupts for all VFs */ 26d9110b0bSSrujanaChalla writeq(~0ull, cpt->reg_base + OTX_CPT_PF_MBOX_ENA_W1SX(0)); 27d9110b0bSSrujanaChalla } 28d9110b0bSSrujanaChalla 29d9110b0bSSrujanaChalla static irqreturn_t otx_cpt_mbx0_intr_handler(int __always_unused irq, 30d9110b0bSSrujanaChalla void *cpt) 31d9110b0bSSrujanaChalla { 32d9110b0bSSrujanaChalla otx_cpt_mbox_intr_handler(cpt, 0); 33d9110b0bSSrujanaChalla 34d9110b0bSSrujanaChalla return IRQ_HANDLED; 35d9110b0bSSrujanaChalla } 36d9110b0bSSrujanaChalla 37d9110b0bSSrujanaChalla static void otx_cpt_reset(struct otx_cpt_device *cpt) 38d9110b0bSSrujanaChalla { 39d9110b0bSSrujanaChalla writeq(1, cpt->reg_base + OTX_CPT_PF_RESET); 40d9110b0bSSrujanaChalla } 41d9110b0bSSrujanaChalla 42d9110b0bSSrujanaChalla static void otx_cpt_find_max_enabled_cores(struct otx_cpt_device *cpt) 43d9110b0bSSrujanaChalla { 44d9110b0bSSrujanaChalla union otx_cptx_pf_constants pf_cnsts = {0}; 45d9110b0bSSrujanaChalla 46d9110b0bSSrujanaChalla pf_cnsts.u = readq(cpt->reg_base + OTX_CPT_PF_CONSTANTS); 47d9110b0bSSrujanaChalla cpt->eng_grps.avail.max_se_cnt = pf_cnsts.s.se; 48d9110b0bSSrujanaChalla cpt->eng_grps.avail.max_ae_cnt = pf_cnsts.s.ae; 49d9110b0bSSrujanaChalla } 50d9110b0bSSrujanaChalla 51d9110b0bSSrujanaChalla static u32 otx_cpt_check_bist_status(struct otx_cpt_device *cpt) 52d9110b0bSSrujanaChalla { 53d9110b0bSSrujanaChalla union otx_cptx_pf_bist_status bist_sts = {0}; 54d9110b0bSSrujanaChalla 55d9110b0bSSrujanaChalla bist_sts.u = readq(cpt->reg_base + OTX_CPT_PF_BIST_STATUS); 56d9110b0bSSrujanaChalla return bist_sts.u; 57d9110b0bSSrujanaChalla } 58d9110b0bSSrujanaChalla 59d9110b0bSSrujanaChalla static u64 otx_cpt_check_exe_bist_status(struct otx_cpt_device *cpt) 60d9110b0bSSrujanaChalla { 61d9110b0bSSrujanaChalla union otx_cptx_pf_exe_bist_status bist_sts = {0}; 62d9110b0bSSrujanaChalla 63d9110b0bSSrujanaChalla bist_sts.u = readq(cpt->reg_base + OTX_CPT_PF_EXE_BIST_STATUS); 64d9110b0bSSrujanaChalla return bist_sts.u; 65d9110b0bSSrujanaChalla } 66d9110b0bSSrujanaChalla 67d9110b0bSSrujanaChalla static int otx_cpt_device_init(struct otx_cpt_device *cpt) 68d9110b0bSSrujanaChalla { 69d9110b0bSSrujanaChalla struct device *dev = &cpt->pdev->dev; 70d9110b0bSSrujanaChalla u16 sdevid; 71d9110b0bSSrujanaChalla u64 bist; 72d9110b0bSSrujanaChalla 73d9110b0bSSrujanaChalla /* Reset the PF when probed first */ 74d9110b0bSSrujanaChalla otx_cpt_reset(cpt); 75d9110b0bSSrujanaChalla mdelay(100); 76d9110b0bSSrujanaChalla 77d9110b0bSSrujanaChalla pci_read_config_word(cpt->pdev, PCI_SUBSYSTEM_ID, &sdevid); 78d9110b0bSSrujanaChalla 79d9110b0bSSrujanaChalla /* Check BIST status */ 80d9110b0bSSrujanaChalla bist = (u64)otx_cpt_check_bist_status(cpt); 81d9110b0bSSrujanaChalla if (bist) { 82*0a8f5989SChristophe JAILLET dev_err(dev, "RAM BIST failed with code 0x%llx\n", bist); 83d9110b0bSSrujanaChalla return -ENODEV; 84d9110b0bSSrujanaChalla } 85d9110b0bSSrujanaChalla 86d9110b0bSSrujanaChalla bist = otx_cpt_check_exe_bist_status(cpt); 87d9110b0bSSrujanaChalla if (bist) { 88*0a8f5989SChristophe JAILLET dev_err(dev, "Engine BIST failed with code 0x%llx\n", bist); 89d9110b0bSSrujanaChalla return -ENODEV; 90d9110b0bSSrujanaChalla } 91d9110b0bSSrujanaChalla 92d9110b0bSSrujanaChalla /* Get max enabled cores */ 93d9110b0bSSrujanaChalla otx_cpt_find_max_enabled_cores(cpt); 94d9110b0bSSrujanaChalla 95d9110b0bSSrujanaChalla if ((sdevid == OTX_CPT_PCI_PF_SUBSYS_ID) && 96d9110b0bSSrujanaChalla (cpt->eng_grps.avail.max_se_cnt == 0)) { 97d9110b0bSSrujanaChalla cpt->pf_type = OTX_CPT_AE; 98d9110b0bSSrujanaChalla } else if ((sdevid == OTX_CPT_PCI_PF_SUBSYS_ID) && 99d9110b0bSSrujanaChalla (cpt->eng_grps.avail.max_ae_cnt == 0)) { 100d9110b0bSSrujanaChalla cpt->pf_type = OTX_CPT_SE; 101d9110b0bSSrujanaChalla } 102d9110b0bSSrujanaChalla 103d9110b0bSSrujanaChalla /* Get max VQs/VFs supported by the device */ 104d9110b0bSSrujanaChalla cpt->max_vfs = pci_sriov_get_totalvfs(cpt->pdev); 105d9110b0bSSrujanaChalla 106d9110b0bSSrujanaChalla /* Disable all cores */ 107d9110b0bSSrujanaChalla otx_cpt_disable_all_cores(cpt); 108d9110b0bSSrujanaChalla 109d9110b0bSSrujanaChalla return 0; 110d9110b0bSSrujanaChalla } 111d9110b0bSSrujanaChalla 112d9110b0bSSrujanaChalla static int otx_cpt_register_interrupts(struct otx_cpt_device *cpt) 113d9110b0bSSrujanaChalla { 114d9110b0bSSrujanaChalla struct device *dev = &cpt->pdev->dev; 115d9110b0bSSrujanaChalla u32 mbox_int_idx = OTX_CPT_PF_MBOX_INT; 116d9110b0bSSrujanaChalla u32 num_vec = OTX_CPT_PF_MSIX_VECTORS; 117d9110b0bSSrujanaChalla int ret; 118d9110b0bSSrujanaChalla 119d9110b0bSSrujanaChalla /* Enable MSI-X */ 120d9110b0bSSrujanaChalla ret = pci_alloc_irq_vectors(cpt->pdev, num_vec, num_vec, PCI_IRQ_MSIX); 121d9110b0bSSrujanaChalla if (ret < 0) { 122d9110b0bSSrujanaChalla dev_err(&cpt->pdev->dev, 123d9110b0bSSrujanaChalla "Request for #%d msix vectors failed\n", 124d9110b0bSSrujanaChalla num_vec); 125d9110b0bSSrujanaChalla return ret; 126d9110b0bSSrujanaChalla } 127d9110b0bSSrujanaChalla 128d9110b0bSSrujanaChalla /* Register mailbox interrupt handlers */ 129d9110b0bSSrujanaChalla ret = request_irq(pci_irq_vector(cpt->pdev, 130d9110b0bSSrujanaChalla OTX_CPT_PF_INT_VEC_E_MBOXX(mbox_int_idx, 0)), 131d9110b0bSSrujanaChalla otx_cpt_mbx0_intr_handler, 0, "CPT Mbox0", cpt); 132d9110b0bSSrujanaChalla if (ret) { 133d9110b0bSSrujanaChalla dev_err(dev, "Request irq failed\n"); 134d9110b0bSSrujanaChalla pci_free_irq_vectors(cpt->pdev); 135d9110b0bSSrujanaChalla return ret; 136d9110b0bSSrujanaChalla } 137d9110b0bSSrujanaChalla /* Enable mailbox interrupt */ 138d9110b0bSSrujanaChalla otx_cpt_enable_mbox_interrupts(cpt); 139d9110b0bSSrujanaChalla return 0; 140d9110b0bSSrujanaChalla } 141d9110b0bSSrujanaChalla 142d9110b0bSSrujanaChalla static void otx_cpt_unregister_interrupts(struct otx_cpt_device *cpt) 143d9110b0bSSrujanaChalla { 144d9110b0bSSrujanaChalla u32 mbox_int_idx = OTX_CPT_PF_MBOX_INT; 145d9110b0bSSrujanaChalla 146d9110b0bSSrujanaChalla otx_cpt_disable_mbox_interrupts(cpt); 147d9110b0bSSrujanaChalla free_irq(pci_irq_vector(cpt->pdev, 148d9110b0bSSrujanaChalla OTX_CPT_PF_INT_VEC_E_MBOXX(mbox_int_idx, 0)), 149d9110b0bSSrujanaChalla cpt); 150d9110b0bSSrujanaChalla pci_free_irq_vectors(cpt->pdev); 151d9110b0bSSrujanaChalla } 152d9110b0bSSrujanaChalla 153d9110b0bSSrujanaChalla 154d9110b0bSSrujanaChalla static int otx_cpt_sriov_configure(struct pci_dev *pdev, int numvfs) 155d9110b0bSSrujanaChalla { 156d9110b0bSSrujanaChalla struct otx_cpt_device *cpt = pci_get_drvdata(pdev); 157d9110b0bSSrujanaChalla int ret = 0; 158d9110b0bSSrujanaChalla 159d9110b0bSSrujanaChalla if (numvfs > cpt->max_vfs) 160d9110b0bSSrujanaChalla numvfs = cpt->max_vfs; 161d9110b0bSSrujanaChalla 162d9110b0bSSrujanaChalla if (numvfs > 0) { 163d9110b0bSSrujanaChalla ret = otx_cpt_try_create_default_eng_grps(cpt->pdev, 164d9110b0bSSrujanaChalla &cpt->eng_grps, 165d9110b0bSSrujanaChalla cpt->pf_type); 166d9110b0bSSrujanaChalla if (ret) 167d9110b0bSSrujanaChalla return ret; 168d9110b0bSSrujanaChalla 169d9110b0bSSrujanaChalla cpt->vfs_enabled = numvfs; 170d9110b0bSSrujanaChalla ret = pci_enable_sriov(pdev, numvfs); 171d9110b0bSSrujanaChalla if (ret) { 172d9110b0bSSrujanaChalla cpt->vfs_enabled = 0; 173d9110b0bSSrujanaChalla return ret; 174d9110b0bSSrujanaChalla } 175d9110b0bSSrujanaChalla otx_cpt_set_eng_grps_is_rdonly(&cpt->eng_grps, true); 176d9110b0bSSrujanaChalla try_module_get(THIS_MODULE); 177d9110b0bSSrujanaChalla ret = numvfs; 178d9110b0bSSrujanaChalla } else { 179d9110b0bSSrujanaChalla pci_disable_sriov(pdev); 180d9110b0bSSrujanaChalla otx_cpt_set_eng_grps_is_rdonly(&cpt->eng_grps, false); 181d9110b0bSSrujanaChalla module_put(THIS_MODULE); 182d9110b0bSSrujanaChalla cpt->vfs_enabled = 0; 183d9110b0bSSrujanaChalla } 184d9110b0bSSrujanaChalla dev_notice(&cpt->pdev->dev, "VFs enabled: %d\n", ret); 185d9110b0bSSrujanaChalla 186d9110b0bSSrujanaChalla return ret; 187d9110b0bSSrujanaChalla } 188d9110b0bSSrujanaChalla 189d9110b0bSSrujanaChalla static int otx_cpt_probe(struct pci_dev *pdev, 190d9110b0bSSrujanaChalla const struct pci_device_id __always_unused *ent) 191d9110b0bSSrujanaChalla { 192d9110b0bSSrujanaChalla struct device *dev = &pdev->dev; 193d9110b0bSSrujanaChalla struct otx_cpt_device *cpt; 194d9110b0bSSrujanaChalla int err; 195d9110b0bSSrujanaChalla 196d9110b0bSSrujanaChalla cpt = devm_kzalloc(dev, sizeof(*cpt), GFP_KERNEL); 197d9110b0bSSrujanaChalla if (!cpt) 198d9110b0bSSrujanaChalla return -ENOMEM; 199d9110b0bSSrujanaChalla 200d9110b0bSSrujanaChalla pci_set_drvdata(pdev, cpt); 201d9110b0bSSrujanaChalla cpt->pdev = pdev; 202d9110b0bSSrujanaChalla 203d9110b0bSSrujanaChalla err = pci_enable_device(pdev); 204d9110b0bSSrujanaChalla if (err) { 205d9110b0bSSrujanaChalla dev_err(dev, "Failed to enable PCI device\n"); 206d9110b0bSSrujanaChalla goto err_clear_drvdata; 207d9110b0bSSrujanaChalla } 208d9110b0bSSrujanaChalla 209d9110b0bSSrujanaChalla err = pci_request_regions(pdev, DRV_NAME); 210d9110b0bSSrujanaChalla if (err) { 211d9110b0bSSrujanaChalla dev_err(dev, "PCI request regions failed 0x%x\n", err); 212d9110b0bSSrujanaChalla goto err_disable_device; 213d9110b0bSSrujanaChalla } 214d9110b0bSSrujanaChalla 215d9110b0bSSrujanaChalla err = pci_set_dma_mask(pdev, DMA_BIT_MASK(48)); 216d9110b0bSSrujanaChalla if (err) { 217d9110b0bSSrujanaChalla dev_err(dev, "Unable to get usable DMA configuration\n"); 218d9110b0bSSrujanaChalla goto err_release_regions; 219d9110b0bSSrujanaChalla } 220d9110b0bSSrujanaChalla 221d9110b0bSSrujanaChalla err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(48)); 222d9110b0bSSrujanaChalla if (err) { 223d9110b0bSSrujanaChalla dev_err(dev, "Unable to get 48-bit DMA for consistent allocations\n"); 224d9110b0bSSrujanaChalla goto err_release_regions; 225d9110b0bSSrujanaChalla } 226d9110b0bSSrujanaChalla 227d9110b0bSSrujanaChalla /* MAP PF's configuration registers */ 228d9110b0bSSrujanaChalla cpt->reg_base = pci_iomap(pdev, OTX_CPT_PF_PCI_CFG_BAR, 0); 229d9110b0bSSrujanaChalla if (!cpt->reg_base) { 230d9110b0bSSrujanaChalla dev_err(dev, "Cannot map config register space, aborting\n"); 231d9110b0bSSrujanaChalla err = -ENOMEM; 232d9110b0bSSrujanaChalla goto err_release_regions; 233d9110b0bSSrujanaChalla } 234d9110b0bSSrujanaChalla 235d9110b0bSSrujanaChalla /* CPT device HW initialization */ 236d9110b0bSSrujanaChalla err = otx_cpt_device_init(cpt); 237d9110b0bSSrujanaChalla if (err) 238d9110b0bSSrujanaChalla goto err_unmap_region; 239d9110b0bSSrujanaChalla 240d9110b0bSSrujanaChalla /* Register interrupts */ 241d9110b0bSSrujanaChalla err = otx_cpt_register_interrupts(cpt); 242d9110b0bSSrujanaChalla if (err) 243d9110b0bSSrujanaChalla goto err_unmap_region; 244d9110b0bSSrujanaChalla 245d9110b0bSSrujanaChalla /* Initialize engine groups */ 246d9110b0bSSrujanaChalla err = otx_cpt_init_eng_grps(pdev, &cpt->eng_grps, cpt->pf_type); 247d9110b0bSSrujanaChalla if (err) 248d9110b0bSSrujanaChalla goto err_unregister_interrupts; 249d9110b0bSSrujanaChalla 250d9110b0bSSrujanaChalla return 0; 251d9110b0bSSrujanaChalla 252d9110b0bSSrujanaChalla err_unregister_interrupts: 253d9110b0bSSrujanaChalla otx_cpt_unregister_interrupts(cpt); 254d9110b0bSSrujanaChalla err_unmap_region: 255d9110b0bSSrujanaChalla pci_iounmap(pdev, cpt->reg_base); 256d9110b0bSSrujanaChalla err_release_regions: 257d9110b0bSSrujanaChalla pci_release_regions(pdev); 258d9110b0bSSrujanaChalla err_disable_device: 259d9110b0bSSrujanaChalla pci_disable_device(pdev); 260d9110b0bSSrujanaChalla err_clear_drvdata: 261d9110b0bSSrujanaChalla pci_set_drvdata(pdev, NULL); 262d9110b0bSSrujanaChalla 263d9110b0bSSrujanaChalla return err; 264d9110b0bSSrujanaChalla } 265d9110b0bSSrujanaChalla 266d9110b0bSSrujanaChalla static void otx_cpt_remove(struct pci_dev *pdev) 267d9110b0bSSrujanaChalla { 268d9110b0bSSrujanaChalla struct otx_cpt_device *cpt = pci_get_drvdata(pdev); 269d9110b0bSSrujanaChalla 270d9110b0bSSrujanaChalla if (!cpt) 271d9110b0bSSrujanaChalla return; 272d9110b0bSSrujanaChalla 273d9110b0bSSrujanaChalla /* Disable VFs */ 274d9110b0bSSrujanaChalla pci_disable_sriov(pdev); 275d9110b0bSSrujanaChalla /* Cleanup engine groups */ 276d9110b0bSSrujanaChalla otx_cpt_cleanup_eng_grps(pdev, &cpt->eng_grps); 277d9110b0bSSrujanaChalla /* Disable CPT PF interrupts */ 278d9110b0bSSrujanaChalla otx_cpt_unregister_interrupts(cpt); 279d9110b0bSSrujanaChalla /* Disengage SE and AE cores from all groups */ 280d9110b0bSSrujanaChalla otx_cpt_disable_all_cores(cpt); 281d9110b0bSSrujanaChalla pci_iounmap(pdev, cpt->reg_base); 282d9110b0bSSrujanaChalla pci_release_regions(pdev); 283d9110b0bSSrujanaChalla pci_disable_device(pdev); 284d9110b0bSSrujanaChalla pci_set_drvdata(pdev, NULL); 285d9110b0bSSrujanaChalla } 286d9110b0bSSrujanaChalla 287d9110b0bSSrujanaChalla /* Supported devices */ 288d9110b0bSSrujanaChalla static const struct pci_device_id otx_cpt_id_table[] = { 289d9110b0bSSrujanaChalla { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OTX_CPT_PCI_PF_DEVICE_ID) }, 290d9110b0bSSrujanaChalla { 0, } /* end of table */ 291d9110b0bSSrujanaChalla }; 292d9110b0bSSrujanaChalla 293d9110b0bSSrujanaChalla static struct pci_driver otx_cpt_pci_driver = { 294d9110b0bSSrujanaChalla .name = DRV_NAME, 295d9110b0bSSrujanaChalla .id_table = otx_cpt_id_table, 296d9110b0bSSrujanaChalla .probe = otx_cpt_probe, 297d9110b0bSSrujanaChalla .remove = otx_cpt_remove, 298d9110b0bSSrujanaChalla .sriov_configure = otx_cpt_sriov_configure 299d9110b0bSSrujanaChalla }; 300d9110b0bSSrujanaChalla 301d9110b0bSSrujanaChalla module_pci_driver(otx_cpt_pci_driver); 302d9110b0bSSrujanaChalla 303d9110b0bSSrujanaChalla MODULE_AUTHOR("Marvell International Ltd."); 304d9110b0bSSrujanaChalla MODULE_DESCRIPTION("Marvell OcteonTX CPT Physical Function Driver"); 305d9110b0bSSrujanaChalla MODULE_LICENSE("GPL v2"); 306d9110b0bSSrujanaChalla MODULE_VERSION(DRV_VERSION); 307d9110b0bSSrujanaChalla MODULE_DEVICE_TABLE(pci, otx_cpt_id_table); 308