/** * mei_cl_bus_notify_event - schedule notify cb on bus client * * @cl: host client * * Return: true if event was scheduled * false if the client is not waiting for event
*/ bool mei_cl_bus_notify_event(struct mei_cl *cl)
{ struct mei_cl_device *cldev = cl->cldev;
if (!cldev || !cldev->notif_cb) returnfalse;
if (!cl->notify_ev) returnfalse;
schedule_work(&cldev->notif_work);
cl->notify_ev = false;
returntrue;
}
/** * mei_cl_bus_rx_event - schedule rx event * * @cl: host client * * Return: true if event was scheduled * false if the client is not waiting for event
*/ bool mei_cl_bus_rx_event(struct mei_cl *cl)
{ struct mei_cl_device *cldev = cl->cldev;
if (!cldev || !cldev->rx_cb) returnfalse;
schedule_work(&cldev->rx_work);
returntrue;
}
/** * mei_cldev_register_rx_cb - register Rx event callback * * @cldev: me client devices * @rx_cb: callback function * * Return: 0 on success * -EALREADY if an callback is already registered * <0 on other errors
*/ int mei_cldev_register_rx_cb(struct mei_cl_device *cldev, mei_cldev_cb_t rx_cb)
{ struct mei_device *bus = cldev->bus; int ret;
if (!rx_cb) return -EINVAL; if (cldev->rx_cb) return -EALREADY;
/** * mei_cldev_get_drvdata - driver data getter * * @cldev: mei client device * * Return: driver private data
*/ void *mei_cldev_get_drvdata(conststruct mei_cl_device *cldev)
{ return dev_get_drvdata(&cldev->dev);
}
EXPORT_SYMBOL_GPL(mei_cldev_get_drvdata);
/** * mei_cldev_set_drvdata - driver data setter * * @cldev: mei client device * @data: data to store
*/ void mei_cldev_set_drvdata(struct mei_cl_device *cldev, void *data)
{
dev_set_drvdata(&cldev->dev, data);
}
EXPORT_SYMBOL_GPL(mei_cldev_set_drvdata);
/** * mei_cldev_ver - return protocol version of the underlying me client * * @cldev: mei client device * * Return: me client protocol version
*/
u8 mei_cldev_ver(conststruct mei_cl_device *cldev)
{ return mei_me_cl_ver(cldev->me_cl);
}
EXPORT_SYMBOL_GPL(mei_cldev_ver);
/** * mei_cldev_enabled - check whether the device is enabled * * @cldev: mei client device * * Return: true if me client is initialized and connected
*/ bool mei_cldev_enabled(conststruct mei_cl_device *cldev)
{ return mei_cl_is_connected(cldev->cl);
}
EXPORT_SYMBOL_GPL(mei_cldev_enabled);
/** * mei_cl_bus_module_get - acquire module of the underlying * hw driver. * * @cldev: mei client device * * Return: true on success; false if the module was removed.
*/ staticbool mei_cl_bus_module_get(struct mei_cl_device *cldev)
{ return try_module_get(cldev->bus->dev->driver->owner);
}
/** * mei_cl_bus_vtag - get bus vtag entry wrapper * The tag for bus client is always first. * * @cl: host client * * Return: bus vtag or NULL
*/ staticinlinestruct mei_cl_vtag *mei_cl_bus_vtag(struct mei_cl *cl)
{ return list_first_entry_or_null(&cl->vtag_map, struct mei_cl_vtag, list);
}
/** * mei_cl_bus_vtag_alloc - add bus client entry to vtag map * * @cldev: me client device * * Return: * * 0 on success * * -ENOMEM if memory allocation failed
*/ staticint mei_cl_bus_vtag_alloc(struct mei_cl_device *cldev)
{ struct mei_cl *cl = cldev->cl; struct mei_cl_vtag *cl_vtag;
/* * Bail out if the client does not supports vtags * or has already allocated one
*/ if (mei_cl_vt_support_check(cl) || mei_cl_bus_vtag(cl)) return 0;
cl_vtag = mei_cl_vtag_alloc(NULL, 0); if (IS_ERR(cl_vtag)) return -ENOMEM;
list_add_tail(&cl_vtag->list, &cl->vtag_map);
return 0;
}
/** * mei_cl_bus_vtag_free - remove the bus entry from vtag map * * @cldev: me client device
*/ staticvoid mei_cl_bus_vtag_free(struct mei_cl_device *cldev)
{ struct mei_cl *cl = cldev->cl; struct mei_cl_vtag *cl_vtag;
cl_vtag = mei_cl_bus_vtag(cl); if (!cl_vtag) return;
if (cldev->notif_cb) {
cancel_work_sync(&cldev->notif_work);
cldev->notif_cb = NULL;
}
}
/** * mei_cldev_disable - disable me client device * disconnect form the me client * * @cldev: me client device * * Return: 0 on success and < 0 on error
*/ int mei_cldev_disable(struct mei_cl_device *cldev)
{ struct mei_device *bus; struct mei_cl *cl; int err;
err = mei_cl_disconnect(cl); if (err < 0)
dev_err(&cldev->dev, "Could not disconnect from the ME client\n");
out: /* Flush queues and remove any pending read unless we have mapped DMA */ if (!cl->dma_mapped) {
mei_cl_flush_queues(cl, NULL);
mei_cl_unlink(cl);
}
/** * mei_cldev_send_gsc_command - sends a gsc command, by sending * a gsl mei message to gsc and receiving reply from gsc * * @cldev: me client device * @client_id: client id to send the command to * @fence_id: fence id to send the command to * @sg_in: scatter gather list containing addresses for rx message buffer * @total_in_len: total length of data in 'in' sg, can be less than the sum of buffers sizes * @sg_out: scatter gather list containing addresses for tx message buffer * * Return: * * written size in bytes * * < 0 on error
*/
ssize_t mei_cldev_send_gsc_command(struct mei_cl_device *cldev,
u8 client_id, u32 fence_id, struct scatterlist *sg_in,
size_t total_in_len, struct scatterlist *sg_out)
{ struct mei_cl *cl; struct mei_device *bus;
ssize_t ret = 0;
if (!bus->hbm_f_gsc_supported) return -EOPNOTSUPP;
sg_out_nents = sg_nents(sg_out);
sg_in_nents = sg_nents(sg_in); /* at least one entry in tx and rx sgls must be present */ if (sg_out_nents <= 0 || sg_in_nents <= 0) return -EINVAL;
/* copy in-sgl to the message */ for (i = 0, sg = sg_in; i < sg_in_nents; i++, sg++) {
ext_hdr->sgl[i].low = lower_32_bits(sg_dma_address(sg));
ext_hdr->sgl[i].high = upper_32_bits(sg_dma_address(sg));
sg_len = min_t(unsignedint, sg_dma_len(sg), PAGE_SIZE);
ext_hdr->sgl[i].length = (sg_len <= total_in_len) ? sg_len : total_in_len;
total_in_len -= ext_hdr->sgl[i].length;
}
/* copy out-sgl to the message */ for (i = sg_in_nents, sg = sg_out; i < sg_in_nents + sg_out_nents; i++, sg++) {
ext_hdr->sgl[i].low = lower_32_bits(sg_dma_address(sg));
ext_hdr->sgl[i].high = upper_32_bits(sg_dma_address(sg));
sg_len = min_t(unsignedint, sg_dma_len(sg), PAGE_SIZE);
ext_hdr->sgl[i].length = sg_len;
}
/* send the message to GSC */
ret = __mei_cl_send(cl, (u8 *)ext_hdr, buf_sz, 0, MEI_CL_IO_SGL); if (ret < 0) {
dev_err(&cldev->dev, "__mei_cl_send failed, returned %zd\n", ret); goto end;
} if (ret != buf_sz) {
dev_err(&cldev->dev, "__mei_cl_send returned %zd instead of expected %zd\n",
ret, buf_sz);
ret = -EIO; goto end;
}
/* receive the reply from GSC, note that at this point sg_in should contain the reply */
ret = __mei_cl_recv(cl, (u8 *)&rx_msg, sizeof(rx_msg), NULL, MEI_CL_IO_SGL, 0);
if (ret != sizeof(rx_msg)) {
dev_err(&cldev->dev, "__mei_cl_recv returned %zd instead of expected %zd\n",
ret, sizeof(rx_msg)); if (ret >= 0)
ret = -EIO; goto end;
}
/* check rx_msg.client_id and rx_msg.fence_id match the ones we send */ if (rx_msg.client_id != client_id || rx_msg.fence_id != fence_id) {
dev_err(&cldev->dev, "received client_id/fence_id %u/%u instead of %u/%u sent\n",
rx_msg.client_id, rx_msg.fence_id, client_id, fence_id);
ret = -EFAULT; goto end;
}
dev_dbg(&cldev->dev, "gsc command: successfully written %u bytes\n", rx_msg.written);
ret = rx_msg.written;
/** * mei_cl_bus_dev_setup - setup me client device * run fix up routines and set the device name * * @bus: mei device * @cldev: me client device * * Return: true if the device is eligible for enumeration
*/ staticbool mei_cl_bus_dev_setup(struct mei_device *bus, struct mei_cl_device *cldev)
{
cldev->do_match = 1;
mei_cl_bus_dev_fixup(cldev);
/* the device name can change during fix up */ if (cldev->do_match)
mei_cl_bus_set_name(cldev);
return cldev->do_match == 1;
}
/** * mei_cl_bus_dev_add - add me client devices * * @cldev: me client device * * Return: 0 on success; < 0 on failure
*/ staticint mei_cl_bus_dev_add(struct mei_cl_device *cldev)
{ int ret;
dev_dbg(&cldev->dev, "adding %pUL:%02X\n",
mei_me_cl_uuid(cldev->me_cl),
mei_me_cl_ver(cldev->me_cl));
ret = device_add(&cldev->dev); if (!ret)
cldev->is_added = 1;
return ret;
}
/** * mei_cl_bus_dev_stop - stop the driver * * @cldev: me client device
*/ staticvoid mei_cl_bus_dev_stop(struct mei_cl_device *cldev)
{
cldev->do_match = 0; if (cldev->is_added)
device_release_driver(&cldev->dev);
}
/** * mei_cl_bus_dev_destroy - destroy me client devices object * * @cldev: me client device * * Locking: called under "dev->cl_bus_lock" lock
*/ staticvoid mei_cl_bus_dev_destroy(struct mei_cl_device *cldev)
{
/** * mei_cl_bus_remove_device - remove a devices form the bus * * @cldev: me client device
*/ staticvoid mei_cl_bus_remove_device(struct mei_cl_device *cldev)
{
mei_cl_bus_dev_stop(cldev);
mei_cl_bus_dev_destroy(cldev);
}
/** * mei_cl_bus_remove_devices - remove all devices form the bus * * @bus: mei device
*/ void mei_cl_bus_remove_devices(struct mei_device *bus)
{ struct mei_cl_device *cldev, *next;
/** * mei_cl_bus_dev_init - allocate and initializes an mei client devices * based on me client * * @bus: mei device * @me_cl: me client * * Locking: called under "dev->cl_bus_lock" lock
*/ staticvoid mei_cl_bus_dev_init(struct mei_device *bus, struct mei_me_client *me_cl)
{ struct mei_cl_device *cldev;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.