0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/intel_th.h>
0009 #include <linux/module.h>
0010 #include <linux/slab.h>
0011 #include <linux/device.h>
0012 #include <linux/dma-mapping.h>
0013
0014 #define MAX_SGTS 16
0015
0016 struct msu_sink_private {
0017 struct device *dev;
0018 struct sg_table **sgts;
0019 unsigned int nr_sgts;
0020 };
0021
0022 static void *msu_sink_assign(struct device *dev, int *mode)
0023 {
0024 struct msu_sink_private *priv;
0025
0026 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
0027 if (!priv)
0028 return NULL;
0029
0030 priv->sgts = kcalloc(MAX_SGTS, sizeof(void *), GFP_KERNEL);
0031 if (!priv->sgts) {
0032 kfree(priv);
0033 return NULL;
0034 }
0035
0036 priv->dev = dev;
0037 *mode = MSC_MODE_MULTI;
0038
0039 return priv;
0040 }
0041
0042 static void msu_sink_unassign(void *data)
0043 {
0044 struct msu_sink_private *priv = data;
0045
0046 kfree(priv->sgts);
0047 kfree(priv);
0048 }
0049
0050
0051 static int msu_sink_alloc_window(void *data, struct sg_table **sgt, size_t size)
0052 {
0053 struct msu_sink_private *priv = data;
0054 unsigned int nents;
0055 struct scatterlist *sg_ptr;
0056 void *block;
0057 int ret, i;
0058
0059 if (priv->nr_sgts == MAX_SGTS)
0060 return -ENOMEM;
0061
0062 nents = DIV_ROUND_UP(size, PAGE_SIZE);
0063
0064 ret = sg_alloc_table(*sgt, nents, GFP_KERNEL);
0065 if (ret)
0066 return -ENOMEM;
0067
0068 priv->sgts[priv->nr_sgts++] = *sgt;
0069
0070 for_each_sg((*sgt)->sgl, sg_ptr, nents, i) {
0071 block = dma_alloc_coherent(priv->dev->parent->parent,
0072 PAGE_SIZE, &sg_dma_address(sg_ptr),
0073 GFP_KERNEL);
0074 if (!block)
0075 return -ENOMEM;
0076
0077 sg_set_buf(sg_ptr, block, PAGE_SIZE);
0078 }
0079
0080 return nents;
0081 }
0082
0083
0084 static void msu_sink_free_window(void *data, struct sg_table *sgt)
0085 {
0086 struct msu_sink_private *priv = data;
0087 struct scatterlist *sg_ptr;
0088 int i;
0089
0090 for_each_sg(sgt->sgl, sg_ptr, sgt->nents, i) {
0091 dma_free_coherent(priv->dev->parent->parent, PAGE_SIZE,
0092 sg_virt(sg_ptr), sg_dma_address(sg_ptr));
0093 }
0094
0095 sg_free_table(sgt);
0096 priv->nr_sgts--;
0097 }
0098
0099 static int msu_sink_ready(void *data, struct sg_table *sgt, size_t bytes)
0100 {
0101 struct msu_sink_private *priv = data;
0102
0103 intel_th_msc_window_unlock(priv->dev, sgt);
0104
0105 return 0;
0106 }
0107
0108 static const struct msu_buffer sink_mbuf = {
0109 .name = "sink",
0110 .assign = msu_sink_assign,
0111 .unassign = msu_sink_unassign,
0112 .alloc_window = msu_sink_alloc_window,
0113 .free_window = msu_sink_free_window,
0114 .ready = msu_sink_ready,
0115 };
0116
0117 module_intel_th_msu_buffer(sink_mbuf);
0118
0119 MODULE_LICENSE("GPL v2");