1 /*
2  * Copyright (C) 2016 Cavium, Inc.
3  *
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.
7  */
8 #include <linux/module.h>
9 #include "cptpf.h"
10 
11 static void cpt_send_msg_to_vf(struct cpt_device *cpt, int vf,
12 			       struct cpt_mbox *mbx)
13 {
14 	/* Writing mbox(0) causes interrupt */
15 	cpt_write_csr64(cpt->reg_base, CPTX_PF_VFX_MBOXX(0, vf, 1),
16 			mbx->data);
17 	cpt_write_csr64(cpt->reg_base, CPTX_PF_VFX_MBOXX(0, vf, 0), mbx->msg);
18 }
19 
20 /* ACKs VF's mailbox message
21  * @vf: VF to which ACK to be sent
22  */
23 static void cpt_mbox_send_ack(struct cpt_device *cpt, int vf,
24 			      struct cpt_mbox *mbx)
25 {
26 	mbx->data = 0ull;
27 	mbx->msg = CPT_MBOX_MSG_TYPE_ACK;
28 	cpt_send_msg_to_vf(cpt, vf, mbx);
29 }
30 
31 static void cpt_clear_mbox_intr(struct cpt_device *cpt, u32 vf)
32 {
33 	/* W1C for the VF */
34 	cpt_write_csr64(cpt->reg_base, CPTX_PF_MBOX_INTX(0, 0), (1 << vf));
35 }
36 
37 /*
38  *  Configure QLEN/Chunk sizes for VF
39  */
40 static void cpt_cfg_qlen_for_vf(struct cpt_device *cpt, int vf, u32 size)
41 {
42 	union cptx_pf_qx_ctl pf_qx_ctl;
43 
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);
48 }
49 
50 /*
51  * Configure VQ priority
52  */
53 static void cpt_cfg_vq_priority(struct cpt_device *cpt, int vf, u32 pri)
54 {
55 	union cptx_pf_qx_ctl pf_qx_ctl;
56 
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);
60 }
61 
62 static int cpt_bind_vq_to_grp(struct cpt_device *cpt, u8 q, u8 grp)
63 {
64 	struct microcode *mcode = cpt->mcode;
65 	union cptx_pf_qx_ctl pf_qx_ctl;
66 	struct device *dev = &cpt->pdev->dev;
67 
68 	if (q >= CPT_MAX_VF_NUM) {
69 		dev_err(dev, "Queues are more than cores in the group");
70 		return -EINVAL;
71 	}
72 	if (grp >= CPT_MAX_CORE_GROUPS) {
73 		dev_err(dev, "Request group is more than possible groups");
74 		return -EINVAL;
75 	}
76 	if (grp >= cpt->next_mc_idx) {
77 		dev_err(dev, "Request group is higher than available functional groups");
78 		return -EINVAL;
79 	}
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"));
84 
85 	return mcode[grp].is_ae ? AE_TYPES : SE_TYPES;
86 }
87 
88 /* Interrupt handler to handle mailbox messages from VFs */
89 static void cpt_handle_mbox_intr(struct cpt_device *cpt, int vf)
90 {
91 	struct cpt_vf_info *vfx = &cpt->vfinfo[vf];
92 	struct cpt_mbox mbx = {};
93 	int vftype;
94 	struct device *dev = &cpt->pdev->dev;
95 	/*
96 	 * MBOX[0] contains msg
97 	 * MBOX[1] contains data
98 	 */
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);
102 	switch (mbx.msg) {
103 	case CPT_MSG_VF_UP:
104 		vfx->state = VF_STATE_UP;
105 		try_module_get(THIS_MODULE);
106 		cpt_mbox_send_ack(cpt, vf, &mbx);
107 		break;
108 	case CPT_MSG_READY:
109 		mbx.msg  = CPT_MSG_READY;
110 		mbx.data = vf;
111 		cpt_send_msg_to_vf(cpt, vf, &mbx);
112 		break;
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);
118 		break;
119 	case CPT_MSG_QLEN:
120 		vfx->qlen = mbx.data;
121 		cpt_cfg_qlen_for_vf(cpt, vf, vfx->qlen);
122 		cpt_mbox_send_ack(cpt, vf, &mbx);
123 		break;
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",
128 				vf, mbx.data);
129 		else {
130 			dev_dbg(dev, "Queue %d binding to group %llu successful",
131 				vf, mbx.data);
132 			mbx.msg = CPT_MSG_QBIND_GRP;
133 			mbx.data = vftype;
134 			cpt_send_msg_to_vf(cpt, vf, &mbx);
135 		}
136 		break;
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);
141 		break;
142 	default:
143 		dev_err(&cpt->pdev->dev, "Invalid msg from VF%d, msg 0x%llx\n",
144 			vf, mbx.msg);
145 		break;
146 	}
147 }
148 
149 void cpt_mbox_intr_handler (struct cpt_device *cpt, int mbx)
150 {
151 	u64 intr;
152 	u8  vf;
153 
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);
161 		}
162 	}
163 }
164