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