root/sys/dev/liquidio/base/lio_iq.h
/*
 *   BSD LICENSE
 *
 *   Copyright(c) 2017 Cavium, Inc.. All rights reserved.
 *   All rights reserved.
 *
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *     * Neither the name of Cavium, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *   OWNER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*   \file  lio_iq.h
 *   \brief Host Driver: Implementation of Octeon input queues. "Input" is
 *   with respect to the Octeon device on the NIC. From this driver's
 *   point of view they are egress queues.
 */

#ifndef __LIO_IQ_H__
#define __LIO_IQ_H__

#define LIO_IQ_SEND_OK          0
#define LIO_IQ_SEND_STOP        1
#define LIO_IQ_SEND_FAILED     -1

/*-------------------------  INSTRUCTION QUEUE --------------------------*/

#define LIO_REQTYPE_NONE                 0
#define LIO_REQTYPE_NORESP_NET           1
#define LIO_REQTYPE_NORESP_NET_SG        2
#define LIO_REQTYPE_RESP_NET             3
#define LIO_REQTYPE_SOFT_COMMAND         4

/*
 * This structure is used by NIC driver to store information required
 * to free the mbuf when the packet has been fetched by Octeon.
 * Bytes offset below assume worst-case of a 64-bit system.
 */
struct lio_mbuf_free_info {
        /* Pointer to mbuf. */
        struct mbuf             *mb;

        /* Pointer to gather list. */
        struct lio_gather       *g;

        bus_dmamap_t            map;
};

struct lio_request_list {
        uint32_t                        reqtype;
        void                            *buf;
        bus_dmamap_t                    map;
        struct lio_mbuf_free_info       finfo;
};

/* Input Queue statistics. Each input queue has four stats fields. */
struct lio_iq_stats {
        uint64_t        instr_posted;           /**< Instructions posted to this queue. */
        uint64_t        instr_processed;        /**< Instructions processed in this queue. */
        uint64_t        instr_dropped;          /**< Instructions that could not be processed */
        uint64_t        bytes_sent;             /**< Bytes sent through this queue. */
        uint64_t        sgentry_sent;           /**< Gather entries sent through this queue. */
        uint64_t        tx_done;                /**< Num of packets sent to network. */
        uint64_t        tx_iq_busy;             /**< Numof times this iq was found to be full. */
        uint64_t        tx_dropped;             /**< Numof pkts dropped dueto xmitpath errors. */
        uint64_t        tx_tot_bytes;           /**< Total count of bytes sento to network. */
        uint64_t        tx_gso;                 /* count of tso */
        uint64_t        tx_vxlan;               /* tunnel */
        uint64_t        tx_dmamap_fail;
        uint64_t        tx_restart;
        uint64_t        mbuf_defrag_failed;
};

/*
 *  The instruction (input) queue.
 *  The input queue is used to post raw (instruction) mode data or packet
 *  data to Octeon device from the host. Each input queue for
 *  a Octeon device has one such structure to represent it.
 */
struct lio_instr_queue {
        struct octeon_device    *oct_dev;

        /* A lock to protect access to the input ring.  */
        struct mtx              lock;

        /* A lock to protect while enqueue to the input ring.  */
        struct mtx              enq_lock;

        /* A lock to protect while posting on the ring.  */
        struct mtx              post_lock;

        uint32_t                pkt_in_done;

        /* A lock to protect access to the input ring. */
        struct mtx              iq_flush_running_lock;

        /* Flag that indicates if the queue uses 64 byte commands. */
        uint32_t                iqcmd_64B:1;

        /* Queue info. */
        union octeon_txpciq     txpciq;

        uint32_t                rsvd:17;

        uint32_t                status:8;

        /* Maximum no. of instructions in this queue. */
        uint32_t                max_count;

        /* Index in input ring where the driver should write the next packet */
        uint32_t                host_write_index;

        /*
         * Index in input ring where Octeon is expected to read the next
         * packet.
         */
        uint32_t                octeon_read_index;

        /*
         * This index aids in finding the window in the queue where Octeon
         * has read the commands.
         */
        uint32_t                flush_index;

        /* This field keeps track of the instructions pending in this queue. */
        volatile int            instr_pending;

        uint32_t                reset_instr_cnt;

        /* Pointer to the Virtual Base addr of the input ring. */
        uint8_t                 *base_addr;
        bus_dma_tag_t           txtag;

        struct lio_request_list *request_list;

        struct buf_ring         *br;

        /* Octeon doorbell register for the ring. */
        uint32_t                doorbell_reg;

        /* Octeon instruction count register for this ring. */
        uint32_t                inst_cnt_reg;

        /* Number of instructions pending to be posted to Octeon. */
        uint32_t                fill_cnt;

        /* The last time that the doorbell was rung. */
        uint64_t                last_db_time;

        /*
         * The doorbell timeout. If the doorbell was not rung for this time
         * and fill_cnt is non-zero, ring the doorbell again.
         */
        uint32_t                db_timeout;

        /* Statistics for this input queue. */
        struct lio_iq_stats     stats;

