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