linux/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c
<<
>>
Prefs
   1/**********************************************************************
   2 * Author: Cavium, Inc.
   3 *
   4 * Contact: support@cavium.com
   5 *          Please include "LiquidIO" in the subject.
   6 *
   7 * Copyright (c) 2003-2016 Cavium, Inc.
   8 *
   9 * This file is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License, Version 2, as
  11 * published by the Free Software Foundation.
  12 *
  13 * This file is distributed in the hope that it will be useful, but
  14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
  15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
  16 * NONINFRINGEMENT.  See the GNU General Public License for more details.
  17 ***********************************************************************/
  18#include <linux/pci.h>
  19#include <linux/netdevice.h>
  20#include "liquidio_common.h"
  21#include "octeon_droq.h"
  22#include "octeon_iq.h"
  23#include "response_manager.h"
  24#include "octeon_device.h"
  25#include "octeon_main.h"
  26#include "octeon_mailbox.h"
  27#include "cn23xx_pf_device.h"
  28
  29/**
  30 * octeon_mbox_read:
  31 * @oct: Pointer mailbox
  32 *
  33 * Reads the 8-bytes of data from the mbox register
  34 * Writes back the acknowldgement inidcating completion of read
  35 */
  36int octeon_mbox_read(struct octeon_mbox *mbox)
  37{
  38        union octeon_mbox_message msg;
  39        int ret = 0;
  40
  41        spin_lock(&mbox->lock);
  42
  43        msg.u64 = readq(mbox->mbox_read_reg);
  44
  45        if ((msg.u64 == OCTEON_PFVFACK) || (msg.u64 == OCTEON_PFVFSIG)) {
  46                spin_unlock(&mbox->lock);
  47                return 0;
  48        }
  49
  50        if (mbox->state & OCTEON_MBOX_STATE_REQUEST_RECEIVING) {
  51                mbox->mbox_req.data[mbox->mbox_req.recv_len - 1] = msg.u64;
  52                mbox->mbox_req.recv_len++;
  53        } else {
  54                if (mbox->state & OCTEON_MBOX_STATE_RESPONSE_RECEIVING) {
  55                        mbox->mbox_resp.data[mbox->mbox_resp.recv_len - 1] =
  56                                msg.u64;
  57                        mbox->mbox_resp.recv_len++;
  58                } else {
  59                        if ((mbox->state & OCTEON_MBOX_STATE_IDLE) &&
  60                            (msg.s.type == OCTEON_MBOX_REQUEST)) {
  61                                mbox->state &= ~OCTEON_MBOX_STATE_IDLE;
  62                                mbox->state |=
  63                                    OCTEON_MBOX_STATE_REQUEST_RECEIVING;
  64                                mbox->mbox_req.msg.u64 = msg.u64;
  65                                mbox->mbox_req.q_no = mbox->q_no;
  66                                mbox->mbox_req.recv_len = 1;
  67                        } else {
  68                                if ((mbox->state &
  69                                     OCTEON_MBOX_STATE_RESPONSE_PENDING) &&
  70                                    (msg.s.type == OCTEON_MBOX_RESPONSE)) {
  71                                        mbox->state &=
  72                                            ~OCTEON_MBOX_STATE_RESPONSE_PENDING;
  73                                        mbox->state |=
  74                                            OCTEON_MBOX_STATE_RESPONSE_RECEIVING
  75                                            ;
  76                                        mbox->mbox_resp.msg.u64 = msg.u64;
  77                                        mbox->mbox_resp.q_no = mbox->q_no;
  78                                        mbox->mbox_resp.recv_len = 1;
  79                                } else {
  80                                        writeq(OCTEON_PFVFERR,
  81                                               mbox->mbox_read_reg);
  82                                        mbox->state |= OCTEON_MBOX_STATE_ERROR;
  83                                        spin_unlock(&mbox->lock);
  84                                        return 1;
  85                                }
  86                        }
  87                }
  88        }
  89
  90        if (mbox->state & OCTEON_MBOX_STATE_REQUEST_RECEIVING) {
  91                if (mbox->mbox_req.recv_len < mbox->mbox_req.msg.s.len) {
  92                        ret = 0;
  93                } else {
  94                        mbox->state &= ~OCTEON_MBOX_STATE_REQUEST_RECEIVING;
  95                        mbox->state |= OCTEON_MBOX_STATE_REQUEST_RECEIVED;
  96                        ret = 1;
  97                }
  98        } else {
  99                if (mbox->state & OCTEON_MBOX_STATE_RESPONSE_RECEIVING) {
 100                        if (mbox->mbox_resp.recv_len <
 101                            mbox->mbox_resp.msg.s.len) {
 102                                ret = 0;
 103                        } else {
 104                                mbox->state &=
 105                                    ~OCTEON_MBOX_STATE_RESPONSE_RECEIVING;
 106                                mbox->state |=
 107                                    OCTEON_MBOX_STATE_RESPONSE_RECEIVED;
 108                                ret = 1;
 109                        }
 110                } else {
 111                        WARN_ON(1);
 112                }
 113        }
 114
 115        writeq(OCTEON_PFVFACK, mbox->mbox_read_reg);
 116
 117        spin_unlock(&mbox->lock);
 118
 119        return ret;
 120}
 121
 122/**
 123 * octeon_mbox_write:
 124 * @oct: Pointer Octeon Device
 125 * @mbox_cmd: Cmd to send to mailbox.
 126 *
 127 * Populates the queue specific mbox structure
 128 * with cmd information.
 129 * Write the cmd to mbox register
 130 */
 131int octeon_mbox_write(struct octeon_device *oct,
 132                      struct octeon_mbox_cmd *mbox_cmd)
 133{
 134        struct octeon_mbox *mbox = oct->mbox[mbox_cmd->q_no];
 135        u32 count, i, ret = OCTEON_MBOX_STATUS_SUCCESS;
 136        long timeout = LIO_MBOX_WRITE_WAIT_TIME;
 137        unsigned long flags;
 138
 139        spin_lock_irqsave(&mbox->lock, flags);
 140
 141        if ((mbox_cmd->msg.s.type == OCTEON_MBOX_RESPONSE) &&
 142            !(mbox->state & OCTEON_MBOX_STATE_REQUEST_RECEIVED)) {
 143                spin_unlock_irqrestore(&mbox->lock, flags);
 144                return OCTEON_MBOX_STATUS_FAILED;
 145        }
 146
 147        if ((mbox_cmd->msg.s.type == OCTEON_MBOX_REQUEST) &&
 148            !(mbox->state & OCTEON_MBOX_STATE_IDLE)) {
 149                spin_unlock_irqrestore(&mbox->lock, flags);
 150                return OCTEON_MBOX_STATUS_BUSY;
 151        }
 152
 153        if (mbox_cmd->msg.s.type == OCTEON_MBOX_REQUEST) {
 154                memcpy(&mbox->mbox_resp, mbox_cmd,
 155                       sizeof(struct octeon_mbox_cmd));
 156                mbox->state = OCTEON_MBOX_STATE_RESPONSE_PENDING;
 157        }
 158
 159        spin_unlock_irqrestore(&mbox->lock, flags);
 160
 161        count = 0;
 162
 163        while (readq(mbox->mbox_write_reg) != OCTEON_PFVFSIG) {
 164                schedule_timeout_uninterruptible(timeout);
 165                if (count++ == LIO_MBOX_WRITE_WAIT_CNT) {
 166                        ret = OCTEON_MBOX_STATUS_FAILED;
 167                        break;
 168                }
 169        }
 170
 171        if (ret == OCTEON_MBOX_STATUS_SUCCESS) {
 172                writeq(mbox_cmd->msg.u64, mbox->mbox_write_reg);
 173                for (i = 0; i < (u32)(mbox_cmd->msg.s.len - 1); i++) {
 174                        count = 0;
 175                        while (readq(mbox->mbox_write_reg) !=
 176                               OCTEON_PFVFACK) {
 177                                schedule_timeout_uninterruptible(timeout);
 178                                if (count++ == LIO_MBOX_WRITE_WAIT_CNT) {
 179                                        ret = OCTEON_MBOX_STATUS_FAILED;
 180                                        break;
 181                                }
 182                        }
 183                        if (ret == OCTEON_MBOX_STATUS_SUCCESS)
 184                                writeq(mbox_cmd->data[i], mbox->mbox_write_reg);
 185                        else
 186                                break;
 187                }
 188        }
 189
 190        spin_lock_irqsave(&mbox->lock, flags);
 191        if (mbox_cmd->msg.s.type == OCTEON_MBOX_RESPONSE) {
 192                mbox->state = OCTEON_MBOX_STATE_IDLE;
 193                writeq(OCTEON_PFVFSIG, mbox->mbox_read_reg);
 194        } else {
 195                if ((!mbox_cmd->msg.s.resp_needed) ||
 196                    (ret == OCTEON_MBOX_STATUS_FAILED)) {
 197                        mbox->state &= ~OCTEON_MBOX_STATE_RESPONSE_PENDING;
 198                        if (!(mbox->state &
 199                              (OCTEON_MBOX_STATE_REQUEST_RECEIVING |
 200                               OCTEON_MBOX_STATE_REQUEST_RECEIVED)))
 201                                mbox->state = OCTEON_MBOX_STATE_IDLE;
 202                }
 203        }
 204        spin_unlock_irqrestore(&mbox->lock, flags);
 205
 206        return ret;
 207}
 208
 209static void get_vf_stats(struct octeon_device *oct,
 210                         struct oct_vf_stats *stats)
 211{
 212        int i;
 213
 214        for (i = 0; i < oct->num_iqs; i++) {
 215                if (!oct->instr_queue[i])
 216                        continue;
 217                stats->tx_packets += oct->instr_queue[i]->stats.tx_done;
 218                stats->tx_bytes += oct->instr_queue[i]->stats.tx_tot_bytes;
 219        }
 220
 221        for (i = 0; i < oct->num_oqs; i++) {
 222                if (!oct->droq[i])
 223                        continue;
 224                stats->rx_packets += oct->droq[i]->stats.rx_pkts_received;
 225                stats->rx_bytes += oct->droq[i]->stats.rx_bytes_received;
 226        }
 227}
 228
 229/**
 230 * octeon_mbox_process_cmd:
 231 * @mbox: Pointer mailbox
 232 * @mbox_cmd: Pointer to command received
 233 *
 234 * Process the cmd received in mbox
 235 */
 236static int octeon_mbox_process_cmd(struct octeon_mbox *mbox,
 237                                   struct octeon_mbox_cmd *mbox_cmd)
 238{
 239        struct octeon_device *oct = mbox->oct_dev;
 240
 241        switch (mbox_cmd->msg.s.cmd) {
 242        case OCTEON_VF_ACTIVE:
 243                dev_dbg(&oct->pci_dev->dev, "got vfactive sending data back\n");
 244                mbox_cmd->msg.s.type = OCTEON_MBOX_RESPONSE;
 245                mbox_cmd->msg.s.resp_needed = 1;
 246                mbox_cmd->msg.s.len = 2;
 247                mbox_cmd->data[0] = 0; /* VF version is in mbox_cmd->data[0] */
 248                ((struct lio_version *)&mbox_cmd->data[0])->major =
 249                        LIQUIDIO_BASE_MAJOR_VERSION;
 250                ((struct lio_version *)&mbox_cmd->data[0])->minor =
 251                        LIQUIDIO_BASE_MINOR_VERSION;
 252                ((struct lio_version *)&mbox_cmd->data[0])->micro =
 253                        LIQUIDIO_BASE_MICRO_VERSION;
 254                memcpy(mbox_cmd->msg.s.params, (uint8_t *)&oct->pfvf_hsword, 6);
 255                /* Sending core cofig info to the corresponding active VF.*/
 256                octeon_mbox_write(oct, mbox_cmd);
 257                break;
 258
 259        case OCTEON_VF_FLR_REQUEST:
 260                dev_info(&oct->pci_dev->dev,
 261                         "got a request for FLR from VF that owns DPI ring %u\n",
 262                         mbox->q_no);
 263                pcie_capability_set_word(
 264                        oct->sriov_info.dpiring_to_vfpcidev_lut[mbox->q_no],
 265                        PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
 266                break;
 267
 268        case OCTEON_PF_CHANGED_VF_MACADDR:
 269                if (OCTEON_CN23XX_VF(oct))
 270                        octeon_pf_changed_vf_macaddr(oct,
 271                                                     mbox_cmd->msg.s.params);
 272                break;
 273
 274        case OCTEON_GET_VF_STATS:
 275                dev_dbg(&oct->pci_dev->dev, "Got VF stats request. Sending data back\n");
 276                mbox_cmd->msg.s.type = OCTEON_MBOX_RESPONSE;
 277                mbox_cmd->msg.s.resp_needed = 1;
 278                mbox_cmd->msg.s.len = 1 +
 279                        sizeof(struct oct_vf_stats) / sizeof(u64);
 280                get_vf_stats(oct, (struct oct_vf_stats *)mbox_cmd->data);
 281                octeon_mbox_write(oct, mbox_cmd);
 282                break;
 283        default:
 284                break;
 285        }
 286        return 0;
 287}
 288
 289/**
 290 *octeon_mbox_process_message:
 291 *
 292 * Process the received mbox message.
 293 */
 294int octeon_mbox_process_message(struct octeon_mbox *mbox)
 295{
 296        struct octeon_mbox_cmd mbox_cmd;
 297        unsigned long flags;
 298
 299        spin_lock_irqsave(&mbox->lock, flags);
 300
 301        if (mbox->state & OCTEON_MBOX_STATE_ERROR) {
 302                if (mbox->state & (OCTEON_MBOX_STATE_RESPONSE_PENDING |
 303                                   OCTEON_MBOX_STATE_RESPONSE_RECEIVING)) {
 304                        memcpy(&mbox_cmd, &mbox->mbox_resp,
 305                               sizeof(struct octeon_mbox_cmd));
 306                        mbox->state = OCTEON_MBOX_STATE_IDLE;
 307                        writeq(OCTEON_PFVFSIG, mbox->mbox_read_reg);
 308                        spin_unlock_irqrestore(&mbox->lock, flags);
 309                        mbox_cmd.recv_status = 1;
 310                        if (mbox_cmd.fn)
 311                                mbox_cmd.fn(mbox->oct_dev, &mbox_cmd,
 312                                            mbox_cmd.fn_arg);
 313                        return 0;
 314                }
 315
 316                mbox->state = OCTEON_MBOX_STATE_IDLE;
 317                writeq(OCTEON_PFVFSIG, mbox->mbox_read_reg);
 318                spin_unlock_irqrestore(&mbox->lock, flags);
 319                return 0;
 320        }
 321
 322        if (mbox->state & OCTEON_MBOX_STATE_RESPONSE_RECEIVED) {
 323                memcpy(&mbox_cmd, &mbox->mbox_resp,
 324                       sizeof(struct octeon_mbox_cmd));
 325                mbox->state = OCTEON_MBOX_STATE_IDLE;
 326                writeq(OCTEON_PFVFSIG, mbox->mbox_read_reg);
 327                spin_unlock_irqrestore(&mbox->lock, flags);
 328                mbox_cmd.recv_status = 0;
 329                if (mbox_cmd.fn)
 330                        mbox_cmd.fn(mbox->oct_dev, &mbox_cmd, mbox_cmd.fn_arg);
 331                return 0;
 332        }
 333
 334        if (mbox->state & OCTEON_MBOX_STATE_REQUEST_RECEIVED) {
 335                memcpy(&mbox_cmd, &mbox->mbox_req,
 336                       sizeof(struct octeon_mbox_cmd));
 337                if (!mbox_cmd.msg.s.resp_needed) {
 338                        mbox->state &= ~OCTEON_MBOX_STATE_REQUEST_RECEIVED;
 339                        if (!(mbox->state &
 340                              OCTEON_MBOX_STATE_RESPONSE_PENDING))
 341                                mbox->state = OCTEON_MBOX_STATE_IDLE;
 342                        writeq(OCTEON_PFVFSIG, mbox->mbox_read_reg);
 343                }
 344
 345                spin_unlock_irqrestore(&mbox->lock, flags);
 346                octeon_mbox_process_cmd(mbox, &mbox_cmd);
 347                return 0;
 348        }
 349
 350        spin_unlock_irqrestore(&mbox->lock, flags);
 351        WARN_ON(1);
 352
 353        return 0;
 354}
 355
 356int octeon_mbox_cancel(struct octeon_device *oct, int q_no)
 357{
 358        struct octeon_mbox *mbox = oct->mbox[q_no];
 359        struct octeon_mbox_cmd *mbox_cmd;
 360        unsigned long flags = 0;
 361
 362        spin_lock_irqsave(&mbox->lock, flags);
 363        mbox_cmd = &mbox->mbox_resp;
 364
 365        if (!(mbox->state & OCTEON_MBOX_STATE_RESPONSE_PENDING)) {
 366                spin_unlock_irqrestore(&mbox->lock, flags);
 367                return 1;
 368        }
 369
 370        mbox->state = OCTEON_MBOX_STATE_IDLE;
 371        memset(mbox_cmd, 0, sizeof(*mbox_cmd));
 372        writeq(OCTEON_PFVFSIG, mbox->mbox_read_reg);
 373        spin_unlock_irqrestore(&mbox->lock, flags);
 374
 375        return 0;
 376}
 377