brintos

brintos / linux-shallow public Read only

0
0
Text · 7.3 KiB · 14a4255 Raw
302 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Marvell OcteonTX CPT driver3 *4 * Copyright (C) 2019 Marvell International Ltd.5 *6 * This program is free software; you can redistribute it and/or modify7 * it under the terms of the GNU General Public License version 2 as8 * published by the Free Software Foundation.9 */10 11#include "otx_cpt_common.h"12#include "otx_cptpf.h"13 14#define DRV_NAME	"octeontx-cpt"15#define DRV_VERSION	"1.0"16 17static void otx_cpt_disable_mbox_interrupts(struct otx_cpt_device *cpt)18{19	/* Disable mbox(0) interrupts for all VFs */20	writeq(~0ull, cpt->reg_base + OTX_CPT_PF_MBOX_ENA_W1CX(0));21}22 23static void otx_cpt_enable_mbox_interrupts(struct otx_cpt_device *cpt)24{25	/* Enable mbox(0) interrupts for all VFs */26	writeq(~0ull, cpt->reg_base + OTX_CPT_PF_MBOX_ENA_W1SX(0));27}28 29static irqreturn_t otx_cpt_mbx0_intr_handler(int __always_unused irq,30					     void *cpt)31{32	otx_cpt_mbox_intr_handler(cpt, 0);33 34	return IRQ_HANDLED;35}36 37static void otx_cpt_reset(struct otx_cpt_device *cpt)38{39	writeq(1, cpt->reg_base + OTX_CPT_PF_RESET);40}41 42static void otx_cpt_find_max_enabled_cores(struct otx_cpt_device *cpt)43{44	union otx_cptx_pf_constants pf_cnsts = {0};45 46	pf_cnsts.u = readq(cpt->reg_base + OTX_CPT_PF_CONSTANTS);47	cpt->eng_grps.avail.max_se_cnt = pf_cnsts.s.se;48	cpt->eng_grps.avail.max_ae_cnt = pf_cnsts.s.ae;49}50 51static u32 otx_cpt_check_bist_status(struct otx_cpt_device *cpt)52{53	union otx_cptx_pf_bist_status bist_sts = {0};54 55	bist_sts.u = readq(cpt->reg_base + OTX_CPT_PF_BIST_STATUS);56	return bist_sts.u;57}58 59static u64 otx_cpt_check_exe_bist_status(struct otx_cpt_device *cpt)60{61	union otx_cptx_pf_exe_bist_status bist_sts = {0};62 63	bist_sts.u = readq(cpt->reg_base + OTX_CPT_PF_EXE_BIST_STATUS);64	return bist_sts.u;65}66 67static int otx_cpt_device_init(struct otx_cpt_device *cpt)68{69	struct device *dev = &cpt->pdev->dev;70	u16 sdevid;71	u64 bist;72 73	/* Reset the PF when probed first */74	otx_cpt_reset(cpt);75	mdelay(100);76 77	pci_read_config_word(cpt->pdev, PCI_SUBSYSTEM_ID, &sdevid);78 79	/* Check BIST status */80	bist = (u64)otx_cpt_check_bist_status(cpt);81	if (bist) {82		dev_err(dev, "RAM BIST failed with code 0x%llx\n", bist);83		return -ENODEV;84	}85 86	bist = otx_cpt_check_exe_bist_status(cpt);87	if (bist) {88		dev_err(dev, "Engine BIST failed with code 0x%llx\n", bist);89		return -ENODEV;90	}91 92	/* Get max enabled cores */93	otx_cpt_find_max_enabled_cores(cpt);94 95	if ((sdevid == OTX_CPT_PCI_PF_SUBSYS_ID) &&96	    (cpt->eng_grps.avail.max_se_cnt == 0)) {97		cpt->pf_type = OTX_CPT_AE;98	} else if ((sdevid == OTX_CPT_PCI_PF_SUBSYS_ID) &&99		   (cpt->eng_grps.avail.max_ae_cnt == 0)) {100		cpt->pf_type = OTX_CPT_SE;101	}102 103	/* Get max VQs/VFs supported by the device */104	cpt->max_vfs = pci_sriov_get_totalvfs(cpt->pdev);105 106	/* Disable all cores */107	otx_cpt_disable_all_cores(cpt);108 109	return 0;110}111 112static int otx_cpt_register_interrupts(struct otx_cpt_device *cpt)113{114	struct device *dev = &cpt->pdev->dev;115	u32 mbox_int_idx = OTX_CPT_PF_MBOX_INT;116	u32 num_vec = OTX_CPT_PF_MSIX_VECTORS;117	int ret;118 119	/* Enable MSI-X */120	ret = pci_alloc_irq_vectors(cpt->pdev, num_vec, num_vec, PCI_IRQ_MSIX);121	if (ret < 0) {122		dev_err(&cpt->pdev->dev,123			"Request for #%d msix vectors failed\n",124			num_vec);125		return ret;126	}127 128	/* Register mailbox interrupt handlers */129	ret = request_irq(pci_irq_vector(cpt->pdev,130				OTX_CPT_PF_INT_VEC_E_MBOXX(mbox_int_idx, 0)),131				otx_cpt_mbx0_intr_handler, 0, "CPT Mbox0", cpt);132	if (ret) {133		dev_err(dev, "Request irq failed\n");134		pci_free_irq_vectors(cpt->pdev);135		return ret;136	}137	/* Enable mailbox interrupt */138	otx_cpt_enable_mbox_interrupts(cpt);139	return 0;140}141 142static void otx_cpt_unregister_interrupts(struct otx_cpt_device *cpt)143{144	u32 mbox_int_idx = OTX_CPT_PF_MBOX_INT;145 146	otx_cpt_disable_mbox_interrupts(cpt);147	free_irq(pci_irq_vector(cpt->pdev,148				OTX_CPT_PF_INT_VEC_E_MBOXX(mbox_int_idx, 0)),149				cpt);150	pci_free_irq_vectors(cpt->pdev);151}152 153 154static int otx_cpt_sriov_configure(struct pci_dev *pdev, int numvfs)155{156	struct otx_cpt_device *cpt = pci_get_drvdata(pdev);157	int ret = 0;158 159	if (numvfs > cpt->max_vfs)160		numvfs = cpt->max_vfs;161 162	if (numvfs > 0) {163		ret = otx_cpt_try_create_default_eng_grps(cpt->pdev,164							  &cpt->eng_grps,165							  cpt->pf_type);166		if (ret)167			return ret;168 169		cpt->vfs_enabled = numvfs;170		ret = pci_enable_sriov(pdev, numvfs);171		if (ret) {172			cpt->vfs_enabled = 0;173			return ret;174		}175		otx_cpt_set_eng_grps_is_rdonly(&cpt->eng_grps, true);176		try_module_get(THIS_MODULE);177		ret = numvfs;178	} else {179		pci_disable_sriov(pdev);180		otx_cpt_set_eng_grps_is_rdonly(&cpt->eng_grps, false);181		module_put(THIS_MODULE);182		cpt->vfs_enabled = 0;183	}184	dev_notice(&cpt->pdev->dev, "VFs enabled: %d\n", ret);185 186	return ret;187}188 189static int otx_cpt_probe(struct pci_dev *pdev,190			 const struct pci_device_id __always_unused *ent)191{192	struct device *dev = &pdev->dev;193	struct otx_cpt_device *cpt;194	int err;195 196	cpt = devm_kzalloc(dev, sizeof(*cpt), GFP_KERNEL);197	if (!cpt)198		return -ENOMEM;199 200	pci_set_drvdata(pdev, cpt);201	cpt->pdev = pdev;202 203	err = pci_enable_device(pdev);204	if (err) {205		dev_err(dev, "Failed to enable PCI device\n");206		goto err_clear_drvdata;207	}208 209	err = pci_request_regions(pdev, DRV_NAME);210	if (err) {211		dev_err(dev, "PCI request regions failed 0x%x\n", err);212		goto err_disable_device;213	}214 215	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48));216	if (err) {217		dev_err(dev, "Unable to get usable 48-bit DMA configuration\n");218		goto err_release_regions;219	}220 221	/* MAP PF's configuration registers */222	cpt->reg_base = pci_iomap(pdev, OTX_CPT_PF_PCI_CFG_BAR, 0);223	if (!cpt->reg_base) {224		dev_err(dev, "Cannot map config register space, aborting\n");225		err = -ENOMEM;226		goto err_release_regions;227	}228 229	/* CPT device HW initialization */230	err = otx_cpt_device_init(cpt);231	if (err)232		goto err_unmap_region;233 234	/* Register interrupts */235	err = otx_cpt_register_interrupts(cpt);236	if (err)237		goto err_unmap_region;238 239	/* Initialize engine groups */240	err = otx_cpt_init_eng_grps(pdev, &cpt->eng_grps, cpt->pf_type);241	if (err)242		goto err_unregister_interrupts;243 244	return 0;245 246err_unregister_interrupts:247	otx_cpt_unregister_interrupts(cpt);248err_unmap_region:249	pci_iounmap(pdev, cpt->reg_base);250err_release_regions:251	pci_release_regions(pdev);252err_disable_device:253	pci_disable_device(pdev);254err_clear_drvdata:255	pci_set_drvdata(pdev, NULL);256 257	return err;258}259 260static void otx_cpt_remove(struct pci_dev *pdev)261{262	struct otx_cpt_device *cpt = pci_get_drvdata(pdev);263 264	if (!cpt)265		return;266 267	/* Disable VFs */268	pci_disable_sriov(pdev);269	/* Cleanup engine groups */270	otx_cpt_cleanup_eng_grps(pdev, &cpt->eng_grps);271	/* Disable CPT PF interrupts */272	otx_cpt_unregister_interrupts(cpt);273	/* Disengage SE and AE cores from all groups */274	otx_cpt_disable_all_cores(cpt);275	pci_iounmap(pdev, cpt->reg_base);276	pci_release_regions(pdev);277	pci_disable_device(pdev);278	pci_set_drvdata(pdev, NULL);279}280 281/* Supported devices */282static const struct pci_device_id otx_cpt_id_table[] = {283	{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OTX_CPT_PCI_PF_DEVICE_ID) },284	{ 0, }  /* end of table */285};286 287static struct pci_driver otx_cpt_pci_driver = {288	.name = DRV_NAME,289	.id_table = otx_cpt_id_table,290	.probe = otx_cpt_probe,291	.remove = otx_cpt_remove,292	.sriov_configure = otx_cpt_sriov_configure293};294 295module_pci_driver(otx_cpt_pci_driver);296 297MODULE_AUTHOR("Marvell International Ltd.");298MODULE_DESCRIPTION("Marvell OcteonTX CPT Physical Function Driver");299MODULE_LICENSE("GPL v2");300MODULE_VERSION(DRV_VERSION);301MODULE_DEVICE_TABLE(pci, otx_cpt_id_table);302