Loading arch/arm/include/asm/dma.h +21 −25 Original line number Diff line number Diff line Loading @@ -19,21 +19,17 @@ #include <asm/system.h> #include <asm/scatterlist.h> typedef unsigned int dmach_t; #include <mach/isa-dma.h> /* * DMA modes * The DMA modes reflect the settings for the ISA DMA controller */ typedef unsigned int dmamode_t; #define DMA_MODE_MASK 3 #define DMA_MODE_MASK 0xcc #define DMA_MODE_READ 0 #define DMA_MODE_WRITE 1 #define DMA_MODE_CASCADE 2 #define DMA_AUTOINIT 4 #define DMA_MODE_READ 0x44 #define DMA_MODE_WRITE 0x48 #define DMA_MODE_CASCADE 0xc0 #define DMA_AUTOINIT 0x10 extern spinlock_t dma_spin_lock; Loading @@ -52,44 +48,44 @@ static inline void release_dma_lock(unsigned long flags) /* Clear the 'DMA Pointer Flip Flop'. * Write 0 for LSB/MSB, 1 for MSB/LSB access. */ #define clear_dma_ff(channel) #define clear_dma_ff(chan) /* Set only the page register bits of the transfer address. * * NOTE: This is an architecture specific function, and should * be hidden from the drivers */ extern void set_dma_page(dmach_t channel, char pagenr); extern void set_dma_page(unsigned int chan, char pagenr); /* Request a DMA channel * * Some architectures may need to do allocate an interrupt */ extern int request_dma(dmach_t channel, const char * device_id); extern int request_dma(unsigned int chan, const char * device_id); /* Free a DMA channel * * Some architectures may need to do free an interrupt */ extern void free_dma(dmach_t channel); extern void free_dma(unsigned int chan); /* Enable DMA for this channel * * On some architectures, this may have other side effects like * enabling an interrupt and setting the DMA registers. */ extern void enable_dma(dmach_t channel); extern void enable_dma(unsigned int chan); /* Disable DMA for this channel * * On some architectures, this may have other side effects like * disabling an interrupt or whatever. */ extern void disable_dma(dmach_t channel); extern void disable_dma(unsigned int chan); /* Test whether the specified channel has an active DMA transfer */ extern int dma_channel_active(dmach_t channel); extern int dma_channel_active(unsigned int chan); /* Set the DMA scatter gather list for this channel * Loading @@ -97,7 +93,7 @@ extern int dma_channel_active(dmach_t channel); * especially since some DMA architectures don't update the * DMA address immediately, but defer it to the enable_dma(). */ extern void set_dma_sg(dmach_t channel, struct scatterlist *sg, int nr_sg); extern void set_dma_sg(unsigned int chan, struct scatterlist *sg, int nr_sg); /* Set the DMA address for this channel * Loading @@ -105,9 +101,9 @@ extern void set_dma_sg(dmach_t channel, struct scatterlist *sg, int nr_sg); * especially since some DMA architectures don't update the * DMA address immediately, but defer it to the enable_dma(). */ extern void __set_dma_addr(dmach_t channel, void *addr); #define set_dma_addr(channel, addr) \ __set_dma_addr(channel, bus_to_virt(addr)) extern void __set_dma_addr(unsigned int chan, void *addr); #define set_dma_addr(chan, addr) \ __set_dma_addr(chan, bus_to_virt(addr)) /* Set the DMA byte count for this channel * Loading @@ -115,7 +111,7 @@ extern void __set_dma_addr(dmach_t channel, void *addr); * especially since some DMA architectures don't update the * DMA count immediately, but defer it to the enable_dma(). */ extern void set_dma_count(dmach_t channel, unsigned long count); extern void set_dma_count(unsigned int chan, unsigned long count); /* Set the transfer direction for this channel * Loading @@ -124,11 +120,11 @@ extern void set_dma_count(dmach_t channel, unsigned long count); * DMA transfer direction immediately, but defer it to the * enable_dma(). */ extern void set_dma_mode(dmach_t channel, dmamode_t mode); extern void set_dma_mode(unsigned int chan, unsigned int mode); /* Set the transfer speed for this channel */ extern void set_dma_speed(dmach_t channel, int cycle_ns); extern void set_dma_speed(unsigned int chan, int cycle_ns); /* Get DMA residue count. After a DMA transfer, this * should return zero. Reading this while a DMA transfer is Loading @@ -136,7 +132,7 @@ extern void set_dma_speed(dmach_t channel, int cycle_ns); * If called before the channel has been used, it may return 1. * Otherwise, it returns the number of _bytes_ left to transfer. */ extern int get_dma_residue(dmach_t channel); extern int get_dma_residue(unsigned int chan); #ifndef NO_DMA #define NO_DMA 255 Loading arch/arm/include/asm/mach/dma.h +16 −19 Original line number Diff line number Diff line Loading @@ -15,13 +15,13 @@ struct dma_struct; typedef struct dma_struct dma_t; struct dma_ops { int (*request)(dmach_t, dma_t *); /* optional */ void (*free)(dmach_t, dma_t *); /* optional */ void (*enable)(dmach_t, dma_t *); /* mandatory */ void (*disable)(dmach_t, dma_t *); /* mandatory */ int (*residue)(dmach_t, dma_t *); /* optional */ int (*setspeed)(dmach_t, dma_t *, int); /* optional */ char *type; int (*request)(unsigned int, dma_t *); /* optional */ void (*free)(unsigned int, dma_t *); /* optional */ void (*enable)(unsigned int, dma_t *); /* mandatory */ void (*disable)(unsigned int, dma_t *); /* mandatory */ int (*residue)(unsigned int, dma_t *); /* optional */ int (*setspeed)(unsigned int, dma_t *, int); /* optional */ const char *type; }; struct dma_struct { Loading @@ -34,24 +34,21 @@ struct dma_struct { unsigned int active:1; /* Transfer active */ unsigned int invalid:1; /* Address/Count changed */ dmamode_t dma_mode; /* DMA mode */ unsigned int dma_mode; /* DMA mode */ int speed; /* DMA speed */ unsigned int lock; /* Device is allocated */ const char *device_id; /* Device name */ unsigned int dma_base; /* Controller base address */ int dma_irq; /* Controller IRQ */ struct scatterlist cur_sg; /* Current controller buffer */ unsigned int state; struct dma_ops *d_ops; const struct dma_ops *d_ops; }; /* Prototype: void arch_dma_init(dma) * Purpose : Initialise architecture specific DMA * Params : dma - pointer to array of DMA structures /* * isa_dma_add - add an ISA-style DMA channel */ extern void arch_dma_init(dma_t *dma); extern int isa_dma_add(unsigned int, dma_t *dma); extern void isa_init_dma(dma_t *dma); /* * Add the ISA DMA controller. Always takes channels 0-7. */ extern void isa_init_dma(void); arch/arm/kernel/dma-isa.c +34 −33 Original line number Diff line number Diff line Loading @@ -24,11 +24,6 @@ #include <asm/dma.h> #include <asm/mach/dma.h> #define ISA_DMA_MODE_READ 0x44 #define ISA_DMA_MODE_WRITE 0x48 #define ISA_DMA_MODE_CASCADE 0xc0 #define ISA_DMA_AUTOINIT 0x10 #define ISA_DMA_MASK 0 #define ISA_DMA_MODE 1 #define ISA_DMA_CLRFF 2 Loading @@ -49,38 +44,35 @@ static unsigned int isa_dma_port[8][7] = { { 0xd4, 0xd6, 0xd8, 0x48a, 0x08a, 0xcc, 0xce } }; static int isa_get_dma_residue(dmach_t channel, dma_t *dma) static int isa_get_dma_residue(unsigned int chan, dma_t *dma) { unsigned int io_port = isa_dma_port[channel][ISA_DMA_COUNT]; unsigned int io_port = isa_dma_port[chan][ISA_DMA_COUNT]; int count; count = 1 + inb(io_port); count |= inb(io_port) << 8; return channel < 4 ? count : (count << 1); return chan < 4 ? count : (count << 1); } static void isa_enable_dma(dmach_t channel, dma_t *dma) static void isa_enable_dma(unsigned int chan, dma_t *dma) { if (dma->invalid) { unsigned long address, length; unsigned int mode; enum dma_data_direction direction; mode = channel & 3; mode = (chan & 3) | dma->dma_mode; switch (dma->dma_mode & DMA_MODE_MASK) { case DMA_MODE_READ: mode |= ISA_DMA_MODE_READ; direction = DMA_FROM_DEVICE; break; case DMA_MODE_WRITE: mode |= ISA_DMA_MODE_WRITE; direction = DMA_TO_DEVICE; break; case DMA_MODE_CASCADE: mode |= ISA_DMA_MODE_CASCADE; direction = DMA_BIDIRECTIONAL; break; Loading @@ -105,34 +97,31 @@ static void isa_enable_dma(dmach_t channel, dma_t *dma) address = dma->buf.dma_address; length = dma->buf.length - 1; outb(address >> 16, isa_dma_port[channel][ISA_DMA_PGLO]); outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]); outb(address >> 16, isa_dma_port[chan][ISA_DMA_PGLO]); outb(address >> 24, isa_dma_port[chan][ISA_DMA_PGHI]); if (channel >= 4) { if (chan >= 4) { address >>= 1; length >>= 1; } outb(0, isa_dma_port[channel][ISA_DMA_CLRFF]); outb(address, isa_dma_port[channel][ISA_DMA_ADDR]); outb(address >> 8, isa_dma_port[channel][ISA_DMA_ADDR]); outb(0, isa_dma_port[chan][ISA_DMA_CLRFF]); outb(length, isa_dma_port[channel][ISA_DMA_COUNT]); outb(length >> 8, isa_dma_port[channel][ISA_DMA_COUNT]); outb(address, isa_dma_port[chan][ISA_DMA_ADDR]); outb(address >> 8, isa_dma_port[chan][ISA_DMA_ADDR]); if (dma->dma_mode & DMA_AUTOINIT) mode |= ISA_DMA_AUTOINIT; outb(length, isa_dma_port[chan][ISA_DMA_COUNT]); outb(length >> 8, isa_dma_port[chan][ISA_DMA_COUNT]); outb(mode, isa_dma_port[channel][ISA_DMA_MODE]); outb(mode, isa_dma_port[chan][ISA_DMA_MODE]); dma->invalid = 0; } outb(channel & 3, isa_dma_port[channel][ISA_DMA_MASK]); outb(chan & 3, isa_dma_port[chan][ISA_DMA_MASK]); } static void isa_disable_dma(dmach_t channel, dma_t *dma) static void isa_disable_dma(unsigned int chan, dma_t *dma) { outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]); outb(chan | 4, isa_dma_port[chan][ISA_DMA_MASK]); } static struct dma_ops isa_dma_ops = { Loading Loading @@ -160,7 +149,12 @@ static struct resource dma_resources[] = { { .end = 0x048f } }; void __init isa_init_dma(dma_t *dma) static dma_t isa_dma[8]; /* * ISA DMA always starts at channel 0 */ void __init isa_init_dma(void) { /* * Try to autodetect presence of an ISA DMA controller. Loading @@ -178,11 +172,11 @@ void __init isa_init_dma(dma_t *dma) outb(0xaa, 0x00); if (inb(0) == 0x55 && inb(0) == 0xaa) { int channel, i; unsigned int chan, i; for (channel = 0; channel < 8; channel++) { dma[channel].d_ops = &isa_dma_ops; isa_disable_dma(channel, NULL); for (chan = 0; chan < 8; chan++) { isa_dma[chan].d_ops = &isa_dma_ops; isa_disable_dma(chan, NULL); } outb(0x40, 0x0b); Loading Loading @@ -217,5 +211,12 @@ void __init isa_init_dma(dma_t *dma) for (i = 0; i < ARRAY_SIZE(dma_resources); i++) request_resource(&ioport_resource, dma_resources + i); for (chan = 0; chan < 8; chan++) { int ret = isa_dma_add(chan, &isa_dma[chan]); if (ret) printk(KERN_ERR "ISADMA%u: unable to register: %d\n", chan, ret); } } } arch/arm/kernel/dma.c +67 −52 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/spinlock.h> #include <linux/errno.h> #include <linux/scatterlist.h> #include <asm/dma.h> Loading @@ -23,19 +24,40 @@ DEFINE_SPINLOCK(dma_spin_lock); EXPORT_SYMBOL(dma_spin_lock); static dma_t dma_chan[MAX_DMA_CHANNELS]; static dma_t *dma_chan[MAX_DMA_CHANNELS]; static inline dma_t *dma_channel(unsigned int chan) { if (chan >= MAX_DMA_CHANNELS) return NULL; return dma_chan[chan]; } int __init isa_dma_add(unsigned int chan, dma_t *dma) { if (!dma->d_ops) return -EINVAL; sg_init_table(&dma->buf, 1); if (dma_chan[chan]) return -EBUSY; dma_chan[chan] = dma; return 0; } /* * Request DMA channel * * On certain platforms, we have to allocate an interrupt as well... */ int request_dma(dmach_t channel, const char *device_id) int request_dma(unsigned int chan, const char *device_id) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); int ret; if (channel >= MAX_DMA_CHANNELS || !dma->d_ops) if (!dma) goto bad_dma; if (xchg(&dma->lock, 1) != 0) Loading @@ -47,7 +69,7 @@ int request_dma(dmach_t channel, const char *device_id) ret = 0; if (dma->d_ops->request) ret = dma->d_ops->request(channel, dma); ret = dma->d_ops->request(chan, dma); if (ret) xchg(&dma->lock, 0); Loading @@ -55,7 +77,7 @@ int request_dma(dmach_t channel, const char *device_id) return ret; bad_dma: printk(KERN_ERR "dma: trying to allocate DMA%d\n", channel); printk(KERN_ERR "dma: trying to allocate DMA%d\n", chan); return -EINVAL; busy: Loading @@ -68,42 +90,42 @@ EXPORT_SYMBOL(request_dma); * * On certain platforms, we have to free interrupt as well... */ void free_dma(dmach_t channel) void free_dma(unsigned int chan) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (channel >= MAX_DMA_CHANNELS || !dma->d_ops) if (!dma) goto bad_dma; if (dma->active) { printk(KERN_ERR "dma%d: freeing active DMA\n", channel); dma->d_ops->disable(channel, dma); printk(KERN_ERR "dma%d: freeing active DMA\n", chan); dma->d_ops->disable(chan, dma); dma->active = 0; } if (xchg(&dma->lock, 0) != 0) { if (dma->d_ops->free) dma->d_ops->free(channel, dma); dma->d_ops->free(chan, dma); return; } printk(KERN_ERR "dma%d: trying to free free DMA\n", channel); printk(KERN_ERR "dma%d: trying to free free DMA\n", chan); return; bad_dma: printk(KERN_ERR "dma: trying to free DMA%d\n", channel); printk(KERN_ERR "dma: trying to free DMA%d\n", chan); } EXPORT_SYMBOL(free_dma); /* Set DMA Scatter-Gather list */ void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg) void set_dma_sg (unsigned int chan, struct scatterlist *sg, int nr_sg) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (dma->active) printk(KERN_ERR "dma%d: altering DMA SG while " "DMA active\n", channel); "DMA active\n", chan); dma->sg = sg; dma->sgcount = nr_sg; Loading @@ -115,13 +137,13 @@ EXPORT_SYMBOL(set_dma_sg); * * Copy address to the structure, and set the invalid bit */ void __set_dma_addr (dmach_t channel, void *addr) void __set_dma_addr (unsigned int chan, void *addr) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (dma->active) printk(KERN_ERR "dma%d: altering DMA address while " "DMA active\n", channel); "DMA active\n", chan); dma->sg = NULL; dma->addr = addr; Loading @@ -133,13 +155,13 @@ EXPORT_SYMBOL(__set_dma_addr); * * Copy address to the structure, and set the invalid bit */ void set_dma_count (dmach_t channel, unsigned long count) void set_dma_count (unsigned int chan, unsigned long count) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (dma->active) printk(KERN_ERR "dma%d: altering DMA count while " "DMA active\n", channel); "DMA active\n", chan); dma->sg = NULL; dma->count = count; Loading @@ -149,13 +171,13 @@ EXPORT_SYMBOL(set_dma_count); /* Set DMA direction mode */ void set_dma_mode (dmach_t channel, dmamode_t mode) void set_dma_mode (unsigned int chan, unsigned int mode) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (dma->active) printk(KERN_ERR "dma%d: altering DMA mode while " "DMA active\n", channel); "DMA active\n", chan); dma->dma_mode = mode; dma->invalid = 1; Loading @@ -164,42 +186,42 @@ EXPORT_SYMBOL(set_dma_mode); /* Enable DMA channel */ void enable_dma (dmach_t channel) void enable_dma (unsigned int chan) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (!dma->lock) goto free_dma; if (dma->active == 0) { dma->active = 1; dma->d_ops->enable(channel, dma); dma->d_ops->enable(chan, dma); } return; free_dma: printk(KERN_ERR "dma%d: trying to enable free DMA\n", channel); printk(KERN_ERR "dma%d: trying to enable free DMA\n", chan); BUG(); } EXPORT_SYMBOL(enable_dma); /* Disable DMA channel */ void disable_dma (dmach_t channel) void disable_dma (unsigned int chan) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (!dma->lock) goto free_dma; if (dma->active == 1) { dma->active = 0; dma->d_ops->disable(channel, dma); dma->d_ops->disable(chan, dma); } return; free_dma: printk(KERN_ERR "dma%d: trying to disable free DMA\n", channel); printk(KERN_ERR "dma%d: trying to disable free DMA\n", chan); BUG(); } EXPORT_SYMBOL(disable_dma); Loading @@ -207,45 +229,38 @@ EXPORT_SYMBOL(disable_dma); /* * Is the specified DMA channel active? */ int dma_channel_active(dmach_t channel) int dma_channel_active(unsigned int chan) { return dma_chan[channel].active; dma_t *dma = dma_channel(chan); return dma->active; } EXPORT_SYMBOL(dma_channel_active); void set_dma_page(dmach_t channel, char pagenr) void set_dma_page(unsigned int chan, char pagenr) { printk(KERN_ERR "dma%d: trying to set_dma_page\n", channel); printk(KERN_ERR "dma%d: trying to set_dma_page\n", chan); } EXPORT_SYMBOL(set_dma_page); void set_dma_speed(dmach_t channel, int cycle_ns) void set_dma_speed(unsigned int chan, int cycle_ns) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); int ret = 0; if (dma->d_ops->setspeed) ret = dma->d_ops->setspeed(channel, dma, cycle_ns); ret = dma->d_ops->setspeed(chan, dma, cycle_ns); dma->speed = ret; } EXPORT_SYMBOL(set_dma_speed); int get_dma_residue(dmach_t channel) int get_dma_residue(unsigned int chan) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); int ret = 0; if (dma->d_ops->residue) ret = dma->d_ops->residue(channel, dma); ret = dma->d_ops->residue(chan, dma); return ret; } EXPORT_SYMBOL(get_dma_residue); static int __init init_dma(void) { arch_dma_init(dma_chan); return 0; } core_initcall(init_dma); arch/arm/mach-footbridge/dma.c +7 −5 Original line number Diff line number Diff line Loading @@ -21,16 +21,16 @@ #include <asm/hardware/dec21285.h> #if 0 static int fb_dma_request(dmach_t channel, dma_t *dma) static int fb_dma_request(unsigned int chan, dma_t *dma) { return -EINVAL; } static void fb_dma_enable(dmach_t channel, dma_t *dma) static void fb_dma_enable(unsigned int chan, dma_t *dma) { } static void fb_dma_disable(dmach_t channel, dma_t *dma) static void fb_dma_disable(unsigned int chan, dma_t *dma) { } Loading @@ -42,7 +42,7 @@ static struct dma_ops fb_dma_ops = { }; #endif void __init arch_dma_init(dma_t *dma) static int __init fb_dma_init(void) { #if 0 dma[_DC21285_DMA(0)].d_ops = &fb_dma_ops; Loading @@ -50,6 +50,8 @@ void __init arch_dma_init(dma_t *dma) #endif #ifdef CONFIG_ISA_DMA if (footbridge_cfn_mode()) isa_init_dma(dma + _ISA_DMA(0)); isa_init_dma(); #endif return 0; } core_initcall(fb_dma_init); Loading
arch/arm/include/asm/dma.h +21 −25 Original line number Diff line number Diff line Loading @@ -19,21 +19,17 @@ #include <asm/system.h> #include <asm/scatterlist.h> typedef unsigned int dmach_t; #include <mach/isa-dma.h> /* * DMA modes * The DMA modes reflect the settings for the ISA DMA controller */ typedef unsigned int dmamode_t; #define DMA_MODE_MASK 3 #define DMA_MODE_MASK 0xcc #define DMA_MODE_READ 0 #define DMA_MODE_WRITE 1 #define DMA_MODE_CASCADE 2 #define DMA_AUTOINIT 4 #define DMA_MODE_READ 0x44 #define DMA_MODE_WRITE 0x48 #define DMA_MODE_CASCADE 0xc0 #define DMA_AUTOINIT 0x10 extern spinlock_t dma_spin_lock; Loading @@ -52,44 +48,44 @@ static inline void release_dma_lock(unsigned long flags) /* Clear the 'DMA Pointer Flip Flop'. * Write 0 for LSB/MSB, 1 for MSB/LSB access. */ #define clear_dma_ff(channel) #define clear_dma_ff(chan) /* Set only the page register bits of the transfer address. * * NOTE: This is an architecture specific function, and should * be hidden from the drivers */ extern void set_dma_page(dmach_t channel, char pagenr); extern void set_dma_page(unsigned int chan, char pagenr); /* Request a DMA channel * * Some architectures may need to do allocate an interrupt */ extern int request_dma(dmach_t channel, const char * device_id); extern int request_dma(unsigned int chan, const char * device_id); /* Free a DMA channel * * Some architectures may need to do free an interrupt */ extern void free_dma(dmach_t channel); extern void free_dma(unsigned int chan); /* Enable DMA for this channel * * On some architectures, this may have other side effects like * enabling an interrupt and setting the DMA registers. */ extern void enable_dma(dmach_t channel); extern void enable_dma(unsigned int chan); /* Disable DMA for this channel * * On some architectures, this may have other side effects like * disabling an interrupt or whatever. */ extern void disable_dma(dmach_t channel); extern void disable_dma(unsigned int chan); /* Test whether the specified channel has an active DMA transfer */ extern int dma_channel_active(dmach_t channel); extern int dma_channel_active(unsigned int chan); /* Set the DMA scatter gather list for this channel * Loading @@ -97,7 +93,7 @@ extern int dma_channel_active(dmach_t channel); * especially since some DMA architectures don't update the * DMA address immediately, but defer it to the enable_dma(). */ extern void set_dma_sg(dmach_t channel, struct scatterlist *sg, int nr_sg); extern void set_dma_sg(unsigned int chan, struct scatterlist *sg, int nr_sg); /* Set the DMA address for this channel * Loading @@ -105,9 +101,9 @@ extern void set_dma_sg(dmach_t channel, struct scatterlist *sg, int nr_sg); * especially since some DMA architectures don't update the * DMA address immediately, but defer it to the enable_dma(). */ extern void __set_dma_addr(dmach_t channel, void *addr); #define set_dma_addr(channel, addr) \ __set_dma_addr(channel, bus_to_virt(addr)) extern void __set_dma_addr(unsigned int chan, void *addr); #define set_dma_addr(chan, addr) \ __set_dma_addr(chan, bus_to_virt(addr)) /* Set the DMA byte count for this channel * Loading @@ -115,7 +111,7 @@ extern void __set_dma_addr(dmach_t channel, void *addr); * especially since some DMA architectures don't update the * DMA count immediately, but defer it to the enable_dma(). */ extern void set_dma_count(dmach_t channel, unsigned long count); extern void set_dma_count(unsigned int chan, unsigned long count); /* Set the transfer direction for this channel * Loading @@ -124,11 +120,11 @@ extern void set_dma_count(dmach_t channel, unsigned long count); * DMA transfer direction immediately, but defer it to the * enable_dma(). */ extern void set_dma_mode(dmach_t channel, dmamode_t mode); extern void set_dma_mode(unsigned int chan, unsigned int mode); /* Set the transfer speed for this channel */ extern void set_dma_speed(dmach_t channel, int cycle_ns); extern void set_dma_speed(unsigned int chan, int cycle_ns); /* Get DMA residue count. After a DMA transfer, this * should return zero. Reading this while a DMA transfer is Loading @@ -136,7 +132,7 @@ extern void set_dma_speed(dmach_t channel, int cycle_ns); * If called before the channel has been used, it may return 1. * Otherwise, it returns the number of _bytes_ left to transfer. */ extern int get_dma_residue(dmach_t channel); extern int get_dma_residue(unsigned int chan); #ifndef NO_DMA #define NO_DMA 255 Loading
arch/arm/include/asm/mach/dma.h +16 −19 Original line number Diff line number Diff line Loading @@ -15,13 +15,13 @@ struct dma_struct; typedef struct dma_struct dma_t; struct dma_ops { int (*request)(dmach_t, dma_t *); /* optional */ void (*free)(dmach_t, dma_t *); /* optional */ void (*enable)(dmach_t, dma_t *); /* mandatory */ void (*disable)(dmach_t, dma_t *); /* mandatory */ int (*residue)(dmach_t, dma_t *); /* optional */ int (*setspeed)(dmach_t, dma_t *, int); /* optional */ char *type; int (*request)(unsigned int, dma_t *); /* optional */ void (*free)(unsigned int, dma_t *); /* optional */ void (*enable)(unsigned int, dma_t *); /* mandatory */ void (*disable)(unsigned int, dma_t *); /* mandatory */ int (*residue)(unsigned int, dma_t *); /* optional */ int (*setspeed)(unsigned int, dma_t *, int); /* optional */ const char *type; }; struct dma_struct { Loading @@ -34,24 +34,21 @@ struct dma_struct { unsigned int active:1; /* Transfer active */ unsigned int invalid:1; /* Address/Count changed */ dmamode_t dma_mode; /* DMA mode */ unsigned int dma_mode; /* DMA mode */ int speed; /* DMA speed */ unsigned int lock; /* Device is allocated */ const char *device_id; /* Device name */ unsigned int dma_base; /* Controller base address */ int dma_irq; /* Controller IRQ */ struct scatterlist cur_sg; /* Current controller buffer */ unsigned int state; struct dma_ops *d_ops; const struct dma_ops *d_ops; }; /* Prototype: void arch_dma_init(dma) * Purpose : Initialise architecture specific DMA * Params : dma - pointer to array of DMA structures /* * isa_dma_add - add an ISA-style DMA channel */ extern void arch_dma_init(dma_t *dma); extern int isa_dma_add(unsigned int, dma_t *dma); extern void isa_init_dma(dma_t *dma); /* * Add the ISA DMA controller. Always takes channels 0-7. */ extern void isa_init_dma(void);
arch/arm/kernel/dma-isa.c +34 −33 Original line number Diff line number Diff line Loading @@ -24,11 +24,6 @@ #include <asm/dma.h> #include <asm/mach/dma.h> #define ISA_DMA_MODE_READ 0x44 #define ISA_DMA_MODE_WRITE 0x48 #define ISA_DMA_MODE_CASCADE 0xc0 #define ISA_DMA_AUTOINIT 0x10 #define ISA_DMA_MASK 0 #define ISA_DMA_MODE 1 #define ISA_DMA_CLRFF 2 Loading @@ -49,38 +44,35 @@ static unsigned int isa_dma_port[8][7] = { { 0xd4, 0xd6, 0xd8, 0x48a, 0x08a, 0xcc, 0xce } }; static int isa_get_dma_residue(dmach_t channel, dma_t *dma) static int isa_get_dma_residue(unsigned int chan, dma_t *dma) { unsigned int io_port = isa_dma_port[channel][ISA_DMA_COUNT]; unsigned int io_port = isa_dma_port[chan][ISA_DMA_COUNT]; int count; count = 1 + inb(io_port); count |= inb(io_port) << 8; return channel < 4 ? count : (count << 1); return chan < 4 ? count : (count << 1); } static void isa_enable_dma(dmach_t channel, dma_t *dma) static void isa_enable_dma(unsigned int chan, dma_t *dma) { if (dma->invalid) { unsigned long address, length; unsigned int mode; enum dma_data_direction direction; mode = channel & 3; mode = (chan & 3) | dma->dma_mode; switch (dma->dma_mode & DMA_MODE_MASK) { case DMA_MODE_READ: mode |= ISA_DMA_MODE_READ; direction = DMA_FROM_DEVICE; break; case DMA_MODE_WRITE: mode |= ISA_DMA_MODE_WRITE; direction = DMA_TO_DEVICE; break; case DMA_MODE_CASCADE: mode |= ISA_DMA_MODE_CASCADE; direction = DMA_BIDIRECTIONAL; break; Loading @@ -105,34 +97,31 @@ static void isa_enable_dma(dmach_t channel, dma_t *dma) address = dma->buf.dma_address; length = dma->buf.length - 1; outb(address >> 16, isa_dma_port[channel][ISA_DMA_PGLO]); outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]); outb(address >> 16, isa_dma_port[chan][ISA_DMA_PGLO]); outb(address >> 24, isa_dma_port[chan][ISA_DMA_PGHI]); if (channel >= 4) { if (chan >= 4) { address >>= 1; length >>= 1; } outb(0, isa_dma_port[channel][ISA_DMA_CLRFF]); outb(address, isa_dma_port[channel][ISA_DMA_ADDR]); outb(address >> 8, isa_dma_port[channel][ISA_DMA_ADDR]); outb(0, isa_dma_port[chan][ISA_DMA_CLRFF]); outb(length, isa_dma_port[channel][ISA_DMA_COUNT]); outb(length >> 8, isa_dma_port[channel][ISA_DMA_COUNT]); outb(address, isa_dma_port[chan][ISA_DMA_ADDR]); outb(address >> 8, isa_dma_port[chan][ISA_DMA_ADDR]); if (dma->dma_mode & DMA_AUTOINIT) mode |= ISA_DMA_AUTOINIT; outb(length, isa_dma_port[chan][ISA_DMA_COUNT]); outb(length >> 8, isa_dma_port[chan][ISA_DMA_COUNT]); outb(mode, isa_dma_port[channel][ISA_DMA_MODE]); outb(mode, isa_dma_port[chan][ISA_DMA_MODE]); dma->invalid = 0; } outb(channel & 3, isa_dma_port[channel][ISA_DMA_MASK]); outb(chan & 3, isa_dma_port[chan][ISA_DMA_MASK]); } static void isa_disable_dma(dmach_t channel, dma_t *dma) static void isa_disable_dma(unsigned int chan, dma_t *dma) { outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]); outb(chan | 4, isa_dma_port[chan][ISA_DMA_MASK]); } static struct dma_ops isa_dma_ops = { Loading Loading @@ -160,7 +149,12 @@ static struct resource dma_resources[] = { { .end = 0x048f } }; void __init isa_init_dma(dma_t *dma) static dma_t isa_dma[8]; /* * ISA DMA always starts at channel 0 */ void __init isa_init_dma(void) { /* * Try to autodetect presence of an ISA DMA controller. Loading @@ -178,11 +172,11 @@ void __init isa_init_dma(dma_t *dma) outb(0xaa, 0x00); if (inb(0) == 0x55 && inb(0) == 0xaa) { int channel, i; unsigned int chan, i; for (channel = 0; channel < 8; channel++) { dma[channel].d_ops = &isa_dma_ops; isa_disable_dma(channel, NULL); for (chan = 0; chan < 8; chan++) { isa_dma[chan].d_ops = &isa_dma_ops; isa_disable_dma(chan, NULL); } outb(0x40, 0x0b); Loading Loading @@ -217,5 +211,12 @@ void __init isa_init_dma(dma_t *dma) for (i = 0; i < ARRAY_SIZE(dma_resources); i++) request_resource(&ioport_resource, dma_resources + i); for (chan = 0; chan < 8; chan++) { int ret = isa_dma_add(chan, &isa_dma[chan]); if (ret) printk(KERN_ERR "ISADMA%u: unable to register: %d\n", chan, ret); } } }
arch/arm/kernel/dma.c +67 −52 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/spinlock.h> #include <linux/errno.h> #include <linux/scatterlist.h> #include <asm/dma.h> Loading @@ -23,19 +24,40 @@ DEFINE_SPINLOCK(dma_spin_lock); EXPORT_SYMBOL(dma_spin_lock); static dma_t dma_chan[MAX_DMA_CHANNELS]; static dma_t *dma_chan[MAX_DMA_CHANNELS]; static inline dma_t *dma_channel(unsigned int chan) { if (chan >= MAX_DMA_CHANNELS) return NULL; return dma_chan[chan]; } int __init isa_dma_add(unsigned int chan, dma_t *dma) { if (!dma->d_ops) return -EINVAL; sg_init_table(&dma->buf, 1); if (dma_chan[chan]) return -EBUSY; dma_chan[chan] = dma; return 0; } /* * Request DMA channel * * On certain platforms, we have to allocate an interrupt as well... */ int request_dma(dmach_t channel, const char *device_id) int request_dma(unsigned int chan, const char *device_id) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); int ret; if (channel >= MAX_DMA_CHANNELS || !dma->d_ops) if (!dma) goto bad_dma; if (xchg(&dma->lock, 1) != 0) Loading @@ -47,7 +69,7 @@ int request_dma(dmach_t channel, const char *device_id) ret = 0; if (dma->d_ops->request) ret = dma->d_ops->request(channel, dma); ret = dma->d_ops->request(chan, dma); if (ret) xchg(&dma->lock, 0); Loading @@ -55,7 +77,7 @@ int request_dma(dmach_t channel, const char *device_id) return ret; bad_dma: printk(KERN_ERR "dma: trying to allocate DMA%d\n", channel); printk(KERN_ERR "dma: trying to allocate DMA%d\n", chan); return -EINVAL; busy: Loading @@ -68,42 +90,42 @@ EXPORT_SYMBOL(request_dma); * * On certain platforms, we have to free interrupt as well... */ void free_dma(dmach_t channel) void free_dma(unsigned int chan) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (channel >= MAX_DMA_CHANNELS || !dma->d_ops) if (!dma) goto bad_dma; if (dma->active) { printk(KERN_ERR "dma%d: freeing active DMA\n", channel); dma->d_ops->disable(channel, dma); printk(KERN_ERR "dma%d: freeing active DMA\n", chan); dma->d_ops->disable(chan, dma); dma->active = 0; } if (xchg(&dma->lock, 0) != 0) { if (dma->d_ops->free) dma->d_ops->free(channel, dma); dma->d_ops->free(chan, dma); return; } printk(KERN_ERR "dma%d: trying to free free DMA\n", channel); printk(KERN_ERR "dma%d: trying to free free DMA\n", chan); return; bad_dma: printk(KERN_ERR "dma: trying to free DMA%d\n", channel); printk(KERN_ERR "dma: trying to free DMA%d\n", chan); } EXPORT_SYMBOL(free_dma); /* Set DMA Scatter-Gather list */ void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg) void set_dma_sg (unsigned int chan, struct scatterlist *sg, int nr_sg) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (dma->active) printk(KERN_ERR "dma%d: altering DMA SG while " "DMA active\n", channel); "DMA active\n", chan); dma->sg = sg; dma->sgcount = nr_sg; Loading @@ -115,13 +137,13 @@ EXPORT_SYMBOL(set_dma_sg); * * Copy address to the structure, and set the invalid bit */ void __set_dma_addr (dmach_t channel, void *addr) void __set_dma_addr (unsigned int chan, void *addr) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (dma->active) printk(KERN_ERR "dma%d: altering DMA address while " "DMA active\n", channel); "DMA active\n", chan); dma->sg = NULL; dma->addr = addr; Loading @@ -133,13 +155,13 @@ EXPORT_SYMBOL(__set_dma_addr); * * Copy address to the structure, and set the invalid bit */ void set_dma_count (dmach_t channel, unsigned long count) void set_dma_count (unsigned int chan, unsigned long count) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (dma->active) printk(KERN_ERR "dma%d: altering DMA count while " "DMA active\n", channel); "DMA active\n", chan); dma->sg = NULL; dma->count = count; Loading @@ -149,13 +171,13 @@ EXPORT_SYMBOL(set_dma_count); /* Set DMA direction mode */ void set_dma_mode (dmach_t channel, dmamode_t mode) void set_dma_mode (unsigned int chan, unsigned int mode) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (dma->active) printk(KERN_ERR "dma%d: altering DMA mode while " "DMA active\n", channel); "DMA active\n", chan); dma->dma_mode = mode; dma->invalid = 1; Loading @@ -164,42 +186,42 @@ EXPORT_SYMBOL(set_dma_mode); /* Enable DMA channel */ void enable_dma (dmach_t channel) void enable_dma (unsigned int chan) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (!dma->lock) goto free_dma; if (dma->active == 0) { dma->active = 1; dma->d_ops->enable(channel, dma); dma->d_ops->enable(chan, dma); } return; free_dma: printk(KERN_ERR "dma%d: trying to enable free DMA\n", channel); printk(KERN_ERR "dma%d: trying to enable free DMA\n", chan); BUG(); } EXPORT_SYMBOL(enable_dma); /* Disable DMA channel */ void disable_dma (dmach_t channel) void disable_dma (unsigned int chan) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); if (!dma->lock) goto free_dma; if (dma->active == 1) { dma->active = 0; dma->d_ops->disable(channel, dma); dma->d_ops->disable(chan, dma); } return; free_dma: printk(KERN_ERR "dma%d: trying to disable free DMA\n", channel); printk(KERN_ERR "dma%d: trying to disable free DMA\n", chan); BUG(); } EXPORT_SYMBOL(disable_dma); Loading @@ -207,45 +229,38 @@ EXPORT_SYMBOL(disable_dma); /* * Is the specified DMA channel active? */ int dma_channel_active(dmach_t channel) int dma_channel_active(unsigned int chan) { return dma_chan[channel].active; dma_t *dma = dma_channel(chan); return dma->active; } EXPORT_SYMBOL(dma_channel_active); void set_dma_page(dmach_t channel, char pagenr) void set_dma_page(unsigned int chan, char pagenr) { printk(KERN_ERR "dma%d: trying to set_dma_page\n", channel); printk(KERN_ERR "dma%d: trying to set_dma_page\n", chan); } EXPORT_SYMBOL(set_dma_page); void set_dma_speed(dmach_t channel, int cycle_ns) void set_dma_speed(unsigned int chan, int cycle_ns) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); int ret = 0; if (dma->d_ops->setspeed) ret = dma->d_ops->setspeed(channel, dma, cycle_ns); ret = dma->d_ops->setspeed(chan, dma, cycle_ns); dma->speed = ret; } EXPORT_SYMBOL(set_dma_speed); int get_dma_residue(dmach_t channel) int get_dma_residue(unsigned int chan) { dma_t *dma = dma_chan + channel; dma_t *dma = dma_channel(chan); int ret = 0; if (dma->d_ops->residue) ret = dma->d_ops->residue(channel, dma); ret = dma->d_ops->residue(chan, dma); return ret; } EXPORT_SYMBOL(get_dma_residue); static int __init init_dma(void) { arch_dma_init(dma_chan); return 0; } core_initcall(init_dma);
arch/arm/mach-footbridge/dma.c +7 −5 Original line number Diff line number Diff line Loading @@ -21,16 +21,16 @@ #include <asm/hardware/dec21285.h> #if 0 static int fb_dma_request(dmach_t channel, dma_t *dma) static int fb_dma_request(unsigned int chan, dma_t *dma) { return -EINVAL; } static void fb_dma_enable(dmach_t channel, dma_t *dma) static void fb_dma_enable(unsigned int chan, dma_t *dma) { } static void fb_dma_disable(dmach_t channel, dma_t *dma) static void fb_dma_disable(unsigned int chan, dma_t *dma) { } Loading @@ -42,7 +42,7 @@ static struct dma_ops fb_dma_ops = { }; #endif void __init arch_dma_init(dma_t *dma) static int __init fb_dma_init(void) { #if 0 dma[_DC21285_DMA(0)].d_ops = &fb_dma_ops; Loading @@ -50,6 +50,8 @@ void __init arch_dma_init(dma_t *dma) #endif #ifdef CONFIG_ISA_DMA if (footbridge_cfn_mode()) isa_init_dma(dma + _ISA_DMA(0)); isa_init_dma(); #endif return 0; } core_initcall(fb_dma_init);