Back to home page

OSCL-LXR

 
 

    


0001 /**********************************************************************
0002  * Author: Cavium, Inc.
0003  *
0004  * Contact: support@cavium.com
0005  *          Please include "LiquidIO" in the subject.
0006  *
0007  * Copyright (c) 2003-2016 Cavium, Inc.
0008  *
0009  * This file is free software; you can redistribute it and/or modify
0010  * it under the terms of the GNU General Public License, Version 2, as
0011  * published by the Free Software Foundation.
0012  *
0013  * This file is distributed in the hope that it will be useful, but
0014  * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
0015  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
0016  * NONINFRINGEMENT.  See the GNU General Public License for more
0017  * details.
0018  **********************************************************************/
0019 #include <linux/pci.h>
0020 #include <linux/netdevice.h>
0021 #include "liquidio_common.h"
0022 #include "octeon_droq.h"
0023 #include "octeon_iq.h"
0024 #include "response_manager.h"
0025 #include "octeon_device.h"
0026 #include "octeon_nic.h"
0027 #include "octeon_main.h"
0028 
0029 void *
0030 octeon_alloc_soft_command_resp(struct octeon_device    *oct,
0031                    union octeon_instr_64B *cmd,
0032                    u32             rdatasize)
0033 {
0034     struct octeon_soft_command *sc;
0035     struct octeon_instr_ih3  *ih3;
0036     struct octeon_instr_ih2  *ih2;
0037     struct octeon_instr_irh *irh;
0038     struct octeon_instr_rdp *rdp;
0039 
0040     sc = (struct octeon_soft_command *)
0041         octeon_alloc_soft_command(oct, 0, rdatasize, 0);
0042 
0043     if (!sc)
0044         return NULL;
0045 
0046     /* Copy existing command structure into the soft command */
0047     memcpy(&sc->cmd, cmd, sizeof(union octeon_instr_64B));
0048 
0049     /* Add in the response related fields. Opcode and Param are already
0050      * there.
0051      */
0052     if (OCTEON_CN23XX_PF(oct) || OCTEON_CN23XX_VF(oct)) {
0053         ih3      = (struct octeon_instr_ih3 *)&sc->cmd.cmd3.ih3;
0054         rdp     = (struct octeon_instr_rdp *)&sc->cmd.cmd3.rdp;
0055         irh     = (struct octeon_instr_irh *)&sc->cmd.cmd3.irh;
0056         /*pkiih3 + irh + ossp[0] + ossp[1] + rdp + rptr = 40 bytes */
0057         ih3->fsz = LIO_SOFTCMDRESP_IH3;
0058     } else {
0059         ih2      = (struct octeon_instr_ih2 *)&sc->cmd.cmd2.ih2;
0060         rdp     = (struct octeon_instr_rdp *)&sc->cmd.cmd2.rdp;
0061         irh     = (struct octeon_instr_irh *)&sc->cmd.cmd2.irh;
0062         /* irh + ossp[0] + ossp[1] + rdp + rptr = 40 bytes */
0063         ih2->fsz = LIO_SOFTCMDRESP_IH2;
0064     }
0065 
0066     irh->rflag = 1; /* a response is required */
0067 
0068     rdp->pcie_port = oct->pcie_port;
0069     rdp->rlen      = rdatasize;
0070 
0071     *sc->status_word = COMPLETION_WORD_INIT;
0072 
0073     if (OCTEON_CN23XX_PF(oct) || OCTEON_CN23XX_VF(oct))
0074         sc->cmd.cmd3.rptr =  sc->dmarptr;
0075     else
0076         sc->cmd.cmd2.rptr =  sc->dmarptr;
0077 
0078     sc->expiry_time = jiffies + msecs_to_jiffies(LIO_SC_MAX_TMO_MS);
0079 
0080     return sc;
0081 }
0082 
0083 int octnet_send_nic_data_pkt(struct octeon_device *oct,
0084                  struct octnic_data_pkt *ndata,
0085                  int xmit_more)
0086 {
0087     int ring_doorbell = !xmit_more;
0088 
0089     return octeon_send_command(oct, ndata->q_no, ring_doorbell, &ndata->cmd,
0090                    ndata->buf, ndata->datasize,
0091                    ndata->reqtype);
0092 }
0093 
0094 static inline struct octeon_soft_command
0095 *octnic_alloc_ctrl_pkt_sc(struct octeon_device *oct,
0096               struct octnic_ctrl_pkt *nctrl)
0097 {
0098     struct octeon_soft_command *sc = NULL;
0099     u8 *data;
0100     u32 rdatasize;
0101     u32 uddsize = 0, datasize = 0;
0102 
0103     uddsize = (u32)(nctrl->ncmd.s.more * 8);
0104 
0105     datasize = OCTNET_CMD_SIZE + uddsize;
0106     rdatasize = 16;
0107 
0108     sc = (struct octeon_soft_command *)
0109         octeon_alloc_soft_command(oct, datasize, rdatasize, 0);
0110 
0111     if (!sc)
0112         return NULL;
0113 
0114     data = (u8 *)sc->virtdptr;
0115 
0116     memcpy(data, &nctrl->ncmd, OCTNET_CMD_SIZE);
0117 
0118     octeon_swap_8B_data((u64 *)data, (OCTNET_CMD_SIZE >> 3));
0119 
0120     if (uddsize) {
0121         /* Endian-Swap for UDD should have been done by caller. */
0122         memcpy(data + OCTNET_CMD_SIZE, nctrl->udd, uddsize);
0123     }
0124 
0125     sc->iq_no = (u32)nctrl->iq_no;
0126 
0127     octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_CMD,
0128                     0, 0, 0);
0129 
0130     init_completion(&sc->complete);
0131     sc->sc_status = OCTEON_REQUEST_PENDING;
0132 
0133     return sc;
0134 }
0135 
0136 int
0137 octnet_send_nic_ctrl_pkt(struct octeon_device *oct,
0138              struct octnic_ctrl_pkt *nctrl)
0139 {
0140     int retval;
0141     struct octeon_soft_command *sc = NULL;
0142 
0143     spin_lock_bh(&oct->cmd_resp_wqlock);
0144     /* Allow only rx ctrl command to stop traffic on the chip
0145      * during offline operations
0146      */
0147     if ((oct->cmd_resp_state == OCT_DRV_OFFLINE) &&
0148         (nctrl->ncmd.s.cmd != OCTNET_CMD_RX_CTL)) {
0149         spin_unlock_bh(&oct->cmd_resp_wqlock);
0150         dev_err(&oct->pci_dev->dev,
0151             "%s cmd:%d not processed since driver offline\n",
0152             __func__, nctrl->ncmd.s.cmd);
0153         return -1;
0154     }
0155 
0156     sc = octnic_alloc_ctrl_pkt_sc(oct, nctrl);
0157     if (!sc) {
0158         dev_err(&oct->pci_dev->dev, "%s soft command alloc failed\n",
0159             __func__);
0160         spin_unlock_bh(&oct->cmd_resp_wqlock);
0161         return -1;
0162     }
0163 
0164     retval = octeon_send_soft_command(oct, sc);
0165     if (retval == IQ_SEND_FAILED) {
0166         octeon_free_soft_command(oct, sc);
0167         dev_err(&oct->pci_dev->dev, "%s pf_num:%d soft command:%d send failed status: %x\n",
0168             __func__, oct->pf_num, nctrl->ncmd.s.cmd, retval);
0169         spin_unlock_bh(&oct->cmd_resp_wqlock);
0170         return -1;
0171     }
0172 
0173     spin_unlock_bh(&oct->cmd_resp_wqlock);
0174 
0175     if (nctrl->ncmd.s.cmdgroup == 0) {
0176         switch (nctrl->ncmd.s.cmd) {
0177             /* caller holds lock, can not sleep */
0178         case OCTNET_CMD_CHANGE_DEVFLAGS:
0179         case OCTNET_CMD_SET_MULTI_LIST:
0180         case OCTNET_CMD_SET_UC_LIST:
0181             WRITE_ONCE(sc->caller_is_done, true);
0182             return retval;
0183         }
0184     }
0185 
0186     retval = wait_for_sc_completion_timeout(oct, sc, 0);
0187     if (retval)
0188         return (retval);
0189 
0190     nctrl->sc_status = sc->sc_status;
0191     retval = nctrl->sc_status;
0192     if (nctrl->cb_fn)
0193         nctrl->cb_fn(nctrl);
0194 
0195     WRITE_ONCE(sc->caller_is_done, true);
0196 
0197     return retval;
0198 }