Changeset 5595841 in mainline


Ignore:
Timestamp:
2018-01-31T16:02:34Z (6 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
3b60ea0
Parents:
2b3dd78
git-author:
Ondřej Hlavatý <aearsis@…> (2018-01-31 15:49:24)
git-committer:
Ondřej Hlavatý <aearsis@…> (2018-01-31 16:02:34)
Message:

libdrv: usbhc_iface now shares memory instead of sending data

Two more things that come along:
1) The two callbacks (read, write) were joined. As they were joined in

the only implementation (ddf_helpers) anyway, and now the code is
almost the same, we took the opportunity and joined them. The bad
thing about it is that there are not enough IPC arguments to
transfer the direction, so we still have to use two "interface IPC
methods".

2) The copying is still done by the former methods (usbhc_read and

usbhc_write) to ensure the page alignment, so this method just
moves the burden of copying from kernel to the caller (which is why
this is actually a performance regression).

But, the two sides can now resolve their issues separately. The caller
can prepare the memory area in advance, and HC can use the memory
directly if it can.

Location:
uspace/lib
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/drv/generic/remote_usbhc.c

    r2b3dd78 r5595841  
    3939#include <errno.h>
    4040#include <devman.h>
     41#include <as.h>
    4142
    4243#include "usbhc_iface.h"
     
    178179}
    179180
    180 errno_t usbhc_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
    181     void *data, size_t size, size_t *rec_size)
    182 {
     181/**
     182 * Issue a USB transfer with a data contained in memory area. That area is
     183 * temporarily shared with the HC.
     184 */
     185errno_t usbhc_transfer(async_exch_t *exch, usb_endpoint_t endpoint,
     186    usb_direction_t dir, uint64_t setup, void *area, size_t size,
     187    size_t *transferred)
     188{
     189        if (transferred)
     190                *transferred = 0;
     191
    183192        if (!exch)
    184193                return EBADMEM;
     
    187196                return EOK;
    188197
    189         /* Make call identifying target USB device and type of transfer. */
    190         aid_t opening_request = async_send_4(exch,
    191             DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_READ, endpoint,
    192             (setup & UINT32_MAX), (setup >> 32), NULL);
    193 
    194         if (opening_request == 0) {
     198        sysarg_t method = (dir == USB_DIRECTION_IN)
     199                ? IPC_M_USB_READ : IPC_M_USB_WRITE;
     200
     201        ipc_call_t call;
     202
     203
     204        aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
     205            method, endpoint, size, (setup & UINT32_MAX), (setup >> 32), &call);
     206
     207        if (opening_request == 0)
    195208                return ENOMEM;
    196         }
    197 
    198         /* Retrieve the data. */
    199         ipc_call_t data_request_call;
    200         aid_t data_request =
    201             async_data_read(exch, data, size, &data_request_call);
    202 
    203         if (data_request == 0) {
    204                 // FIXME: How to let the other side know that we want to abort?
    205                 async_forget(opening_request);
    206                 return ENOMEM;
    207         }
    208 
    209         /* Wait for the answer. */
    210         errno_t data_request_rc;
    211         errno_t opening_request_rc;
    212         async_wait_for(data_request, &data_request_rc);
    213         async_wait_for(opening_request, &opening_request_rc);
    214 
    215         if (data_request_rc != EOK) {
    216                 /* Prefer the return code of the opening request. */
    217                 if (opening_request_rc != EOK) {
    218                         return (errno_t) opening_request_rc;
    219                 } else {
    220                         return (errno_t) data_request_rc;
    221                 }
    222         }
    223         if (opening_request_rc != EOK) {
    224                 return (errno_t) opening_request_rc;
    225         }
    226 
    227         *rec_size = IPC_GET_ARG2(data_request_call);
    228         return EOK;
    229 }
    230 
    231 errno_t usbhc_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
    232     const void *data, size_t size)
    233 {
    234         if (!exch)
    235                 return EBADMEM;
    236 
    237         if (size == 0 && setup == 0)
    238                 return EOK;
    239 
    240         aid_t opening_request = async_send_5(exch,
    241             DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size,
    242             (setup & UINT32_MAX), (setup >> 32), NULL);
    243 
    244         if (opening_request == 0) {
    245                 return ENOMEM;
    246         }
    247209
    248210        /* Send the data if any. */
    249211        if (size > 0) {
    250                 const errno_t ret = async_data_write_start(exch, data, size);
     212                unsigned flags = (dir == USB_DIRECTION_IN)
     213                        ? AS_AREA_WRITE : AS_AREA_READ;
     214
     215                const errno_t ret = async_share_out_start(exch, area, flags);
    251216                if (ret != EOK) {
    252217                        async_forget(opening_request);
     
    259224        async_wait_for(opening_request, &opening_request_rc);
    260225
     226        if (transferred)
     227                *transferred = IPC_GET_ARG1(call);
     228
    261229        return (errno_t) opening_request_rc;
     230}
     231
     232errno_t usbhc_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
     233    void *data, size_t size, size_t *rec_size)
     234{
     235        if (size == 0)
     236                return usbhc_transfer(exch, endpoint, USB_DIRECTION_IN,
     237                    setup, NULL, 0, NULL);
     238
     239        /* Prepare an area to read */
     240        void *area = as_area_create(AS_AREA_ANY, size,
     241            AS_AREA_READ | AS_AREA_WRITE, AS_AREA_UNPAGED);
     242        if (!area)
     243                return ENOMEM;
     244
     245        const errno_t err = usbhc_transfer(exch, endpoint, USB_DIRECTION_IN,
     246            setup, area, size, rec_size);
     247        if (err == EOK)
     248                memcpy(data, area, *rec_size);
     249
     250        as_area_destroy(area);
     251        return err;
     252}
     253
     254errno_t usbhc_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
     255    const void *data, size_t size)
     256{
     257        if (size == 0)
     258                return usbhc_transfer(exch, endpoint, USB_DIRECTION_OUT,
     259                    setup, NULL, 0, NULL);
     260
     261        /* Prepare an area to read */
     262        void *area = as_area_create(AS_AREA_ANY, size,
     263            AS_AREA_READ | AS_AREA_WRITE, AS_AREA_UNPAGED);
     264        if (!area)
     265                return ENOMEM;
     266
     267        memcpy(area, data, size);
     268        const errno_t err = usbhc_transfer(exch, endpoint, USB_DIRECTION_OUT,
     269            setup, area, size, NULL);
     270        as_area_destroy(area);
     271        return err;
    262272}
    263273
     
    267277static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    268278static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    269 static void remote_usbhc_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
    270 static void remote_usbhc_write(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
     279static void remote_usbhc_transfer(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
    271280
    272281/** Remote USB interface operations. */
     
    277286        [IPC_M_USB_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
    278287        [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint,
    279         [IPC_M_USB_READ] = remote_usbhc_read,
    280         [IPC_M_USB_WRITE] = remote_usbhc_write,
     288        [IPC_M_USB_READ] = remote_usbhc_transfer,
     289        [IPC_M_USB_WRITE] = remote_usbhc_transfer,
    281290};
    282291
     
    290299typedef struct {
    291300        ipc_callid_t caller;
    292         ipc_callid_t data_caller;
    293301        void *buffer;
    294302} async_transaction_t;
     
    413421        }
    414422        if (trans->buffer != NULL) {
    415                 free(trans->buffer);
     423                as_area_destroy(trans->buffer);
    416424        }
    417425
     
    427435
    428436        trans->caller = caller;
    429         trans->data_caller = 0;
    430437        trans->buffer = NULL;
    431438
     
    433440}
    434441
    435 static errno_t callback_out(void *arg, int error, size_t transferred_size)
     442static errno_t transfer_finished(void *arg, int error, size_t transferred_size)
    436443{
    437444        async_transaction_t *trans = arg;
    438 
    439         const errno_t err = async_answer_0(trans->caller, error);
    440 
    441         async_transaction_destroy(trans);
    442 
    443         return err;
    444 }
    445 
    446 static errno_t callback_in(void *arg, int error, size_t transferred_size)
    447 {
    448         async_transaction_t *trans = arg;
    449 
    450         if (trans->data_caller) {
    451                 if (error == EOK) {
    452                         error = async_data_read_finalize(trans->data_caller,
    453                             trans->buffer, transferred_size);
    454                 } else {
    455                         async_answer_0(trans->data_caller, EINTR);
    456                 }
    457         }
    458 
    459         const errno_t err = async_answer_0(trans->caller, error);
     445        const errno_t err = async_answer_1(trans->caller, error, transferred_size);
    460446        async_transaction_destroy(trans);
    461447        return err;
    462448}
    463449
    464 void remote_usbhc_read(
    465     ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
     450static errno_t receive_memory_buffer(async_transaction_t *trans,
     451        size_t required_size, unsigned required_flags)
     452{
     453        assert(trans);
     454        assert(required_size > 0);
     455
     456        errno_t err;
     457        ipc_callid_t data_callid;
     458        size_t size;
     459        unsigned flags;
     460
     461        if (!async_share_out_receive(&data_callid, &size, &flags))
     462                return EPARTY;
     463
     464        if (size < required_size || (flags & required_flags) != required_flags) {
     465                async_answer_0(data_callid, EINVAL);
     466                return EINVAL;
     467        }
     468
     469        if ((err = async_share_out_finalize(data_callid, &trans->buffer)))
     470                return err;
     471
     472        return EOK;
     473}
     474
     475void remote_usbhc_transfer(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
    466476{
    467477        assert(fun);
     
    471481        const usbhc_iface_t *usbhc_iface = iface;
    472482
    473         if (!usbhc_iface->read) {
     483        if (!usbhc_iface->transfer) {
    474484                async_answer_0(callid, ENOTSUP);
    475485                return;
    476486        }
    477487
    478         const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
    479         const uint64_t setup =
    480             ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
    481             (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
     488        const sysarg_t method = IPC_GET_ARG1(*call);
     489        const usb_direction_t dir =
     490                method == IPC_M_USB_READ ? USB_DIRECTION_IN : USB_DIRECTION_OUT;
     491
     492        const usb_endpoint_t ep = IPC_GET_ARG2(*call);
     493        const size_t size = IPC_GET_ARG3(*call);
     494        const uint64_t setup = ((uint64_t)IPC_GET_ARG4(*call)) |
     495            (((uint64_t)IPC_GET_ARG5(*call)) << 32);
    482496
    483497        async_transaction_t *trans = async_transaction_create(callid);
     
    487501        }
    488502
    489         size_t size = 0;
    490         if (!async_data_read_receive(&trans->data_caller, &size)) {
    491                 async_answer_0(callid, EPARTY);
    492                 async_transaction_destroy(trans);
    493                 return;
    494         }
    495 
    496         trans->buffer = malloc(size);
    497         if (trans->buffer == NULL) {
    498                 async_answer_0(trans->data_caller, ENOMEM);
    499                 async_answer_0(callid, ENOMEM);
    500                 async_transaction_destroy(trans);
    501                 return;
    502         }
    503 
    504         const usb_target_t target = {{
    505                 /* .address is initialized by read itself */
    506                 .endpoint = ep,
    507         }};
    508 
    509         const errno_t rc = usbhc_iface->read(
    510             fun, target, setup, trans->buffer, size, callback_in, trans);
    511 
    512         if (rc != EOK) {
    513                 async_answer_0(trans->data_caller, rc);
    514                 async_answer_0(callid, rc);
    515                 async_transaction_destroy(trans);
    516         }
    517 }
    518 
    519 void remote_usbhc_write(
    520     ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
    521 {
    522         assert(fun);
    523         assert(iface);
    524         assert(call);
    525 
    526         const usbhc_iface_t *usbhc_iface = iface;
    527 
    528         if (!usbhc_iface->write) {
    529                 async_answer_0(callid, ENOTSUP);
    530                 return;
    531         }
    532 
    533         const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
    534         const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
    535         const uint64_t setup =
    536             ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
    537             (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
    538 
    539         async_transaction_t *trans = async_transaction_create(callid);
    540         if (trans == NULL) {
    541                 async_answer_0(callid, ENOMEM);
    542                 return;
    543         }
    544 
    545         size_t size = 0;
    546         if (data_buffer_len > 0) {
    547                 const errno_t rc = async_data_write_accept(&trans->buffer, false,
    548                     1, data_buffer_len, 0, &size);
    549 
     503        if (size > 0) {
     504                const unsigned required_flags = (dir == USB_DIRECTION_IN)
     505                        ? AS_AREA_WRITE : AS_AREA_READ;
     506
     507                const errno_t rc = receive_memory_buffer(trans, size, required_flags);
    550508                if (rc != EOK) {
     509                        async_transaction_destroy(trans);
    551510                        async_answer_0(callid, rc);
    552                         async_transaction_destroy(trans);
    553511                        return;
    554512                }
     
    562520        }};
    563521
    564         const errno_t rc = usbhc_iface->write(
    565             fun, target, setup, trans->buffer, size, callback_out, trans);
     522        const errno_t rc = usbhc_iface->transfer(fun, target, dir, setup,
     523            trans->buffer, size, &transfer_finished, trans);
    566524
    567525        if (rc != EOK) {
     
    570528        }
    571529}
     530
    572531/**
    573532 * @}
  • uspace/lib/drv/include/usbhc_iface.h

    r2b3dd78 r5595841  
    148148extern errno_t usbhc_unregister_endpoint(async_exch_t *, const usb_pipe_desc_t *);
    149149
     150extern errno_t usbhc_transfer(async_exch_t *, usb_endpoint_t, usb_direction_t,
     151    uint64_t, void *, size_t, size_t *);
    150152extern errno_t usbhc_read(async_exch_t *, usb_endpoint_t, uint64_t, void *, size_t,
    151153    size_t *);
     
    166168        int (*unregister_endpoint)(ddf_fun_t *, const usb_pipe_desc_t *);
    167169
    168         errno_t (*read)(ddf_fun_t *, usb_target_t,
    169                 uint64_t, char *, size_t,
    170                 usbhc_iface_transfer_callback_t, void *);
    171         errno_t (*write)(ddf_fun_t *, usb_target_t,
    172                 uint64_t, const char *, size_t,
     170        errno_t (*transfer)(ddf_fun_t *, usb_target_t,
     171                usb_direction_t, uint64_t, char *, size_t,
    173172                usbhc_iface_transfer_callback_t, void *);
    174173} usbhc_iface_t;
  • uspace/lib/usbhost/src/ddf_helpers.c

    r2b3dd78 r5595841  
    254254}
    255255
    256 /** Inbound communication interface function.
     256/**
     257 * Transfer issuing interface function.
     258 *
    257259 * @param fun DDF function.
    258260 * @param target Communication target.
     261 * @param dir Communication direction.
    259262 * @param setup_data Data to use in setup stage (control transfers).
    260263 * @param data Pointer to data buffer.
     
    264267 * @return Error code.
    265268 */
    266 static errno_t dev_read(ddf_fun_t *fun, usb_target_t target,
    267     uint64_t setup_data, char *data, size_t size,
     269static errno_t transfer(ddf_fun_t *fun, usb_target_t target,
     270    usb_direction_t dir, uint64_t setup_data, char *data, size_t size,
    268271    usbhc_iface_transfer_callback_t callback, void *arg)
    269272{
     
    283286                return EBADMEM;
    284287
    285         return bus_device_send_batch(dev, target, USB_DIRECTION_IN,
    286             data, size, setup_data,
    287             callback, arg, "READ");
    288 }
    289 
    290 /** Outbound communication interface function.
    291  * @param fun DDF function.
    292  * @param target Communication target.
    293  * @param setup_data Data to use in setup stage (control transfers).
    294  * @param data Pointer to data buffer.
    295  * @param size Size of the data buffer.
    296  * @param callback Function to call on communication end.
    297  * @param arg Argument passed to the callback function.
    298  * @return Error code.
    299  */
    300 static errno_t dev_write(ddf_fun_t *fun, usb_target_t target,
    301     uint64_t setup_data, const char *data, size_t size,
    302     usbhc_iface_transfer_callback_t callback, void *arg)
    303 {
    304         assert(fun);
    305         device_t *dev = ddf_fun_data_get(fun);
    306         assert(dev);
    307 
    308         target.address = dev->address;
    309 
    310         if (!usb_target_is_valid(&target))
    311                 return EINVAL;
    312 
    313         if (size > 0 && data == NULL)
    314                 return EBADMEM;
    315 
    316         if (!callback && arg)
    317                 return EBADMEM;
    318 
    319         return bus_device_send_batch(dev, target, USB_DIRECTION_OUT,
     288        const char *name = (dir == USB_DIRECTION_IN) ? "READ" : "WRITE";
     289
     290        return bus_device_send_batch(dev, target, dir,
    320291            (char *) data, size, setup_data,
    321             callback, arg, "WRITE");
     292            callback, arg, name);
    322293}
    323294
     
    337308        .unregister_endpoint = unregister_endpoint,
    338309
    339         .read = dev_read,
    340         .write = dev_write,
     310        .transfer = transfer,
    341311};
    342312
Note: See TracChangeset for help on using the changeset viewer.