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