linux/drivers/net/ethernet/marvell/octeontx2/af/mbox.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Marvell OcteonTx2 RVU Admin Function driver
   3 *
   4 * Copyright (C) 2018 Marvell International Ltd.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/interrupt.h>
  13#include <linux/pci.h>
  14
  15#include "rvu_reg.h"
  16#include "mbox.h"
  17
  18static const u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
  19
  20void __otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
  21{
  22        void *hw_mbase = mbox->hwbase + (devid * MBOX_SIZE);
  23        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
  24        struct mbox_hdr *tx_hdr, *rx_hdr;
  25
  26        tx_hdr = hw_mbase + mbox->tx_start;
  27        rx_hdr = hw_mbase + mbox->rx_start;
  28
  29        mdev->msg_size = 0;
  30        mdev->rsp_size = 0;
  31        tx_hdr->num_msgs = 0;
  32        tx_hdr->msg_size = 0;
  33        rx_hdr->num_msgs = 0;
  34        rx_hdr->msg_size = 0;
  35}
  36EXPORT_SYMBOL(__otx2_mbox_reset);
  37
  38void otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
  39{
  40        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
  41
  42        spin_lock(&mdev->mbox_lock);
  43        __otx2_mbox_reset(mbox, devid);
  44        spin_unlock(&mdev->mbox_lock);
  45}
  46EXPORT_SYMBOL(otx2_mbox_reset);
  47
  48void otx2_mbox_destroy(struct otx2_mbox *mbox)
  49{
  50        mbox->reg_base = NULL;
  51        mbox->hwbase = NULL;
  52
  53        kfree(mbox->dev);
  54        mbox->dev = NULL;
  55}
  56EXPORT_SYMBOL(otx2_mbox_destroy);
  57
  58int otx2_mbox_init(struct otx2_mbox *mbox, void *hwbase, struct pci_dev *pdev,
  59                   void *reg_base, int direction, int ndevs)
  60{
  61        struct otx2_mbox_dev *mdev;
  62        int devid;
  63
  64        switch (direction) {
  65        case MBOX_DIR_AFPF:
  66        case MBOX_DIR_PFVF:
  67                mbox->tx_start = MBOX_DOWN_TX_START;
  68                mbox->rx_start = MBOX_DOWN_RX_START;
  69                mbox->tx_size  = MBOX_DOWN_TX_SIZE;
  70                mbox->rx_size  = MBOX_DOWN_RX_SIZE;
  71                break;
  72        case MBOX_DIR_PFAF:
  73        case MBOX_DIR_VFPF:
  74                mbox->tx_start = MBOX_DOWN_RX_START;
  75                mbox->rx_start = MBOX_DOWN_TX_START;
  76                mbox->tx_size  = MBOX_DOWN_RX_SIZE;
  77                mbox->rx_size  = MBOX_DOWN_TX_SIZE;
  78                break;
  79        case MBOX_DIR_AFPF_UP:
  80        case MBOX_DIR_PFVF_UP:
  81                mbox->tx_start = MBOX_UP_TX_START;
  82                mbox->rx_start = MBOX_UP_RX_START;
  83                mbox->tx_size  = MBOX_UP_TX_SIZE;
  84                mbox->rx_size  = MBOX_UP_RX_SIZE;
  85                break;
  86        case MBOX_DIR_PFAF_UP:
  87        case MBOX_DIR_VFPF_UP:
  88                mbox->tx_start = MBOX_UP_RX_START;
  89                mbox->rx_start = MBOX_UP_TX_START;
  90                mbox->tx_size  = MBOX_UP_RX_SIZE;
  91                mbox->rx_size  = MBOX_UP_TX_SIZE;
  92                break;
  93        default:
  94                return -ENODEV;
  95        }
  96
  97        switch (direction) {
  98        case MBOX_DIR_AFPF:
  99        case MBOX_DIR_AFPF_UP:
 100                mbox->trigger = RVU_AF_AFPF_MBOX0;
 101                mbox->tr_shift = 4;
 102                break;
 103        case MBOX_DIR_PFAF:
 104        case MBOX_DIR_PFAF_UP:
 105                mbox->trigger = RVU_PF_PFAF_MBOX1;
 106                mbox->tr_shift = 0;
 107                break;
 108        case MBOX_DIR_PFVF:
 109        case MBOX_DIR_PFVF_UP:
 110                mbox->trigger = RVU_PF_VFX_PFVF_MBOX0;
 111                mbox->tr_shift = 12;
 112                break;
 113        case MBOX_DIR_VFPF:
 114        case MBOX_DIR_VFPF_UP:
 115                mbox->trigger = RVU_VF_VFPF_MBOX1;
 116                mbox->tr_shift = 0;
 117                break;
 118        default:
 119                return -ENODEV;
 120        }
 121
 122        mbox->reg_base = reg_base;
 123        mbox->hwbase = hwbase;
 124        mbox->pdev = pdev;
 125
 126        mbox->dev = kcalloc(ndevs, sizeof(struct otx2_mbox_dev), GFP_KERNEL);
 127        if (!mbox->dev) {
 128                otx2_mbox_destroy(mbox);
 129                return -ENOMEM;
 130        }
 131
 132        mbox->ndevs = ndevs;
 133        for (devid = 0; devid < ndevs; devid++) {
 134                mdev = &mbox->dev[devid];
 135                mdev->mbase = mbox->hwbase + (devid * MBOX_SIZE);
 136                spin_lock_init(&mdev->mbox_lock);
 137                /* Init header to reset value */
 138                otx2_mbox_reset(mbox, devid);
 139        }
 140
 141        return 0;
 142}
 143EXPORT_SYMBOL(otx2_mbox_init);
 144
 145int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid)
 146{
 147        unsigned long timeout = jiffies + msecs_to_jiffies(MBOX_RSP_TIMEOUT);
 148        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 149        struct device *sender = &mbox->pdev->dev;
 150
 151        while (!time_after(jiffies, timeout)) {
 152                if (mdev->num_msgs == mdev->msgs_acked)
 153                        return 0;
 154                usleep_range(800, 1000);
 155        }
 156        dev_dbg(sender, "timed out while waiting for rsp\n");
 157        return -EIO;
 158}
 159EXPORT_SYMBOL(otx2_mbox_wait_for_rsp);
 160
 161int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid)
 162{
 163        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 164        unsigned long timeout = jiffies + 1 * HZ;
 165
 166        while (!time_after(jiffies, timeout)) {
 167                if (mdev->num_msgs == mdev->msgs_acked)
 168                        return 0;
 169                cpu_relax();
 170        }
 171        return -EIO;
 172}
 173EXPORT_SYMBOL(otx2_mbox_busy_poll_for_rsp);
 174
 175void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid)
 176{
 177        void *hw_mbase = mbox->hwbase + (devid * MBOX_SIZE);
 178        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 179        struct mbox_hdr *tx_hdr, *rx_hdr;
 180
 181        tx_hdr = hw_mbase + mbox->tx_start;
 182        rx_hdr = hw_mbase + mbox->rx_start;
 183
 184        /* If bounce buffer is implemented copy mbox messages from
 185         * bounce buffer to hw mbox memory.
 186         */
 187        if (mdev->mbase != hw_mbase)
 188                memcpy(hw_mbase + mbox->tx_start + msgs_offset,
 189                       mdev->mbase + mbox->tx_start + msgs_offset,
 190                       mdev->msg_size);
 191
 192        spin_lock(&mdev->mbox_lock);
 193
 194        tx_hdr->msg_size = mdev->msg_size;
 195
 196        /* Reset header for next messages */
 197        mdev->msg_size = 0;
 198        mdev->rsp_size = 0;
 199        mdev->msgs_acked = 0;
 200
 201        /* Sync mbox data into memory */
 202        smp_wmb();
 203
 204        /* num_msgs != 0 signals to the peer that the buffer has a number of
 205         * messages.  So this should be written after writing all the messages
 206         * to the shared memory.
 207         */
 208        tx_hdr->num_msgs = mdev->num_msgs;
 209        rx_hdr->num_msgs = 0;
 210        spin_unlock(&mdev->mbox_lock);
 211
 212        /* The interrupt should be fired after num_msgs is written
 213         * to the shared memory
 214         */
 215        writeq(1, (void __iomem *)mbox->reg_base +
 216               (mbox->trigger | (devid << mbox->tr_shift)));
 217}
 218EXPORT_SYMBOL(otx2_mbox_msg_send);
 219
 220struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid,
 221                                            int size, int size_rsp)
 222{
 223        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 224        struct mbox_msghdr *msghdr = NULL;
 225
 226        spin_lock(&mdev->mbox_lock);
 227        size = ALIGN(size, MBOX_MSG_ALIGN);
 228        size_rsp = ALIGN(size_rsp, MBOX_MSG_ALIGN);
 229        /* Check if there is space in mailbox */
 230        if ((mdev->msg_size + size) > mbox->tx_size - msgs_offset)
 231                goto exit;
 232        if ((mdev->rsp_size + size_rsp) > mbox->rx_size - msgs_offset)
 233                goto exit;
 234
 235        if (mdev->msg_size == 0)
 236                mdev->num_msgs = 0;
 237        mdev->num_msgs++;
 238
 239        msghdr = mdev->mbase + mbox->tx_start + msgs_offset + mdev->msg_size;
 240
 241        /* Clear the whole msg region */
 242        memset(msghdr, 0, size);
 243        /* Init message header with reset values */
 244        msghdr->ver = OTX2_MBOX_VERSION;
 245        mdev->msg_size += size;
 246        mdev->rsp_size += size_rsp;
 247        msghdr->next_msgoff = mdev->msg_size + msgs_offset;
 248exit:
 249        spin_unlock(&mdev->mbox_lock);
 250
 251        return msghdr;
 252}
 253EXPORT_SYMBOL(otx2_mbox_alloc_msg_rsp);
 254
 255struct mbox_msghdr *otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid,
 256                                      struct mbox_msghdr *msg)
 257{
 258        unsigned long imsg = mbox->tx_start + msgs_offset;
 259        unsigned long irsp = mbox->rx_start + msgs_offset;
 260        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 261        u16 msgs;
 262
 263        spin_lock(&mdev->mbox_lock);
 264
 265        if (mdev->num_msgs != mdev->msgs_acked)
 266                goto error;
 267
 268        for (msgs = 0; msgs < mdev->msgs_acked; msgs++) {
 269                struct mbox_msghdr *pmsg = mdev->mbase + imsg;
 270                struct mbox_msghdr *prsp = mdev->mbase + irsp;
 271
 272                if (msg == pmsg) {
 273                        if (pmsg->id != prsp->id)
 274                                goto error;
 275                        spin_unlock(&mdev->mbox_lock);
 276                        return prsp;
 277                }
 278
 279                imsg = mbox->tx_start + pmsg->next_msgoff;
 280                irsp = mbox->rx_start + prsp->next_msgoff;
 281        }
 282
 283error:
 284        spin_unlock(&mdev->mbox_lock);
 285        return ERR_PTR(-ENODEV);
 286}
 287EXPORT_SYMBOL(otx2_mbox_get_rsp);
 288
 289int otx2_mbox_check_rsp_msgs(struct otx2_mbox *mbox, int devid)
 290{
 291        unsigned long ireq = mbox->tx_start + msgs_offset;
 292        unsigned long irsp = mbox->rx_start + msgs_offset;
 293        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 294        int rc = -ENODEV;
 295        u16 msgs;
 296
 297        spin_lock(&mdev->mbox_lock);
 298
 299        if (mdev->num_msgs != mdev->msgs_acked)
 300                goto exit;
 301
 302        for (msgs = 0; msgs < mdev->msgs_acked; msgs++) {
 303                struct mbox_msghdr *preq = mdev->mbase + ireq;
 304                struct mbox_msghdr *prsp = mdev->mbase + irsp;
 305
 306                if (preq->id != prsp->id)
 307                        goto exit;
 308                if (prsp->rc) {
 309                        rc = prsp->rc;
 310                        goto exit;
 311                }
 312
 313                ireq = mbox->tx_start + preq->next_msgoff;
 314                irsp = mbox->rx_start + prsp->next_msgoff;
 315        }
 316        rc = 0;
 317exit:
 318        spin_unlock(&mdev->mbox_lock);
 319        return rc;
 320}
 321EXPORT_SYMBOL(otx2_mbox_check_rsp_msgs);
 322
 323int
 324otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid, u16 pcifunc, u16 id)
 325{
 326        struct msg_rsp *rsp;
 327
 328        rsp = (struct msg_rsp *)
 329               otx2_mbox_alloc_msg(mbox, devid, sizeof(*rsp));
 330        if (!rsp)
 331                return -ENOMEM;
 332        rsp->hdr.id = id;
 333        rsp->hdr.sig = OTX2_MBOX_RSP_SIG;
 334        rsp->hdr.rc = MBOX_MSG_INVALID;
 335        rsp->hdr.pcifunc = pcifunc;
 336        return 0;
 337}
 338EXPORT_SYMBOL(otx2_reply_invalid_msg);
 339
 340bool otx2_mbox_nonempty(struct otx2_mbox *mbox, int devid)
 341{
 342        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 343        bool ret;
 344
 345        spin_lock(&mdev->mbox_lock);
 346        ret = mdev->num_msgs != 0;
 347        spin_unlock(&mdev->mbox_lock);
 348
 349        return ret;
 350}
 351EXPORT_SYMBOL(otx2_mbox_nonempty);
 352
 353const char *otx2_mbox_id2name(u16 id)
 354{
 355        switch (id) {
 356#define M(_name, _id, _1, _2, _3) case _id: return # _name;
 357        MBOX_MESSAGES
 358#undef M
 359        default:
 360                return "INVALID ID";
 361        }
 362}
 363EXPORT_SYMBOL(otx2_mbox_id2name);
 364
 365MODULE_AUTHOR("Marvell International Ltd.");
 366MODULE_LICENSE("GPL v2");
 367