+
+static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
+ unsigned length)
+{
+ int i;
+ u32 temp;
+ struct td_node *lastnode, *node = kzalloc(sizeof(struct td_node),
+ GFP_ATOMIC);
+
+ if (node == NULL)
+ return -ENOMEM;
+
+ node->ptr = dma_pool_alloc(hwep->td_pool, GFP_ATOMIC,
+ &node->dma);
+ if (node->ptr == NULL) {
+ kfree(node);
+ return -ENOMEM;
+ }
+
+ memset(node->ptr, 0, sizeof(struct ci_hw_td));
+ node->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));
+ node->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES);
+ node->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE);
+
+ temp = (u32) (hwreq->req.dma + hwreq->req.actual);
+ if (length) {
+ node->ptr->page[0] = cpu_to_le32(temp);
+ for (i = 1; i < TD_PAGE_COUNT; i++) {
+ u32 page = temp + i * CI_HDRC_PAGE_SIZE;
+ page &= ~TD_RESERVED_MASK;
+ node->ptr->page[i] = cpu_to_le32(page);
+ }
+ }
+
+ hwreq->req.actual += length;
+
+ if (!list_empty(&hwreq->tds)) {
+ /* get the last entry */
+ lastnode = list_entry(hwreq->tds.prev,
+ struct td_node, td);
+ lastnode->ptr->next = cpu_to_le32(node->dma);
+ }
+
+ INIT_LIST_HEAD(&node->td);
+ list_add_tail(&node->td, &hwreq->tds);
+
+ return 0;
+}
+