struct qed_chain { /* Fastpath portion of the chain - required for commands such * as produce / consume.
*/
/* Point to next element to produce/consume */ void *p_prod_elem; void *p_cons_elem;
/* Fastpath portions of the PBL [if exists] */
struct { /* Table for keeping the virtual and physical addresses of the * chain pages, respectively to the physical addresses * in the pbl table.
*/ struct addr_tbl_entry *pp_addr_tbl;
union { struct qed_chain_u16 chain16; struct qed_chain_u32 chain32;
} u;
/* Capacity counts only usable elements */
u32 capacity;
u32 page_cnt;
enum qed_chain_mode mode;
/* Elements information for fast calculations */
u16 elem_per_page;
u16 elem_per_page_mask;
u16 elem_size;
u16 next_page_mask;
u16 usable_per_page;
u8 elem_unusable;
enum qed_chain_cnt_type cnt_type;
/* Slowpath of the chain - required for initialization and destruction, * but isn't involved in regular functionality.
*/
u32 page_size;
/* Base address of a pre-allocated buffer for pbl */ struct {
__le64 *table_virt;
dma_addr_t table_phys;
size_t table_size;
} pbl_sp;
/* Address of first page of the chain - the address is required * for fastpath operation [consume/produce] but only for the SINGLE * flavour which isn't considered fastpath [== SPQ].
*/ void *p_virt_addr;
dma_addr_t p_phys_addr;
/* Total number of elements [for entire chain] */
u32 size;
#define test_and_skip(p, idx) \ do { \ if (is_chain_u16(p)) { \ if (is_unusable_idx(p, idx)) \
(p)->u.chain16.idx += (p)->elem_unusable; \
} else { \ if (is_unusable_idx_u32(p, idx)) \
(p)->u.chain32.idx += (p)->elem_unusable; \
} \
} while (0)
/** * qed_chain_return_produced(): A chain in which the driver "Produces" * elements should use this API * to indicate previous produced elements * are now consumed. * * @p_chain: Chain. * * Return: Void.
*/ staticinlinevoid qed_chain_return_produced(struct qed_chain *p_chain)
{ if (is_chain_u16(p_chain))
p_chain->u.chain16.cons_idx++; else
p_chain->u.chain32.cons_idx++;
test_and_skip(p_chain, cons_idx);
}
/** * qed_chain_produce(): A chain in which the driver "Produces" * elements should use this to get a pointer to * the next element which can be "Produced". It's driver * responsibility to validate that the chain has room for * new element. * * @p_chain: Chain. * * Return: void*, a pointer to next element.
*/ staticinlinevoid *qed_chain_produce(struct qed_chain *p_chain)
{ void *p_ret = NULL, *p_prod_idx, *p_prod_page_idx;
/** * qed_chain_get_capacity(): Get the maximum number of BDs in chain * * @p_chain: Chain. * * Return: number of unusable BDs.
*/ staticinline u32 qed_chain_get_capacity(struct qed_chain *p_chain)
{ return p_chain->capacity;
}
/** * qed_chain_recycle_consumed(): Returns an element which was * previously consumed; * Increments producers so they could * be written to FW. * * @p_chain: Chain. * * Return: Void.
*/ staticinlinevoid qed_chain_recycle_consumed(struct qed_chain *p_chain)
{
test_and_skip(p_chain, prod_idx); if (is_chain_u16(p_chain))
p_chain->u.chain16.prod_idx++; else
p_chain->u.chain32.prod_idx++;
}
/** * qed_chain_consume(): A Chain in which the driver utilizes data written * by a different source (i.e., FW) should use this to * access passed buffers. * * @p_chain: Chain. * * Return: void*, a pointer to the next buffer written.
*/ staticinlinevoid *qed_chain_consume(struct qed_chain *p_chain)
{ void *p_ret = NULL, *p_cons_idx, *p_cons_page_idx;
if (p_chain->mode == QED_CHAIN_MODE_PBL) { /* Use (page_cnt - 1) as a reset value for the prod/cons page's * indices, to avoid unnecessary page advancing on the first * call to qed_chain_produce/consume. Instead, the indices * will be advanced to page_cnt and then will be wrapped to 0.
*/
u32 reset_val = p_chain->page_cnt - 1;
switch (p_chain->intended_use) { case QED_CHAIN_USE_TO_CONSUME: /* produce empty elements */ for (i = 0; i < p_chain->capacity; i++)
qed_chain_recycle_consumed(p_chain); break;
case QED_CHAIN_USE_TO_CONSUME_PRODUCE: case QED_CHAIN_USE_TO_PRODUCE: default: /* Do nothing */ break;
}
}
/** * qed_chain_get_last_elem(): Returns a pointer to the last element of the * chain. * * @p_chain: Chain. * * Return: void*.
*/ staticinlinevoid *qed_chain_get_last_elem(struct qed_chain *p_chain)
{ struct qed_chain_next *p_next = NULL; void *p_virt_addr = NULL;
u32 size, last_page_idx;
if (!p_chain->p_virt_addr) goto out;
switch (p_chain->mode) { case QED_CHAIN_MODE_NEXT_PTR:
size = p_chain->elem_size * p_chain->usable_per_page;
p_virt_addr = p_chain->p_virt_addr;
p_next = (struct qed_chain_next *)((u8 *)p_virt_addr + size); while (p_next->next_virt != p_chain->p_virt_addr) {
p_virt_addr = p_next->next_virt;
p_next = (struct qed_chain_next *)((u8 *)p_virt_addr +
size);
} break; case QED_CHAIN_MODE_SINGLE:
p_virt_addr = p_chain->p_virt_addr; break; case QED_CHAIN_MODE_PBL:
last_page_idx = p_chain->page_cnt - 1;
p_virt_addr = p_chain->pbl.pp_addr_tbl[last_page_idx].virt_addr; break;
} /* p_virt_addr points at this stage to the last page of the chain */
size = p_chain->elem_size * (p_chain->usable_per_page - 1);
p_virt_addr = (u8 *)p_virt_addr + size;
out: return p_virt_addr;
}
/** * qed_chain_set_prod(): sets the prod to the given value. * * @p_chain: Chain. * @prod_idx: Prod Idx. * @p_prod_elem: Prod elem. * * Return Void.
*/ staticinlinevoid qed_chain_set_prod(struct qed_chain *p_chain,
u32 prod_idx, void *p_prod_elem)
{ if (p_chain->mode == QED_CHAIN_MODE_PBL) {
u32 cur_prod, page_mask, page_cnt, page_diff;
/* Assume that number of elements in a page is power of 2 */
page_mask = ~p_chain->elem_per_page_mask;
/* Use "cur_prod - 1" and "prod_idx - 1" since producer index * reaches the first element of next page before the page index * is incremented. See qed_chain_produce(). * Index wrap around is not a problem because the difference * between current and given producer indices is always * positive and lower than the chain's capacity.
*/
page_diff = (((cur_prod - 1) & page_mask) -
((prod_idx - 1) & page_mask)) /
p_chain->elem_per_page;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.