Karen Xie | c367346 | 2008-12-09 14:15:32 -0800 | [diff] [blame] | 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 | |
Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 16 | #include <linux/slab.h> |
Karen Xie | 992040f | 2009-02-13 21:38:59 -0800 | [diff] [blame] | 17 | #include <linux/vmalloc.h> |
| 18 | |
Karen Xie | c367346 | 2008-12-09 14:15:32 -0800 | [diff] [blame] | 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 |
Karen Xie | 295ab1b | 2009-06-15 11:15:16 -0700 | [diff] [blame] | 58 | * @refcnt: ref. count |
Karen Xie | c367346 | 2008-12-09 14:15:32 -0800 | [diff] [blame] | 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; |
Karen Xie | 295ab1b | 2009-06-15 11:15:16 -0700 | [diff] [blame] | 75 | struct kref refcnt; |
Karen Xie | c367346 | 2008-12-09 14:15:32 -0800 | [diff] [blame] | 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 | |
Karen Xie | f62d089 | 2009-02-13 21:38:54 -0800 | [diff] [blame] | 93 | #define ISCSI_PDU_NONPAYLOAD_LEN 312 /* bhs(48) + ahs(256) + digest(8) */ |
Karen Xie | c367346 | 2008-12-09 14:15:32 -0800 | [diff] [blame] | 94 | #define ULP2_MAX_PKT_SIZE 16224 |
Karen Xie | f62d089 | 2009-02-13 21:38:54 -0800 | [diff] [blame] | 95 | #define ULP2_MAX_PDU_PAYLOAD (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_LEN) |
Karen Xie | c367346 | 2008-12-09 14:15:32 -0800 | [diff] [blame] | 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 | /** |
Karen Xie | 154229a | 2009-03-05 14:46:08 -0600 | [diff] [blame] | 191 | * cxgb3i_sw_tag_usable - check if s/w tag has enough bits left for hw bits |
Karen Xie | c367346 | 2008-12-09 14:15:32 -0800 | [diff] [blame] | 192 | * @tformat: tag format information |
| 193 | * @sw_tag: s/w tag to be checked |
| 194 | * |
Karen Xie | 154229a | 2009-03-05 14:46:08 -0600 | [diff] [blame] | 195 | * return true if the tag can be used for hw ddp tag, false otherwise. |
Karen Xie | c367346 | 2008-12-09 14:15:32 -0800 | [diff] [blame] | 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 | /** |
Karen Xie | 154229a | 2009-03-05 14:46:08 -0600 | [diff] [blame] | 227 | * cxgb3i_ddp_tag_base - shift s/w tag bits so that reserved bits are not used |
Karen Xie | c367346 | 2008-12-09 14:15:32 -0800 | [diff] [blame] | 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); |
Karen Xie | 9fa1926 | 2009-04-01 13:11:24 -0500 | [diff] [blame] | 307 | int cxgb3i_adapter_ddp_info(struct t3cdev *, struct cxgb3i_tag_format *, |
Karen Xie | c367346 | 2008-12-09 14:15:32 -0800 | [diff] [blame] | 308 | unsigned int *txsz, unsigned int *rxsz); |
Karen Xie | 0d0c27f | 2009-04-01 13:11:27 -0500 | [diff] [blame] | 309 | |
| 310 | void cxgb3i_ddp_init(struct t3cdev *); |
| 311 | void cxgb3i_ddp_cleanup(struct t3cdev *); |
Karen Xie | c367346 | 2008-12-09 14:15:32 -0800 | [diff] [blame] | 312 | #endif |