18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci#include <linux/aer.h> 38c2ecf20Sopenharmony_ci#include <linux/delay.h> 48c2ecf20Sopenharmony_ci#include <linux/firmware.h> 58c2ecf20Sopenharmony_ci#include <linux/list.h> 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/mutex.h> 88c2ecf20Sopenharmony_ci#include <linux/pci.h> 98c2ecf20Sopenharmony_ci#include <linux/pci_ids.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "nitrox_dev.h" 128c2ecf20Sopenharmony_ci#include "nitrox_common.h" 138c2ecf20Sopenharmony_ci#include "nitrox_csr.h" 148c2ecf20Sopenharmony_ci#include "nitrox_hal.h" 158c2ecf20Sopenharmony_ci#include "nitrox_isr.h" 168c2ecf20Sopenharmony_ci#include "nitrox_debugfs.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define CNN55XX_DEV_ID 0x12 198c2ecf20Sopenharmony_ci#define UCODE_HLEN 48 208c2ecf20Sopenharmony_ci#define DEFAULT_SE_GROUP 0 218c2ecf20Sopenharmony_ci#define DEFAULT_AE_GROUP 0 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define DRIVER_VERSION "1.2" 248c2ecf20Sopenharmony_ci#define CNN55XX_UCD_BLOCK_SIZE 32768 258c2ecf20Sopenharmony_ci#define CNN55XX_MAX_UCODE_SIZE (CNN55XX_UCD_BLOCK_SIZE * 2) 268c2ecf20Sopenharmony_ci#define FW_DIR "cavium/" 278c2ecf20Sopenharmony_ci/* SE microcode */ 288c2ecf20Sopenharmony_ci#define SE_FW FW_DIR "cnn55xx_se.fw" 298c2ecf20Sopenharmony_ci/* AE microcode */ 308c2ecf20Sopenharmony_ci#define AE_FW FW_DIR "cnn55xx_ae.fw" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic const char nitrox_driver_name[] = "CNN55XX"; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic LIST_HEAD(ndevlist); 358c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(devlist_lock); 368c2ecf20Sopenharmony_cistatic unsigned int num_devices; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/** 398c2ecf20Sopenharmony_ci * nitrox_pci_tbl - PCI Device ID Table 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_cistatic const struct pci_device_id nitrox_pci_tbl[] = { 428c2ecf20Sopenharmony_ci {PCI_VDEVICE(CAVIUM, CNN55XX_DEV_ID), 0}, 438c2ecf20Sopenharmony_ci /* required last entry */ 448c2ecf20Sopenharmony_ci {0, } 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, nitrox_pci_tbl); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic unsigned int qlen = DEFAULT_CMD_QLEN; 498c2ecf20Sopenharmony_cimodule_param(qlen, uint, 0644); 508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(qlen, "Command queue length - default 2048"); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV 538c2ecf20Sopenharmony_ciint nitrox_sriov_configure(struct pci_dev *pdev, int num_vfs); 548c2ecf20Sopenharmony_ci#else 558c2ecf20Sopenharmony_ciint nitrox_sriov_configure(struct pci_dev *pdev, int num_vfs) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci return 0; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci#endif 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/** 628c2ecf20Sopenharmony_ci * struct ucode - Firmware Header 638c2ecf20Sopenharmony_ci * @id: microcode ID 648c2ecf20Sopenharmony_ci * @version: firmware version 658c2ecf20Sopenharmony_ci * @code_size: code section size 668c2ecf20Sopenharmony_ci * @raz: alignment 678c2ecf20Sopenharmony_ci * @code: code section 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_cistruct ucode { 708c2ecf20Sopenharmony_ci u8 id; 718c2ecf20Sopenharmony_ci char version[VERSION_LEN - 1]; 728c2ecf20Sopenharmony_ci __be32 code_size; 738c2ecf20Sopenharmony_ci u8 raz[12]; 748c2ecf20Sopenharmony_ci u64 code[]; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/** 788c2ecf20Sopenharmony_ci * write_to_ucd_unit - Write Firmware to NITROX UCD unit 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_cistatic void write_to_ucd_unit(struct nitrox_device *ndev, u32 ucode_size, 818c2ecf20Sopenharmony_ci u64 *ucode_data, int block_num) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci u32 code_size; 848c2ecf20Sopenharmony_ci u64 offset, data; 858c2ecf20Sopenharmony_ci int i = 0; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* 888c2ecf20Sopenharmony_ci * UCD structure 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * ------------- 918c2ecf20Sopenharmony_ci * | BLK 7 | 928c2ecf20Sopenharmony_ci * ------------- 938c2ecf20Sopenharmony_ci * | BLK 6 | 948c2ecf20Sopenharmony_ci * ------------- 958c2ecf20Sopenharmony_ci * | ... | 968c2ecf20Sopenharmony_ci * ------------- 978c2ecf20Sopenharmony_ci * | BLK 0 | 988c2ecf20Sopenharmony_ci * ------------- 998c2ecf20Sopenharmony_ci * Total of 8 blocks, each size 32KB 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* set the block number */ 1038c2ecf20Sopenharmony_ci offset = UCD_UCODE_LOAD_BLOCK_NUM; 1048c2ecf20Sopenharmony_ci nitrox_write_csr(ndev, offset, block_num); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci code_size = roundup(ucode_size, 16); 1078c2ecf20Sopenharmony_ci while (code_size) { 1088c2ecf20Sopenharmony_ci data = ucode_data[i]; 1098c2ecf20Sopenharmony_ci /* write 8 bytes at a time */ 1108c2ecf20Sopenharmony_ci offset = UCD_UCODE_LOAD_IDX_DATAX(i); 1118c2ecf20Sopenharmony_ci nitrox_write_csr(ndev, offset, data); 1128c2ecf20Sopenharmony_ci code_size -= 8; 1138c2ecf20Sopenharmony_ci i++; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci usleep_range(300, 400); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic int nitrox_load_fw(struct nitrox_device *ndev) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci const struct firmware *fw; 1228c2ecf20Sopenharmony_ci const char *fw_name; 1238c2ecf20Sopenharmony_ci struct ucode *ucode; 1248c2ecf20Sopenharmony_ci u64 *ucode_data; 1258c2ecf20Sopenharmony_ci u64 offset; 1268c2ecf20Sopenharmony_ci union ucd_core_eid_ucode_block_num core_2_eid_val; 1278c2ecf20Sopenharmony_ci union aqm_grp_execmsk_lo aqm_grp_execmask_lo; 1288c2ecf20Sopenharmony_ci union aqm_grp_execmsk_hi aqm_grp_execmask_hi; 1298c2ecf20Sopenharmony_ci u32 ucode_size; 1308c2ecf20Sopenharmony_ci int ret, i = 0; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci fw_name = SE_FW; 1338c2ecf20Sopenharmony_ci dev_info(DEV(ndev), "Loading firmware \"%s\"\n", fw_name); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci ret = request_firmware(&fw, fw_name, DEV(ndev)); 1368c2ecf20Sopenharmony_ci if (ret < 0) { 1378c2ecf20Sopenharmony_ci dev_err(DEV(ndev), "failed to get firmware %s\n", fw_name); 1388c2ecf20Sopenharmony_ci return ret; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci ucode = (struct ucode *)fw->data; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci ucode_size = be32_to_cpu(ucode->code_size) * 2; 1448c2ecf20Sopenharmony_ci if (!ucode_size || ucode_size > CNN55XX_MAX_UCODE_SIZE) { 1458c2ecf20Sopenharmony_ci dev_err(DEV(ndev), "Invalid ucode size: %u for firmware %s\n", 1468c2ecf20Sopenharmony_ci ucode_size, fw_name); 1478c2ecf20Sopenharmony_ci release_firmware(fw); 1488c2ecf20Sopenharmony_ci return -EINVAL; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci ucode_data = ucode->code; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* copy the firmware version */ 1538c2ecf20Sopenharmony_ci memcpy(&ndev->hw.fw_name[0][0], ucode->version, (VERSION_LEN - 2)); 1548c2ecf20Sopenharmony_ci ndev->hw.fw_name[0][VERSION_LEN - 1] = '\0'; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* Load SE Firmware on UCD Block 0 */ 1578c2ecf20Sopenharmony_ci write_to_ucd_unit(ndev, ucode_size, ucode_data, 0); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci release_firmware(fw); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* put all SE cores in DEFAULT_SE_GROUP */ 1628c2ecf20Sopenharmony_ci offset = POM_GRP_EXECMASKX(DEFAULT_SE_GROUP); 1638c2ecf20Sopenharmony_ci nitrox_write_csr(ndev, offset, (~0ULL)); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* write block number and firmware length 1668c2ecf20Sopenharmony_ci * bit:<2:0> block number 1678c2ecf20Sopenharmony_ci * bit:3 is set SE uses 32KB microcode 1688c2ecf20Sopenharmony_ci * bit:3 is clear SE uses 64KB microcode 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci core_2_eid_val.value = 0ULL; 1718c2ecf20Sopenharmony_ci core_2_eid_val.ucode_blk = 0; 1728c2ecf20Sopenharmony_ci if (ucode_size <= CNN55XX_UCD_BLOCK_SIZE) 1738c2ecf20Sopenharmony_ci core_2_eid_val.ucode_len = 1; 1748c2ecf20Sopenharmony_ci else 1758c2ecf20Sopenharmony_ci core_2_eid_val.ucode_len = 0; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci for (i = 0; i < ndev->hw.se_cores; i++) { 1788c2ecf20Sopenharmony_ci offset = UCD_SE_EID_UCODE_BLOCK_NUMX(i); 1798c2ecf20Sopenharmony_ci nitrox_write_csr(ndev, offset, core_2_eid_val.value); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci fw_name = AE_FW; 1848c2ecf20Sopenharmony_ci dev_info(DEV(ndev), "Loading firmware \"%s\"\n", fw_name); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci ret = request_firmware(&fw, fw_name, DEV(ndev)); 1878c2ecf20Sopenharmony_ci if (ret < 0) { 1888c2ecf20Sopenharmony_ci dev_err(DEV(ndev), "failed to get firmware %s\n", fw_name); 1898c2ecf20Sopenharmony_ci return ret; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci ucode = (struct ucode *)fw->data; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci ucode_size = be32_to_cpu(ucode->code_size) * 2; 1958c2ecf20Sopenharmony_ci if (!ucode_size || ucode_size > CNN55XX_MAX_UCODE_SIZE) { 1968c2ecf20Sopenharmony_ci dev_err(DEV(ndev), "Invalid ucode size: %u for firmware %s\n", 1978c2ecf20Sopenharmony_ci ucode_size, fw_name); 1988c2ecf20Sopenharmony_ci release_firmware(fw); 1998c2ecf20Sopenharmony_ci return -EINVAL; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci ucode_data = ucode->code; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* copy the firmware version */ 2048c2ecf20Sopenharmony_ci memcpy(&ndev->hw.fw_name[1][0], ucode->version, (VERSION_LEN - 2)); 2058c2ecf20Sopenharmony_ci ndev->hw.fw_name[1][VERSION_LEN - 1] = '\0'; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* Load AE Firmware on UCD Block 2 */ 2088c2ecf20Sopenharmony_ci write_to_ucd_unit(ndev, ucode_size, ucode_data, 2); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci release_firmware(fw); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* put all AE cores in DEFAULT_AE_GROUP */ 2138c2ecf20Sopenharmony_ci offset = AQM_GRP_EXECMSK_LOX(DEFAULT_AE_GROUP); 2148c2ecf20Sopenharmony_ci aqm_grp_execmask_lo.exec_0_to_39 = 0xFFFFFFFFFFULL; 2158c2ecf20Sopenharmony_ci nitrox_write_csr(ndev, offset, aqm_grp_execmask_lo.value); 2168c2ecf20Sopenharmony_ci offset = AQM_GRP_EXECMSK_HIX(DEFAULT_AE_GROUP); 2178c2ecf20Sopenharmony_ci aqm_grp_execmask_hi.exec_40_to_79 = 0xFFFFFFFFFFULL; 2188c2ecf20Sopenharmony_ci nitrox_write_csr(ndev, offset, aqm_grp_execmask_hi.value); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* write block number and firmware length 2218c2ecf20Sopenharmony_ci * bit:<2:0> block number 2228c2ecf20Sopenharmony_ci * bit:3 is set AE uses 32KB microcode 2238c2ecf20Sopenharmony_ci * bit:3 is clear AE uses 64KB microcode 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci core_2_eid_val.value = 0ULL; 2268c2ecf20Sopenharmony_ci core_2_eid_val.ucode_blk = 2; 2278c2ecf20Sopenharmony_ci if (ucode_size <= CNN55XX_UCD_BLOCK_SIZE) 2288c2ecf20Sopenharmony_ci core_2_eid_val.ucode_len = 1; 2298c2ecf20Sopenharmony_ci else 2308c2ecf20Sopenharmony_ci core_2_eid_val.ucode_len = 0; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci for (i = 0; i < ndev->hw.ae_cores; i++) { 2338c2ecf20Sopenharmony_ci offset = UCD_AE_EID_UCODE_BLOCK_NUMX(i); 2348c2ecf20Sopenharmony_ci nitrox_write_csr(ndev, offset, core_2_eid_val.value); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/** 2418c2ecf20Sopenharmony_ci * nitrox_add_to_devlist - add NITROX device to global device list 2428c2ecf20Sopenharmony_ci * @ndev: NITROX device 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic int nitrox_add_to_devlist(struct nitrox_device *ndev) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct nitrox_device *dev; 2478c2ecf20Sopenharmony_ci int ret = 0; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ndev->list); 2508c2ecf20Sopenharmony_ci refcount_set(&ndev->refcnt, 1); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci mutex_lock(&devlist_lock); 2538c2ecf20Sopenharmony_ci list_for_each_entry(dev, &ndevlist, list) { 2548c2ecf20Sopenharmony_ci if (dev == ndev) { 2558c2ecf20Sopenharmony_ci ret = -EEXIST; 2568c2ecf20Sopenharmony_ci goto unlock; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci ndev->idx = num_devices++; 2608c2ecf20Sopenharmony_ci list_add_tail(&ndev->list, &ndevlist); 2618c2ecf20Sopenharmony_ciunlock: 2628c2ecf20Sopenharmony_ci mutex_unlock(&devlist_lock); 2638c2ecf20Sopenharmony_ci return ret; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/** 2678c2ecf20Sopenharmony_ci * nitrox_remove_from_devlist - remove NITROX device from 2688c2ecf20Sopenharmony_ci * global device list 2698c2ecf20Sopenharmony_ci * @ndev: NITROX device 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_cistatic void nitrox_remove_from_devlist(struct nitrox_device *ndev) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci mutex_lock(&devlist_lock); 2748c2ecf20Sopenharmony_ci list_del(&ndev->list); 2758c2ecf20Sopenharmony_ci num_devices--; 2768c2ecf20Sopenharmony_ci mutex_unlock(&devlist_lock); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistruct nitrox_device *nitrox_get_first_device(void) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct nitrox_device *ndev; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci mutex_lock(&devlist_lock); 2848c2ecf20Sopenharmony_ci list_for_each_entry(ndev, &ndevlist, list) { 2858c2ecf20Sopenharmony_ci if (nitrox_ready(ndev)) 2868c2ecf20Sopenharmony_ci break; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci mutex_unlock(&devlist_lock); 2898c2ecf20Sopenharmony_ci if (&ndev->list == &ndevlist) 2908c2ecf20Sopenharmony_ci return NULL; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci refcount_inc(&ndev->refcnt); 2938c2ecf20Sopenharmony_ci /* barrier to sync with other cpus */ 2948c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 2958c2ecf20Sopenharmony_ci return ndev; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_civoid nitrox_put_device(struct nitrox_device *ndev) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci if (!ndev) 3018c2ecf20Sopenharmony_ci return; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci refcount_dec(&ndev->refcnt); 3048c2ecf20Sopenharmony_ci /* barrier to sync with other cpus */ 3058c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic int nitrox_device_flr(struct pci_dev *pdev) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci int pos = 0; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci pos = pci_save_state(pdev); 3138c2ecf20Sopenharmony_ci if (pos) { 3148c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to save pci state\n"); 3158c2ecf20Sopenharmony_ci return -ENOMEM; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* check flr support */ 3198c2ecf20Sopenharmony_ci if (pcie_has_flr(pdev)) 3208c2ecf20Sopenharmony_ci pcie_flr(pdev); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci pci_restore_state(pdev); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic int nitrox_pf_sw_init(struct nitrox_device *ndev) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci int err; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci err = nitrox_common_sw_init(ndev); 3328c2ecf20Sopenharmony_ci if (err) 3338c2ecf20Sopenharmony_ci return err; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci err = nitrox_register_interrupts(ndev); 3368c2ecf20Sopenharmony_ci if (err) 3378c2ecf20Sopenharmony_ci nitrox_common_sw_cleanup(ndev); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return err; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic void nitrox_pf_sw_cleanup(struct nitrox_device *ndev) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci nitrox_unregister_interrupts(ndev); 3458c2ecf20Sopenharmony_ci nitrox_common_sw_cleanup(ndev); 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci/** 3498c2ecf20Sopenharmony_ci * nitrox_bist_check - Check NITROX BIST registers status 3508c2ecf20Sopenharmony_ci * @ndev: NITROX device 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_cistatic int nitrox_bist_check(struct nitrox_device *ndev) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci u64 value = 0; 3558c2ecf20Sopenharmony_ci int i; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci for (i = 0; i < NR_CLUSTERS; i++) { 3588c2ecf20Sopenharmony_ci value += nitrox_read_csr(ndev, EMU_BIST_STATUSX(i)); 3598c2ecf20Sopenharmony_ci value += nitrox_read_csr(ndev, EFL_CORE_BIST_REGX(i)); 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci value += nitrox_read_csr(ndev, UCD_BIST_STATUS); 3628c2ecf20Sopenharmony_ci value += nitrox_read_csr(ndev, NPS_CORE_BIST_REG); 3638c2ecf20Sopenharmony_ci value += nitrox_read_csr(ndev, NPS_CORE_NPC_BIST_REG); 3648c2ecf20Sopenharmony_ci value += nitrox_read_csr(ndev, NPS_PKT_SLC_BIST_REG); 3658c2ecf20Sopenharmony_ci value += nitrox_read_csr(ndev, NPS_PKT_IN_BIST_REG); 3668c2ecf20Sopenharmony_ci value += nitrox_read_csr(ndev, POM_BIST_REG); 3678c2ecf20Sopenharmony_ci value += nitrox_read_csr(ndev, BMI_BIST_REG); 3688c2ecf20Sopenharmony_ci value += nitrox_read_csr(ndev, EFL_TOP_BIST_STAT); 3698c2ecf20Sopenharmony_ci value += nitrox_read_csr(ndev, BMO_BIST_REG); 3708c2ecf20Sopenharmony_ci value += nitrox_read_csr(ndev, LBC_BIST_STATUS); 3718c2ecf20Sopenharmony_ci value += nitrox_read_csr(ndev, PEM_BIST_STATUSX(0)); 3728c2ecf20Sopenharmony_ci if (value) 3738c2ecf20Sopenharmony_ci return -EIO; 3748c2ecf20Sopenharmony_ci return 0; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic int nitrox_pf_hw_init(struct nitrox_device *ndev) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci int err; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci err = nitrox_bist_check(ndev); 3828c2ecf20Sopenharmony_ci if (err) { 3838c2ecf20Sopenharmony_ci dev_err(&ndev->pdev->dev, "BIST check failed\n"); 3848c2ecf20Sopenharmony_ci return err; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci /* get cores information */ 3878c2ecf20Sopenharmony_ci nitrox_get_hwinfo(ndev); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci nitrox_config_nps_core_unit(ndev); 3908c2ecf20Sopenharmony_ci nitrox_config_aqm_unit(ndev); 3918c2ecf20Sopenharmony_ci nitrox_config_nps_pkt_unit(ndev); 3928c2ecf20Sopenharmony_ci nitrox_config_pom_unit(ndev); 3938c2ecf20Sopenharmony_ci nitrox_config_efl_unit(ndev); 3948c2ecf20Sopenharmony_ci /* configure IO units */ 3958c2ecf20Sopenharmony_ci nitrox_config_bmi_unit(ndev); 3968c2ecf20Sopenharmony_ci nitrox_config_bmo_unit(ndev); 3978c2ecf20Sopenharmony_ci /* configure Local Buffer Cache */ 3988c2ecf20Sopenharmony_ci nitrox_config_lbc_unit(ndev); 3998c2ecf20Sopenharmony_ci nitrox_config_rand_unit(ndev); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* load firmware on cores */ 4028c2ecf20Sopenharmony_ci err = nitrox_load_fw(ndev); 4038c2ecf20Sopenharmony_ci if (err) 4048c2ecf20Sopenharmony_ci return err; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci nitrox_config_emu_unit(ndev); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci return 0; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci/** 4128c2ecf20Sopenharmony_ci * nitrox_probe - NITROX Initialization function. 4138c2ecf20Sopenharmony_ci * @pdev: PCI device information struct 4148c2ecf20Sopenharmony_ci * @id: entry in nitrox_pci_tbl 4158c2ecf20Sopenharmony_ci * 4168c2ecf20Sopenharmony_ci * Return: 0, if the driver is bound to the device, or 4178c2ecf20Sopenharmony_ci * a negative error if there is failure. 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_cistatic int nitrox_probe(struct pci_dev *pdev, 4208c2ecf20Sopenharmony_ci const struct pci_device_id *id) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct nitrox_device *ndev; 4238c2ecf20Sopenharmony_ci int err; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci dev_info_once(&pdev->dev, "%s driver version %s\n", 4268c2ecf20Sopenharmony_ci nitrox_driver_name, DRIVER_VERSION); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci err = pci_enable_device_mem(pdev); 4298c2ecf20Sopenharmony_ci if (err) 4308c2ecf20Sopenharmony_ci return err; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* do FLR */ 4338c2ecf20Sopenharmony_ci err = nitrox_device_flr(pdev); 4348c2ecf20Sopenharmony_ci if (err) { 4358c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "FLR failed\n"); 4368c2ecf20Sopenharmony_ci pci_disable_device(pdev); 4378c2ecf20Sopenharmony_ci return err; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) { 4418c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "DMA to 64-BIT address\n"); 4428c2ecf20Sopenharmony_ci } else { 4438c2ecf20Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 4448c2ecf20Sopenharmony_ci if (err) { 4458c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "DMA configuration failed\n"); 4468c2ecf20Sopenharmony_ci pci_disable_device(pdev); 4478c2ecf20Sopenharmony_ci return err; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci err = pci_request_mem_regions(pdev, nitrox_driver_name); 4528c2ecf20Sopenharmony_ci if (err) { 4538c2ecf20Sopenharmony_ci pci_disable_device(pdev); 4548c2ecf20Sopenharmony_ci return err; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci pci_set_master(pdev); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci ndev = kzalloc(sizeof(*ndev), GFP_KERNEL); 4598c2ecf20Sopenharmony_ci if (!ndev) { 4608c2ecf20Sopenharmony_ci err = -ENOMEM; 4618c2ecf20Sopenharmony_ci goto ndev_fail; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, ndev); 4658c2ecf20Sopenharmony_ci ndev->pdev = pdev; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* add to device list */ 4688c2ecf20Sopenharmony_ci nitrox_add_to_devlist(ndev); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci ndev->hw.vendor_id = pdev->vendor; 4718c2ecf20Sopenharmony_ci ndev->hw.device_id = pdev->device; 4728c2ecf20Sopenharmony_ci ndev->hw.revision_id = pdev->revision; 4738c2ecf20Sopenharmony_ci /* command timeout in jiffies */ 4748c2ecf20Sopenharmony_ci ndev->timeout = msecs_to_jiffies(CMD_TIMEOUT); 4758c2ecf20Sopenharmony_ci ndev->node = dev_to_node(&pdev->dev); 4768c2ecf20Sopenharmony_ci if (ndev->node == NUMA_NO_NODE) 4778c2ecf20Sopenharmony_ci ndev->node = 0; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci ndev->bar_addr = ioremap(pci_resource_start(pdev, 0), 4808c2ecf20Sopenharmony_ci pci_resource_len(pdev, 0)); 4818c2ecf20Sopenharmony_ci if (!ndev->bar_addr) { 4828c2ecf20Sopenharmony_ci err = -EIO; 4838c2ecf20Sopenharmony_ci goto ioremap_err; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci /* allocate command queus based on cpus, max queues are 64 */ 4868c2ecf20Sopenharmony_ci ndev->nr_queues = min_t(u32, MAX_PF_QUEUES, num_online_cpus()); 4878c2ecf20Sopenharmony_ci ndev->qlen = qlen; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci err = nitrox_pf_sw_init(ndev); 4908c2ecf20Sopenharmony_ci if (err) 4918c2ecf20Sopenharmony_ci goto ioremap_err; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci err = nitrox_pf_hw_init(ndev); 4948c2ecf20Sopenharmony_ci if (err) 4958c2ecf20Sopenharmony_ci goto pf_hw_fail; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci nitrox_debugfs_init(ndev); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* clear the statistics */ 5008c2ecf20Sopenharmony_ci atomic64_set(&ndev->stats.posted, 0); 5018c2ecf20Sopenharmony_ci atomic64_set(&ndev->stats.completed, 0); 5028c2ecf20Sopenharmony_ci atomic64_set(&ndev->stats.dropped, 0); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci atomic_set(&ndev->state, __NDEV_READY); 5058c2ecf20Sopenharmony_ci /* barrier to sync with other cpus */ 5068c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci err = nitrox_crypto_register(); 5098c2ecf20Sopenharmony_ci if (err) 5108c2ecf20Sopenharmony_ci goto crypto_fail; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci return 0; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cicrypto_fail: 5158c2ecf20Sopenharmony_ci nitrox_debugfs_exit(ndev); 5168c2ecf20Sopenharmony_ci atomic_set(&ndev->state, __NDEV_NOT_READY); 5178c2ecf20Sopenharmony_ci /* barrier to sync with other cpus */ 5188c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 5198c2ecf20Sopenharmony_cipf_hw_fail: 5208c2ecf20Sopenharmony_ci nitrox_pf_sw_cleanup(ndev); 5218c2ecf20Sopenharmony_ciioremap_err: 5228c2ecf20Sopenharmony_ci nitrox_remove_from_devlist(ndev); 5238c2ecf20Sopenharmony_ci kfree(ndev); 5248c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 5258c2ecf20Sopenharmony_cindev_fail: 5268c2ecf20Sopenharmony_ci pci_release_mem_regions(pdev); 5278c2ecf20Sopenharmony_ci pci_disable_device(pdev); 5288c2ecf20Sopenharmony_ci return err; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci/** 5328c2ecf20Sopenharmony_ci * nitrox_remove - Unbind the driver from the device. 5338c2ecf20Sopenharmony_ci * @pdev: PCI device information struct 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_cistatic void nitrox_remove(struct pci_dev *pdev) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci struct nitrox_device *ndev = pci_get_drvdata(pdev); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (!ndev) 5408c2ecf20Sopenharmony_ci return; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (!refcount_dec_and_test(&ndev->refcnt)) { 5438c2ecf20Sopenharmony_ci dev_err(DEV(ndev), "Device refcnt not zero (%d)\n", 5448c2ecf20Sopenharmony_ci refcount_read(&ndev->refcnt)); 5458c2ecf20Sopenharmony_ci return; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci dev_info(DEV(ndev), "Removing Device %x:%x\n", 5498c2ecf20Sopenharmony_ci ndev->hw.vendor_id, ndev->hw.device_id); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci atomic_set(&ndev->state, __NDEV_NOT_READY); 5528c2ecf20Sopenharmony_ci /* barrier to sync with other cpus */ 5538c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci nitrox_remove_from_devlist(ndev); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV 5588c2ecf20Sopenharmony_ci /* disable SR-IOV */ 5598c2ecf20Sopenharmony_ci nitrox_sriov_configure(pdev, 0); 5608c2ecf20Sopenharmony_ci#endif 5618c2ecf20Sopenharmony_ci nitrox_crypto_unregister(); 5628c2ecf20Sopenharmony_ci nitrox_debugfs_exit(ndev); 5638c2ecf20Sopenharmony_ci nitrox_pf_sw_cleanup(ndev); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci iounmap(ndev->bar_addr); 5668c2ecf20Sopenharmony_ci kfree(ndev); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 5698c2ecf20Sopenharmony_ci pci_release_mem_regions(pdev); 5708c2ecf20Sopenharmony_ci pci_disable_device(pdev); 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic void nitrox_shutdown(struct pci_dev *pdev) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 5768c2ecf20Sopenharmony_ci pci_release_mem_regions(pdev); 5778c2ecf20Sopenharmony_ci pci_disable_device(pdev); 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic struct pci_driver nitrox_driver = { 5818c2ecf20Sopenharmony_ci .name = nitrox_driver_name, 5828c2ecf20Sopenharmony_ci .id_table = nitrox_pci_tbl, 5838c2ecf20Sopenharmony_ci .probe = nitrox_probe, 5848c2ecf20Sopenharmony_ci .remove = nitrox_remove, 5858c2ecf20Sopenharmony_ci .shutdown = nitrox_shutdown, 5868c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV 5878c2ecf20Sopenharmony_ci .sriov_configure = nitrox_sriov_configure, 5888c2ecf20Sopenharmony_ci#endif 5898c2ecf20Sopenharmony_ci}; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cimodule_pci_driver(nitrox_driver); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ciMODULE_AUTHOR("Srikanth Jampala <Jampala.Srikanth@cavium.com>"); 5948c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cavium CNN55XX PF Driver" DRIVER_VERSION " "); 5958c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 5968c2ecf20Sopenharmony_ciMODULE_VERSION(DRIVER_VERSION); 5978c2ecf20Sopenharmony_ciMODULE_FIRMWARE(SE_FW); 598