150472Speter// SPDX-License-Identifier: GPL-2.0 21664Sphk/* 369040Sben * An example software sink buffer for Intel TH MSU. 469040Sben * 569040Sben * Copyright (C) 2019 Intel Corporation. 669040Sben */ 782604Salex 882604Salex#include <linux/intel_th.h> 982604Salex#include <linux/module.h> 1082604Salex#include <linux/slab.h> 111664Sphk#include <linux/device.h> 123023Srgrimes#include <linux/dma-mapping.h> 133023Srgrimes 1482604Salex#define MAX_SGTS 16 1582604Salex 1682604Salexstruct msu_sink_private { 171664Sphk struct device *dev; 1872679Skris struct sg_table **sgts; 1999260Sjohan unsigned int nr_sgts; 2072878Skris}; 2172878Skris 2272878Skrisstatic void *msu_sink_assign(struct device *dev, int *mode) 2372878Skris{ 2472878Skris struct msu_sink_private *priv; 2599260Sjohan 2673145Skris priv = kzalloc(sizeof(*priv), GFP_KERNEL); 2773145Skris if (!priv) 2873145Skris return NULL; 2972878Skris 3072878Skris priv->sgts = kcalloc(MAX_SGTS, sizeof(void *), GFP_KERNEL); 3172679Skris if (!priv->sgts) { 32101232Sru kfree(priv); 33101232Sru return NULL; 34101232Sru } 3572878Skris 3674146Skris priv->dev = dev; 3772878Skris *mode = MSC_MODE_MULTI; 3858648Skris 3968917Sdougb return priv; 4058648Skris} 4168917Sdougb 4258648Skrisstatic void msu_sink_unassign(void *data) 4358648Skris{ 4458648Skris struct msu_sink_private *priv = data; 451664Sphk 4629281Sjkh kfree(priv->sgts); 471664Sphk kfree(priv); 4859006Sobrien} 4959006Sobrien 5059006Sobrien/* See also: msc.c: __msc_buffer_win_alloc() */ 5159006Sobrienstatic int msu_sink_alloc_window(void *data, struct sg_table **sgt, size_t size) 521664Sphk{ 5359006Sobrien struct msu_sink_private *priv = data; 5459006Sobrien unsigned int nents; 5562136Sobrien struct scatterlist *sg_ptr; 5662136Sobrien void *block; 5780452Speter int ret, i; 5899260Sjohan 5962136Sobrien if (priv->nr_sgts == MAX_SGTS) 6082604Salex return -ENOMEM; 6182604Salex 6282604Salex nents = DIV_ROUND_UP(size, PAGE_SIZE); 6382604Salex 6462136Sobrien ret = sg_alloc_table(*sgt, nents, GFP_KERNEL); 6568917Sdougb if (ret) 6668263Sobrien return -ENOMEM; 6768263Sobrien 6868263Sobrien priv->sgts[priv->nr_sgts++] = *sgt; 6965380Sobrien 7065380Sobrien for_each_sg((*sgt)->sgl, sg_ptr, nents, i) { 7165380Sobrien block = dma_alloc_coherent(priv->dev->parent->parent, 7281749Sobrien PAGE_SIZE, &sg_dma_address(sg_ptr), 7381749Sobrien GFP_KERNEL); 7481749Sobrien if (!block) 7581749Sobrien return -ENOMEM; 7681749Sobrien 7781749Sobrien sg_set_buf(sg_ptr, block, PAGE_SIZE); 7842325Sobrien } 79100870Sru 8035222Sache return nents; 8165884Sache} 8265957Sache 8365884Sache/* See also: msc.c: __msc_buffer_win_free() */ 8464803Sbrianstatic void msu_sink_free_window(void *data, struct sg_table *sgt) 8564803Sbrian{ 8664803Sbrian struct msu_sink_private *priv = data; 8768705Sgreen struct scatterlist *sg_ptr; 8868705Sgreen int i; 8968705Sgreen 9097387Stjr for_each_sg(sgt->sgl, sg_ptr, sgt->nents, i) { 9197387Stjr dma_free_coherent(priv->dev->parent->parent, PAGE_SIZE, 9297387Stjr sg_virt(sg_ptr), sg_dma_address(sg_ptr)); 9397387Stjr } 9451299Speter 9557542Skris sg_free_table(sgt); 9690522Sobrien priv->nr_sgts--; 9759124Sasmodai} 9857542Skris 9990522Sobrienstatic int msu_sink_ready(void *data, struct sg_table *sgt, size_t bytes) 10077041Sru{ 10192868Sru struct msu_sink_private *priv = data; 10261139Shoek 10358859Ssheldonh intel_th_msc_window_unlock(priv->dev, sgt); 10459884Schuckr 10557764Skris return 0; 10657542Skris} 10757542Skris 10898064Sdougbstatic const struct msu_buffer sink_mbuf = { 10957542Skris .name = "sink", 11058418Sobrien .assign = msu_sink_assign, 11159338Sobrien .unassign = msu_sink_unassign, 11258280Skris .alloc_window = msu_sink_alloc_window, 11357553Skris .free_window = msu_sink_free_window, 11457542Skris .ready = msu_sink_ready, 11557542Skris}; 11657542Skris 11765381Sobrienmodule_intel_th_msu_buffer(sink_mbuf); 11857553Skris 11957542SkrisMODULE_LICENSE("GPL v2"); 12035206Sphk