21.07.05 Luke Kosewski * A patch to the sata_promise driver in libata for it to correctly mask out hotplug interrupts on SATAII150 Tx4/Tx2 Plus controllers. Also, the 'spin_lock' in the interrupt handler has been changed to a 'spin_lock_irqsave' for consistency with other libata drivers. Signed-off-by: Luke Kosewski --- linux-2.6.13-rc3/drivers/scsi/sata_promise.c.old 2005-07-21 13:35:43.311486155 -0400 +++ linux-2.6.13-rc3/drivers/scsi/sata_promise.c 2005-07-21 13:40:06.145261193 -0400 @@ -52,6 +52,7 @@ enum { PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */ PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */ PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */ + PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */ PDC_SLEW_CTL = 0x470, /* slew rate control reg */ PDC_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) | @@ -60,8 +61,10 @@ enum { board_2037x = 0, /* FastTrak S150 TX2plus */ board_20319 = 1, /* FastTrak S150 TX4 */ board_20619 = 2, /* FastTrak TX4000 */ + board_2057x = 3, /* SATAII150 Tx2plus */ + board_40518 = 4, /* SATAII150 Tx4 */ - PDC_HAS_PATA = (1 << 1), /* PDC20375 has PATA */ + PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */ PDC_RESET = (1 << 11), /* HDMA reset */ }; @@ -76,6 +79,7 @@ static u32 pdc_sata_scr_read (struct ata static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t pdc2_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static void pdc_eng_timeout(struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); @@ -128,6 +132,26 @@ static struct ata_port_operations pdc_at .host_stop = ata_host_stop, }; +static struct ata_port_operations pdc2_ata_ops = { + .port_disable = ata_port_disable, + .tf_load = pdc_tf_load_mmio, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = pdc_exec_command_mmio, + .dev_select = ata_std_dev_select, + .phy_reset = pdc_phy_reset, + .qc_prep = pdc_qc_prep, + .qc_issue = pdc_qc_issue_prot, + .eng_timeout = pdc_eng_timeout, + .irq_handler = pdc2_interrupt, + .irq_clear = pdc_irq_clear, + .scr_read = pdc_sata_scr_read, + .scr_write = pdc_sata_scr_write, + .port_start = pdc_port_start, + .port_stop = pdc_port_stop, + .host_stop = ata_host_stop, +}; + static struct ata_port_info pdc_port_info[] = { /* board_2037x */ { @@ -161,6 +185,28 @@ static struct ata_port_info pdc_port_inf .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_ata_ops, }, + + /* board_2057x */ + { + .sht = &pdc_ata_sht, + .host_flags = /* ATA_FLAG_SATA | */ ATA_FLAG_NO_LEGACY | + ATA_FLAG_SRST | ATA_FLAG_MMIO, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .port_ops = &pdc2_ata_ops, + }, + + /* board_40518 */ + { + .sht = &pdc_ata_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SRST | ATA_FLAG_MMIO, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .port_ops = &pdc2_ata_ops, + }, }; static struct pci_device_id pdc_ata_pci_tbl[] = { @@ -175,16 +221,16 @@ static struct pci_device_id pdc_ata_pci_ { PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3574, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2037x }, + board_2057x }, { PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2037x }, + board_2057x }, { PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20319 }, { PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20319 }, { PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_20319 }, + board_40518 }, { PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20619 }, @@ -432,39 +478,36 @@ static void pdc_irq_clear(struct ata_por readl(mmio + PDC_INT_SEQMASK); } -static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +static inline unsigned int pdc_interrupt_common(int irq, void *dev_instance, struct pt_regs *regs, unsigned int hotplug_regs) { struct ata_host_set *host_set = dev_instance; struct ata_port *ap; - u32 mask = 0; - unsigned int i, tmp; - unsigned int handled = 0; void *mmio_base; - - VPRINTK("ENTER\n"); + u32 mask = 0; + unsigned int i, tmp, handled = 0; + unsigned long flags; if (!host_set || !host_set->mmio_base) { - VPRINTK("QUICK EXIT\n"); - return IRQ_NONE; + return 0; } mmio_base = host_set->mmio_base; + + spin_lock_irqsave(&host_set->lock, flags); /* reading should also clear interrupts */ mask = readl(mmio_base + PDC_INT_SEQMASK); if (mask == 0xffffffff) { VPRINTK("QUICK EXIT 2\n"); - return IRQ_NONE; + goto done_irq; } mask &= 0xffff; /* only 16 tags possible */ if (!mask) { VPRINTK("QUICK EXIT 3\n"); - return IRQ_NONE; + goto done_irq; } - spin_lock(&host_set->lock); - writel(mask, mmio_base + PDC_INT_SEQMASK); for (i = 0; i < host_set->n_ports; i++) { @@ -479,12 +522,20 @@ static irqreturn_t pdc_interrupt (int ir handled += pdc_host_intr(ap, qc); } } + +done_irq: + spin_unlock_irqrestore(&host_set->lock, flags); + return handled; +} - spin_unlock(&host_set->lock); - - VPRINTK("EXIT\n"); +static irqreturn_t pdc2_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + return IRQ_RETVAL(pdc_interrupt_common(irq, dev_instance, regs, PDC2_SATA_PLUG_CSR)); +} - return IRQ_RETVAL(handled); +static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +{ + return IRQ_RETVAL(pdc_interrupt_common(irq, dev_instance, regs, PDC_SATA_PLUG_CSR)); } static inline void pdc_packet_start(struct ata_queued_cmd *qc) @@ -561,6 +612,7 @@ static void pdc_ata_setup_port(struct at static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe) { void *mmio = pe->mmio_base; + void* offset; u32 tmp; /* @@ -574,13 +626,19 @@ static void pdc_host_init(unsigned int c tmp |= 0x12000; /* bit 16 (fifo 8 dw) and 13 (bmr burst?) */ writel(tmp, mmio + PDC_FLASH_CTL); + offset = mmio; + if (chip_id >= board_2057x && chip_id <= board_40518) + offset += PDC2_SATA_PLUG_CSR; + else + offset += PDC_SATA_PLUG_CSR; + /* clear plug/unplug flags for all ports */ - tmp = readl(mmio + PDC_SATA_PLUG_CSR); - writel(tmp | 0xff, mmio + PDC_SATA_PLUG_CSR); + tmp = readl(offset); + writel(tmp | 0xff, offset); /* mask plug/unplug ints */ - tmp = readl(mmio + PDC_SATA_PLUG_CSR); - writel(tmp | 0xff0000, mmio + PDC_SATA_PLUG_CSR); + tmp = readl(offset); + writel(tmp | 0xff0000, offset); /* reduce TBG clock to 133 Mhz. */ tmp = readl(mmio + PDC_TBG_MODE); @@ -674,6 +732,7 @@ static int pdc_ata_init_one (struct pci_ /* notice 4-port boards */ switch (board_idx) { case board_20319: + case board_40518: probe_ent->n_ports = 4; pdc_ata_setup_port(&probe_ent->port[2], base + 0x300); @@ -686,6 +745,7 @@ static int pdc_ata_init_one (struct pci_ probe_ent->port_flags[3] = ATA_FLAG_SATA; break; case board_2037x: + case board_2057x: /* Some boards have also PATA port */ tmp = readb(mmio_base + PDC_FLASH_CTL+1); if (!(tmp & 0x80))