/* * Topcliff PCH DMA controller driver * Copyright (c) 2010 Intel Corporation * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/init.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/pch_dma.h> #include "dmaengine.h" #define DRV_NAME "pch-dma" #define DMA_CTL0_DISABLE 0x0 #define DMA_CTL0_SG 0x1 #define DMA_CTL0_ONESHOT 0x2 #define DMA_CTL0_MODE_MASK_BITS 0x3 #define DMA_CTL0_DIR_SHIFT_BITS 2 #define DMA_CTL0_BITS_PER_CH 4 #define DMA_CTL2_START_SHIFT_BITS 8 #define DMA_CTL2_IRQ_ENABLE_MASK ((1UL << DMA_CTL2_START_SHIFT_BITS) - 1) #define DMA_STATUS_IDLE 0x0 #define DMA_STATUS_DESC_READ 0x1 #define DMA_STATUS_WAIT 0x2 #define DMA_STATUS_ACCESS 0x3 #define DMA_STATUS_BITS_PER_CH 2 #define DMA_STATUS_MASK_BITS 0x3 #define DMA_STATUS_SHIFT_BITS 16 #define DMA_STATUS_IRQ(x) (0x1 << (x)) #define DMA_STATUS0_ERR(x) (0x1 << ((x) + 8)) #define DMA_STATUS2_ERR(x) (0x1 << (x)) #define DMA_DESC_WIDTH_SHIFT_BITS 12 #define DMA_DESC_WIDTH_1_BYTE (0x3 << DMA_DESC_WIDTH_SHIFT_BITS) #define DMA_DESC_WIDTH_2_BYTES (0x2 << DMA_DESC_WIDTH_SHIFT_BITS) #define DMA_DESC_WIDTH_4_BYTES (0x0 << DMA_DESC_WIDTH_SHIFT_BITS) #define DMA_DESC_MAX_COUNT_1_BYTE 0x3FF #define DMA_DESC_MAX_COUNT_2_BYTES 0x3FF #define DMA_DESC_MAX_COUNT_4_BYTES 0x7FF #define DMA_DESC_END_WITHOUT_IRQ 0x0 #define DMA_DESC_END_WITH_IRQ 0x1 #define DMA_DESC_FOLLOW_WITHOUT_IRQ 0x2 #define DMA_DESC_FOLLOW_WITH_IRQ 0x3 #define MAX_CHAN_NR 12 #define DMA_MASK_CTL0_MODE 0x33333333 #define DMA_MASK_CTL2_MODE 0x00003333 static unsigned int init_nr_desc_per_channel = 64; module_param(init_nr_desc_per_channel, uint, 0644); MODULE_PARM_DESC(init_nr_desc_per_channel, "initial descriptors per channel (default: 64)"); struct pch_dma_desc_regs { u32 dev_addr; u32 mem_addr; u32 size; u32 next; }; struct pch_dma_regs { u32 dma_ctl0; u32 dma_ctl1; u32 dma_ctl2; u32 dma_ctl3; u32 dma_sts0; u32 dma_sts1; u32 dma_sts2; u32 reserved3; struct pch_dma_desc_regs desc[MAX_CHAN_NR]; }; struct pch_dma_desc { struct pch_dma_desc_regs regs; struct dma_async_tx_descriptor txd; struct list_head desc_node; struct list_head tx_list; }; struct pch_dma_chan { struct dma_chan chan; void __iomem *membase; enum dma_transfer_direction dir; struct tasklet_struct tasklet; unsigned long err_status; spinlock_t lock; struct list_head active_list; struct list_head queue; struct list_head free_list; unsigned int descs_allocated; }; #define PDC_DEV_ADDR 0x00 #define PDC_MEM_ADDR 0x04 #define PDC_SIZE 0x08 #define PDC_NEXT 0x0C #define channel_readl(pdc, name) \ readl((pdc)->membase + PDC_##name) #define channel_writel(pdc, name, val) \ writel((val), (pdc)->membase + PDC_##name) struct pch_dma { struct dma_device dma; void __iomem *membase; struct pci_pool *pool; struct pch_dma_regs regs; struct pch_dma_desc_regs ch_regs[MAX_CHAN_NR]; struct pch_dma_chan channels[MAX_CHAN_NR]; }; #define PCH_DMA_CTL0 0x00 #define PCH_DMA_CTL1 0x04 #define PCH_DMA_CTL2 0x08 #define PCH_DMA_CTL3 0x0C #define PCH_DMA_STS0 0x10 #define PCH_DMA_STS1 0x14 #define PCH_DMA_STS2 0x18 #define dma_readl(pd, name) \ readl((pd)->membase + PCH_DMA_##name) #define dma_writel(pd, name, val) \ writel((val), (pd)->membase + PCH_DMA_##name) static inline struct pch_dma_desc *to_pd_desc(struct dma_async_tx_descriptor *txd) { return container_of(txd, struct pch_dma_desc, txd); } static inline struct pch_dma_chan *to_pd_chan(struct dma_chan *chan) { return container_of(chan, struct pch_dma_chan, chan); } static inline struct pch_dma *to_pd(struct dma_device *ddev) { return container_of(ddev, struct pch_dma, dma); } static inline struct device *chan2dev(struct dma_chan *chan) { return &chan->dev->device; } static inline struct device *chan2parent(struct dma_chan *chan) { return chan->dev->device.parent; } static inline struct pch_dma_desc *pdc_first_active(struct pch_dma_chan *pd_chan) { return list_first_entry(&pd_chan->active_list, struct pch_dma_desc, desc_node); } static inline struct pch_dma_desc *pdc_first_queued(struct pch_dma_chan *pd_chan) { return list_first_entry(&pd_chan->queue, struct pch_dma_desc, desc_node); } static void pdc_enable_irq(struct dma_chan *chan, int enable) { struct pch_dma *pd = to_pd(chan->device); u32 val; int pos; if (chan->chan_id < 8) pos = chan->chan_id; else pos = chan->chan_id + 8; val = dma_readl(pd, CTL2); if (enable) val |= 0x1 << pos; else val &= ~(0x1 << pos); dma_writel(pd, CTL2, val); dev_dbg(chan2dev(chan), "pdc_enable_irq: chan %d -> %x\n", chan->chan_id, val); } static void pdc_set_dir(struct dma_chan *chan) { struct pch_dma_chan *pd_chan = to_pd_chan(chan); struct pch_dma *pd = to_pd(chan->device); u32 val; u32 mask_mode; u32 mask_ctl; if (chan->chan_id < 8) { val = dma_readl(pd, CTL0); mask_mode = DMA_CTL0_MODE_MASK_BITS << <style> @media only all and (prefers-color-scheme: dark) { .highlight .hll { background-color: #49483e } .highlight .c { color: #75715e } /* Comment */ .highlight .err { color: #960050; background-color: #1e0010 } /* Error */ .highlight .k { color: #66d9ef } /* Keyword */ .highlight .l { color: #ae81ff } /* Literal */ .highlight .n { color: #f8f8f2 } /* Name */ .highlight .o { color: #f92672 } /* Operator */ .highlight .p { color: #f8f8f2 } /* Punctuation */ .highlight .ch { color: #75715e } /* Comment.Hashbang */ .highlight .cm { color: #75715e } /* Comment.Multiline */ .highlight .cp { color: #75715e } /* Comment.Preproc */ .highlight .cpf { color: #75715e } /* Comment.PreprocFile */ .highlight .c1 { color: #75715e } /* Comment.Single */ .highlight .cs { color: #75715e } /* Comment.Special */ .highlight .gd { color: #f92672 } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gi { color: #a6e22e } /* Generic.Inserted */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #75715e } /* Generic.Subheading */ .highlight .kc { color: #66d9ef } /* Keyword.Constant */ .highlight .kd { color: #66d9ef } /* Keyword.Declaration */ .highlight .kn { color: #f92672 } /* Keyword.Namespace */ .highlight .kp { color: #66d9ef } /* Keyword.Pseudo */ .highlight .kr { color: #66d9ef } /* Keyword.Reserved */ .highlight .kt { color: #66d9ef } /* Keyword.Type */ .highlight .ld { color: #e6db74 } /* Literal.Date */ .highlight .m { color: #ae81ff } /* Literal.Number */ .highlight .s { color: #e6db74 } /* Literal.String */ .highlight .na { color: #a6e22e } /* Name.Attribute */ .highlight .nb { color: #f8f8f2 } /* Name.Builtin */ .highlight .nc { color: #a6e22e } /* Name.Class */ .highlight .no { color: #66d9ef } /* Name.Constant */ .highlight .nd { color: #a6e22e } /* Name.Decorator */ .highlight .ni { color: #f8f8f2 } /* Name.Entity */ .highlight .ne { color: #a6e22e } /* Name.Exception */ .highlight .nf { color: #a6e22e } /* Name.Function */ .highlight .nl { color: #f8f8f2 } /* Name.Label */ .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ .highlight .nx { color: #a6e22e } /* Name.Other */ .highlight .py { color: #f8f8f2 } /* Name.Property */ .highlight .nt { color: #f92672 } /* Name.Tag */ .highlight .nv { color: #f8f8f2 } /* Name.Variable */ .highlight .ow { color: #f92672 } /* Operator.Word */ .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ .highlight .sc { color: #e6db74 } /* Literal.String.Char */ .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ .highlight .se { color: #ae81ff } /* Literal.String.Escape */ .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ .highlight .sx { color: #e6db74 } /* Literal.String.Other */ .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ } </style><div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/env python</span> <span class="c1"># Copyright (c) 2017 Intel Corporation</span> <span class="c1">#</span> <span class="c1"># Licensed under the Apache License, Version 2.0 (the "License");</span> <span class="c1"># you may not use this file except in compliance with the License.</span> <span class="c1"># You may obtain a copy of the License at</span> <span class="c1">#</span> <span class="c1"># http://www.apache.org/licenses/LICENSE-2.0</span> <span class="c1">#</span> <span class="c1"># Unless required by applicable law or agreed to in writing, software</span> <span class="c1"># distributed under the License is distributed on an "AS IS" BASIS,</span> <span class="c1"># WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span> <span class="c1"># See the License for the specific language governing permissions and</span> <span class="c1"># limitations under the License.</span> <span class="n">DOCUMENTATION</span> <span class="o">=</span> <span class="s1">'''</span> <span class="s1">---</span> <span class="s1">module: write_string</span> <span class="s1">short_description: write a string to a file</span> <span class="s1">description:</span> <span class="s1"> - write a string to a file without using temp files</span> <span class="s1">options:</span> <span class="s1"> path: path to write to</span> <span class="s1"> val: string to write</span> <span class="s1"> mode: python file mode (w, wb, a, ab)</span> <span class="s1">'''</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span> <span class="n">module</span> <span class="o">=</span> <span class="n">AnsibleModule</span><span class="p">(</span> <span class="n">argument_spec</span><span class="o">=</span><span class="p">{</span> <span class="s1">'path'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'required'</span><span class="p">:</span> <span class="bp">True</span><span class="p">,</span> <span class="s1">'type'</span><span class="p">:</span> <span class="s1">'path'</span><span class="p">,</span> <span class="s1">'aliases'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'dest'</span><span class="p">]},</span> <span class="s1">'val'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'required'</span><span class="p">:</span> <span class="bp">True</span><span class="p">,</span> <span class="s1">'type'</span><span class="p">:</span> <span class="s1">'str'</span><span class="p">},</span> <span class="s1">'mode'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'required'</span><span class="p">:</span> <span class="bp">False</span><span class="p">,</span> <span class="s1">'default'</span><span class="p">:</span> <span class="s2">"w"</span><span class="p">,</span> <span class="s1">'type'</span><span class="p">:</span> <span class="s1">'str'</span><span class="p">,</span> <span class="s1">'choices'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'w'</span><span class="p">,</span> <span class="s1">'wb'</span><span class="p">,</span> <span class="s1">'a'</span><span class="p">,</span> <span class="s1">'ab'</span><span class="p">]}}</span> <span class="p">)</span> <span class="n">params</span> <span class="o">=</span> <span class="n">module</span><span class="o">.</span><span class="n">params</span> <span class="n">path</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">'path'</span><span class="p">]</span> <span class="n">mode</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">'mode'</span><span class="p">]</span> <span class="n">val</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">'val'</span><span class="p">]</span> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">mode</span><span class="p">)</span> <span class="k">as</span> <span class="n">file_object</span><span class="p">:</span> <span class="n">file_object</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">val</span><span class="p">)</span> <span class="n">module</span><span class="o">.</span><span class="n">exit_json</span><span class="p">(</span><span class="n">changed</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="c1"># <<INCLUDE_ANSIBLE_MODULE_COMMON>></span> <span class="kn">from</span> <span class="nn">ansible.module_utils.basic</span> <span class="kn">import</span> <span class="o">*</span> <span class="c1"># noqa</span> <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span> <span class="n">main</span><span class="p">()</span> </pre></div> </code></pre></td></tr></table> </div> <!-- class=content --> <div id="lfcollabprojects-footer"> <div class="gray-diagonal"> <div class="footer-inner"> <p> © 2015 <a href="https://opnfv.org/">Open Platform for NFV Project, Inc</a>., a Linux Foundation Collaborative Project. All Rights Reserved. </p> <p> Open Platform for NFV and OPNFV are trademarks of the Open Platform for NFV Project, Inc. </p> <p> Linux Foundation is a registered trademark of The Linux Foundation. Linux is a registered <a href="http://www.linuxfoundation.org/programs/legal/trademark" title="Linux Mark Institute" >trademark</a > of Linus Torvalds. </p> <p> Please see our <a href="https://opnfv.org/about/bylaws-and-policies/terms-use" >terms of use</a >, <a href="https://opnfv.org/about/bylaws-and-policies/trademarks" >trademark policy</a >, and <a href="https://opnfv.org/about/bylaws-and-policies/privacy-policy" >privacy policy</a >. </p> </div> </div> </div> </div> <!-- id=cgit --> </body> </html> const struct pci_device_id *id) { struct pch_dma *pd; struct pch_dma_regs *regs; unsigned int nr_channels; int err; int i; nr_channels = id->driver_data; pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) return -ENOMEM; pci_set_drvdata(pdev, pd); err = pci_enable_device(pdev); if (err) { dev_err(&pdev->dev, "Cannot enable PCI device\n"); goto err_free_mem; } if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { dev_err(&pdev->dev, "Cannot find proper base address\n"); err = -ENODEV; goto err_disable_pdev; } err = pci_request_regions(pdev, DRV_NAME); if (err) { dev_err(&pdev->dev, "Cannot obtain PCI resources\n"); goto err_disable_pdev; } err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { dev_err(&pdev->dev, "Cannot set proper DMA config\n"); goto err_free_res; } regs = pd->membase = pci_iomap(pdev, 1, 0); if (!pd->membase) { dev_err(&pdev->dev, "Cannot map MMIO registers\n"); err = -ENOMEM; goto err_free_res; } pci_set_master(pdev); err = request_irq(pdev->irq, pd_irq, IRQF_SHARED, DRV_NAME, pd); if (err) { dev_err(&pdev->dev, "Failed to request IRQ\n"); goto err_iounmap; } pd->pool = pci_pool_create("pch_dma_desc_pool", pdev, sizeof(struct pch_dma_desc), 4, 0); if (!pd->pool) { dev_err(&pdev->dev, "Failed to alloc DMA descriptors\n"); err = -ENOMEM; goto err_free_irq; } pd->dma.dev = &pdev->dev; INIT_LIST_HEAD(&pd->dma.channels); for (i = 0; i < nr_channels; i++) { struct pch_dma_chan *pd_chan = &pd->channels[i]; pd_chan->chan.device = &pd->dma; dma_cookie_init(&pd_chan->chan); pd_chan->membase = ®s->desc[i]; spin_lock_init(&pd_chan->lock); INIT_LIST_HEAD(&pd_chan->active_list); INIT_LIST_HEAD(&pd_chan->queue); INIT_LIST_HEAD(&pd_chan->free_list); tasklet_init(&pd_chan->tasklet, pdc_tasklet, (unsigned long)pd_chan); list_add_tail(&pd_chan->chan.device_node, &pd->dma.channels); } dma_cap_zero(pd->dma.cap_mask); dma_cap_set(DMA_PRIVATE, pd->dma.cap_mask); dma_cap_set(DMA_SLAVE, pd->dma.cap_mask); pd->dma.device_alloc_chan_resources = pd_alloc_chan_resources; pd->dma.device_free_chan_resources = pd_free_chan_resources; pd->dma.device_tx_status = pd_tx_status; pd->dma.device_issue_pending = pd_issue_pending; pd->dma.device_prep_slave_sg = pd_prep_slave_sg; pd->dma.device_terminate_all = pd_device_terminate_all; err = dma_async_device_register(&pd->dma); if (err) { dev_err(&pdev->dev, "Failed to register DMA device\n"); goto err_free_pool; } return 0; err_free_pool: pci_pool_destroy(pd->pool); err_free_irq: free_irq(pdev->irq, pd); err_iounmap: pci_iounmap(pdev, pd->membase); err_free_res: pci_release_regions(pdev); err_disable_pdev: pci_disable_device(pdev); err_free_mem: kfree(pd); return err; } static void pch_dma_remove(struct pci_dev *pdev) { struct pch_dma *pd = pci_get_drvdata(pdev); struct pch_dma_chan *pd_chan; struct dma_chan *chan, *_c; if (pd) { dma_async_device_unregister(&pd->dma); free_irq(pdev->irq, pd); list_for_each_entry_safe(chan, _c, &pd->dma.channels, device_node) { pd_chan = to_pd_chan(chan); tasklet_kill(&pd_chan->tasklet); } pci_pool_destroy(pd->pool); pci_iounmap(pdev, pd->membase); pci_release_regions(pdev); pci_disable_device(pdev); kfree(pd); } } /* PCI Device ID of DMA device */ #define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_DEVICE_ID_EG20T_PCH_DMA_8CH 0x8810 #define PCI_DEVICE_ID_EG20T_PCH_DMA_4CH 0x8815 #define PCI_DEVICE_ID_ML7213_DMA1_8CH 0x8026 #define PCI_DEVICE_ID_ML7213_DMA2_8CH 0x802B #define PCI_DEVICE_ID_ML7213_DMA3_4CH 0x8034 #define PCI_DEVICE_ID_ML7213_DMA4_12CH 0x8032 #define PCI_DEVICE_ID_ML7223_DMA1_4CH 0x800B #define PCI_DEVICE_ID_ML7223_DMA2_4CH 0x800E #define PCI_DEVICE_ID_ML7223_DMA3_4CH 0x8017 #define PCI_DEVICE_ID_ML7223_DMA4_4CH 0x803B #define PCI_DEVICE_ID_ML7831_DMA1_8CH 0x8810 #define PCI_DEVICE_ID_ML7831_DMA2_4CH 0x8815 static const struct pci_device_id pch_dma_id_table[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_8CH), 8 }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_4CH), 4 }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA1_8CH), 8}, /* UART Video */ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA2_8CH), 8}, /* PCMIF SPI */ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA3_4CH), 4}, /* FPGA */ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA4_12CH), 12}, /* I2S */ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA1_4CH), 4}, /* UART */ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA2_4CH), 4}, /* Video SPI */ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA3_4CH), 4}, /* Security */ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA4_4CH), 4}, /* FPGA */ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_DMA1_8CH), 8}, /* UART */ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_DMA2_4CH), 4}, /* SPI */ { 0, }, }; static struct pci_driver pch_dma_driver = { .name = DRV_NAME, .id_table = pch_dma_id_table, .probe = pch_dma_probe, .remove = pch_dma_remove, #ifdef CONFIG_PM .suspend = pch_dma_suspend, .resume = pch_dma_resume, #endif }; module_pci_driver(pch_dma_driver); MODULE_DESCRIPTION("Intel EG20T PCH / LAPIS Semicon ML7213/ML7223/ML7831 IOH " "DMA controller driver"); MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>"); MODULE_LICENSE("GPL v2"); MODULE_DEVICE_TABLE(pci, pch_dma_id_table);