root/drivers/net/ethernet/marvell/octeontx2/af/mbox.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. otx2_mbox_reset
  2. otx2_mbox_destroy
  3. otx2_mbox_init
  4. otx2_mbox_wait_for_rsp
  5. otx2_mbox_busy_poll_for_rsp
  6. otx2_mbox_msg_send
  7. otx2_mbox_alloc_msg_rsp
  8. otx2_mbox_get_rsp
  9. otx2_reply_invalid_msg
  10. otx2_mbox_nonempty
  11. otx2_mbox_id2name

   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 
  18 static const u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
  19 
  20 void otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
  21 {
  22         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
  23         struct mbox_hdr *tx_hdr, *rx_hdr;
  24 
  25         tx_hdr = mdev->mbase + mbox->tx_start;
  26         rx_hdr = mdev->mbase + mbox->rx_start;
  27 
  28         spin_lock(&mdev->mbox_lock);
  29         mdev->msg_size = 0;
  30         mdev->rsp_size = 0;
  31         tx_hdr->num_msgs = 0;
  32         rx_hdr->num_msgs = 0;
  33         spin_unlock(&mdev->mbox_lock);
  34 }
  35 EXPORT_SYMBOL(otx2_mbox_reset);
  36 
  37 void otx2_mbox_destroy(struct otx2_mbox *mbox)
  38 {
  39         mbox->reg_base = NULL;
  40         mbox->hwbase = NULL;
  41 
  42         kfree(mbox->dev);
  43         mbox->dev = NULL;
  44 }
  45 EXPORT_SYMBOL(otx2_mbox_destroy);
  46 
  47 int otx2_mbox_init(struct otx2_mbox *mbox, void *hwbase, struct pci_dev *pdev,
  48                    void *reg_base, int direction, int ndevs)
  49 {
  50         struct otx2_mbox_dev *mdev;
  51         int devid;
  52 
  53         switch (direction) {
  54         case MBOX_DIR_AFPF:
  55         case MBOX_DIR_PFVF:
  56                 mbox->tx_start = MBOX_DOWN_TX_START;
  57                 mbox->rx_start = MBOX_DOWN_RX_START;
  58                 mbox->tx_size  = MBOX_DOWN_TX_SIZE;
  59                 mbox->rx_size  = MBOX_DOWN_RX_SIZE;
  60                 break;
  61         case MBOX_DIR_PFAF:
  62         case MBOX_DIR_VFPF:
  63                 mbox->tx_start = MBOX_DOWN_RX_START;
  64                 mbox->rx_start = MBOX_DOWN_TX_START;
  65                 mbox->tx_size  = MBOX_DOWN_RX_SIZE;
  66                 mbox->rx_size  = MBOX_DOWN_TX_SIZE;
  67                 break;
  68         case MBOX_DIR_AFPF_UP:
  69         case MBOX_DIR_PFVF_UP:
  70                 mbox->tx_start = MBOX_UP_TX_START;
  71                 mbox->rx_start = MBOX_UP_RX_START;
  72                 mbox->tx_size  = MBOX_UP_TX_SIZE;
  73                 mbox->rx_size  = MBOX_UP_RX_SIZE;
  74                 break;
  75         case MBOX_DIR_PFAF_UP:
  76         case MBOX_DIR_VFPF_UP:
  77                 mbox->tx_start = MBOX_UP_RX_START;
  78                 mbox->rx_start = MBOX_UP_TX_START;
  79                 mbox->tx_size  = MBOX_UP_RX_SIZE;
  80                 mbox->rx_size  = MBOX_UP_TX_SIZE;
  81                 break;
  82         default:
  83                 return -ENODEV;
  84         }
  85 
  86         switch (direction) {
  87         case MBOX_DIR_AFPF:
  88         case MBOX_DIR_AFPF_UP:
  89                 mbox->trigger = RVU_AF_AFPF_MBOX0;
  90                 mbox->tr_shift = 4;
  91                 break;
  92         case MBOX_DIR_PFAF:
  93         case MBOX_DIR_PFAF_UP:
  94                 mbox->trigger = RVU_PF_PFAF_MBOX1;
  95                 mbox->tr_shift = 0;
  96                 break;
  97         case MBOX_DIR_PFVF:
  98         case MBOX_DIR_PFVF_UP:
  99                 mbox->trigger = RVU_PF_VFX_PFVF_MBOX0;
 100                 mbox->tr_shift = 12;
 101                 break;
 102         case MBOX_DIR_VFPF:
 103         case MBOX_DIR_VFPF_UP:
 104                 mbox->trigger = RVU_VF_VFPF_MBOX1;
 105                 mbox->tr_shift = 0;
 106                 break;
 107         default:
 108                 return -ENODEV;
 109         }
 110 
 111         mbox->reg_base = reg_base;
 112         mbox->hwbase = hwbase;
 113         mbox->pdev = pdev;
 114 
 115         mbox->dev = kcalloc(ndevs, sizeof(struct otx2_mbox_dev), GFP_KERNEL);
 116         if (!mbox->dev) {
 117                 otx2_mbox_destroy(mbox);
 118                 return -ENOMEM;
 119         }
 120 
 121         mbox->ndevs = ndevs;
 122         for (devid = 0; devid < ndevs; devid++) {
 123                 mdev = &mbox->dev[devid];
 124                 mdev->mbase = mbox->hwbase + (devid * MBOX_SIZE);
 125                 spin_lock_init(&mdev->mbox_lock);
 126                 /* Init header to reset value */
 127                 otx2_mbox_reset(mbox, devid);
 128         }
 129 
 130         return 0;
 131 }
 132 EXPORT_SYMBOL(otx2_mbox_init);
 133 
 134 int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid)
 135 {
 136         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 137         int timeout = 0, sleep = 1;
 138 
 139         while (mdev->num_msgs != mdev->msgs_acked) {
 140                 msleep(sleep);
 141                 timeout += sleep;
 142                 if (timeout >= MBOX_RSP_TIMEOUT)
 143                         return -EIO;
 144         }
 145         return 0;
 146 }
 147 EXPORT_SYMBOL(otx2_mbox_wait_for_rsp);
 148 
 149 int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid)
 150 {
 151         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 152         unsigned long timeout = jiffies + 1 * HZ;
 153 
 154         while (!time_after(jiffies, timeout)) {
 155                 if (mdev->num_msgs == mdev->msgs_acked)
 156                         return 0;
 157                 cpu_relax();
 158         }
 159         return -EIO;
 160 }
 161 EXPORT_SYMBOL(otx2_mbox_busy_poll_for_rsp);
 162 
 163 void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid)
 164 {
 165         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 166         struct mbox_hdr *tx_hdr, *rx_hdr;
 167 
 168         tx_hdr = mdev->mbase + mbox->tx_start;
 169         rx_hdr = mdev->mbase + mbox->rx_start;
 170 
 171         spin_lock(&mdev->mbox_lock);
 172         /* Reset header for next messages */
 173         mdev->msg_size = 0;
 174         mdev->rsp_size = 0;
 175         mdev->msgs_acked = 0;
 176 
 177         /* Sync mbox data into memory */
 178         smp_wmb();
 179 
 180         /* num_msgs != 0 signals to the peer that the buffer has a number of
 181          * messages.  So this should be written after writing all the messages
 182          * to the shared memory.
 183          */
 184         tx_hdr->num_msgs = mdev->num_msgs;
 185         rx_hdr->num_msgs = 0;
 186         spin_unlock(&mdev->mbox_lock);
 187 
 188         /* The interrupt should be fired after num_msgs is written
 189          * to the shared memory
 190          */
 191         writeq(1, (void __iomem *)mbox->reg_base +
 192                (mbox->trigger | (devid << mbox->tr_shift)));
 193 }
 194 EXPORT_SYMBOL(otx2_mbox_msg_send);
 195 
 196 struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid,
 197                                             int size, int size_rsp)
 198 {
 199         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 200         struct mbox_msghdr *msghdr = NULL;
 201 
 202         spin_lock(&mdev->mbox_lock);
 203         size = ALIGN(size, MBOX_MSG_ALIGN);
 204         size_rsp = ALIGN(size_rsp, MBOX_MSG_ALIGN);
 205         /* Check if there is space in mailbox */
 206         if ((mdev->msg_size + size) > mbox->tx_size - msgs_offset)
 207                 goto exit;
 208         if ((mdev->rsp_size + size_rsp) > mbox->rx_size - msgs_offset)
 209                 goto exit;
 210 
 211         if (mdev->msg_size == 0)
 212                 mdev->num_msgs = 0;
 213         mdev->num_msgs++;
 214 
 215         msghdr = mdev->mbase + mbox->tx_start + msgs_offset + mdev->msg_size;
 216 
 217         /* Clear the whole msg region */
 218         memset(msghdr, 0, sizeof(*msghdr) + size);
 219         /* Init message header with reset values */
 220         msghdr->ver = OTX2_MBOX_VERSION;
 221         mdev->msg_size += size;
 222         mdev->rsp_size += size_rsp;
 223         msghdr->next_msgoff = mdev->msg_size + msgs_offset;
 224 exit:
 225         spin_unlock(&mdev->mbox_lock);
 226 
 227         return msghdr;
 228 }
 229 EXPORT_SYMBOL(otx2_mbox_alloc_msg_rsp);
 230 
 231 struct mbox_msghdr *otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid,
 232                                       struct mbox_msghdr *msg)
 233 {
 234         unsigned long imsg = mbox->tx_start + msgs_offset;
 235         unsigned long irsp = mbox->rx_start + msgs_offset;
 236         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 237         u16 msgs;
 238 
 239         if (mdev->num_msgs != mdev->msgs_acked)
 240                 return ERR_PTR(-ENODEV);
 241 
 242         for (msgs = 0; msgs < mdev->msgs_acked; msgs++) {
 243                 struct mbox_msghdr *pmsg = mdev->mbase + imsg;
 244                 struct mbox_msghdr *prsp = mdev->mbase + irsp;
 245 
 246                 if (msg == pmsg) {
 247                         if (pmsg->id != prsp->id)
 248                                 return ERR_PTR(-ENODEV);
 249                         return prsp;
 250                 }
 251 
 252                 imsg = pmsg->next_msgoff;
 253                 irsp = prsp->next_msgoff;
 254         }
 255 
 256         return ERR_PTR(-ENODEV);
 257 }
 258 EXPORT_SYMBOL(otx2_mbox_get_rsp);
 259 
 260 int
 261 otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid, u16 pcifunc, u16 id)
 262 {
 263         struct msg_rsp *rsp;
 264 
 265         rsp = (struct msg_rsp *)
 266                otx2_mbox_alloc_msg(mbox, devid, sizeof(*rsp));
 267         if (!rsp)
 268                 return -ENOMEM;
 269         rsp->hdr.id = id;
 270         rsp->hdr.sig = OTX2_MBOX_RSP_SIG;
 271         rsp->hdr.rc = MBOX_MSG_INVALID;
 272         rsp->hdr.pcifunc = pcifunc;
 273         return 0;
 274 }
 275 EXPORT_SYMBOL(otx2_reply_invalid_msg);
 276 
 277 bool otx2_mbox_nonempty(struct otx2_mbox *mbox, int devid)
 278 {
 279         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 280         bool ret;
 281 
 282         spin_lock(&mdev->mbox_lock);
 283         ret = mdev->num_msgs != 0;
 284         spin_unlock(&mdev->mbox_lock);
 285 
 286         return ret;
 287 }
 288 EXPORT_SYMBOL(otx2_mbox_nonempty);
 289 
 290 const char *otx2_mbox_id2name(u16 id)
 291 {
 292         switch (id) {
 293 #define M(_name, _id, _1, _2, _3) case _id: return # _name;
 294         MBOX_MESSAGES
 295 #undef M
 296         default:
 297                 return "INVALID ID";
 298         }
 299 }
 300 EXPORT_SYMBOL(otx2_mbox_id2name);
 301 
 302 MODULE_AUTHOR("Marvell International Ltd.");
 303 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */