cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

otx_cptpf_main.c (7452B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Marvell OcteonTX CPT driver
      3 *
      4 * Copyright (C) 2019 Marvell International Ltd.
      5 *
      6 * This program is free software; you can redistribute it and/or modify
      7 * it under the terms of the GNU General Public License version 2 as
      8 * 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_configure
    293};
    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);