Path: blob/master/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c
26282 views
// SPDX-License-Identifier: GPL-2.01// Copyright 2019 NXP23#include <linux/init.h>4#include <linux/module.h>5#include <linux/dmapool.h>6#include <linux/of_irq.h>7#include <linux/iommu.h>8#include <linux/sys_soc.h>9#include <linux/fsl/mc.h>10#include <soc/fsl/dpaa2-io.h>1112#include "../virt-dma.h"13#include "dpdmai.h"14#include "dpaa2-qdma.h"1516static bool smmu_disable = true;1718static struct dpaa2_qdma_chan *to_dpaa2_qdma_chan(struct dma_chan *chan)19{20return container_of(chan, struct dpaa2_qdma_chan, vchan.chan);21}2223static struct dpaa2_qdma_comp *to_fsl_qdma_comp(struct virt_dma_desc *vd)24{25return container_of(vd, struct dpaa2_qdma_comp, vdesc);26}2728static int dpaa2_qdma_alloc_chan_resources(struct dma_chan *chan)29{30struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan);31struct dpaa2_qdma_engine *dpaa2_qdma = dpaa2_chan->qdma;32struct device *dev = &dpaa2_qdma->priv->dpdmai_dev->dev;3334dpaa2_chan->fd_pool = dma_pool_create("fd_pool", dev,35sizeof(struct dpaa2_fd),36sizeof(struct dpaa2_fd), 0);37if (!dpaa2_chan->fd_pool)38goto err;3940dpaa2_chan->fl_pool =41dma_pool_create("fl_pool", dev,42sizeof(struct dpaa2_fl_entry) * 3,43sizeof(struct dpaa2_fl_entry), 0);4445if (!dpaa2_chan->fl_pool)46goto err_fd;4748dpaa2_chan->sdd_pool =49dma_pool_create("sdd_pool", dev,50sizeof(struct dpaa2_qdma_sd_d) * 2,51sizeof(struct dpaa2_qdma_sd_d), 0);52if (!dpaa2_chan->sdd_pool)53goto err_fl;5455return dpaa2_qdma->desc_allocated++;56err_fl:57dma_pool_destroy(dpaa2_chan->fl_pool);58err_fd:59dma_pool_destroy(dpaa2_chan->fd_pool);60err:61return -ENOMEM;62}6364static void dpaa2_qdma_free_chan_resources(struct dma_chan *chan)65{66struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan);67struct dpaa2_qdma_engine *dpaa2_qdma = dpaa2_chan->qdma;68unsigned long flags;6970LIST_HEAD(head);7172spin_lock_irqsave(&dpaa2_chan->vchan.lock, flags);73vchan_get_all_descriptors(&dpaa2_chan->vchan, &head);74spin_unlock_irqrestore(&dpaa2_chan->vchan.lock, flags);7576vchan_dma_desc_free_list(&dpaa2_chan->vchan, &head);7778dpaa2_dpdmai_free_comp(dpaa2_chan, &dpaa2_chan->comp_used);79dpaa2_dpdmai_free_comp(dpaa2_chan, &dpaa2_chan->comp_free);8081dma_pool_destroy(dpaa2_chan->fd_pool);82dma_pool_destroy(dpaa2_chan->fl_pool);83dma_pool_destroy(dpaa2_chan->sdd_pool);84dpaa2_qdma->desc_allocated--;85}8687/*88* Request a command descriptor for enqueue.89*/90static struct dpaa2_qdma_comp *91dpaa2_qdma_request_desc(struct dpaa2_qdma_chan *dpaa2_chan)92{93struct dpaa2_qdma_priv *qdma_priv = dpaa2_chan->qdma->priv;94struct device *dev = &qdma_priv->dpdmai_dev->dev;95struct dpaa2_qdma_comp *comp_temp = NULL;96unsigned long flags;9798spin_lock_irqsave(&dpaa2_chan->queue_lock, flags);99if (list_empty(&dpaa2_chan->comp_free)) {100spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags);101comp_temp = kzalloc(sizeof(*comp_temp), GFP_NOWAIT);102if (!comp_temp)103goto err;104comp_temp->fd_virt_addr =105dma_pool_alloc(dpaa2_chan->fd_pool, GFP_NOWAIT,106&comp_temp->fd_bus_addr);107if (!comp_temp->fd_virt_addr)108goto err_comp;109110comp_temp->fl_virt_addr =111dma_pool_alloc(dpaa2_chan->fl_pool, GFP_NOWAIT,112&comp_temp->fl_bus_addr);113if (!comp_temp->fl_virt_addr)114goto err_fd_virt;115116comp_temp->desc_virt_addr =117dma_pool_alloc(dpaa2_chan->sdd_pool, GFP_NOWAIT,118&comp_temp->desc_bus_addr);119if (!comp_temp->desc_virt_addr)120goto err_fl_virt;121122comp_temp->qchan = dpaa2_chan;123return comp_temp;124}125126comp_temp = list_first_entry(&dpaa2_chan->comp_free,127struct dpaa2_qdma_comp, list);128list_del(&comp_temp->list);129spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags);130131comp_temp->qchan = dpaa2_chan;132133return comp_temp;134135err_fl_virt:136dma_pool_free(dpaa2_chan->fl_pool,137comp_temp->fl_virt_addr,138comp_temp->fl_bus_addr);139err_fd_virt:140dma_pool_free(dpaa2_chan->fd_pool,141comp_temp->fd_virt_addr,142comp_temp->fd_bus_addr);143err_comp:144kfree(comp_temp);145err:146dev_err(dev, "Failed to request descriptor\n");147return NULL;148}149150static void151dpaa2_qdma_populate_fd(u32 format, struct dpaa2_qdma_comp *dpaa2_comp)152{153struct dpaa2_fd *fd;154155fd = dpaa2_comp->fd_virt_addr;156memset(fd, 0, sizeof(struct dpaa2_fd));157158/* fd populated */159dpaa2_fd_set_addr(fd, dpaa2_comp->fl_bus_addr);160161/*162* Bypass memory translation, Frame list format, short length disable163* we need to disable BMT if fsl-mc use iova addr164*/165if (smmu_disable)166dpaa2_fd_set_bpid(fd, QMAN_FD_BMT_ENABLE);167dpaa2_fd_set_format(fd, QMAN_FD_FMT_ENABLE | QMAN_FD_SL_DISABLE);168169dpaa2_fd_set_frc(fd, format | QDMA_SER_CTX);170}171172/* first frame list for descriptor buffer */173static void174dpaa2_qdma_populate_first_framel(struct dpaa2_fl_entry *f_list,175struct dpaa2_qdma_comp *dpaa2_comp,176bool wrt_changed)177{178struct dpaa2_qdma_sd_d *sdd;179180sdd = dpaa2_comp->desc_virt_addr;181memset(sdd, 0, 2 * (sizeof(*sdd)));182183/* source descriptor CMD */184sdd->cmd = cpu_to_le32(QDMA_SD_CMD_RDTTYPE_COHERENT);185sdd++;186187/* dest descriptor CMD */188if (wrt_changed)189sdd->cmd = cpu_to_le32(LX2160_QDMA_DD_CMD_WRTTYPE_COHERENT);190else191sdd->cmd = cpu_to_le32(QDMA_DD_CMD_WRTTYPE_COHERENT);192193memset(f_list, 0, sizeof(struct dpaa2_fl_entry));194195/* first frame list to source descriptor */196dpaa2_fl_set_addr(f_list, dpaa2_comp->desc_bus_addr);197dpaa2_fl_set_len(f_list, 0x20);198dpaa2_fl_set_format(f_list, QDMA_FL_FMT_SBF | QDMA_FL_SL_LONG);199200/* bypass memory translation */201if (smmu_disable)202f_list->bpid = cpu_to_le16(QDMA_FL_BMT_ENABLE);203}204205/* source and destination frame list */206static void207dpaa2_qdma_populate_frames(struct dpaa2_fl_entry *f_list,208dma_addr_t dst, dma_addr_t src,209size_t len, uint8_t fmt)210{211/* source frame list to source buffer */212memset(f_list, 0, sizeof(struct dpaa2_fl_entry));213214dpaa2_fl_set_addr(f_list, src);215dpaa2_fl_set_len(f_list, len);216217/* single buffer frame or scatter gather frame */218dpaa2_fl_set_format(f_list, (fmt | QDMA_FL_SL_LONG));219220/* bypass memory translation */221if (smmu_disable)222f_list->bpid = cpu_to_le16(QDMA_FL_BMT_ENABLE);223224f_list++;225226/* destination frame list to destination buffer */227memset(f_list, 0, sizeof(struct dpaa2_fl_entry));228229dpaa2_fl_set_addr(f_list, dst);230dpaa2_fl_set_len(f_list, len);231dpaa2_fl_set_format(f_list, (fmt | QDMA_FL_SL_LONG));232/* single buffer frame or scatter gather frame */233dpaa2_fl_set_final(f_list, QDMA_FL_F);234/* bypass memory translation */235if (smmu_disable)236f_list->bpid = cpu_to_le16(QDMA_FL_BMT_ENABLE);237}238239static struct dma_async_tx_descriptor240*dpaa2_qdma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst,241dma_addr_t src, size_t len, ulong flags)242{243struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan);244struct dpaa2_qdma_engine *dpaa2_qdma;245struct dpaa2_qdma_comp *dpaa2_comp;246struct dpaa2_fl_entry *f_list;247bool wrt_changed;248249dpaa2_qdma = dpaa2_chan->qdma;250dpaa2_comp = dpaa2_qdma_request_desc(dpaa2_chan);251if (!dpaa2_comp)252return NULL;253254wrt_changed = (bool)dpaa2_qdma->qdma_wrtype_fixup;255256/* populate Frame descriptor */257dpaa2_qdma_populate_fd(QDMA_FD_LONG_FORMAT, dpaa2_comp);258259f_list = dpaa2_comp->fl_virt_addr;260261/* first frame list for descriptor buffer (logn format) */262dpaa2_qdma_populate_first_framel(f_list, dpaa2_comp, wrt_changed);263264f_list++;265266dpaa2_qdma_populate_frames(f_list, dst, src, len, QDMA_FL_FMT_SBF);267268return vchan_tx_prep(&dpaa2_chan->vchan, &dpaa2_comp->vdesc, flags);269}270271static void dpaa2_qdma_issue_pending(struct dma_chan *chan)272{273struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan);274struct dpaa2_qdma_comp *dpaa2_comp;275struct virt_dma_desc *vdesc;276struct dpaa2_fd *fd;277unsigned long flags;278int err;279280spin_lock_irqsave(&dpaa2_chan->queue_lock, flags);281spin_lock(&dpaa2_chan->vchan.lock);282if (vchan_issue_pending(&dpaa2_chan->vchan)) {283vdesc = vchan_next_desc(&dpaa2_chan->vchan);284if (!vdesc)285goto err_enqueue;286dpaa2_comp = to_fsl_qdma_comp(vdesc);287288fd = dpaa2_comp->fd_virt_addr;289290list_del(&vdesc->node);291list_add_tail(&dpaa2_comp->list, &dpaa2_chan->comp_used);292293err = dpaa2_io_service_enqueue_fq(NULL, dpaa2_chan->fqid, fd);294if (err) {295list_move_tail(&dpaa2_comp->list,296&dpaa2_chan->comp_free);297}298}299err_enqueue:300spin_unlock(&dpaa2_chan->vchan.lock);301spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags);302}303304static int __cold dpaa2_qdma_setup(struct fsl_mc_device *ls_dev)305{306struct dpaa2_qdma_priv_per_prio *ppriv;307struct device *dev = &ls_dev->dev;308struct dpaa2_qdma_priv *priv;309u8 prio_def = DPDMAI_PRIO_NUM;310int err = -EINVAL;311int i;312313priv = dev_get_drvdata(dev);314315priv->dev = dev;316priv->dpqdma_id = ls_dev->obj_desc.id;317318/* Get the handle for the DPDMAI this interface is associate with */319err = dpdmai_open(priv->mc_io, 0, priv->dpqdma_id, &ls_dev->mc_handle);320if (err) {321dev_err(dev, "dpdmai_open() failed\n");322return err;323}324325dev_dbg(dev, "Opened dpdmai object successfully\n");326327err = dpdmai_get_attributes(priv->mc_io, 0, ls_dev->mc_handle,328&priv->dpdmai_attr);329if (err) {330dev_err(dev, "dpdmai_get_attributes() failed\n");331goto exit;332}333334if (priv->dpdmai_attr.version.major > DPDMAI_VER_MAJOR) {335err = -EINVAL;336dev_err(dev, "DPDMAI major version mismatch\n"337"Found %u.%u, supported version is %u.%u\n",338priv->dpdmai_attr.version.major,339priv->dpdmai_attr.version.minor,340DPDMAI_VER_MAJOR, DPDMAI_VER_MINOR);341goto exit;342}343344if (priv->dpdmai_attr.version.minor > DPDMAI_VER_MINOR) {345err = -EINVAL;346dev_err(dev, "DPDMAI minor version mismatch\n"347"Found %u.%u, supported version is %u.%u\n",348priv->dpdmai_attr.version.major,349priv->dpdmai_attr.version.minor,350DPDMAI_VER_MAJOR, DPDMAI_VER_MINOR);351goto exit;352}353354priv->num_pairs = min(priv->dpdmai_attr.num_of_priorities, prio_def);355ppriv = kcalloc(priv->num_pairs, sizeof(*ppriv), GFP_KERNEL);356if (!ppriv) {357err = -ENOMEM;358goto exit;359}360priv->ppriv = ppriv;361362for (i = 0; i < priv->num_pairs; i++) {363err = dpdmai_get_rx_queue(priv->mc_io, 0, ls_dev->mc_handle,364i, 0, &priv->rx_queue_attr[i]);365if (err) {366dev_err(dev, "dpdmai_get_rx_queue() failed\n");367goto exit;368}369ppriv->rsp_fqid = priv->rx_queue_attr[i].fqid;370371err = dpdmai_get_tx_queue(priv->mc_io, 0, ls_dev->mc_handle,372i, 0, &priv->tx_queue_attr[i]);373if (err) {374dev_err(dev, "dpdmai_get_tx_queue() failed\n");375goto exit;376}377ppriv->req_fqid = priv->tx_queue_attr[i].fqid;378ppriv->prio = DPAA2_QDMA_DEFAULT_PRIORITY;379ppriv->priv = priv;380ppriv++;381}382383return 0;384exit:385dpdmai_close(priv->mc_io, 0, ls_dev->mc_handle);386return err;387}388389static void dpaa2_qdma_fqdan_cb(struct dpaa2_io_notification_ctx *ctx)390{391struct dpaa2_qdma_priv_per_prio *ppriv = container_of(ctx,392struct dpaa2_qdma_priv_per_prio, nctx);393struct dpaa2_qdma_comp *dpaa2_comp, *_comp_tmp;394struct dpaa2_qdma_priv *priv = ppriv->priv;395u32 n_chans = priv->dpaa2_qdma->n_chans;396struct dpaa2_qdma_chan *qchan;397const struct dpaa2_fd *fd_eq;398const struct dpaa2_fd *fd;399struct dpaa2_dq *dq;400int is_last = 0;401int found;402u8 status;403int err;404int i;405406do {407err = dpaa2_io_service_pull_fq(NULL, ppriv->rsp_fqid,408ppriv->store);409} while (err);410411while (!is_last) {412do {413dq = dpaa2_io_store_next(ppriv->store, &is_last);414} while (!is_last && !dq);415if (!dq) {416dev_err(priv->dev, "FQID returned no valid frames!\n");417continue;418}419420/* obtain FD and process the error */421fd = dpaa2_dq_fd(dq);422423status = dpaa2_fd_get_ctrl(fd) & 0xff;424if (status)425dev_err(priv->dev, "FD error occurred\n");426found = 0;427for (i = 0; i < n_chans; i++) {428qchan = &priv->dpaa2_qdma->chans[i];429spin_lock(&qchan->queue_lock);430if (list_empty(&qchan->comp_used)) {431spin_unlock(&qchan->queue_lock);432continue;433}434list_for_each_entry_safe(dpaa2_comp, _comp_tmp,435&qchan->comp_used, list) {436fd_eq = dpaa2_comp->fd_virt_addr;437438if (le64_to_cpu(fd_eq->simple.addr) ==439le64_to_cpu(fd->simple.addr)) {440spin_lock(&qchan->vchan.lock);441vchan_cookie_complete(&442dpaa2_comp->vdesc);443spin_unlock(&qchan->vchan.lock);444found = 1;445break;446}447}448spin_unlock(&qchan->queue_lock);449if (found)450break;451}452}453454dpaa2_io_service_rearm(NULL, ctx);455}456457static int __cold dpaa2_qdma_dpio_setup(struct dpaa2_qdma_priv *priv)458{459struct dpaa2_qdma_priv_per_prio *ppriv;460struct device *dev = priv->dev;461int err = -EINVAL;462int i, num;463464num = priv->num_pairs;465ppriv = priv->ppriv;466for (i = 0; i < num; i++) {467ppriv->nctx.is_cdan = 0;468ppriv->nctx.desired_cpu = DPAA2_IO_ANY_CPU;469ppriv->nctx.id = ppriv->rsp_fqid;470ppriv->nctx.cb = dpaa2_qdma_fqdan_cb;471err = dpaa2_io_service_register(NULL, &ppriv->nctx, dev);472if (err) {473dev_err(dev, "Notification register failed\n");474goto err_service;475}476477ppriv->store =478dpaa2_io_store_create(DPAA2_QDMA_STORE_SIZE, dev);479if (!ppriv->store) {480err = -ENOMEM;481dev_err(dev, "dpaa2_io_store_create() failed\n");482goto err_store;483}484485ppriv++;486}487return 0;488489err_store:490dpaa2_io_service_deregister(NULL, &ppriv->nctx, dev);491err_service:492ppriv--;493while (ppriv >= priv->ppriv) {494dpaa2_io_service_deregister(NULL, &ppriv->nctx, dev);495dpaa2_io_store_destroy(ppriv->store);496ppriv--;497}498return err;499}500501static void dpaa2_dpmai_store_free(struct dpaa2_qdma_priv *priv)502{503struct dpaa2_qdma_priv_per_prio *ppriv = priv->ppriv;504int i;505506for (i = 0; i < priv->num_pairs; i++) {507dpaa2_io_store_destroy(ppriv->store);508ppriv++;509}510}511512static void dpaa2_dpdmai_dpio_free(struct dpaa2_qdma_priv *priv)513{514struct dpaa2_qdma_priv_per_prio *ppriv = priv->ppriv;515struct device *dev = priv->dev;516int i;517518for (i = 0; i < priv->num_pairs; i++) {519dpaa2_io_service_deregister(NULL, &ppriv->nctx, dev);520ppriv++;521}522}523524static int __cold dpaa2_dpdmai_bind(struct dpaa2_qdma_priv *priv)525{526struct dpdmai_rx_queue_cfg rx_queue_cfg;527struct dpaa2_qdma_priv_per_prio *ppriv;528struct device *dev = priv->dev;529struct fsl_mc_device *ls_dev;530int i, num;531int err;532533ls_dev = to_fsl_mc_device(dev);534num = priv->num_pairs;535ppriv = priv->ppriv;536for (i = 0; i < num; i++) {537rx_queue_cfg.options = DPDMAI_QUEUE_OPT_USER_CTX |538DPDMAI_QUEUE_OPT_DEST;539rx_queue_cfg.user_ctx = ppriv->nctx.qman64;540rx_queue_cfg.dest_cfg.dest_type = DPDMAI_DEST_DPIO;541rx_queue_cfg.dest_cfg.dest_id = ppriv->nctx.dpio_id;542rx_queue_cfg.dest_cfg.priority = ppriv->prio;543err = dpdmai_set_rx_queue(priv->mc_io, 0, ls_dev->mc_handle,544rx_queue_cfg.dest_cfg.priority, 0,545&rx_queue_cfg);546if (err) {547dev_err(dev, "dpdmai_set_rx_queue() failed\n");548return err;549}550551ppriv++;552}553554return 0;555}556557static int __cold dpaa2_dpdmai_dpio_unbind(struct dpaa2_qdma_priv *priv)558{559struct dpaa2_qdma_priv_per_prio *ppriv = priv->ppriv;560struct device *dev = priv->dev;561struct fsl_mc_device *ls_dev;562int err = 0;563int i;564565ls_dev = to_fsl_mc_device(dev);566567for (i = 0; i < priv->num_pairs; i++) {568ppriv->nctx.qman64 = 0;569ppriv->nctx.dpio_id = 0;570ppriv++;571}572573err = dpdmai_reset(priv->mc_io, 0, ls_dev->mc_handle);574if (err)575dev_err(dev, "dpdmai_reset() failed\n");576577return err;578}579580static void dpaa2_dpdmai_free_comp(struct dpaa2_qdma_chan *qchan,581struct list_head *head)582{583struct dpaa2_qdma_comp *comp_tmp, *_comp_tmp;584unsigned long flags;585586list_for_each_entry_safe(comp_tmp, _comp_tmp,587head, list) {588spin_lock_irqsave(&qchan->queue_lock, flags);589list_del(&comp_tmp->list);590spin_unlock_irqrestore(&qchan->queue_lock, flags);591dma_pool_free(qchan->fd_pool,592comp_tmp->fd_virt_addr,593comp_tmp->fd_bus_addr);594dma_pool_free(qchan->fl_pool,595comp_tmp->fl_virt_addr,596comp_tmp->fl_bus_addr);597dma_pool_free(qchan->sdd_pool,598comp_tmp->desc_virt_addr,599comp_tmp->desc_bus_addr);600kfree(comp_tmp);601}602}603604static void dpaa2_dpdmai_free_channels(struct dpaa2_qdma_engine *dpaa2_qdma)605{606struct dpaa2_qdma_chan *qchan;607int num, i;608609num = dpaa2_qdma->n_chans;610for (i = 0; i < num; i++) {611qchan = &dpaa2_qdma->chans[i];612dpaa2_dpdmai_free_comp(qchan, &qchan->comp_used);613dpaa2_dpdmai_free_comp(qchan, &qchan->comp_free);614dma_pool_destroy(qchan->fd_pool);615dma_pool_destroy(qchan->fl_pool);616dma_pool_destroy(qchan->sdd_pool);617}618}619620static void dpaa2_qdma_free_desc(struct virt_dma_desc *vdesc)621{622struct dpaa2_qdma_comp *dpaa2_comp;623struct dpaa2_qdma_chan *qchan;624unsigned long flags;625626dpaa2_comp = to_fsl_qdma_comp(vdesc);627qchan = dpaa2_comp->qchan;628spin_lock_irqsave(&qchan->queue_lock, flags);629list_move_tail(&dpaa2_comp->list, &qchan->comp_free);630spin_unlock_irqrestore(&qchan->queue_lock, flags);631}632633static int dpaa2_dpdmai_init_channels(struct dpaa2_qdma_engine *dpaa2_qdma)634{635struct dpaa2_qdma_priv *priv = dpaa2_qdma->priv;636struct dpaa2_qdma_chan *dpaa2_chan;637int num = priv->num_pairs;638int i;639640INIT_LIST_HEAD(&dpaa2_qdma->dma_dev.channels);641for (i = 0; i < dpaa2_qdma->n_chans; i++) {642dpaa2_chan = &dpaa2_qdma->chans[i];643dpaa2_chan->qdma = dpaa2_qdma;644dpaa2_chan->fqid = priv->tx_queue_attr[i % num].fqid;645dpaa2_chan->vchan.desc_free = dpaa2_qdma_free_desc;646vchan_init(&dpaa2_chan->vchan, &dpaa2_qdma->dma_dev);647spin_lock_init(&dpaa2_chan->queue_lock);648INIT_LIST_HEAD(&dpaa2_chan->comp_used);649INIT_LIST_HEAD(&dpaa2_chan->comp_free);650}651return 0;652}653654static int dpaa2_qdma_probe(struct fsl_mc_device *dpdmai_dev)655{656struct device *dev = &dpdmai_dev->dev;657struct dpaa2_qdma_engine *dpaa2_qdma;658struct dpaa2_qdma_priv *priv;659int err;660661priv = kzalloc(sizeof(*priv), GFP_KERNEL);662if (!priv)663return -ENOMEM;664dev_set_drvdata(dev, priv);665priv->dpdmai_dev = dpdmai_dev;666667priv->iommu_domain = iommu_get_domain_for_dev(dev);668if (priv->iommu_domain)669smmu_disable = false;670671/* obtain a MC portal */672err = fsl_mc_portal_allocate(dpdmai_dev, 0, &priv->mc_io);673if (err) {674if (err == -ENXIO)675err = -EPROBE_DEFER;676else677dev_err(dev, "MC portal allocation failed\n");678goto err_mcportal;679}680681/* DPDMAI initialization */682err = dpaa2_qdma_setup(dpdmai_dev);683if (err) {684dev_err(dev, "dpaa2_dpdmai_setup() failed\n");685goto err_dpdmai_setup;686}687688/* DPIO */689err = dpaa2_qdma_dpio_setup(priv);690if (err) {691dev_err(dev, "dpaa2_dpdmai_dpio_setup() failed\n");692goto err_dpio_setup;693}694695/* DPDMAI binding to DPIO */696err = dpaa2_dpdmai_bind(priv);697if (err) {698dev_err(dev, "dpaa2_dpdmai_bind() failed\n");699goto err_bind;700}701702/* DPDMAI enable */703err = dpdmai_enable(priv->mc_io, 0, dpdmai_dev->mc_handle);704if (err) {705dev_err(dev, "dpdmai_enable() failed\n");706goto err_enable;707}708709dpaa2_qdma = kzalloc(sizeof(*dpaa2_qdma), GFP_KERNEL);710if (!dpaa2_qdma) {711err = -ENOMEM;712goto err_eng;713}714715priv->dpaa2_qdma = dpaa2_qdma;716dpaa2_qdma->priv = priv;717718dpaa2_qdma->desc_allocated = 0;719dpaa2_qdma->n_chans = NUM_CH;720721dpaa2_dpdmai_init_channels(dpaa2_qdma);722723if (soc_device_match(soc_fixup_tuning))724dpaa2_qdma->qdma_wrtype_fixup = true;725else726dpaa2_qdma->qdma_wrtype_fixup = false;727728dma_cap_set(DMA_PRIVATE, dpaa2_qdma->dma_dev.cap_mask);729dma_cap_set(DMA_SLAVE, dpaa2_qdma->dma_dev.cap_mask);730dma_cap_set(DMA_MEMCPY, dpaa2_qdma->dma_dev.cap_mask);731732dpaa2_qdma->dma_dev.dev = dev;733dpaa2_qdma->dma_dev.device_alloc_chan_resources =734dpaa2_qdma_alloc_chan_resources;735dpaa2_qdma->dma_dev.device_free_chan_resources =736dpaa2_qdma_free_chan_resources;737dpaa2_qdma->dma_dev.device_tx_status = dma_cookie_status;738dpaa2_qdma->dma_dev.device_prep_dma_memcpy = dpaa2_qdma_prep_memcpy;739dpaa2_qdma->dma_dev.device_issue_pending = dpaa2_qdma_issue_pending;740741err = dma_async_device_register(&dpaa2_qdma->dma_dev);742if (err) {743dev_err(dev, "Can't register NXP QDMA engine.\n");744goto err_dpaa2_qdma;745}746747return 0;748749err_dpaa2_qdma:750kfree(dpaa2_qdma);751err_eng:752dpdmai_disable(priv->mc_io, 0, dpdmai_dev->mc_handle);753err_enable:754dpaa2_dpdmai_dpio_unbind(priv);755err_bind:756dpaa2_dpmai_store_free(priv);757dpaa2_dpdmai_dpio_free(priv);758err_dpio_setup:759kfree(priv->ppriv);760dpdmai_close(priv->mc_io, 0, dpdmai_dev->mc_handle);761err_dpdmai_setup:762fsl_mc_portal_free(priv->mc_io);763err_mcportal:764kfree(priv);765dev_set_drvdata(dev, NULL);766return err;767}768769static void dpaa2_qdma_remove(struct fsl_mc_device *ls_dev)770{771struct dpaa2_qdma_engine *dpaa2_qdma;772struct dpaa2_qdma_priv *priv;773struct device *dev;774775dev = &ls_dev->dev;776priv = dev_get_drvdata(dev);777dpaa2_qdma = priv->dpaa2_qdma;778779dpdmai_disable(priv->mc_io, 0, ls_dev->mc_handle);780dpaa2_dpdmai_dpio_unbind(priv);781dpaa2_dpmai_store_free(priv);782dpaa2_dpdmai_dpio_free(priv);783dpdmai_close(priv->mc_io, 0, ls_dev->mc_handle);784fsl_mc_portal_free(priv->mc_io);785dev_set_drvdata(dev, NULL);786dpaa2_dpdmai_free_channels(dpaa2_qdma);787788dma_async_device_unregister(&dpaa2_qdma->dma_dev);789kfree(priv);790kfree(dpaa2_qdma);791}792793static void dpaa2_qdma_shutdown(struct fsl_mc_device *ls_dev)794{795struct dpaa2_qdma_priv *priv;796struct device *dev;797798dev = &ls_dev->dev;799priv = dev_get_drvdata(dev);800801dpdmai_disable(priv->mc_io, 0, ls_dev->mc_handle);802dpaa2_dpdmai_dpio_unbind(priv);803dpdmai_close(priv->mc_io, 0, ls_dev->mc_handle);804dpdmai_destroy(priv->mc_io, 0, priv->dpqdma_id, ls_dev->mc_handle);805}806807static const struct fsl_mc_device_id dpaa2_qdma_id_table[] = {808{809.vendor = FSL_MC_VENDOR_FREESCALE,810.obj_type = "dpdmai",811},812{ .vendor = 0x0 }813};814815static struct fsl_mc_driver dpaa2_qdma_driver = {816.driver = {817.name = "dpaa2-qdma",818},819.probe = dpaa2_qdma_probe,820.remove = dpaa2_qdma_remove,821.shutdown = dpaa2_qdma_shutdown,822.match_id_table = dpaa2_qdma_id_table823};824825static int __init dpaa2_qdma_driver_init(void)826{827return fsl_mc_driver_register(&(dpaa2_qdma_driver));828}829late_initcall(dpaa2_qdma_driver_init);830831static void __exit fsl_qdma_exit(void)832{833fsl_mc_driver_unregister(&(dpaa2_qdma_driver));834}835module_exit(fsl_qdma_exit);836837MODULE_ALIAS("platform:fsl-dpaa2-qdma");838MODULE_LICENSE("GPL v2");839MODULE_DESCRIPTION("NXP Layerscape DPAA2 qDMA engine driver");840841842