brintos

brintos / linux-shallow public Read only

0
0
Text · 4.4 KiB · 21474d4 Raw
146 lines · c
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_gen4_hw_data.h"10#include "adf_pfvf_pf_proto.h"11#include "adf_pfvf_utils.h"12 13/* VF2PF interrupt source registers */14#define ADF_4XXX_VM2PF_SOU		0x41A18015#define ADF_4XXX_VM2PF_MSK		0x41A1C016#define ADF_GEN4_VF_MSK			0xFFFF17 18#define ADF_PFVF_GEN4_MSGTYPE_SHIFT	219#define ADF_PFVF_GEN4_MSGTYPE_MASK	0x3F20#define ADF_PFVF_GEN4_MSGDATA_SHIFT	821#define ADF_PFVF_GEN4_MSGDATA_MASK	0xFFFFFF22 23static const struct pfvf_csr_format csr_gen4_fmt = {24	{ ADF_PFVF_GEN4_MSGTYPE_SHIFT, ADF_PFVF_GEN4_MSGTYPE_MASK },25	{ ADF_PFVF_GEN4_MSGDATA_SHIFT, ADF_PFVF_GEN4_MSGDATA_MASK },26};27 28static u32 adf_gen4_pf_get_pf2vf_offset(u32 i)29{30	return ADF_GEN4_PF2VM_OFFSET(i);31}32 33static u32 adf_gen4_pf_get_vf2pf_offset(u32 i)34{35	return ADF_GEN4_VM2PF_OFFSET(i);36}37 38static void adf_gen4_enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask)39{40	u32 val;41 42	val = ADF_CSR_RD(pmisc_addr, ADF_4XXX_VM2PF_MSK) & ~vf_mask;43	ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, val);44}45 46static void adf_gen4_disable_all_vf2pf_interrupts(void __iomem *pmisc_addr)47{48	ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, ADF_GEN4_VF_MSK);49}50 51static u32 adf_gen4_disable_pending_vf2pf_interrupts(void __iomem *pmisc_addr)52{53	u32 sources, disabled, pending;54 55	/* Get the interrupt sources triggered by VFs */56	sources = ADF_CSR_RD(pmisc_addr, ADF_4XXX_VM2PF_SOU);57	if (!sources)58		return 0;59 60	/* Get the already disabled interrupts */61	disabled = ADF_CSR_RD(pmisc_addr, ADF_4XXX_VM2PF_MSK);62 63	pending = sources & ~disabled;64	if (!pending)65		return 0;66 67	/* Due to HW limitations, when disabling the interrupts, we can't68	 * just disable the requested sources, as this would lead to missed69	 * interrupts if VM2PF_SOU changes just before writing to VM2PF_MSK.70	 * To work around it, disable all and re-enable only the sources that71	 * are not in vf_mask and were not already disabled. Re-enabling will72	 * trigger a new interrupt for the sources that have changed in the73	 * meantime, if any.74	 */75	ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, ADF_GEN4_VF_MSK);76	ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, disabled | sources);77 78	/* Return the sources of the (new) interrupt(s) */79	return pending;80}81 82static int adf_gen4_pfvf_send(struct adf_accel_dev *accel_dev,83			      struct pfvf_message msg, u32 pfvf_offset,84			      struct mutex *csr_lock)85{86	void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);87	u32 csr_val;88	int ret;89 90	csr_val = adf_pfvf_csr_msg_of(accel_dev, msg, &csr_gen4_fmt);91	if (unlikely(!csr_val))92		return -EINVAL;93 94	mutex_lock(csr_lock);95 96	ADF_CSR_WR(pmisc_addr, pfvf_offset, csr_val | ADF_PFVF_INT);97 98	/* Wait for confirmation from remote that it received the message */99	ret = read_poll_timeout(ADF_CSR_RD, csr_val, !(csr_val & ADF_PFVF_INT),100				ADF_PFVF_MSG_ACK_DELAY_US,101				ADF_PFVF_MSG_ACK_MAX_DELAY_US,102				true, pmisc_addr, pfvf_offset);103	if (ret < 0)104		dev_dbg(&GET_DEV(accel_dev), "ACK not received from remote\n");105 106	mutex_unlock(csr_lock);107	return ret;108}109 110static struct pfvf_message adf_gen4_pfvf_recv(struct adf_accel_dev *accel_dev,111					      u32 pfvf_offset, u8 compat_ver)112{113	void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);114	struct pfvf_message msg = { 0 };115	u32 csr_val;116 117	/* Read message from the CSR */118	csr_val = ADF_CSR_RD(pmisc_addr, pfvf_offset);119	if (!(csr_val & ADF_PFVF_INT)) {120		dev_info(&GET_DEV(accel_dev),121			 "Spurious PFVF interrupt, msg 0x%.8x. Ignored\n", csr_val);122		return msg;123	}124 125	/* We can now acknowledge the message reception by clearing the126	 * interrupt bit127	 */128	ADF_CSR_WR(pmisc_addr, pfvf_offset, csr_val & ~ADF_PFVF_INT);129 130	/* Return the pfvf_message format */131	return adf_pfvf_message_of(accel_dev, csr_val, &csr_gen4_fmt);132}133 134void adf_gen4_init_pf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops)135{136	pfvf_ops->enable_comms = adf_enable_pf2vf_comms;137	pfvf_ops->get_pf2vf_offset = adf_gen4_pf_get_pf2vf_offset;138	pfvf_ops->get_vf2pf_offset = adf_gen4_pf_get_vf2pf_offset;139	pfvf_ops->enable_vf2pf_interrupts = adf_gen4_enable_vf2pf_interrupts;140	pfvf_ops->disable_all_vf2pf_interrupts = adf_gen4_disable_all_vf2pf_interrupts;141	pfvf_ops->disable_pending_vf2pf_interrupts = adf_gen4_disable_pending_vf2pf_interrupts;142	pfvf_ops->send_msg = adf_gen4_pfvf_send;143	pfvf_ops->recv_msg = adf_gen4_pfvf_recv;144}145EXPORT_SYMBOL_GPL(adf_gen4_init_pf_pfvf_ops);146