Changeset 361e61b in mainline for uspace/drv/uhci-hcd/transfer_list.c


Ignore:
Timestamp:
2011-03-21T14:23:15Z (13 years ago)
Author:
Matej Klonfar <maklf@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
55e388a1
Parents:
c32688d (diff), 48fe0c9 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

merge with development

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/uhci-hcd/transfer_list.c

    rc32688d r361e61b  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcihc
    2929 * @{
    3030 */
    3131/** @file
    32  * @brief UHCI driver
     32 * @brief UHCI driver transfer list implementation
    3333 */
    3434#include <errno.h>
    35 
    3635#include <usb/debug.h>
    3736
     
    4140    transfer_list_t *instance, batch_t *batch);
    4241/*----------------------------------------------------------------------------*/
    43 /** Initializes transfer list structures.
     42/** Initialize transfer list structures.
    4443 *
    4544 * @param[in] instance Memory place to use.
    46  * @param[in] name Name of te new list.
    47  * @return Error code
    48  *
    49  * Allocates memory for internat queue_head_t structure.
     45 * @param[in] name Name of the new list.
     46 * @return Error code
     47 *
     48 * Allocates memory for internal qh_t structure.
    5049 */
    5150int transfer_list_init(transfer_list_t *instance, const char *name)
    5251{
    5352        assert(instance);
    54         instance->next = NULL;
    5553        instance->name = name;
    56         instance->queue_head = malloc32(sizeof(queue_head_t));
     54        instance->queue_head = malloc32(sizeof(qh_t));
    5755        if (!instance->queue_head) {
    5856                usb_log_error("Failed to allocate queue head.\n");
     
    6159        instance->queue_head_pa = addr_to_phys(instance->queue_head);
    6260
    63         queue_head_init(instance->queue_head);
     61        qh_init(instance->queue_head);
    6462        list_initialize(&instance->batch_list);
    6563        fibril_mutex_initialize(&instance->guard);
     
    6765}
    6866/*----------------------------------------------------------------------------*/
    69 /** Set the next list in chain.
     67/** Set the next list in transfer list chain.
    7068 *
    7169 * @param[in] instance List to lead.
    7270 * @param[in] next List to append.
    7371 * @return Error code
     72 *
     73 * Does not check whether this replaces an existing list .
    7474 */
    7575void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next)
     
    7979        if (!instance->queue_head)
    8080                return;
    81         queue_head_append_qh(instance->queue_head, next->queue_head_pa);
    82         instance->queue_head->element = instance->queue_head->next_queue;
    83 }
    84 /*----------------------------------------------------------------------------*/
    85 /** Submits a new transfer batch to list and queue.
     81        /* Set both next and element to point to the same QH */
     82        qh_set_next_qh(instance->queue_head, next->queue_head_pa);
     83        qh_set_element_qh(instance->queue_head, next->queue_head_pa);
     84}
     85/*----------------------------------------------------------------------------*/
     86/** Submit transfer batch to the list and queue.
    8687 *
    8788 * @param[in] instance List to use.
    8889 * @param[in] batch Transfer batch to submit.
    8990 * @return Error code
     91 *
     92 * The batch is added to the end of the list and queue.
    9093 */
    9194void transfer_list_add_batch(transfer_list_t *instance, batch_t *batch)
     
    9396        assert(instance);
    9497        assert(batch);
    95         usb_log_debug2(
    96             "Adding batch(%p) to queue %s.\n", batch, instance->name);
    97 
    98         uint32_t pa = (uintptr_t)addr_to_phys(batch->qh);
     98        usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, batch);
     99
     100        const uint32_t pa = addr_to_phys(batch_qh(batch));
    99101        assert((pa & LINK_POINTER_ADDRESS_MASK) == pa);
    100         pa |= LINK_POINTER_QUEUE_HEAD_FLAG;
    101 
    102         batch->qh->next_queue = instance->queue_head->next_queue;
     102
     103        /* New batch will be added to the end of the current list
     104         * so set the link accordingly */
     105        qh_set_next_qh(batch_qh(batch), instance->queue_head->next);
    103106
    104107        fibril_mutex_lock(&instance->guard);
    105108
    106         if (instance->queue_head->element == instance->queue_head->next_queue) {
    107                 /* there is nothing scheduled */
    108                 list_append(&batch->link, &instance->batch_list);
    109                 instance->queue_head->element = pa;
    110                 usb_log_debug("Batch(%p) added to queue %s first.\n",
    111                         batch, instance->name);
    112                 fibril_mutex_unlock(&instance->guard);
    113                 return;
    114         }
    115         /* now we can be sure that there is someting scheduled */
    116         assert(!list_empty(&instance->batch_list));
     109        /* Add to the hardware queue. */
     110        if (list_empty(&instance->batch_list)) {
     111                /* There is nothing scheduled */
     112                qh_t *qh = instance->queue_head;
     113                assert(qh->element == qh->next);
     114                qh_set_element_qh(qh, pa);
     115        } else {
     116                /* There is something scheduled */
     117                batch_t *last = list_get_instance(
     118                    instance->batch_list.prev, batch_t, link);
     119                qh_set_next_qh(batch_qh(last), pa);
     120        }
     121        /* Add to the driver list */
     122        list_append(&batch->link, &instance->batch_list);
     123
    117124        batch_t *first = list_get_instance(
    118                   instance->batch_list.next, batch_t, link);
    119         batch_t *last = list_get_instance(
    120             instance->batch_list.prev, batch_t, link);
    121         queue_head_append_qh(last->qh, pa);
    122         list_append(&batch->link, &instance->batch_list);
    123 
    124         usb_log_debug("Batch(%p) added to queue %s last, first is %p.\n",
     125            instance->batch_list.next, batch_t, link);
     126        usb_log_debug("Batch(%p) added to queue %s, first is %p.\n",
    125127                batch, instance->name, first);
    126128        fibril_mutex_unlock(&instance->guard);
    127129}
    128130/*----------------------------------------------------------------------------*/
    129 /** Removes a transfer batch from list and queue.
    130  *
    131  * @param[in] instance List to use.
    132  * @param[in] batch Transfer batch to remove.
    133  * @return Error code
    134  */
    135 void transfer_list_remove_batch(transfer_list_t *instance, batch_t *batch)
    136 {
    137         assert(instance);
    138         assert(batch);
    139         assert(instance->queue_head);
    140         assert(batch->qh);
    141         usb_log_debug2(
    142             "Removing batch(%p) from queue %s.\n", batch, instance->name);
    143 
    144         if (batch->link.prev == &instance->batch_list) {
    145                 /* I'm the first one here */
    146                 usb_log_debug(
    147                     "Batch(%p) removed (FIRST) from %s, next element %x.\n",
    148                     batch, instance->name, batch->qh->next_queue);
    149                 instance->queue_head->element = batch->qh->next_queue;
    150         } else {
    151                 usb_log_debug(
    152                     "Batch(%p) removed (FIRST:NO) from %s, next element %x.\n",
    153                     batch, instance->name, batch->qh->next_queue);
    154                 batch_t *prev =
    155                     list_get_instance(batch->link.prev, batch_t, link);
    156                 prev->qh->next_queue = batch->qh->next_queue;
    157         }
    158         list_remove(&batch->link);
    159 }
    160 /*----------------------------------------------------------------------------*/
    161 /** Checks list for finished transfers.
    162  *
    163  * @param[in] instance List to use.
    164  * @return Error code
     131/** Check list for finished batches.
     132 *
     133 * @param[in] instance List to use.
     134 * @return Error code
     135 *
     136 * Creates a local list of finished batches and calls next_step on each and
     137 * every one. This is safer because next_step may theoretically access
     138 * this transfer list leading to the deadlock if its done inline.
    165139 */
    166140void transfer_list_remove_finished(transfer_list_t *instance)
     
    177151
    178152                if (batch_is_complete(batch)) {
     153                        /* Save for post-processing */
    179154                        transfer_list_remove_batch(instance, batch);
    180155                        list_append(current, &done);
     
    191166        }
    192167}
     168/*----------------------------------------------------------------------------*/
     169/** Walk the list and abort all batches.
     170 *
     171 * @param[in] instance List to use.
     172 */
     173void transfer_list_abort_all(transfer_list_t *instance)
     174{
     175        fibril_mutex_lock(&instance->guard);
     176        while (list_empty(&instance->batch_list)) {
     177                link_t *current = instance->batch_list.next;
     178                batch_t *batch = list_get_instance(current, batch_t, link);
     179                transfer_list_remove_batch(instance, batch);
     180                batch_finish(batch, EIO);
     181        }
     182        fibril_mutex_unlock(&instance->guard);
     183}
     184/*----------------------------------------------------------------------------*/
     185/** Remove a transfer batch from the list and queue.
     186 *
     187 * @param[in] instance List to use.
     188 * @param[in] batch Transfer batch to remove.
     189 * @return Error code
     190 *
     191 * Does not lock the transfer list, caller is responsible for that.
     192 */
     193void transfer_list_remove_batch(transfer_list_t *instance, batch_t *batch)
     194{
     195        assert(instance);
     196        assert(instance->queue_head);
     197        assert(batch);
     198        assert(batch_qh(batch));
     199        usb_log_debug2(
     200            "Queue %s: removing batch(%p).\n", instance->name, batch);
     201
     202        const char * pos = NULL;
     203        /* Remove from the hardware queue */
     204        if (batch->link.prev == &instance->batch_list) {
     205                /* I'm the first one here */
     206                qh_set_element_qh(instance->queue_head, batch_qh(batch)->next);
     207                pos = "FIRST";
     208        } else {
     209                batch_t *prev =
     210                    list_get_instance(batch->link.prev, batch_t, link);
     211                qh_set_next_qh(batch_qh(prev), batch_qh(batch)->next);
     212                pos = "NOT FIRST";
     213        }
     214        /* Remove from the driver list */
     215        list_remove(&batch->link);
     216        usb_log_debug("Batch(%p) removed (%s) from %s, next element %x.\n",
     217            batch, pos, instance->name, batch_qh(batch)->next);
     218}
    193219/**
    194220 * @}
Note: See TracChangeset for help on using the changeset viewer.