2 * Copyright (C) 2016 Cavium, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of version 2 of the GNU General Public License
6 * as published by the Free Software Foundation.
8 #include <linux/module.h>
11 static void cpt_send_msg_to_vf(struct cpt_device
*cpt
, int vf
,
14 /* Writing mbox(0) causes interrupt */
15 cpt_write_csr64(cpt
->reg_base
, CPTX_PF_VFX_MBOXX(0, vf
, 1),
17 cpt_write_csr64(cpt
->reg_base
, CPTX_PF_VFX_MBOXX(0, vf
, 0), mbx
->msg
);
20 /* ACKs VF's mailbox message
21 * @vf: VF to which ACK to be sent
23 static void cpt_mbox_send_ack(struct cpt_device
*cpt
, int vf
,
27 mbx
->msg
= CPT_MBOX_MSG_TYPE_ACK
;
28 cpt_send_msg_to_vf(cpt
, vf
, mbx
);
31 static void cpt_clear_mbox_intr(struct cpt_device
*cpt
, u32 vf
)
34 cpt_write_csr64(cpt
->reg_base
, CPTX_PF_MBOX_INTX(0, 0), (1 << vf
));
38 * Configure QLEN/Chunk sizes for VF
40 static void cpt_cfg_qlen_for_vf(struct cpt_device
*cpt
, int vf
, u32 size
)
42 union cptx_pf_qx_ctl pf_qx_ctl
;
44 pf_qx_ctl
.u
= cpt_read_csr64(cpt
->reg_base
, CPTX_PF_QX_CTL(0, vf
));
45 pf_qx_ctl
.s
.size
= size
;
46 pf_qx_ctl
.s
.cont_err
= true;
47 cpt_write_csr64(cpt
->reg_base
, CPTX_PF_QX_CTL(0, vf
), pf_qx_ctl
.u
);
51 * Configure VQ priority
53 static void cpt_cfg_vq_priority(struct cpt_device
*cpt
, int vf
, u32 pri
)
55 union cptx_pf_qx_ctl pf_qx_ctl
;
57 pf_qx_ctl
.u
= cpt_read_csr64(cpt
->reg_base
, CPTX_PF_QX_CTL(0, vf
));
58 pf_qx_ctl
.s
.pri
= pri
;
59 cpt_write_csr64(cpt
->reg_base
, CPTX_PF_QX_CTL(0, vf
), pf_qx_ctl
.u
);
62 static int cpt_bind_vq_to_grp(struct cpt_device
*cpt
, u8 q
, u8 grp
)
64 struct microcode
*mcode
= cpt
->mcode
;
65 union cptx_pf_qx_ctl pf_qx_ctl
;
66 struct device
*dev
= &cpt
->pdev
->dev
;
68 if (q
>= CPT_MAX_VF_NUM
) {
69 dev_err(dev
, "Queues are more than cores in the group");
72 if (grp
>= CPT_MAX_CORE_GROUPS
) {
73 dev_err(dev
, "Request group is more than possible groups");
76 if (grp
>= cpt
->next_mc_idx
) {
77 dev_err(dev
, "Request group is higher than available functional groups");
80 pf_qx_ctl
.u
= cpt_read_csr64(cpt
->reg_base
, CPTX_PF_QX_CTL(0, q
));
81 pf_qx_ctl
.s
.grp
= mcode
[grp
].group
;
82 cpt_write_csr64(cpt
->reg_base
, CPTX_PF_QX_CTL(0, q
), pf_qx_ctl
.u
);
83 dev_dbg(dev
, "VF %d TYPE %s", q
, (mcode
[grp
].is_ae
? "AE" : "SE"));
85 return mcode
[grp
].is_ae
? AE_TYPES
: SE_TYPES
;
88 /* Interrupt handler to handle mailbox messages from VFs */
89 static void cpt_handle_mbox_intr(struct cpt_device
*cpt
, int vf
)
91 struct cpt_vf_info
*vfx
= &cpt
->vfinfo
[vf
];
92 struct cpt_mbox mbx
= {};
94 struct device
*dev
= &cpt
->pdev
->dev
;
96 * MBOX[0] contains msg
97 * MBOX[1] contains data
99 mbx
.msg
= cpt_read_csr64(cpt
->reg_base
, CPTX_PF_VFX_MBOXX(0, vf
, 0));
100 mbx
.data
= cpt_read_csr64(cpt
->reg_base
, CPTX_PF_VFX_MBOXX(0, vf
, 1));
101 dev_dbg(dev
, "%s: Mailbox msg 0x%llx from VF%d", __func__
, mbx
.msg
, vf
);
104 vfx
->state
= VF_STATE_UP
;
105 try_module_get(THIS_MODULE
);
106 cpt_mbox_send_ack(cpt
, vf
, &mbx
);
109 mbx
.msg
= CPT_MSG_READY
;
111 cpt_send_msg_to_vf(cpt
, vf
, &mbx
);
113 case CPT_MSG_VF_DOWN
:
114 /* First msg in VF teardown sequence */
115 vfx
->state
= VF_STATE_DOWN
;
116 module_put(THIS_MODULE
);
117 cpt_mbox_send_ack(cpt
, vf
, &mbx
);
120 vfx
->qlen
= mbx
.data
;
121 cpt_cfg_qlen_for_vf(cpt
, vf
, vfx
->qlen
);
122 cpt_mbox_send_ack(cpt
, vf
, &mbx
);
124 case CPT_MSG_QBIND_GRP
:
125 vftype
= cpt_bind_vq_to_grp(cpt
, vf
, (u8
)mbx
.data
);
126 if ((vftype
!= AE_TYPES
) && (vftype
!= SE_TYPES
))
127 dev_err(dev
, "Queue %d binding to group %llu failed",
130 dev_dbg(dev
, "Queue %d binding to group %llu successful",
132 mbx
.msg
= CPT_MSG_QBIND_GRP
;
134 cpt_send_msg_to_vf(cpt
, vf
, &mbx
);
137 case CPT_MSG_VQ_PRIORITY
:
138 vfx
->priority
= mbx
.data
;
139 cpt_cfg_vq_priority(cpt
, vf
, vfx
->priority
);
140 cpt_mbox_send_ack(cpt
, vf
, &mbx
);
143 dev_err(&cpt
->pdev
->dev
, "Invalid msg from VF%d, msg 0x%llx\n",
149 void cpt_mbox_intr_handler (struct cpt_device
*cpt
, int mbx
)
154 intr
= cpt_read_csr64(cpt
->reg_base
, CPTX_PF_MBOX_INTX(0, 0));
155 dev_dbg(&cpt
->pdev
->dev
, "PF interrupt Mbox%d 0x%llx\n", mbx
, intr
);
156 for (vf
= 0; vf
< CPT_MAX_VF_NUM
; vf
++) {
157 if (intr
& (1ULL << vf
)) {
158 dev_dbg(&cpt
->pdev
->dev
, "Intr from VF %d\n", vf
);
159 cpt_handle_mbox_intr(cpt
, vf
);
160 cpt_clear_mbox_intr(cpt
, vf
);