]> git.hungrycats.org Git - linux/commitdiff
[SPARC64]: Get PCI floppies fully functional again.
authorDavid S. Miller <davem@nuts.ninka.net>
Wed, 19 Nov 2003 12:50:27 +0000 (04:50 -0800)
committerDavid S. Miller <davem@nuts.ninka.net>
Wed, 19 Nov 2003 12:50:27 +0000 (04:50 -0800)
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
include/asm-sparc64/ebus.h
include/asm-sparc64/floppy.h

index dbe2d7a30d239a8bae72bda1211a7bb4e61694c7..e9c300988dc2ca41511d103645e1d52be6ae2a55 100644 (file)
 
 #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);
index 8a4f4248d67c14bc77354a26c7c821712b187da6..82e8376430f853a3eb5b1530f420bb3e99f8e455 100644 (file)
@@ -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.
index 231fbb4f8ff729a6e887f556a69b578983316cd8..8beed5df56b364d3852971b284b35cc177e489a4 100644 (file)
@@ -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;