Path: blob/master/drivers/crypto/cavium/cpt/cptpf_main.c
26285 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Copyright (C) 2016 Cavium, Inc.3*/45#include <linux/device.h>6#include <linux/firmware.h>7#include <linux/interrupt.h>8#include <linux/module.h>9#include <linux/moduleparam.h>10#include <linux/pci.h>11#include <linux/printk.h>1213#include "cptpf.h"1415#define DRV_NAME "thunder-cpt"16#define DRV_VERSION "1.0"1718static u32 num_vfs = 4; /* Default 4 VF enabled */19module_param(num_vfs, uint, 0444);20MODULE_PARM_DESC(num_vfs, "Number of VFs to enable(1-16)");2122/*23* Disable cores specified by coremask24*/25static void cpt_disable_cores(struct cpt_device *cpt, u64 coremask,26u8 type, u8 grp)27{28u64 pf_exe_ctl;29u32 timeout = 100;30u64 grpmask = 0;31struct device *dev = &cpt->pdev->dev;3233if (type == AE_TYPES)34coremask = (coremask << cpt->max_se_cores);3536/* Disengage the cores from groups */37grpmask = cpt_read_csr64(cpt->reg_base, CPTX_PF_GX_EN(0, grp));38cpt_write_csr64(cpt->reg_base, CPTX_PF_GX_EN(0, grp),39(grpmask & ~coremask));40udelay(CSR_DELAY);41grp = cpt_read_csr64(cpt->reg_base, CPTX_PF_EXEC_BUSY(0));42while (grp & coremask) {43dev_err(dev, "Cores still busy %llx", coremask);44grp = cpt_read_csr64(cpt->reg_base,45CPTX_PF_EXEC_BUSY(0));46if (!timeout--)47break;4849udelay(CSR_DELAY);50}5152/* Disable the cores */53pf_exe_ctl = cpt_read_csr64(cpt->reg_base, CPTX_PF_EXE_CTL(0));54cpt_write_csr64(cpt->reg_base, CPTX_PF_EXE_CTL(0),55(pf_exe_ctl & ~coremask));56udelay(CSR_DELAY);57}5859/*60* Enable cores specified by coremask61*/62static void cpt_enable_cores(struct cpt_device *cpt, u64 coremask,63u8 type)64{65u64 pf_exe_ctl;6667if (type == AE_TYPES)68coremask = (coremask << cpt->max_se_cores);6970pf_exe_ctl = cpt_read_csr64(cpt->reg_base, CPTX_PF_EXE_CTL(0));71cpt_write_csr64(cpt->reg_base, CPTX_PF_EXE_CTL(0),72(pf_exe_ctl | coremask));73udelay(CSR_DELAY);74}7576static void cpt_configure_group(struct cpt_device *cpt, u8 grp,77u64 coremask, u8 type)78{79u64 pf_gx_en = 0;8081if (type == AE_TYPES)82coremask = (coremask << cpt->max_se_cores);8384pf_gx_en = cpt_read_csr64(cpt->reg_base, CPTX_PF_GX_EN(0, grp));85cpt_write_csr64(cpt->reg_base, CPTX_PF_GX_EN(0, grp),86(pf_gx_en | coremask));87udelay(CSR_DELAY);88}8990static void cpt_disable_mbox_interrupts(struct cpt_device *cpt)91{92/* Clear mbox(0) interupts for all vfs */93cpt_write_csr64(cpt->reg_base, CPTX_PF_MBOX_ENA_W1CX(0, 0), ~0ull);94}9596static void cpt_disable_ecc_interrupts(struct cpt_device *cpt)97{98/* Clear ecc(0) interupts for all vfs */99cpt_write_csr64(cpt->reg_base, CPTX_PF_ECC0_ENA_W1C(0), ~0ull);100}101102static void cpt_disable_exec_interrupts(struct cpt_device *cpt)103{104/* Clear exec interupts for all vfs */105cpt_write_csr64(cpt->reg_base, CPTX_PF_EXEC_ENA_W1C(0), ~0ull);106}107108static void cpt_disable_all_interrupts(struct cpt_device *cpt)109{110cpt_disable_mbox_interrupts(cpt);111cpt_disable_ecc_interrupts(cpt);112cpt_disable_exec_interrupts(cpt);113}114115static void cpt_enable_mbox_interrupts(struct cpt_device *cpt)116{117/* Set mbox(0) interupts for all vfs */118cpt_write_csr64(cpt->reg_base, CPTX_PF_MBOX_ENA_W1SX(0, 0), ~0ull);119}120121static int cpt_load_microcode(struct cpt_device *cpt, struct microcode *mcode)122{123int ret = 0, core = 0, shift = 0;124u32 total_cores = 0;125struct device *dev = &cpt->pdev->dev;126127if (!mcode || !mcode->code) {128dev_err(dev, "Either the mcode is null or data is NULL\n");129return -EINVAL;130}131132if (mcode->code_size == 0) {133dev_err(dev, "microcode size is 0\n");134return -EINVAL;135}136137/* Assumes 0-9 are SE cores for UCODE_BASE registers and138* AE core bases follow139*/140if (mcode->is_ae) {141core = CPT_MAX_SE_CORES; /* start couting from 10 */142total_cores = CPT_MAX_TOTAL_CORES; /* upto 15 */143} else {144core = 0; /* start couting from 0 */145total_cores = CPT_MAX_SE_CORES; /* upto 9 */146}147148/* Point to microcode for each core of the group */149for (; core < total_cores ; core++, shift++) {150if (mcode->core_mask & (1 << shift)) {151cpt_write_csr64(cpt->reg_base,152CPTX_PF_ENGX_UCODE_BASE(0, core),153(u64)mcode->phys_base);154}155}156return ret;157}158159static int do_cpt_init(struct cpt_device *cpt, struct microcode *mcode)160{161int ret = 0;162struct device *dev = &cpt->pdev->dev;163164/* Make device not ready */165cpt->flags &= ~CPT_FLAG_DEVICE_READY;166/* Disable All PF interrupts */167cpt_disable_all_interrupts(cpt);168/* Calculate mcode group and coremasks */169if (mcode->is_ae) {170if (mcode->num_cores > cpt->max_ae_cores) {171dev_err(dev, "Requested for more cores than available AE cores\n");172ret = -EINVAL;173goto cpt_init_fail;174}175176if (cpt->next_group >= CPT_MAX_CORE_GROUPS) {177dev_err(dev, "Can't load, all eight microcode groups in use");178return -ENFILE;179}180181mcode->group = cpt->next_group;182/* Convert requested cores to mask */183mcode->core_mask = GENMASK(mcode->num_cores, 0);184cpt_disable_cores(cpt, mcode->core_mask, AE_TYPES,185mcode->group);186/* Load microcode for AE engines */187ret = cpt_load_microcode(cpt, mcode);188if (ret) {189dev_err(dev, "Microcode load Failed for %s\n",190mcode->version);191goto cpt_init_fail;192}193cpt->next_group++;194/* Configure group mask for the mcode */195cpt_configure_group(cpt, mcode->group, mcode->core_mask,196AE_TYPES);197/* Enable AE cores for the group mask */198cpt_enable_cores(cpt, mcode->core_mask, AE_TYPES);199} else {200if (mcode->num_cores > cpt->max_se_cores) {201dev_err(dev, "Requested for more cores than available SE cores\n");202ret = -EINVAL;203goto cpt_init_fail;204}205if (cpt->next_group >= CPT_MAX_CORE_GROUPS) {206dev_err(dev, "Can't load, all eight microcode groups in use");207return -ENFILE;208}209210mcode->group = cpt->next_group;211/* Covert requested cores to mask */212mcode->core_mask = GENMASK(mcode->num_cores, 0);213cpt_disable_cores(cpt, mcode->core_mask, SE_TYPES,214mcode->group);215/* Load microcode for SE engines */216ret = cpt_load_microcode(cpt, mcode);217if (ret) {218dev_err(dev, "Microcode load Failed for %s\n",219mcode->version);220goto cpt_init_fail;221}222cpt->next_group++;223/* Configure group mask for the mcode */224cpt_configure_group(cpt, mcode->group, mcode->core_mask,225SE_TYPES);226/* Enable SE cores for the group mask */227cpt_enable_cores(cpt, mcode->core_mask, SE_TYPES);228}229230/* Enabled PF mailbox interrupts */231cpt_enable_mbox_interrupts(cpt);232cpt->flags |= CPT_FLAG_DEVICE_READY;233234return ret;235236cpt_init_fail:237/* Enabled PF mailbox interrupts */238cpt_enable_mbox_interrupts(cpt);239240return ret;241}242243struct ucode_header {244u8 version[CPT_UCODE_VERSION_SZ];245__be32 code_length;246u32 data_length;247u64 sram_address;248};249250static int cpt_ucode_load_fw(struct cpt_device *cpt, const u8 *fw, bool is_ae)251{252const struct firmware *fw_entry;253struct device *dev = &cpt->pdev->dev;254struct ucode_header *ucode;255unsigned int code_length;256struct microcode *mcode;257int j, ret = 0;258259ret = request_firmware(&fw_entry, fw, dev);260if (ret)261return ret;262263ucode = (struct ucode_header *)fw_entry->data;264mcode = &cpt->mcode[cpt->next_mc_idx];265memcpy(mcode->version, (u8 *)fw_entry->data, CPT_UCODE_VERSION_SZ);266code_length = ntohl(ucode->code_length);267if (code_length == 0 || code_length >= INT_MAX / 2) {268ret = -EINVAL;269goto fw_release;270}271mcode->code_size = code_length * 2;272273mcode->is_ae = is_ae;274mcode->core_mask = 0ULL;275mcode->num_cores = is_ae ? 6 : 10;276277/* Allocate DMAable space */278mcode->code = dma_alloc_coherent(&cpt->pdev->dev, mcode->code_size,279&mcode->phys_base, GFP_KERNEL);280if (!mcode->code) {281dev_err(dev, "Unable to allocate space for microcode");282ret = -ENOMEM;283goto fw_release;284}285286memcpy((void *)mcode->code, (void *)(fw_entry->data + sizeof(*ucode)),287mcode->code_size);288289/* Byte swap 64-bit */290for (j = 0; j < (mcode->code_size / 8); j++)291((__be64 *)mcode->code)[j] = cpu_to_be64(((u64 *)mcode->code)[j]);292/* MC needs 16-bit swap */293for (j = 0; j < (mcode->code_size / 2); j++)294((__be16 *)mcode->code)[j] = cpu_to_be16(((u16 *)mcode->code)[j]);295296dev_dbg(dev, "mcode->code_size = %u\n", mcode->code_size);297dev_dbg(dev, "mcode->is_ae = %u\n", mcode->is_ae);298dev_dbg(dev, "mcode->num_cores = %u\n", mcode->num_cores);299dev_dbg(dev, "mcode->code = %llx\n", (u64)mcode->code);300dev_dbg(dev, "mcode->phys_base = %llx\n", mcode->phys_base);301302ret = do_cpt_init(cpt, mcode);303if (ret) {304dma_free_coherent(&cpt->pdev->dev, mcode->code_size,305mcode->code, mcode->phys_base);306dev_err(dev, "do_cpt_init failed with ret: %d\n", ret);307goto fw_release;308}309310dev_info(dev, "Microcode Loaded %s\n", mcode->version);311mcode->is_mc_valid = 1;312cpt->next_mc_idx++;313314fw_release:315release_firmware(fw_entry);316317return ret;318}319320static int cpt_ucode_load(struct cpt_device *cpt)321{322int ret = 0;323struct device *dev = &cpt->pdev->dev;324325ret = cpt_ucode_load_fw(cpt, "cpt8x-mc-ae.out", true);326if (ret) {327dev_err(dev, "ae:cpt_ucode_load failed with ret: %d\n", ret);328return ret;329}330ret = cpt_ucode_load_fw(cpt, "cpt8x-mc-se.out", false);331if (ret) {332dev_err(dev, "se:cpt_ucode_load failed with ret: %d\n", ret);333return ret;334}335336return ret;337}338339static irqreturn_t cpt_mbx0_intr_handler(int irq, void *cpt_irq)340{341struct cpt_device *cpt = (struct cpt_device *)cpt_irq;342343cpt_mbox_intr_handler(cpt, 0);344345return IRQ_HANDLED;346}347348static void cpt_reset(struct cpt_device *cpt)349{350cpt_write_csr64(cpt->reg_base, CPTX_PF_RESET(0), 1);351}352353static void cpt_find_max_enabled_cores(struct cpt_device *cpt)354{355union cptx_pf_constants pf_cnsts = {0};356357pf_cnsts.u = cpt_read_csr64(cpt->reg_base, CPTX_PF_CONSTANTS(0));358cpt->max_se_cores = pf_cnsts.s.se;359cpt->max_ae_cores = pf_cnsts.s.ae;360}361362static u32 cpt_check_bist_status(struct cpt_device *cpt)363{364union cptx_pf_bist_status bist_sts = {0};365366bist_sts.u = cpt_read_csr64(cpt->reg_base,367CPTX_PF_BIST_STATUS(0));368369return bist_sts.u;370}371372static u64 cpt_check_exe_bist_status(struct cpt_device *cpt)373{374union cptx_pf_exe_bist_status bist_sts = {0};375376bist_sts.u = cpt_read_csr64(cpt->reg_base,377CPTX_PF_EXE_BIST_STATUS(0));378379return bist_sts.u;380}381382static void cpt_disable_all_cores(struct cpt_device *cpt)383{384u32 grp, timeout = 100;385struct device *dev = &cpt->pdev->dev;386387/* Disengage the cores from groups */388for (grp = 0; grp < CPT_MAX_CORE_GROUPS; grp++) {389cpt_write_csr64(cpt->reg_base, CPTX_PF_GX_EN(0, grp), 0);390udelay(CSR_DELAY);391}392393grp = cpt_read_csr64(cpt->reg_base, CPTX_PF_EXEC_BUSY(0));394while (grp) {395dev_err(dev, "Cores still busy");396grp = cpt_read_csr64(cpt->reg_base,397CPTX_PF_EXEC_BUSY(0));398if (!timeout--)399break;400401udelay(CSR_DELAY);402}403/* Disable the cores */404cpt_write_csr64(cpt->reg_base, CPTX_PF_EXE_CTL(0), 0);405}406407/*408* Ensure all cores are disengaged from all groups by409* calling cpt_disable_all_cores() before calling this410* function.411*/412static void cpt_unload_microcode(struct cpt_device *cpt)413{414u32 grp = 0, core;415416/* Free microcode bases and reset group masks */417for (grp = 0; grp < CPT_MAX_CORE_GROUPS; grp++) {418struct microcode *mcode = &cpt->mcode[grp];419420if (cpt->mcode[grp].code)421dma_free_coherent(&cpt->pdev->dev, mcode->code_size,422mcode->code, mcode->phys_base);423mcode->code = NULL;424}425/* Clear UCODE_BASE registers for all engines */426for (core = 0; core < CPT_MAX_TOTAL_CORES; core++)427cpt_write_csr64(cpt->reg_base,428CPTX_PF_ENGX_UCODE_BASE(0, core), 0ull);429}430431static int cpt_device_init(struct cpt_device *cpt)432{433u64 bist;434struct device *dev = &cpt->pdev->dev;435436/* Reset the PF when probed first */437cpt_reset(cpt);438msleep(100);439440/*Check BIST status*/441bist = (u64)cpt_check_bist_status(cpt);442if (bist) {443dev_err(dev, "RAM BIST failed with code 0x%llx", bist);444return -ENODEV;445}446447bist = cpt_check_exe_bist_status(cpt);448if (bist) {449dev_err(dev, "Engine BIST failed with code 0x%llx", bist);450return -ENODEV;451}452453/*Get CLK frequency*/454/*Get max enabled cores */455cpt_find_max_enabled_cores(cpt);456/*Disable all cores*/457cpt_disable_all_cores(cpt);458/*Reset device parameters*/459cpt->next_mc_idx = 0;460cpt->next_group = 0;461/* PF is ready */462cpt->flags |= CPT_FLAG_DEVICE_READY;463464return 0;465}466467static int cpt_register_interrupts(struct cpt_device *cpt)468{469int ret;470struct device *dev = &cpt->pdev->dev;471472/* Enable MSI-X */473ret = pci_alloc_irq_vectors(cpt->pdev, CPT_PF_MSIX_VECTORS,474CPT_PF_MSIX_VECTORS, PCI_IRQ_MSIX);475if (ret < 0) {476dev_err(&cpt->pdev->dev, "Request for #%d msix vectors failed\n",477CPT_PF_MSIX_VECTORS);478return ret;479}480481/* Register mailbox interrupt handlers */482ret = request_irq(pci_irq_vector(cpt->pdev, CPT_PF_INT_VEC_E_MBOXX(0)),483cpt_mbx0_intr_handler, 0, "CPT Mbox0", cpt);484if (ret)485goto fail;486487/* Enable mailbox interrupt */488cpt_enable_mbox_interrupts(cpt);489return 0;490491fail:492dev_err(dev, "Request irq failed\n");493pci_disable_msix(cpt->pdev);494return ret;495}496497static void cpt_unregister_interrupts(struct cpt_device *cpt)498{499free_irq(pci_irq_vector(cpt->pdev, CPT_PF_INT_VEC_E_MBOXX(0)), cpt);500pci_disable_msix(cpt->pdev);501}502503static int cpt_sriov_init(struct cpt_device *cpt, int num_vfs)504{505int pos = 0;506int err;507u16 total_vf_cnt;508struct pci_dev *pdev = cpt->pdev;509510pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);511if (!pos) {512dev_err(&pdev->dev, "SRIOV capability is not found in PCIe config space\n");513return -ENODEV;514}515516cpt->num_vf_en = num_vfs; /* User requested VFs */517pci_read_config_word(pdev, (pos + PCI_SRIOV_TOTAL_VF), &total_vf_cnt);518if (total_vf_cnt < cpt->num_vf_en)519cpt->num_vf_en = total_vf_cnt;520521if (!total_vf_cnt)522return 0;523524/*Enabled the available VFs */525err = pci_enable_sriov(pdev, cpt->num_vf_en);526if (err) {527dev_err(&pdev->dev, "SRIOV enable failed, num VF is %d\n",528cpt->num_vf_en);529cpt->num_vf_en = 0;530return err;531}532533/* TODO: Optionally enable static VQ priorities feature */534535dev_info(&pdev->dev, "SRIOV enabled, number of VF available %d\n",536cpt->num_vf_en);537538cpt->flags |= CPT_FLAG_SRIOV_ENABLED;539540return 0;541}542543static int cpt_probe(struct pci_dev *pdev, const struct pci_device_id *ent)544{545struct device *dev = &pdev->dev;546struct cpt_device *cpt;547int err;548549if (num_vfs > 16 || num_vfs < 4) {550dev_warn(dev, "Invalid vf count %d, Resetting it to 4(default)\n",551num_vfs);552num_vfs = 4;553}554555cpt = devm_kzalloc(dev, sizeof(*cpt), GFP_KERNEL);556if (!cpt)557return -ENOMEM;558559pci_set_drvdata(pdev, cpt);560cpt->pdev = pdev;561err = pci_enable_device(pdev);562if (err) {563dev_err(dev, "Failed to enable PCI device\n");564pci_set_drvdata(pdev, NULL);565return err;566}567568err = pci_request_regions(pdev, DRV_NAME);569if (err) {570dev_err(dev, "PCI request regions failed 0x%x\n", err);571goto cpt_err_disable_device;572}573574err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48));575if (err) {576dev_err(dev, "Unable to get usable 48-bit DMA configuration\n");577goto cpt_err_release_regions;578}579580/* MAP PF's configuration registers */581cpt->reg_base = pcim_iomap(pdev, 0, 0);582if (!cpt->reg_base) {583dev_err(dev, "Cannot map config register space, aborting\n");584err = -ENOMEM;585goto cpt_err_release_regions;586}587588/* CPT device HW initialization */589cpt_device_init(cpt);590591/* Register interrupts */592err = cpt_register_interrupts(cpt);593if (err)594goto cpt_err_release_regions;595596err = cpt_ucode_load(cpt);597if (err)598goto cpt_err_unregister_interrupts;599600/* Configure SRIOV */601err = cpt_sriov_init(cpt, num_vfs);602if (err)603goto cpt_err_unregister_interrupts;604605return 0;606607cpt_err_unregister_interrupts:608cpt_unregister_interrupts(cpt);609cpt_err_release_regions:610pci_release_regions(pdev);611cpt_err_disable_device:612pci_disable_device(pdev);613pci_set_drvdata(pdev, NULL);614return err;615}616617static void cpt_remove(struct pci_dev *pdev)618{619struct cpt_device *cpt = pci_get_drvdata(pdev);620621/* Disengage SE and AE cores from all groups*/622cpt_disable_all_cores(cpt);623/* Unload microcodes */624cpt_unload_microcode(cpt);625cpt_unregister_interrupts(cpt);626pci_disable_sriov(pdev);627pci_release_regions(pdev);628pci_disable_device(pdev);629pci_set_drvdata(pdev, NULL);630}631632static void cpt_shutdown(struct pci_dev *pdev)633{634struct cpt_device *cpt = pci_get_drvdata(pdev);635636if (!cpt)637return;638639dev_info(&pdev->dev, "Shutdown device %x:%x.\n",640(u32)pdev->vendor, (u32)pdev->device);641642cpt_unregister_interrupts(cpt);643pci_release_regions(pdev);644pci_disable_device(pdev);645pci_set_drvdata(pdev, NULL);646}647648/* Supported devices */649static const struct pci_device_id cpt_id_table[] = {650{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, CPT_81XX_PCI_PF_DEVICE_ID) },651{ 0, } /* end of table */652};653654static struct pci_driver cpt_pci_driver = {655.name = DRV_NAME,656.id_table = cpt_id_table,657.probe = cpt_probe,658.remove = cpt_remove,659.shutdown = cpt_shutdown,660};661662module_pci_driver(cpt_pci_driver);663664MODULE_AUTHOR("George Cherian <[email protected]>");665MODULE_DESCRIPTION("Cavium Thunder CPT Physical Function Driver");666MODULE_LICENSE("GPL v2");667MODULE_VERSION(DRV_VERSION);668MODULE_DEVICE_TABLE(pci, cpt_id_table);669670671