Ignore:
Timestamp:
2011-10-28T20:53:41Z (14 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
48ae3ef
Parents:
83c3123
Message:

libusbhost: Drop hash_table and use multiple lists instead.

This has several advantages:
Knowing that all endpoints on one address are in one list makes toggle resets more efficient.
Endpoint search is done only once for inserts and deletes.
Lists are part of the structure and not allocated separately, removing one more failure point from init path.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usbhost/src/usb_endpoint_manager.c

    r83c3123 r7265558  
    3434#include <usb/host/usb_endpoint_manager.h>
    3535
    36 #define BUCKET_COUNT 7
    37 #define MAX_KEYS (3)
    38 
    39 static hash_index_t usb_hash(unsigned long key[])
    40 {
    41         /* USB endpoints use 4 bits, thus ((key[0] << 4) | key[1])
    42          * produces unique value for every address.endpoint pair */
    43         return ((key[0] << 4) | key[1]) % BUCKET_COUNT;
    44 }
    45 /*----------------------------------------------------------------------------*/
    46 static int ep_compare(unsigned long key[], hash_count_t keys, link_t *item)
    47 {
    48         assert(item);
    49         endpoint_t *ep = hash_table_get_instance(item, endpoint_t, link);
     36static inline bool ep_match(const endpoint_t *ep,
     37    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
     38{
    5039        assert(ep);
    51         bool match = true;
    52         switch (keys) {
    53         case 3:
    54                 match = match &&
    55                     ((key[2] == ep->direction)
    56                     || (ep->direction == USB_DIRECTION_BOTH)
    57                     || (key[2] == USB_DIRECTION_BOTH));
    58         case 2:
    59                 match = match && (key[1] == (unsigned long)ep->endpoint);
    60         case 1:
    61                 match = match && (key[0] == (unsigned long)ep->address);
    62                 break;
    63         default:
    64                 match = false;
    65         }
    66         return match;
    67 }
    68 /*----------------------------------------------------------------------------*/
    69 static void ep_remove(link_t *item)
    70 {
    71         assert(item);
    72         endpoint_t *ep = hash_table_get_instance(item, endpoint_t, link);
    73         endpoint_destroy(ep);
    74 }
    75 /*----------------------------------------------------------------------------*/
    76 static void toggle_reset_filtered(link_t *item, void *arg)
    77 {
    78         assert(item);
    79         endpoint_t *ep = hash_table_get_instance(item, endpoint_t, link);
    80         const usb_target_t *target = arg;
    81         endpoint_toggle_reset_filtered(ep, *target);
    82 }
    83 /*----------------------------------------------------------------------------*/
    84 static hash_table_operations_t op = {
    85         .hash = usb_hash,
    86         .compare = ep_compare,
    87         .remove_callback = ep_remove,
    88 };
     40        return
     41            ((direction == ep->direction)
     42                || (ep->direction == USB_DIRECTION_BOTH)
     43                || (direction == USB_DIRECTION_BOTH))
     44            && (endpoint == ep->endpoint)
     45            && (address == ep->address);
     46}
     47/*----------------------------------------------------------------------------*/
     48static list_t * get_list(usb_endpoint_manager_t *instance, usb_address_t addr)
     49{
     50        assert(instance);
     51        return &instance->endpoint_lists[addr % ENDPOINT_LIST_COUNT];
     52}
     53/*----------------------------------------------------------------------------*/
     54static endpoint_t * find_locked(usb_endpoint_manager_t *instance,
     55    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
     56{
     57        assert(instance);
     58        assert(fibril_mutex_is_locked(&instance->guard));
     59        list_foreach(*get_list(instance, address), iterator) {
     60                endpoint_t *ep = endpoint_get_instance(iterator);
     61                if (ep_match(ep, address, endpoint, direction))
     62                        return ep;
     63        }
     64        return NULL;
     65}
    8966/*----------------------------------------------------------------------------*/
    9067size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type,
     
    9976        const unsigned packet_count =
    10077            (size + max_packet_size - 1) / max_packet_size;
    101         /* TODO: It may be that ISO and INT transfers use only one data packet
    102          * per transaction, but I did not find text in UB spec that confirms
    103          * this */
     78        /* TODO: It may be that ISO and INT transfers use only one packet per
     79         * transaction, but I did not find text in USB spec to confirm this */
    10480        /* NOTE: All data packets will be considered to be max_packet_size */
    10581        switch (speed)
     
    138114        instance->free_bw = available_bandwidth;
    139115        instance->bw_count = bw_count;
    140         const bool ht =
    141             hash_table_create(&instance->ep_table, BUCKET_COUNT, MAX_KEYS, &op);
    142         return ht ? EOK : ENOMEM;
    143 }
    144 /*----------------------------------------------------------------------------*/
    145 void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance)
    146 {
    147         hash_table_destroy(&instance->ep_table);
     116        for (unsigned i = 0; i < ENDPOINT_LIST_COUNT; ++i) {
     117                list_initialize(&instance->endpoint_lists[i]);
     118        }
     119        return EOK;
    148120}
    149121/*----------------------------------------------------------------------------*/
     
    164136        }
    165137
    166         unsigned long key[MAX_KEYS] =
    167             {ep->address, ep->endpoint, ep->direction};
    168 
    169         const link_t *item =
    170             hash_table_find(&instance->ep_table, key);
    171         if (item != NULL) {
     138        /* Check for existence */
     139        const endpoint_t *endpoint =
     140            find_locked(instance, ep->address, ep->endpoint, ep->direction);
     141        if (endpoint != NULL) {
    172142                fibril_mutex_unlock(&instance->guard);
    173143                return EEXISTS;
    174144        }
    175 
    176         hash_table_insert(&instance->ep_table, key, &ep->link);
     145        list_t *list = get_list(instance, ep->address);
     146        list_append(&ep->link, list);
     147
    177148        instance->free_bw -= ep->bandwidth;
    178149        fibril_mutex_unlock(&instance->guard);
     
    184155{
    185156        assert(instance);
    186         unsigned long key[MAX_KEYS] = {address, endpoint, direction};
    187157
    188158        fibril_mutex_lock(&instance->guard);
    189         link_t *item = hash_table_find(&instance->ep_table, key);
    190         if (item == NULL) {
    191                 fibril_mutex_unlock(&instance->guard);
    192                 return EINVAL;
    193         }
    194 
    195         endpoint_t *ep = hash_table_get_instance(item, endpoint_t, link);
    196         if (ep->active) {
    197                 fibril_mutex_unlock(&instance->guard);
    198                 return EBUSY;
    199         }
    200 
    201         instance->free_bw += ep->bandwidth;
    202         hash_table_remove(&instance->ep_table, key, MAX_KEYS);
     159        endpoint_t *ep = find_locked(instance, address, endpoint, direction);
     160        if (ep != NULL) {
     161                list_remove(&ep->link);
     162                instance->free_bw += ep->bandwidth;
     163        }
    203164
    204165        fibril_mutex_unlock(&instance->guard);
    205         return EOK;
     166        endpoint_destroy(ep);
     167        return (ep != NULL) ? EOK : EINVAL;
    206168}
    207169/*----------------------------------------------------------------------------*/
     
    210172{
    211173        assert(instance);
    212         unsigned long key[MAX_KEYS] = {address, endpoint, direction};
    213174
    214175        fibril_mutex_lock(&instance->guard);
    215         const link_t *item = hash_table_find(&instance->ep_table, key);
    216         if (item == NULL) {
    217                 fibril_mutex_unlock(&instance->guard);
    218                 return NULL;
    219         }
    220         endpoint_t *ep = hash_table_get_instance(item, endpoint_t, link);
    221 
     176        endpoint_t *ep = find_locked(instance, address, endpoint, direction);
    222177        fibril_mutex_unlock(&instance->guard);
     178
    223179        return ep;
    224180}
     
    247203                /* Recipient is endpoint, value is zero (ENDPOINT_STALL) */
    248204                if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
     205                        fibril_mutex_lock(&instance->guard);
    249206                        /* endpoint number is < 16, thus first byte is enough */
    250                         usb_target_t reset_target =
    251                             { .address = target.address, data[4] };
    252                         fibril_mutex_lock(&instance->guard);
    253                         hash_table_apply(&instance->ep_table,
    254                             toggle_reset_filtered, &reset_target);
     207                        list_foreach(*get_list(instance, target.address), it) {
     208                                endpoint_t *ep = endpoint_get_instance(it);
     209                                if ((ep->address == target.address)
     210                                    && (ep->endpoint = data[4])) {
     211                                        endpoint_toggle_set(ep,0);
     212                                }
     213                        }
    255214                        fibril_mutex_unlock(&instance->guard);
    256215                }
     
    259218        case 0x9: /* Set Configuration */
    260219        case 0x11: /* Set Interface */
    261                 /* Recipient must be device */
     220                /* Recipient must be device, this resets all endpoints,
     221                 * In fact there should be no endpoints but EP 0 registered
     222                 * as different interfaces use different endpoints. */
    262223                if ((data[0] & 0xf) == 0) {
    263                         usb_target_t reset_target =
    264                             { .address = target.address, 0 };
    265224                        fibril_mutex_lock(&instance->guard);
    266                         hash_table_apply(&instance->ep_table,
    267                             toggle_reset_filtered, &reset_target);
     225                        list_foreach(*get_list(instance, target.address), it) {
     226                                endpoint_t *ep = endpoint_get_instance(it);
     227                                if (ep->address == target.address) {
     228                                        endpoint_toggle_set(ep,0);
     229                                }
     230                        }
    268231                        fibril_mutex_unlock(&instance->guard);
    269232                }
Note: See TracChangeset for help on using the changeset viewer.