Linux Audio

Check our new training course

Loading...
v6.8
  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);
v6.13.7
  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		0x41A180
 15#define ADF_4XXX_VM2PF_MSK		0x41A1C0
 16#define ADF_GEN4_VF_MSK			0xFFFF
 17
 18#define ADF_PFVF_GEN4_MSGTYPE_SHIFT	2
 19#define ADF_PFVF_GEN4_MSGTYPE_MASK	0x3F
 20#define ADF_PFVF_GEN4_MSGDATA_SHIFT	8
 21#define ADF_PFVF_GEN4_MSGDATA_MASK	0xFFFFFF
 22
 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't
 68	 * just disable the requested sources, as this would lead to missed
 69	 * interrupts if VM2PF_SOU changes just before writing to VM2PF_MSK.
 70	 * To work around it, disable all and re-enable only the sources that
 71	 * are not in vf_mask and were not already disabled. Re-enabling will
 72	 * trigger a new interrupt for the sources that have changed in the
 73	 * 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 the
126	 * interrupt bit
127	 */
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);