summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/misc/mei/bus.c67
-rw-r--r--drivers/misc/mei/client.c3
-rw-r--r--drivers/misc/mei/hw.h5
-rw-r--r--include/linux/mei_cl_bus.h3
4 files changed, 75 insertions, 3 deletions
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 44bac4ad687c..46aa3554e97b 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -643,6 +643,64 @@ static void mei_cl_bus_vtag_free(struct mei_cl_device *cldev)
kfree(cl_vtag);
}
+void *mei_cldev_dma_map(struct mei_cl_device *cldev, u8 buffer_id, size_t size)
+{
+ struct mei_device *bus;
+ struct mei_cl *cl;
+ int ret;
+
+ if (!cldev || !buffer_id || !size)
+ return ERR_PTR(-EINVAL);
+
+ if (!IS_ALIGNED(size, MEI_FW_PAGE_SIZE)) {
+ dev_err(&cldev->dev, "Map size should be aligned to %lu\n",
+ MEI_FW_PAGE_SIZE);
+ return ERR_PTR(-EINVAL);
+ }
+
+ cl = cldev->cl;
+ bus = cldev->bus;
+
+ mutex_lock(&bus->device_lock);
+ if (cl->state == MEI_FILE_UNINITIALIZED) {
+ ret = mei_cl_link(cl);
+ if (ret)
+ goto out;
+ /* update pointers */
+ cl->cldev = cldev;
+ }
+
+ ret = mei_cl_dma_alloc_and_map(cl, NULL, buffer_id, size);
+out:
+ mutex_unlock(&bus->device_lock);
+ if (ret)
+ return ERR_PTR(ret);
+ return cl->dma.vaddr;
+}
+EXPORT_SYMBOL_GPL(mei_cldev_dma_map);
+
+int mei_cldev_dma_unmap(struct mei_cl_device *cldev)
+{
+ struct mei_device *bus;
+ struct mei_cl *cl;
+ int ret;
+
+ if (!cldev)
+ return -EINVAL;
+
+ cl = cldev->cl;
+ bus = cldev->bus;
+
+ mutex_lock(&bus->device_lock);
+ ret = mei_cl_dma_unmap(cl, NULL);
+
+ mei_cl_flush_queues(cl, NULL);
+ mei_cl_unlink(cl);
+ mutex_unlock(&bus->device_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mei_cldev_dma_unmap);
+
/**
* mei_cldev_enable - enable me client device
* create connection with me client
@@ -753,9 +811,11 @@ int mei_cldev_disable(struct mei_cl_device *cldev)
dev_err(bus->dev, "Could not disconnect from the ME client\n");
out:
- /* Flush queues and remove any pending read */
- mei_cl_flush_queues(cl, NULL);
- mei_cl_unlink(cl);
+ /* 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);
+ }
mutex_unlock(&bus->device_lock);
return err;
@@ -1052,6 +1112,7 @@ static void mei_cl_bus_dev_release(struct device *dev)
if (!cldev)
return;
+ mei_cl_flush_queues(cldev->cl, NULL);
mei_me_cl_put(cldev->me_cl);
mei_dev_bus_put(cldev->bus);
mei_cl_unlink(cldev->cl);
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 96f4e59c32a5..0e90591235a6 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -700,6 +700,9 @@ int mei_cl_unlink(struct mei_cl *cl)
cl_dbg(dev, cl, "unlink client");
+ if (cl->state == MEI_FILE_UNINITIALIZED)
+ return 0;
+
if (dev->open_handle_count > 0)
dev->open_handle_count--;
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index dfd60c916da0..b46077b17114 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -23,6 +23,11 @@
#define MEI_HBM_TIMEOUT 1 /* 1 second */
/*
+ * FW page size for DMA allocations
+ */
+#define MEI_FW_PAGE_SIZE 4096UL
+
+/*
* MEI Version
*/
#define HBM_MINOR_VERSION 2
diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
index c6786c12b207..df1fab44ea5c 100644
--- a/include/linux/mei_cl_bus.h
+++ b/include/linux/mei_cl_bus.h
@@ -117,4 +117,7 @@ int mei_cldev_enable(struct mei_cl_device *cldev);
int mei_cldev_disable(struct mei_cl_device *cldev);
bool mei_cldev_enabled(const struct mei_cl_device *cldev);
+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);
+
#endif /* _LINUX_MEI_CL_BUS_H */