1 // SPDX-License-Identifier: GPL-2.0
2 /* Marvell OcteonTX CPT driver
4 * Copyright (C) 2019 Marvell International Ltd.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 #include <linux/delay.h>
12 #include "otx_cptvf.h"
14 #define CPT_MBOX_MSG_TIMEOUT 2000
16 static char *get_mbox_opcode_str(int msg_opcode
)
18 char *str
= "Unknown";
21 case OTX_CPT_MSG_VF_UP
:
25 case OTX_CPT_MSG_VF_DOWN
:
29 case OTX_CPT_MSG_READY
:
33 case OTX_CPT_MSG_QLEN
:
37 case OTX_CPT_MSG_QBIND_GRP
:
41 case OTX_CPT_MSG_VQ_PRIORITY
:
45 case OTX_CPT_MSG_PF_TYPE
:
53 case OTX_CPT_MSG_NACK
:
60 static void dump_mbox_msg(struct otx_cpt_mbox
*mbox_msg
, int vf_id
)
62 char raw_data_str
[OTX_CPT_MAX_MBOX_DATA_STR_SIZE
];
64 hex_dump_to_buffer(mbox_msg
, sizeof(struct otx_cpt_mbox
), 16, 8,
65 raw_data_str
, OTX_CPT_MAX_MBOX_DATA_STR_SIZE
, false);
67 pr_debug("MBOX msg %s received from VF%d raw_data %s",
68 get_mbox_opcode_str(mbox_msg
->msg
), vf_id
,
71 pr_debug("MBOX msg %s received from PF raw_data %s",
72 get_mbox_opcode_str(mbox_msg
->msg
), raw_data_str
);
75 static void cptvf_send_msg_to_pf(struct otx_cptvf
*cptvf
,
76 struct otx_cpt_mbox
*mbx
)
78 /* Writing mbox(1) causes interrupt */
79 writeq(mbx
->msg
, cptvf
->reg_base
+ OTX_CPT_VFX_PF_MBOXX(0, 0));
80 writeq(mbx
->data
, cptvf
->reg_base
+ OTX_CPT_VFX_PF_MBOXX(0, 1));
83 /* Interrupt handler to handle mailbox messages from VFs */
84 void otx_cptvf_handle_mbox_intr(struct otx_cptvf
*cptvf
)
86 struct otx_cpt_mbox mbx
= {};
89 * MBOX[0] contains msg
90 * MBOX[1] contains data
92 mbx
.msg
= readq(cptvf
->reg_base
+ OTX_CPT_VFX_PF_MBOXX(0, 0));
93 mbx
.data
= readq(cptvf
->reg_base
+ OTX_CPT_VFX_PF_MBOXX(0, 1));
95 dump_mbox_msg(&mbx
, -1);
98 case OTX_CPT_MSG_VF_UP
:
99 cptvf
->pf_acked
= true;
100 cptvf
->num_vfs
= mbx
.data
;
102 case OTX_CPT_MSG_READY
:
103 cptvf
->pf_acked
= true;
104 cptvf
->vfid
= mbx
.data
;
105 dev_dbg(&cptvf
->pdev
->dev
, "Received VFID %d\n", cptvf
->vfid
);
107 case OTX_CPT_MSG_QBIND_GRP
:
108 cptvf
->pf_acked
= true;
109 cptvf
->vftype
= mbx
.data
;
110 dev_dbg(&cptvf
->pdev
->dev
, "VF %d type %s group %d\n",
112 ((mbx
.data
== OTX_CPT_SE_TYPES
) ? "SE" : "AE"),
115 case OTX_CPT_MSG_ACK
:
116 cptvf
->pf_acked
= true;
118 case OTX_CPT_MSG_NACK
:
119 cptvf
->pf_nacked
= true;
122 dev_err(&cptvf
->pdev
->dev
, "Invalid msg from PF, msg 0x%llx\n",
128 static int cptvf_send_msg_to_pf_timeout(struct otx_cptvf
*cptvf
,
129 struct otx_cpt_mbox
*mbx
)
131 int timeout
= CPT_MBOX_MSG_TIMEOUT
;
134 cptvf
->pf_acked
= false;
135 cptvf
->pf_nacked
= false;
136 cptvf_send_msg_to_pf(cptvf
, mbx
);
137 /* Wait for previous message to be acked, timeout 2sec */
138 while (!cptvf
->pf_acked
) {
139 if (cptvf
->pf_nacked
)
146 dev_err(&cptvf
->pdev
->dev
,
147 "PF didn't ack to mbox msg %llx from VF%u\n",
148 mbx
->msg
, cptvf
->vfid
);
156 * Checks if VF is able to comminicate with PF
157 * and also gets the CPT number this VF is associated to.
159 int otx_cptvf_check_pf_ready(struct otx_cptvf
*cptvf
)
161 struct otx_cpt_mbox mbx
= {};
164 mbx
.msg
= OTX_CPT_MSG_READY
;
165 ret
= cptvf_send_msg_to_pf_timeout(cptvf
, &mbx
);
171 * Communicate VQs size to PF to program CPT(0)_PF_Q(0-15)_CTL of the VF.
174 int otx_cptvf_send_vq_size_msg(struct otx_cptvf
*cptvf
)
176 struct otx_cpt_mbox mbx
= {};
179 mbx
.msg
= OTX_CPT_MSG_QLEN
;
180 mbx
.data
= cptvf
->qsize
;
181 ret
= cptvf_send_msg_to_pf_timeout(cptvf
, &mbx
);
187 * Communicate VF group required to PF and get the VQ binded to that group
189 int otx_cptvf_send_vf_to_grp_msg(struct otx_cptvf
*cptvf
, int group
)
191 struct otx_cpt_mbox mbx
= {};
194 mbx
.msg
= OTX_CPT_MSG_QBIND_GRP
;
195 /* Convey group of the VF */
197 ret
= cptvf_send_msg_to_pf_timeout(cptvf
, &mbx
);
200 cptvf
->vfgrp
= group
;
206 * Communicate VF group required to PF and get the VQ binded to that group
208 int otx_cptvf_send_vf_priority_msg(struct otx_cptvf
*cptvf
)
210 struct otx_cpt_mbox mbx
= {};
213 mbx
.msg
= OTX_CPT_MSG_VQ_PRIORITY
;
214 /* Convey group of the VF */
215 mbx
.data
= cptvf
->priority
;
216 ret
= cptvf_send_msg_to_pf_timeout(cptvf
, &mbx
);
222 * Communicate to PF that VF is UP and running
224 int otx_cptvf_send_vf_up(struct otx_cptvf
*cptvf
)
226 struct otx_cpt_mbox mbx
= {};
229 mbx
.msg
= OTX_CPT_MSG_VF_UP
;
230 ret
= cptvf_send_msg_to_pf_timeout(cptvf
, &mbx
);
236 * Communicate to PF that VF is DOWN and running
238 int otx_cptvf_send_vf_down(struct otx_cptvf
*cptvf
)
240 struct otx_cpt_mbox mbx
= {};
243 mbx
.msg
= OTX_CPT_MSG_VF_DOWN
;
244 ret
= cptvf_send_msg_to_pf_timeout(cptvf
, &mbx
);