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 @@
#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,14 +252,16 @@ 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;
if ((orig_csr & EBDMA_CSR_EN_DMA) !=
(csr & EBDMA_CSR_EN_DMA))
writel(csr, p->regs + EBDMA_CSR);
spin_unlock_irqrestore(&p->lock, flags);
}
......
......@@ -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.
......
......@@ -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;
......
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