Commit ea21e4ac authored by Jeff Garzik's avatar Jeff Garzik

[libata] create, and use, ->irq_clear hook

This is more conservative in general, and so applies to multiple
controllers.  Specifically it attempts to address irq-related issues
on the Intel ICH5/6 hardware.  On Intel ICH5/6, the BMDMA 'interrupt'
status bit will be set even on non-DMA commands, which software
(and I) did not expect.

This change clears pending interrupts once upon initialization,
and then each time ata_irq_on() is called.
parent e6920719
......@@ -143,6 +143,7 @@ static struct ata_port_operations piix_pata_ops = {
.eng_timeout = ata_eng_timeout,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.port_start = ata_port_start,
.port_stop = ata_port_stop,
......@@ -168,6 +169,7 @@ static struct ata_port_operations piix_sata_ops = {
.eng_timeout = ata_eng_timeout,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.port_start = ata_port_start,
.port_stop = ata_port_stop,
......
......@@ -2537,6 +2537,11 @@ void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
}
void ata_bmdma_irq_clear(struct ata_port *ap)
{
ata_bmdma_ack_irq(ap);
}
/**
* ata_host_intr - Handle host interrupt for given (port, task)
* @ap: Port on which interrupt arrived (possibly...)
......@@ -2879,6 +2884,7 @@ int ata_device_add(struct ata_probe_ent *ent)
host_set->irq = ent->irq;
host_set->mmio_base = ent->mmio_base;
host_set->private_data = ent->private_data;
host_set->ops = ent->port_ops;
/* register each port bound to this device */
for (i = 0; i < ent->n_ports; i++) {
......@@ -2901,6 +2907,8 @@ int ata_device_add(struct ata_probe_ent *ent)
ap->ioaddr.bmdma_addr,
ent->irq);
ata_chk_status(ap);
host_set->ops->irq_clear(ap);
count++;
}
......@@ -2909,10 +2917,6 @@ int ata_device_add(struct ata_probe_ent *ent)
return 0;
}
/* TODO: ack irq here, to ensure it won't scream
* when we enable it?
*/
/* obtain irq, that is shared between channels */
if (request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
DRV_NAME, host_set))
......@@ -3238,8 +3242,8 @@ void ata_pci_remove_one (struct pci_dev *pdev)
free_irq(host_set->irq, host_set);
if (host_set->mmio_base)
iounmap(host_set->mmio_base);
if (host_set->ports[0]->ops->host_stop)
host_set->ports[0]->ops->host_stop(host_set);
if (host_set->ops->host_stop)
host_set->ops->host_stop(host_set);
for (i = 0; i < host_set->n_ports; i++) {
ap = host_set->ports[i];
......@@ -3363,6 +3367,7 @@ EXPORT_SYMBOL_GPL(ata_bmdma_setup_pio);
EXPORT_SYMBOL_GPL(ata_bmdma_start_pio);
EXPORT_SYMBOL_GPL(ata_bmdma_setup_mmio);
EXPORT_SYMBOL_GPL(ata_bmdma_start_mmio);
EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
EXPORT_SYMBOL_GPL(ata_port_probe);
EXPORT_SYMBOL_GPL(sata_phy_reset);
EXPORT_SYMBOL_GPL(ata_bus_reset);
......
......@@ -142,6 +142,7 @@ static struct ata_port_operations nv_ops = {
.qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout,
.irq_handler = nv_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
......
......@@ -86,6 +86,7 @@ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
static inline void pdc_dma_complete (struct ata_port *ap,
struct ata_queued_cmd *qc, int have_err);
static void pdc_irq_clear(struct ata_port *ap);
static Scsi_Host_Template pdc_sata_sht = {
.module = THIS_MODULE,
......@@ -118,6 +119,7 @@ static struct ata_port_operations pdc_sata_ops = {
.qc_issue = ata_qc_issue_prot,
.eng_timeout = pdc_eng_timeout,
.irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
.scr_read = pdc_sata_scr_read,
.scr_write = pdc_sata_scr_write,
.port_start = pdc_port_start,
......@@ -379,6 +381,14 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap,
return handled;
}
static void pdc_irq_clear(struct ata_port *ap)
{
struct ata_host_set *host_set = ap->host_set;
void *mmio = host_set->mmio_base;
readl(mmio + PDC_INT_SEQMASK);
}
static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
{
struct ata_host_set *host_set = dev_instance;
......
......@@ -136,6 +136,7 @@ static struct ata_port_operations sil_ops = {
.qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.scr_read = sil_scr_read,
.scr_write = sil_scr_write,
.port_start = ata_port_start,
......
......@@ -104,6 +104,7 @@ static struct ata_port_operations sis_ops = {
.qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.scr_read = sis_scr_read,
.scr_write = sis_scr_write,
.port_start = ata_port_start,
......
......@@ -237,6 +237,7 @@ static struct ata_port_operations k2_sata_ops = {
.qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.scr_read = k2_sata_scr_read,
.scr_write = k2_sata_scr_write,
.port_start = ata_port_start,
......
......@@ -171,6 +171,7 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
#endif
static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
void *psource, u32 offset, u32 size);
static void pdc20621_irq_clear(struct ata_port *ap);
static Scsi_Host_Template pdc_sata_sht = {
......@@ -204,6 +205,7 @@ static struct ata_port_operations pdc_20621_ops = {
.qc_issue = ata_qc_issue_prot,
.eng_timeout = pdc_eng_timeout,
.irq_handler = pdc20621_interrupt,
.irq_clear = pdc20621_irq_clear,
.port_start = pdc_port_start,
.port_stop = pdc_port_stop,
.host_stop = pdc20621_host_stop,
......@@ -703,6 +705,16 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
return handled;
}
static void pdc20621_irq_clear(struct ata_port *ap)
{
struct ata_host_set *host_set = ap->host_set;
void *mmio = host_set->mmio_base;
mmio += PDC_CHIP0_OFS;
readl(mmio + PDC_20621_SEQMASK);
}
static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
{
struct ata_host_set *host_set = dev_instance;
......
......@@ -114,6 +114,7 @@ static struct ata_port_operations svia_sata_ops = {
.eng_timeout = ata_eng_timeout,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.scr_read = svia_scr_read,
.scr_write = svia_scr_write,
......
......@@ -219,6 +219,7 @@ static struct ata_port_operations vsc_sata_ops = {
.qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout,
.irq_handler = vsc_sata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.scr_read = vsc_sata_scr_read,
.scr_write = vsc_sata_scr_write,
.port_start = ata_port_start,
......
......@@ -202,6 +202,7 @@ struct ata_host_set {
void *mmio_base;
unsigned int n_ports;
void *private_data;
struct ata_port_operations *ops;
struct ata_port * ports[0];
};
......@@ -318,6 +319,7 @@ struct ata_port_operations {
void (*eng_timeout) (struct ata_port *ap);
irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
void (*irq_clear) (struct ata_port *);
u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
......@@ -382,6 +384,7 @@ extern void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc);
extern void ata_bmdma_start_mmio (struct ata_queued_cmd *qc);
extern void ata_bmdma_setup_pio (struct ata_queued_cmd *qc);
extern void ata_bmdma_start_pio (struct ata_queued_cmd *qc);
extern void ata_bmdma_irq_clear(struct ata_port *ap);
extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits);
extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat);
extern void ata_eng_timeout(struct ata_port *ap);
......@@ -484,6 +487,7 @@ static inline void ata_tf_init(struct ata_port *ap, struct ata_taskfile *tf, uns
static inline u8 ata_irq_on(struct ata_port *ap)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
u8 tmp;
ap->ctl &= ~ATA_NIEN;
ap->last_ctl = ap->ctl;
......@@ -492,7 +496,11 @@ static inline u8 ata_irq_on(struct ata_port *ap)
writeb(ap->ctl, ioaddr->ctl_addr);
else
outb(ap->ctl, ioaddr->ctl_addr);
return ata_wait_idle(ap);
tmp = ata_wait_idle(ap);
ap->ops->irq_clear(ap);
return tmp;
}
static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
......
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