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

adf_isr.c (10209B)


      1// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
      2/* Copyright(c) 2014 - 2020 Intel Corporation */
      3#include <linux/kernel.h>
      4#include <linux/init.h>
      5#include <linux/types.h>
      6#include <linux/pci.h>
      7#include <linux/slab.h>
      8#include <linux/errno.h>
      9#include <linux/interrupt.h>
     10#include "adf_accel_devices.h"
     11#include "adf_common_drv.h"
     12#include "adf_cfg.h"
     13#include "adf_cfg_strings.h"
     14#include "adf_cfg_common.h"
     15#include "adf_transport_access_macros.h"
     16#include "adf_transport_internal.h"
     17
     18#define ADF_MAX_NUM_VFS	32
     19static struct workqueue_struct *adf_misc_wq;
     20
     21static int adf_enable_msix(struct adf_accel_dev *accel_dev)
     22{
     23	struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
     24	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
     25	u32 msix_num_entries = hw_data->num_banks + 1;
     26	int ret;
     27
     28	if (hw_data->set_msix_rttable)
     29		hw_data->set_msix_rttable(accel_dev);
     30
     31	ret = pci_alloc_irq_vectors(pci_dev_info->pci_dev, msix_num_entries,
     32				    msix_num_entries, PCI_IRQ_MSIX);
     33	if (unlikely(ret < 0)) {
     34		dev_err(&GET_DEV(accel_dev),
     35			"Failed to allocate %d MSI-X vectors\n",
     36			msix_num_entries);
     37		return ret;
     38	}
     39	return 0;
     40}
     41
     42static void adf_disable_msix(struct adf_accel_pci *pci_dev_info)
     43{
     44	pci_free_irq_vectors(pci_dev_info->pci_dev);
     45}
     46
     47static irqreturn_t adf_msix_isr_bundle(int irq, void *bank_ptr)
     48{
     49	struct adf_etr_bank_data *bank = bank_ptr;
     50	struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(bank->accel_dev);
     51
     52	csr_ops->write_csr_int_flag_and_col(bank->csr_addr, bank->bank_number,
     53					    0);
     54	tasklet_hi_schedule(&bank->resp_handler);
     55	return IRQ_HANDLED;
     56}
     57
     58#ifdef CONFIG_PCI_IOV
     59void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask)
     60{
     61	void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);
     62	unsigned long flags;
     63
     64	spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
     65	GET_PFVF_OPS(accel_dev)->enable_vf2pf_interrupts(pmisc_addr, vf_mask);
     66	spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
     67}
     68
     69void adf_disable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev)
     70{
     71	void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);
     72	unsigned long flags;
     73
     74	spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
     75	GET_PFVF_OPS(accel_dev)->disable_all_vf2pf_interrupts(pmisc_addr);
     76	spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
     77}
     78
     79static u32 adf_disable_pending_vf2pf_interrupts(struct adf_accel_dev *accel_dev)
     80{
     81	void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);
     82	u32 pending;
     83
     84	spin_lock(&accel_dev->pf.vf2pf_ints_lock);
     85	pending = GET_PFVF_OPS(accel_dev)->disable_pending_vf2pf_interrupts(pmisc_addr);
     86	spin_unlock(&accel_dev->pf.vf2pf_ints_lock);
     87
     88	return pending;
     89}
     90
     91static bool adf_handle_vf2pf_int(struct adf_accel_dev *accel_dev)
     92{
     93	bool irq_handled = false;
     94	unsigned long vf_mask;
     95
     96	/* Get the interrupt sources triggered by VFs, except for those already disabled */
     97	vf_mask = adf_disable_pending_vf2pf_interrupts(accel_dev);
     98	if (vf_mask) {
     99		struct adf_accel_vf_info *vf_info;
    100		int i;
    101
    102		/*
    103		 * Handle VF2PF interrupt unless the VF is malicious and
    104		 * is attempting to flood the host OS with VF2PF interrupts.
    105		 */
    106		for_each_set_bit(i, &vf_mask, ADF_MAX_NUM_VFS) {
    107			vf_info = accel_dev->pf.vf_info + i;
    108
    109			if (!__ratelimit(&vf_info->vf2pf_ratelimit)) {
    110				dev_info(&GET_DEV(accel_dev),
    111					 "Too many ints from VF%d\n",
    112					  vf_info->vf_nr);
    113				continue;
    114			}
    115
    116			adf_schedule_vf2pf_handler(vf_info);
    117			irq_handled = true;
    118		}
    119	}
    120	return irq_handled;
    121}
    122#endif /* CONFIG_PCI_IOV */
    123
    124static bool adf_handle_pm_int(struct adf_accel_dev *accel_dev)
    125{
    126	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
    127
    128	if (hw_data->handle_pm_interrupt &&
    129	    hw_data->handle_pm_interrupt(accel_dev))
    130		return true;
    131
    132	return false;
    133}
    134
    135static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr)
    136{
    137	struct adf_accel_dev *accel_dev = dev_ptr;
    138
    139#ifdef CONFIG_PCI_IOV
    140	/* If SR-IOV is enabled (vf_info is non-NULL), check for VF->PF ints */
    141	if (accel_dev->pf.vf_info && adf_handle_vf2pf_int(accel_dev))
    142		return IRQ_HANDLED;
    143#endif /* CONFIG_PCI_IOV */
    144
    145	if (adf_handle_pm_int(accel_dev))
    146		return IRQ_HANDLED;
    147
    148	dev_dbg(&GET_DEV(accel_dev), "qat_dev%d spurious AE interrupt\n",
    149		accel_dev->accel_id);
    150
    151	return IRQ_NONE;
    152}
    153
    154static void adf_free_irqs(struct adf_accel_dev *accel_dev)
    155{
    156	struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
    157	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
    158	struct adf_irq *irqs = pci_dev_info->msix_entries.irqs;
    159	struct adf_etr_data *etr_data = accel_dev->transport;
    160	int clust_irq = hw_data->num_banks;
    161	int irq, i = 0;
    162
    163	if (pci_dev_info->msix_entries.num_entries > 1) {
    164		for (i = 0; i < hw_data->num_banks; i++) {
    165			if (irqs[i].enabled) {
    166				irq = pci_irq_vector(pci_dev_info->pci_dev, i);
    167				irq_set_affinity_hint(irq, NULL);
    168				free_irq(irq, &etr_data->banks[i]);
    169			}
    170		}
    171	}
    172
    173	if (irqs[i].enabled) {
    174		irq = pci_irq_vector(pci_dev_info->pci_dev, clust_irq);
    175		free_irq(irq, accel_dev);
    176	}
    177}
    178
    179static int adf_request_irqs(struct adf_accel_dev *accel_dev)
    180{
    181	struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
    182	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
    183	struct adf_irq *irqs = pci_dev_info->msix_entries.irqs;
    184	struct adf_etr_data *etr_data = accel_dev->transport;
    185	int clust_irq = hw_data->num_banks;
    186	int ret, irq, i = 0;
    187	char *name;
    188
    189	/* Request msix irq for all banks unless SR-IOV enabled */
    190	if (!accel_dev->pf.vf_info) {
    191		for (i = 0; i < hw_data->num_banks; i++) {
    192			struct adf_etr_bank_data *bank = &etr_data->banks[i];
    193			unsigned int cpu, cpus = num_online_cpus();
    194
    195			name = irqs[i].name;
    196			snprintf(name, ADF_MAX_MSIX_VECTOR_NAME,
    197				 "qat%d-bundle%d", accel_dev->accel_id, i);
    198			irq = pci_irq_vector(pci_dev_info->pci_dev, i);
    199			if (unlikely(irq < 0)) {
    200				dev_err(&GET_DEV(accel_dev),
    201					"Failed to get IRQ number of device vector %d - %s\n",
    202					i, name);
    203				ret = irq;
    204				goto err;
    205			}
    206			ret = request_irq(irq, adf_msix_isr_bundle, 0,
    207					  &name[0], bank);
    208			if (ret) {
    209				dev_err(&GET_DEV(accel_dev),
    210					"Failed to allocate IRQ %d for %s\n",
    211					irq, name);
    212				goto err;
    213			}
    214
    215			cpu = ((accel_dev->accel_id * hw_data->num_banks) +
    216			       i) % cpus;
    217			irq_set_affinity_hint(irq, get_cpu_mask(cpu));
    218			irqs[i].enabled = true;
    219		}
    220	}
    221
    222	/* Request msix irq for AE */
    223	name = irqs[i].name;
    224	snprintf(name, ADF_MAX_MSIX_VECTOR_NAME,
    225		 "qat%d-ae-cluster", accel_dev->accel_id);
    226	irq = pci_irq_vector(pci_dev_info->pci_dev, clust_irq);
    227	if (unlikely(irq < 0)) {
    228		dev_err(&GET_DEV(accel_dev),
    229			"Failed to get IRQ number of device vector %d - %s\n",
    230			i, name);
    231		ret = irq;
    232		goto err;
    233	}
    234	ret = request_irq(irq, adf_msix_isr_ae, 0, &name[0], accel_dev);
    235	if (ret) {
    236		dev_err(&GET_DEV(accel_dev),
    237			"Failed to allocate IRQ %d for %s\n", irq, name);
    238		goto err;
    239	}
    240	irqs[i].enabled = true;
    241	return ret;
    242err:
    243	adf_free_irqs(accel_dev);
    244	return ret;
    245}
    246
    247static int adf_isr_alloc_msix_vectors_data(struct adf_accel_dev *accel_dev)
    248{
    249	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
    250	u32 msix_num_entries = 1;
    251	struct adf_irq *irqs;
    252
    253	/* If SR-IOV is disabled (vf_info is NULL), add entries for each bank */
    254	if (!accel_dev->pf.vf_info)
    255		msix_num_entries += hw_data->num_banks;
    256
    257	irqs = kzalloc_node(msix_num_entries * sizeof(*irqs),
    258			    GFP_KERNEL, dev_to_node(&GET_DEV(accel_dev)));
    259	if (!irqs)
    260		return -ENOMEM;
    261
    262	accel_dev->accel_pci_dev.msix_entries.num_entries = msix_num_entries;
    263	accel_dev->accel_pci_dev.msix_entries.irqs = irqs;
    264	return 0;
    265}
    266
    267static void adf_isr_free_msix_vectors_data(struct adf_accel_dev *accel_dev)
    268{
    269	kfree(accel_dev->accel_pci_dev.msix_entries.irqs);
    270	accel_dev->accel_pci_dev.msix_entries.irqs = NULL;
    271}
    272
    273static int adf_setup_bh(struct adf_accel_dev *accel_dev)
    274{
    275	struct adf_etr_data *priv_data = accel_dev->transport;
    276	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
    277	int i;
    278
    279	for (i = 0; i < hw_data->num_banks; i++)
    280		tasklet_init(&priv_data->banks[i].resp_handler,
    281			     adf_response_handler,
    282			     (unsigned long)&priv_data->banks[i]);
    283	return 0;
    284}
    285
    286static void adf_cleanup_bh(struct adf_accel_dev *accel_dev)
    287{
    288	struct adf_etr_data *priv_data = accel_dev->transport;
    289	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
    290	int i;
    291
    292	for (i = 0; i < hw_data->num_banks; i++) {
    293		tasklet_disable(&priv_data->banks[i].resp_handler);
    294		tasklet_kill(&priv_data->banks[i].resp_handler);
    295	}
    296}
    297
    298/**
    299 * adf_isr_resource_free() - Free IRQ for acceleration device
    300 * @accel_dev:  Pointer to acceleration device.
    301 *
    302 * Function frees interrupts for acceleration device.
    303 */
    304void adf_isr_resource_free(struct adf_accel_dev *accel_dev)
    305{
    306	adf_free_irqs(accel_dev);
    307	adf_cleanup_bh(accel_dev);
    308	adf_disable_msix(&accel_dev->accel_pci_dev);
    309	adf_isr_free_msix_vectors_data(accel_dev);
    310}
    311EXPORT_SYMBOL_GPL(adf_isr_resource_free);
    312
    313/**
    314 * adf_isr_resource_alloc() - Allocate IRQ for acceleration device
    315 * @accel_dev:  Pointer to acceleration device.
    316 *
    317 * Function allocates interrupts for acceleration device.
    318 *
    319 * Return: 0 on success, error code otherwise.
    320 */
    321int adf_isr_resource_alloc(struct adf_accel_dev *accel_dev)
    322{
    323	int ret;
    324
    325	ret = adf_isr_alloc_msix_vectors_data(accel_dev);
    326	if (ret)
    327		goto err_out;
    328
    329	ret = adf_enable_msix(accel_dev);
    330	if (ret)
    331		goto err_free_msix_table;
    332
    333	ret = adf_setup_bh(accel_dev);
    334	if (ret)
    335		goto err_disable_msix;
    336
    337	ret = adf_request_irqs(accel_dev);
    338	if (ret)
    339		goto err_cleanup_bh;
    340
    341	return 0;
    342
    343err_cleanup_bh:
    344	adf_cleanup_bh(accel_dev);
    345
    346err_disable_msix:
    347	adf_disable_msix(&accel_dev->accel_pci_dev);
    348
    349err_free_msix_table:
    350	adf_isr_free_msix_vectors_data(accel_dev);
    351
    352err_out:
    353	return ret;
    354}
    355EXPORT_SYMBOL_GPL(adf_isr_resource_alloc);
    356
    357/**
    358 * adf_init_misc_wq() - Init misc workqueue
    359 *
    360 * Function init workqueue 'qat_misc_wq' for general purpose.
    361 *
    362 * Return: 0 on success, error code otherwise.
    363 */
    364int __init adf_init_misc_wq(void)
    365{
    366	adf_misc_wq = alloc_workqueue("qat_misc_wq", WQ_MEM_RECLAIM, 0);
    367
    368	return !adf_misc_wq ? -ENOMEM : 0;
    369}
    370
    371void adf_exit_misc_wq(void)
    372{
    373	if (adf_misc_wq)
    374		destroy_workqueue(adf_misc_wq);
    375
    376	adf_misc_wq = NULL;
    377}
    378
    379bool adf_misc_wq_queue_work(struct work_struct *work)
    380{
    381	return queue_work(adf_misc_wq, work);
    382}