1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/workqueue.h>
4 #include "nitrox_csr.h"
5 #include "nitrox_hal.h"
6 #include "nitrox_dev.h"
8 #define RING_TO_VFNO(_x, _y) ((_x) / (_y))
11 * mbx_msg_type - Mailbox message types
21 * mbx_msg_opcode - Mailbox message opcodes
31 struct nitrox_vfdev
*vfdev
;
32 struct nitrox_device
*ndev
;
33 struct work_struct pf2vf_resp
;
36 static inline u64
pf2vf_read_mbox(struct nitrox_device
*ndev
, int ring
)
40 reg_addr
= NPS_PKT_MBOX_VF_PF_PFDATAX(ring
);
41 return nitrox_read_csr(ndev
, reg_addr
);
44 static inline void pf2vf_write_mbox(struct nitrox_device
*ndev
, u64 value
,
49 reg_addr
= NPS_PKT_MBOX_PF_VF_PFDATAX(ring
);
50 nitrox_write_csr(ndev
, reg_addr
, value
);
53 static void pf2vf_send_response(struct nitrox_device
*ndev
,
54 struct nitrox_vfdev
*vfdev
)
58 msg
.value
= vfdev
->msg
.value
;
60 switch (vfdev
->msg
.opcode
) {
62 msg
.data
= ndev
->mode
;
65 vfdev
->nr_queues
= vfdev
->msg
.data
;
66 atomic_set(&vfdev
->state
, __NDEV_READY
);
68 case MSG_OP_CHIPID_VFID
:
69 msg
.id
.chipid
= ndev
->idx
;
70 msg
.id
.vfid
= vfdev
->vfno
;
74 atomic_set(&vfdev
->state
, __NDEV_NOT_READY
);
77 msg
.type
= MBX_MSG_TYPE_NOP
;
81 if (msg
.type
== MBX_MSG_TYPE_NOP
)
85 msg
.type
= MBX_MSG_TYPE_ACK
;
86 pf2vf_write_mbox(ndev
, msg
.value
, vfdev
->ring
);
89 atomic64_inc(&vfdev
->mbx_resp
);
92 static void pf2vf_resp_handler(struct work_struct
*work
)
94 struct pf2vf_work
*pf2vf_resp
= container_of(work
, struct pf2vf_work
,
96 struct nitrox_vfdev
*vfdev
= pf2vf_resp
->vfdev
;
97 struct nitrox_device
*ndev
= pf2vf_resp
->ndev
;
99 switch (vfdev
->msg
.type
) {
100 case MBX_MSG_TYPE_REQ
:
101 /* process the request from VF */
102 pf2vf_send_response(ndev
, vfdev
);
104 case MBX_MSG_TYPE_ACK
:
105 case MBX_MSG_TYPE_NACK
:
112 void nitrox_pf2vf_mbox_handler(struct nitrox_device
*ndev
)
114 struct nitrox_vfdev
*vfdev
;
115 struct pf2vf_work
*pfwork
;
120 /* loop for VF(0..63) */
121 reg_addr
= NPS_PKT_MBOX_INT_LO
;
122 value
= nitrox_read_csr(ndev
, reg_addr
);
123 for_each_set_bit(i
, (const unsigned long *)&value
, BITS_PER_LONG
) {
124 /* get the vfno from ring */
125 vfno
= RING_TO_VFNO(i
, ndev
->iov
.max_vf_queues
);
126 vfdev
= ndev
->iov
.vfdev
+ vfno
;
128 /* fill the vf mailbox data */
129 vfdev
->msg
.value
= pf2vf_read_mbox(ndev
, vfdev
->ring
);
130 pfwork
= kzalloc(sizeof(*pfwork
), GFP_ATOMIC
);
134 pfwork
->vfdev
= vfdev
;
136 INIT_WORK(&pfwork
->pf2vf_resp
, pf2vf_resp_handler
);
137 queue_work(ndev
->iov
.pf2vf_wq
, &pfwork
->pf2vf_resp
);
138 /* clear the corresponding vf bit */
139 nitrox_write_csr(ndev
, reg_addr
, BIT_ULL(i
));
142 /* loop for VF(64..127) */
143 reg_addr
= NPS_PKT_MBOX_INT_HI
;
144 value
= nitrox_read_csr(ndev
, reg_addr
);
145 for_each_set_bit(i
, (const unsigned long *)&value
, BITS_PER_LONG
) {
146 /* get the vfno from ring */
147 vfno
= RING_TO_VFNO(i
+ 64, ndev
->iov
.max_vf_queues
);
148 vfdev
= ndev
->iov
.vfdev
+ vfno
;
149 vfdev
->ring
= (i
+ 64);
150 /* fill the vf mailbox data */
151 vfdev
->msg
.value
= pf2vf_read_mbox(ndev
, vfdev
->ring
);
153 pfwork
= kzalloc(sizeof(*pfwork
), GFP_ATOMIC
);
157 pfwork
->vfdev
= vfdev
;
159 INIT_WORK(&pfwork
->pf2vf_resp
, pf2vf_resp_handler
);
160 queue_work(ndev
->iov
.pf2vf_wq
, &pfwork
->pf2vf_resp
);
161 /* clear the corresponding vf bit */
162 nitrox_write_csr(ndev
, reg_addr
, BIT_ULL(i
));
166 int nitrox_mbox_init(struct nitrox_device
*ndev
)
168 struct nitrox_vfdev
*vfdev
;
171 ndev
->iov
.vfdev
= kcalloc(ndev
->iov
.num_vfs
,
172 sizeof(struct nitrox_vfdev
), GFP_KERNEL
);
173 if (!ndev
->iov
.vfdev
)
176 for (i
= 0; i
< ndev
->iov
.num_vfs
; i
++) {
177 vfdev
= ndev
->iov
.vfdev
+ i
;
181 /* allocate pf2vf response workqueue */
182 ndev
->iov
.pf2vf_wq
= alloc_workqueue("nitrox_pf2vf", 0, 0);
183 if (!ndev
->iov
.pf2vf_wq
) {
184 kfree(ndev
->iov
.vfdev
);
187 /* enable pf2vf mailbox interrupts */
188 enable_pf2vf_mbox_interrupts(ndev
);
193 void nitrox_mbox_cleanup(struct nitrox_device
*ndev
)
195 /* disable pf2vf mailbox interrupts */
196 disable_pf2vf_mbox_interrupts(ndev
);
197 /* destroy workqueue */
198 if (ndev
->iov
.pf2vf_wq
)
199 destroy_workqueue(ndev
->iov
.pf2vf_wq
);
201 kfree(ndev
->iov
.vfdev
);
202 ndev
->iov
.pf2vf_wq
= NULL
;
203 ndev
->iov
.vfdev
= NULL
;