lkml.org 
[lkml]   [2021]   [Jan]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v3 22/34] xlink-core: Enable VPU IP management and runtime control
    Date
    From: Seamus Kelly <seamus.kelly@intel.com>

    Enable VPU management including, enumeration, boot and runtime control.

    Add APIs:
    write control data:
    used to transmit small, local data
    start vpu:
    calls boot_device API ( soon to be deprecated )
    stop vpu
    calls reset_device API ( soon to be deprecated )
    reset vpu
    calls reset_device API ( soon to be deprecated )
    get device name:
    Returns the device name for the input device id
    This could be a char device path, for example "/dev/ttyUSB0"
    for a serial device; or it could be a device string
    description, for example, for PCIE "00:00.0 Host bridge: Intel
    Corporation 440BX/ZX/DX - 82443BX/ZX/DX Host bridge (rev 01)"
    get device list:
    Returns the list of software device IDs for all connected
    physical devices
    get device status:
    returns the current state of the input device
    OFF - The device is off (D3cold/Slot power removed).
    BUSY - device is busy and not available (device is booting)
    READY - device is available for use
    ERROR - device HW failure is detected
    RECOVERY - device is in recovery mode, waiting for recovery operations
    boot device:
    When used on the remote host - starts the SOC device by calling
    corresponding function from VPU Driver.
    Takes firmware's 'binary_name' as input.
    For Linux, the firmware image is expected to be located in
    '/lib/firmware' folder or its subfolders.
    For Linux, 'binary_name' is not a path but an image name that
    will be searched in the default Linux search paths ('/lib/firmware').
    When used on the local host - triggers the booting of VPUIP device.
    reset device:
    When used on the remote host - resets the device by calling
    corresponding VPU Driver function.
    When used on the local host - resets the VPUIP device
    get device mode:
    query and returns the current device power mode
    set device mode:
    used for device throttling or entering various power modes


    Cc: Arnd Bergmann <arnd@arndb.de>
    Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Reviewed-by: Mark Gross <mgross@linux.intel.com>
    Signed-off-by: Seamus Kelly <seamus.kelly@intel.com>
    ---
    drivers/misc/xlink-core/xlink-core.c | 235 ++++++++++++++++++++
    drivers/misc/xlink-core/xlink-defs.h | 2 +
    drivers/misc/xlink-core/xlink-ioctl.c | 214 ++++++++++++++++++
    drivers/misc/xlink-core/xlink-ioctl.h | 9 +
    drivers/misc/xlink-core/xlink-multiplexer.c | 56 +++++
    drivers/misc/xlink-core/xlink-platform.c | 86 +++++++
    include/linux/xlink.h | 27 +++
    7 files changed, 629 insertions(+)

    diff --git a/drivers/misc/xlink-core/xlink-core.c b/drivers/misc/xlink-core/xlink-core.c
    index bdbf8c6a99ca..d0a3f98d16af 100644
    --- a/drivers/misc/xlink-core/xlink-core.c
    +++ b/drivers/misc/xlink-core/xlink-core.c
    @@ -73,6 +73,8 @@ struct keembay_xlink_dev {
    struct mutex lock; // protect access to xlink_dev
    };

    +static u8 volbuf[XLINK_MAX_BUF_SIZE]; // buffer for volatile transactions
    +
    /*
    * global variable pointing to our xlink device.
    *
    @@ -264,6 +266,9 @@ static long xlink_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    case XL_READ_DATA:
    rc = ioctl_read_data(arg);
    break;
    + case XL_READ_TO_BUFFER:
    + rc = ioctl_read_to_buffer(arg);
    + break;
    case XL_WRITE_DATA:
    rc = ioctl_write_data(arg);
    break;
    @@ -276,9 +281,39 @@ static long xlink_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    case XL_CLOSE_CHANNEL:
    rc = ioctl_close_channel(arg);
    break;
    + case XL_START_VPU:
    + rc = ioctl_start_vpu(arg);
    + break;
    + case XL_STOP_VPU:
    + rc = xlink_stop_vpu();
    + break;
    + case XL_RESET_VPU:
    + rc = xlink_stop_vpu();
    + break;
    case XL_DISCONNECT:
    rc = ioctl_disconnect(arg);
    break;
    + case XL_GET_DEVICE_NAME:
    + rc = ioctl_get_device_name(arg);
    + break;
    + case XL_GET_DEVICE_LIST:
    + rc = ioctl_get_device_list(arg);
    + break;
    + case XL_GET_DEVICE_STATUS:
    + rc = ioctl_get_device_status(arg);
    + break;
    + case XL_BOOT_DEVICE:
    + rc = ioctl_boot_device(arg);
    + break;
    + case XL_RESET_DEVICE:
    + rc = ioctl_reset_device(arg);
    + break;
    + case XL_GET_DEVICE_MODE:
    + rc = ioctl_get_device_mode(arg);
    + break;
    + case XL_SET_DEVICE_MODE:
    + rc = ioctl_set_device_mode(arg);
    + break;
    }
    if (rc)
    return -EIO;
    @@ -289,6 +324,30 @@ static long xlink_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    /*
    * xlink Kernel API.
    */
    +enum xlink_error xlink_stop_vpu(void)
    +{
    +#ifdef CONFIG_XLINK_LOCAL_HOST
    + int rc;
    +
    + rc = xlink_ipc_reset_device(0x0); // stop vpu slice 0
    + if (rc)
    + return X_LINK_ERROR;
    +#endif
    + return X_LINK_SUCCESS;
    +}
    +EXPORT_SYMBOL_GPL(xlink_stop_vpu);
    +enum xlink_error xlink_start_vpu(char *filename)
    +{
    +#ifdef CONFIG_XLINK_LOCAL_HOST
    + int rc;
    +
    + rc = xlink_ipc_boot_device(0x0, filename); // start vpu slice 0
    + if (rc)
    + return X_LINK_ERROR;
    +#endif
    + return X_LINK_SUCCESS;
    +}
    +EXPORT_SYMBOL_GPL(xlink_start_vpu);

    enum xlink_error xlink_initialize(void)
    {
    @@ -527,6 +586,34 @@ enum xlink_error xlink_write_data_user(struct xlink_handle *handle,
    return rc;
    }

    +enum xlink_error xlink_write_control_data(struct xlink_handle *handle,
    + u16 chan, u8 const *pmessage,
    + u32 size)
    +{
    + struct xlink_event *event;
    + struct xlink_link *link;
    + int event_queued = 0;
    + enum xlink_error rc;
    +
    + if (!xlink || !handle)
    + return X_LINK_ERROR;
    + if (size > XLINK_MAX_CONTROL_DATA_SIZE)
    + return X_LINK_ERROR; // TODO: XLink Parameter Error
    + link = get_link_by_sw_device_id(handle->sw_device_id);
    + if (!link)
    + return X_LINK_ERROR;
    + event = xlink_create_event(link->id, XLINK_WRITE_CONTROL_REQ,
    + &link->handle, chan, size, 0);
    + if (!event)
    + return X_LINK_ERROR;
    + memcpy(event->header.control_data, pmessage, size);
    + rc = xlink_multiplexer_tx(event, &event_queued);
    + if (!event_queued)
    + xlink_destroy_event(event);
    + return rc;
    +}
    +EXPORT_SYMBOL_GPL(xlink_write_control_data);
    +
    enum xlink_error xlink_write_volatile(struct xlink_handle *handle,
    u16 chan, u8 const *message, u32 size)
    {
    @@ -711,6 +798,154 @@ enum xlink_error xlink_disconnect(struct xlink_handle *handle)
    }
    EXPORT_SYMBOL_GPL(xlink_disconnect);

    +enum xlink_error xlink_get_device_list(u32 *sw_device_id_list,
    + u32 *num_devices)
    +{
    + u32 interface_nmb_devices = 0;
    + enum xlink_error rc;
    + int i;
    +
    + if (!xlink)
    + return X_LINK_ERROR;
    + if (!sw_device_id_list || !num_devices)
    + return X_LINK_ERROR;
    + /* loop through each interface and combine the lists */
    + for (i = 0; i < NMB_OF_INTERFACES; i++) {
    + rc = xlink_platform_get_device_list(i, sw_device_id_list,
    + &interface_nmb_devices);
    + if (!rc) {
    + *num_devices += interface_nmb_devices;
    + sw_device_id_list += interface_nmb_devices;
    + }
    + interface_nmb_devices = 0;
    + }
    + return X_LINK_SUCCESS;
    +}
    +EXPORT_SYMBOL_GPL(xlink_get_device_list);
    +enum xlink_error xlink_get_device_name(struct xlink_handle *handle, char *name,
    + size_t name_size)
    +{
    + enum xlink_error rc;
    + int interface;
    +
    + if (!xlink || !handle)
    + return X_LINK_ERROR;
    + if (!name || !name_size)
    + return X_LINK_ERROR;
    + interface = get_interface_from_sw_device_id(handle->sw_device_id);
    + if (interface == NULL_INTERFACE)
    + return X_LINK_ERROR;
    + rc = xlink_platform_get_device_name(interface, handle->sw_device_id,
    + name, name_size);
    + if (rc)
    + rc = X_LINK_ERROR;
    + else
    + rc = X_LINK_SUCCESS;
    + return rc;
    +}
    +EXPORT_SYMBOL_GPL(xlink_get_device_name);
    +enum xlink_error xlink_get_device_status(struct xlink_handle *handle,
    + u32 *device_status)
    +{
    + enum xlink_error rc;
    + u32 interface;
    +
    + if (!xlink)
    + return X_LINK_ERROR;
    + if (!device_status)
    + return X_LINK_ERROR;
    + interface = get_interface_from_sw_device_id(handle->sw_device_id);
    + if (interface == NULL_INTERFACE)
    + return X_LINK_ERROR;
    + rc = xlink_platform_get_device_status(interface, handle->sw_device_id,
    + device_status);
    + if (rc)
    + rc = X_LINK_ERROR;
    + else
    + rc = X_LINK_SUCCESS;
    + return rc;
    +}
    +EXPORT_SYMBOL_GPL(xlink_get_device_status);
    +enum xlink_error xlink_boot_device(struct xlink_handle *handle,
    + const char *binary_name)
    +{
    + enum xlink_error rc;
    + u32 interface;
    +
    + if (!xlink || !handle)
    + return X_LINK_ERROR;
    + if (!binary_name)
    + return X_LINK_ERROR;
    + interface = get_interface_from_sw_device_id(handle->sw_device_id);
    + if (interface == NULL_INTERFACE)
    + return X_LINK_ERROR;
    + rc = xlink_platform_boot_device(interface, handle->sw_device_id,
    + binary_name);
    + if (rc)
    + rc = X_LINK_ERROR;
    + else
    + rc = X_LINK_SUCCESS;
    + return rc;
    +}
    +EXPORT_SYMBOL_GPL(xlink_boot_device);
    +enum xlink_error xlink_reset_device(struct xlink_handle *handle)
    +{
    + enum xlink_error rc;
    + u32 interface;
    +
    + if (!xlink || !handle)
    + return X_LINK_ERROR;
    + interface = get_interface_from_sw_device_id(handle->sw_device_id);
    + if (interface == NULL_INTERFACE)
    + return X_LINK_ERROR;
    + rc = xlink_platform_reset_device(interface, handle->sw_device_id);
    + if (rc)
    + rc = X_LINK_ERROR;
    + else
    + rc = X_LINK_SUCCESS;
    + return rc;
    +}
    +EXPORT_SYMBOL_GPL(xlink_reset_device);
    +enum xlink_error xlink_set_device_mode(struct xlink_handle *handle,
    + enum xlink_device_power_mode power_mode)
    +{
    + enum xlink_error rc;
    + u32 interface;
    +
    + if (!xlink || !handle)
    + return X_LINK_ERROR;
    + interface = get_interface_from_sw_device_id(handle->sw_device_id);
    + if (interface == NULL_INTERFACE)
    + return X_LINK_ERROR;
    + rc = xlink_platform_set_device_mode(interface, handle->sw_device_id,
    + power_mode);
    + if (rc)
    + rc = X_LINK_ERROR;
    + else
    + rc = X_LINK_SUCCESS;
    + return rc;
    +}
    +EXPORT_SYMBOL_GPL(xlink_set_device_mode);
    +enum xlink_error xlink_get_device_mode(struct xlink_handle *handle,
    + enum xlink_device_power_mode *power_mode)
    +{
    + enum xlink_error rc;
    + u32 interface;
    +
    + if (!xlink || !handle)
    + return X_LINK_ERROR;
    + interface = get_interface_from_sw_device_id(handle->sw_device_id);
    + if (interface == NULL_INTERFACE)
    + return X_LINK_ERROR;
    + rc = xlink_platform_get_device_mode(interface, handle->sw_device_id,
    + power_mode);
    + if (rc)
    + rc = X_LINK_ERROR;
    + else
    + rc = X_LINK_SUCCESS;
    + return rc;
    +}
    +EXPORT_SYMBOL_GPL(xlink_get_device_mode);
    /* Device tree driver match. */
    static const struct of_device_id kmb_xlink_of_match[] = {
    {
    diff --git a/drivers/misc/xlink-core/xlink-defs.h b/drivers/misc/xlink-core/xlink-defs.h
    index 09aee36d5542..8985f6631175 100644
    --- a/drivers/misc/xlink-core/xlink-defs.h
    +++ b/drivers/misc/xlink-core/xlink-defs.h
    @@ -101,6 +101,7 @@ enum xlink_event_type {
    XLINK_OPEN_CHANNEL_REQ,
    XLINK_CLOSE_CHANNEL_REQ,
    XLINK_PING_REQ,
    + XLINK_WRITE_CONTROL_REQ,
    XLINK_REQ_LAST,
    // response events
    XLINK_WRITE_RESP = 0x10,
    @@ -111,6 +112,7 @@ enum xlink_event_type {
    XLINK_OPEN_CHANNEL_RESP,
    XLINK_CLOSE_CHANNEL_RESP,
    XLINK_PING_RESP,
    + XLINK_WRITE_CONTROL_RESP,
    XLINK_RESP_LAST,
    };

    diff --git a/drivers/misc/xlink-core/xlink-ioctl.c b/drivers/misc/xlink-core/xlink-ioctl.c
    index 1f75ad38137b..90947bbccfed 100644
    --- a/drivers/misc/xlink-core/xlink-ioctl.c
    +++ b/drivers/misc/xlink-core/xlink-ioctl.c
    @@ -111,6 +111,34 @@ int ioctl_read_data(unsigned long arg)
    return copy_result_to_user(rd.return_code, rc);
    }

    +int ioctl_read_to_buffer(unsigned long arg)
    +{
    + struct xlink_handle devh = {};
    + struct xlinkreadtobuffer rdtobuf = {};
    + int rc = 0;
    + u32 size;
    + u8 volbuf[XLINK_MAX_BUF_SIZE]; // buffer for volatile transactions
    +
    + if (copy_from_user(&rdtobuf, (void __user *)arg,
    + sizeof(struct xlinkreadtobuffer)))
    + return -EFAULT;
    + if (copy_from_user(&devh, (void __user *)rdtobuf.handle,
    + sizeof(struct xlink_handle)))
    + return -EFAULT;
    + rc = xlink_read_data_to_buffer(&devh, rdtobuf.chan,
    + (u8 *)volbuf, &size);
    + if (!rc) {
    + if (copy_to_user((void __user *)rdtobuf.pmessage, (void *)volbuf,
    + size))
    + return -EFAULT;
    + if (copy_to_user((void __user *)rdtobuf.size, (void *)&size,
    + sizeof(size)))
    + return -EFAULT;
    + }
    +
    + return copy_result_to_user(rdtobuf.return_code, rc);
    +}
    +
    int ioctl_write_data(unsigned long arg)
    {
    struct xlink_handle devh = {};
    @@ -194,6 +222,26 @@ int ioctl_close_channel(unsigned long arg)
    return copy_result_to_user(op.return_code, rc);
    }

    +int ioctl_start_vpu(unsigned long arg)
    +{
    + struct xlinkstartvpu startvpu = {};
    + char filename[64];
    + int rc = 0;
    +
    + if (copy_from_user(&startvpu, (void __user *)arg,
    + sizeof(struct xlinkstartvpu)))
    + return -EFAULT;
    + if (startvpu.namesize > sizeof(filename))
    + return -EINVAL;
    + memset(filename, 0, sizeof(filename));
    + if (copy_from_user(filename, (void __user *)startvpu.filename,
    + startvpu.namesize))
    + return -EFAULT;
    + rc = xlink_start_vpu(filename);
    +
    + return copy_result_to_user(startvpu.return_code, rc);
    +}
    +
    int ioctl_disconnect(unsigned long arg)
    {
    struct xlink_handle devh = {};
    @@ -210,3 +258,169 @@ int ioctl_disconnect(unsigned long arg)

    return copy_result_to_user(con.return_code, rc);
    }
    +
    +int ioctl_get_device_name(unsigned long arg)
    +{
    + struct xlink_handle devh = {};
    + struct xlinkgetdevicename devn = {};
    + char name[XLINK_MAX_DEVICE_NAME_SIZE];
    + int rc = 0;
    +
    + if (copy_from_user(&devn, (void __user *)arg,
    + sizeof(struct xlinkgetdevicename)))
    + return -EFAULT;
    + if (copy_from_user(&devh, (void __user *)devn.handle,
    + sizeof(struct xlink_handle)))
    + return -EFAULT;
    + if (devn.name_size <= XLINK_MAX_DEVICE_NAME_SIZE) {
    + rc = xlink_get_device_name(&devh, name, devn.name_size);
    + if (!rc) {
    + if (copy_to_user((void __user *)devn.name, (void *)name,
    + devn.name_size))
    + return -EFAULT;
    + }
    + } else {
    + rc = X_LINK_ERROR;
    + }
    +
    + return copy_result_to_user(devn.return_code, rc);
    +}
    +
    +int ioctl_get_device_list(unsigned long arg)
    +{
    + struct xlinkgetdevicelist devl = {};
    + u32 sw_device_id_list[XLINK_MAX_DEVICE_LIST_SIZE];
    + u32 num_devices = 0;
    + int rc = 0;
    +
    + if (copy_from_user(&devl, (void __user *)arg,
    + sizeof(struct xlinkgetdevicelist)))
    + return -EFAULT;
    + rc = xlink_get_device_list(sw_device_id_list, &num_devices);
    + if (!rc && num_devices <= XLINK_MAX_DEVICE_LIST_SIZE) {
    + /* TODO: this next copy is dangerous! we have no idea
    + * how large the devl.sw_device_id_list buffer is
    + * provided by the user. if num_devices is too large,
    + * the copy will overflow the buffer.
    + */
    + if (copy_to_user((void __user *)devl.sw_device_id_list,
    + (void *)sw_device_id_list,
    + (sizeof(*sw_device_id_list)
    + * num_devices)))
    + return -EFAULT;
    + if (copy_to_user((void __user *)devl.num_devices, (void *)&num_devices,
    + (sizeof(num_devices))))
    + return -EFAULT;
    + }
    +
    + return copy_result_to_user(devl.return_code, rc);
    +}
    +
    +int ioctl_get_device_status(unsigned long arg)
    +{
    + struct xlink_handle devh = {};
    + struct xlinkgetdevicestatus devs = {};
    + u32 device_status = 0;
    + int rc = 0;
    +
    + if (copy_from_user(&devs, (void __user *)arg,
    + sizeof(struct xlinkgetdevicestatus)))
    + return -EFAULT;
    + if (copy_from_user(&devh, (void __user *)devs.handle,
    + sizeof(struct xlink_handle)))
    + return -EFAULT;
    + rc = xlink_get_device_status(&devh, &device_status);
    + if (!rc) {
    + if (copy_to_user((void __user *)devs.device_status,
    + (void *)&device_status,
    + sizeof(device_status)))
    + return -EFAULT;
    + }
    +
    + return copy_result_to_user(devs.return_code, rc);
    +}
    +
    +int ioctl_boot_device(unsigned long arg)
    +{
    + struct xlink_handle devh = {};
    + struct xlinkbootdevice boot = {};
    + char filename[64];
    + int rc = 0;
    +
    + if (copy_from_user(&boot, (void __user *)arg,
    + sizeof(struct xlinkbootdevice)))
    + return -EFAULT;
    + if (copy_from_user(&devh, (void __user *)boot.handle,
    + sizeof(struct xlink_handle)))
    + return -EFAULT;
    + if (boot.binary_name_size > sizeof(filename))
    + return -EINVAL;
    + memset(filename, 0, sizeof(filename));
    + if (copy_from_user(filename, (void __user *)boot.binary_name,
    + boot.binary_name_size))
    + return -EFAULT;
    + rc = xlink_boot_device(&devh, filename);
    +
    + return copy_result_to_user(boot.return_code, rc);
    +}
    +
    +int ioctl_reset_device(unsigned long arg)
    +{
    + struct xlink_handle devh = {};
    + struct xlinkresetdevice res = {};
    + int rc = 0;
    +
    + if (copy_from_user(&res, (void __user *)arg,
    + sizeof(struct xlinkresetdevice)))
    + return -EFAULT;
    + if (copy_from_user(&devh, (void __user *)res.handle,
    + sizeof(struct xlink_handle)))
    + return -EFAULT;
    + rc = xlink_reset_device(&devh);
    +
    + return copy_result_to_user(res.return_code, rc);
    +}
    +
    +int ioctl_get_device_mode(unsigned long arg)
    +{
    + struct xlink_handle devh = {};
    + struct xlinkdevmode devm = {};
    + u32 device_mode = 0;
    + int rc = 0;
    +
    + if (copy_from_user(&devm, (void __user *)arg,
    + sizeof(struct xlinkdevmode)))
    + return -EFAULT;
    + if (copy_from_user(&devh, (void __user *)devm.handle,
    + sizeof(struct xlink_handle)))
    + return -EFAULT;
    + rc = xlink_get_device_mode(&devh, &device_mode);
    + if (!rc) {
    + if (copy_to_user((void __user *)devm.device_mode, (void *)&device_mode,
    + sizeof(device_mode)))
    + return -EFAULT;
    + }
    +
    + return copy_result_to_user(devm.return_code, rc);
    +}
    +
    +int ioctl_set_device_mode(unsigned long arg)
    +{
    + struct xlink_handle devh = {};
    + struct xlinkdevmode devm = {};
    + u32 device_mode = 0;
    + int rc = 0;
    +
    + if (copy_from_user(&devm, (void __user *)arg,
    + sizeof(struct xlinkdevmode)))
    + return -EFAULT;
    + if (copy_from_user(&devh, (void __user *)devm.handle,
    + sizeof(struct xlink_handle)))
    + return -EFAULT;
    + if (copy_from_user(&device_mode, (void __user *)devm.device_mode,
    + sizeof(device_mode)))
    + return -EFAULT;
    + rc = xlink_set_device_mode(&devh, device_mode);
    +
    + return copy_result_to_user(devm.return_code, rc);
    +}
    diff --git a/drivers/misc/xlink-core/xlink-ioctl.h b/drivers/misc/xlink-core/xlink-ioctl.h
    index 0f317c6c2b94..d016d8418f30 100644
    --- a/drivers/misc/xlink-core/xlink-ioctl.h
    +++ b/drivers/misc/xlink-core/xlink-ioctl.h
    @@ -12,10 +12,19 @@
    int ioctl_connect(unsigned long arg);
    int ioctl_open_channel(unsigned long arg);
    int ioctl_read_data(unsigned long arg);
    +int ioctl_read_to_buffer(unsigned long arg);
    int ioctl_write_data(unsigned long arg);
    int ioctl_write_volatile_data(unsigned long arg);
    int ioctl_release_data(unsigned long arg);
    int ioctl_close_channel(unsigned long arg);
    +int ioctl_start_vpu(unsigned long arg);
    int ioctl_disconnect(unsigned long arg);
    +int ioctl_get_device_name(unsigned long arg);
    +int ioctl_get_device_list(unsigned long arg);
    +int ioctl_get_device_status(unsigned long arg);
    +int ioctl_boot_device(unsigned long arg);
    +int ioctl_reset_device(unsigned long arg);
    +int ioctl_get_device_mode(unsigned long arg);
    +int ioctl_set_device_mode(unsigned long arg);

    #endif /* XLINK_IOCTL_H_ */
    diff --git a/drivers/misc/xlink-core/xlink-multiplexer.c b/drivers/misc/xlink-core/xlink-multiplexer.c
    index 339734826f3e..48451dc30712 100644
    --- a/drivers/misc/xlink-core/xlink-multiplexer.c
    +++ b/drivers/misc/xlink-core/xlink-multiplexer.c
    @@ -491,6 +491,7 @@ enum xlink_error xlink_multiplexer_tx(struct xlink_event *event,
    switch (event->header.type) {
    case XLINK_WRITE_REQ:
    case XLINK_WRITE_VOLATILE_REQ:
    + case XLINK_WRITE_CONTROL_REQ:
    opchan = get_channel(link_id, chan);
    if (!opchan || opchan->chan->status != CHAN_OPEN) {
    rc = X_LINK_COMMUNICATION_FAIL;
    @@ -657,6 +658,7 @@ enum xlink_error xlink_multiplexer_tx(struct xlink_event *event,
    break;
    case XLINK_WRITE_RESP:
    case XLINK_WRITE_VOLATILE_RESP:
    + case XLINK_WRITE_CONTROL_RESP:
    case XLINK_READ_RESP:
    case XLINK_READ_TO_BUFFER_RESP:
    case XLINK_RELEASE_RESP:
    @@ -759,6 +761,46 @@ enum xlink_error xlink_multiplexer_rx(struct xlink_event *event)
    }
    release_channel(opchan);
    break;
    + case XLINK_WRITE_CONTROL_REQ:
    + opchan = get_channel(link_id, chan);
    + if (!opchan) {
    + rc = X_LINK_COMMUNICATION_FAIL;
    + } else {
    + event->header.timeout = opchan->chan->timeout;
    + buffer = xlink_platform_allocate(xmux->dev, &paddr,
    + event->header.size,
    + XLINK_PACKET_ALIGNMENT,
    + XLINK_NORMAL_MEMORY);
    + if (buffer) {
    + size = event->header.size;
    + memcpy(buffer, event->header.control_data, size);
    + event->paddr = paddr;
    + event->data = buffer;
    + if (add_packet_to_channel(opchan,
    + &opchan->rx_queue,
    + event->data,
    + event->header.size,
    + paddr)) {
    + xlink_platform_deallocate(xmux->dev,
    + buffer, paddr,
    + event->header.size,
    + XLINK_PACKET_ALIGNMENT,
    + XLINK_NORMAL_MEMORY);
    + rc = X_LINK_ERROR;
    + release_channel(opchan);
    + break;
    + }
    + event->header.type = XLINK_WRITE_CONTROL_RESP;
    + xlink_dispatcher_event_add(EVENT_RX, event);
    + // channel blocking, notify waiting threads of available packet
    + complete(&opchan->pkt_available);
    + } else {
    + // failed to allocate buffer
    + rc = X_LINK_ERROR;
    + }
    + }
    + release_channel(opchan);
    + break;
    case XLINK_READ_REQ:
    case XLINK_READ_TO_BUFFER_REQ:
    opchan = get_channel(link_id, chan);
    @@ -848,6 +890,7 @@ enum xlink_error xlink_multiplexer_rx(struct xlink_event *event)
    break;
    case XLINK_WRITE_RESP:
    case XLINK_WRITE_VOLATILE_RESP:
    + case XLINK_WRITE_CONTROL_RESP:
    opchan = get_channel(link_id, chan);
    if (!opchan)
    rc = X_LINK_COMMUNICATION_FAIL;
    @@ -929,6 +972,18 @@ enum xlink_error xlink_passthrough(struct xlink_event *event)
    rc = X_LINK_ERROR;
    }
    break;
    + case XLINK_WRITE_CONTROL_REQ:
    + if (xmux->channels[link_id][chan].ipc_status == CHAN_OPEN) {
    + ipc.is_volatile = 1;
    + rc = xlink_platform_write(IPC_INTERFACE,
    + event->handle->sw_device_id,
    + event->header.control_data,
    + &event->header.size, 0, &ipc);
    + } else {
    + /* channel not open */
    + rc = X_LINK_ERROR;
    + }
    + break;
    case XLINK_READ_REQ:
    if (xmux->channels[link_id][chan].ipc_status == CHAN_OPEN) {
    /* if channel has receive blocking set,
    @@ -1013,6 +1068,7 @@ enum xlink_error xlink_passthrough(struct xlink_event *event)
    case XLINK_PING_REQ:
    case XLINK_WRITE_RESP:
    case XLINK_WRITE_VOLATILE_RESP:
    + case XLINK_WRITE_CONTROL_RESP:
    case XLINK_READ_RESP:
    case XLINK_READ_TO_BUFFER_RESP:
    case XLINK_RELEASE_RESP:
    diff --git a/drivers/misc/xlink-core/xlink-platform.c b/drivers/misc/xlink-core/xlink-platform.c
    index c34b69ee206b..56eb8da28a5f 100644
    --- a/drivers/misc/xlink-core/xlink-platform.c
    +++ b/drivers/misc/xlink-core/xlink-platform.c
    @@ -34,6 +34,20 @@ static inline int xlink_ipc_read(u32 sw_device_id, void *data,
    size_t * const size, u32 timeout, void *context)
    { return -1; }

    +static inline int xlink_ipc_get_device_list(u32 *sw_device_id_list,
    + u32 *num_devices)
    +{ return -1; }
    +static inline int xlink_ipc_get_device_name(u32 sw_device_id,
    + char *device_name, size_t name_size)
    +{ return -1; }
    +static inline int xlink_ipc_get_device_status(u32 sw_device_id,
    + u32 *device_status)
    +{ return -1; }
    +static inline int xlink_ipc_boot_device(u32 sw_device_id,
    + const char *binary_path)
    +{ return -1; }
    +static inline int xlink_ipc_reset_device(u32 sw_device_id)
    +{ return -1; }
    static inline int xlink_ipc_open_channel(u32 sw_device_id,
    u32 channel)
    { return -1; }
    @@ -59,6 +73,23 @@ static int (*write_fcts[NMB_OF_INTERFACES])(u32, void *, size_t * const, u32) =
    static int (*read_fcts[NMB_OF_INTERFACES])(u32, void *, size_t * const, u32) = {
    NULL, xlink_pcie_read, NULL, NULL};

    +static int (*reset_fcts[NMB_OF_INTERFACES])(u32) = {
    + xlink_ipc_reset_device, xlink_pcie_reset_device, NULL, NULL};
    +static int (*boot_fcts[NMB_OF_INTERFACES])(u32, const char *) = {
    + xlink_ipc_boot_device, xlink_pcie_boot_device, NULL, NULL};
    +static int (*dev_name_fcts[NMB_OF_INTERFACES])(u32, char *, size_t) = {
    + xlink_ipc_get_device_name, xlink_pcie_get_device_name,
    + NULL, NULL};
    +static int (*dev_list_fcts[NMB_OF_INTERFACES])(u32 *, u32 *) = {
    + xlink_ipc_get_device_list, xlink_pcie_get_device_list,
    + NULL, NULL};
    +static int (*dev_status_fcts[NMB_OF_INTERFACES])(u32, u32 *) = {
    + xlink_ipc_get_device_status, xlink_pcie_get_device_status,
    + NULL, NULL};
    +static int (*dev_set_mode_fcts[NMB_OF_INTERFACES])(u32, u32) = {
    + NULL, NULL, NULL, NULL};
    +static int (*dev_get_mode_fcts[NMB_OF_INTERFACES])(u32, u32 *) = {
    + NULL, NULL, NULL, NULL};
    static int (*open_chan_fcts[NMB_OF_INTERFACES])(u32, u32) = {
    xlink_ipc_open_channel, NULL, NULL, NULL};

    @@ -103,6 +134,61 @@ int xlink_platform_read(u32 interface, u32 sw_device_id, void *data,
    return read_fcts[interface](sw_device_id, data, size, timeout);
    }

    +int xlink_platform_reset_device(u32 interface, u32 sw_device_id)
    +{
    + if (interface >= NMB_OF_INTERFACES || !reset_fcts[interface])
    + return -1;
    + return reset_fcts[interface](sw_device_id);
    +}
    +
    +int xlink_platform_boot_device(u32 interface, u32 sw_device_id,
    + const char *binary_name)
    +{
    + if (interface >= NMB_OF_INTERFACES || !boot_fcts[interface])
    + return -1;
    + return boot_fcts[interface](sw_device_id, binary_name);
    +}
    +
    +int xlink_platform_get_device_name(u32 interface, u32 sw_device_id,
    + char *device_name, size_t name_size)
    +{
    + if (interface >= NMB_OF_INTERFACES || !dev_name_fcts[interface])
    + return -1;
    + return dev_name_fcts[interface](sw_device_id, device_name, name_size);
    +}
    +
    +int xlink_platform_get_device_list(u32 interface,
    + u32 *sw_device_id_list, u32 *num_devices)
    +{
    + if (interface >= NMB_OF_INTERFACES || !dev_list_fcts[interface])
    + return -1;
    + return dev_list_fcts[interface](sw_device_id_list, num_devices);
    +}
    +
    +int xlink_platform_get_device_status(u32 interface, u32 sw_device_id,
    + u32 *device_status)
    +{
    + if (interface >= NMB_OF_INTERFACES || !dev_status_fcts[interface])
    + return -1;
    + return dev_status_fcts[interface](sw_device_id, device_status);
    +}
    +
    +int xlink_platform_set_device_mode(u32 interface, u32 sw_device_id,
    + u32 power_mode)
    +{
    + if (interface >= NMB_OF_INTERFACES || !dev_set_mode_fcts[interface])
    + return -1;
    + return dev_set_mode_fcts[interface](sw_device_id, power_mode);
    +}
    +
    +int xlink_platform_get_device_mode(u32 interface, u32 sw_device_id,
    + u32 *power_mode)
    +{
    + if (interface >= NMB_OF_INTERFACES || !dev_get_mode_fcts[interface])
    + return -1;
    + return dev_get_mode_fcts[interface](sw_device_id, power_mode);
    +}
    +
    int xlink_platform_open_channel(u32 interface, u32 sw_device_id,
    u32 channel)
    {
    diff --git a/include/linux/xlink.h b/include/linux/xlink.h
    index c22439d5aade..b00dbc719530 100644
    --- a/include/linux/xlink.h
    +++ b/include/linux/xlink.h
    @@ -78,6 +78,10 @@ enum xlink_error xlink_write_data(struct xlink_handle *handle,
    enum xlink_error xlink_write_volatile(struct xlink_handle *handle,
    u16 chan, u8 const *message, u32 size);

    +enum xlink_error xlink_write_control_data(struct xlink_handle *handle,
    + u16 chan, u8 const *message,
    + u32 size);
    +
    enum xlink_error xlink_read_data(struct xlink_handle *handle,
    u16 chan, u8 **message, u32 *size);

    @@ -90,6 +94,29 @@ enum xlink_error xlink_release_data(struct xlink_handle *handle,

    enum xlink_error xlink_disconnect(struct xlink_handle *handle);

    +enum xlink_error xlink_get_device_list(u32 *sw_device_id_list, u32 *num_devices);
    +
    +enum xlink_error xlink_get_device_name(struct xlink_handle *handle, char *name,
    + size_t name_size);
    +
    +enum xlink_error xlink_get_device_status(struct xlink_handle *handle,
    + u32 *device_status);
    +
    +enum xlink_error xlink_boot_device(struct xlink_handle *handle,
    + const char *binary_name);
    +
    +enum xlink_error xlink_reset_device(struct xlink_handle *handle);
    +
    +enum xlink_error xlink_set_device_mode(struct xlink_handle *handle,
    + enum xlink_device_power_mode power_mode);
    +
    +enum xlink_error xlink_get_device_mode(struct xlink_handle *handle,
    + enum xlink_device_power_mode *power_mode);
    +
    +enum xlink_error xlink_start_vpu(char *filename); /* depreciated */
    +
    +enum xlink_error xlink_stop_vpu(void); /* depreciated */
    +
    /* API functions to be implemented
    *
    * enum xlink_error xlink_write_crc_data(struct xlink_handle *handle,
    --
    2.17.1
    \
     
     \ /
      Last update: 2021-01-30 07:01    [W:4.426 / U:0.120 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site