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