~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/unicore32/kernel/dma.c

Version: ~ [ linux-5.3-rc5 ] ~ [ linux-5.2.9 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.67 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.139 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.189 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.189 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.72 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * linux/arch/unicore32/kernel/dma.c
  3  *
  4  * Code specific to PKUnity SoC and UniCore ISA
  5  *
  6  *      Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
  7  *      Copyright (C) 2001-2010 Guan Xuetao
  8  *
  9  * This program is free software; you can redistribute it and/or modify
 10  * it under the terms of the GNU General Public License version 2 as
 11  * published by the Free Software Foundation.
 12  */
 13 
 14 #include <linux/module.h>
 15 #include <linux/init.h>
 16 #include <linux/kernel.h>
 17 #include <linux/interrupt.h>
 18 #include <linux/errno.h>
 19 #include <linux/io.h>
 20 
 21 #include <asm/irq.h>
 22 #include <mach/hardware.h>
 23 #include <mach/dma.h>
 24 
 25 struct dma_channel {
 26         char *name;
 27         puv3_dma_prio prio;
 28         void (*irq_handler)(int, void *);
 29         void (*err_handler)(int, void *);
 30         void *data;
 31 };
 32 
 33 static struct dma_channel dma_channels[MAX_DMA_CHANNELS];
 34 
 35 int puv3_request_dma(char *name, puv3_dma_prio prio,
 36                          void (*irq_handler)(int, void *),
 37                          void (*err_handler)(int, void *),
 38                          void *data)
 39 {
 40         unsigned long flags;
 41         int i, found = 0;
 42 
 43         /* basic sanity checks */
 44         if (!name)
 45                 return -EINVAL;
 46 
 47         local_irq_save(flags);
 48 
 49         do {
 50                 /* try grabbing a DMA channel with the requested priority */
 51                 for (i = 0; i < MAX_DMA_CHANNELS; i++) {
 52                         if ((dma_channels[i].prio == prio) &&
 53                             !dma_channels[i].name) {
 54                                 found = 1;
 55                                 break;
 56                         }
 57                 }
 58                 /* if requested prio group is full, try a hier priority */
 59         } while (!found && prio--);
 60 
 61         if (found) {
 62                 dma_channels[i].name = name;
 63                 dma_channels[i].irq_handler = irq_handler;
 64                 dma_channels[i].err_handler = err_handler;
 65                 dma_channels[i].data = data;
 66         } else {
 67                 printk(KERN_WARNING "No more available DMA channels for %s\n",
 68                                 name);
 69                 i = -ENODEV;
 70         }
 71 
 72         local_irq_restore(flags);
 73         return i;
 74 }
 75 EXPORT_SYMBOL(puv3_request_dma);
 76 
 77 void puv3_free_dma(int dma_ch)
 78 {
 79         unsigned long flags;
 80 
 81         if (!dma_channels[dma_ch].name) {
 82                 printk(KERN_CRIT
 83                         "%s: trying to free channel %d which is already freed\n",
 84                         __func__, dma_ch);
 85                 return;
 86         }
 87 
 88         local_irq_save(flags);
 89         dma_channels[dma_ch].name = NULL;
 90         dma_channels[dma_ch].err_handler = NULL;
 91         local_irq_restore(flags);
 92 }
 93 EXPORT_SYMBOL(puv3_free_dma);
 94 
 95 static irqreturn_t dma_irq_handler(int irq, void *dev_id)
 96 {
 97         int i, dint;
 98 
 99         dint = readl(DMAC_ITCSR);
100         for (i = 0; i < MAX_DMA_CHANNELS; i++) {
101                 if (dint & DMAC_CHANNEL(i)) {
102                         struct dma_channel *channel = &dma_channels[i];
103 
104                         /* Clear TC interrupt of channel i */
105                         writel(DMAC_CHANNEL(i), DMAC_ITCCR);
106                         writel(0, DMAC_ITCCR);
107 
108                         if (channel->name && channel->irq_handler) {
109                                 channel->irq_handler(i, channel->data);
110                         } else {
111                                 /*
112                                  * IRQ for an unregistered DMA channel:
113                                  * let's clear the interrupts and disable it.
114                                  */
115                                 printk(KERN_WARNING "spurious IRQ for"
116                                                 " DMA channel %d\n", i);
117                         }
118                 }
119         }
120         return IRQ_HANDLED;
121 }
122 
123 static irqreturn_t dma_err_handler(int irq, void *dev_id)
124 {
125         int i, dint;
126 
127         dint = readl(DMAC_IESR);
128         for (i = 0; i < MAX_DMA_CHANNELS; i++) {
129                 if (dint & DMAC_CHANNEL(i)) {
130                         struct dma_channel *channel = &dma_channels[i];
131 
132                         /* Clear Err interrupt of channel i */
133                         writel(DMAC_CHANNEL(i), DMAC_IECR);
134                         writel(0, DMAC_IECR);
135 
136                         if (channel->name && channel->err_handler) {
137                                 channel->err_handler(i, channel->data);
138                         } else {
139                                 /*
140                                  * IRQ for an unregistered DMA channel:
141                                  * let's clear the interrupts and disable it.
142                                  */
143                                 printk(KERN_WARNING "spurious IRQ for"
144                                                 " DMA channel %d\n", i);
145                         }
146                 }
147         }
148         return IRQ_HANDLED;
149 }
150 
151 int __init puv3_init_dma(void)
152 {
153         int i, ret;
154 
155         /* dma channel priorities on v8 processors:
156          * ch 0 - 1  <--> (0) DMA_PRIO_HIGH
157          * ch 2 - 3  <--> (1) DMA_PRIO_MEDIUM
158          * ch 4 - 5  <--> (2) DMA_PRIO_LOW
159          */
160         for (i = 0; i < MAX_DMA_CHANNELS; i++) {
161                 puv3_stop_dma(i);
162                 dma_channels[i].name = NULL;
163                 dma_channels[i].prio = min((i & 0x7) >> 1, DMA_PRIO_LOW);
164         }
165 
166         ret = request_irq(IRQ_DMA, dma_irq_handler, 0, "DMA", NULL);
167         if (ret) {
168                 printk(KERN_CRIT "Can't register IRQ for DMA\n");
169                 return ret;
170         }
171 
172         ret = request_irq(IRQ_DMAERR, dma_err_handler, 0, "DMAERR", NULL);
173         if (ret) {
174                 printk(KERN_CRIT "Can't register IRQ for DMAERR\n");
175                 free_irq(IRQ_DMA, "DMA");
176                 return ret;
177         }
178 
179         return 0;
180 }
181 
182 postcore_initcall(puv3_init_dma);
183 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp