Skip to content

Commit

Permalink
[ARM] dma: move RiscPC specific DMA data out of dma_struct
Browse files Browse the repository at this point in the history
Separate the RiscPC specific (IOMD and floppy FIQ) data out of the core
DMA structure by making the IOMD and floppy DMA supersets.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Russell King authored and Russell King committed Dec 11, 2008
1 parent 2f757f2 commit ad9dd94
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 73 deletions.
18 changes: 13 additions & 5 deletions arch/arm/include/asm/mach/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,22 @@ struct dma_struct {
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;
};

struct floppy_dma {
struct dma_struct dma;
unsigned int fiq;
};

struct iomd_dma {
struct dma_struct dma;
unsigned int state;
unsigned long base; /* Controller base address */
int irq; /* Controller IRQ */
struct scatterlist cur_sg; /* Current controller buffer */
};

/*
* isa_dma_add - add an ISA-style DMA channel
*/
Expand Down
146 changes: 78 additions & 68 deletions arch/arm/mach-rpc/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ typedef enum {
#define CR (IOMD_IO0CR - IOMD_IO0CURA)
#define ST (IOMD_IO0ST - IOMD_IO0CURA)

static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)
static void iomd_get_next_sg(struct scatterlist *sg, struct iomd_dma *idma)
{
unsigned long end, offset, flags = 0;

if (dma->sg) {
sg->dma_address = dma->sg->dma_address;
if (idma->dma.sg) {
sg->dma_address = idma->dma.sg->dma_address;
offset = sg->dma_address & ~PAGE_MASK;

end = offset + dma->sg->length;
end = offset + idma->dma.sg->length;

if (end > PAGE_SIZE)
end = PAGE_SIZE;
Expand All @@ -62,15 +62,15 @@ static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)

sg->length = end - TRANSFER_SIZE;

dma->sg->length -= end - offset;
dma->sg->dma_address += end - offset;
idma->dma.sg->length -= end - offset;
idma->dma.sg->dma_address += end - offset;

if (dma->sg->length == 0) {
if (dma->sgcount > 1) {
dma->sg++;
dma->sgcount--;
if (idma->dma.sg->length == 0) {
if (idma->dma.sgcount > 1) {
idma->dma.sg++;
idma->dma.sgcount--;
} else {
dma->sg = NULL;
idma->dma.sg = NULL;
flags |= DMA_END_S;
}
}
Expand All @@ -85,8 +85,8 @@ static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)

static irqreturn_t iomd_dma_handle(int irq, void *dev_id)
{
dma_t *dma = (dma_t *)dev_id;
unsigned long base = dma->dma_base;
struct iomd_dma *idma = dev_id;
unsigned long base = idma->base;

do {
unsigned int status;
Expand All @@ -95,88 +95,94 @@ static irqreturn_t iomd_dma_handle(int irq, void *dev_id)
if (!(status & DMA_ST_INT))
return IRQ_HANDLED;

if ((dma->state ^ status) & DMA_ST_AB)
iomd_get_next_sg(&dma->cur_sg, dma);
if ((idma->state ^ status) & DMA_ST_AB)
iomd_get_next_sg(&idma->cur_sg, idma);

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);
dma->state = DMA_ST_AB;
iomd_writel(idma->cur_sg.dma_address, base + CURA);
iomd_writel(idma->cur_sg.length, base + ENDA);
idma->state = DMA_ST_AB;
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);
dma->state = 0;
iomd_writel(idma->cur_sg.dma_address, base + CURB);
iomd_writel(idma->cur_sg.length, base + ENDB);
idma->state = 0;
break;
}

if (status & DMA_ST_OFL &&
dma->cur_sg.length == (DMA_END_S|DMA_END_L))
idma->cur_sg.length == (DMA_END_S|DMA_END_L))
break;
} while (1);

dma->state = ~DMA_ST_AB;
idma->state = ~DMA_ST_AB;
disable_irq(irq);

