• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * cxgb3i_ddp.h: Chelsio S3xx iSCSI DDP Manager.
3  *
4  * Copyright (c) 2008 Chelsio Communications, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation.
9  *
10  * Written by: Karen Xie (kxie@chelsio.com)
11  */
12 
13 #ifndef __CXGB3I_ULP2_DDP_H__
14 #define __CXGB3I_ULP2_DDP_H__
15 
16 #include <linux/vmalloc.h>
17 
18 /**
19  * struct cxgb3i_tag_format - cxgb3i ulp tag format for an iscsi entity
20  *
21  * @sw_bits:	# of bits used by iscsi software layer
22  * @rsvd_bits:	# of bits used by h/w
23  * @rsvd_shift:	h/w bits shift left
24  * @rsvd_mask:	reserved bit mask
25  */
26 struct cxgb3i_tag_format {
27 	unsigned char sw_bits;
28 	unsigned char rsvd_bits;
29 	unsigned char rsvd_shift;
30 	unsigned char filler[1];
31 	u32 rsvd_mask;
32 };
33 
34 /**
35  * struct cxgb3i_gather_list - cxgb3i direct data placement memory
36  *
37  * @tag:	ddp tag
38  * @length:	total data buffer length
39  * @offset:	initial offset to the 1st page
40  * @nelem:	# of pages
41  * @pages:	page pointers
42  * @phys_addr:	physical address
43  */
44 struct cxgb3i_gather_list {
45 	u32 tag;
46 	unsigned int length;
47 	unsigned int offset;
48 	unsigned int nelem;
49 	struct page **pages;
50 	dma_addr_t phys_addr[0];
51 };
52 
53 /**
54  * struct cxgb3i_ddp_info - cxgb3i direct data placement for pdu payload
55  *
56  * @list:	list head to link elements
57  * @tdev:	pointer to t3cdev used by cxgb3 driver
58  * @max_txsz:	max tx packet size for ddp
59  * @max_rxsz:	max rx packet size for ddp
60  * @llimit:	lower bound of the page pod memory
61  * @ulimit:	upper bound of the page pod memory
62  * @nppods:	# of page pod entries
63  * @idx_last:	page pod entry last used
64  * @idx_bits:	# of bits the pagepod index would take
65  * @idx_mask:	pagepod index mask
66  * @rsvd_tag_mask: tag mask
67  * @map_lock:	lock to synchonize access to the page pod map
68  * @gl_map:	ddp memory gather list
69  * @gl_skb:	skb used to program the pagepod
70  */
71 struct cxgb3i_ddp_info {
72 	struct list_head list;
73 	struct t3cdev *tdev;
74 	struct pci_dev *pdev;
75 	unsigned int max_txsz;
76 	unsigned int max_rxsz;
77 	unsigned int llimit;
78 	unsigned int ulimit;
79 	unsigned int nppods;
80 	unsigned int idx_last;
81 	unsigned char idx_bits;
82 	unsigned char filler[3];
83 	u32 idx_mask;
84 	u32 rsvd_tag_mask;
85 	spinlock_t map_lock;
86 	struct cxgb3i_gather_list **gl_map;
87 	struct sk_buff **gl_skb;
88 };
89 
90 #define ISCSI_PDU_NONPAYLOAD_LEN	312 /* bhs(48) + ahs(256) + digest(8) */
91 #define ULP2_MAX_PKT_SIZE	16224
92 #define ULP2_MAX_PDU_PAYLOAD	(ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_LEN)
93 #define PPOD_PAGES_MAX		4
94 #define PPOD_PAGES_SHIFT	2	/* 4 pages per pod */
95 
96 /*
97  * struct pagepod_hdr, pagepod - pagepod format
98  */
99 struct pagepod_hdr {
100 	u32 vld_tid;
101 	u32 pgsz_tag_clr;
102 	u32 maxoffset;
103 	u32 pgoffset;
104 	u64 rsvd;
105 };
106 
107 struct pagepod {
108 	struct pagepod_hdr hdr;
109 	u64 addr[PPOD_PAGES_MAX + 1];
110 };
111 
112 #define PPOD_SIZE		sizeof(struct pagepod)	/* 64 */
113 #define PPOD_SIZE_SHIFT		6
114 
115 #define PPOD_COLOR_SHIFT	0
116 #define PPOD_COLOR_SIZE		6
117 #define PPOD_COLOR_MASK		((1 << PPOD_COLOR_SIZE) - 1)
118 
119 #define PPOD_IDX_SHIFT		PPOD_COLOR_SIZE
120 #define PPOD_IDX_MAX_SIZE	24
121 
122 #define S_PPOD_TID    0
123 #define M_PPOD_TID    0xFFFFFF
124 #define V_PPOD_TID(x) ((x) << S_PPOD_TID)
125 
126 #define S_PPOD_VALID    24
127 #define V_PPOD_VALID(x) ((x) << S_PPOD_VALID)
128 #define F_PPOD_VALID    V_PPOD_VALID(1U)
129 
130 #define S_PPOD_COLOR    0
131 #define M_PPOD_COLOR    0x3F
132 #define V_PPOD_COLOR(x) ((x) << S_PPOD_COLOR)
133 
134 #define S_PPOD_TAG    6
135 #define M_PPOD_TAG    0xFFFFFF
136 #define V_PPOD_TAG(x) ((x) << S_PPOD_TAG)
137 
138 #define S_PPOD_PGSZ    30
139 #define M_PPOD_PGSZ    0x3
140 #define V_PPOD_PGSZ(x) ((x) << S_PPOD_PGSZ)
141 
142 /*
143  * large memory chunk allocation/release
144  * use vmalloc() if kmalloc() fails
145  */
cxgb3i_alloc_big_mem(unsigned int size,gfp_t gfp)146 static inline void *cxgb3i_alloc_big_mem(unsigned int size,
147 					 gfp_t gfp)
148 {
149 	void *p = kmalloc(size, gfp);
150 	if (!p)
151 		p = vmalloc(size);
152 	if (p)
153 		memset(p, 0, size);
154 	return p;
155 }
156 
cxgb3i_free_big_mem(void * addr)157 static inline void cxgb3i_free_big_mem(void *addr)
158 {
159 	if (is_vmalloc_addr(addr))
160 		vfree(addr);
161 	else
162 		kfree(addr);
163 }
164 
165 /*
166  * cxgb3i ddp tag are 32 bits, it consists of reserved bits used by h/w and
167  * non-reserved bits that can be used by the iscsi s/w.
168  * The reserved bits are identified by the rsvd_bits and rsvd_shift fields
169  * in struct cxgb3i_tag_format.
170  *
171  * The upper most reserved bit can be used to check if a tag is ddp tag or not:
172  * 	if the bit is 0, the tag is a valid ddp tag
173  */
174 
175 /**
176  * cxgb3i_is_ddp_tag - check if a given tag is a hw/ddp tag
177  * @tformat: tag format information
178  * @tag: tag to be checked
179  *
180  * return true if the tag is a ddp tag, false otherwise.
181  */
cxgb3i_is_ddp_tag(struct cxgb3i_tag_format * tformat,u32 tag)182 static inline int cxgb3i_is_ddp_tag(struct cxgb3i_tag_format *tformat, u32 tag)
183 {
184 	return !(tag & (1 << (tformat->rsvd_bits + tformat->rsvd_shift - 1)));
185 }
186 
187 /**
188  * cxgb3i_sw_tag_usable - check if a given s/w tag has enough bits left for
189  *			  the reserved/hw bits
190  * @tformat: tag format information
191  * @sw_tag: s/w tag to be checked
192  *
193  * return true if the tag is a ddp tag, false otherwise.
194  */
cxgb3i_sw_tag_usable(struct cxgb3i_tag_format * tformat,u32 sw_tag)195 static inline int cxgb3i_sw_tag_usable(struct cxgb3i_tag_format *tformat,
196 					u32 sw_tag)
197 {
198 	sw_tag >>= (32 - tformat->rsvd_bits);
199 	return !sw_tag;
200 }
201 
202 /**
203  * cxgb3i_set_non_ddp_tag - mark a given s/w tag as an invalid ddp tag
204  * @tformat: tag format information
205  * @sw_tag: s/w tag to be checked
206  *
207  * insert 1 at the upper most reserved bit to mark it as an invalid ddp tag.
208  */
cxgb3i_set_non_ddp_tag(struct cxgb3i_tag_format * tformat,u32 sw_tag)209 static inline u32 cxgb3i_set_non_ddp_tag(struct cxgb3i_tag_format *tformat,
210 					 u32 sw_tag)
211 {
212 	unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1;
213 	u32 mask = (1 << shift) - 1;
214 
215 	if (sw_tag && (sw_tag & ~mask)) {
216 		u32 v1 = sw_tag & ((1 << shift) - 1);
217 		u32 v2 = (sw_tag >> (shift - 1)) << shift;
218 
219 		return v2 | v1 | 1 << shift;
220 	}
221 	return sw_tag | 1 << shift;
222 }
223 
224 /**
225  * cxgb3i_ddp_tag_base - shift the s/w tag bits so that reserved bits are not
226  *			 used.
227  * @tformat: tag format information
228  * @sw_tag: s/w tag to be checked
229  */
cxgb3i_ddp_tag_base(struct cxgb3i_tag_format * tformat,u32 sw_tag)230 static inline u32 cxgb3i_ddp_tag_base(struct cxgb3i_tag_format *tformat,
231 				      u32 sw_tag)
232 {
233 	u32 mask = (1 << tformat->rsvd_shift) - 1;
234 
235 	if (sw_tag && (sw_tag & ~mask)) {
236 		u32 v1 = sw_tag & mask;
237 		u32 v2 = sw_tag >> tformat->rsvd_shift;
238 
239 		v2 <<= tformat->rsvd_shift + tformat->rsvd_bits;
240 		return v2 | v1;
241 	}
242 	return sw_tag;
243 }
244 
245 /**
246  * cxgb3i_tag_rsvd_bits - get the reserved bits used by the h/w
247  * @tformat: tag format information
248  * @tag: tag to be checked
249  *
250  * return the reserved bits in the tag
251  */
cxgb3i_tag_rsvd_bits(struct cxgb3i_tag_format * tformat,u32 tag)252 static inline u32 cxgb3i_tag_rsvd_bits(struct cxgb3i_tag_format *tformat,
253 				       u32 tag)
254 {
255 	if (cxgb3i_is_ddp_tag(tformat, tag))
256 		return (tag >> tformat->rsvd_shift) & tformat->rsvd_mask;
257 	return 0;
258 }
259 
260 /**
261  * cxgb3i_tag_nonrsvd_bits - get the non-reserved bits used by the s/w
262  * @tformat: tag format information
263  * @tag: tag to be checked
264  *
265  * return the non-reserved bits in the tag.
266  */
cxgb3i_tag_nonrsvd_bits(struct cxgb3i_tag_format * tformat,u32 tag)267 static inline u32 cxgb3i_tag_nonrsvd_bits(struct cxgb3i_tag_format *tformat,
268 					  u32 tag)
269 {
270 	unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1;
271 	u32 v1, v2;
272 
273 	if (cxgb3i_is_ddp_tag(tformat, tag)) {
274 		v1 = tag & ((1 << tformat->rsvd_shift) - 1);
275 		v2 = (tag >> (shift + 1)) << tformat->rsvd_shift;
276 	} else {
277 		u32 mask = (1 << shift) - 1;
278 
279 		tag &= ~(1 << shift);
280 		v1 = tag & mask;
281 		v2 = (tag >> 1) & ~mask;
282 	}
283 	return v1 | v2;
284 }
285 
286 int cxgb3i_ddp_tag_reserve(struct t3cdev *, unsigned int tid,
287 			   struct cxgb3i_tag_format *, u32 *tag,
288 			   struct cxgb3i_gather_list *, gfp_t gfp);
289 void cxgb3i_ddp_tag_release(struct t3cdev *, u32 tag);
290 
291 struct cxgb3i_gather_list *cxgb3i_ddp_make_gl(unsigned int xferlen,
292 				struct scatterlist *sgl,
293 				unsigned int sgcnt,
294 				struct pci_dev *pdev,
295 				gfp_t gfp);
296 void cxgb3i_ddp_release_gl(struct cxgb3i_gather_list *gl,
297 				struct pci_dev *pdev);
298 
299 int cxgb3i_setup_conn_host_pagesize(struct t3cdev *, unsigned int tid,
300 				    int reply);
301 int cxgb3i_setup_conn_pagesize(struct t3cdev *, unsigned int tid, int reply,
302 			       unsigned long pgsz);
303 int cxgb3i_setup_conn_digest(struct t3cdev *, unsigned int tid,
304 				int hcrc, int dcrc, int reply);
305 int cxgb3i_ddp_find_page_index(unsigned long pgsz);
306 int cxgb3i_adapter_ddp_init(struct t3cdev *, struct cxgb3i_tag_format *,
307 			    unsigned int *txsz, unsigned int *rxsz);
308 void cxgb3i_adapter_ddp_cleanup(struct t3cdev *);
309 #endif
310