        /* DMA mapped base address of the input descriptor ring. */
        uint64_t                base_addr_dma;

        /* Application context */
        void                    *app_ctx;

        /* network stack queue index */
        int                     q_index;

        /* os ifidx associated with this queue */
        int                     ifidx;

};

/*----------------------  INSTRUCTION FORMAT ----------------------------*/

struct lio_instr3_64B {
        /* Pointer where the input data is available. */
        uint64_t        dptr;

        /* Instruction Header. */
        uint64_t        ih3;

        /* Instruction Header. */
        uint64_t        pki_ih3;

        /* Input Request Header. */
        uint64_t        irh;

        /* opcode/subcode specific parameters */
        uint64_t        ossp[2];

        /* Return Data Parameters */
        uint64_t        rdp;

        /*
         * Pointer where the response for a RAW mode packet will be written
         * by Octeon.
         */
        uint64_t        rptr;

};

union lio_instr_64B {
        struct lio_instr3_64B   cmd3;
};

/* The size of each buffer in soft command buffer pool */
#define LIO_SOFT_COMMAND_BUFFER_SIZE    2048

struct lio_soft_command {
        /* Soft command buffer info. */
        struct lio_stailq_node  node;
        uint64_t                dma_addr;
        uint32_t                size;

        /* Command and return status */
        union lio_instr_64B     cmd;

#define COMPLETION_WORD_INIT    0xffffffffffffffffULL
        uint64_t                *status_word;

        /* Data buffer info */
        void                    *virtdptr;
        uint64_t                dmadptr;
        uint32_t                datasize;

        /* Return buffer info */
        void                    *virtrptr;
        uint64_t                dmarptr;
        uint32_t                rdatasize;

        /* Context buffer info */
        void                    *ctxptr;
        uint32_t                ctxsize;

        /* Time out and callback */
        int                     wait_time;
        int                     timeout;
        uint32_t                iq_no;
        void                    (*callback) (struct octeon_device *, uint32_t,
                                             void *);
        void                    *callback_arg;
};

/* Maximum number of buffers to allocate into soft command buffer pool */
#define LIO_MAX_SOFT_COMMAND_BUFFERS    256

/* Head of a soft command buffer pool. */
struct lio_sc_buffer_pool {
        /* List structure to add delete pending entries to */
        struct lio_stailq_head  head;

        /* A lock for this response list */
        struct mtx              lock;

        volatile uint32_t       alloc_buf_count;
};

#define LIO_INCR_INSTRQUEUE_PKT_COUNT(octeon_dev_ptr, iq_no, field, count) \
                (((octeon_dev_ptr)->instr_queue[iq_no]->stats.field) += count)

int     lio_setup_sc_buffer_pool(struct octeon_device *oct);
int     lio_free_sc_buffer_pool(struct octeon_device *oct);
struct lio_soft_command *lio_alloc_soft_command(struct octeon_device *oct,
                                                uint32_t datasize,
                                                uint32_t rdatasize,
                                                uint32_t ctxsize);
void    lio_free_soft_command(struct octeon_device *oct,
                              struct lio_soft_command *sc);

/*
 *  lio_init_instr_queue()
 *  @param octeon_dev      - pointer to the octeon device structure.
 *  @param txpciq          - queue to be initialized (0 <= q_no <= 3).
 *
 *  Called at driver init time for each input queue. iq_conf has the
 *  configuration parameters for the queue.
 *
 *  @return  Success: 0   Failure: 1
 */
int     lio_init_instr_queue(struct octeon_device *octeon_dev,
                             union octeon_txpciq txpciq, uint32_t num_descs);

/*
 *  lio_delete_instr_queue()
 *  @param octeon_dev      - pointer to the octeon device structure.
 *  @param iq_no           - queue to be deleted
 *
 *  Called at driver unload time for each input queue. Deletes all
 *  allocated resources for the input queue.
 *
 *  @return  Success: 0   Failure: 1
 */
int     lio_delete_instr_queue(struct octeon_device *octeon_dev,
                               uint32_t iq_no);

int     lio_wait_for_instr_fetch(struct octeon_device *oct);

int     lio_process_iq_request_list(struct octeon_device *oct,
                                    struct lio_instr_queue *iq,
                                    uint32_t budget);

int     lio_send_command(struct octeon_device *oct, uint32_t iq_no,
                         uint32_t force_db, void *cmd, void *buf,
                         uint32_t datasize, uint32_t reqtype);

void    lio_prepare_soft_command(struct octeon_device *oct,
                                 struct lio_soft_command *sc,
                                 uint8_t opcode, uint8_t subcode,
                                 uint32_t irh_ossp, uint64_t ossp0,
                                 uint64_t ossp1);

int     lio_send_soft_command(struct octeon_device *oct,
                              struct lio_soft_command *sc);

int     lio_setup_iq(struct octeon_device *oct, int ifidx,
                     int q_index, union octeon_txpciq iq_no,
                     uint32_t num_descs);
int     lio_flush_iq(struct octeon_device *oct, struct lio_instr_queue *iq,
                     uint32_t budget);
#endif  /* __LIO_IQ_H__ */