125763b3cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 29e2c7d99SGeorge Cherian /* 39e2c7d99SGeorge Cherian * Copyright (C) 2016 Cavium, Inc. 49e2c7d99SGeorge Cherian */ 59e2c7d99SGeorge Cherian 69e2c7d99SGeorge Cherian #include <linux/device.h> 79e2c7d99SGeorge Cherian #include <linux/firmware.h> 89e2c7d99SGeorge Cherian #include <linux/interrupt.h> 99e2c7d99SGeorge Cherian #include <linux/module.h> 109e2c7d99SGeorge Cherian #include <linux/moduleparam.h> 119e2c7d99SGeorge Cherian #include <linux/pci.h> 129e2c7d99SGeorge Cherian #include <linux/printk.h> 139e2c7d99SGeorge Cherian #include <linux/version.h> 149e2c7d99SGeorge Cherian 159e2c7d99SGeorge Cherian #include "cptpf.h" 169e2c7d99SGeorge Cherian 179e2c7d99SGeorge Cherian #define DRV_NAME "thunder-cpt" 189e2c7d99SGeorge Cherian #define DRV_VERSION "1.0" 199e2c7d99SGeorge Cherian 209e2c7d99SGeorge Cherian static u32 num_vfs = 4; /* Default 4 VF enabled */ 219e2c7d99SGeorge Cherian module_param(num_vfs, uint, 0444); 229e2c7d99SGeorge Cherian MODULE_PARM_DESC(num_vfs, "Number of VFs to enable(1-16)"); 239e2c7d99SGeorge Cherian 249e2c7d99SGeorge Cherian /* 259e2c7d99SGeorge Cherian * Disable cores specified by coremask 269e2c7d99SGeorge Cherian */ 279e2c7d99SGeorge Cherian static void cpt_disable_cores(struct cpt_device *cpt, u64 coremask, 289e2c7d99SGeorge Cherian u8 type, u8 grp) 299e2c7d99SGeorge Cherian { 309e2c7d99SGeorge Cherian u64 pf_exe_ctl; 319e2c7d99SGeorge Cherian u32 timeout = 100; 329e2c7d99SGeorge Cherian u64 grpmask = 0; 339e2c7d99SGeorge Cherian struct device *dev = &cpt->pdev->dev; 349e2c7d99SGeorge Cherian 359e2c7d99SGeorge Cherian if (type == AE_TYPES) 369e2c7d99SGeorge Cherian coremask = (coremask << cpt->max_se_cores); 379e2c7d99SGeorge Cherian 389e2c7d99SGeorge Cherian /* Disengage the cores from groups */ 399e2c7d99SGeorge Cherian grpmask = cpt_read_csr64(cpt->reg_base, CPTX_PF_GX_EN(0, grp)); 409e2c7d99SGeorge Cherian cpt_write_csr64(cpt->reg_base, CPTX_PF_GX_EN(0, grp), 419e2c7d99SGeorge Cherian (grpmask & ~coremask)); 429e2c7d99SGeorge Cherian udelay(CSR_DELAY); 439e2c7d99SGeorge Cherian grp = cpt_read_csr64(cpt->reg_base, CPTX_PF_EXEC_BUSY(0)); 449e2c7d99SGeorge Cherian while (grp & coremask) { 459e2c7d99SGeorge Cherian dev_err(dev, "Cores still busy %llx", coremask); 469e2c7d99SGeorge Cherian grp = cpt_read_csr64(cpt->reg_base, 479e2c7d99SGeorge Cherian CPTX_PF_EXEC_BUSY(0)); 489e2c7d99SGeorge Cherian if (timeout--) 499e2c7d99SGeorge Cherian break; 509e2c7d99SGeorge Cherian 519e2c7d99SGeorge Cherian udelay(CSR_DELAY); 529e2c7d99SGeorge Cherian } 539e2c7d99SGeorge Cherian 549e2c7d99SGeorge Cherian /* Disable the cores */ 559e2c7d99SGeorge Cherian pf_exe_ctl = cpt_read_csr64(cpt->reg_base, CPTX_PF_EXE_CTL(0)); 569e2c7d99SGeorge Cherian cpt_write_csr64(cpt->reg_base, CPTX_PF_EXE_CTL(0), 579e2c7d99SGeorge Cherian (pf_exe_ctl & ~coremask)); 589e2c7d99SGeorge Cherian udelay(CSR_DELAY); 599e2c7d99SGeorge Cherian } 609e2c7d99SGeorge Cherian 619e2c7d99SGeorge Cherian /* 629e2c7d99SGeorge Cherian * Enable cores specified by coremask 639e2c7d99SGeorge Cherian */ 649e2c7d99SGeorge Cherian static void cpt_enable_cores(struct cpt_device *cpt, u64 coremask, 659e2c7d99SGeorge Cherian u8 type) 669e2c7d99SGeorge Cherian { 679e2c7d99SGeorge Cherian u64 pf_exe_ctl; 689e2c7d99SGeorge Cherian 699e2c7d99SGeorge Cherian if (type == AE_TYPES) 709e2c7d99SGeorge Cherian coremask = (coremask << cpt->max_se_cores); 719e2c7d99SGeorge Cherian 729e2c7d99SGeorge Cherian pf_exe_ctl = cpt_read_csr64(cpt->reg_base, CPTX_PF_EXE_CTL(0)); 739e2c7d99SGeorge Cherian cpt_write_csr64(cpt->reg_base, CPTX_PF_EXE_CTL(0), 749e2c7d99SGeorge Cherian (pf_exe_ctl | coremask)); 759e2c7d99SGeorge Cherian udelay(CSR_DELAY); 769e2c7d99SGeorge Cherian } 779e2c7d99SGeorge Cherian 789e2c7d99SGeorge Cherian static void cpt_configure_group(struct cpt_device *cpt, u8 grp, 799e2c7d99SGeorge Cherian u64 coremask, u8 type) 809e2c7d99SGeorge Cherian { 819e2c7d99SGeorge Cherian u64 pf_gx_en = 0; 829e2c7d99SGeorge Cherian 839e2c7d99SGeorge Cherian if (type == AE_TYPES) 849e2c7d99SGeorge Cherian coremask = (coremask << cpt->max_se_cores); 859e2c7d99SGeorge Cherian 869e2c7d99SGeorge Cherian pf_gx_en = cpt_read_csr64(cpt->reg_base, CPTX_PF_GX_EN(0, grp)); 879e2c7d99SGeorge Cherian cpt_write_csr64(cpt->reg_base, CPTX_PF_GX_EN(0, grp), 889e2c7d99SGeorge Cherian (pf_gx_en | coremask)); 899e2c7d99SGeorge Cherian udelay(CSR_DELAY); 909e2c7d99SGeorge Cherian } 919e2c7d99SGeorge Cherian 929e2c7d99SGeorge Cherian static void cpt_disable_mbox_interrupts(struct cpt_device *cpt) 939e2c7d99SGeorge Cherian { 949e2c7d99SGeorge Cherian /* Clear mbox(0) interupts for all vfs */ 959e2c7d99SGeorge Cherian cpt_write_csr64(cpt->reg_base, CPTX_PF_MBOX_ENA_W1CX(0, 0), ~0ull); 969e2c7d99SGeorge Cherian } 979e2c7d99SGeorge Cherian 989e2c7d99SGeorge Cherian static void cpt_disable_ecc_interrupts(struct cpt_device *cpt) 999e2c7d99SGeorge Cherian { 1009e2c7d99SGeorge Cherian /* Clear ecc(0) interupts for all vfs */ 1019e2c7d99SGeorge Cherian cpt_write_csr64(cpt->reg_base, CPTX_PF_ECC0_ENA_W1C(0), ~0ull); 1029e2c7d99SGeorge Cherian } 1039e2c7d99SGeorge Cherian 1049e2c7d99SGeorge Cherian static void cpt_disable_exec_interrupts(struct cpt_device *cpt) 1059e2c7d99SGeorge Cherian { 1069e2c7d99SGeorge Cherian /* Clear exec interupts for all vfs */ 1079e2c7d99SGeorge Cherian cpt_write_csr64(cpt->reg_base, CPTX_PF_EXEC_ENA_W1C(0), ~0ull); 1089e2c7d99SGeorge Cherian } 1099e2c7d99SGeorge Cherian 1109e2c7d99SGeorge Cherian static void cpt_disable_all_interrupts(struct cpt_device *cpt) 1119e2c7d99SGeorge Cherian { 1129e2c7d99SGeorge Cherian cpt_disable_mbox_interrupts(cpt); 1139e2c7d99SGeorge Cherian cpt_disable_ecc_interrupts(cpt); 1149e2c7d99SGeorge Cherian cpt_disable_exec_interrupts(cpt); 1159e2c7d99SGeorge Cherian } 1169e2c7d99SGeorge Cherian 1179e2c7d99SGeorge Cherian static void cpt_enable_mbox_interrupts(struct cpt_device *cpt) 1189e2c7d99SGeorge Cherian { 1199e2c7d99SGeorge Cherian /* Set mbox(0) interupts for all vfs */ 1209e2c7d99SGeorge Cherian cpt_write_csr64(cpt->reg_base, CPTX_PF_MBOX_ENA_W1SX(0, 0), ~0ull); 1219e2c7d99SGeorge Cherian } 1229e2c7d99SGeorge Cherian 1239e2c7d99SGeorge Cherian static int cpt_load_microcode(struct cpt_device *cpt, struct microcode *mcode) 1249e2c7d99SGeorge Cherian { 1259e2c7d99SGeorge Cherian int ret = 0, core = 0, shift = 0; 1269e2c7d99SGeorge Cherian u32 total_cores = 0; 1279e2c7d99SGeorge Cherian struct device *dev = &cpt->pdev->dev; 1289e2c7d99SGeorge Cherian 1299e2c7d99SGeorge Cherian if (!mcode || !mcode->code) { 1309e2c7d99SGeorge Cherian dev_err(dev, "Either the mcode is null or data is NULL\n"); 1319e2c7d99SGeorge Cherian return -EINVAL; 1329e2c7d99SGeorge Cherian } 1339e2c7d99SGeorge Cherian 1349e2c7d99SGeorge Cherian if (mcode->code_size == 0) { 1359e2c7d99SGeorge Cherian dev_err(dev, "microcode size is 0\n"); 1369e2c7d99SGeorge Cherian return -EINVAL; 1379e2c7d99SGeorge Cherian } 1389e2c7d99SGeorge Cherian 1399e2c7d99SGeorge Cherian /* Assumes 0-9 are SE cores for UCODE_BASE registers and 1409e2c7d99SGeorge Cherian * AE core bases follow 1419e2c7d99SGeorge Cherian */ 1429e2c7d99SGeorge Cherian if (mcode->is_ae) { 1439e2c7d99SGeorge Cherian core = CPT_MAX_SE_CORES; /* start couting from 10 */ 1449e2c7d99SGeorge Cherian total_cores = CPT_MAX_TOTAL_CORES; /* upto 15 */ 1459e2c7d99SGeorge Cherian } else { 1469e2c7d99SGeorge Cherian core = 0; /* start couting from 0 */ 1479e2c7d99SGeorge Cherian total_cores = CPT_MAX_SE_CORES; /* upto 9 */ 1489e2c7d99SGeorge Cherian } 1499e2c7d99SGeorge Cherian 1509e2c7d99SGeorge Cherian /* Point to microcode for each core of the group */ 1519e2c7d99SGeorge Cherian for (; core < total_cores ; core++, shift++) { 1529e2c7d99SGeorge Cherian if (mcode->core_mask & (1 << shift)) { 1539e2c7d99SGeorge Cherian cpt_write_csr64(cpt->reg_base, 1549e2c7d99SGeorge Cherian CPTX_PF_ENGX_UCODE_BASE(0, core), 1559e2c7d99SGeorge Cherian (u64)mcode->phys_base); 1569e2c7d99SGeorge Cherian } 1579e2c7d99SGeorge Cherian } 1589e2c7d99SGeorge Cherian return ret; 1599e2c7d99SGeorge Cherian } 1609e2c7d99SGeorge Cherian 1619e2c7d99SGeorge Cherian static int do_cpt_init(struct cpt_device *cpt, struct microcode *mcode) 1629e2c7d99SGeorge Cherian { 1639e2c7d99SGeorge Cherian int ret = 0; 1649e2c7d99SGeorge Cherian struct device *dev = &cpt->pdev->dev; 1659e2c7d99SGeorge Cherian 1669e2c7d99SGeorge Cherian /* Make device not ready */ 1679e2c7d99SGeorge Cherian cpt->flags &= ~CPT_FLAG_DEVICE_READY; 1689e2c7d99SGeorge Cherian /* Disable All PF interrupts */ 1699e2c7d99SGeorge Cherian cpt_disable_all_interrupts(cpt); 1709e2c7d99SGeorge Cherian /* Calculate mcode group and coremasks */ 1719e2c7d99SGeorge Cherian if (mcode->is_ae) { 1729e2c7d99SGeorge Cherian if (mcode->num_cores > cpt->max_ae_cores) { 1739e2c7d99SGeorge Cherian dev_err(dev, "Requested for more cores than available AE cores\n"); 1749e2c7d99SGeorge Cherian ret = -EINVAL; 1759e2c7d99SGeorge Cherian goto cpt_init_fail; 1769e2c7d99SGeorge Cherian } 1779e2c7d99SGeorge Cherian 1789e2c7d99SGeorge Cherian if (cpt->next_group >= CPT_MAX_CORE_GROUPS) { 1799e2c7d99SGeorge Cherian dev_err(dev, "Can't load, all eight microcode groups in use"); 1809e2c7d99SGeorge Cherian return -ENFILE; 1819e2c7d99SGeorge Cherian } 1829e2c7d99SGeorge Cherian 1839e2c7d99SGeorge Cherian mcode->group = cpt->next_group; 1849e2c7d99SGeorge Cherian /* Convert requested cores to mask */ 1859e2c7d99SGeorge Cherian mcode->core_mask = GENMASK(mcode->num_cores, 0); 1869e2c7d99SGeorge Cherian cpt_disable_cores(cpt, mcode->core_mask, AE_TYPES, 1879e2c7d99SGeorge Cherian mcode->group); 1889e2c7d99SGeorge Cherian /* Load microcode for AE engines */ 1899e2c7d99SGeorge Cherian ret = cpt_load_microcode(cpt, mcode); 1909e2c7d99SGeorge Cherian if (ret) { 1919e2c7d99SGeorge Cherian dev_err(dev, "Microcode load Failed for %s\n", 1929e2c7d99SGeorge Cherian mcode->version); 1939e2c7d99SGeorge Cherian goto cpt_init_fail; 1949e2c7d99SGeorge Cherian } 1959e2c7d99SGeorge Cherian cpt->next_group++; 1969e2c7d99SGeorge Cherian /* Configure group mask for the mcode */ 1979e2c7d99SGeorge Cherian cpt_configure_group(cpt, mcode->group, mcode->core_mask, 1989e2c7d99SGeorge Cherian AE_TYPES); 1999e2c7d99SGeorge Cherian /* Enable AE cores for the group mask */ 2009e2c7d99SGeorge Cherian cpt_enable_cores(cpt, mcode->core_mask, AE_TYPES); 2019e2c7d99SGeorge Cherian } else { 2029e2c7d99SGeorge Cherian if (mcode->num_cores > cpt->max_se_cores) { 2039e2c7d99SGeorge Cherian dev_err(dev, "Requested for more cores than available SE cores\n"); 2049e2c7d99SGeorge Cherian ret = -EINVAL; 2059e2c7d99SGeorge Cherian goto cpt_init_fail; 2069e2c7d99SGeorge Cherian } 2079e2c7d99SGeorge Cherian if (cpt->next_group >= CPT_MAX_CORE_GROUPS) { 2089e2c7d99SGeorge Cherian dev_err(dev, "Can't load, all eight microcode groups in use"); 2099e2c7d99SGeorge Cherian return -ENFILE; 2109e2c7d99SGeorge Cherian } 2119e2c7d99SGeorge Cherian 2129e2c7d99SGeorge Cherian mcode->group = cpt->next_group; 2139e2c7d99SGeorge Cherian /* Covert requested cores to mask */ 2149e2c7d99SGeorge Cherian mcode->core_mask = GENMASK(mcode->num_cores, 0); 2159e2c7d99SGeorge Cherian cpt_disable_cores(cpt, mcode->core_mask, SE_TYPES, 2169e2c7d99SGeorge Cherian mcode->group); 2179e2c7d99SGeorge Cherian /* Load microcode for SE engines */ 2189e2c7d99SGeorge Cherian ret = cpt_load_microcode(cpt, mcode); 2199e2c7d99SGeorge Cherian if (ret) { 2209e2c7d99SGeorge Cherian dev_err(dev, "Microcode load Failed for %s\n", 2219e2c7d99SGeorge Cherian mcode->version); 2229e2c7d99SGeorge Cherian goto cpt_init_fail; 2239e2c7d99SGeorge Cherian } 2249e2c7d99SGeorge Cherian cpt->next_group++; 2259e2c7d99SGeorge Cherian /* Configure group mask for the mcode */ 2269e2c7d99SGeorge Cherian cpt_configure_group(cpt, mcode->group, mcode->core_mask, 2279e2c7d99SGeorge Cherian SE_TYPES); 2289e2c7d99SGeorge Cherian /* Enable SE cores for the group mask */ 2299e2c7d99SGeorge Cherian cpt_enable_cores(cpt, mcode->core_mask, SE_TYPES); 2309e2c7d99SGeorge Cherian } 2319e2c7d99SGeorge Cherian 2329e2c7d99SGeorge Cherian /* Enabled PF mailbox interrupts */ 2339e2c7d99SGeorge Cherian cpt_enable_mbox_interrupts(cpt); 2349e2c7d99SGeorge Cherian cpt->flags |= CPT_FLAG_DEVICE_READY; 2359e2c7d99SGeorge Cherian 2369e2c7d99SGeorge Cherian return ret; 2379e2c7d99SGeorge Cherian 2389e2c7d99SGeorge Cherian cpt_init_fail: 2399e2c7d99SGeorge Cherian /* Enabled PF mailbox interrupts */ 2409e2c7d99SGeorge Cherian cpt_enable_mbox_interrupts(cpt); 2419e2c7d99SGeorge Cherian 2429e2c7d99SGeorge Cherian return ret; 2439e2c7d99SGeorge Cherian } 2449e2c7d99SGeorge Cherian 2459e2c7d99SGeorge Cherian struct ucode_header { 2469e2c7d99SGeorge Cherian u8 version[CPT_UCODE_VERSION_SZ]; 2479e2c7d99SGeorge Cherian u32 code_length; 2489e2c7d99SGeorge Cherian u32 data_length; 2499e2c7d99SGeorge Cherian u64 sram_address; 2509e2c7d99SGeorge Cherian }; 2519e2c7d99SGeorge Cherian 2529e2c7d99SGeorge Cherian static int cpt_ucode_load_fw(struct cpt_device *cpt, const u8 *fw, bool is_ae) 2539e2c7d99SGeorge Cherian { 2549e2c7d99SGeorge Cherian const struct firmware *fw_entry; 2559e2c7d99SGeorge Cherian struct device *dev = &cpt->pdev->dev; 2569e2c7d99SGeorge Cherian struct ucode_header *ucode; 2579e2c7d99SGeorge Cherian struct microcode *mcode; 2589e2c7d99SGeorge Cherian int j, ret = 0; 2599e2c7d99SGeorge Cherian 2609e2c7d99SGeorge Cherian ret = request_firmware(&fw_entry, fw, dev); 2619e2c7d99SGeorge Cherian if (ret) 2629e2c7d99SGeorge Cherian return ret; 2639e2c7d99SGeorge Cherian 2649e2c7d99SGeorge Cherian ucode = (struct ucode_header *)fw_entry->data; 2659e2c7d99SGeorge Cherian mcode = &cpt->mcode[cpt->next_mc_idx]; 2669e2c7d99SGeorge Cherian memcpy(mcode->version, (u8 *)fw_entry->data, CPT_UCODE_VERSION_SZ); 2679e2c7d99SGeorge Cherian mcode->code_size = ntohl(ucode->code_length) * 2; 268baf5b752SCorentin LABBE if (!mcode->code_size) { 269baf5b752SCorentin LABBE ret = -EINVAL; 270baf5b752SCorentin LABBE goto fw_release; 271baf5b752SCorentin LABBE } 2729e2c7d99SGeorge Cherian 2739e2c7d99SGeorge Cherian mcode->is_ae = is_ae; 2749e2c7d99SGeorge Cherian mcode->core_mask = 0ULL; 2759e2c7d99SGeorge Cherian mcode->num_cores = is_ae ? 6 : 10; 2769e2c7d99SGeorge Cherian 2779e2c7d99SGeorge Cherian /* Allocate DMAable space */ 278750afb08SLuis Chamberlain mcode->code = dma_alloc_coherent(&cpt->pdev->dev, mcode->code_size, 2799e2c7d99SGeorge Cherian &mcode->phys_base, GFP_KERNEL); 2809e2c7d99SGeorge Cherian if (!mcode->code) { 2819e2c7d99SGeorge Cherian dev_err(dev, "Unable to allocate space for microcode"); 282baf5b752SCorentin LABBE ret = -ENOMEM; 283baf5b752SCorentin LABBE goto fw_release; 2849e2c7d99SGeorge Cherian } 2859e2c7d99SGeorge Cherian 2869e2c7d99SGeorge Cherian memcpy((void *)mcode->code, (void *)(fw_entry->data + sizeof(*ucode)), 2879e2c7d99SGeorge Cherian mcode->code_size); 2889e2c7d99SGeorge Cherian 2899e2c7d99SGeorge Cherian /* Byte swap 64-bit */ 2909e2c7d99SGeorge Cherian for (j = 0; j < (mcode->code_size / 8); j++) 2919e2c7d99SGeorge Cherian ((u64 *)mcode->code)[j] = cpu_to_be64(((u64 *)mcode->code)[j]); 2929e2c7d99SGeorge Cherian /* MC needs 16-bit swap */ 2939e2c7d99SGeorge Cherian for (j = 0; j < (mcode->code_size / 2); j++) 2949e2c7d99SGeorge Cherian ((u16 *)mcode->code)[j] = cpu_to_be16(((u16 *)mcode->code)[j]); 2959e2c7d99SGeorge Cherian 2969e2c7d99SGeorge Cherian dev_dbg(dev, "mcode->code_size = %u\n", mcode->code_size); 2979e2c7d99SGeorge Cherian dev_dbg(dev, "mcode->is_ae = %u\n", mcode->is_ae); 2989e2c7d99SGeorge Cherian dev_dbg(dev, "mcode->num_cores = %u\n", mcode->num_cores); 2999e2c7d99SGeorge Cherian dev_dbg(dev, "mcode->code = %llx\n", (u64)mcode->code); 3009e2c7d99SGeorge Cherian dev_dbg(dev, "mcode->phys_base = %llx\n", mcode->phys_base); 3019e2c7d99SGeorge Cherian 3029e2c7d99SGeorge Cherian ret = do_cpt_init(cpt, mcode); 3039e2c7d99SGeorge Cherian if (ret) { 3049e2c7d99SGeorge Cherian dev_err(dev, "do_cpt_init failed with ret: %d\n", ret); 305baf5b752SCorentin LABBE goto fw_release; 3069e2c7d99SGeorge Cherian } 3079e2c7d99SGeorge Cherian 3089e2c7d99SGeorge Cherian dev_info(dev, "Microcode Loaded %s\n", mcode->version); 3099e2c7d99SGeorge Cherian mcode->is_mc_valid = 1; 3109e2c7d99SGeorge Cherian cpt->next_mc_idx++; 311baf5b752SCorentin LABBE 312baf5b752SCorentin LABBE fw_release: 3139e2c7d99SGeorge Cherian release_firmware(fw_entry); 3149e2c7d99SGeorge Cherian 3159e2c7d99SGeorge Cherian return ret; 3169e2c7d99SGeorge Cherian } 3179e2c7d99SGeorge Cherian 3189e2c7d99SGeorge Cherian static int cpt_ucode_load(struct cpt_device *cpt) 3199e2c7d99SGeorge Cherian { 3209e2c7d99SGeorge Cherian int ret = 0; 3219e2c7d99SGeorge Cherian struct device *dev = &cpt->pdev->dev; 3229e2c7d99SGeorge Cherian 3239e2c7d99SGeorge Cherian ret = cpt_ucode_load_fw(cpt, "cpt8x-mc-ae.out", true); 3249e2c7d99SGeorge Cherian if (ret) { 3259e2c7d99SGeorge Cherian dev_err(dev, "ae:cpt_ucode_load failed with ret: %d\n", ret); 3269e2c7d99SGeorge Cherian return ret; 3279e2c7d99SGeorge Cherian } 3289e2c7d99SGeorge Cherian ret = cpt_ucode_load_fw(cpt, "cpt8x-mc-se.out", false); 3299e2c7d99SGeorge Cherian if (ret) { 3309e2c7d99SGeorge Cherian dev_err(dev, "se:cpt_ucode_load failed with ret: %d\n", ret); 3319e2c7d99SGeorge Cherian return ret; 3329e2c7d99SGeorge Cherian } 3339e2c7d99SGeorge Cherian 3349e2c7d99SGeorge Cherian return ret; 3359e2c7d99SGeorge Cherian } 3369e2c7d99SGeorge Cherian 3379e2c7d99SGeorge Cherian static irqreturn_t cpt_mbx0_intr_handler(int irq, void *cpt_irq) 3389e2c7d99SGeorge Cherian { 3399e2c7d99SGeorge Cherian struct cpt_device *cpt = (struct cpt_device *)cpt_irq; 3409e2c7d99SGeorge Cherian 3419e2c7d99SGeorge Cherian cpt_mbox_intr_handler(cpt, 0); 3429e2c7d99SGeorge Cherian 3439e2c7d99SGeorge Cherian return IRQ_HANDLED; 3449e2c7d99SGeorge Cherian } 3459e2c7d99SGeorge Cherian 3469e2c7d99SGeorge Cherian static void cpt_reset(struct cpt_device *cpt) 3479e2c7d99SGeorge Cherian { 3489e2c7d99SGeorge Cherian cpt_write_csr64(cpt->reg_base, CPTX_PF_RESET(0), 1); 3499e2c7d99SGeorge Cherian } 3509e2c7d99SGeorge Cherian 3519e2c7d99SGeorge Cherian static void cpt_find_max_enabled_cores(struct cpt_device *cpt) 3529e2c7d99SGeorge Cherian { 3539e2c7d99SGeorge Cherian union cptx_pf_constants pf_cnsts = {0}; 3549e2c7d99SGeorge Cherian 3559e2c7d99SGeorge Cherian pf_cnsts.u = cpt_read_csr64(cpt->reg_base, CPTX_PF_CONSTANTS(0)); 3569e2c7d99SGeorge Cherian cpt->max_se_cores = pf_cnsts.s.se; 3579e2c7d99SGeorge Cherian cpt->max_ae_cores = pf_cnsts.s.ae; 3589e2c7d99SGeorge Cherian } 3599e2c7d99SGeorge Cherian 3609e2c7d99SGeorge Cherian static u32 cpt_check_bist_status(struct cpt_device *cpt) 3619e2c7d99SGeorge Cherian { 3629e2c7d99SGeorge Cherian union cptx_pf_bist_status bist_sts = {0}; 3639e2c7d99SGeorge Cherian 3649e2c7d99SGeorge Cherian bist_sts.u = cpt_read_csr64(cpt->reg_base, 3659e2c7d99SGeorge Cherian CPTX_PF_BIST_STATUS(0)); 3669e2c7d99SGeorge Cherian 3679e2c7d99SGeorge Cherian return bist_sts.u; 3689e2c7d99SGeorge Cherian } 3699e2c7d99SGeorge Cherian 3709e2c7d99SGeorge Cherian static u64 cpt_check_exe_bist_status(struct cpt_device *cpt) 3719e2c7d99SGeorge Cherian { 3729e2c7d99SGeorge Cherian union cptx_pf_exe_bist_status bist_sts = {0}; 3739e2c7d99SGeorge Cherian 3749e2c7d99SGeorge Cherian bist_sts.u = cpt_read_csr64(cpt->reg_base, 3759e2c7d99SGeorge Cherian CPTX_PF_EXE_BIST_STATUS(0)); 3769e2c7d99SGeorge Cherian 3779e2c7d99SGeorge Cherian return bist_sts.u; 3789e2c7d99SGeorge Cherian } 3799e2c7d99SGeorge Cherian 3809e2c7d99SGeorge Cherian static void cpt_disable_all_cores(struct cpt_device *cpt) 3819e2c7d99SGeorge Cherian { 3829e2c7d99SGeorge Cherian u32 grp, timeout = 100; 3839e2c7d99SGeorge Cherian struct device *dev = &cpt->pdev->dev; 3849e2c7d99SGeorge Cherian 3859e2c7d99SGeorge Cherian /* Disengage the cores from groups */ 3869e2c7d99SGeorge Cherian for (grp = 0; grp < CPT_MAX_CORE_GROUPS; grp++) { 3879e2c7d99SGeorge Cherian cpt_write_csr64(cpt->reg_base, CPTX_PF_GX_EN(0, grp), 0); 3889e2c7d99SGeorge Cherian udelay(CSR_DELAY); 3899e2c7d99SGeorge Cherian } 3909e2c7d99SGeorge Cherian 3919e2c7d99SGeorge Cherian grp = cpt_read_csr64(cpt->reg_base, CPTX_PF_EXEC_BUSY(0)); 3929e2c7d99SGeorge Cherian while (grp) { 3939e2c7d99SGeorge Cherian dev_err(dev, "Cores still busy"); 3949e2c7d99SGeorge Cherian grp = cpt_read_csr64(cpt->reg_base, 3959e2c7d99SGeorge Cherian CPTX_PF_EXEC_BUSY(0)); 3969e2c7d99SGeorge Cherian if (timeout--) 3979e2c7d99SGeorge Cherian break; 3989e2c7d99SGeorge Cherian 3999e2c7d99SGeorge Cherian udelay(CSR_DELAY); 4009e2c7d99SGeorge Cherian } 4019e2c7d99SGeorge Cherian /* Disable the cores */ 4029e2c7d99SGeorge Cherian cpt_write_csr64(cpt->reg_base, CPTX_PF_EXE_CTL(0), 0); 4039e2c7d99SGeorge Cherian } 4049e2c7d99SGeorge Cherian 4059e2c7d99SGeorge Cherian /** 4069e2c7d99SGeorge Cherian * Ensure all cores are disengaged from all groups by 4079e2c7d99SGeorge Cherian * calling cpt_disable_all_cores() before calling this 4089e2c7d99SGeorge Cherian * function. 4099e2c7d99SGeorge Cherian */ 4109e2c7d99SGeorge Cherian static void cpt_unload_microcode(struct cpt_device *cpt) 4119e2c7d99SGeorge Cherian { 4129e2c7d99SGeorge Cherian u32 grp = 0, core; 4139e2c7d99SGeorge Cherian 4149e2c7d99SGeorge Cherian /* Free microcode bases and reset group masks */ 4159e2c7d99SGeorge Cherian for (grp = 0; grp < CPT_MAX_CORE_GROUPS; grp++) { 4169e2c7d99SGeorge Cherian struct microcode *mcode = &cpt->mcode[grp]; 4179e2c7d99SGeorge Cherian 4189e2c7d99SGeorge Cherian if (cpt->mcode[grp].code) 4199e2c7d99SGeorge Cherian dma_free_coherent(&cpt->pdev->dev, mcode->code_size, 4209e2c7d99SGeorge Cherian mcode->code, mcode->phys_base); 4219e2c7d99SGeorge Cherian mcode->code = NULL; 4229e2c7d99SGeorge Cherian } 4239e2c7d99SGeorge Cherian /* Clear UCODE_BASE registers for all engines */ 4249e2c7d99SGeorge Cherian for (core = 0; core < CPT_MAX_TOTAL_CORES; core++) 4259e2c7d99SGeorge Cherian cpt_write_csr64(cpt->reg_base, 4269e2c7d99SGeorge Cherian CPTX_PF_ENGX_UCODE_BASE(0, core), 0ull); 4279e2c7d99SGeorge Cherian } 4289e2c7d99SGeorge Cherian 4299e2c7d99SGeorge Cherian static int cpt_device_init(struct cpt_device *cpt) 4309e2c7d99SGeorge Cherian { 4319e2c7d99SGeorge Cherian u64 bist; 4329e2c7d99SGeorge Cherian struct device *dev = &cpt->pdev->dev; 4339e2c7d99SGeorge Cherian 4349e2c7d99SGeorge Cherian /* Reset the PF when probed first */ 4359e2c7d99SGeorge Cherian cpt_reset(cpt); 436e9acf052SJia-Ju Bai msleep(100); 4379e2c7d99SGeorge Cherian 4389e2c7d99SGeorge Cherian /*Check BIST status*/ 4399e2c7d99SGeorge Cherian bist = (u64)cpt_check_bist_status(cpt); 4409e2c7d99SGeorge Cherian if (bist) { 4419e2c7d99SGeorge Cherian dev_err(dev, "RAM BIST failed with code 0x%llx", bist); 4429e2c7d99SGeorge Cherian return -ENODEV; 4439e2c7d99SGeorge Cherian } 4449e2c7d99SGeorge Cherian 4459e2c7d99SGeorge Cherian bist = cpt_check_exe_bist_status(cpt); 4469e2c7d99SGeorge Cherian if (bist) { 4479e2c7d99SGeorge Cherian dev_err(dev, "Engine BIST failed with code 0x%llx", bist); 4489e2c7d99SGeorge Cherian return -ENODEV; 4499e2c7d99SGeorge Cherian } 4509e2c7d99SGeorge Cherian 4519e2c7d99SGeorge Cherian /*Get CLK frequency*/ 4529e2c7d99SGeorge Cherian /*Get max enabled cores */ 4539e2c7d99SGeorge Cherian cpt_find_max_enabled_cores(cpt); 4549e2c7d99SGeorge Cherian /*Disable all cores*/ 4559e2c7d99SGeorge Cherian cpt_disable_all_cores(cpt); 4569e2c7d99SGeorge Cherian /*Reset device parameters*/ 4579e2c7d99SGeorge Cherian cpt->next_mc_idx = 0; 4589e2c7d99SGeorge Cherian cpt->next_group = 0; 4599e2c7d99SGeorge Cherian /* PF is ready */ 4609e2c7d99SGeorge Cherian cpt->flags |= CPT_FLAG_DEVICE_READY; 4619e2c7d99SGeorge Cherian 4629e2c7d99SGeorge Cherian return 0; 4639e2c7d99SGeorge Cherian } 4649e2c7d99SGeorge Cherian 4659e2c7d99SGeorge Cherian static int cpt_register_interrupts(struct cpt_device *cpt) 4669e2c7d99SGeorge Cherian { 4679e2c7d99SGeorge Cherian int ret; 4689e2c7d99SGeorge Cherian struct device *dev = &cpt->pdev->dev; 4699e2c7d99SGeorge Cherian 4709e2c7d99SGeorge Cherian /* Enable MSI-X */ 471613844e8SChristoph Hellwig ret = pci_alloc_irq_vectors(cpt->pdev, CPT_PF_MSIX_VECTORS, 472613844e8SChristoph Hellwig CPT_PF_MSIX_VECTORS, PCI_IRQ_MSIX); 473613844e8SChristoph Hellwig if (ret < 0) { 474613844e8SChristoph Hellwig dev_err(&cpt->pdev->dev, "Request for #%d msix vectors failed\n", 475613844e8SChristoph Hellwig CPT_PF_MSIX_VECTORS); 4769e2c7d99SGeorge Cherian return ret; 477613844e8SChristoph Hellwig } 4789e2c7d99SGeorge Cherian 4799e2c7d99SGeorge Cherian /* Register mailbox interrupt handlers */ 480613844e8SChristoph Hellwig ret = request_irq(pci_irq_vector(cpt->pdev, CPT_PF_INT_VEC_E_MBOXX(0)), 4819e2c7d99SGeorge Cherian cpt_mbx0_intr_handler, 0, "CPT Mbox0", cpt); 4829e2c7d99SGeorge Cherian if (ret) 4839e2c7d99SGeorge Cherian goto fail; 4849e2c7d99SGeorge Cherian 4859e2c7d99SGeorge Cherian /* Enable mailbox interrupt */ 4869e2c7d99SGeorge Cherian cpt_enable_mbox_interrupts(cpt); 4879e2c7d99SGeorge Cherian return 0; 4889e2c7d99SGeorge Cherian 4899e2c7d99SGeorge Cherian fail: 4909e2c7d99SGeorge Cherian dev_err(dev, "Request irq failed\n"); 491613844e8SChristoph Hellwig pci_disable_msix(cpt->pdev); 4929e2c7d99SGeorge Cherian return ret; 4939e2c7d99SGeorge Cherian } 4949e2c7d99SGeorge Cherian 4959e2c7d99SGeorge Cherian static void cpt_unregister_interrupts(struct cpt_device *cpt) 4969e2c7d99SGeorge Cherian { 497613844e8SChristoph Hellwig free_irq(pci_irq_vector(cpt->pdev, CPT_PF_INT_VEC_E_MBOXX(0)), cpt); 498613844e8SChristoph Hellwig pci_disable_msix(cpt->pdev); 4999e2c7d99SGeorge Cherian } 5009e2c7d99SGeorge Cherian 5019e2c7d99SGeorge Cherian static int cpt_sriov_init(struct cpt_device *cpt, int num_vfs) 5029e2c7d99SGeorge Cherian { 5039e2c7d99SGeorge Cherian int pos = 0; 5049e2c7d99SGeorge Cherian int err; 5059e2c7d99SGeorge Cherian u16 total_vf_cnt; 5069e2c7d99SGeorge Cherian struct pci_dev *pdev = cpt->pdev; 5079e2c7d99SGeorge Cherian 5089e2c7d99SGeorge Cherian pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); 5099e2c7d99SGeorge Cherian if (!pos) { 5109e2c7d99SGeorge Cherian dev_err(&pdev->dev, "SRIOV capability is not found in PCIe config space\n"); 5119e2c7d99SGeorge Cherian return -ENODEV; 5129e2c7d99SGeorge Cherian } 5139e2c7d99SGeorge Cherian 5149e2c7d99SGeorge Cherian cpt->num_vf_en = num_vfs; /* User requested VFs */ 5159e2c7d99SGeorge Cherian pci_read_config_word(pdev, (pos + PCI_SRIOV_TOTAL_VF), &total_vf_cnt); 5169e2c7d99SGeorge Cherian if (total_vf_cnt < cpt->num_vf_en) 5179e2c7d99SGeorge Cherian cpt->num_vf_en = total_vf_cnt; 5189e2c7d99SGeorge Cherian 5199e2c7d99SGeorge Cherian if (!total_vf_cnt) 5209e2c7d99SGeorge Cherian return 0; 5219e2c7d99SGeorge Cherian 5229e2c7d99SGeorge Cherian /*Enabled the available VFs */ 5239e2c7d99SGeorge Cherian err = pci_enable_sriov(pdev, cpt->num_vf_en); 5249e2c7d99SGeorge Cherian if (err) { 5259e2c7d99SGeorge Cherian dev_err(&pdev->dev, "SRIOV enable failed, num VF is %d\n", 5269e2c7d99SGeorge Cherian cpt->num_vf_en); 5279e2c7d99SGeorge Cherian cpt->num_vf_en = 0; 5289e2c7d99SGeorge Cherian return err; 5299e2c7d99SGeorge Cherian } 5309e2c7d99SGeorge Cherian 5319e2c7d99SGeorge Cherian /* TODO: Optionally enable static VQ priorities feature */ 5329e2c7d99SGeorge Cherian 5339e2c7d99SGeorge Cherian dev_info(&pdev->dev, "SRIOV enabled, number of VF available %d\n", 5349e2c7d99SGeorge Cherian cpt->num_vf_en); 5359e2c7d99SGeorge Cherian 5369e2c7d99SGeorge Cherian cpt->flags |= CPT_FLAG_SRIOV_ENABLED; 5379e2c7d99SGeorge Cherian 5389e2c7d99SGeorge Cherian return 0; 5399e2c7d99SGeorge Cherian } 5409e2c7d99SGeorge Cherian 5419e2c7d99SGeorge Cherian static int cpt_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 5429e2c7d99SGeorge Cherian { 5439e2c7d99SGeorge Cherian struct device *dev = &pdev->dev; 5449e2c7d99SGeorge Cherian struct cpt_device *cpt; 5459e2c7d99SGeorge Cherian int err; 5469e2c7d99SGeorge Cherian 5479e2c7d99SGeorge Cherian if (num_vfs > 16 || num_vfs < 4) { 5489e2c7d99SGeorge Cherian dev_warn(dev, "Invalid vf count %d, Resetting it to 4(default)\n", 5499e2c7d99SGeorge Cherian num_vfs); 5509e2c7d99SGeorge Cherian num_vfs = 4; 5519e2c7d99SGeorge Cherian } 5529e2c7d99SGeorge Cherian 5539e2c7d99SGeorge Cherian cpt = devm_kzalloc(dev, sizeof(*cpt), GFP_KERNEL); 5549e2c7d99SGeorge Cherian if (!cpt) 5559e2c7d99SGeorge Cherian return -ENOMEM; 5569e2c7d99SGeorge Cherian 5579e2c7d99SGeorge Cherian pci_set_drvdata(pdev, cpt); 5589e2c7d99SGeorge Cherian cpt->pdev = pdev; 5599e2c7d99SGeorge Cherian err = pci_enable_device(pdev); 5609e2c7d99SGeorge Cherian if (err) { 5619e2c7d99SGeorge Cherian dev_err(dev, "Failed to enable PCI device\n"); 5629e2c7d99SGeorge Cherian pci_set_drvdata(pdev, NULL); 5639e2c7d99SGeorge Cherian return err; 5649e2c7d99SGeorge Cherian } 5659e2c7d99SGeorge Cherian 5669e2c7d99SGeorge Cherian err = pci_request_regions(pdev, DRV_NAME); 5679e2c7d99SGeorge Cherian if (err) { 5689e2c7d99SGeorge Cherian dev_err(dev, "PCI request regions failed 0x%x\n", err); 5699e2c7d99SGeorge Cherian goto cpt_err_disable_device; 5709e2c7d99SGeorge Cherian } 5719e2c7d99SGeorge Cherian 572*aeb4d8c0SChristophe JAILLET err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); 5739e2c7d99SGeorge Cherian if (err) { 574*aeb4d8c0SChristophe JAILLET dev_err(dev, "Unable to get usable 48-bit DMA configuration\n"); 5759e2c7d99SGeorge Cherian goto cpt_err_release_regions; 5769e2c7d99SGeorge Cherian } 5779e2c7d99SGeorge Cherian 5789e2c7d99SGeorge Cherian /* MAP PF's configuration registers */ 5799e2c7d99SGeorge Cherian cpt->reg_base = pcim_iomap(pdev, 0, 0); 5809e2c7d99SGeorge Cherian if (!cpt->reg_base) { 5819e2c7d99SGeorge Cherian dev_err(dev, "Cannot map config register space, aborting\n"); 5829e2c7d99SGeorge Cherian err = -ENOMEM; 5839e2c7d99SGeorge Cherian goto cpt_err_release_regions; 5849e2c7d99SGeorge Cherian } 5859e2c7d99SGeorge Cherian 5869e2c7d99SGeorge Cherian /* CPT device HW initialization */ 5879e2c7d99SGeorge Cherian cpt_device_init(cpt); 5889e2c7d99SGeorge Cherian 5899e2c7d99SGeorge Cherian /* Register interrupts */ 5909e2c7d99SGeorge Cherian err = cpt_register_interrupts(cpt); 5919e2c7d99SGeorge Cherian if (err) 5929e2c7d99SGeorge Cherian goto cpt_err_release_regions; 5939e2c7d99SGeorge Cherian 5949e2c7d99SGeorge Cherian err = cpt_ucode_load(cpt); 5959e2c7d99SGeorge Cherian if (err) 5969e2c7d99SGeorge Cherian goto cpt_err_unregister_interrupts; 5979e2c7d99SGeorge Cherian 5989e2c7d99SGeorge Cherian /* Configure SRIOV */ 5999e2c7d99SGeorge Cherian err = cpt_sriov_init(cpt, num_vfs); 6009e2c7d99SGeorge Cherian if (err) 6019e2c7d99SGeorge Cherian goto cpt_err_unregister_interrupts; 6029e2c7d99SGeorge Cherian 6039e2c7d99SGeorge Cherian return 0; 6049e2c7d99SGeorge Cherian 6059e2c7d99SGeorge Cherian cpt_err_unregister_interrupts: 6069e2c7d99SGeorge Cherian cpt_unregister_interrupts(cpt); 6079e2c7d99SGeorge Cherian cpt_err_release_regions: 6089e2c7d99SGeorge Cherian pci_release_regions(pdev); 6099e2c7d99SGeorge Cherian cpt_err_disable_device: 6109e2c7d99SGeorge Cherian pci_disable_device(pdev); 6119e2c7d99SGeorge Cherian pci_set_drvdata(pdev, NULL); 6129e2c7d99SGeorge Cherian return err; 6139e2c7d99SGeorge Cherian } 6149e2c7d99SGeorge Cherian 6159e2c7d99SGeorge Cherian static void cpt_remove(struct pci_dev *pdev) 6169e2c7d99SGeorge Cherian { 6179e2c7d99SGeorge Cherian struct cpt_device *cpt = pci_get_drvdata(pdev); 6189e2c7d99SGeorge Cherian 6199e2c7d99SGeorge Cherian /* Disengage SE and AE cores from all groups*/ 6209e2c7d99SGeorge Cherian cpt_disable_all_cores(cpt); 6219e2c7d99SGeorge Cherian /* Unload microcodes */ 6229e2c7d99SGeorge Cherian cpt_unload_microcode(cpt); 6239e2c7d99SGeorge Cherian cpt_unregister_interrupts(cpt); 6249e2c7d99SGeorge Cherian pci_disable_sriov(pdev); 6259e2c7d99SGeorge Cherian pci_release_regions(pdev); 6269e2c7d99SGeorge Cherian pci_disable_device(pdev); 6279e2c7d99SGeorge Cherian pci_set_drvdata(pdev, NULL); 6289e2c7d99SGeorge Cherian } 6299e2c7d99SGeorge Cherian 6309e2c7d99SGeorge Cherian static void cpt_shutdown(struct pci_dev *pdev) 6319e2c7d99SGeorge Cherian { 6329e2c7d99SGeorge Cherian struct cpt_device *cpt = pci_get_drvdata(pdev); 6339e2c7d99SGeorge Cherian 6349e2c7d99SGeorge Cherian if (!cpt) 6359e2c7d99SGeorge Cherian return; 6369e2c7d99SGeorge Cherian 6379e2c7d99SGeorge Cherian dev_info(&pdev->dev, "Shutdown device %x:%x.\n", 6389e2c7d99SGeorge Cherian (u32)pdev->vendor, (u32)pdev->device); 6399e2c7d99SGeorge Cherian 6409e2c7d99SGeorge Cherian cpt_unregister_interrupts(cpt); 6419e2c7d99SGeorge Cherian pci_release_regions(pdev); 6429e2c7d99SGeorge Cherian pci_disable_device(pdev); 6439e2c7d99SGeorge Cherian pci_set_drvdata(pdev, NULL); 6449e2c7d99SGeorge Cherian } 6459e2c7d99SGeorge Cherian 6469e2c7d99SGeorge Cherian /* Supported devices */ 6479e2c7d99SGeorge Cherian static const struct pci_device_id cpt_id_table[] = { 6489e2c7d99SGeorge Cherian { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, CPT_81XX_PCI_PF_DEVICE_ID) }, 6499e2c7d99SGeorge Cherian { 0, } /* end of table */ 6509e2c7d99SGeorge Cherian }; 6519e2c7d99SGeorge Cherian 6529e2c7d99SGeorge Cherian static struct pci_driver cpt_pci_driver = { 6539e2c7d99SGeorge Cherian .name = DRV_NAME, 6549e2c7d99SGeorge Cherian .id_table = cpt_id_table, 6559e2c7d99SGeorge Cherian .probe = cpt_probe, 6569e2c7d99SGeorge Cherian .remove = cpt_remove, 6579e2c7d99SGeorge Cherian .shutdown = cpt_shutdown, 6589e2c7d99SGeorge Cherian }; 6599e2c7d99SGeorge Cherian 6609e2c7d99SGeorge Cherian module_pci_driver(cpt_pci_driver); 6619e2c7d99SGeorge Cherian 6629e2c7d99SGeorge Cherian MODULE_AUTHOR("George Cherian <george.cherian@cavium.com>"); 6639e2c7d99SGeorge Cherian MODULE_DESCRIPTION("Cavium Thunder CPT Physical Function Driver"); 6649e2c7d99SGeorge Cherian MODULE_LICENSE("GPL v2"); 6659e2c7d99SGeorge Cherian MODULE_VERSION(DRV_VERSION); 6669e2c7d99SGeorge Cherian MODULE_DEVICE_TABLE(pci, cpt_id_table); 667