linux/drivers/crypto/marvell/octeontx/otx_cptpf_main.c
<<
>>
Prefs
   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
  17static 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
  23static 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
  29static 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
  37static void otx_cpt_reset(struct otx_cpt_device *cpt)
  38{
  39        writeq(1, cpt->reg_base + OTX_CPT_PF_RESET);
  40}
  41
  42static 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
  51static 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
  59static 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
  67static 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\n", 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\n", 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
 112static 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
 142static 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
 154static 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
 189static 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 = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48));
 216        if (err) {
 217                dev_err(dev, "Unable to get usable 48-bit DMA configuration\n");
 218                goto err_release_regions;
 219        }
 220
 221        /* MAP PF's configuration registers */
 222        cpt->reg_base = pci_iomap(pdev, OTX_CPT_PF_PCI_CFG_BAR, 0);
 223        if (!cpt->reg_base) {
 224                dev_err(dev, "Cannot map config register space, aborting\n");
 225                err = -ENOMEM;
 226                goto err_release_regions;
 227        }
 228
 229        /* CPT device HW initialization */
 230        err = otx_cpt_device_init(cpt);
 231        if (err)
 232                goto err_unmap_region;
 233
 234        /* Register interrupts */
 235        err = otx_cpt_register_interrupts(cpt);
 236        if (err)
 237                goto err_unmap_region;
 238
 239        /* Initialize engine groups */
 240        err = otx_cpt_init_eng_grps(pdev, &cpt->eng_grps, cpt->pf_type);
 241        if (err)
 242                goto err_unregister_interrupts;
 243
 244        return 0;
 245
 246err_unregister_interrupts:
 247        otx_cpt_unregister_interrupts(cpt);
 248err_unmap_region:
 249        pci_iounmap(pdev, cpt->reg_base);
 250err_release_regions:
 251        pci_release_regions(pdev);
 252err_disable_device:
 253        pci_disable_device(pdev);
 254err_clear_drvdata:
 255        pci_set_drvdata(pdev, NULL);
 256
 257        return err;
 258}
 259
 260static void otx_cpt_remove(struct pci_dev *pdev)
 261{
 262        struct otx_cpt_device *cpt = pci_get_drvdata(pdev);
 263
 264        if (!cpt)
 265                return;
 266
 267        /* Disable VFs */
 268        pci_disable_sriov(pdev);
 269        /* Cleanup engine groups */
 270        otx_cpt_cleanup_eng_grps(pdev, &cpt->eng_grps);
 271        /* Disable CPT PF interrupts */
 272        otx_cpt_unregister_interrupts(cpt);
 273        /* Disengage SE and AE cores from all groups */
 274        otx_cpt_disable_all_cores(cpt);
 275        pci_iounmap(pdev, cpt->reg_base);
 276        pci_release_regions(pdev);
 277        pci_disable_device(pdev);
 278        pci_set_drvdata(pdev, NULL);
 279}
 280
 281/* Supported devices */
 282static const struct pci_device_id otx_cpt_id_table[] = {
 283        { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OTX_CPT_PCI_PF_DEVICE_ID) },
 284        { 0, }  /* end of table */
 285};
 286
 287static struct pci_driver otx_cpt_pci_driver = {
 288        .name = DRV_NAME,
 289        .id_table = otx_cpt_id_table,
 290        .probe = otx_cpt_probe,
 291        .remove = otx_cpt_remove,
 292        .sriov_configure = otx_cpt_sriov_configure
 293};
 294
 295module_pci_driver(otx_cpt_pci_driver);
 296
 297MODULE_AUTHOR("Marvell International Ltd.");
 298MODULE_DESCRIPTION("Marvell OcteonTX CPT Physical Function Driver");
 299MODULE_LICENSE("GPL v2");
 300MODULE_VERSION(DRV_VERSION);
 301MODULE_DEVICE_TABLE(pci, otx_cpt_id_table);
 302