summaryrefslogtreecommitdiffstats
path: root/sys/dev/cxgbe/cxgbei/cxgbei_ulp2_ddp.h
blob: f069f09aa47f617c09aa94d3dc15a7d999de7be9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*-
 * Copyright (c) 2012 Chelsio Communications, Inc.
 * All rights reserved.
 *
 * Chelsio T5xx iSCSI driver
 * cxgbei_ulp2_ddp.c: Chelsio iSCSI DDP Manager.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
 *
 * $FreeBSD$
 *
 */

#ifndef __CXGBEI_ULP2_DDP_H__
#define __CXGBEI_ULP2_DDP_H__

#define CXGBEI_PAGE_MASK	(~(PAGE_SIZE-1))
#define DDP_THRESHOLD		2048

/*
 * cxgbei ddp tag are 32 bits, it consists of reserved bits used by h/w and
 * non-reserved bits that can be used by the iscsi s/w.
 * The reserved bits are identified by the rsvd_bits and rsvd_shift fields
 * in struct cxgbei_ulp2_tag_format.
 *
 * The upper most reserved bit can be used to check if a tag is ddp tag or not:
 * 	if the bit is 0, the tag is a valid ddp tag
 */

/*
 * cxgbei_ulp2_is_ddp_tag - check if a given tag is a hw/ddp tag
 * @tformat: tag format information
 * @tag: tag to be checked
 *
 * return true if the tag is a ddp tag, false otherwise.
 */
static inline int
cxgbei_ulp2_is_ddp_tag(struct cxgbei_ulp2_tag_format *tformat, uint32_t tag)
{

	return (!(tag & (1 << (tformat->rsvd_bits + tformat->rsvd_shift - 1))));
}

/*
 * cxgbei_ulp2_sw_tag_usable - check if s/w tag has enough bits left for hw bits
 * @tformat: tag format information
 * @sw_tag: s/w tag to be checked
 *
 * return true if the tag can be used for hw ddp tag, false otherwise.
 */
static inline int
cxgbei_ulp2_sw_tag_usable(struct cxgbei_ulp2_tag_format *tformat,
    uint32_t sw_tag)
{

	return (1);	/* XXXNP: huh? */

	sw_tag >>= (32 - tformat->rsvd_bits + tformat->rsvd_shift);
	return !sw_tag;
}

/*
 * cxgbei_ulp2_set_non_ddp_tag - mark a given s/w tag as an invalid ddp tag
 * @tformat: tag format information
 * @sw_tag: s/w tag to be checked
 *
 * insert 1 at the upper most reserved bit to mark it as an invalid ddp tag.
 */
static inline uint32_t
cxgbei_ulp2_set_non_ddp_tag(struct cxgbei_ulp2_tag_format *tformat,
					 uint32_t sw_tag)
{
	uint32_t rsvd_bits = tformat->rsvd_bits + tformat->rsvd_shift;
	if (sw_tag) {
                u32 v1 = sw_tag & ((1 << (rsvd_bits - 1)) - 1);
                u32 v2 = (sw_tag >> (rsvd_bits - 1)) << rsvd_bits;
                return v2 | (1 << (rsvd_bits - 1)) | v1;
        }

	return sw_tag | (1 << (rsvd_bits - 1)) ;
}

struct dma_segments {
	bus_dmamap_t bus_map;
	bus_addr_t phys_addr;
};
/*
 * struct cxgbei_ulp2_gather_list - cxgbei direct data placement memory
 *
 * @tag:	ddp tag
 * @length:	total data buffer length
 * @offset:	initial offset to the 1st page
 * @nelem:	# of pages
 * @pages:	page pointers
 * @phys_addr:	physical address
 */
struct cxgbei_ulp2_gather_list {
	uint32_t tag;
	uint32_t tid;
	uint32_t port_id;
	void *egress_dev;
	unsigned int length;
	unsigned int offset;
	unsigned int nelem;
	bus_size_t	mapsize;
	bus_dmamap_t	bus_map;
	bus_dma_segment_t	*segments;
	void **pages;
	struct dma_segments dma_sg[0];
};

