blob: 0c0dd9a658cc254d007560c2fe861860727c8743 [file] [log] [blame]
/*
* This file is part of the Chelsio FCoE driver for Linux.
*
* Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __CSIO_WR_H__
#define __CSIO_WR_H__
#include <linux/cache.h>
#include "csio_defs.h"
#include "t4fw_api.h"
#include "t4fw_api_stor.h"
/*
* SGE register field values.
*/
#define X_INGPCIEBOUNDARY_32B 0
#define X_INGPCIEBOUNDARY_64B 1
#define X_INGPCIEBOUNDARY_128B 2
#define X_INGPCIEBOUNDARY_256B 3
#define X_INGPCIEBOUNDARY_512B 4
#define X_INGPCIEBOUNDARY_1024B 5
#define X_INGPCIEBOUNDARY_2048B 6
#define X_INGPCIEBOUNDARY_4096B 7
/* GTS register */
#define X_TIMERREG_COUNTER0 0
#define X_TIMERREG_COUNTER1 1
#define X_TIMERREG_COUNTER2 2
#define X_TIMERREG_COUNTER3 3
#define X_TIMERREG_COUNTER4 4
#define X_TIMERREG_COUNTER5 5
#define X_TIMERREG_RESTART_COUNTER 6
#define X_TIMERREG_UPDATE_CIDX 7
/*
* Egress Context field values
*/
#define X_FETCHBURSTMIN_16B 0
#define X_FETCHBURSTMIN_32B 1
#define X_FETCHBURSTMIN_64B 2
#define X_FETCHBURSTMIN_128B 3
#define X_FETCHBURSTMAX_64B 0
#define X_FETCHBURSTMAX_128B 1
#define X_FETCHBURSTMAX_256B 2
#define X_FETCHBURSTMAX_512B 3
#define X_HOSTFCMODE_NONE 0
#define X_HOSTFCMODE_INGRESS_QUEUE 1
#define X_HOSTFCMODE_STATUS_PAGE 2
#define X_HOSTFCMODE_BOTH 3
/*
* Ingress Context field values
*/
#define X_UPDATESCHEDULING_TIMER 0
#define X_UPDATESCHEDULING_COUNTER_OPTTIMER 1
#define X_UPDATEDELIVERY_NONE 0
#define X_UPDATEDELIVERY_INTERRUPT 1
#define X_UPDATEDELIVERY_STATUS_PAGE 2
#define X_UPDATEDELIVERY_BOTH 3
#define X_INTERRUPTDESTINATION_PCIE 0
#define X_INTERRUPTDESTINATION_IQ 1
#define X_RSPD_TYPE_FLBUF 0
#define X_RSPD_TYPE_CPL 1
#define X_RSPD_TYPE_INTR 2
/* WR status is at the same position as retval in a CMD header */
#define csio_wr_status(_wr) \
(FW_CMD_RETVAL_G(ntohl(((struct fw_cmd_hdr *)(_wr))->lo)))
struct csio_hw;
extern int csio_intr_coalesce_cnt;
extern int csio_intr_coalesce_time;
/* Ingress queue params */
struct csio_iq_params {
uint8_t iq_start:1;
uint8_t iq_stop:1;
uint8_t pfn:3;
uint8_t vfn;
uint16_t physiqid;
uint16_t iqid;
uint16_t fl0id;
uint16_t fl1id;
uint8_t viid;
uint8_t type;
uint8_t iqasynch;
uint8_t reserved4;
uint8_t iqandst;
uint8_t iqanus;
uint8_t iqanud;
uint16_t iqandstindex;
uint8_t iqdroprss;
uint8_t iqpciech;
uint8_t iqdcaen;
uint8_t iqdcacpu;
uint8_t iqintcntthresh;
uint8_t iqo;
uint8_t iqcprio;
uint8_t iqesize;
uint16_t iqsize;
uint64_t iqaddr;
uint8_t iqflintiqhsen;
uint8_t reserved5;
uint8_t iqflintcongen;
uint8_t iqflintcngchmap;
uint32_t reserved6;
uint8_t fl0hostfcmode;
uint8_t fl0cprio;
uint8_t fl0paden;
uint8_t fl0packen;
uint8_t fl0congen;
uint8_t fl0dcaen;
uint8_t fl0dcacpu;
uint8_t fl0fbmin;
uint8_t fl0fbmax;
uint8_t fl0cidxfthresho;
uint8_t fl0cidxfthresh;
uint16_t fl0size;
uint64_t fl0addr;
uint64_t reserved7;
uint8_t fl1hostfcmode;
uint8_t fl1cprio;
uint8_t fl1paden;
uint8_t fl1packen;
uint8_t fl1congen;
uint8_t fl1dcaen;
uint8_t fl1dcacpu;
uint8_t fl1fbmin;
uint8_t fl1fbmax;
uint8_t fl1cidxfthresho;
uint8_t fl1cidxfthresh;
uint16_t fl1size;
uint64_t fl1addr;
};
/* Egress queue params */
struct csio_eq_params {
uint8_t pfn;
uint8_t vfn;
uint8_t eqstart:1;
uint8_t eqstop:1;
uint16_t physeqid;
uint32_t eqid;
uint8_t hostfcmode:2;
uint8_t cprio:1;
uint8_t pciechn:3;
uint16_t iqid;
uint8_t dcaen:1;
uint8_t dcacpu:5;
uint8_t fbmin:3;
uint8_t fbmax:3;
uint8_t cidxfthresho:1;
uint8_t cidxfthresh:3;
uint16_t eqsize;
uint64_t eqaddr;
};
struct csio_dma_buf {
struct list_head list;
void *vaddr; /* Virtual address */
dma_addr_t paddr; /* Physical address */
uint32_t len; /* Buffer size */
};
/* Generic I/O request structure */
struct csio_ioreq {
struct csio_sm sm; /* SM, List
* should be the first member
*/
int iq_idx; /* Ingress queue index */
int eq_idx; /* Egress queue index */
uint32_t nsge; /* Number of SG elements */
uint32_t tmo; /* Driver timeout */
uint32_t datadir; /* Data direction */
struct csio_dma_buf dma_buf; /* Req/resp DMA buffers */
uint16_t wr_status; /* WR completion status */
int16_t drv_status; /* Driver internal status */
struct csio_lnode *lnode; /* Owner lnode */
struct csio_rnode *rnode; /* Src/destination rnode */
void (*io_cbfn) (struct csio_hw *, struct csio_ioreq *);
/* completion callback */
void *scratch1; /* Scratch area 1.
*/
void *scratch2; /* Scratch area 2. */
struct list_head gen_list; /* Any list associated with
* this ioreq.
*/
uint64_t fw_handle; /* Unique handle passed
* to FW
*/
uint8_t dcopy; /* Data copy required */
uint8_t reserved1;
uint16_t reserved2;
struct completion cmplobj; /* ioreq completion object */
} ____cacheline_aligned_in_smp;
/*
* Egress status page for egress cidx updates
*/
struct csio_qstatus_page {
__be32 qid;
__be16 cidx;
__be16 pidx;
};
enum {
CSIO_MAX_FLBUF_PER_IQWR = 4,
CSIO_QCREDIT_SZ = 64, /* pidx/cidx increments
* in bytes
*/
CSIO_MAX_QID = 0xFFFF,
CSIO_MAX_IQ = 128,
CSIO_SGE_NTIMERS = 6,
CSIO_SGE_NCOUNTERS = 4,
CSIO_SGE_FL_SIZE_REGS = 16,
};
/* Defines for type */
enum {
CSIO_EGRESS = 1,
CSIO_INGRESS = 2,
CSIO_FREELIST = 3,
};
/*
* Structure for footer (last 2 flits) of Ingress Queue Entry.
*/
struct csio_iqwr_footer {
__be32 hdrbuflen_pidx;
__be32 pldbuflen_qid;
union {
u8 type_gen;
__be64 last_flit;
} u;
};
#define IQWRF_NEWBUF (1 << 31)
#define IQWRF_LEN_GET(x) (((x) >> 0) & 0x7fffffffU)
#define IQWRF_GEN_SHIFT 7
#define IQWRF_TYPE_GET(x) (((x) >> 4) & 0x3U)
/*
* WR pair:
* ========
* A WR can start towards the end of a queue, and then continue at the
* beginning, since the queue is considered to be circular. This will
* require a pair of address/len to be passed back to the caller -
* hence the Work request pair structure.
*/
struct csio_wr_pair {
void *addr1;
uint32_t size1;
void *addr2;
uint32_t size2;
};
/*
* The following structure is used by ingress processing to return the
* free list buffers to consumers.
*/
struct csio_fl_dma_buf {
struct csio_dma_buf flbufs[CSIO_MAX_FLBUF_PER_IQWR];
/* Freelist DMA buffers */
int offset; /* Offset within the
* first FL buf.
*/
uint32_t totlen; /* Total length */
uint8_t defer_free; /* Free of buffer can
* deferred
*/
};
/* Data-types */
typedef void (*iq_handler_t)(struct csio_hw *, void *, uint32_t,
struct csio_fl_dma_buf *, void *);
struct csio_iq {
uint16_t iqid; /* Queue ID */
uint16_t physiqid; /* Physical Queue ID */
uint16_t genbit; /* Generation bit,
* initially set to 1
*/
int flq_idx; /* Freelist queue index */
iq_handler_t iq_intx_handler; /* IQ INTx handler routine */
};
struct csio_eq {
uint16_t eqid; /* Qid */
uint16_t physeqid; /* Physical Queue ID */
uint8_t wrap[512]; /* Temp area for q-wrap around*/
};
struct csio_fl {
uint16_t flid; /* Qid */
uint16_t packen; /* Packing enabled? */
int offset; /* Offset within FL buf */
int sreg; /* Size register */
struct csio_dma_buf *bufs; /* Free list buffer ptr array
* indexed using flq->cidx/pidx
*/
};
struct csio_qstats {
uint32_t n_tot_reqs; /* Total no. of Requests */
uint32_t n_tot_rsps; /* Total no. of responses */
uint32_t n_qwrap; /* Queue wraps */
uint32_t n_eq_wr_split; /* Number of split EQ WRs */
uint32_t n_qentry; /* Queue entry */
uint32_t n_qempty; /* Queue empty */
uint32_t n_qfull; /* Queue fulls */
uint32_t n_rsp_unknown; /* Unknown response type */
uint32_t n_stray_comp; /* Stray completion intr */
uint32_t n_flq_refill; /* Number of FL refills */
};
/* Queue metadata */
struct csio_q {
uint16_t type; /* Type: Ingress/Egress/FL */
uint16_t pidx; /* producer index */
uint16_t cidx; /* consumer index */
uint16_t inc_idx; /* Incremental index */
uint32_t wr_sz; /* Size of all WRs in this q
* if fixed
*/
void *vstart; /* Base virtual address
* of queue
*/
void *vwrap; /* Virtual end address to
* wrap around at
*/
uint32_t credits; /* Size of queue in credits */
void *owner; /* Owner */
union { /* Queue contexts */
struct csio_iq iq;
struct csio_eq eq;
struct csio_fl fl;
} un;
dma_addr_t pstart; /* Base physical address of
* queue
*/
uint32_t portid; /* PCIE Channel */
uint32_t size; /* Size of queue in bytes */
struct csio_qstats stats; /* Statistics */
} ____cacheline_aligned_in_smp;
struct csio_sge {
uint32_t csio_fl_align; /* Calculated and cached
* for fast path
*/
uint32_t sge_control; /* padding, boundaries,
* lengths, etc.
*/
uint32_t sge_host_page_size; /* Host page size */
uint32_t sge_fl_buf_size[CSIO_SGE_FL_SIZE_REGS];
/* free list buffer sizes */
uint16_t timer_val[CSIO_SGE_NTIMERS];
uint8_t counter_val[CSIO_SGE_NCOUNTERS];
};
/* Work request module */
struct csio_wrm {
int num_q; /* Number of queues */
struct csio_q **q_arr; /* Array of queue pointers
* allocated dynamically
* based on configured values
*/
uint32_t fw_iq_start; /* Start ID of IQ for this fn*/
uint32_t fw_eq_start; /* Start ID of EQ for this fn*/
struct csio_q *intr_map[CSIO_MAX_IQ];
/* IQ-id to IQ map table. */
int free_qidx; /* queue idx of free queue */
struct csio_sge sge; /* SGE params */
};
#define csio_get_q(__hw, __idx) ((__hw)->wrm.q_arr[__idx])
#define csio_q_type(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->type)
#define csio_q_pidx(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->pidx)
#define csio_q_cidx(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->cidx)
#define csio_q_inc_idx(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->inc_idx)
#define csio_q_vstart(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->vstart)
#define csio_q_pstart(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->pstart)
#define csio_q_size(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->size)
#define csio_q_credits(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->credits)
#define csio_q_portid(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->portid)
#define csio_q_wr_sz(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->wr_sz)
#define csio_q_iqid(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->un.iq.iqid)
#define csio_q_physiqid(__hw, __idx) \
((__hw)->wrm.q_arr[(__idx)]->un.iq.physiqid)
#define csio_q_iq_flq_idx(__hw, __idx) \
((__hw)->wrm.q_arr[(__idx)]->un.iq.flq_idx)
#define csio_q_eqid(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->un.eq.eqid)
#define csio_q_flid(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->un.fl.flid)
#define csio_q_physeqid(__hw, __idx) \
((__hw)->wrm.q_arr[(__idx)]->un.eq.physeqid)
#define csio_iq_has_fl(__iq) ((__iq)->un.iq.flq_idx != -1)
#define csio_q_iq_to_flid(__hw, __iq_idx) \
csio_q_flid((__hw), (__hw)->wrm.q_arr[(__iq_qidx)]->un.iq.flq_idx)
#define csio_q_set_intr_map(__hw, __iq_idx, __rel_iq_id) \
(__hw)->wrm.intr_map[__rel_iq_id] = csio_get_q(__hw, __iq_idx)
#define csio_q_eq_wrap(__hw, __idx) ((__hw)->wrm.q_arr[(__idx)]->un.eq.wrap)
struct csio_mb;
int csio_wr_alloc_q(struct csio_hw *, uint32_t, uint32_t,
uint16_t, void *, uint32_t, int, iq_handler_t);
int csio_wr_iq_create(struct csio_hw *, void *, int,
uint32_t, uint8_t, bool,
void (*)(struct csio_hw *, struct csio_mb *));
int csio_wr_eq_create(struct csio_hw *, void *, int, int, uint8_t,
void (*)(struct csio_hw *, struct csio_mb *));
int csio_wr_destroy_queues(struct csio_hw *, bool cmd);
int csio_wr_get(struct csio_hw *, int, uint32_t,
struct csio_wr_pair *);
void csio_wr_copy_to_wrp(void *, struct csio_wr_pair *, uint32_t, uint32_t);
int csio_wr_issue(struct csio_hw *, int, bool);
int csio_wr_process_iq(struct csio_hw *, struct csio_q *,
void (*)(struct csio_hw *, void *,
uint32_t, struct csio_fl_dma_buf *,
void *),
void *);
int csio_wr_process_iq_idx(struct csio_hw *, int,
void (*)(struct csio_hw *, void *,
uint32_t, struct csio_fl_dma_buf *,
void *),
void *);
void csio_wr_sge_init(struct csio_hw *);
int csio_wrm_init(struct csio_wrm *, struct csio_hw *);
void csio_wrm_exit(struct csio_wrm *, struct csio_hw *);
#endif /* ifndef __CSIO_WR_H__ */