Commit 4b59e57f authored by Russell King's avatar Russell King

[ARM] Acorn DMA/Expansion card fixups

 - Allow icside to moan if it tries to change DMA settings while
   the DMA is in progress.
 - Fix Acorn expansion card IRQ handling.
 - Clean up IOMD DMA state machine.
parent cafe839d
......@@ -120,6 +120,10 @@ void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg)
{
dma_t *dma = dma_chan + channel;
if (dma->active)
printk(KERN_ERR "dma%d: altering DMA SG while "
"DMA active\n", channel);
dma->sg = sg;
dma->sgcount = nr_sg;
dma->using_sg = 1;
......@@ -218,6 +222,14 @@ void disable_dma (dmach_t channel)
BUG();
}
/*
* Is the specified DMA channel active?
*/
int dma_channel_active(dmach_t channel)
{
return dma_chan[channel].active;
}
void set_dma_page(dmach_t channel, char pagenr)
{
printk(KERN_ERR "dma%d: trying to set_dma_page\n", channel);
......
......@@ -541,7 +541,7 @@ static expansioncard_ops_t ecard_default_ops = {
*
* They are not meant to be called directly, but via enable/disable_irq.
*/
static void ecard_irq_mask(unsigned int irqnr)
static void ecard_irq_unmask(unsigned int irqnr)
{
ecard_t *ec = slot_to_ecard(irqnr - 32);
......@@ -557,7 +557,7 @@ static void ecard_irq_mask(unsigned int irqnr)
}
}
static void ecard_irq_unmask(unsigned int irqnr)
static void ecard_irq_mask(unsigned int irqnr)
{
ecard_t *ec = slot_to_ecard(irqnr - 32);
......@@ -945,20 +945,20 @@ ecard_probe(int slot, card_type_t type)
break;
}
ec->irq = 32 + slot;
#ifdef IO_EC_MEMC8_BASE
if (slot == 8)
ec->irq = 11;
#endif
/*
* hook the interrupt handlers
*/
if (ec->irq != 0 && ec->irq >= 32) {
if (slot < 8) {
ec->irq = 32 + slot;
set_irq_chip(ec->irq, &ecard_chip);
set_irq_handler(ec->irq, do_level_IRQ);
set_irq_flags(ec->irq, IRQF_VALID);
}
#ifdef IO_EC_MEMC8_BASE
if (slot == 8)
ec->irq = 11;
#endif
#ifdef CONFIG_ARCH_RPC
/* On RiscPC, only first two slots have DMA capability */
if (slot < 2)
......
......@@ -33,10 +33,6 @@ typedef enum {
dma_size_32 = 4,
dma_size_128 = 16
} dma_size_t;
typedef struct {
dma_size_t transfersize;
} dma_t;
#endif
#define TRANSFER_SIZE 2
......@@ -48,10 +44,6 @@ typedef struct {
#define CR (IOMD_IO0CR - IOMD_IO0CURA)
#define ST (IOMD_IO0ST - IOMD_IO0CURA)
#define state_prog_a 0
#define state_wait_a 1
#define state_wait_b 2
static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)
{
unsigned long end, offset, flags = 0;
......@@ -91,76 +83,40 @@ static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)
sg->length |= flags;
}
static inline void iomd_setup_dma_a(struct scatterlist *sg, dma_t *dma)
{
iomd_writel(sg->dma_address, dma->dma_base + CURA);
iomd_writel(sg->length, dma->dma_base + ENDA);
}
static inline void iomd_setup_dma_b(struct scatterlist *sg, dma_t *dma)
{
iomd_writel(sg->dma_address, dma->dma_base + CURB);
iomd_writel(sg->length, dma->dma_base + ENDB);
}
static void iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs)
{
dma_t *dma = (dma_t *)dev_id;
unsigned int status = 0, no_buffer = dma->sg == NULL;
unsigned long base = dma->dma_base;
do {
switch (dma->state) {
case state_prog_a:
iomd_get_next_sg(&dma->cur_sg, dma);
iomd_setup_dma_a(&dma->cur_sg, dma);
dma->state = state_wait_a;
case state_wait_a:
status = iomd_readb(dma->dma_base + ST);
switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) {
case DMA_ST_OFL|DMA_ST_INT:
iomd_get_next_sg(&dma->cur_sg, dma);
iomd_setup_dma_a(&dma->cur_sg, dma);
break;
case DMA_ST_INT:
iomd_get_next_sg(&dma->cur_sg, dma);
iomd_setup_dma_b(&dma->cur_sg, dma);
dma->state = state_wait_b;
break;
case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB:
iomd_setup_dma_b(&dma->cur_sg, dma);
dma->state = state_wait_b;
break;
}
unsigned int status;
status = iomd_readb(base + ST);
if (!(status & DMA_ST_INT))
return;
if (status & DMA_ST_OFL && !dma->sg)
break;
case state_wait_b:
status = iomd_readb(dma->dma_base + ST);
switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) {
case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB:
iomd_get_next_sg(&dma->cur_sg, dma);
iomd_setup_dma_b(&dma->cur_sg, dma);
break;
case DMA_ST_INT|DMA_ST_AB:
iomd_get_next_sg(&dma->cur_sg, dma);
iomd_setup_dma_a(&dma->cur_sg, dma);
dma->state = state_wait_a;
break;
case DMA_ST_OFL|DMA_ST_INT:
iomd_setup_dma_a(&dma->cur_sg, dma);
dma->state = state_wait_a;
break;
}
iomd_get_next_sg(&dma->cur_sg, dma);
switch (status & (DMA_ST_OFL | DMA_ST_AB)) {
case DMA_ST_OFL: /* OIA */
case DMA_ST_AB: /* .IB */
iomd_writel(dma->cur_sg.dma_address, base + CURA);
iomd_writel(dma->cur_sg.length, base + ENDA);
break;
case DMA_ST_OFL | DMA_ST_AB: /* OIB */
case 0: /* .IA */
iomd_writel(dma->cur_sg.dma_address, base + CURB);
iomd_writel(dma->cur_sg.length, base + ENDB);
break;
}
} while (dma->sg && (status & DMA_ST_INT));
} while (1);
if (no_buffer)
disable_irq(irq);
iomd_writeb(0, dma->dma_base + CR);
disable_irq(irq);
}
static int iomd_request_dma(dmach_t channel, dma_t *dma)
......@@ -194,7 +150,6 @@ static void iomd_enable_dma(dmach_t channel, dma_t *dma)
}
iomd_writeb(DMA_CR_C, dma_base + CR);
dma->state = state_prog_a;
}
if (dma->dma_mode == DMA_MODE_READ)
......@@ -207,11 +162,15 @@ static void iomd_enable_dma(dmach_t channel, dma_t *dma)
static void iomd_disable_dma(dmach_t channel, dma_t *dma)
{
unsigned long dma_base = dma->dma_base;
unsigned long flags;
unsigned int ctrl;
disable_irq(dma->dma_irq);
local_irq_save(flags);
ctrl = iomd_readb(dma_base + CR);
if (ctrl & DMA_CR_E)
disable_irq(dma->dma_irq);
iomd_writeb(ctrl & ~DMA_CR_E, dma_base + CR);
local_irq_restore(flags);
}
static int iomd_set_dma_speed(dmach_t channel, dma_t *dma, int cycle)
......
......@@ -74,6 +74,10 @@ extern void enable_dma(dmach_t channel);
*/
extern void disable_dma(dmach_t channel);
/* Test whether the specified channel has an active DMA transfer
*/
extern int dma_channel_active(dmach_t channel);
/* Set the DMA scatter gather list for this channel
*
* This should not be called if a DMA channel is enabled,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment