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