Changeset 7265558 in mainline


Ignore:
Timestamp:
2011-10-28T20:53:41Z (12 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.

Location:
uspace
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/ohci/hc.c

    r83c3123 r7265558  
    192192        list_initialize(&instance->pending_batches);
    193193
    194         ret = hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
     194        hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
    195195            bandwidth_count_usb11);
    196         CHECK_RET_RETURN(ret, "Failed to initialize generic driver: %s.\n",
    197             str_error(ret));
    198196        instance->generic.private_data = instance;
    199197        instance->generic.schedule = hc_schedule;
  • uspace/drv/bus/usb/uhci/hc.c

    r83c3123 r7265558  
    192192            "Device registers at %p (%zuB) accessible.\n", io, reg_size);
    193193
    194         ret = hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
     194        ret = hc_init_mem_structures(instance);
     195        CHECK_RET_RETURN(ret,
     196            "Failed to initialize UHCI memory structures: %s.\n",
     197            str_error(ret));
     198
     199#undef CHECK_RET_RETURN
     200
     201        hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
    195202            bandwidth_count_usb11);
    196         CHECK_RET_RETURN(ret, "Failed to initialize HCD generic driver: %s.\n",
    197             str_error(ret));
    198203
    199204        instance->generic.private_data = instance;
    200205        instance->generic.schedule = hc_schedule;
    201206        instance->generic.ep_add_hook = NULL;
    202 
    203 #undef CHECK_RET_DEST_FUN_RETURN
    204 
    205         ret = hc_init_mem_structures(instance);
    206         if (ret != EOK) {
    207                 usb_log_error(
    208                     "Failed to initialize UHCI memory structures: %s.\n",
    209                     str_error(ret));
    210                 hcd_destroy(&instance->generic);
    211                 return ret;
    212         }
    213207
    214208        hc_init_hw(instance);
  • uspace/lib/usbhost/include/usb/host/endpoint.h

    r83c3123 r7265558  
    7777int endpoint_toggle_get(endpoint_t *instance);
    7878void endpoint_toggle_set(endpoint_t *instance, int toggle);
    79 void endpoint_toggle_reset_filtered(endpoint_t *instance, usb_target_t target);
     79
     80static inline endpoint_t * endpoint_get_instance(link_t *item)
     81{
     82        return list_get_instance(item, endpoint_t, link);
     83}
    8084#endif
    8185/**
  • uspace/lib/usbhost/include/usb/host/hcd.h

    r83c3123 r7265558  
    3737
    3838#include <assert.h>
     39#include <usbhc_iface.h>
    3940#include <usb/host/usb_device_manager.h>
    4041#include <usb/host/usb_endpoint_manager.h>
    4142#include <usb/host/usb_transfer_batch.h>
    42 #include <usbhc_iface.h>
    4343
    4444typedef struct hcd hcd_t;
     
    5353};
    5454/*----------------------------------------------------------------------------*/
    55 static inline int hcd_init(hcd_t *hcd, size_t bandwidth,
     55static inline void hcd_init(hcd_t *hcd, size_t bandwidth,
    5656    size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t))
    5757{
    5858        assert(hcd);
    5959        usb_device_manager_init(&hcd->dev_manager);
    60         return usb_endpoint_manager_init(&hcd->ep_manager, bandwidth, bw_count);
    61 }
    62 /*----------------------------------------------------------------------------*/
    63 static inline void hcd_destroy(hcd_t *hcd)
    64 {
    65         usb_endpoint_manager_destroy(&hcd->ep_manager);
     60        usb_endpoint_manager_init(&hcd->ep_manager, bandwidth, bw_count);
    6661}
    6762/*----------------------------------------------------------------------------*/
  • uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h

    r83c3123 r7265558  
    4040#define LIBUSBHOST_HOST_USB_ENDPOINT_MANAGER_H
    4141
    42 #include <stdlib.h>
    43 #include <adt/hash_table.h>
     42#include <adt/list.h>
    4443#include <fibril_synch.h>
    4544#include <usb/usb.h>
     45
    4646#include <usb/host/endpoint.h>
    4747
    4848#define BANDWIDTH_TOTAL_USB11 12000000
    4949#define BANDWIDTH_AVAILABLE_USB11 ((BANDWIDTH_TOTAL_USB11 / 10) * 9)
     50#define ENDPOINT_LIST_COUNT 8
    5051
    5152typedef struct usb_endpoint_manager {
    52         hash_table_t ep_table;
     53        list_t endpoint_lists[ENDPOINT_LIST_COUNT];
    5354        fibril_mutex_t guard;
    5455        size_t free_bw;
  • uspace/lib/usbhost/src/endpoint.c

    r83c3123 r7265558  
    133133        instance->toggle = toggle;
    134134}
    135 /*----------------------------------------------------------------------------*/
    136 void endpoint_toggle_reset_filtered(endpoint_t *instance, usb_target_t target)
    137 {
    138         assert(instance);
    139         if (instance->address == target.address &&
    140             (instance->endpoint == target.endpoint || target.endpoint == 0))
    141                 endpoint_toggle_set(instance, 0);
    142 }
    143135/**
    144136 * @}
  • 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.