return IRQ_HANDLED;
}

static int iomd_request_dma(unsigned int chan, dma_t *dma)
{
return request_irq(dma->dma_irq, iomd_dma_handle,
IRQF_DISABLED, dma->device_id, dma);
struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);

return request_irq(idma->irq, iomd_dma_handle,
IRQF_DISABLED, idma->dma.device_id, idma);
}

static void iomd_free_dma(unsigned int chan, dma_t *dma)
{
free_irq(dma->dma_irq, dma);
struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);

free_irq(idma->irq, idma);
}

static void iomd_enable_dma(unsigned int chan, dma_t *dma)
{
unsigned long dma_base = dma->dma_base;
struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
unsigned long dma_base = idma->base;
unsigned int ctrl = TRANSFER_SIZE | DMA_CR_E;

if (dma->invalid) {
dma->invalid = 0;
if (idma->dma.invalid) {
idma->dma.invalid = 0;

/*
* Cope with ISA-style drivers which expect cache
* coherence.
*/
if (!dma->sg) {
dma->sg = &dma->buf;
dma->sgcount = 1;
dma->buf.length = dma->count;
dma->buf.dma_address = dma_map_single(NULL,
dma->addr, dma->count,
dma->dma_mode == DMA_MODE_READ ?
if (!idma->dma.sg) {
idma->dma.sg = &idma->dma.buf;
idma->dma.sgcount = 1;
idma->dma.buf.length = idma->dma.count;
idma->dma.buf.dma_address = dma_map_single(NULL,
idma->dma.addr, idma->dma.count,
idma->dma.dma_mode == DMA_MODE_READ ?
DMA_FROM_DEVICE : DMA_TO_DEVICE);
}

iomd_writeb(DMA_CR_C, dma_base + CR);
dma->state = DMA_ST_AB;
idma->state = DMA_ST_AB;
}
if (dma->dma_mode == DMA_MODE_READ)

if (idma->dma.dma_mode == DMA_MODE_READ)
ctrl |= DMA_CR_D;

iomd_writeb(ctrl, dma_base + CR);
enable_irq(dma->dma_irq);
enable_irq(idma->irq);
}

static void iomd_disable_dma(unsigned int chan, dma_t *dma)
{
unsigned long dma_base = dma->dma_base;
struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
unsigned long dma_base = idma->base;
unsigned long flags;

local_irq_save(flags);
if (dma->state != ~DMA_ST_AB)
disable_irq(dma->dma_irq);
if (idma->state != ~DMA_ST_AB)
disable_irq(idma->irq);
iomd_writeb(0, dma_base + CR);
local_irq_restore(flags);
}
Expand Down Expand Up @@ -238,14 +244,15 @@ static struct fiq_handler fh = {

static void floppy_enable_dma(unsigned int chan, dma_t *dma)
{
struct floppy_dma *fdma = container_of(dma, struct floppy_dma, dma);
void *fiqhandler_start;
unsigned int fiqhandler_length;
struct pt_regs regs;

if (dma->sg)
if (fdma->dma.sg)
BUG();

if (dma->dma_mode == DMA_MODE_READ) {
if (fdma->dma.dma_mode == DMA_MODE_READ) {
extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
fiqhandler_start = &floppy_fiqin_start;
fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start;
Expand All @@ -255,8 +262,8 @@ static void floppy_enable_dma(unsigned int chan, dma_t *dma)
fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start;
}

regs.ARM_r9 = dma->count;
regs.ARM_r10 = (unsigned long)dma->addr;
regs.ARM_r9 = fdma->dma.count;
regs.ARM_r10 = (unsigned long)fdma->dma.addr;
regs.ARM_fp = (unsigned long)FLOPPYDMA_BASE;

if (claim_fiq(&fh)) {
Expand All @@ -266,12 +273,13 @@ static void floppy_enable_dma(unsigned int chan, dma_t *dma)

set_fiq_handler(fiqhandler_start, fiqhandler_length);
set_fiq_regs(&regs);
enable_fiq(dma->dma_irq);
enable_fiq(fdma->fiq);
}

static void floppy_disable_dma(unsigned int chan, dma_t *dma)
{
disable_fiq(dma->dma_irq);
struct floppy_dma *fdma = container_of(dma, struct floppy_dma, dma);
disable_fiq(fdma->fiq);
release_fiq(&fh);
}

Expand Down Expand Up @@ -302,11 +310,13 @@ static struct dma_ops sound_dma_ops = {
.disable = sound_enable_disable_dma,
};

static dma_t iomd_dma[6];
static struct iomd_dma iomd_dma[6];

static dma_t floppy_dma = {
.dma_irq = FIQ_FLOPPYDATA,
.d_ops = &floppy_dma_ops,
static struct floppy_dma floppy_dma = {
.dma = {
.d_ops = &floppy_dma_ops,
},
.fiq = FIQ_FLOPPYDATA,
};

static dma_t sound_dma = {
Expand All @@ -331,28 +341,28 @@ static int __init rpc_dma_init(void)
*/
iomd_writeb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT);

iomd_dma[DMA_0].dma_base = IOMD_IO0CURA;
iomd_dma[DMA_0].dma_irq = IRQ_DMA0;
iomd_dma[DMA_1].dma_base = IOMD_IO1CURA;
iomd_dma[DMA_1].dma_irq = IRQ_DMA1;
iomd_dma[DMA_2].dma_base = IOMD_IO2CURA;
iomd_dma[DMA_2].dma_irq = IRQ_DMA2;
iomd_dma[DMA_3].dma_base = IOMD_IO3CURA;
iomd_dma[DMA_3].dma_irq = IRQ_DMA3;
iomd_dma[DMA_S0].dma_base = IOMD_SD0CURA;
iomd_dma[DMA_S0].dma_irq = IRQ_DMAS0;
iomd_dma[DMA_S1].dma_base = IOMD_SD1CURA;
iomd_dma[DMA_S1].dma_irq = IRQ_DMAS1;
iomd_dma[DMA_0].base = IOMD_IO0CURA;
iomd_dma[DMA_0].irq = IRQ_DMA0;
iomd_dma[DMA_1].base = IOMD_IO1CURA;
iomd_dma[DMA_1].irq = IRQ_DMA1;
iomd_dma[DMA_2].base = IOMD_IO2CURA;
iomd_dma[DMA_2].irq = IRQ_DMA2;
iomd_dma[DMA_3].base = IOMD_IO3CURA;
iomd_dma[DMA_3].irq = IRQ_DMA3;
iomd_dma[DMA_S0].base = IOMD_SD0CURA;
iomd_dma[DMA_S0].irq = IRQ_DMAS0;
iomd_dma[DMA_S1].base = IOMD_SD1CURA;
iomd_dma[DMA_S1].irq = IRQ_DMAS1;

for (i = DMA_0; i <= DMA_S1; i++) {
iomd_dma[i].d_ops = &iomd_dma_ops;
iomd_dma[i].dma.d_ops = &iomd_dma_ops;

ret = isa_dma_add(i, &iomd_dma[i]);
ret = isa_dma_add(i, &iomd_dma[i].dma);
if (ret)
printk("IOMDDMA%u: unable to register: %d\n", i, ret);
}

ret = isa_dma_add(DMA_VIRTUAL_FLOPPY, &floppy_dma);
ret = isa_dma_add(DMA_VIRTUAL_FLOPPY, &floppy_dma.dma);
if (ret)
printk("IOMDFLOPPY: unable to register: %d\n", ret);
ret = isa_dma_add(DMA_VIRTUAL_SOUND, &sound_dma);
Expand Down

0 comments on commit ad9dd94

Please sign in to comment.