Ignore:
Timestamp:
2018-01-31T16:02:34Z (7 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.

File:
1 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 * @}
Note: See TracChangeset for help on using the changeset viewer.