#define IPPOD_SIZE		sizeof(struct cxgbei_ulp2_pagepod) /* 64 */
#define IPPOD_SIZE_SHIFT	6

#define IPPOD_COLOR_SHIFT	0
#define IPPOD_COLOR_SIZE	6
#define IPPOD_COLOR_MASK	((1 << IPPOD_COLOR_SIZE) - 1)

#define IPPOD_IDX_SHIFT		IPPOD_COLOR_SIZE
#define IPPOD_IDX_MAX_SIZE	24

#define S_IPPOD_TID    0
#define M_IPPOD_TID    0xFFFFFF
#define V_IPPOD_TID(x) ((x) << S_IPPOD_TID)

#define S_IPPOD_VALID    24
#define V_IPPOD_VALID(x) ((x) << S_IPPOD_VALID)
#define F_IPPOD_VALID    V_IPPOD_VALID(1U)

#define S_IPPOD_COLOR    0
#define M_IPPOD_COLOR    0x3F
#define V_IPPOD_COLOR(x) ((x) << S_IPPOD_COLOR)

#define S_IPPOD_TAG    6
#define M_IPPOD_TAG    0xFFFFFF
#define V_IPPOD_TAG(x) ((x) << S_IPPOD_TAG)

#define S_IPPOD_PGSZ    30
#define M_IPPOD_PGSZ    0x3
#define V_IPPOD_PGSZ(x) ((x) << S_IPPOD_PGSZ)

static inline uint32_t
cxgbei_ulp2_ddp_tag_base(u_int idx, u_char *colors,
    struct cxgbei_ulp2_tag_format *tformat, uint32_t sw_tag)
{
	if (__predict_false(++colors[idx] == 1 << IPPOD_IDX_SHIFT))
		colors[idx] = 0;

	sw_tag <<= tformat->rsvd_bits + tformat->rsvd_shift;

	return (sw_tag | idx << IPPOD_IDX_SHIFT | colors[idx]);
}

#define ISCSI_PDU_NONPAYLOAD_LEN	312 /* bhs(48) + ahs(256) + digest(8) */

/*
 * align pdu size to multiple of 512 for better performance
 */
#define cxgbei_align_pdu_size(n) do { n = (n) & (~511); } while (0)

#define ULP2_MAX_PKT_SIZE	16224
#define ULP2_MAX_PDU_PAYLOAD	(ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_LEN)
#define IPPOD_PAGES_MAX		4
#define IPPOD_PAGES_SHIFT	2	/* 4 pages per pod */

/*
 * struct pagepod_hdr, pagepod - pagepod format
 */
struct cxgbei_ulp2_pagepod_hdr {
	uint32_t vld_tid;
	uint32_t pgsz_tag_clr;
	uint32_t maxoffset;
	uint32_t pgoffset;
	uint64_t rsvd;
};

struct cxgbei_ulp2_pagepod {
	struct cxgbei_ulp2_pagepod_hdr hdr;
	uint64_t addr[IPPOD_PAGES_MAX + 1];
};

int cxgbei_ulp2_ddp_tag_reserve(struct cxgbei_data *, void *, unsigned int,
    struct cxgbei_ulp2_tag_format *, uint32_t *,
    struct cxgbei_ulp2_gather_list *, int , int );
void cxgbei_ulp2_ddp_tag_release(struct cxgbei_data *, uint32_t,
    struct icl_cxgbei_conn *);

struct cxgbei_ulp2_gather_list *cxgbei_ulp2_ddp_make_gl_from_iscsi_sgvec(u_int,
    struct cxgbei_sgl *, u_int, struct cxgbei_data *, int);
void cxgbei_ulp2_ddp_release_gl(struct cxgbei_data *,
    struct cxgbei_ulp2_gather_list *);

int cxgbei_ulp2_ddp_find_page_index(u_long);
int cxgbei_ulp2_adapter_ddp_info(struct cxgbei_data *,
    struct cxgbei_ulp2_tag_format *);

void cxgbei_ddp_cleanup(struct cxgbei_data *);
#endif
OpenPOWER on IntegriCloud