diff options
| author | Jeff Garzik <jgarzik@pobox.com> | 2004-07-03 14:40:48 -0400 |
|---|---|---|
| committer | Jeff Garzik <jgarzik@pobox.com> | 2004-07-03 14:40:48 -0400 |
| commit | ea21e4ac2f5d655db154b64329c437688c92f7d5 (patch) | |
| tree | a0e598bc5b94d821e06f359474ea55414ccb4da7 | |
| parent | e69207190a6f3c9d0413c4a8c9518dd07d18e0a3 (diff) | |
[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.
| -rw-r--r-- | drivers/scsi/ata_piix.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/libata-core.c | 17 | ||||
| -rw-r--r-- | drivers/scsi/sata_nv.c | 1 | ||||
| -rw-r--r-- | drivers/scsi/sata_promise.c | 10 | ||||
| -rw-r--r-- | drivers/scsi/sata_sil.c | 1 | ||||
| -rw-r--r-- | drivers/scsi/sata_sis.c | 1 | ||||
| -rw-r--r-- | drivers/scsi/sata_svw.c | 1 | ||||
| -rw-r--r-- | drivers/scsi/sata_sx4.c | 12 | ||||
| -rw-r--r-- | drivers/scsi/sata_via.c | 1 | ||||
| -rw-r--r-- | drivers/scsi/sata_vsc.c | 1 | ||||
| -rw-r--r-- | include/linux/libata.h | 10 |
11 files changed, 50 insertions, 7 deletions
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index c668625bcedc..c030c0a6838e 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -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, diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 63c2982cab28..98689e54277f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -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); diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index 8e8fa4c6b182..bf1932e4930e 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -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, diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index 86f88e159b4c..dcaebcf7110c 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -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; diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index 2c247d340d46..72a89d1beb69 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -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, diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index df102f1d2a9c..88b7a02ead5c 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c @@ -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, diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index 4393d494c97b..398f24f27ed2 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -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, diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index b315dfda0d56..3b71fa2853f6 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -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; diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index 1c4df92a7a51..993edfc99590 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c @@ -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, diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index adb61f709e09..d63a339cc11d 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -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, diff --git a/include/linux/libata.h b/include/linux/libata.h index c57be1ab010d..7fc0c2763f88 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -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) |
