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