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 9 #include "cptvf.h" 10 11 static void cptvf_send_msg_to_pf(struct cpt_vf *cptvf, struct cpt_mbox *mbx) 12 { 13 /* Writing mbox(1) causes interrupt */ 14 cpt_write_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 0), 15 mbx->msg); 16 cpt_write_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 1), 17 mbx->data); 18 } 19 20 /* Interrupt handler to handle mailbox messages from VFs */ 21 void cptvf_handle_mbox_intr(struct cpt_vf *cptvf) 22 { 23 struct cpt_mbox mbx = {}; 24 25 /* 26 * MBOX[0] contains msg 27 * MBOX[1] contains data 28 */ 29 mbx.msg = cpt_read_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 0)); 30 mbx.data = cpt_read_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 1)); 31 dev_dbg(&cptvf->pdev->dev, "%s: Mailbox msg 0x%llx from PF\n", 32 __func__, mbx.msg); 33 switch (mbx.msg) { 34 case CPT_MSG_READY: 35 { 36 cptvf->pf_acked = true; 37 cptvf->vfid = mbx.data; 38 dev_dbg(&cptvf->pdev->dev, "Received VFID %d\n", cptvf->vfid); 39 break; 40 } 41 case CPT_MSG_QBIND_GRP: 42 cptvf->pf_acked = true; 43 cptvf->vftype = mbx.data; 44 dev_dbg(&cptvf->pdev->dev, "VF %d type %s group %d\n", 45 cptvf->vfid, ((mbx.data == SE_TYPES) ? "SE" : "AE"), 46 cptvf->vfgrp); 47 break; 48 case CPT_MBOX_MSG_TYPE_ACK: 49 cptvf->pf_acked = true; 50 break; 51 case CPT_MBOX_MSG_TYPE_NACK: 52 cptvf->pf_nacked = true; 53 break; 54 default: 55 dev_err(&cptvf->pdev->dev, "Invalid msg from PF, msg 0x%llx\n", 56 mbx.msg); 57 break; 58 } 59 } 60 61 static int cptvf_send_msg_to_pf_timeout(struct cpt_vf *cptvf, 62 struct cpt_mbox *mbx) 63 { 64 int timeout = CPT_MBOX_MSG_TIMEOUT; 65 int sleep = 10; 66 67 cptvf->pf_acked = false; 68 cptvf->pf_nacked = false; 69 cptvf_send_msg_to_pf(cptvf, mbx); 70 /* Wait for previous message to be acked, timeout 2sec */ 71 while (!cptvf->pf_acked) { 72 if (cptvf->pf_nacked) 73 return -EINVAL; 74 msleep(sleep); 75 if (cptvf->pf_acked) 76 break; 77 timeout -= sleep; 78 if (!timeout) { 79 dev_err(&cptvf->pdev->dev, "PF didn't ack to mbox msg %llx from VF%u\n", 80 (mbx->msg & 0xFF), cptvf->vfid); 81 return -EBUSY; 82 } 83 } 84 85 return 0; 86 } 87 88 /* 89 * Checks if VF is able to comminicate with PF 90 * and also gets the CPT number this VF is associated to. 91 */ 92 int cptvf_check_pf_ready(struct cpt_vf *cptvf) 93 { 94 struct pci_dev *pdev = cptvf->pdev; 95 struct cpt_mbox mbx = {}; 96 97 mbx.msg = CPT_MSG_READY; 98 if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) { 99 dev_err(&pdev->dev, "PF didn't respond to READY msg\n"); 100 return -EBUSY; 101 } 102 103 return 0; 104 } 105 106 /* 107 * Communicate VQs size to PF to program CPT(0)_PF_Q(0-15)_CTL of the VF. 108 * Must be ACKed. 109 */ 110 int cptvf_send_vq_size_msg(struct cpt_vf *cptvf) 111 { 112 struct pci_dev *pdev = cptvf->pdev; 113 struct cpt_mbox mbx = {}; 114 115 mbx.msg = CPT_MSG_QLEN; 116 mbx.data = cptvf->qsize; 117 if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) { 118 dev_err(&pdev->dev, "PF didn't respond to vq_size msg\n"); 119 return -EBUSY; 120 } 121 122 return 0; 123 } 124 125 /* 126 * Communicate VF group required to PF and get the VQ binded to that group 127 */ 128 int cptvf_send_vf_to_grp_msg(struct cpt_vf *cptvf) 129 { 130 struct pci_dev *pdev = cptvf->pdev; 131 struct cpt_mbox mbx = {}; 132 133 mbx.msg = CPT_MSG_QBIND_GRP; 134 /* Convey group of the VF */ 135 mbx.data = cptvf->vfgrp; 136 if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) { 137 dev_err(&pdev->dev, "PF didn't respond to vf_type msg\n"); 138 return -EBUSY; 139 } 140 141 return 0; 142 } 143 144 /* 145 * Communicate VF group required to PF and get the VQ binded to that group 146 */ 147 int cptvf_send_vf_priority_msg(struct cpt_vf *cptvf) 148 { 149 struct pci_dev *pdev = cptvf->pdev; 150 struct cpt_mbox mbx = {}; 151 152 mbx.msg = CPT_MSG_VQ_PRIORITY; 153 /* Convey group of the VF */ 154 mbx.data = cptvf->priority; 155 if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) { 156 dev_err(&pdev->dev, "PF didn't respond to vf_type msg\n"); 157 return -EBUSY; 158 } 159 return 0; 160 } 161 162 /* 163 * Communicate to PF that VF is UP and running 164 */ 165 int cptvf_send_vf_up(struct cpt_vf *cptvf) 166 { 167 struct pci_dev *pdev = cptvf->pdev; 168 struct cpt_mbox mbx = {}; 169 170 mbx.msg = CPT_MSG_VF_UP; 171 if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) { 172 dev_err(&pdev->dev, "PF didn't respond to UP msg\n"); 173 return -EBUSY; 174 } 175 176 return 0; 177 } 178 179 /* 180 * Communicate to PF that VF is DOWN and running 181 */ 182 int cptvf_send_vf_down(struct cpt_vf *cptvf) 183 { 184 struct pci_dev *pdev = cptvf->pdev; 185 struct cpt_mbox mbx = {}; 186 187 mbx.msg = CPT_MSG_VF_DOWN; 188 if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) { 189 dev_err(&pdev->dev, "PF didn't respond to DOWN msg\n"); 190 return -EBUSY; 191 } 192 193 return 0; 194 } 195