diff options
| author | Yuval Mintz <Yuval.Mintz@qlogic.com> | 2016-06-03 07:35:32 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2016-06-03 20:08:39 -0400 |
| commit | a91eb52abb504a1dd3248a5d07b54e7f95d5fcf1 (patch) | |
| tree | 704b48fd0bd99efd5085cd7307e67506cbb36a6f /include/linux/qed | |
| parent | 330348d94223346f855357fab2517f6c903001c7 (diff) | |
qed: Revisit chain implementation
RoCE driver is going to need a 32-bit chain [current chain implementation
for qed* currently supports only 16-bit producer/consumer chains].
This patch adds said support, as well as doing other slight tweaks and
modifications to qed's chain API.
Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/linux/qed')
| -rw-r--r-- | include/linux/qed/qed_chain.h | 553 | ||||
| -rw-r--r-- | include/linux/qed/qed_if.h | 3 |
2 files changed, 336 insertions, 220 deletions
diff --git a/include/linux/qed/qed_chain.h b/include/linux/qed/qed_chain.h index 5f8fcaaa6504..eceaa9ed2ae9 100644 --- a/include/linux/qed/qed_chain.h +++ b/include/linux/qed/qed_chain.h | |||
| @@ -47,16 +47,56 @@ enum qed_chain_use_mode { | |||
| 47 | QED_CHAIN_USE_TO_CONSUME_PRODUCE, /* Chain starts empty */ | 47 | QED_CHAIN_USE_TO_CONSUME_PRODUCE, /* Chain starts empty */ |
| 48 | }; | 48 | }; |
| 49 | 49 | ||
| 50 | enum qed_chain_cnt_type { | ||
| 51 | /* The chain's size/prod/cons are kept in 16-bit variables */ | ||
| 52 | QED_CHAIN_CNT_TYPE_U16, | ||
| 53 | |||
| 54 | /* The chain's size/prod/cons are kept in 32-bit variables */ | ||
| 55 | QED_CHAIN_CNT_TYPE_U32, | ||
| 56 | }; | ||
| 57 | |||
| 50 | struct qed_chain_next { | 58 | struct qed_chain_next { |
| 51 | struct regpair next_phys; | 59 | struct regpair next_phys; |
| 52 | void *next_virt; | 60 | void *next_virt; |
| 53 | }; | 61 | }; |
| 54 | 62 | ||
| 63 | struct qed_chain_pbl_u16 { | ||
| 64 | u16 prod_page_idx; | ||
| 65 | u16 cons_page_idx; | ||
| 66 | }; | ||
| 67 | |||
| 68 | struct qed_chain_pbl_u32 { | ||
| 69 | u32 prod_page_idx; | ||
| 70 | u32 cons_page_idx; | ||
| 71 | }; | ||
| 72 | |||
| 55 | struct qed_chain_pbl { | 73 | struct qed_chain_pbl { |
| 74 | /* Base address of a pre-allocated buffer for pbl */ | ||
| 56 | dma_addr_t p_phys_table; | 75 | dma_addr_t p_phys_table; |
| 57 | void *p_virt_table; | 76 | void *p_virt_table; |
| 58 | u16 prod_page_idx; | 77 | |
| 59 | u16 cons_page_idx; | 78 | /* Table for keeping the virtual addresses of the chain pages, |
| 79 | * respectively to the physical addresses in the pbl table. | ||
| 80 | */ | ||
| 81 | void **pp_virt_addr_tbl; | ||
| 82 | |||
| 83 | /* Index to current used page by producer/consumer */ | ||
| 84 | union { | ||
| 85 | struct qed_chain_pbl_u16 pbl16; | ||
| 86 | struct qed_chain_pbl_u32 pbl32; | ||
| 87 | } u; | ||
| 88 | }; | ||
| 89 | |||
| 90 | struct qed_chain_u16 { | ||
| 91 | /* Cyclic index of next element to produce/consme */ | ||
| 92 | u16 prod_idx; | ||
| 93 | u16 cons_idx; | ||
| 94 | }; | ||
| 95 | |||
| 96 | struct qed_chain_u32 { | ||
| 97 | /* Cyclic index of next element to produce/consme */ | ||
| 98 | u32 prod_idx; | ||
| 99 | u32 cons_idx; | ||
| 60 | }; | 100 | }; |
| 61 | 101 | ||
| 62 | struct qed_chain { | 102 | struct qed_chain { |
| @@ -64,13 +104,25 @@ struct qed_chain { | |||
| 64 | dma_addr_t p_phys_addr; | 104 | dma_addr_t p_phys_addr; |
| 65 | void *p_prod_elem; | 105 | void *p_prod_elem; |
| 66 | void *p_cons_elem; | 106 | void *p_cons_elem; |
| 67 | u16 page_cnt; | 107 | |
| 68 | enum qed_chain_mode mode; | 108 | enum qed_chain_mode mode; |
| 69 | enum qed_chain_use_mode intended_use; /* used to produce/consume */ | 109 | enum qed_chain_use_mode intended_use; /* used to produce/consume */ |
| 70 | u16 capacity; /*< number of _usable_ elements */ | 110 | enum qed_chain_cnt_type cnt_type; |
| 71 | u16 size; /* number of elements */ | 111 | |
| 72 | u16 prod_idx; | 112 | union { |
| 73 | u16 cons_idx; | 113 | struct qed_chain_u16 chain16; |
| 114 | struct qed_chain_u32 chain32; | ||
| 115 | } u; | ||
| 116 | |||
| 117 | u32 page_cnt; | ||
| 118 | |||
| 119 | /* Number of elements - capacity is for usable elements only, | ||
| 120 | * while size will contain total number of elements [for entire chain]. | ||
| 121 | */ | ||
| 122 | u32 capacity; | ||
| 123 | u32 size; | ||
| 124 | |||
| 125 | /* Elements information for fast calculations */ | ||
| 74 | u16 elem_per_page; | 126 | u16 elem_per_page; |
| 75 | u16 elem_per_page_mask; | 127 | u16 elem_per_page_mask; |
| 76 | u16 elem_unusable; | 128 | u16 elem_unusable; |
| @@ -96,66 +148,69 @@ struct qed_chain { | |||
| 96 | #define QED_CHAIN_PAGE_CNT(elem_cnt, elem_size, mode) \ | 148 | #define QED_CHAIN_PAGE_CNT(elem_cnt, elem_size, mode) \ |
| 97 | DIV_ROUND_UP(elem_cnt, USABLE_ELEMS_PER_PAGE(elem_size, mode)) | 149 | DIV_ROUND_UP(elem_cnt, USABLE_ELEMS_PER_PAGE(elem_size, mode)) |
| 98 | 150 | ||
| 151 | #define is_chain_u16(p) ((p)->cnt_type == QED_CHAIN_CNT_TYPE_U16) | ||
| 152 | #define is_chain_u32(p) ((p)->cnt_type == QED_CHAIN_CNT_TYPE_U32) | ||
| 153 | |||
| 99 | /* Accessors */ | 154 | /* Accessors */ |
| 100 | static inline u16 qed_chain_get_prod_idx(struct qed_chain *p_chain) | 155 | static inline u16 qed_chain_get_prod_idx(struct qed_chain *p_chain) |
| 101 | { | 156 | { |
| 102 | return p_chain->prod_idx; | 157 | return p_chain->u.chain16.prod_idx; |
| 103 | } | 158 | } |
| 104 | 159 | ||
| 105 | static inline u16 qed_chain_get_cons_idx(struct qed_chain *p_chain) | 160 | static inline u16 qed_chain_get_cons_idx(struct qed_chain *p_chain) |
| 106 | { | 161 | { |
| 107 | return p_chain->cons_idx; | 162 | return p_chain->u.chain16.cons_idx; |
| 163 | } | ||
| 164 | |||
| 165 | static inline u32 qed_chain_get_cons_idx_u32(struct qed_chain *p_chain) | ||
| 166 | { | ||
| 167 | return p_chain->u.chain32.cons_idx; | ||
| 108 | } | 168 | } |
| 109 | 169 | ||
| 110 | static inline u16 qed_chain_get_elem_left(struct qed_chain *p_chain) | 170 | static inline u16 qed_chain_get_elem_left(struct qed_chain *p_chain) |
| 111 | { | 171 | { |
| 112 | u16 used; | 172 | u16 used; |
| 113 | 173 | ||
| 114 | /* we don't need to trancate upon assignmet, as we assign u32->u16 */ | 174 | used = (u16) (((u32)0x10000 + |
| 115 | used = ((u32)0x10000u + (u32)(p_chain->prod_idx)) - | 175 | (u32)p_chain->u.chain16.prod_idx) - |
| 116 | (u32)p_chain->cons_idx; | 176 | (u32)p_chain->u.chain16.cons_idx); |
| 117 | if (p_chain->mode == QED_CHAIN_MODE_NEXT_PTR) | 177 | if (p_chain->mode == QED_CHAIN_MODE_NEXT_PTR) |
| 118 | used -= p_chain->prod_idx / p_chain->elem_per_page - | 178 | used -= p_chain->u.chain16.prod_idx / p_chain->elem_per_page - |
| 119 | p_chain->cons_idx / p_chain->elem_per_page; | 179 | p_chain->u.chain16.cons_idx / p_chain->elem_per_page; |
| 120 | 180 | ||
| 121 | return p_chain->capacity - used; | 181 | return (u16)(p_chain->capacity - used); |
| 122 | } | 182 | } |
| 123 | 183 | ||
| 124 | static inline u8 qed_chain_is_full(struct qed_chain *p_chain) | 184 | static inline u32 qed_chain_get_elem_left_u32(struct qed_chain *p_chain) |
| 125 | { | 185 | { |
| 126 | return qed_chain_get_elem_left(p_chain) == p_chain->capacity; | 186 | u32 used; |
| 127 | } | ||
| 128 | 187 | ||
| 129 | static inline u8 qed_chain_is_empty(struct qed_chain *p_chain) | 188 | used = (u32) (((u64)0x100000000ULL + |
| 130 | { | 189 | (u64)p_chain->u.chain32.prod_idx) - |
| 131 | return qed_chain_get_elem_left(p_chain) == 0; | 190 | (u64)p_chain->u.chain32.cons_idx); |
| 132 | } | 191 | if (p_chain->mode == QED_CHAIN_MODE_NEXT_PTR) |
| 192 | used -= p_chain->u.chain32.prod_idx / p_chain->elem_per_page - | ||
| 193 | p_chain->u.chain32.cons_idx / p_chain->elem_per_page; | ||
| 133 | 194 | ||
| 134 | static inline u16 qed_chain_get_elem_per_page( | 195 | return p_chain->capacity - used; |
| 135 | struct qed_chain *p_chain) | ||
| 136 | { | ||
| 137 | return p_chain->elem_per_page; | ||
| 138 | } | 196 | } |
| 139 | 197 | ||
| 140 | static inline u16 qed_chain_get_usable_per_page( | 198 | static inline u16 qed_chain_get_usable_per_page(struct qed_chain *p_chain) |
| 141 | struct qed_chain *p_chain) | ||
| 142 | { | 199 | { |
| 143 | return p_chain->usable_per_page; | 200 | return p_chain->usable_per_page; |
| 144 | } | 201 | } |
| 145 | 202 | ||
| 146 | static inline u16 qed_chain_get_unusable_per_page( | 203 | static inline u16 qed_chain_get_unusable_per_page(struct qed_chain *p_chain) |
| 147 | struct qed_chain *p_chain) | ||
| 148 | { | 204 | { |
| 149 | return p_chain->elem_unusable; | 205 | return p_chain->elem_unusable; |
| 150 | } | 206 | } |
| 151 | 207 | ||
| 152 | static inline u16 qed_chain_get_size(struct qed_chain *p_chain) | 208 | static inline u32 qed_chain_get_page_cnt(struct qed_chain *p_chain) |
| 153 | { | 209 | { |
| 154 | return p_chain->size; | 210 | return p_chain->page_cnt; |
| 155 | } | 211 | } |
| 156 | 212 | ||
| 157 | static inline dma_addr_t | 213 | static inline dma_addr_t qed_chain_get_pbl_phys(struct qed_chain *p_chain) |
| 158 | qed_chain_get_pbl_phys(struct qed_chain *p_chain) | ||
| 159 | { | 214 | { |
| 160 | return p_chain->pbl.p_phys_table; | 215 | return p_chain->pbl.p_phys_table; |
| 161 | } | 216 | } |
| @@ -172,65 +227,63 @@ qed_chain_get_pbl_phys(struct qed_chain *p_chain) | |||
| 172 | */ | 227 | */ |
| 173 | static inline void | 228 | static inline void |
| 174 | qed_chain_advance_page(struct qed_chain *p_chain, | 229 | qed_chain_advance_page(struct qed_chain *p_chain, |
| 175 | void **p_next_elem, | 230 | void **p_next_elem, void *idx_to_inc, void *page_to_inc) |
| 176 | u16 *idx_to_inc, | ||
| 177 | u16 *page_to_inc) | ||
| 178 | 231 | ||
| 179 | { | 232 | { |
| 233 | struct qed_chain_next *p_next = NULL; | ||
| 234 | u32 page_index = 0; | ||
| 180 | switch (p_chain->mode) { | 235 | switch (p_chain->mode) { |
| 181 | case QED_CHAIN_MODE_NEXT_PTR: | 236 | case QED_CHAIN_MODE_NEXT_PTR: |
| 182 | { | 237 | p_next = *p_next_elem; |
| 183 | struct qed_chain_next *p_next = *p_next_elem; | ||
| 184 | *p_next_elem = p_next->next_virt; | 238 | *p_next_elem = p_next->next_virt; |
| 185 | *idx_to_inc += p_chain->elem_unusable; | 239 | if (is_chain_u16(p_chain)) |
| 240 | *(u16 *)idx_to_inc += p_chain->elem_unusable; | ||
| 241 | else | ||
| 242 | *(u32 *)idx_to_inc += p_chain->elem_unusable; | ||
| 186 | break; | 243 | break; |
| 187 | } | ||
| 188 | case QED_CHAIN_MODE_SINGLE: | 244 | case QED_CHAIN_MODE_SINGLE: |
| 189 | *p_next_elem = p_chain->p_virt_addr; | 245 | *p_next_elem = p_chain->p_virt_addr; |
| 190 | break; | 246 | break; |
| 191 | 247 | ||
| 192 | case QED_CHAIN_MODE_PBL: | 248 | case QED_CHAIN_MODE_PBL: |
| 193 | /* It is assumed pages are sequential, next element needs | 249 | if (is_chain_u16(p_chain)) { |
| 194 | * to change only when passing going back to first from last. | 250 | if (++(*(u16 *)page_to_inc) == p_chain->page_cnt) |
| 195 | */ | 251 | *(u16 *)page_to_inc = 0; |
| 196 | if (++(*page_to_inc) == p_chain->page_cnt) { | 252 | page_index = *(u16 *)page_to_inc; |
| 197 | *page_to_inc = 0; | 253 | } else { |
| 198 | *p_next_elem = p_chain->p_virt_addr; | 254 | if (++(*(u32 *)page_to_inc) == p_chain->page_cnt) |
| 255 | *(u32 *)page_to_inc = 0; | ||
| 256 | page_index = *(u32 *)page_to_inc; | ||
| 199 | } | 257 | } |
| 258 | *p_next_elem = p_chain->pbl.pp_virt_addr_tbl[page_index]; | ||
| 200 | } | 259 | } |
| 201 | } | 260 | } |
| 202 | 261 | ||
| 203 | #define is_unusable_idx(p, idx) \ | 262 | #define is_unusable_idx(p, idx) \ |
| 204 | (((p)->idx & (p)->elem_per_page_mask) == (p)->usable_per_page) | 263 | (((p)->u.chain16.idx & (p)->elem_per_page_mask) == (p)->usable_per_page) |
| 264 | |||
| 265 | #define is_unusable_idx_u32(p, idx) \ | ||
| 266 | (((p)->u.chain32.idx & (p)->elem_per_page_mask) == (p)->usable_per_page) | ||
| 267 | #define is_unusable_next_idx(p, idx) \ | ||
| 268 | ((((p)->u.chain16.idx + 1) & (p)->elem_per_page_mask) == \ | ||
| 269 | (p)->usable_per_page) | ||
| 205 | 270 | ||
| 206 | #define is_unusable_next_idx(p, idx) \ | 271 | #define is_unusable_next_idx_u32(p, idx) \ |
| 207 | ((((p)->idx + 1) & (p)->elem_per_page_mask) == (p)->usable_per_page) | 272 | ((((p)->u.chain32.idx + 1) & (p)->elem_per_page_mask) == \ |
| 273 | (p)->usable_per_page) | ||
| 208 | 274 | ||
| 209 | #define test_ans_skip(p, idx) \ | 275 | #define test_and_skip(p, idx) \ |
| 210 | do { \ | 276 | do { \ |
| 211 | if (is_unusable_idx(p, idx)) { \ | 277 | if (is_chain_u16(p)) { \ |
| 212 | (p)->idx += (p)->elem_unusable; \ | 278 | if (is_unusable_idx(p, idx)) \ |
| 279 | (p)->u.chain16.idx += (p)->elem_unusable; \ | ||
| 280 | } else { \ | ||
| 281 | if (is_unusable_idx_u32(p, idx)) \ | ||
| 282 | (p)->u.chain32.idx += (p)->elem_unusable; \ | ||
| 213 | } \ | 283 | } \ |
| 214 | } while (0) | 284 | } while (0) |
| 215 | 285 | ||
| 216 | /** | 286 | /** |
| 217 | * @brief qed_chain_return_multi_produced - | ||
| 218 | * | ||
| 219 | * A chain in which the driver "Produces" elements should use this API | ||
| 220 | * to indicate previous produced elements are now consumed. | ||
| 221 | * | ||
| 222 | * @param p_chain | ||
| 223 | * @param num | ||
| 224 | */ | ||
| 225 | static inline void | ||
| 226 | qed_chain_return_multi_produced(struct qed_chain *p_chain, | ||
| 227 | u16 num) | ||
| 228 | { | ||
| 229 | p_chain->cons_idx += num; | ||
| 230 | test_ans_skip(p_chain, cons_idx); | ||
| 231 | } | ||
| 232 | |||
| 233 | /** | ||
| 234 | * @brief qed_chain_return_produced - | 287 | * @brief qed_chain_return_produced - |
| 235 | * | 288 | * |
| 236 | * A chain in which the driver "Produces" elements should use this API | 289 | * A chain in which the driver "Produces" elements should use this API |
| @@ -240,8 +293,11 @@ qed_chain_return_multi_produced(struct qed_chain *p_chain, | |||
| 240 | */ | 293 | */ |
| 241 | static inline void qed_chain_return_produced(struct qed_chain *p_chain) | 294 | static inline void qed_chain_return_produced(struct qed_chain *p_chain) |
| 242 | { | 295 | { |
| 243 | p_chain->cons_idx++; | 296 | if (is_chain_u16(p_chain)) |
| 244 | test_ans_skip(p_chain, cons_idx); | 297 | p_chain->u.chain16.cons_idx++; |
| 298 | else | ||
| 299 | p_chain->u.chain32.cons_idx++; | ||
| 300 | test_and_skip(p_chain, cons_idx); | ||
| 245 | } | 301 | } |
| 246 | 302 | ||
| 247 | /** | 303 | /** |
| @@ -257,21 +313,33 @@ static inline void qed_chain_return_produced(struct qed_chain *p_chain) | |||
| 257 | */ | 313 | */ |
| 258 | static inline void *qed_chain_produce(struct qed_chain *p_chain) | 314 | static inline void *qed_chain_produce(struct qed_chain *p_chain) |
| 259 | { | 315 | { |
| 260 | void *ret = NULL; | 316 | void *p_ret = NULL, *p_prod_idx, *p_prod_page_idx; |
| 261 | 317 | ||
| 262 | if ((p_chain->prod_idx & p_chain->elem_per_page_mask) == | 318 | if (is_chain_u16(p_chain)) { |
| 263 | p_chain->next_page_mask) { | 319 | if ((p_chain->u.chain16.prod_idx & |
| 264 | qed_chain_advance_page(p_chain, &p_chain->p_prod_elem, | 320 | p_chain->elem_per_page_mask) == p_chain->next_page_mask) { |
| 265 | &p_chain->prod_idx, | 321 | p_prod_idx = &p_chain->u.chain16.prod_idx; |
| 266 | &p_chain->pbl.prod_page_idx); | 322 | p_prod_page_idx = &p_chain->pbl.u.pbl16.prod_page_idx; |
| 323 | qed_chain_advance_page(p_chain, &p_chain->p_prod_elem, | ||
| 324 | p_prod_idx, p_prod_page_idx); | ||
| 325 | } | ||
| 326 | p_chain->u.chain16.prod_idx++; | ||
| 327 | } else { | ||
| 328 | if ((p_chain->u.chain32.prod_idx & | ||
| 329 | p_chain->elem_per_page_mask) == p_chain->next_page_mask) { | ||
| 330 | p_prod_idx = &p_chain->u.chain32.prod_idx; | ||
| 331 | p_prod_page_idx = &p_chain->pbl.u.pbl32.prod_page_idx; | ||
| 332 | qed_chain_advance_page(p_chain, &p_chain->p_prod_elem, | ||
| 333 | p_prod_idx, p_prod_page_idx); | ||
| 334 | } | ||
| 335 | p_chain->u.chain32.prod_idx++; | ||
| 267 | } | 336 | } |
| 268 | 337 | ||
| 269 | ret = p_chain->p_prod_elem; | 338 | p_ret = p_chain->p_prod_elem; |
| 270 | p_chain->prod_idx++; | ||
| 271 | p_chain->p_prod_elem = (void *)(((u8 *)p_chain->p_prod_elem) + | 339 | p_chain->p_prod_elem = (void *)(((u8 *)p_chain->p_prod_elem) + |
| 272 | p_chain->elem_size); | 340 | p_chain->elem_size); |
| 273 | 341 | ||
| 274 | return ret; | 342 | return p_ret; |
| 275 | } | 343 | } |
| 276 | 344 | ||
| 277 | /** | 345 | /** |
| @@ -282,9 +350,9 @@ static inline void *qed_chain_produce(struct qed_chain *p_chain) | |||
| 282 | * @param p_chain | 350 | * @param p_chain |
| 283 | * @param num | 351 | * @param num |
| 284 | * | 352 | * |
| 285 | * @return u16, number of unusable BDs | 353 | * @return number of unusable BDs |
| 286 | */ | 354 | */ |
| 287 | static inline u16 qed_chain_get_capacity(struct qed_chain *p_chain) | 355 | static inline u32 qed_chain_get_capacity(struct qed_chain *p_chain) |
| 288 | { | 356 | { |
| 289 | return p_chain->capacity; | 357 | return p_chain->capacity; |
| 290 | } | 358 | } |
| @@ -297,11 +365,13 @@ static inline u16 qed_chain_get_capacity(struct qed_chain *p_chain) | |||
| 297 | * | 365 | * |
| 298 | * @param p_chain | 366 | * @param p_chain |
| 299 | */ | 367 | */ |
| 300 | static inline void | 368 | static inline void qed_chain_recycle_consumed(struct qed_chain *p_chain) |
| 301 | qed_chain_recycle_consumed(struct qed_chain *p_chain) | ||
| 302 | { | 369 | { |
| 303 | test_ans_skip(p_chain, prod_idx); | 370 | test_and_skip(p_chain, prod_idx); |
| 304 | p_chain->prod_idx++; | 371 | if (is_chain_u16(p_chain)) |
| 372 | p_chain->u.chain16.prod_idx++; | ||
| 373 | else | ||
| 374 | p_chain->u.chain32.prod_idx++; | ||
| 305 | } | 375 | } |
| 306 | 376 | ||
| 307 | /** | 377 | /** |
| @@ -316,21 +386,33 @@ qed_chain_recycle_consumed(struct qed_chain *p_chain) | |||
| 316 | */ | 386 | */ |
| 317 | static inline void *qed_chain_consume(struct qed_chain *p_chain) | 387 | static inline void *qed_chain_consume(struct qed_chain *p_chain) |
| 318 | { | 388 | { |
| 319 | void *ret = NULL; | 389 | void *p_ret = NULL, *p_cons_idx, *p_cons_page_idx; |
| 320 | 390 | ||
| 321 | if ((p_chain->cons_idx & p_chain->elem_per_page_mask) == | 391 | if (is_chain_u16(p_chain)) { |
| 322 | p_chain->next_page_mask) { | 392 | if ((p_chain->u.chain16.cons_idx & |
| 393 | p_chain->elem_per_page_mask) == p_chain->next_page_mask) { | ||
| 394 | p_cons_idx = &p_chain->u.chain16.cons_idx; | ||
| 395 | p_cons_page_idx = &p_chain->pbl.u.pbl16.cons_page_idx; | ||
| 396 | qed_chain_advance_page(p_chain, &p_chain->p_cons_elem, | ||
| 397 | p_cons_idx, p_cons_page_idx); | ||
| 398 | } | ||
| 399 | p_chain->u.chain16.cons_idx++; | ||
| 400 | } else { | ||
| 401 | if ((p_chain->u.chain32.cons_idx & | ||
| 402 | p_chain->elem_per_page_mask) == p_chain->next_page_mask) { | ||
| 403 | p_cons_idx = &p_chain->u.chain32.cons_idx; | ||
| 404 | p_cons_page_idx = &p_chain->pbl.u.pbl32.cons_page_idx; | ||
| 323 | qed_chain_advance_page(p_chain, &p_chain->p_cons_elem, | 405 | qed_chain_advance_page(p_chain, &p_chain->p_cons_elem, |
| 324 | &p_chain->cons_idx, | 406 | p_cons_idx, p_cons_page_idx); |
| 325 | &p_chain->pbl.cons_page_idx); | 407 | } |
| 408 | p_chain->u.chain32.cons_idx++; | ||
| 326 | } | 409 | } |
| 327 | 410 | ||
| 328 | ret = p_chain->p_cons_elem; | 411 | p_ret = p_chain->p_cons_elem; |
| 329 | p_chain->cons_idx++; | ||
| 330 | p_chain->p_cons_elem = (void *)(((u8 *)p_chain->p_cons_elem) + | 412 | p_chain->p_cons_elem = (void *)(((u8 *)p_chain->p_cons_elem) + |
| 331 | p_chain->elem_size); | 413 | p_chain->elem_size); |
| 332 | 414 | ||
| 333 | return ret; | 415 | return p_ret; |
| 334 | } | 416 | } |
| 335 | 417 | ||
| 336 | /** | 418 | /** |
| @@ -340,16 +422,33 @@ static inline void *qed_chain_consume(struct qed_chain *p_chain) | |||
| 340 | */ | 422 | */ |
| 341 | static inline void qed_chain_reset(struct qed_chain *p_chain) | 423 | static inline void qed_chain_reset(struct qed_chain *p_chain) |
| 342 | { | 424 | { |
| 343 | int i; | 425 | u32 i; |
| 344 | 426 | ||
| 345 | p_chain->prod_idx = 0; | 427 | if (is_chain_u16(p_chain)) { |
| 346 | p_chain->cons_idx = 0; | 428 | p_chain->u.chain16.prod_idx = 0; |
| 347 | p_chain->p_cons_elem = p_chain->p_virt_addr; | 429 | p_chain->u.chain16.cons_idx = 0; |
| 348 | p_chain->p_prod_elem = p_chain->p_virt_addr; | 430 | } else { |
| 431 | p_chain->u.chain32.prod_idx = 0; | ||
| 432 | p_chain->u.chain32.cons_idx = 0; | ||
| 433 | } | ||
| 434 | p_chain->p_cons_elem = p_chain->p_virt_addr; | ||
| 435 | p_chain->p_prod_elem = p_chain->p_virt_addr; | ||
| 349 | 436 | ||
| 350 | if (p_chain->mode == QED_CHAIN_MODE_PBL) { | 437 | if (p_chain->mode == QED_CHAIN_MODE_PBL) { |
| 351 | p_chain->pbl.prod_page_idx = p_chain->page_cnt - 1; | 438 | /* Use (page_cnt - 1) as a reset value for the prod/cons page's |
| 352 | p_chain->pbl.cons_page_idx = p_chain->page_cnt - 1; | 439 | * indices, to avoid unnecessary page advancing on the first |
| 440 | * call to qed_chain_produce/consume. Instead, the indices | ||
| 441 | * will be advanced to page_cnt and then will be wrapped to 0. | ||
| 442 | */ | ||
| 443 | u32 reset_val = p_chain->page_cnt - 1; | ||
| 444 | |||
| 445 | if (is_chain_u16(p_chain)) { | ||
| 446 | p_chain->pbl.u.pbl16.prod_page_idx = (u16)reset_val; | ||
| 447 | p_chain->pbl.u.pbl16.cons_page_idx = (u16)reset_val; | ||
| 448 | } else { | ||
| 449 | p_chain->pbl.u.pbl32.prod_page_idx = reset_val; | ||
| 450 | p_chain->pbl.u.pbl32.cons_page_idx = reset_val; | ||
| 451 | } | ||
| 353 | } | 452 | } |
| 354 | 453 | ||
| 355 | switch (p_chain->intended_use) { | 454 | switch (p_chain->intended_use) { |
| @@ -377,168 +476,184 @@ static inline void qed_chain_reset(struct qed_chain *p_chain) | |||
| 377 | * @param intended_use | 476 | * @param intended_use |
| 378 | * @param mode | 477 | * @param mode |
| 379 | */ | 478 | */ |
| 380 | static inline void qed_chain_init(struct qed_chain *p_chain, | 479 | static inline void qed_chain_init_params(struct qed_chain *p_chain, |
| 381 | void *p_virt_addr, | 480 | u32 page_cnt, |
| 382 | dma_addr_t p_phys_addr, | 481 | u8 elem_size, |
| 383 | u16 page_cnt, | 482 | enum qed_chain_use_mode intended_use, |
| 384 | u8 elem_size, | 483 | enum qed_chain_mode mode, |
| 385 | enum qed_chain_use_mode intended_use, | 484 | enum qed_chain_cnt_type cnt_type) |
| 386 | enum qed_chain_mode mode) | ||
| 387 | { | 485 | { |
| 388 | /* chain fixed parameters */ | 486 | /* chain fixed parameters */ |
| 389 | p_chain->p_virt_addr = p_virt_addr; | 487 | p_chain->p_virt_addr = NULL; |
| 390 | p_chain->p_phys_addr = p_phys_addr; | 488 | p_chain->p_phys_addr = 0; |
| 391 | p_chain->elem_size = elem_size; | 489 | p_chain->elem_size = elem_size; |
| 392 | p_chain->page_cnt = page_cnt; | 490 | p_chain->intended_use = intended_use; |
| 393 | p_chain->mode = mode; | 491 | p_chain->mode = mode; |
| 492 | p_chain->cnt_type = cnt_type; | ||
| 394 | 493 | ||
| 395 | p_chain->intended_use = intended_use; | ||
| 396 | p_chain->elem_per_page = ELEMS_PER_PAGE(elem_size); | 494 | p_chain->elem_per_page = ELEMS_PER_PAGE(elem_size); |
| 397 | p_chain->usable_per_page = | 495 | p_chain->usable_per_page = USABLE_ELEMS_PER_PAGE(elem_size, mode); |
| 398 | USABLE_ELEMS_PER_PAGE(elem_size, mode); | ||
| 399 | p_chain->capacity = p_chain->usable_per_page * page_cnt; | ||
| 400 | p_chain->size = p_chain->elem_per_page * page_cnt; | ||
| 401 | p_chain->elem_per_page_mask = p_chain->elem_per_page - 1; | 496 | p_chain->elem_per_page_mask = p_chain->elem_per_page - 1; |
| 402 | |||
| 403 | p_chain->elem_unusable = UNUSABLE_ELEMS_PER_PAGE(elem_size, mode); | 497 | p_chain->elem_unusable = UNUSABLE_ELEMS_PER_PAGE(elem_size, mode); |
| 404 | |||
| 405 | p_chain->next_page_mask = (p_chain->usable_per_page & | 498 | p_chain->next_page_mask = (p_chain->usable_per_page & |
| 406 | p_chain->elem_per_page_mask); | 499 | p_chain->elem_per_page_mask); |
| 407 | 500 | ||
| 408 | if (mode == QED_CHAIN_MODE_NEXT_PTR) { | 501 | p_chain->page_cnt = page_cnt; |
| 409 | struct qed_chain_next *p_next; | 502 | p_chain->capacity = p_chain->usable_per_page * page_cnt; |
| 410 | u16 i; | 503 | p_chain->size = p_chain->elem_per_page * page_cnt; |
| 411 | |||
| 412 | for (i = 0; i < page_cnt - 1; i++) { | ||
| 413 | /* Increment mem_phy to the next page. */ | ||
| 414 | p_phys_addr += QED_CHAIN_PAGE_SIZE; | ||
| 415 | |||
| 416 | /* Initialize the physical address of the next page. */ | ||
| 417 | p_next = (struct qed_chain_next *)((u8 *)p_virt_addr + | ||
| 418 | elem_size * | ||
| 419 | p_chain-> | ||
| 420 | usable_per_page); | ||
| 421 | |||
| 422 | p_next->next_phys.lo = DMA_LO_LE(p_phys_addr); | ||
| 423 | p_next->next_phys.hi = DMA_HI_LE(p_phys_addr); | ||
| 424 | |||
| 425 | /* Initialize the virtual address of the next page. */ | ||
| 426 | p_next->next_virt = (void *)((u8 *)p_virt_addr + | ||
| 427 | QED_CHAIN_PAGE_SIZE); | ||
| 428 | |||
| 429 | /* Move to the next page. */ | ||
| 430 | p_virt_addr = p_next->next_virt; | ||
| 431 | } | ||
| 432 | |||
| 433 | /* Last page's next should point to beginning of the chain */ | ||
| 434 | p_next = (struct qed_chain_next *)((u8 *)p_virt_addr + | ||
| 435 | elem_size * | ||
| 436 | p_chain->usable_per_page); | ||
| 437 | 504 | ||
| 438 | p_next->next_phys.lo = DMA_LO_LE(p_chain->p_phys_addr); | 505 | p_chain->pbl.p_phys_table = 0; |
| 439 | p_next->next_phys.hi = DMA_HI_LE(p_chain->p_phys_addr); | 506 | p_chain->pbl.p_virt_table = NULL; |
| 440 | p_next->next_virt = p_chain->p_virt_addr; | 507 | p_chain->pbl.pp_virt_addr_tbl = NULL; |
| 441 | } | ||
| 442 | qed_chain_reset(p_chain); | ||
| 443 | } | 508 | } |
| 444 | 509 | ||
| 445 | /** | 510 | /** |
| 446 | * @brief qed_chain_pbl_init - Initalizes a basic pbl chain | 511 | * @brief qed_chain_init_mem - |
| 447 | * struct | 512 | * |
| 513 | * Initalizes a basic chain struct with its chain buffers | ||
| 514 | * | ||
| 448 | * @param p_chain | 515 | * @param p_chain |
| 449 | * @param p_virt_addr virtual address of allocated buffer's beginning | 516 | * @param p_virt_addr virtual address of allocated buffer's beginning |
| 450 | * @param p_phys_addr physical address of allocated buffer's beginning | 517 | * @param p_phys_addr physical address of allocated buffer's beginning |
| 451 | * @param page_cnt number of pages in the allocated buffer | 518 | * |
| 452 | * @param elem_size size of each element in the chain | ||
| 453 | * @param use_mode | ||
| 454 | * @param p_phys_pbl pointer to a pre-allocated side table | ||
| 455 | * which will hold physical page addresses. | ||
| 456 | * @param p_virt_pbl pointer to a pre allocated side table | ||
| 457 | * which will hold virtual page addresses. | ||
| 458 | */ | 519 | */ |
| 459 | static inline void | 520 | static inline void qed_chain_init_mem(struct qed_chain *p_chain, |
| 460 | qed_chain_pbl_init(struct qed_chain *p_chain, | 521 | void *p_virt_addr, dma_addr_t p_phys_addr) |
| 461 | void *p_virt_addr, | ||
| 462 | dma_addr_t p_phys_addr, | ||
| 463 | u16 page_cnt, | ||
| 464 | u8 elem_size, | ||
| 465 | enum qed_chain_use_mode use_mode, | ||
| 466 | dma_addr_t p_phys_pbl, | ||
| 467 | dma_addr_t *p_virt_pbl) | ||
| 468 | { | 522 | { |
| 469 | dma_addr_t *p_pbl_dma = p_virt_pbl; | 523 | p_chain->p_virt_addr = p_virt_addr; |
| 470 | int i; | 524 | p_chain->p_phys_addr = p_phys_addr; |
| 471 | 525 | } | |
| 472 | qed_chain_init(p_chain, p_virt_addr, p_phys_addr, page_cnt, | ||
| 473 | elem_size, use_mode, QED_CHAIN_MODE_PBL); | ||
| 474 | 526 | ||
| 527 | /** | ||
| 528 | * @brief qed_chain_init_pbl_mem - | ||
| 529 | * | ||
| 530 | * Initalizes a basic chain struct with its pbl buffers | ||
| 531 | * | ||
| 532 | * @param p_chain | ||
| 533 | * @param p_virt_pbl pointer to a pre allocated side table which will hold | ||
| 534 | * virtual page addresses. | ||
| 535 | * @param p_phys_pbl pointer to a pre-allocated side table which will hold | ||
| 536 | * physical page addresses. | ||
| 537 | * @param pp_virt_addr_tbl | ||
| 538 | * pointer to a pre-allocated side table which will hold | ||
| 539 | * the virtual addresses of the chain pages. | ||
| 540 | * | ||
| 541 | */ | ||
| 542 | static inline void qed_chain_init_pbl_mem(struct qed_chain *p_chain, | ||
| 543 | void *p_virt_pbl, | ||
| 544 | dma_addr_t p_phys_pbl, | ||
| 545 | void **pp_virt_addr_tbl) | ||
| 546 | { | ||
| 475 | p_chain->pbl.p_phys_table = p_phys_pbl; | 547 | p_chain->pbl.p_phys_table = p_phys_pbl; |
| 476 | p_chain->pbl.p_virt_table = p_virt_pbl; | 548 | p_chain->pbl.p_virt_table = p_virt_pbl; |
| 477 | 549 | p_chain->pbl.pp_virt_addr_tbl = pp_virt_addr_tbl; | |
| 478 | /* Fill the PBL with physical addresses*/ | ||
| 479 | for (i = 0; i < page_cnt; i++) { | ||
| 480 | *p_pbl_dma = p_phys_addr; | ||
| 481 | p_phys_addr += QED_CHAIN_PAGE_SIZE; | ||
| 482 | p_pbl_dma++; | ||
| 483 | } | ||
| 484 | } | 550 | } |
| 485 | 551 | ||
| 486 | /** | 552 | /** |
| 487 | * @brief qed_chain_set_prod - sets the prod to the given | 553 | * @brief qed_chain_init_next_ptr_elem - |
| 488 | * value | 554 | * |
| 555 | * Initalizes a next pointer element | ||
| 556 | * | ||
| 557 | * @param p_chain | ||
| 558 | * @param p_virt_curr virtual address of a chain page of which the next | ||
| 559 | * pointer element is initialized | ||
| 560 | * @param p_virt_next virtual address of the next chain page | ||
| 561 | * @param p_phys_next physical address of the next chain page | ||
| 489 | * | 562 | * |
| 490 | * @param prod_idx | ||
| 491 | * @param p_prod_elem | ||
| 492 | */ | 563 | */ |
| 493 | static inline void qed_chain_set_prod(struct qed_chain *p_chain, | 564 | static inline void |
| 494 | u16 prod_idx, | 565 | qed_chain_init_next_ptr_elem(struct qed_chain *p_chain, |
| 495 | void *p_prod_elem) | 566 | void *p_virt_curr, |
| 567 | void *p_virt_next, dma_addr_t p_phys_next) | ||
| 496 | { | 568 | { |
| 497 | p_chain->prod_idx = prod_idx; | 569 | struct qed_chain_next *p_next; |
| 498 | p_chain->p_prod_elem = p_prod_elem; | 570 | u32 size; |
| 571 | |||
| 572 | size = p_chain->elem_size * p_chain->usable_per_page; | ||
| 573 | p_next = (struct qed_chain_next *)((u8 *)p_virt_curr + size); | ||
| 574 | |||
| 575 | DMA_REGPAIR_LE(p_next->next_phys, p_phys_next); | ||
| 576 | |||
| 577 | p_next->next_virt = p_virt_next; | ||
| 499 | } | 578 | } |
| 500 | 579 | ||
| 501 | /** | 580 | /** |
| 502 | * @brief qed_chain_get_elem - | 581 | * @brief qed_chain_get_last_elem - |
| 503 | * | 582 | * |
| 504 | * get a pointer to an element represented by absolute idx | 583 | * Returns a pointer to the last element of the chain |
| 505 | * | 584 | * |
| 506 | * @param p_chain | 585 | * @param p_chain |
| 507 | * @assumption p_chain->size is a power of 2 | ||
| 508 | * | 586 | * |
| 509 | * @return void*, a pointer to next element | 587 | * @return void* |
| 510 | */ | 588 | */ |
| 511 | static inline void *qed_chain_sge_get_elem(struct qed_chain *p_chain, | 589 | static inline void *qed_chain_get_last_elem(struct qed_chain *p_chain) |
| 512 | u16 idx) | ||
| 513 | { | 590 | { |
| 514 | void *ret = NULL; | 591 | struct qed_chain_next *p_next = NULL; |
| 515 | 592 | void *p_virt_addr = NULL; | |
| 516 | if (idx >= p_chain->size) | 593 | u32 size, last_page_idx; |
| 517 | return NULL; | ||
| 518 | 594 | ||
| 519 | ret = (u8 *)p_chain->p_virt_addr + p_chain->elem_size * idx; | 595 | if (!p_chain->p_virt_addr) |
| 596 | goto out; | ||
| 520 | 597 | ||
| 521 | return ret; | 598 | switch (p_chain->mode) { |
| 599 | case QED_CHAIN_MODE_NEXT_PTR: | ||
| 600 | size = p_chain->elem_size * p_chain->usable_per_page; | ||
| 601 | p_virt_addr = p_chain->p_virt_addr; | ||
| 602 | p_next = (struct qed_chain_next *)((u8 *)p_virt_addr + size); | ||
| 603 | while (p_next->next_virt != p_chain->p_virt_addr) { | ||
| 604 | p_virt_addr = p_next->next_virt; | ||
| 605 | p_next = (struct qed_chain_next *)((u8 *)p_virt_addr + | ||
| 606 | size); | ||
| 607 | } | ||
| 608 | break; | ||
| 609 | case QED_CHAIN_MODE_SINGLE: | ||
| 610 | p_virt_addr = p_chain->p_virt_addr; | ||
| 611 | break; | ||
| 612 | case QED_CHAIN_MODE_PBL: | ||
| 613 | last_page_idx = p_chain->page_cnt - 1; | ||
| 614 | p_virt_addr = p_chain->pbl.pp_virt_addr_tbl[last_page_idx]; | ||
| 615 | break; | ||
| 616 | } | ||
| 617 | /* p_virt_addr points at this stage to the last page of the chain */ | ||
| 618 | size = p_chain->elem_size * (p_chain->usable_per_page - 1); | ||
| 619 | p_virt_addr = (u8 *)p_virt_addr + size; | ||
| 620 | out: | ||
| 621 | return p_virt_addr; | ||
| 522 | } | 622 | } |
| 523 | 623 | ||
| 524 | /** | 624 | /** |
| 525 | * @brief qed_chain_sge_inc_cons_prod | 625 | * @brief qed_chain_set_prod - sets the prod to the given value |
| 526 | * | 626 | * |
| 527 | * for sge chains, producer isn't increased serially, the ring | 627 | * @param prod_idx |
| 528 | * is expected to be full at all times. Once elements are | 628 | * @param p_prod_elem |
| 529 | * consumed, they are immediately produced. | 629 | */ |
| 630 | static inline void qed_chain_set_prod(struct qed_chain *p_chain, | ||
| 631 | u32 prod_idx, void *p_prod_elem) | ||
| 632 | { | ||
| 633 | if (is_chain_u16(p_chain)) | ||
| 634 | p_chain->u.chain16.prod_idx = (u16) prod_idx; | ||
| 635 | else | ||
| 636 | p_chain->u.chain32.prod_idx = prod_idx; | ||
| 637 | p_chain->p_prod_elem = p_prod_elem; | ||
| 638 | } | ||
| 639 | |||
| 640 | /** | ||
| 641 | * @brief qed_chain_pbl_zero_mem - set chain memory to 0 | ||
| 530 | * | 642 | * |
| 531 | * @param p_chain | 643 | * @param p_chain |
| 532 | * @param cnt | ||
| 533 | * | ||
| 534 | * @return inline void | ||
| 535 | */ | 644 | */ |
| 536 | static inline void | 645 | static inline void qed_chain_pbl_zero_mem(struct qed_chain *p_chain) |
| 537 | qed_chain_sge_inc_cons_prod(struct qed_chain *p_chain, | ||
| 538 | u16 cnt) | ||
| 539 | { | 646 | { |
| 540 | p_chain->prod_idx += cnt; | 647 | u32 i, page_cnt; |
| 541 | p_chain->cons_idx += cnt; | 648 | |
| 649 | if (p_chain->mode != QED_CHAIN_MODE_PBL) | ||
| 650 | return; | ||
| 651 | |||
| 652 | page_cnt = qed_chain_get_page_cnt(p_chain); | ||
| 653 | |||
| 654 | for (i = 0; i < page_cnt; i++) | ||
| 655 | memset(p_chain->pbl.pp_virt_addr_tbl[i], 0, | ||
| 656 | QED_CHAIN_PAGE_SIZE); | ||
| 542 | } | 657 | } |
| 543 | 658 | ||
| 544 | #endif | 659 | #endif |
diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h index 4c29439f54bf..15efccfdc46e 100644 --- a/include/linux/qed/qed_if.h +++ b/include/linux/qed/qed_if.h | |||
| @@ -325,7 +325,8 @@ struct qed_common_ops { | |||
| 325 | int (*chain_alloc)(struct qed_dev *cdev, | 325 | int (*chain_alloc)(struct qed_dev *cdev, |
| 326 | enum qed_chain_use_mode intended_use, | 326 | enum qed_chain_use_mode intended_use, |
| 327 | enum qed_chain_mode mode, | 327 | enum qed_chain_mode mode, |
| 328 | u16 num_elems, | 328 | enum qed_chain_cnt_type cnt_type, |
| 329 | u32 num_elems, | ||
| 329 | size_t elem_size, | 330 | size_t elem_size, |
| 330 | struct qed_chain *p_chain); | 331 | struct qed_chain *p_chain); |
| 331 | 332 | ||
