Commit 64383da3 authored by David S. Miller's avatar David S. Miller

[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.
parent cfa2d622
...@@ -58,12 +58,16 @@ ...@@ -58,12 +58,16 @@
#define EBUS_DMA_RESET_TIMEOUT 10000 #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; int i;
u32 val = 0; u32 val = 0;
writel(EBDMA_CSR_RESET, p->regs + EBDMA_CSR); writel(EBDMA_CSR_RESET, p->regs + EBDMA_CSR);
udelay(1);
if (no_drain)
return;
for (i = EBUS_DMA_RESET_TIMEOUT; i > 0; i--) { for (i = EBUS_DMA_RESET_TIMEOUT; i > 0; i--) {
val = readl(p->regs + EBDMA_CSR); 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) ...@@ -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; struct ebus_dma_info *p = dev_id;
unsigned long flags; unsigned long flags;
u32 csr; u32 csr = 0;
spin_lock_irqsave(&p->lock, flags); spin_lock_irqsave(&p->lock, flags);
csr = readl(p->regs + EBDMA_CSR); 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) ...@@ -98,20 +102,31 @@ static irqreturn_t ebus_dma_irq(int irq, void *dev_id, struct pt_regs *regs)
} }
return IRQ_NONE; return IRQ_NONE;
} }
int ebus_dma_register(struct ebus_dma_info *p) int ebus_dma_register(struct ebus_dma_info *p)
{ {
u32 csr;
if (!p->regs) if (!p->regs)
return -EINVAL; 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; return -EINVAL;
if ((p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) && !p->callback) if ((p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) && !p->callback)
return -EINVAL; return -EINVAL;
if (!strlen(p->name)) if (!strlen(p->name))
return -EINVAL; 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; return 0;
} }
...@@ -201,14 +216,23 @@ EXPORT_SYMBOL(ebus_dma_request); ...@@ -201,14 +216,23 @@ EXPORT_SYMBOL(ebus_dma_request);
void ebus_dma_prepare(struct ebus_dma_info *p, int write) void ebus_dma_prepare(struct ebus_dma_info *p, int write)
{ {
unsigned long flags; unsigned long flags;
u32 csr;
spin_lock_irqsave(&p->lock, flags); spin_lock_irqsave(&p->lock, flags);
__ebus_dma_reset(p); __ebus_dma_reset(p, 0);
writel(EBDMA_CSR_INT_EN |
((write) ? EBDMA_CSR_WRITE : 0) | csr = (EBDMA_CSR_INT_EN |
EBDMA_CSR_EN_CNT | EBDMA_CSR_EN_CNT |
EBDMA_CSR_BURST_SZ_16 | 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); spin_unlock_irqrestore(&p->lock, flags);
} }
EXPORT_SYMBOL(ebus_dma_prepare); EXPORT_SYMBOL(ebus_dma_prepare);
...@@ -228,15 +252,17 @@ EXPORT_SYMBOL(ebus_dma_addr); ...@@ -228,15 +252,17 @@ EXPORT_SYMBOL(ebus_dma_addr);
void ebus_dma_enable(struct ebus_dma_info *p, int on) void ebus_dma_enable(struct ebus_dma_info *p, int on)
{ {
unsigned long flags; unsigned long flags;
u32 csr; u32 orig_csr, csr;
spin_lock_irqsave(&p->lock, flags); spin_lock_irqsave(&p->lock, flags);
csr = readl(p->regs + EBDMA_CSR); orig_csr = csr = readl(p->regs + EBDMA_CSR);
if (on) if (on)
csr |= EBDMA_CSR_EN_DMA; csr |= EBDMA_CSR_EN_DMA;
else else
csr &= ~EBDMA_CSR_EN_DMA; 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); spin_unlock_irqrestore(&p->lock, flags);
} }
EXPORT_SYMBOL(ebus_dma_enable); EXPORT_SYMBOL(ebus_dma_enable);
......
...@@ -57,6 +57,7 @@ struct ebus_dma_info { ...@@ -57,6 +57,7 @@ struct ebus_dma_info {
unsigned int flags; unsigned int flags;
#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER 0x00000001 #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 /* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
* set. * set.
......
...@@ -340,12 +340,12 @@ static void sun_pci_fd_enable_dma(void) ...@@ -340,12 +340,12 @@ static void sun_pci_fd_enable_dma(void)
sun_pci_dma_current.len, sun_pci_dma_current.len,
sun_pci_dma_current.direction); sun_pci_dma_current.direction);
ebus_dma_enable(&sun_pci_fd_ebus_dma, 1);
if (ebus_dma_request(&sun_pci_fd_ebus_dma, if (ebus_dma_request(&sun_pci_fd_ebus_dma,
sun_pci_dma_current.addr, sun_pci_dma_current.addr,
sun_pci_dma_current.len)) sun_pci_dma_current.len))
BUG(); BUG();
ebus_dma_enable(&sun_pci_fd_ebus_dma, 1);
} }
static void sun_pci_fd_disable_dma(void) static void sun_pci_fd_disable_dma(void)
...@@ -361,6 +361,11 @@ 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) 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); ebus_dma_prepare(&sun_pci_fd_ebus_dma, mode != DMA_MODE_WRITE);
} }
...@@ -630,11 +635,9 @@ static unsigned long __init sun_floppy_init(void) ...@@ -630,11 +635,9 @@ static unsigned long __init sun_floppy_init(void)
prom_getproperty(edev->prom_node, "status", prom_getproperty(edev->prom_node, "status",
state, sizeof(state)); state, sizeof(state));
if(!strncmp(state, "disabled", 8)) if (!strncmp(state, "disabled", 8))
return 0; return 0;
/* XXX ioremap */
sun_fdc = (struct sun_flpy_controller *)edev->resource[0].start;
FLOPPY_IRQ = edev->irqs[0]; FLOPPY_IRQ = edev->irqs[0];
/* Make sure the high density bit is set, some systems /* Make sure the high density bit is set, some systems
...@@ -646,11 +649,14 @@ static unsigned long __init sun_floppy_init(void) ...@@ -646,11 +649,14 @@ static unsigned long __init sun_floppy_init(void)
sun_pci_ebus_dev = ebus->self; sun_pci_ebus_dev = ebus->self;
spin_lock_init(&sun_pci_fd_ebus_dma.lock); spin_lock_init(&sun_pci_fd_ebus_dma.lock);
/* XXX ioremap */ /* XXX ioremap */
sun_pci_fd_ebus_dma.regs = edev->resource[1].start; sun_pci_fd_ebus_dma.regs = edev->resource[1].start;
if (!sun_pci_fd_ebus_dma.regs) if (!sun_pci_fd_ebus_dma.regs)
return 0; 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.callback = sun_pci_fd_dma_callback;
sun_pci_fd_ebus_dma.client_cookie = NULL; sun_pci_fd_ebus_dma.client_cookie = NULL;
sun_pci_fd_ebus_dma.irq = FLOPPY_IRQ; sun_pci_fd_ebus_dma.irq = FLOPPY_IRQ;
...@@ -658,6 +664,9 @@ static unsigned long __init sun_floppy_init(void) ...@@ -658,6 +664,9 @@ static unsigned long __init sun_floppy_init(void)
if (ebus_dma_register(&sun_pci_fd_ebus_dma)) if (ebus_dma_register(&sun_pci_fd_ebus_dma))
return 0; 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_inb = sun_pci_fd_inb;
sun_fdops.fd_outb = sun_pci_fd_outb; sun_fdops.fd_outb = sun_pci_fd_outb;
......
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