1d9110b0bSSrujanaChalla // SPDX-License-Identifier: GPL-2.0
2d9110b0bSSrujanaChalla /* Marvell OcteonTX CPT driver
3d9110b0bSSrujanaChalla *
4d9110b0bSSrujanaChalla * Copyright (C) 2019 Marvell International Ltd.
5d9110b0bSSrujanaChalla *
6d9110b0bSSrujanaChalla * This program is free software; you can redistribute it and/or modify
7d9110b0bSSrujanaChalla * it under the terms of the GNU General Public License version 2 as
8d9110b0bSSrujanaChalla * published by the Free Software Foundation.
9d9110b0bSSrujanaChalla */
10d9110b0bSSrujanaChalla
11d9110b0bSSrujanaChalla #include "otx_cpt_common.h"
12d9110b0bSSrujanaChalla #include "otx_cptpf.h"
13d9110b0bSSrujanaChalla
get_mbox_opcode_str(int msg_opcode)14d9110b0bSSrujanaChalla static char *get_mbox_opcode_str(int msg_opcode)
15d9110b0bSSrujanaChalla {
16d9110b0bSSrujanaChalla char *str = "Unknown";
17d9110b0bSSrujanaChalla
18d9110b0bSSrujanaChalla switch (msg_opcode) {
19d9110b0bSSrujanaChalla case OTX_CPT_MSG_VF_UP:
20d9110b0bSSrujanaChalla str = "UP";
21d9110b0bSSrujanaChalla break;
22d9110b0bSSrujanaChalla
23d9110b0bSSrujanaChalla case OTX_CPT_MSG_VF_DOWN:
24d9110b0bSSrujanaChalla str = "DOWN";
25d9110b0bSSrujanaChalla break;
26d9110b0bSSrujanaChalla
27d9110b0bSSrujanaChalla case OTX_CPT_MSG_READY:
28d9110b0bSSrujanaChalla str = "READY";
29d9110b0bSSrujanaChalla break;
30d9110b0bSSrujanaChalla
31d9110b0bSSrujanaChalla case OTX_CPT_MSG_QLEN:
32d9110b0bSSrujanaChalla str = "QLEN";
33d9110b0bSSrujanaChalla break;
34d9110b0bSSrujanaChalla
35d9110b0bSSrujanaChalla case OTX_CPT_MSG_QBIND_GRP:
36d9110b0bSSrujanaChalla str = "QBIND_GRP";
37d9110b0bSSrujanaChalla break;
38d9110b0bSSrujanaChalla
39d9110b0bSSrujanaChalla case OTX_CPT_MSG_VQ_PRIORITY:
40d9110b0bSSrujanaChalla str = "VQ_PRIORITY";
41d9110b0bSSrujanaChalla break;
42d9110b0bSSrujanaChalla
43d9110b0bSSrujanaChalla case OTX_CPT_MSG_PF_TYPE:
44d9110b0bSSrujanaChalla str = "PF_TYPE";
45d9110b0bSSrujanaChalla break;
46d9110b0bSSrujanaChalla
47d9110b0bSSrujanaChalla case OTX_CPT_MSG_ACK:
48d9110b0bSSrujanaChalla str = "ACK";
49d9110b0bSSrujanaChalla break;
50d9110b0bSSrujanaChalla
51d9110b0bSSrujanaChalla case OTX_CPT_MSG_NACK:
52d9110b0bSSrujanaChalla str = "NACK";
53d9110b0bSSrujanaChalla break;
54d9110b0bSSrujanaChalla }
55d9110b0bSSrujanaChalla
56d9110b0bSSrujanaChalla return str;
57d9110b0bSSrujanaChalla }
58d9110b0bSSrujanaChalla
dump_mbox_msg(struct otx_cpt_mbox * mbox_msg,int vf_id)59d9110b0bSSrujanaChalla static void dump_mbox_msg(struct otx_cpt_mbox *mbox_msg, int vf_id)
60d9110b0bSSrujanaChalla {
61d9110b0bSSrujanaChalla char raw_data_str[OTX_CPT_MAX_MBOX_DATA_STR_SIZE];
62d9110b0bSSrujanaChalla
63d9110b0bSSrujanaChalla hex_dump_to_buffer(mbox_msg, sizeof(struct otx_cpt_mbox), 16, 8,
64d9110b0bSSrujanaChalla raw_data_str, OTX_CPT_MAX_MBOX_DATA_STR_SIZE, false);
65d9110b0bSSrujanaChalla if (vf_id >= 0)
66*0a8f5989SChristophe JAILLET pr_debug("MBOX opcode %s received from VF%d raw_data %s\n",
67d9110b0bSSrujanaChalla get_mbox_opcode_str(mbox_msg->msg), vf_id,
68d9110b0bSSrujanaChalla raw_data_str);
69d9110b0bSSrujanaChalla else
70*0a8f5989SChristophe JAILLET pr_debug("MBOX opcode %s received from PF raw_data %s\n",
71d9110b0bSSrujanaChalla get_mbox_opcode_str(mbox_msg->msg), raw_data_str);
72d9110b0bSSrujanaChalla }
73d9110b0bSSrujanaChalla
otx_cpt_send_msg_to_vf(struct otx_cpt_device * cpt,int vf,struct otx_cpt_mbox * mbx)74d9110b0bSSrujanaChalla static void otx_cpt_send_msg_to_vf(struct otx_cpt_device *cpt, int vf,
75d9110b0bSSrujanaChalla struct otx_cpt_mbox *mbx)
76d9110b0bSSrujanaChalla {
77d9110b0bSSrujanaChalla /* Writing mbox(0) causes interrupt */
78d9110b0bSSrujanaChalla writeq(mbx->data, cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 1));
79d9110b0bSSrujanaChalla writeq(mbx->msg, cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 0));
80d9110b0bSSrujanaChalla }
81d9110b0bSSrujanaChalla
82d9110b0bSSrujanaChalla /*
83d9110b0bSSrujanaChalla * ACKs VF's mailbox message
84d9110b0bSSrujanaChalla * @vf: VF to which ACK to be sent
85d9110b0bSSrujanaChalla */
otx_cpt_mbox_send_ack(struct otx_cpt_device * cpt,int vf,struct otx_cpt_mbox * mbx)86d9110b0bSSrujanaChalla static void otx_cpt_mbox_send_ack(struct otx_cpt_device *cpt, int vf,
87d9110b0bSSrujanaChalla struct otx_cpt_mbox *mbx)
88d9110b0bSSrujanaChalla {
89d9110b0bSSrujanaChalla mbx->data = 0ull;
90d9110b0bSSrujanaChalla mbx->msg = OTX_CPT_MSG_ACK;
91d9110b0bSSrujanaChalla otx_cpt_send_msg_to_vf(cpt, vf, mbx);
92d9110b0bSSrujanaChalla }
93d9110b0bSSrujanaChalla
94d9110b0bSSrujanaChalla /* NACKs VF's mailbox message that PF is not able to complete the action */
otx_cptpf_mbox_send_nack(struct otx_cpt_device * cpt,int vf,struct otx_cpt_mbox * mbx)95d9110b0bSSrujanaChalla static void otx_cptpf_mbox_send_nack(struct otx_cpt_device *cpt, int vf,
96d9110b0bSSrujanaChalla struct otx_cpt_mbox *mbx)
97d9110b0bSSrujanaChalla {
98d9110b0bSSrujanaChalla mbx->data = 0ull;
99d9110b0bSSrujanaChalla mbx->msg = OTX_CPT_MSG_NACK;
100d9110b0bSSrujanaChalla otx_cpt_send_msg_to_vf(cpt, vf, mbx);
101d9110b0bSSrujanaChalla }
102d9110b0bSSrujanaChalla
otx_cpt_clear_mbox_intr(struct otx_cpt_device * cpt,u32 vf)103d9110b0bSSrujanaChalla static void otx_cpt_clear_mbox_intr(struct otx_cpt_device *cpt, u32 vf)
104d9110b0bSSrujanaChalla {
105d9110b0bSSrujanaChalla /* W1C for the VF */
106d9110b0bSSrujanaChalla writeq(1ull << vf, cpt->reg_base + OTX_CPT_PF_MBOX_INTX(0));
107d9110b0bSSrujanaChalla }
108d9110b0bSSrujanaChalla
109d9110b0bSSrujanaChalla /*
110d9110b0bSSrujanaChalla * Configure QLEN/Chunk sizes for VF
111d9110b0bSSrujanaChalla */
otx_cpt_cfg_qlen_for_vf(struct otx_cpt_device * cpt,int vf,u32 size)112d9110b0bSSrujanaChalla static void otx_cpt_cfg_qlen_for_vf(struct otx_cpt_device *cpt, int vf,
113d9110b0bSSrujanaChalla u32 size)
114d9110b0bSSrujanaChalla {
115d9110b0bSSrujanaChalla union otx_cptx_pf_qx_ctl pf_qx_ctl;
116d9110b0bSSrujanaChalla
117d9110b0bSSrujanaChalla pf_qx_ctl.u = readq(cpt->reg_base + OTX_CPT_PF_QX_CTL(vf));
118d9110b0bSSrujanaChalla pf_qx_ctl.s.size = size;
119d9110b0bSSrujanaChalla pf_qx_ctl.s.cont_err = true;
120d9110b0bSSrujanaChalla writeq(pf_qx_ctl.u, cpt->reg_base + OTX_CPT_PF_QX_CTL(vf));
121d9110b0bSSrujanaChalla }
122d9110b0bSSrujanaChalla
123d9110b0bSSrujanaChalla /*
124d9110b0bSSrujanaChalla * Configure VQ priority
125d9110b0bSSrujanaChalla */
otx_cpt_cfg_vq_priority(struct otx_cpt_device * cpt,int vf,u32 pri)126d9110b0bSSrujanaChalla static void otx_cpt_cfg_vq_priority(struct otx_cpt_device *cpt, int vf, u32 pri)
127d9110b0bSSrujanaChalla {
128d9110b0bSSrujanaChalla union otx_cptx_pf_qx_ctl pf_qx_ctl;
129d9110b0bSSrujanaChalla
130d9110b0bSSrujanaChalla pf_qx_ctl.u = readq(cpt->reg_base + OTX_CPT_PF_QX_CTL(vf));
131d9110b0bSSrujanaChalla pf_qx_ctl.s.pri = pri;
132d9110b0bSSrujanaChalla writeq(pf_qx_ctl.u, cpt->reg_base + OTX_CPT_PF_QX_CTL(vf));
133d9110b0bSSrujanaChalla }
134d9110b0bSSrujanaChalla
otx_cpt_bind_vq_to_grp(struct otx_cpt_device * cpt,u8 q,u8 grp)135d9110b0bSSrujanaChalla static int otx_cpt_bind_vq_to_grp(struct otx_cpt_device *cpt, u8 q, u8 grp)
136d9110b0bSSrujanaChalla {
137d9110b0bSSrujanaChalla struct device *dev = &cpt->pdev->dev;
138d9110b0bSSrujanaChalla struct otx_cpt_eng_grp_info *eng_grp;
139d9110b0bSSrujanaChalla union otx_cptx_pf_qx_ctl pf_qx_ctl;
140d9110b0bSSrujanaChalla struct otx_cpt_ucode *ucode;
141d9110b0bSSrujanaChalla
142d9110b0bSSrujanaChalla if (q >= cpt->max_vfs) {
143*0a8f5989SChristophe JAILLET dev_err(dev, "Requested queue %d is > than maximum avail %d\n",
144d9110b0bSSrujanaChalla q, cpt->max_vfs);
145d9110b0bSSrujanaChalla return -EINVAL;
146d9110b0bSSrujanaChalla }
147d9110b0bSSrujanaChalla
148d9110b0bSSrujanaChalla if (grp >= OTX_CPT_MAX_ENGINE_GROUPS) {
149*0a8f5989SChristophe JAILLET dev_err(dev, "Requested group %d is > than maximum avail %d\n",
150d9110b0bSSrujanaChalla grp, OTX_CPT_MAX_ENGINE_GROUPS);
151d9110b0bSSrujanaChalla return -EINVAL;
152d9110b0bSSrujanaChalla }
153d9110b0bSSrujanaChalla
154d9110b0bSSrujanaChalla eng_grp = &cpt->eng_grps.grp[grp];
155d9110b0bSSrujanaChalla if (!eng_grp->is_enabled) {
156*0a8f5989SChristophe JAILLET dev_err(dev, "Requested engine group %d is disabled\n", grp);
157d9110b0bSSrujanaChalla return -EINVAL;
158d9110b0bSSrujanaChalla }
159d9110b0bSSrujanaChalla
160d9110b0bSSrujanaChalla pf_qx_ctl.u = readq(cpt->reg_base + OTX_CPT_PF_QX_CTL(q));
161d9110b0bSSrujanaChalla pf_qx_ctl.s.grp = grp;
162d9110b0bSSrujanaChalla writeq(pf_qx_ctl.u, cpt->reg_base + OTX_CPT_PF_QX_CTL(q));
163d9110b0bSSrujanaChalla
164d9110b0bSSrujanaChalla if (eng_grp->mirror.is_ena)
165d9110b0bSSrujanaChalla ucode = &eng_grp->g->grp[eng_grp->mirror.idx].ucode[0];
166d9110b0bSSrujanaChalla else
167d9110b0bSSrujanaChalla ucode = &eng_grp->ucode[0];
168d9110b0bSSrujanaChalla
169d9110b0bSSrujanaChalla if (otx_cpt_uc_supports_eng_type(ucode, OTX_CPT_SE_TYPES))
170d9110b0bSSrujanaChalla return OTX_CPT_SE_TYPES;
171d9110b0bSSrujanaChalla else if (otx_cpt_uc_supports_eng_type(ucode, OTX_CPT_AE_TYPES))
172d9110b0bSSrujanaChalla return OTX_CPT_AE_TYPES;
173d9110b0bSSrujanaChalla else
174d9110b0bSSrujanaChalla return BAD_OTX_CPTVF_TYPE;
175d9110b0bSSrujanaChalla }
176d9110b0bSSrujanaChalla
177d9110b0bSSrujanaChalla /* Interrupt handler to handle mailbox messages from VFs */
otx_cpt_handle_mbox_intr(struct otx_cpt_device * cpt,int vf)178d9110b0bSSrujanaChalla static void otx_cpt_handle_mbox_intr(struct otx_cpt_device *cpt, int vf)
179d9110b0bSSrujanaChalla {
180d9110b0bSSrujanaChalla int vftype = 0;
181d9110b0bSSrujanaChalla struct otx_cpt_mbox mbx = {};
182d9110b0bSSrujanaChalla struct device *dev = &cpt->pdev->dev;
183d9110b0bSSrujanaChalla /*
184d9110b0bSSrujanaChalla * MBOX[0] contains msg
185d9110b0bSSrujanaChalla * MBOX[1] contains data
186d9110b0bSSrujanaChalla */
187d9110b0bSSrujanaChalla mbx.msg = readq(cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 0));
188d9110b0bSSrujanaChalla mbx.data = readq(cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 1));
189d9110b0bSSrujanaChalla
190d9110b0bSSrujanaChalla dump_mbox_msg(&mbx, vf);
191d9110b0bSSrujanaChalla
192d9110b0bSSrujanaChalla switch (mbx.msg) {
193d9110b0bSSrujanaChalla case OTX_CPT_MSG_VF_UP:
194d9110b0bSSrujanaChalla mbx.msg = OTX_CPT_MSG_VF_UP;
195d9110b0bSSrujanaChalla mbx.data = cpt->vfs_enabled;
196d9110b0bSSrujanaChalla otx_cpt_send_msg_to_vf(cpt, vf, &mbx);
197d9110b0bSSrujanaChalla break;
198d9110b0bSSrujanaChalla case OTX_CPT_MSG_READY:
199d9110b0bSSrujanaChalla mbx.msg = OTX_CPT_MSG_READY;
200d9110b0bSSrujanaChalla mbx.data = vf;
201d9110b0bSSrujanaChalla otx_cpt_send_msg_to_vf(cpt, vf, &mbx);
202d9110b0bSSrujanaChalla break;
203d9110b0bSSrujanaChalla case OTX_CPT_MSG_VF_DOWN:
204d9110b0bSSrujanaChalla /* First msg in VF teardown sequence */
205d9110b0bSSrujanaChalla otx_cpt_mbox_send_ack(cpt, vf, &mbx);
206d9110b0bSSrujanaChalla break;
207d9110b0bSSrujanaChalla case OTX_CPT_MSG_QLEN:
208d9110b0bSSrujanaChalla otx_cpt_cfg_qlen_for_vf(cpt, vf, mbx.data);
209d9110b0bSSrujanaChalla otx_cpt_mbox_send_ack(cpt, vf, &mbx);
210d9110b0bSSrujanaChalla break;
211d9110b0bSSrujanaChalla case OTX_CPT_MSG_QBIND_GRP:
212d9110b0bSSrujanaChalla vftype = otx_cpt_bind_vq_to_grp(cpt, vf, (u8)mbx.data);
213d9110b0bSSrujanaChalla if ((vftype != OTX_CPT_AE_TYPES) &&
214d9110b0bSSrujanaChalla (vftype != OTX_CPT_SE_TYPES)) {
215*0a8f5989SChristophe JAILLET dev_err(dev, "VF%d binding to eng group %llu failed\n",
216d9110b0bSSrujanaChalla vf, mbx.data);
217d9110b0bSSrujanaChalla otx_cptpf_mbox_send_nack(cpt, vf, &mbx);
218d9110b0bSSrujanaChalla } else {
219d9110b0bSSrujanaChalla mbx.msg = OTX_CPT_MSG_QBIND_GRP;
220d9110b0bSSrujanaChalla mbx.data = vftype;
221d9110b0bSSrujanaChalla otx_cpt_send_msg_to_vf(cpt, vf, &mbx);
222d9110b0bSSrujanaChalla }
223d9110b0bSSrujanaChalla break;
224d9110b0bSSrujanaChalla case OTX_CPT_MSG_PF_TYPE:
225d9110b0bSSrujanaChalla mbx.msg = OTX_CPT_MSG_PF_TYPE;
226d9110b0bSSrujanaChalla mbx.data = cpt->pf_type;
227d9110b0bSSrujanaChalla otx_cpt_send_msg_to_vf(cpt, vf, &mbx);
228d9110b0bSSrujanaChalla break;
229d9110b0bSSrujanaChalla case OTX_CPT_MSG_VQ_PRIORITY:
230d9110b0bSSrujanaChalla otx_cpt_cfg_vq_priority(cpt, vf, mbx.data);
231d9110b0bSSrujanaChalla otx_cpt_mbox_send_ack(cpt, vf, &mbx);
232d9110b0bSSrujanaChalla break;
233d9110b0bSSrujanaChalla default:
234d9110b0bSSrujanaChalla dev_err(&cpt->pdev->dev, "Invalid msg from VF%d, msg 0x%llx\n",
235d9110b0bSSrujanaChalla vf, mbx.msg);
236d9110b0bSSrujanaChalla break;
237d9110b0bSSrujanaChalla }
238d9110b0bSSrujanaChalla }
239d9110b0bSSrujanaChalla
otx_cpt_mbox_intr_handler(struct otx_cpt_device * cpt,int mbx)240d9110b0bSSrujanaChalla void otx_cpt_mbox_intr_handler (struct otx_cpt_device *cpt, int mbx)
241d9110b0bSSrujanaChalla {
242d9110b0bSSrujanaChalla u64 intr;
243d9110b0bSSrujanaChalla u8 vf;
244d9110b0bSSrujanaChalla
245d9110b0bSSrujanaChalla intr = readq(cpt->reg_base + OTX_CPT_PF_MBOX_INTX(0));
246d9110b0bSSrujanaChalla pr_debug("PF interrupt mbox%d mask 0x%llx\n", mbx, intr);
247d9110b0bSSrujanaChalla for (vf = 0; vf < cpt->max_vfs; vf++) {
248d9110b0bSSrujanaChalla if (intr & (1ULL << vf)) {
249d9110b0bSSrujanaChalla otx_cpt_handle_mbox_intr(cpt, vf);
250d9110b0bSSrujanaChalla otx_cpt_clear_mbox_intr(cpt, vf);
251d9110b0bSSrujanaChalla }
252d9110b0bSSrujanaChalla }
253d9110b0bSSrujanaChalla }
254