linux/drivers/crypto/cavium/cpt/cptpf_mbox.c
<<
>>
Prefs
   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
  11static 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 */
  23static 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
  31static 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 */
  40static 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 */
  53static 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
  62static 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 */
  89static 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
 149void 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