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_gen4_pfvf.c (4629B)


      1// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
      2/* Copyright(c) 2021 Intel Corporation */
      3#include <linux/iopoll.h>
      4#include <linux/mutex.h>
      5#include <linux/types.h>
      6#include "adf_accel_devices.h"
      7#include "adf_common_drv.h"
      8#include "adf_gen4_pfvf.h"
      9#include "adf_pfvf_pf_proto.h"
     10#include "adf_pfvf_utils.h"
     11
     12#define ADF_4XXX_PF2VM_OFFSET(i)	(0x40B010 + ((i) * 0x20))
     13#define ADF_4XXX_VM2PF_OFFSET(i)	(0x40B014 + ((i) * 0x20))
     14
     15/* VF2PF interrupt source registers */
     16#define ADF_4XXX_VM2PF_SOU		0x41A180
     17#define ADF_4XXX_VM2PF_MSK		0x41A1C0
     18#define ADF_GEN4_VF_MSK			0xFFFF
     19
     20#define ADF_PFVF_GEN4_MSGTYPE_SHIFT	2
     21#define ADF_PFVF_GEN4_MSGTYPE_MASK	0x3F
     22#define ADF_PFVF_GEN4_MSGDATA_SHIFT	8
     23#define ADF_PFVF_GEN4_MSGDATA_MASK	0xFFFFFF
     24
     25static const struct pfvf_csr_format csr_gen4_fmt = {
     26	{ ADF_PFVF_GEN4_MSGTYPE_SHIFT, ADF_PFVF_GEN4_MSGTYPE_MASK },
     27	{ ADF_PFVF_GEN4_MSGDATA_SHIFT, ADF_PFVF_GEN4_MSGDATA_MASK },
     28};
     29
     30static u32 adf_gen4_pf_get_pf2vf_offset(u32 i)
     31{
     32	return ADF_4XXX_PF2VM_OFFSET(i);
     33}
     34
     35static u32 adf_gen4_pf_get_vf2pf_offset(u32 i)
     36{
     37	return ADF_4XXX_VM2PF_OFFSET(i);
     38}
     39
     40static void adf_gen4_enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask)
     41{
     42	u32 val;
     43
     44	val = ADF_CSR_RD(pmisc_addr, ADF_4XXX_VM2PF_MSK) & ~vf_mask;
     45	ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, val);
     46}
     47
     48static void adf_gen4_disable_all_vf2pf_interrupts(void __iomem *pmisc_addr)
     49{
     50	ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, ADF_GEN4_VF_MSK);
     51}
     52
     53static u32 adf_gen4_disable_pending_vf2pf_interrupts(void __iomem *pmisc_addr)
     54{
     55	u32 sources, disabled, pending;
     56
     57	/* Get the interrupt sources triggered by VFs */
     58	sources = ADF_CSR_RD(pmisc_addr, ADF_4XXX_VM2PF_SOU);
     59	if (!sources)
     60		return 0;
     61
     62	/* Get the already disabled interrupts */
     63	disabled = ADF_CSR_RD(pmisc_addr, ADF_4XXX_VM2PF_MSK);
     64
     65	pending = sources & ~disabled;
     66	if (!pending)
     67		return 0;
     68
     69	/* Due to HW limitations, when disabling the interrupts, we can't
     70	 * just disable the requested sources, as this would lead to missed
     71	 * interrupts if VM2PF_SOU changes just before writing to VM2PF_MSK.
     72	 * To work around it, disable all and re-enable only the sources that
     73	 * are not in vf_mask and were not already disabled. Re-enabling will
     74	 * trigger a new interrupt for the sources that have changed in the
     75	 * meantime, if any.
     76	 */
     77	ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, ADF_GEN4_VF_MSK);
     78	ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, disabled | sources);
     79
     80	/* Return the sources of the (new) interrupt(s) */
     81	return pending;
     82}
     83
     84static int adf_gen4_pfvf_send(struct adf_accel_dev *accel_dev,
     85			      struct pfvf_message msg, u32 pfvf_offset,
     86			      struct mutex *csr_lock)
     87{
     88	void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);
     89	u32 csr_val;
     90	int ret;
     91
     92	csr_val = adf_pfvf_csr_msg_of(accel_dev, msg, &csr_gen4_fmt);
     93	if (unlikely(!csr_val))
     94		return -EINVAL;
     95
     96	mutex_lock(csr_lock);
     97
     98	ADF_CSR_WR(pmisc_addr, pfvf_offset, csr_val | ADF_PFVF_INT);
     99
    100	/* Wait for confirmation from remote that it received the message */
    101	ret = read_poll_timeout(ADF_CSR_RD, csr_val, !(csr_val & ADF_PFVF_INT),
    102				ADF_PFVF_MSG_ACK_DELAY_US,
    103				ADF_PFVF_MSG_ACK_MAX_DELAY_US,
    104				true, pmisc_addr, pfvf_offset);
    105	if (ret < 0)
    106		dev_dbg(&GET_DEV(accel_dev), "ACK not received from remote\n");
    107
    108	mutex_unlock(csr_lock);
    109	return ret;
    110}
    111
    112static struct pfvf_message adf_gen4_pfvf_recv(struct adf_accel_dev *accel_dev,
    113					      u32 pfvf_offset, u8 compat_ver)
    114{
    115	void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);
    116	struct pfvf_message msg = { 0 };
    117	u32 csr_val;
    118
    119	/* Read message from the CSR */
    120	csr_val = ADF_CSR_RD(pmisc_addr, pfvf_offset);
    121	if (!(csr_val & ADF_PFVF_INT)) {
    122		dev_info(&GET_DEV(accel_dev),
    123			 "Spurious PFVF interrupt, msg 0x%.8x. Ignored\n", csr_val);
    124		return msg;
    125	}
    126
    127	/* We can now acknowledge the message reception by clearing the
    128	 * interrupt bit
    129	 */
    130	ADF_CSR_WR(pmisc_addr, pfvf_offset, csr_val & ~ADF_PFVF_INT);
    131
    132	/* Return the pfvf_message format */
    133	return adf_pfvf_message_of(accel_dev, csr_val, &csr_gen4_fmt);
    134}
    135
    136void adf_gen4_init_pf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops)
    137{
    138	pfvf_ops->enable_comms = adf_enable_pf2vf_comms;
    139	pfvf_ops->get_pf2vf_offset = adf_gen4_pf_get_pf2vf_offset;
    140	pfvf_ops->get_vf2pf_offset = adf_gen4_pf_get_vf2pf_offset;
    141	pfvf_ops->enable_vf2pf_interrupts = adf_gen4_enable_vf2pf_interrupts;
    142	pfvf_ops->disable_all_vf2pf_interrupts = adf_gen4_disable_all_vf2pf_interrupts;
    143	pfvf_ops->disable_pending_vf2pf_interrupts = adf_gen4_disable_pending_vf2pf_interrupts;
    144	pfvf_ops->send_msg = adf_gen4_pfvf_send;
    145	pfvf_ops->recv_msg = adf_gen4_pfvf_recv;
    146}
    147EXPORT_SYMBOL_GPL(adf_gen4_init_pf_pfvf_ops);