From 64383da3045a33a2edb29536b073d4b78560b075 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 19 Nov 2003 04:50:27 -0800 Subject: [PATCH] [SPARC64]: Get PCI floppies fully functional again. EBUS DMA fixes: - Add EBUS_DMA_FLAG_TCI_DISABLE that the client can set if it wants only to hear device interrupts, not DMA complete ones. - When initially resetting the EBUS DMA unit, put valid burst etc. encodings in the CSR register. Not doing this appears to leave the attached ISA device in a weird state. PCI FLOPPY fixes: - Do ebus_dma_enable() before ebus_dma_request() - In sun_pci_fd_set_dma_mode() do not forget to set the direction. - Set EBUS_DMA_FLAG_TCI_DISABLE in ebus_dma flags. - Make sure that in error paths sun_fdc/FCD1 will be -1 (invalid). Thanks to Soyoung Park for loaning her Ultra5 to me so I could fix this. --- arch/sparc64/kernel/ebus.c | 48 +++++++++++++++++++++++++++--------- include/asm-sparc64/ebus.h | 1 + include/asm-sparc64/floppy.h | 21 +++++++++++----- 3 files changed, 53 insertions(+), 17 deletions(-) diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index dbe2d7a30d239..e9c300988dc2c 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -58,12 +58,16 @@ #define EBUS_DMA_RESET_TIMEOUT 10000 -static void __ebus_dma_reset(struct ebus_dma_info *p) +static void __ebus_dma_reset(struct ebus_dma_info *p, int no_drain) { int i; u32 val = 0; writel(EBDMA_CSR_RESET, p->regs + EBDMA_CSR); + udelay(1); + + if (no_drain) + return; for (i = EBUS_DMA_RESET_TIMEOUT; i > 0; i--) { val = readl(p->regs + EBDMA_CSR); @@ -78,7 +82,7 @@ static irqreturn_t ebus_dma_irq(int irq, void *dev_id, struct pt_regs *regs) { struct ebus_dma_info *p = dev_id; unsigned long flags; - u32 csr; + u32 csr = 0; spin_lock_irqsave(&p->lock, flags); csr = readl(p->regs + EBDMA_CSR); @@ -98,20 +102,31 @@ static irqreturn_t ebus_dma_irq(int irq, void *dev_id, struct pt_regs *regs) } return IRQ_NONE; + } int ebus_dma_register(struct ebus_dma_info *p) { + u32 csr; + if (!p->regs) return -EINVAL; - if (p->flags & ~(EBUS_DMA_FLAG_USE_EBDMA_HANDLER)) + if (p->flags & ~(EBUS_DMA_FLAG_USE_EBDMA_HANDLER | + EBUS_DMA_FLAG_TCI_DISABLE)) return -EINVAL; if ((p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) && !p->callback) return -EINVAL; if (!strlen(p->name)) return -EINVAL; - __ebus_dma_reset(p); + __ebus_dma_reset(p, 1); + + csr = EBDMA_CSR_BURST_SZ_16 | EBDMA_CSR_EN_CNT; + + if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE) + csr |= EBDMA_CSR_TCI_DIS; + + writel(csr, p->regs + EBDMA_CSR); return 0; } @@ -201,14 +216,23 @@ EXPORT_SYMBOL(ebus_dma_request); void ebus_dma_prepare(struct ebus_dma_info *p, int write) { unsigned long flags; + u32 csr; spin_lock_irqsave(&p->lock, flags); - __ebus_dma_reset(p); - writel(EBDMA_CSR_INT_EN | - ((write) ? EBDMA_CSR_WRITE : 0) | + __ebus_dma_reset(p, 0); + + csr = (EBDMA_CSR_INT_EN | EBDMA_CSR_EN_CNT | EBDMA_CSR_BURST_SZ_16 | - EBDMA_CSR_EN_NEXT, p->regs + EBDMA_CSR); + EBDMA_CSR_EN_NEXT); + + if (write) + csr |= EBDMA_CSR_WRITE; + if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE) + csr |= EBDMA_CSR_TCI_DIS; + + writel(csr, p->regs + EBDMA_CSR); + spin_unlock_irqrestore(&p->lock, flags); } EXPORT_SYMBOL(ebus_dma_prepare); @@ -228,15 +252,17 @@ EXPORT_SYMBOL(ebus_dma_addr); void ebus_dma_enable(struct ebus_dma_info *p, int on) { unsigned long flags; - u32 csr; + u32 orig_csr, csr; spin_lock_irqsave(&p->lock, flags); - csr = readl(p->regs + EBDMA_CSR); + orig_csr = csr = readl(p->regs + EBDMA_CSR); if (on) csr |= EBDMA_CSR_EN_DMA; else csr &= ~EBDMA_CSR_EN_DMA; - writel(csr, p->regs + EBDMA_CSR); + if ((orig_csr & EBDMA_CSR_EN_DMA) != + (csr & EBDMA_CSR_EN_DMA)) + writel(csr, p->regs + EBDMA_CSR); spin_unlock_irqrestore(&p->lock, flags); } EXPORT_SYMBOL(ebus_dma_enable); diff --git a/include/asm-sparc64/ebus.h b/include/asm-sparc64/ebus.h index 8a4f4248d67c1..82e8376430f85 100644 --- a/include/asm-sparc64/ebus.h +++ b/include/asm-sparc64/ebus.h @@ -57,6 +57,7 @@ struct ebus_dma_info { unsigned int flags; #define EBUS_DMA_FLAG_USE_EBDMA_HANDLER 0x00000001 +#define EBUS_DMA_FLAG_TCI_DISABLE 0x00000002 /* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is * set. diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h index 231fbb4f8ff72..8beed5df56b36 100644 --- a/include/asm-sparc64/floppy.h +++ b/include/asm-sparc64/floppy.h @@ -340,12 +340,12 @@ static void sun_pci_fd_enable_dma(void) sun_pci_dma_current.len, sun_pci_dma_current.direction); + ebus_dma_enable(&sun_pci_fd_ebus_dma, 1); + if (ebus_dma_request(&sun_pci_fd_ebus_dma, sun_pci_dma_current.addr, sun_pci_dma_current.len)) BUG(); - - ebus_dma_enable(&sun_pci_fd_ebus_dma, 1); } static void sun_pci_fd_disable_dma(void) @@ -361,6 +361,11 @@ static void sun_pci_fd_disable_dma(void) static void sun_pci_fd_set_dma_mode(int mode) { + if (mode == DMA_MODE_WRITE) + sun_pci_dma_pending.direction = PCI_DMA_TODEVICE; + else + sun_pci_dma_pending.direction = PCI_DMA_FROMDEVICE; + ebus_dma_prepare(&sun_pci_fd_ebus_dma, mode != DMA_MODE_WRITE); } @@ -630,11 +635,9 @@ static unsigned long __init sun_floppy_init(void) prom_getproperty(edev->prom_node, "status", state, sizeof(state)); - if(!strncmp(state, "disabled", 8)) + if (!strncmp(state, "disabled", 8)) return 0; - /* XXX ioremap */ - sun_fdc = (struct sun_flpy_controller *)edev->resource[0].start; FLOPPY_IRQ = edev->irqs[0]; /* Make sure the high density bit is set, some systems @@ -646,11 +649,14 @@ static unsigned long __init sun_floppy_init(void) sun_pci_ebus_dev = ebus->self; spin_lock_init(&sun_pci_fd_ebus_dma.lock); + /* XXX ioremap */ sun_pci_fd_ebus_dma.regs = edev->resource[1].start; if (!sun_pci_fd_ebus_dma.regs) return 0; - sun_pci_fd_ebus_dma.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; + + sun_pci_fd_ebus_dma.flags = (EBUS_DMA_FLAG_USE_EBDMA_HANDLER | + EBUS_DMA_FLAG_TCI_DISABLE); sun_pci_fd_ebus_dma.callback = sun_pci_fd_dma_callback; sun_pci_fd_ebus_dma.client_cookie = NULL; sun_pci_fd_ebus_dma.irq = FLOPPY_IRQ; @@ -658,6 +664,9 @@ static unsigned long __init sun_floppy_init(void) if (ebus_dma_register(&sun_pci_fd_ebus_dma)) return 0; + /* XXX ioremap */ + sun_fdc = (struct sun_flpy_controller *)edev->resource[0].start; + sun_fdops.fd_inb = sun_pci_fd_inb; sun_fdops.fd_outb = sun_pci_fd_outb; -- 2.53.0