Commit 2266e58a authored by Vitaly Lubart's avatar Vitaly Lubart Committed by Daniele Ceraolo Spurio

mei: bus: extend bus API to support command streamer API

Add mei bus API for sending gsc commands: mei_cldev_send_gsc_command()

The GSC commands are originated in the graphics stack
and are in form of SGL DMA buffers.
The GSC commands are synchronous, the response is received
in the same call on the out sg list buffers.
The function setups pointers for in and out sg lists in the
mei sgl extended header and sends it to the firmware.
Signed-off-by: default avatarVitaly Lubart <vitaly.lubart@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-5-daniele.ceraolospurio@intel.com
parent 2af56dde
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/scatterlist.h>
#include <linux/mei_cl_bus.h> #include <linux/mei_cl_bus.h>
#include "mei_dev.h" #include "mei_dev.h"
...@@ -838,6 +839,131 @@ int mei_cldev_disable(struct mei_cl_device *cldev) ...@@ -838,6 +839,131 @@ int mei_cldev_disable(struct mei_cl_device *cldev)
} }
EXPORT_SYMBOL_GPL(mei_cldev_disable); EXPORT_SYMBOL_GPL(mei_cldev_disable);
/**
* 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;
struct mei_ext_hdr_gsc_h2f *ext_hdr;
size_t buf_sz = sizeof(struct mei_ext_hdr_gsc_h2f);
int sg_out_nents, sg_in_nents;
int i;
struct scatterlist *sg;
struct mei_ext_hdr_gsc_f2h rx_msg;
unsigned int sg_len;
if (!cldev || !sg_in || !sg_out)
return -EINVAL;
cl = cldev->cl;
bus = cldev->bus;
dev_dbg(bus->dev, "client_id %u, fence_id %u\n", client_id, fence_id);
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;
buf_sz += (sg_out_nents + sg_in_nents) * sizeof(struct mei_gsc_sgl);
ext_hdr = kzalloc(buf_sz, GFP_KERNEL);
if (!ext_hdr)
return -ENOMEM;
/* construct the GSC message */
ext_hdr->hdr.type = MEI_EXT_HDR_GSC;
ext_hdr->hdr.length = buf_sz / sizeof(u32); /* length is in dw */
ext_hdr->client_id = client_id;
ext_hdr->addr_type = GSC_ADDRESS_TYPE_PHYSICAL_SGL;
ext_hdr->fence_id = fence_id;
ext_hdr->input_address_count = sg_in_nents;
ext_hdr->output_address_count = sg_out_nents;
ext_hdr->reserved[0] = 0;
ext_hdr->reserved[1] = 0;
/* 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(unsigned int, 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(unsigned int, 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(bus->dev, "__mei_cl_send failed, returned %zd\n", ret);
goto end;
}
if (ret != buf_sz) {
dev_err(bus->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(bus->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(bus->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(bus->dev, "gsc command: successfully written %u bytes\n", rx_msg.written);
ret = rx_msg.written;
end:
kfree(ext_hdr);
return ret;
}
EXPORT_SYMBOL_GPL(mei_cldev_send_gsc_command);
/** /**
* mei_cl_device_find - find matching entry in the driver id table * mei_cl_device_find - find matching entry in the driver id table
* *
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
struct mei_cl_device; struct mei_cl_device;
struct mei_device; struct mei_device;
struct scatterlist;
typedef void (*mei_cldev_cb_t)(struct mei_cl_device *cldev); typedef void (*mei_cldev_cb_t)(struct mei_cl_device *cldev);
...@@ -116,6 +117,11 @@ void mei_cldev_set_drvdata(struct mei_cl_device *cldev, void *data); ...@@ -116,6 +117,11 @@ void mei_cldev_set_drvdata(struct mei_cl_device *cldev, void *data);
int mei_cldev_enable(struct mei_cl_device *cldev); int mei_cldev_enable(struct mei_cl_device *cldev);
int mei_cldev_disable(struct mei_cl_device *cldev); int mei_cldev_disable(struct mei_cl_device *cldev);
bool mei_cldev_enabled(const struct mei_cl_device *cldev); bool mei_cldev_enabled(const struct mei_cl_device *cldev);
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);
void *mei_cldev_dma_map(struct mei_cl_device *cldev, u8 buffer_id, size_t size); void *mei_cldev_dma_map(struct mei_cl_device *cldev, u8 buffer_id, size_t size);
int mei_cldev_dma_unmap(struct mei_cl_device *cldev); int mei_cldev_dma_unmap(struct mei_cl_device *cldev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment