1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* Copyright (C) 2020 Marvell. */ |
3 | |
4 | #include "otx2_cpt_common.h" |
5 | #include "otx2_cptvf.h" |
6 | #include <rvu_reg.h> |
7 | |
8 | int otx2_cpt_mbox_bbuf_init(struct otx2_cptvf_dev *cptvf, struct pci_dev *pdev) |
9 | { |
10 | struct otx2_mbox_dev *mdev; |
11 | struct otx2_mbox *otx2_mbox; |
12 | |
13 | cptvf->bbuf_base = devm_kmalloc(dev: &pdev->dev, MBOX_SIZE, GFP_KERNEL); |
14 | if (!cptvf->bbuf_base) |
15 | return -ENOMEM; |
16 | /* |
17 | * Overwrite mbox mbase to point to bounce buffer, so that PF/VF |
18 | * prepare all mbox messages in bounce buffer instead of directly |
19 | * in hw mbox memory. |
20 | */ |
21 | otx2_mbox = &cptvf->pfvf_mbox; |
22 | mdev = &otx2_mbox->dev[0]; |
23 | mdev->mbase = cptvf->bbuf_base; |
24 | |
25 | return 0; |
26 | } |
27 | |
28 | static void otx2_cpt_sync_mbox_bbuf(struct otx2_mbox *mbox, int devid) |
29 | { |
30 | u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); |
31 | void *hw_mbase = mbox->hwbase + (devid * MBOX_SIZE); |
32 | struct otx2_mbox_dev *mdev = &mbox->dev[devid]; |
33 | struct mbox_hdr *hdr; |
34 | u64 msg_size; |
35 | |
36 | if (mdev->mbase == hw_mbase) |
37 | return; |
38 | |
39 | hdr = hw_mbase + mbox->rx_start; |
40 | msg_size = hdr->msg_size; |
41 | |
42 | if (msg_size > mbox->rx_size - msgs_offset) |
43 | msg_size = mbox->rx_size - msgs_offset; |
44 | |
45 | /* Copy mbox messages from mbox memory to bounce buffer */ |
46 | memcpy(mdev->mbase + mbox->rx_start, |
47 | hw_mbase + mbox->rx_start, msg_size + msgs_offset); |
48 | } |
49 | |
50 | irqreturn_t otx2_cptvf_pfvf_mbox_intr(int __always_unused irq, void *arg) |
51 | { |
52 | struct otx2_cptvf_dev *cptvf = arg; |
53 | u64 intr; |
54 | |
55 | /* Read the interrupt bits */ |
56 | intr = otx2_cpt_read64(reg_base: cptvf->reg_base, blk: BLKADDR_RVUM, slot: 0, |
57 | OTX2_RVU_VF_INT); |
58 | |
59 | if (intr & 0x1ULL) { |
60 | /* Schedule work queue function to process the MBOX request */ |
61 | queue_work(wq: cptvf->pfvf_mbox_wq, work: &cptvf->pfvf_mbox_work); |
62 | /* Clear and ack the interrupt */ |
63 | otx2_cpt_write64(reg_base: cptvf->reg_base, blk: BLKADDR_RVUM, slot: 0, |
64 | OTX2_RVU_VF_INT, val: 0x1ULL); |
65 | } |
66 | return IRQ_HANDLED; |
67 | } |
68 | |
69 | static void process_pfvf_mbox_mbox_msg(struct otx2_cptvf_dev *cptvf, |
70 | struct mbox_msghdr *msg) |
71 | { |
72 | struct otx2_cptlfs_info *lfs = &cptvf->lfs; |
73 | struct otx2_cpt_kvf_limits_rsp *rsp_limits; |
74 | struct otx2_cpt_egrp_num_rsp *rsp_grp; |
75 | struct otx2_cpt_caps_rsp *eng_caps; |
76 | struct cpt_rd_wr_reg_msg *rsp_reg; |
77 | struct msix_offset_rsp *rsp_msix; |
78 | int i; |
79 | |
80 | if (msg->id >= MBOX_MSG_MAX) { |
81 | dev_err(&cptvf->pdev->dev, |
82 | "MBOX msg with unknown ID %d\n" , msg->id); |
83 | return; |
84 | } |
85 | if (msg->sig != OTX2_MBOX_RSP_SIG) { |
86 | dev_err(&cptvf->pdev->dev, |
87 | "MBOX msg with wrong signature %x, ID %d\n" , |
88 | msg->sig, msg->id); |
89 | return; |
90 | } |
91 | switch (msg->id) { |
92 | case MBOX_MSG_READY: |
93 | cptvf->vf_id = ((msg->pcifunc >> RVU_PFVF_FUNC_SHIFT) |
94 | & RVU_PFVF_FUNC_MASK) - 1; |
95 | break; |
96 | case MBOX_MSG_ATTACH_RESOURCES: |
97 | /* Check if resources were successfully attached */ |
98 | if (!msg->rc) |
99 | lfs->are_lfs_attached = 1; |
100 | break; |
101 | case MBOX_MSG_DETACH_RESOURCES: |
102 | /* Check if resources were successfully detached */ |
103 | if (!msg->rc) |
104 | lfs->are_lfs_attached = 0; |
105 | break; |
106 | case MBOX_MSG_MSIX_OFFSET: |
107 | rsp_msix = (struct msix_offset_rsp *) msg; |
108 | for (i = 0; i < rsp_msix->cptlfs; i++) |
109 | lfs->lf[i].msix_offset = rsp_msix->cptlf_msixoff[i]; |
110 | break; |
111 | case MBOX_MSG_CPT_RD_WR_REGISTER: |
112 | rsp_reg = (struct cpt_rd_wr_reg_msg *) msg; |
113 | if (msg->rc) { |
114 | dev_err(&cptvf->pdev->dev, |
115 | "Reg %llx rd/wr(%d) failed %d\n" , |
116 | rsp_reg->reg_offset, rsp_reg->is_write, |
117 | msg->rc); |
118 | return; |
119 | } |
120 | if (!rsp_reg->is_write) |
121 | *rsp_reg->ret_val = rsp_reg->val; |
122 | break; |
123 | case MBOX_MSG_GET_ENG_GRP_NUM: |
124 | rsp_grp = (struct otx2_cpt_egrp_num_rsp *) msg; |
125 | cptvf->lfs.kcrypto_eng_grp_num = rsp_grp->eng_grp_num; |
126 | break; |
127 | case MBOX_MSG_GET_KVF_LIMITS: |
128 | rsp_limits = (struct otx2_cpt_kvf_limits_rsp *) msg; |
129 | cptvf->lfs.kvf_limits = rsp_limits->kvf_limits; |
130 | break; |
131 | case MBOX_MSG_GET_CAPS: |
132 | eng_caps = (struct otx2_cpt_caps_rsp *)msg; |
133 | memcpy(cptvf->eng_caps, eng_caps->eng_caps, |
134 | sizeof(cptvf->eng_caps)); |
135 | break; |
136 | case MBOX_MSG_CPT_LF_RESET: |
137 | break; |
138 | default: |
139 | dev_err(&cptvf->pdev->dev, "Unsupported msg %d received.\n" , |
140 | msg->id); |
141 | break; |
142 | } |
143 | } |
144 | |
145 | void otx2_cptvf_pfvf_mbox_handler(struct work_struct *work) |
146 | { |
147 | struct otx2_cptvf_dev *cptvf; |
148 | struct otx2_mbox *pfvf_mbox; |
149 | struct otx2_mbox_dev *mdev; |
150 | struct mbox_hdr *rsp_hdr; |
151 | struct mbox_msghdr *msg; |
152 | int offset, i; |
153 | |
154 | /* sync with mbox memory region */ |
155 | smp_rmb(); |
156 | |
157 | cptvf = container_of(work, struct otx2_cptvf_dev, pfvf_mbox_work); |
158 | pfvf_mbox = &cptvf->pfvf_mbox; |
159 | otx2_cpt_sync_mbox_bbuf(mbox: pfvf_mbox, devid: 0); |
160 | mdev = &pfvf_mbox->dev[0]; |
161 | rsp_hdr = (struct mbox_hdr *)(mdev->mbase + pfvf_mbox->rx_start); |
162 | if (rsp_hdr->num_msgs == 0) |
163 | return; |
164 | offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); |
165 | |
166 | for (i = 0; i < rsp_hdr->num_msgs; i++) { |
167 | msg = (struct mbox_msghdr *)(mdev->mbase + pfvf_mbox->rx_start + |
168 | offset); |
169 | process_pfvf_mbox_mbox_msg(cptvf, msg); |
170 | offset = msg->next_msgoff; |
171 | mdev->msgs_acked++; |
172 | } |
173 | otx2_mbox_reset(mbox: pfvf_mbox, devid: 0); |
174 | } |
175 | |
176 | int otx2_cptvf_send_eng_grp_num_msg(struct otx2_cptvf_dev *cptvf, int eng_type) |
177 | { |
178 | struct otx2_mbox *mbox = &cptvf->pfvf_mbox; |
179 | struct pci_dev *pdev = cptvf->pdev; |
180 | struct otx2_cpt_egrp_num_msg *req; |
181 | |
182 | req = (struct otx2_cpt_egrp_num_msg *) |
183 | otx2_mbox_alloc_msg_rsp(mbox, devid: 0, size: sizeof(*req), |
184 | size_rsp: sizeof(struct otx2_cpt_egrp_num_rsp)); |
185 | if (req == NULL) { |
186 | dev_err(&pdev->dev, "RVU MBOX failed to get message.\n" ); |
187 | return -EFAULT; |
188 | } |
189 | req->hdr.id = MBOX_MSG_GET_ENG_GRP_NUM; |
190 | req->hdr.sig = OTX2_MBOX_REQ_SIG; |
191 | req->hdr.pcifunc = OTX2_CPT_RVU_PFFUNC(cptvf->vf_id, 0); |
192 | req->eng_type = eng_type; |
193 | |
194 | return otx2_cpt_send_mbox_msg(mbox, pdev); |
195 | } |
196 | |
197 | int otx2_cptvf_send_kvf_limits_msg(struct otx2_cptvf_dev *cptvf) |
198 | { |
199 | struct otx2_mbox *mbox = &cptvf->pfvf_mbox; |
200 | struct pci_dev *pdev = cptvf->pdev; |
201 | struct mbox_msghdr *req; |
202 | |
203 | req = (struct mbox_msghdr *) |
204 | otx2_mbox_alloc_msg_rsp(mbox, devid: 0, size: sizeof(*req), |
205 | size_rsp: sizeof(struct otx2_cpt_kvf_limits_rsp)); |
206 | if (req == NULL) { |
207 | dev_err(&pdev->dev, "RVU MBOX failed to get message.\n" ); |
208 | return -EFAULT; |
209 | } |
210 | req->id = MBOX_MSG_GET_KVF_LIMITS; |
211 | req->sig = OTX2_MBOX_REQ_SIG; |
212 | req->pcifunc = OTX2_CPT_RVU_PFFUNC(cptvf->vf_id, 0); |
213 | |
214 | return otx2_cpt_send_mbox_msg(mbox, pdev); |
215 | } |
216 | |
217 | int otx2_cptvf_send_caps_msg(struct otx2_cptvf_dev *cptvf) |
218 | { |
219 | struct otx2_mbox *mbox = &cptvf->pfvf_mbox; |
220 | struct pci_dev *pdev = cptvf->pdev; |
221 | struct mbox_msghdr *req; |
222 | |
223 | req = (struct mbox_msghdr *) |
224 | otx2_mbox_alloc_msg_rsp(mbox, devid: 0, size: sizeof(*req), |
225 | size_rsp: sizeof(struct otx2_cpt_caps_rsp)); |
226 | if (!req) { |
227 | dev_err(&pdev->dev, "RVU MBOX failed to get message.\n" ); |
228 | return -EFAULT; |
229 | } |
230 | req->id = MBOX_MSG_GET_CAPS; |
231 | req->sig = OTX2_MBOX_REQ_SIG; |
232 | req->pcifunc = OTX2_CPT_RVU_PFFUNC(cptvf->vf_id, 0); |
233 | |
234 | return otx2_cpt_send_mbox_msg(mbox, pdev); |
235 | } |
236 | |