From 095fec887eaa1c38d17c0c929a6733c744a9fa1f Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 12 Nov 2005 09:50:49 -0500 Subject: [libata sata_mv] minor fixes - clear SError and EDMA irq cause registers, after re-init'ing the phy - move enums with type suffix 'U' to their own enum --- drivers/scsi/sata_mv.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 257c128f4aa..82d1750e779 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -72,11 +72,6 @@ enum { MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT), MV_PORT_PRIV_DMA_SZ = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ), - /* Our DMA boundary is determined by an ePRD being unable to handle - * anything larger than 64KB - */ - MV_DMA_BOUNDARY = 0xffffU, - MV_PORTS_PER_HC = 4, /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */ MV_PORT_HC_SHIFT = 2, @@ -192,7 +187,6 @@ enum { EDMA_REQ_Q_BASE_HI_OFS = 0x10, EDMA_REQ_Q_IN_PTR_OFS = 0x14, /* also contains BASE_LO */ - EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U, EDMA_REQ_Q_OUT_PTR_OFS = 0x18, EDMA_REQ_Q_PTR_SHIFT = 5, @@ -200,7 +194,6 @@ enum { EDMA_RSP_Q_BASE_HI_OFS = 0x1c, EDMA_RSP_Q_IN_PTR_OFS = 0x20, EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */ - EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U, EDMA_RSP_Q_PTR_SHIFT = 3, EDMA_CMD_OFS = 0x28, @@ -216,6 +209,17 @@ enum { MV_PP_FLAG_EDMA_DS_ACT = (1 << 1), }; +enum { + /* Our DMA boundary is determined by an ePRD being unable to handle + * anything larger than 64KB + */ + MV_DMA_BOUNDARY = 0xffffU, + + EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U, + + EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U, +}; + /* Command ReQuest Block: 32B */ struct mv_crqb { u32 sg_addr; @@ -1215,6 +1219,7 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, */ static void mv_phy_reset(struct ata_port *ap) { + struct mv_port_priv *pp = ap->private_data; void __iomem *port_mmio = mv_ap_base(ap); struct ata_taskfile tf; struct ata_device *dev = &ap->device[0]; @@ -1232,7 +1237,7 @@ static void mv_phy_reset(struct ata_port *ap) */ writelfl(0, port_mmio + EDMA_CMD_OFS); - VPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x " + DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x " "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); @@ -1247,7 +1252,9 @@ static void mv_phy_reset(struct ata_port *ap) break; } while (time_before(jiffies, timeout)); - VPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x " + mv_scr_write(ap, SCR_ERROR, mv_scr_read(ap, SCR_ERROR)); + + DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x " "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); @@ -1271,7 +1278,12 @@ static void mv_phy_reset(struct ata_port *ap) VPRINTK("Port disabled post-sig: No device present.\n"); ata_port_disable(ap); } - VPRINTK("EXIT\n"); + + writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); + + pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; + + printk("EXIT\n"); } /** -- cgit v1.2.3 From 8b260248d9e0e8b64bb72fd4dee03ad86984c344 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 12 Nov 2005 12:32:50 -0500 Subject: [libata sata_mv] trim trailing whitespace --- drivers/scsi/sata_mv.c | 76 +++++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 82d1750e779..26e9d51e6ca 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -1,7 +1,7 @@ /* * sata_mv.c - Marvell SATA support * - * Copyright 2005: EMC Corporation, all rights reserved. + * Copyright 2005: EMC Corporation, all rights reserved. * * Please ALWAYS copy linux-ide@vger.kernel.org on emails. * @@ -84,7 +84,7 @@ enum { MV_FLAG_GLBL_SFT_RST = (1 << 28), /* Global Soft Reset support */ MV_COMMON_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO), - MV_6XXX_FLAGS = (MV_FLAG_IRQ_COALESCE | + MV_6XXX_FLAGS = (MV_FLAG_IRQ_COALESCE | MV_FLAG_GLBL_SFT_RST), chip_504x = 0, @@ -129,7 +129,7 @@ enum { SELF_INT = (1 << 23), TWSI_INT = (1 << 24), HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */ - HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE | + HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT | HC_MAIN_RSVD), @@ -177,12 +177,12 @@ enum { EDMA_ERR_LNK_CTRL_TX = (0x1f << 21), EDMA_ERR_LNK_DATA_TX = (0x1f << 26), EDMA_ERR_TRANS_PROTO = (1 << 31), - EDMA_ERR_FATAL = (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR | + EDMA_ERR_FATAL = (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR | EDMA_ERR_DEV_DCON | EDMA_ERR_CRBQ_PAR | EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR | - EDMA_ERR_IORDY | EDMA_ERR_LNK_CTRL_RX_2 | + EDMA_ERR_IORDY | EDMA_ERR_LNK_CTRL_RX_2 | EDMA_ERR_LNK_DATA_RX | - EDMA_ERR_LNK_DATA_TX | + EDMA_ERR_LNK_DATA_TX | EDMA_ERR_TRANS_PROTO), EDMA_REQ_Q_BASE_HI_OFS = 0x10, @@ -345,7 +345,7 @@ static struct ata_port_info mv_port_info[] = { }, { /* chip_608x */ .sht = &mv_sht, - .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS | + .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS | MV_FLAG_DUAL_HC), .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 */ @@ -393,7 +393,7 @@ static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc) static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port) { return (mv_hc_base(base, port >> MV_PORT_HC_SHIFT) + - MV_SATAHC_ARBTR_REG_SZ + + MV_SATAHC_ARBTR_REG_SZ + ((port & MV_PORT_MASK) * MV_PORT_REG_SZ)); } @@ -456,7 +456,7 @@ static void mv_stop_dma(struct ata_port *ap) } else { assert(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS))); } - + /* now properly wait for the eDMA to stop */ for (i = 1000; i > 0; i--) { reg = readl(port_mmio + EDMA_CMD_OFS); @@ -507,7 +507,7 @@ static void mv_dump_all_regs(void __iomem *mmio_base, int port, struct pci_dev *pdev) { #ifdef ATA_DEBUG - void __iomem *hc_base = mv_hc_base(mmio_base, + void __iomem *hc_base = mv_hc_base(mmio_base, port >> MV_PORT_HC_SHIFT); void __iomem *port_base; int start_port, num_ports, p, start_hc, num_hcs, hc; @@ -521,7 +521,7 @@ static void mv_dump_all_regs(void __iomem *mmio_base, int port, start_port = port; num_ports = num_hcs = 1; } - DPRINTK("All registers for port(s) %u-%u:\n", start_port, + DPRINTK("All registers for port(s) %u-%u:\n", start_port, num_ports > 1 ? num_ports - 1 : start_port); if (NULL != pdev) { @@ -705,7 +705,7 @@ static int mv_port_start(struct ata_port *ap) goto err_out; memset(pp, 0, sizeof(*pp)); - mem = dma_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma, + mem = dma_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL); if (!mem) goto err_out_pp; @@ -715,7 +715,7 @@ static int mv_port_start(struct ata_port *ap) if (rc) goto err_out_priv; - /* First item in chunk of DMA memory: + /* First item in chunk of DMA memory: * 32-slot command request table (CRQB), 32 bytes each in size */ pp->crqb = mem; @@ -723,7 +723,7 @@ static int mv_port_start(struct ata_port *ap) mem += MV_CRQB_Q_SZ; mem_dma += MV_CRQB_Q_SZ; - /* Second item: + /* Second item: * 32-slot command response table (CRPB), 8 bytes each in size */ pp->crpb = mem; @@ -737,18 +737,18 @@ static int mv_port_start(struct ata_port *ap) pp->sg_tbl = mem; pp->sg_tbl_dma = mem_dma; - writelfl(EDMA_CFG_Q_DEPTH | EDMA_CFG_RD_BRST_EXT | + writelfl(EDMA_CFG_Q_DEPTH | EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN, port_mmio + EDMA_CFG_OFS); writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS); - writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK, + writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK, port_mmio + EDMA_REQ_Q_IN_PTR_OFS); writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS); writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS); writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS); - writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK, + writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); pp->req_producer = pp->rsp_consumer = 0; @@ -863,7 +863,7 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) } /* the req producer index should be the same as we remember it */ - assert(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >> + assert(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == pp->req_producer); @@ -875,9 +875,9 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) assert(MV_MAX_Q_DEPTH > qc->tag); flags |= qc->tag << CRQB_TAG_SHIFT; - pp->crqb[pp->req_producer].sg_addr = + pp->crqb[pp->req_producer].sg_addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff); - pp->crqb[pp->req_producer].sg_addr_hi = + pp->crqb[pp->req_producer].sg_addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16); pp->crqb[pp->req_producer].ctrl_flags = cpu_to_le16(flags); @@ -900,7 +900,7 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) #ifdef LIBATA_NCQ /* FIXME: remove this line when NCQ added */ case ATA_CMD_FPDMA_READ: case ATA_CMD_FPDMA_WRITE: - mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0); + mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0); mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0); break; #endif /* FIXME: remove this line when NCQ added */ @@ -966,7 +966,7 @@ static int mv_qc_issue(struct ata_queued_cmd *qc) pp->req_producer); /* until we do queuing, the queue should be empty at this point */ assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == - ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >> + ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK)); mv_inc_q_index(&pp->req_producer); /* now incr producer index */ @@ -1003,15 +1003,15 @@ static u8 mv_get_crpb_status(struct ata_port *ap) out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); /* the response consumer index should be the same as we remember it */ - assert(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + assert(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == pp->rsp_consumer); /* increment our consumer index... */ pp->rsp_consumer = mv_inc_q_index(&pp->rsp_consumer); - + /* and, until we do NCQ, there should only be 1 CRPB waiting */ - assert(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >> - EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + assert(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >> + EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == pp->rsp_consumer); /* write out our inc'd consumer index so EDMA knows we're caught up */ @@ -1135,7 +1135,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, err_mask |= AC_ERR_OTHER; handled++; } - + if (handled && ap) { qc = ata_qc_from_tag(ap, ap->active_tag); if (NULL != qc) { @@ -1150,7 +1150,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, } /** - * mv_interrupt - + * mv_interrupt - * @irq: unused * @dev_instance: private data; in this case the host structure * @regs: unused @@ -1160,7 +1160,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, * routine to handle. Also check for PCI errors which are only * reported here. * - * LOCKING: + * LOCKING: * This routine holds the host_set lock while processing pending * interrupts. */ @@ -1303,12 +1303,12 @@ static void mv_eng_timeout(struct ata_port *ap) printk(KERN_ERR "ata%u: Entering mv_eng_timeout\n",ap->id); DPRINTK("All regs @ start of eng_timeout\n"); - mv_dump_all_regs(ap->host_set->mmio_base, ap->port_no, + mv_dump_all_regs(ap->host_set->mmio_base, ap->port_no, to_pci_dev(ap->host_set->dev)); qc = ata_qc_from_tag(ap, ap->active_tag); printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n", - ap->host_set->mmio_base, ap, qc, qc->scsicmd, + ap->host_set->mmio_base, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd); mv_err_intr(ap); @@ -1348,17 +1348,17 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS; unsigned serr_ofs; - /* PIO related setup + /* PIO related setup */ port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA); - port->error_addr = + port->error_addr = port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR); port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT); port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL); port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM); port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH); port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE); - port->status_addr = + port->status_addr = port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS); /* special case: control/altstatus doesn't have ATA_REG_ address */ port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS; @@ -1374,7 +1374,7 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) /* unmask all EDMA error interrupts */ writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS); - VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n", + VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n", readl(port_mmio + EDMA_CFG_OFS), readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS), readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS)); @@ -1396,7 +1396,7 @@ static int mv_host_init(struct ata_probe_ent *probe_ent) void __iomem *mmio = probe_ent->mmio_base; void __iomem *port_mmio; - if ((MV_FLAG_GLBL_SFT_RST & probe_ent->host_flags) && + if ((MV_FLAG_GLBL_SFT_RST & probe_ent->host_flags) && mv_global_soft_reset(probe_ent->mmio_base)) { rc = 1; goto done; @@ -1430,7 +1430,7 @@ static int mv_host_init(struct ata_probe_ent *probe_ent) writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS); VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x " - "PCI int cause/mask=0x%08x/0x%08x\n", + "PCI int cause/mask=0x%08x/0x%08x\n", readl(mmio + HC_MAIN_IRQ_CAUSE_OFS), readl(mmio + HC_MAIN_IRQ_MASK_OFS), readl(mmio + PCI_IRQ_CAUSE_OFS), @@ -1470,7 +1470,7 @@ static void mv_print_info(struct ata_probe_ent *probe_ent) dev_printk(KERN_INFO, &pdev->dev, "%u slots %u ports %s mode IRQ via %s\n", - (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports, + (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports, scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx"); } -- cgit v1.2.3 From 9a68c1b9580886a2ff07a42733adb7583ee3d9ac Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 12 Nov 2005 12:40:41 -0500 Subject: [libata sata_mv] note driver is "HIGHLY EXPERIMENTAL" in Kconfig --- drivers/scsi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 84c42c44e04..20dd85a7781 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -497,7 +497,7 @@ config SCSI_ATA_PIIX If unsure, say N. config SCSI_SATA_MV - tristate "Marvell SATA support" + tristate "Marvell SATA support (HIGHLY EXPERIMENTAL)" depends on SCSI_SATA && PCI && EXPERIMENTAL help This option enables support for the Marvell Serial ATA family. -- cgit v1.2.3 From bca1c4eb9411533d613123618c0d127fae532595 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 12 Nov 2005 12:48:15 -0500 Subject: [libata sata_mv] implement a bunch of errata workarounds Based largely on the GPL'd Marvell vendor driver. --- drivers/scsi/sata_mv.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 261 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 26e9d51e6ca..b1696e353dd 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -50,6 +50,8 @@ enum { MV_PCI_REG_BASE = 0, MV_IRQ_COAL_REG_BASE = 0x18000, /* 6xxx part only */ MV_SATAHC0_REG_BASE = 0x20000, + MV_GPIO_PORT_CTL = 0x104f0, + MV_RESET_CFG = 0x180d8, MV_PCI_REG_SZ = MV_MAJOR_REG_AREA_SZ, MV_SATAHC_REG_SZ = MV_MAJOR_REG_AREA_SZ, @@ -148,6 +150,11 @@ enum { /* SATA registers */ SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */ SATA_ACTIVE_OFS = 0x350, + PHY_MODE4 = 0x314, + PHY_MODE2 = 0x330, + SATA_INTERFACE_CTL = 0x050, + + MV_M2_PREAMP_MASK = 0x7e0, /* Port registers */ EDMA_CFG_OFS = 0, @@ -201,14 +208,26 @@ enum { EDMA_DS = (1 << 1), ATA_RST = (1 << 2), + EDMA_ARB_CFG = 0x38, + EDMA_NO_SNOOP = (1 << 6), + /* Host private flags (hp_flags) */ MV_HP_FLAG_MSI = (1 << 0), + MV_HP_ERRATA_60X1A1 = (1 << 1), + MV_HP_ERRATA_60X1B0 = (1 << 2), + MV_HP_ERRATA_50XXB0 = (1 << 3), + MV_HP_ERRATA_50XXB1 = (1 << 4), + MV_HP_ERRATA_50XXB2 = (1 << 5), + MV_HP_50XX = (1 << 6), /* Port private flags (pp_flags) */ MV_PP_FLAG_EDMA_EN = (1 << 0), MV_PP_FLAG_EDMA_DS_ACT = (1 << 1), }; +#define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX) +#define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0) + enum { /* Our DMA boundary is determined by an ePRD being unable to handle * anything larger than 64KB @@ -256,8 +275,14 @@ struct mv_port_priv { u32 pp_flags; }; +struct mv_port_signal { + u32 amps; + u32 pre; +}; + struct mv_host_priv { u32 hp_flags; + struct mv_port_signal signal[8]; }; static void mv_irq_clear(struct ata_port *ap); @@ -354,10 +379,12 @@ static struct ata_port_info mv_port_info[] = { }; static const struct pci_device_id mv_pci_tbl[] = { +#if 0 /* unusably broken right now */ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x}, {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x}, {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_508x}, {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x}, +#endif {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x}, {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x}, @@ -402,9 +429,9 @@ static inline void __iomem *mv_ap_base(struct ata_port *ap) return mv_port_base(ap->host_set->mmio_base, ap->port_no); } -static inline int mv_get_hc_count(unsigned long hp_flags) +static inline int mv_get_hc_count(unsigned long host_flags) { - return ((hp_flags & MV_FLAG_DUAL_HC) ? 2 : 1); + return ((host_flags & MV_FLAG_DUAL_HC) ? 2 : 1); } static void mv_irq_clear(struct ata_port *ap) @@ -694,6 +721,7 @@ static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev) static int mv_port_start(struct ata_port *ap) { struct device *dev = ap->host_set->dev; + struct mv_host_priv *hpriv = ap->host_set->private_data; struct mv_port_priv *pp; void __iomem *port_mmio = mv_ap_base(ap); void *mem; @@ -751,6 +779,15 @@ static int mv_port_start(struct ata_port *ap) writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); + if (hpriv->hp_flags & MV_HP_ERRATA_60X1A1) { + u32 new_tmp, tmp; + + new_tmp = tmp = readl(port_mmio + EDMA_ARB_CFG); + new_tmp &= ~EDMA_NO_SNOOP; + if (new_tmp != tmp) + writel(new_tmp, port_mmio + EDMA_ARB_CFG); + } + pp->req_producer = pp->rsp_consumer = 0; /* Don't turn on EDMA here...do it before DMA commands only. Else @@ -1206,6 +1243,52 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, return IRQ_RETVAL(handled); } +static void mv_phy_errata5(struct ata_port *ap) +{ + /* FIXME */ +} + +static void mv_phy_errata6(struct ata_port *ap) +{ + struct mv_host_priv *hpriv = ap->host_set->private_data; + u32 hp_flags = hpriv->hp_flags; + void __iomem *port_mmio = mv_ap_base(ap); + int fix_phy_mode4 = + hp_flags & (MV_HP_ERRATA_60X1A1 | MV_HP_ERRATA_60X1B0); + u32 m2; + + if (fix_phy_mode4) { + u32 tmp, m4; + + m4 = readl(port_mmio + PHY_MODE4); + tmp = readl(port_mmio + 0x310); + + m4 = (m4 & ~(1 << 1)) | (1 << 0); + + writel(m4, port_mmio + PHY_MODE4); + writel(tmp, port_mmio + 0x310); + } + + /* Revert values of pre-emphasis and signal amps to the saved ones */ + m2 = readl(port_mmio + PHY_MODE2); + + m2 &= ~MV_M2_PREAMP_MASK; + m2 |= hpriv->signal[ap->port_no].amps; + m2 |= hpriv->signal[ap->port_no].pre; + + writel(m2, port_mmio + PHY_MODE2); +} + +static void mv_phy_errata(struct ata_port *ap) +{ + struct mv_host_priv *hpriv = ap->host_set->private_data; + + if (IS_50XX(hpriv)) + mv_phy_errata5(ap); + else + mv_phy_errata6(ap); +} + /** * mv_phy_reset - Perform eDMA reset followed by COMRESET * @ap: ATA channel to manipulate @@ -1220,6 +1303,7 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, static void mv_phy_reset(struct ata_port *ap) { struct mv_port_priv *pp = ap->private_data; + struct mv_host_priv *hpriv = ap->host_set->private_data; void __iomem *port_mmio = mv_ap_base(ap); struct ata_taskfile tf; struct ata_device *dev = &ap->device[0]; @@ -1230,6 +1314,13 @@ static void mv_phy_reset(struct ata_port *ap) mv_stop_dma(ap); writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS); + + if (IS_60XX(hpriv)) { + u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL); + ifctl |= (1 << 12) | (1 << 7); + writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL); + } + udelay(25); /* allow reset propagation */ /* Spec never mentions clearing the bit. Marvell's driver does @@ -1237,6 +1328,8 @@ static void mv_phy_reset(struct ata_port *ap) */ writelfl(0, port_mmio + EDMA_CMD_OFS); + mv_phy_errata(ap); + DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x " "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); @@ -1283,7 +1376,7 @@ static void mv_phy_reset(struct ata_port *ap) pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; - printk("EXIT\n"); + VPRINTK("EXIT\n"); } /** @@ -1380,8 +1473,152 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS)); } +static void mv_enable_leds5(struct mv_host_priv *hpriv, void __iomem *mmio) +{ + /* FIXME */ +} + +static void mv_enable_leds6(struct mv_host_priv *hpriv, void __iomem *mmio) +{ + if (hpriv->hp_flags & MV_HP_ERRATA_60X1A1) + writel(0x00020060, mmio + MV_GPIO_PORT_CTL); + + else if (hpriv->hp_flags & MV_HP_ERRATA_60X1B0) + writel(0x00000060, mmio + MV_GPIO_PORT_CTL); +} + +static void mv_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) +{ + if (IS_50XX(hpriv)) + mv_enable_leds5(hpriv, mmio); + else + mv_enable_leds6(hpriv, mmio); +} + +static void mv_cfg_signal5(struct mv_host_priv *hpriv, int idx, + void __iomem *mmio) +{ + /* FIXME */ +} + +static void mv_cfg_signal6(struct mv_host_priv *hpriv, int idx, + void __iomem *mmio) +{ + void __iomem *port_mmio; + u32 tmp; + + if (hpriv->hp_flags & MV_HP_ERRATA_60X1A1) { + hpriv->signal[idx].amps = 0x5 << 8; + hpriv->signal[idx].pre = 0x3 << 5; + return; + } + + assert (hpriv->hp_flags & MV_HP_ERRATA_60X1B0); + + tmp = readl(mmio + MV_RESET_CFG); + if ((tmp & (1 << 0)) == 0) { + hpriv->signal[idx].amps = 0x4 << 8; + hpriv->signal[idx].pre = 0x1 << 5; + return; + } + + port_mmio = mv_port_base(mmio, idx); + tmp = readl(port_mmio + PHY_MODE2); + + hpriv->signal[idx].amps = tmp & 0x700; /* bits 10:8 */ + hpriv->signal[idx].pre = tmp & 0xe0; /* bits 7:5 */ +} + +static int mv_cfg_errata(struct pci_dev *pdev, struct mv_host_priv *hpriv, + unsigned int board_idx) +{ + u8 rev_id; + u32 hp_flags = hpriv->hp_flags; + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); + + switch(board_idx) { + case chip_504x: + case chip_508x: + hp_flags |= MV_HP_50XX; + + if (pdev->device == 0x5080) { + switch (rev_id) { + case 0x0: + dev_printk(KERN_WARNING, &pdev->dev, + "Applying B0 workarounds to unknown rev 0\n"); + /* fall through */ + case 0x1: + hp_flags |= MV_HP_ERRATA_50XXB0; + break; + case 0x2: + hp_flags |= MV_HP_ERRATA_50XXB1; + break; + case 0x3: + hp_flags |= MV_HP_ERRATA_50XXB2; + break; + default: + dev_printk(KERN_WARNING, &pdev->dev, + "Applying B2 workarounds to future rev\n"); + hp_flags |= MV_HP_ERRATA_50XXB2; + break; + } + } else { + switch (rev_id) { + case 0x0: + hp_flags |= MV_HP_ERRATA_50XXB0; + break; + case 0x1: + dev_printk(KERN_WARNING, &pdev->dev, + "Applying B1 workarounds to unknown rev 1\n"); + /* fall through */ + case 0x2: + hp_flags |= MV_HP_ERRATA_50XXB1; + break; + default: + dev_printk(KERN_WARNING, &pdev->dev, + "Applying B2 workarounds to future rev\n"); + /* fall through */ + case 0x3: + hp_flags |= MV_HP_ERRATA_50XXB2; + break; + } + } + break; + + case chip_604x: + case chip_608x: + switch (rev_id) { + case 0x0: + dev_printk(KERN_WARNING, &pdev->dev, + "Applying A1 workarounds to unknown rev 0\n"); + /* fall through */ + case 0x1: + hp_flags |= MV_HP_ERRATA_60X1A1; + break; + default: + dev_printk(KERN_WARNING, &pdev->dev, + "Applying B0 workarounds to future rev\n"); + /* fall through */ + case 0x2: + hp_flags |= MV_HP_ERRATA_60X1B0; + break; + } + break; + + default: + printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx); + return 1; + } + + hpriv->hp_flags = hp_flags; + + return 0; +} + /** * mv_host_init - Perform some early initialization of the host. + * @pdev: host PCI device * @probe_ent: early data struct representing the host * * If possible, do an early global reset of the host. Then do @@ -1390,11 +1627,28 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) * LOCKING: * Inherited from caller. */ -static int mv_host_init(struct ata_probe_ent *probe_ent) +static int mv_host_init(struct pci_dev *pdev, struct ata_probe_ent *probe_ent, + unsigned int board_idx) { int rc = 0, n_hc, port, hc; void __iomem *mmio = probe_ent->mmio_base; void __iomem *port_mmio; + struct mv_host_priv *hpriv = probe_ent->private_data; + + rc = mv_cfg_errata(pdev, hpriv, board_idx); + if (rc) + goto done; + + n_hc = mv_get_hc_count(probe_ent->host_flags); + probe_ent->n_ports = MV_PORTS_PER_HC * n_hc; + + if (IS_50XX(hpriv)) { + for (port = 0; port < probe_ent->n_ports; port++) + mv_cfg_signal5(hpriv, port, mmio); + } else { + for (port = 0; port < probe_ent->n_ports; port++) + mv_cfg_signal6(hpriv, port, mmio); + } if ((MV_FLAG_GLBL_SFT_RST & probe_ent->host_flags) && mv_global_soft_reset(probe_ent->mmio_base)) { @@ -1402,8 +1656,7 @@ static int mv_host_init(struct ata_probe_ent *probe_ent) goto done; } - n_hc = mv_get_hc_count(probe_ent->host_flags); - probe_ent->n_ports = MV_PORTS_PER_HC * n_hc; + mv_enable_leds(hpriv, mmio); for (port = 0; port < probe_ent->n_ports; port++) { port_mmio = mv_port_base(mmio, port); @@ -1435,6 +1688,7 @@ static int mv_host_init(struct ata_probe_ent *probe_ent) readl(mmio + HC_MAIN_IRQ_MASK_OFS), readl(mmio + PCI_IRQ_CAUSE_OFS), readl(mmio + PCI_IRQ_MASK_OFS)); + done: return rc; } @@ -1540,7 +1794,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->private_data = hpriv; /* initialize adapter */ - rc = mv_host_init(probe_ent); + rc = mv_host_init(pdev, probe_ent, board_idx); if (rc) { goto err_out_hpriv; } -- cgit v1.2.3 From ba3fe8fb6a469390a14379519915f3c39a973d99 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 12 Nov 2005 19:08:48 -0500 Subject: [libata sata_mv] move code around No content change, just prepping up future mv_hw_ops modularization. --- drivers/scsi/sata_mv.c | 96 +++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index b1696e353dd..9d116d00273 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -1243,11 +1243,59 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, return IRQ_RETVAL(handled); } +static void mv_cfg_signal5(struct mv_host_priv *hpriv, int idx, + void __iomem *mmio) +{ + /* FIXME */ +} + +static void mv_enable_leds5(struct mv_host_priv *hpriv, void __iomem *mmio) +{ + /* FIXME */ +} + static void mv_phy_errata5(struct ata_port *ap) { /* FIXME */ } +static void mv_cfg_signal6(struct mv_host_priv *hpriv, int idx, + void __iomem *mmio) +{ + void __iomem *port_mmio; + u32 tmp; + + if (hpriv->hp_flags & MV_HP_ERRATA_60X1A1) { + hpriv->signal[idx].amps = 0x5 << 8; + hpriv->signal[idx].pre = 0x3 << 5; + return; + } + + assert (hpriv->hp_flags & MV_HP_ERRATA_60X1B0); + + tmp = readl(mmio + MV_RESET_CFG); + if ((tmp & (1 << 0)) == 0) { + hpriv->signal[idx].amps = 0x4 << 8; + hpriv->signal[idx].pre = 0x1 << 5; + return; + } + + port_mmio = mv_port_base(mmio, idx); + tmp = readl(port_mmio + PHY_MODE2); + + hpriv->signal[idx].amps = tmp & 0x700; /* bits 10:8 */ + hpriv->signal[idx].pre = tmp & 0xe0; /* bits 7:5 */ +} + +static void mv_enable_leds6(struct mv_host_priv *hpriv, void __iomem *mmio) +{ + if (hpriv->hp_flags & MV_HP_ERRATA_60X1A1) + writel(0x00020060, mmio + MV_GPIO_PORT_CTL); + + else if (hpriv->hp_flags & MV_HP_ERRATA_60X1B0) + writel(0x00000060, mmio + MV_GPIO_PORT_CTL); +} + static void mv_phy_errata6(struct ata_port *ap) { struct mv_host_priv *hpriv = ap->host_set->private_data; @@ -1473,20 +1521,6 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS)); } -static void mv_enable_leds5(struct mv_host_priv *hpriv, void __iomem *mmio) -{ - /* FIXME */ -} - -static void mv_enable_leds6(struct mv_host_priv *hpriv, void __iomem *mmio) -{ - if (hpriv->hp_flags & MV_HP_ERRATA_60X1A1) - writel(0x00020060, mmio + MV_GPIO_PORT_CTL); - - else if (hpriv->hp_flags & MV_HP_ERRATA_60X1B0) - writel(0x00000060, mmio + MV_GPIO_PORT_CTL); -} - static void mv_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) { if (IS_50XX(hpriv)) @@ -1495,40 +1529,6 @@ static void mv_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) mv_enable_leds6(hpriv, mmio); } -static void mv_cfg_signal5(struct mv_host_priv *hpriv, int idx, - void __iomem *mmio) -{ - /* FIXME */ -} - -static void mv_cfg_signal6(struct mv_host_priv *hpriv, int idx, - void __iomem *mmio) -{ - void __iomem *port_mmio; - u32 tmp; - - if (hpriv->hp_flags & MV_HP_ERRATA_60X1A1) { - hpriv->signal[idx].amps = 0x5 << 8; - hpriv->signal[idx].pre = 0x3 << 5; - return; - } - - assert (hpriv->hp_flags & MV_HP_ERRATA_60X1B0); - - tmp = readl(mmio + MV_RESET_CFG); - if ((tmp & (1 << 0)) == 0) { - hpriv->signal[idx].amps = 0x4 << 8; - hpriv->signal[idx].pre = 0x1 << 5; - return; - } - - port_mmio = mv_port_base(mmio, idx); - tmp = readl(port_mmio + PHY_MODE2); - - hpriv->signal[idx].amps = tmp & 0x700; /* bits 10:8 */ - hpriv->signal[idx].pre = tmp & 0xe0; /* bits 7:5 */ -} - static int mv_cfg_errata(struct pci_dev *pdev, struct mv_host_priv *hpriv, unsigned int board_idx) { -- cgit v1.2.3 From 47c2b677daeed9c79ecb7167c211ff36876ea611 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 12 Nov 2005 21:13:17 -0500 Subject: [libata sata_mv] mv_hw_ops for hardware families; new errata - eliminate a bunch of redundant tests by creating a per-chip-family set of hooks, mv_hw_ops - implement more errata, from newer Marvell GPL'd driver --- drivers/scsi/sata_mv.c | 296 ++++++++++++++++++++++++++----------------------- 1 file changed, 158 insertions(+), 138 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 9d116d00273..4ca4b35d002 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -83,16 +83,15 @@ enum { /* Host Flags */ MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */ MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */ - MV_FLAG_GLBL_SFT_RST = (1 << 28), /* Global Soft Reset support */ MV_COMMON_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO), - MV_6XXX_FLAGS = (MV_FLAG_IRQ_COALESCE | - MV_FLAG_GLBL_SFT_RST), + MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE, chip_504x = 0, chip_508x = 1, - chip_604x = 2, - chip_608x = 3, + chip_5080 = 2, + chip_604x = 3, + chip_608x = 4, CRQB_FLAG_READ = (1 << 0), CRQB_TAG_SHIFT = 1, @@ -150,6 +149,7 @@ enum { /* SATA registers */ SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */ SATA_ACTIVE_OFS = 0x350, + PHY_MODE3 = 0x310, PHY_MODE4 = 0x314, PHY_MODE2 = 0x330, SATA_INTERFACE_CTL = 0x050, @@ -209,23 +209,20 @@ enum { ATA_RST = (1 << 2), EDMA_ARB_CFG = 0x38, - EDMA_NO_SNOOP = (1 << 6), /* Host private flags (hp_flags) */ MV_HP_FLAG_MSI = (1 << 0), - MV_HP_ERRATA_60X1A1 = (1 << 1), - MV_HP_ERRATA_60X1B0 = (1 << 2), - MV_HP_ERRATA_50XXB0 = (1 << 3), - MV_HP_ERRATA_50XXB1 = (1 << 4), - MV_HP_ERRATA_50XXB2 = (1 << 5), - MV_HP_50XX = (1 << 6), + MV_HP_ERRATA_50XXB0 = (1 << 1), + MV_HP_ERRATA_50XXB2 = (1 << 2), + MV_HP_ERRATA_60X1B2 = (1 << 3), + MV_HP_ERRATA_60X1C0 = (1 << 4), + MV_HP_50XX = (1 << 5), /* Port private flags (pp_flags) */ MV_PP_FLAG_EDMA_EN = (1 << 0), MV_PP_FLAG_EDMA_DS_ACT = (1 << 1), }; -#define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX) #define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0) enum { @@ -280,9 +277,19 @@ struct mv_port_signal { u32 pre; }; +struct mv_host_priv; +struct mv_hw_ops { + void (*phy_errata)(struct ata_port *ap); + void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio); + void (*read_preamp)(struct mv_host_priv *hpriv, int idx, + void __iomem *mmio); + int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio); +}; + struct mv_host_priv { u32 hp_flags; struct mv_port_signal signal[8]; + const struct mv_hw_ops *ops; }; static void mv_irq_clear(struct ata_port *ap); @@ -299,6 +306,18 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, static void mv_eng_timeout(struct ata_port *ap); static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +static void mv5_phy_errata(struct ata_port *ap); +static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio); +static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx, + void __iomem *mmio); +static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio); + +static void mv6_phy_errata(struct ata_port *ap); +static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio); +static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx, + void __iomem *mmio); +static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio); + static struct scsi_host_template mv_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -361,6 +380,13 @@ static struct ata_port_info mv_port_info[] = { .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */ .port_ops = &mv_ops, }, + { /* chip_5080 */ + .sht = &mv_sht, + .host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */ + .port_ops = &mv_ops, + }, { /* chip_604x */ .sht = &mv_sht, .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), @@ -382,7 +408,7 @@ static const struct pci_device_id mv_pci_tbl[] = { #if 0 /* unusably broken right now */ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x}, {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x}, - {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_508x}, + {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_5080}, {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x}, #endif @@ -402,6 +428,20 @@ static struct pci_driver mv_pci_driver = { .remove = ata_pci_remove_one, }; +static const struct mv_hw_ops mv5xxx_ops = { + .phy_errata = mv5_phy_errata, + .enable_leds = mv5_enable_leds, + .read_preamp = mv5_read_preamp, + .reset_hc = mv5_reset_hc, +}; + +static const struct mv_hw_ops mv6xxx_ops = { + .phy_errata = mv6_phy_errata, + .enable_leds = mv6_enable_leds, + .read_preamp = mv6_read_preamp, + .reset_hc = mv6_reset_hc, +}; + /* * Functions */ @@ -624,9 +664,9 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) * LOCKING: * Inherited from caller. */ -static int mv_global_soft_reset(void __iomem *mmio_base) +static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio) { - void __iomem *reg = mmio_base + PCI_MAIN_CMD_STS_OFS; + void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS; int i, rc = 0; u32 t; @@ -721,7 +761,6 @@ static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev) static int mv_port_start(struct ata_port *ap) { struct device *dev = ap->host_set->dev; - struct mv_host_priv *hpriv = ap->host_set->private_data; struct mv_port_priv *pp; void __iomem *port_mmio = mv_ap_base(ap); void *mem; @@ -779,15 +818,6 @@ static int mv_port_start(struct ata_port *ap) writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); - if (hpriv->hp_flags & MV_HP_ERRATA_60X1A1) { - u32 new_tmp, tmp; - - new_tmp = tmp = readl(port_mmio + EDMA_ARB_CFG); - new_tmp &= ~EDMA_NO_SNOOP; - if (new_tmp != tmp) - writel(new_tmp, port_mmio + EDMA_ARB_CFG); - } - pp->req_producer = pp->rsp_consumer = 0; /* Don't turn on EDMA here...do it before DMA commands only. Else @@ -1243,39 +1273,37 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, return IRQ_RETVAL(handled); } -static void mv_cfg_signal5(struct mv_host_priv *hpriv, int idx, +static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio) { /* FIXME */ } -static void mv_enable_leds5(struct mv_host_priv *hpriv, void __iomem *mmio) +static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) { /* FIXME */ } -static void mv_phy_errata5(struct ata_port *ap) +static void mv5_phy_errata(struct ata_port *ap) { /* FIXME */ } -static void mv_cfg_signal6(struct mv_host_priv *hpriv, int idx, +static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio) +{ + /* FIXME */ + return 1; +} + +static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio) { void __iomem *port_mmio; u32 tmp; - if (hpriv->hp_flags & MV_HP_ERRATA_60X1A1) { - hpriv->signal[idx].amps = 0x5 << 8; - hpriv->signal[idx].pre = 0x3 << 5; - return; - } - - assert (hpriv->hp_flags & MV_HP_ERRATA_60X1B0); - tmp = readl(mmio + MV_RESET_CFG); if ((tmp & (1 << 0)) == 0) { - hpriv->signal[idx].amps = 0x4 << 8; + hpriv->signal[idx].amps = 0x7 << 8; hpriv->signal[idx].pre = 0x1 << 5; return; } @@ -1287,34 +1315,57 @@ static void mv_cfg_signal6(struct mv_host_priv *hpriv, int idx, hpriv->signal[idx].pre = tmp & 0xe0; /* bits 7:5 */ } -static void mv_enable_leds6(struct mv_host_priv *hpriv, void __iomem *mmio) +static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) { - if (hpriv->hp_flags & MV_HP_ERRATA_60X1A1) - writel(0x00020060, mmio + MV_GPIO_PORT_CTL); - - else if (hpriv->hp_flags & MV_HP_ERRATA_60X1B0) - writel(0x00000060, mmio + MV_GPIO_PORT_CTL); + writel(0x00000060, mmio + MV_GPIO_PORT_CTL); } -static void mv_phy_errata6(struct ata_port *ap) +static void mv6_phy_errata(struct ata_port *ap) { struct mv_host_priv *hpriv = ap->host_set->private_data; u32 hp_flags = hpriv->hp_flags; void __iomem *port_mmio = mv_ap_base(ap); + int fix_phy_mode2 = + hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0); int fix_phy_mode4 = - hp_flags & (MV_HP_ERRATA_60X1A1 | MV_HP_ERRATA_60X1B0); - u32 m2; + hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0); + u32 m2, tmp; + + if (fix_phy_mode2) { + m2 = readl(port_mmio + PHY_MODE2); + m2 &= ~(1 << 16); + m2 |= (1 << 31); + writel(m2, port_mmio + PHY_MODE2); + + udelay(200); + + m2 = readl(port_mmio + PHY_MODE2); + m2 &= ~((1 << 16) | (1 << 31)); + writel(m2, port_mmio + PHY_MODE2); + + udelay(200); + } + + /* who knows what this magic does */ + tmp = readl(port_mmio + PHY_MODE3); + tmp &= ~0x7F800000; + tmp |= 0x2A800000; + writel(tmp, port_mmio + PHY_MODE3); if (fix_phy_mode4) { - u32 tmp, m4; + u32 m4; m4 = readl(port_mmio + PHY_MODE4); - tmp = readl(port_mmio + 0x310); + + if (hp_flags & MV_HP_ERRATA_60X1B2) + tmp = readl(port_mmio + 0x310); m4 = (m4 & ~(1 << 1)) | (1 << 0); writel(m4, port_mmio + PHY_MODE4); - writel(tmp, port_mmio + 0x310); + + if (hp_flags & MV_HP_ERRATA_60X1B2) + writel(tmp, port_mmio + 0x310); } /* Revert values of pre-emphasis and signal amps to the saved ones */ @@ -1323,20 +1374,11 @@ static void mv_phy_errata6(struct ata_port *ap) m2 &= ~MV_M2_PREAMP_MASK; m2 |= hpriv->signal[ap->port_no].amps; m2 |= hpriv->signal[ap->port_no].pre; + m2 &= ~(1 << 16); writel(m2, port_mmio + PHY_MODE2); } -static void mv_phy_errata(struct ata_port *ap) -{ - struct mv_host_priv *hpriv = ap->host_set->private_data; - - if (IS_50XX(hpriv)) - mv_phy_errata5(ap); - else - mv_phy_errata6(ap); -} - /** * mv_phy_reset - Perform eDMA reset followed by COMRESET * @ap: ATA channel to manipulate @@ -1376,7 +1418,7 @@ static void mv_phy_reset(struct ata_port *ap) */ writelfl(0, port_mmio + EDMA_CMD_OFS); - mv_phy_errata(ap); + hpriv->ops->phy_errata(ap); DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x " "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), @@ -1521,15 +1563,7 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS)); } -static void mv_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) -{ - if (IS_50XX(hpriv)) - mv_enable_leds5(hpriv, mmio); - else - mv_enable_leds6(hpriv, mmio); -} - -static int mv_cfg_errata(struct pci_dev *pdev, struct mv_host_priv *hpriv, +static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv, unsigned int board_idx) { u8 rev_id; @@ -1538,70 +1572,60 @@ static int mv_cfg_errata(struct pci_dev *pdev, struct mv_host_priv *hpriv, pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); switch(board_idx) { + case chip_5080: + hpriv->ops = &mv5xxx_ops; + hp_flags |= MV_HP_50XX; + + switch (rev_id) { + case 0x1: + hp_flags |= MV_HP_ERRATA_50XXB0; + break; + case 0x3: + hp_flags |= MV_HP_ERRATA_50XXB2; + break; + default: + dev_printk(KERN_WARNING, &pdev->dev, + "Applying 50XXB2 workarounds to unknown rev\n"); + hp_flags |= MV_HP_ERRATA_50XXB2; + break; + } + break; + case chip_504x: case chip_508x: + hpriv->ops = &mv5xxx_ops; hp_flags |= MV_HP_50XX; - if (pdev->device == 0x5080) { - switch (rev_id) { - case 0x0: - dev_printk(KERN_WARNING, &pdev->dev, - "Applying B0 workarounds to unknown rev 0\n"); - /* fall through */ - case 0x1: - hp_flags |= MV_HP_ERRATA_50XXB0; - break; - case 0x2: - hp_flags |= MV_HP_ERRATA_50XXB1; - break; - case 0x3: - hp_flags |= MV_HP_ERRATA_50XXB2; - break; - default: - dev_printk(KERN_WARNING, &pdev->dev, - "Applying B2 workarounds to future rev\n"); - hp_flags |= MV_HP_ERRATA_50XXB2; - break; - } - } else { - switch (rev_id) { - case 0x0: - hp_flags |= MV_HP_ERRATA_50XXB0; - break; - case 0x1: - dev_printk(KERN_WARNING, &pdev->dev, - "Applying B1 workarounds to unknown rev 1\n"); - /* fall through */ - case 0x2: - hp_flags |= MV_HP_ERRATA_50XXB1; - break; - default: - dev_printk(KERN_WARNING, &pdev->dev, - "Applying B2 workarounds to future rev\n"); - /* fall through */ - case 0x3: - hp_flags |= MV_HP_ERRATA_50XXB2; - break; - } + switch (rev_id) { + case 0x0: + hp_flags |= MV_HP_ERRATA_50XXB0; + break; + case 0x3: + hp_flags |= MV_HP_ERRATA_50XXB2; + break; + default: + dev_printk(KERN_WARNING, &pdev->dev, + "Applying B2 workarounds to unknown rev\n"); + hp_flags |= MV_HP_ERRATA_50XXB2; + break; } break; case chip_604x: case chip_608x: + hpriv->ops = &mv6xxx_ops; + switch (rev_id) { - case 0x0: - dev_printk(KERN_WARNING, &pdev->dev, - "Applying A1 workarounds to unknown rev 0\n"); - /* fall through */ - case 0x1: - hp_flags |= MV_HP_ERRATA_60X1A1; + case 0x7: + hp_flags |= MV_HP_ERRATA_60X1B2; + break; + case 0x9: + hp_flags |= MV_HP_ERRATA_60X1C0; break; default: dev_printk(KERN_WARNING, &pdev->dev, - "Applying B0 workarounds to future rev\n"); - /* fall through */ - case 0x2: - hp_flags |= MV_HP_ERRATA_60X1B0; + "Applying B2 workarounds to unknown rev\n"); + hp_flags |= MV_HP_ERRATA_60X1B2; break; } break; @@ -1617,7 +1641,7 @@ static int mv_cfg_errata(struct pci_dev *pdev, struct mv_host_priv *hpriv, } /** - * mv_host_init - Perform some early initialization of the host. + * mv_init_host - Perform some early initialization of the host. * @pdev: host PCI device * @probe_ent: early data struct representing the host * @@ -1627,7 +1651,7 @@ static int mv_cfg_errata(struct pci_dev *pdev, struct mv_host_priv *hpriv, * LOCKING: * Inherited from caller. */ -static int mv_host_init(struct pci_dev *pdev, struct ata_probe_ent *probe_ent, +static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent, unsigned int board_idx) { int rc = 0, n_hc, port, hc; @@ -1635,28 +1659,24 @@ static int mv_host_init(struct pci_dev *pdev, struct ata_probe_ent *probe_ent, void __iomem *port_mmio; struct mv_host_priv *hpriv = probe_ent->private_data; - rc = mv_cfg_errata(pdev, hpriv, board_idx); + /* global interrupt mask */ + writel(0, mmio + HC_MAIN_IRQ_MASK_OFS); + + rc = mv_chip_id(pdev, hpriv, board_idx); if (rc) goto done; n_hc = mv_get_hc_count(probe_ent->host_flags); probe_ent->n_ports = MV_PORTS_PER_HC * n_hc; - if (IS_50XX(hpriv)) { - for (port = 0; port < probe_ent->n_ports; port++) - mv_cfg_signal5(hpriv, port, mmio); - } else { - for (port = 0; port < probe_ent->n_ports; port++) - mv_cfg_signal6(hpriv, port, mmio); - } + for (port = 0; port < probe_ent->n_ports; port++) + hpriv->ops->read_preamp(hpriv, port, mmio); - if ((MV_FLAG_GLBL_SFT_RST & probe_ent->host_flags) && - mv_global_soft_reset(probe_ent->mmio_base)) { - rc = 1; + rc = hpriv->ops->reset_hc(hpriv, mmio); + if (rc) goto done; - } - mv_enable_leds(hpriv, mmio); + hpriv->ops->enable_leds(hpriv, mmio); for (port = 0; port < probe_ent->n_ports; port++) { port_mmio = mv_port_base(mmio, port); @@ -1794,7 +1814,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->private_data = hpriv; /* initialize adapter */ - rc = mv_host_init(pdev, probe_ent, board_idx); + rc = mv_init_host(pdev, probe_ent, board_idx); if (rc) { goto err_out_hpriv; } -- cgit v1.2.3 From 522479fb98c6667f081e75f87e298e413c0b1db8 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 12 Nov 2005 22:14:02 -0500 Subject: [libata sata_mv] hardware initialization work Implement flash reset and PCI reset on 50xx and 60xx. Implement LED enable on 50xx. --- drivers/scsi/sata_mv.c | 117 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 105 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 4ca4b35d002..180baa53206 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -50,6 +50,7 @@ enum { MV_PCI_REG_BASE = 0, MV_IRQ_COAL_REG_BASE = 0x18000, /* 6xxx part only */ MV_SATAHC0_REG_BASE = 0x20000, + MV_FLASH_CTL = 0x1046c, MV_GPIO_PORT_CTL = 0x104f0, MV_RESET_CFG = 0x180d8, @@ -87,12 +88,6 @@ enum { ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO), MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE, - chip_504x = 0, - chip_508x = 1, - chip_5080 = 2, - chip_604x = 3, - chip_608x = 4, - CRQB_FLAG_READ = (1 << 0), CRQB_TAG_SHIFT = 1, CRQB_CMD_ADDR_SHIFT = 8, @@ -112,8 +107,19 @@ enum { PCI_MASTER_EMPTY = (1 << 3), GLOB_SFT_RST = (1 << 4), - PCI_IRQ_CAUSE_OFS = 0x1d58, - PCI_IRQ_MASK_OFS = 0x1d5c, + MV_PCI_MODE = 0xd00, + MV_PCI_EXP_ROM_BAR_CTL = 0xd2c, + MV_PCI_DISC_TIMER = 0xd04, + MV_PCI_MSI_TRIGGER = 0xc38, + MV_PCI_SERR_MASK = 0xc28, + MV_PCI_XBAR_TMOUT = 0x1d04, + MV_PCI_ERR_LOW_ADDRESS = 0x1d40, + MV_PCI_ERR_HIGH_ADDRESS = 0x1d44, + MV_PCI_ERR_ATTRIBUTE = 0x1d48, + MV_PCI_ERR_COMMAND = 0x1d50, + + PCI_IRQ_CAUSE_OFS = 0x1d58, + PCI_IRQ_MASK_OFS = 0x1d5c, PCI_UNMASK_ALL_IRQS = 0x7fffff, /* bits 22-0 */ HC_MAIN_IRQ_CAUSE_OFS = 0x1d60, @@ -236,6 +242,14 @@ enum { EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U, }; +enum chip_type { + chip_504x, + chip_508x, + chip_5080, + chip_604x, + chip_608x, +}; + /* Command ReQuest Block: 32B */ struct mv_crqb { u32 sg_addr; @@ -284,6 +298,8 @@ struct mv_hw_ops { void (*read_preamp)(struct mv_host_priv *hpriv, int idx, void __iomem *mmio); int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio); + void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio); + void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio); }; struct mv_host_priv { @@ -311,12 +327,16 @@ static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio); static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio); +static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio); +static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio); static void mv6_phy_errata(struct ata_port *ap); static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio); static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio); +static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio); +static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio); static struct scsi_host_template mv_sht = { .module = THIS_MODULE, @@ -433,6 +453,8 @@ static const struct mv_hw_ops mv5xxx_ops = { .enable_leds = mv5_enable_leds, .read_preamp = mv5_read_preamp, .reset_hc = mv5_reset_hc, + .reset_flash = mv5_reset_flash, + .reset_bus = mv5_reset_bus, }; static const struct mv_hw_ops mv6xxx_ops = { @@ -440,6 +462,8 @@ static const struct mv_hw_ops mv6xxx_ops = { .enable_leds = mv6_enable_leds, .read_preamp = mv6_read_preamp, .reset_hc = mv6_reset_hc, + .reset_flash = mv6_reset_flash, + .reset_bus = mv_reset_pci_bus, }; /* @@ -655,9 +679,45 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) } } +#undef ZERO +#define ZERO(reg) writel(0, mmio + (reg)) +static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio) +{ + u32 tmp; + + tmp = readl(mmio + MV_PCI_MODE); + tmp &= 0xff00ffff; + writel(tmp, mmio + MV_PCI_MODE); + + ZERO(MV_PCI_DISC_TIMER); + ZERO(MV_PCI_MSI_TRIGGER); + writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT); + ZERO(HC_MAIN_IRQ_MASK_OFS); + ZERO(MV_PCI_SERR_MASK); + ZERO(PCI_IRQ_CAUSE_OFS); + ZERO(PCI_IRQ_MASK_OFS); + ZERO(MV_PCI_ERR_LOW_ADDRESS); + ZERO(MV_PCI_ERR_HIGH_ADDRESS); + ZERO(MV_PCI_ERR_ATTRIBUTE); + ZERO(MV_PCI_ERR_COMMAND); +} +#undef ZERO + +static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio) +{ + u32 tmp; + + mv5_reset_flash(hpriv, mmio); + + tmp = readl(mmio + MV_GPIO_PORT_CTL); + tmp &= 0x3; + tmp |= (1 << 5) | (1 << 6); + writel(tmp, mmio + MV_GPIO_PORT_CTL); +} + /** - * mv_global_soft_reset - Perform the 6xxx global soft reset - * @mmio_base: base address of the HBA + * mv6_reset_hc - Perform the 6xxx global soft reset + * @mmio: base address of the HBA * * This routine only applies to 6xxx parts. * @@ -1273,6 +1333,29 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, return IRQ_RETVAL(handled); } +static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio) +{ + u8 rev_id; + int early_5080; + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); + + early_5080 = (pdev->device == 0x5080) && (rev_id == 0); + + if (!early_5080) { + u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL); + tmp |= (1 << 0); + writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL); + } + + mv_reset_pci_bus(pdev, mmio); +} + +static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio) +{ + writel(0x0fcfffff, mmio + MV_FLASH_CTL); +} + static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio) { @@ -1281,7 +1364,15 @@ static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx, static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) { - /* FIXME */ + u32 tmp; + + writel(0, mmio + MV_GPIO_PORT_CTL); + + /* FIXME: handle MV_HP_ERRATA_50XXB2 errata */ + + tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL); + tmp |= ~(1 << 0); + writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL); } static void mv5_phy_errata(struct ata_port *ap) @@ -1564,7 +1655,7 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) } static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv, - unsigned int board_idx) + unsigned int board_idx) { u8 rev_id; u32 hp_flags = hpriv->hp_flags; @@ -1676,6 +1767,8 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent, if (rc) goto done; + hpriv->ops->reset_flash(hpriv, mmio); + hpriv->ops->reset_bus(pdev, mmio); hpriv->ops->enable_leds(hpriv, mmio); for (port = 0; port < probe_ent->n_ports; port++) { -- cgit v1.2.3 From 101ffae26c23ea928fce6d31a8b4901327d91a15 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 12 Nov 2005 22:17:49 -0500 Subject: [libata sata_mv] move code around No content changes. Move 60xx code to be closer to other 60xx code. --- drivers/scsi/sata_mv.c | 200 ++++++++++++++++++++++++------------------------- 1 file changed, 100 insertions(+), 100 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 180baa53206..f695d0bbb5c 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -679,106 +679,6 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) } } -#undef ZERO -#define ZERO(reg) writel(0, mmio + (reg)) -static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio) -{ - u32 tmp; - - tmp = readl(mmio + MV_PCI_MODE); - tmp &= 0xff00ffff; - writel(tmp, mmio + MV_PCI_MODE); - - ZERO(MV_PCI_DISC_TIMER); - ZERO(MV_PCI_MSI_TRIGGER); - writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT); - ZERO(HC_MAIN_IRQ_MASK_OFS); - ZERO(MV_PCI_SERR_MASK); - ZERO(PCI_IRQ_CAUSE_OFS); - ZERO(PCI_IRQ_MASK_OFS); - ZERO(MV_PCI_ERR_LOW_ADDRESS); - ZERO(MV_PCI_ERR_HIGH_ADDRESS); - ZERO(MV_PCI_ERR_ATTRIBUTE); - ZERO(MV_PCI_ERR_COMMAND); -} -#undef ZERO - -static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio) -{ - u32 tmp; - - mv5_reset_flash(hpriv, mmio); - - tmp = readl(mmio + MV_GPIO_PORT_CTL); - tmp &= 0x3; - tmp |= (1 << 5) | (1 << 6); - writel(tmp, mmio + MV_GPIO_PORT_CTL); -} - -/** - * mv6_reset_hc - Perform the 6xxx global soft reset - * @mmio: base address of the HBA - * - * This routine only applies to 6xxx parts. - * - * LOCKING: - * Inherited from caller. - */ -static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio) -{ - void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS; - int i, rc = 0; - u32 t; - - /* Following procedure defined in PCI "main command and status - * register" table. - */ - t = readl(reg); - writel(t | STOP_PCI_MASTER, reg); - - for (i = 0; i < 1000; i++) { - udelay(1); - t = readl(reg); - if (PCI_MASTER_EMPTY & t) { - break; - } - } - if (!(PCI_MASTER_EMPTY & t)) { - printk(KERN_ERR DRV_NAME ": PCI master won't flush\n"); - rc = 1; - goto done; - } - - /* set reset */ - i = 5; - do { - writel(t | GLOB_SFT_RST, reg); - t = readl(reg); - udelay(1); - } while (!(GLOB_SFT_RST & t) && (i-- > 0)); - - if (!(GLOB_SFT_RST & t)) { - printk(KERN_ERR DRV_NAME ": can't set global reset\n"); - rc = 1; - goto done; - } - - /* clear reset and *reenable the PCI master* (not mentioned in spec) */ - i = 5; - do { - writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg); - t = readl(reg); - udelay(1); - } while ((GLOB_SFT_RST & t) && (i-- > 0)); - - if (GLOB_SFT_RST & t) { - printk(KERN_ERR DRV_NAME ": can't clear global reset\n"); - rc = 1; - } -done: - return rc; -} - /** * mv_host_stop - Host specific cleanup/stop routine. * @host_set: host data structure @@ -1386,6 +1286,106 @@ static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio) return 1; } +#undef ZERO +#define ZERO(reg) writel(0, mmio + (reg)) +static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio) +{ + u32 tmp; + + tmp = readl(mmio + MV_PCI_MODE); + tmp &= 0xff00ffff; + writel(tmp, mmio + MV_PCI_MODE); + + ZERO(MV_PCI_DISC_TIMER); + ZERO(MV_PCI_MSI_TRIGGER); + writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT); + ZERO(HC_MAIN_IRQ_MASK_OFS); + ZERO(MV_PCI_SERR_MASK); + ZERO(PCI_IRQ_CAUSE_OFS); + ZERO(PCI_IRQ_MASK_OFS); + ZERO(MV_PCI_ERR_LOW_ADDRESS); + ZERO(MV_PCI_ERR_HIGH_ADDRESS); + ZERO(MV_PCI_ERR_ATTRIBUTE); + ZERO(MV_PCI_ERR_COMMAND); +} +#undef ZERO + +static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio) +{ + u32 tmp; + + mv5_reset_flash(hpriv, mmio); + + tmp = readl(mmio + MV_GPIO_PORT_CTL); + tmp &= 0x3; + tmp |= (1 << 5) | (1 << 6); + writel(tmp, mmio + MV_GPIO_PORT_CTL); +} + +/** + * mv6_reset_hc - Perform the 6xxx global soft reset + * @mmio: base address of the HBA + * + * This routine only applies to 6xxx parts. + * + * LOCKING: + * Inherited from caller. + */ +static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio) +{ + void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS; + int i, rc = 0; + u32 t; + + /* Following procedure defined in PCI "main command and status + * register" table. + */ + t = readl(reg); + writel(t | STOP_PCI_MASTER, reg); + + for (i = 0; i < 1000; i++) { + udelay(1); + t = readl(reg); + if (PCI_MASTER_EMPTY & t) { + break; + } + } + if (!(PCI_MASTER_EMPTY & t)) { + printk(KERN_ERR DRV_NAME ": PCI master won't flush\n"); + rc = 1; + goto done; + } + + /* set reset */ + i = 5; + do { + writel(t | GLOB_SFT_RST, reg); + t = readl(reg); + udelay(1); + } while (!(GLOB_SFT_RST & t) && (i-- > 0)); + + if (!(GLOB_SFT_RST & t)) { + printk(KERN_ERR DRV_NAME ": can't set global reset\n"); + rc = 1; + goto done; + } + + /* clear reset and *reenable the PCI master* (not mentioned in spec) */ + i = 5; + do { + writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg); + t = readl(reg); + udelay(1); + } while ((GLOB_SFT_RST & t) && (i-- > 0)); + + if (GLOB_SFT_RST & t) { + printk(KERN_ERR DRV_NAME ": can't clear global reset\n"); + rc = 1; + } +done: + return rc; +} + static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio) { -- cgit v1.2.3 From 2a47ce06d534692f9bd2bf4e90a20fc9b1054c39 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 12 Nov 2005 23:05:14 -0500 Subject: [libata sata_mv] call phy fixups during init, as well as phy reset --- drivers/scsi/sata_mv.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index f695d0bbb5c..5defd056fe1 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -293,7 +293,8 @@ struct mv_port_signal { struct mv_host_priv; struct mv_hw_ops { - void (*phy_errata)(struct ata_port *ap); + void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio, + unsigned int port); void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio); void (*read_preamp)(struct mv_host_priv *hpriv, int idx, void __iomem *mmio); @@ -322,7 +323,8 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, static void mv_eng_timeout(struct ata_port *ap); static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -static void mv5_phy_errata(struct ata_port *ap); +static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, + unsigned int port); static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio); @@ -330,7 +332,8 @@ static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio); -static void mv6_phy_errata(struct ata_port *ap); +static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, + unsigned int port); static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio); @@ -1275,7 +1278,8 @@ static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL); } -static void mv5_phy_errata(struct ata_port *ap) +static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, + unsigned int port) { /* FIXME */ } @@ -1411,11 +1415,10 @@ static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) writel(0x00000060, mmio + MV_GPIO_PORT_CTL); } -static void mv6_phy_errata(struct ata_port *ap) +static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *port_mmio, + unsigned int port) { - struct mv_host_priv *hpriv = ap->host_set->private_data; u32 hp_flags = hpriv->hp_flags; - void __iomem *port_mmio = mv_ap_base(ap); int fix_phy_mode2 = hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0); int fix_phy_mode4 = @@ -1463,8 +1466,8 @@ static void mv6_phy_errata(struct ata_port *ap) m2 = readl(port_mmio + PHY_MODE2); m2 &= ~MV_M2_PREAMP_MASK; - m2 |= hpriv->signal[ap->port_no].amps; - m2 |= hpriv->signal[ap->port_no].pre; + m2 |= hpriv->signal[port].amps; + m2 |= hpriv->signal[port].pre; m2 &= ~(1 << 16); writel(m2, port_mmio + PHY_MODE2); @@ -1509,7 +1512,7 @@ static void mv_phy_reset(struct ata_port *ap) */ writelfl(0, port_mmio + EDMA_CMD_OFS); - hpriv->ops->phy_errata(ap); + hpriv->ops->phy_errata(hpriv, port_mmio, ap->port_no); DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x " "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), @@ -1747,7 +1750,6 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent, { int rc = 0, n_hc, port, hc; void __iomem *mmio = probe_ent->mmio_base; - void __iomem *port_mmio; struct mv_host_priv *hpriv = probe_ent->private_data; /* global interrupt mask */ @@ -1772,7 +1774,19 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent, hpriv->ops->enable_leds(hpriv, mmio); for (port = 0; port < probe_ent->n_ports; port++) { - port_mmio = mv_port_base(mmio, port); + void __iomem *port_mmio = mv_port_base(mmio, port); + + if (IS_60XX(hpriv)) { + u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL); + ifctl |= (1 << 12); + writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL); + } + + hpriv->ops->phy_errata(hpriv, port_mmio, port); + } + + for (port = 0; port < probe_ent->n_ports; port++) { + void __iomem *port_mmio = mv_port_base(mmio, port); mv_port_init(&probe_ent->port[port], port_mmio); } -- cgit v1.2.3 From c9d39130123238ac18478a42e25cb7996eacfcc0 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sun, 13 Nov 2005 17:47:51 -0500 Subject: [libata sata_mv] fix tons of 50XX bugs --- drivers/scsi/sata_mv.c | 301 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 252 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 5defd056fe1..722ab537b7a 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -158,6 +158,9 @@ enum { PHY_MODE3 = 0x310, PHY_MODE4 = 0x314, PHY_MODE2 = 0x330, + MV5_PHY_MODE = 0x74, + MV5_LT_MODE = 0x30, + MV5_PHY_CTL = 0x0C, SATA_INTERFACE_CTL = 0x050, MV_M2_PREAMP_MASK = 0x7e0, @@ -214,6 +217,7 @@ enum { EDMA_DS = (1 << 1), ATA_RST = (1 << 2), + EDMA_IORDY_TMOUT = 0x34, EDMA_ARB_CFG = 0x38, /* Host private flags (hp_flags) */ @@ -229,6 +233,7 @@ enum { MV_PP_FLAG_EDMA_DS_ACT = (1 << 1), }; +#define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX) #define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0) enum { @@ -298,7 +303,8 @@ struct mv_hw_ops { void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio); void (*read_preamp)(struct mv_host_priv *hpriv, int idx, void __iomem *mmio); - int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio); + int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio, + unsigned int n_hc); void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio); void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio); }; @@ -312,6 +318,8 @@ struct mv_host_priv { static void mv_irq_clear(struct ata_port *ap); static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in); static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); +static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in); +static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); static void mv_phy_reset(struct ata_port *ap); static void mv_host_stop(struct ata_host_set *host_set); static int mv_port_start(struct ata_port *ap); @@ -328,7 +336,8 @@ static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio); -static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio); +static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, + unsigned int n_hc); static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio); @@ -337,9 +346,13 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio); -static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio); +static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, + unsigned int n_hc); static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio); +static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio, + unsigned int port_no); +static void mv_stop_and_reset(struct ata_port *ap); static struct scsi_host_template mv_sht = { .module = THIS_MODULE, @@ -361,7 +374,34 @@ static struct scsi_host_template mv_sht = { .ordered_flush = 1, }; -static const struct ata_port_operations mv_ops = { +static const struct ata_port_operations mv5_ops = { + .port_disable = ata_port_disable, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .phy_reset = mv_phy_reset, + + .qc_prep = mv_qc_prep, + .qc_issue = mv_qc_issue, + + .eng_timeout = mv_eng_timeout, + + .irq_handler = mv_interrupt, + .irq_clear = mv_irq_clear, + + .scr_read = mv5_scr_read, + .scr_write = mv5_scr_write, + + .port_start = mv_port_start, + .port_stop = mv_port_stop, + .host_stop = mv_host_stop, +}; + +static const struct ata_port_operations mv6_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -393,29 +433,29 @@ static struct ata_port_info mv_port_info[] = { .sht = &mv_sht, .host_flags = MV_COMMON_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ - .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */ - .port_ops = &mv_ops, + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &mv5_ops, }, { /* chip_508x */ .sht = &mv_sht, .host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), .pio_mask = 0x1f, /* pio0-4 */ - .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */ - .port_ops = &mv_ops, + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &mv5_ops, }, { /* chip_5080 */ .sht = &mv_sht, .host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), .pio_mask = 0x1f, /* pio0-4 */ - .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */ - .port_ops = &mv_ops, + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &mv5_ops, }, { /* chip_604x */ .sht = &mv_sht, .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 */ - .port_ops = &mv_ops, + .port_ops = &mv6_ops, }, { /* chip_608x */ .sht = &mv_sht, @@ -423,17 +463,15 @@ static struct ata_port_info mv_port_info[] = { MV_FLAG_DUAL_HC), .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 */ - .port_ops = &mv_ops, + .port_ops = &mv6_ops, }, }; static const struct pci_device_id mv_pci_tbl[] = { -#if 0 /* unusably broken right now */ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x}, {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x}, {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_5080}, {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x}, -#endif {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x}, {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x}, @@ -484,11 +522,27 @@ static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc) return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ)); } +static inline unsigned int mv_hc_from_port(unsigned int port) +{ + return port >> MV_PORT_HC_SHIFT; +} + +static inline unsigned int mv_hardport_from_port(unsigned int port) +{ + return port & MV_PORT_MASK; +} + +static inline void __iomem *mv_hc_base_from_port(void __iomem *base, + unsigned int port) +{ + return mv_hc_base(base, mv_hc_from_port(port)); +} + static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port) { - return (mv_hc_base(base, port >> MV_PORT_HC_SHIFT) + + return mv_hc_base_from_port(base, port) + MV_SATAHC_ARBTR_REG_SZ + - ((port & MV_PORT_MASK) * MV_PORT_REG_SZ)); + (mv_hardport_from_port(port) * MV_PORT_REG_SZ); } static inline void __iomem *mv_ap_base(struct ata_port *ap) @@ -1089,7 +1143,7 @@ static void mv_err_intr(struct ata_port *ap) /* check for fatal here and recover if needed */ if (EDMA_ERR_FATAL & edma_err_cause) { - mv_phy_reset(ap); + mv_stop_and_reset(ap); } } @@ -1236,6 +1290,51 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, return IRQ_RETVAL(handled); } +static void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port) +{ + void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port); + unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL; + + return hc_mmio + ofs; +} + +static unsigned int mv5_scr_offset(unsigned int sc_reg_in) +{ + unsigned int ofs; + + switch (sc_reg_in) { + case SCR_STATUS: + case SCR_ERROR: + case SCR_CONTROL: + ofs = sc_reg_in * sizeof(u32); + break; + default: + ofs = 0xffffffffU; + break; + } + return ofs; +} + +static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in) +{ + void __iomem *mmio = mv5_phy_base(ap->host_set->mmio_base, ap->port_no); + unsigned int ofs = mv5_scr_offset(sc_reg_in); + + if (ofs != 0xffffffffU) + return readl(mmio + ofs); + else + return (u32) ofs; +} + +static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) +{ + void __iomem *mmio = mv5_phy_base(ap->host_set->mmio_base, ap->port_no); + unsigned int ofs = mv5_scr_offset(sc_reg_in); + + if (ofs != 0xffffffffU) + writelfl(val, mmio + ofs); +} + static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio) { u8 rev_id; @@ -1262,7 +1361,13 @@ static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio) static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio) { - /* FIXME */ + void __iomem *phy_mmio = mv5_phy_base(mmio, idx); + u32 tmp; + + tmp = readl(phy_mmio + MV5_PHY_MODE); + + hpriv->signal[idx].pre = tmp & 0x1800; /* bits 12:11 */ + hpriv->signal[idx].amps = tmp & 0xe0; /* bits 7:5 */ } static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) @@ -1281,13 +1386,90 @@ static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, unsigned int port) { - /* FIXME */ + void __iomem *phy_mmio = mv5_phy_base(mmio, port); + const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5); + u32 tmp; + int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0); + + if (fix_apm_sq) { + tmp = readl(phy_mmio + MV5_LT_MODE); + tmp |= (1 << 19); + writel(tmp, phy_mmio + MV5_LT_MODE); + + tmp = readl(phy_mmio + MV5_PHY_CTL); + tmp &= ~0x3; + tmp |= 0x1; + writel(tmp, phy_mmio + MV5_PHY_CTL); + } + + tmp = readl(phy_mmio + MV5_PHY_MODE); + tmp &= ~mask; + tmp |= hpriv->signal[port].pre; + tmp |= hpriv->signal[port].amps; + writel(tmp, phy_mmio + MV5_PHY_MODE); +} + + +#undef ZERO +#define ZERO(reg) writel(0, port_mmio + (reg)) +static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio, + unsigned int port) +{ + void __iomem *port_mmio = mv_port_base(mmio, port); + + writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS); + + mv_channel_reset(hpriv, mmio, port); + + ZERO(0x028); /* command */ + writel(0x11f, port_mmio + EDMA_CFG_OFS); + ZERO(0x004); /* timer */ + ZERO(0x008); /* irq err cause */ + ZERO(0x00c); /* irq err mask */ + ZERO(0x010); /* rq bah */ + ZERO(0x014); /* rq inp */ + ZERO(0x018); /* rq outp */ + ZERO(0x01c); /* respq bah */ + ZERO(0x024); /* respq outp */ + ZERO(0x020); /* respq inp */ + ZERO(0x02c); /* test control */ + writel(0xbc, port_mmio + EDMA_IORDY_TMOUT); } +#undef ZERO -static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio) +#define ZERO(reg) writel(0, hc_mmio + (reg)) +static void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio, + unsigned int hc) { - /* FIXME */ - return 1; + void __iomem *hc_mmio = mv_hc_base(mmio, hc); + u32 tmp; + + ZERO(0x00c); + ZERO(0x010); + ZERO(0x014); + ZERO(0x018); + + tmp = readl(hc_mmio + 0x20); + tmp &= 0x1c1c1c1c; + tmp |= 0x03030303; + writel(tmp, hc_mmio + 0x20); +} +#undef ZERO + +static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, + unsigned int n_hc) +{ + unsigned int hc, port; + + for (hc = 0; hc < n_hc; hc++) { + for (port = 0; port < MV_PORTS_PER_HC; port++) + mv5_reset_hc_port(hpriv, mmio, + (hc * MV_PORTS_PER_HC) + port); + + mv5_reset_one_hc(hpriv, mmio, hc); + } + + return 0; } #undef ZERO @@ -1335,7 +1517,8 @@ static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio) * LOCKING: * Inherited from caller. */ -static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio) +static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, + unsigned int n_hc) { void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS; int i, rc = 0; @@ -1415,9 +1598,11 @@ static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) writel(0x00000060, mmio + MV_GPIO_PORT_CTL); } -static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *port_mmio, +static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, unsigned int port) { + void __iomem *port_mmio = mv_port_base(mmio, port); + u32 hp_flags = hpriv->hp_flags; int fix_phy_mode2 = hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0); @@ -1473,6 +1658,44 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *port_mmio, writel(m2, port_mmio + PHY_MODE2); } +static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio, + unsigned int port_no) +{ + void __iomem *port_mmio = mv_port_base(mmio, port_no); + + writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS); + + if (IS_60XX(hpriv)) { + u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL); + ifctl |= (1 << 12) | (1 << 7); + writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL); + } + + udelay(25); /* allow reset propagation */ + + /* Spec never mentions clearing the bit. Marvell's driver does + * clear the bit, however. + */ + writelfl(0, port_mmio + EDMA_CMD_OFS); + + hpriv->ops->phy_errata(hpriv, mmio, port_no); + + if (IS_50XX(hpriv)) + mdelay(1); +} + +static void mv_stop_and_reset(struct ata_port *ap) +{ + struct mv_host_priv *hpriv = ap->host_set->private_data; + void __iomem *mmio = ap->host_set->mmio_base; + + mv_stop_dma(ap); + + mv_channel_reset(hpriv, mmio, ap->port_no); + + mv_phy_reset(ap); +} + /** * mv_phy_reset - Perform eDMA reset followed by COMRESET * @ap: ATA channel to manipulate @@ -1487,7 +1710,6 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *port_mmio, static void mv_phy_reset(struct ata_port *ap) { struct mv_port_priv *pp = ap->private_data; - struct mv_host_priv *hpriv = ap->host_set->private_data; void __iomem *port_mmio = mv_ap_base(ap); struct ata_taskfile tf; struct ata_device *dev = &ap->device[0]; @@ -1495,25 +1717,6 @@ static void mv_phy_reset(struct ata_port *ap) VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio); - mv_stop_dma(ap); - - writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS); - - if (IS_60XX(hpriv)) { - u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL); - ifctl |= (1 << 12) | (1 << 7); - writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL); - } - - udelay(25); /* allow reset propagation */ - - /* Spec never mentions clearing the bit. Marvell's driver does - * clear the bit, however. - */ - writelfl(0, port_mmio + EDMA_CMD_OFS); - - hpriv->ops->phy_errata(hpriv, port_mmio, ap->port_no); - DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x " "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); @@ -1589,7 +1792,7 @@ static void mv_eng_timeout(struct ata_port *ap) &qc->scsicmd->cmnd); mv_err_intr(ap); - mv_phy_reset(ap); + mv_stop_and_reset(ap); if (!qc) { printk(KERN_ERR "ata%u: BUG: timeout without command\n", @@ -1765,7 +1968,7 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent, for (port = 0; port < probe_ent->n_ports; port++) hpriv->ops->read_preamp(hpriv, port, mmio); - rc = hpriv->ops->reset_hc(hpriv, mmio); + rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc); if (rc) goto done; @@ -1774,15 +1977,15 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent, hpriv->ops->enable_leds(hpriv, mmio); for (port = 0; port < probe_ent->n_ports; port++) { - void __iomem *port_mmio = mv_port_base(mmio, port); - if (IS_60XX(hpriv)) { + void __iomem *port_mmio = mv_port_base(mmio, port); + u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL); ifctl |= (1 << 12); writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL); } - hpriv->ops->phy_errata(hpriv, port_mmio, port); + hpriv->ops->phy_errata(hpriv, mmio, port); } for (port = 0; port < probe_ent->n_ports; port++) { -- cgit v1.2.3 From d10cb35a876c72b4b6711a366e341a1e4d8aa709 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 16 Nov 2005 16:56:49 +0900 Subject: [PATCH] sil24: add constants Adds constants for ATAPI support to sata_sil24. This patch is originally from Jeff Garzik . Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/sata_sil24.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 55e744d6db8..cb1933a3bd5 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -139,6 +139,7 @@ enum { PORT_CS_DEV_RST = (1 << 1), /* device reset */ PORT_CS_INIT = (1 << 2), /* port initialize */ PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */ + PORT_CS_CDB16 = (1 << 5), /* 0=12b cdb, 1=16b cdb */ PORT_CS_RESUME = (1 << 6), /* port resume */ PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */ PORT_CS_PM_EN = (1 << 13), /* port multiplier enable */ @@ -188,11 +189,29 @@ enum { PORT_CERR_XFR_PCIPERR = 35, /* PSD ecode 11 - PCI prity err during transfer */ PORT_CERR_SENDSERVICE = 36, /* FIS received while sending service */ + /* bits of PRB control field */ + PRB_CTRL_PROTOCOL = (1 << 0), /* override def. ATA protocol */ + PRB_CTRL_PACKET_READ = (1 << 4), /* PACKET cmd read */ + PRB_CTRL_PACKET_WRITE = (1 << 5), /* PACKET cmd write */ + PRB_CTRL_NIEN = (1 << 6), /* Mask completion irq */ + PRB_CTRL_SRST = (1 << 7), /* Soft reset request (ign BSY?) */ + + /* PRB protocol field */ + PRB_PROT_PACKET = (1 << 0), + PRB_PROT_TCQ = (1 << 1), + PRB_PROT_NCQ = (1 << 2), + PRB_PROT_READ = (1 << 3), + PRB_PROT_WRITE = (1 << 4), + PRB_PROT_TRANSPARENT = (1 << 5), + /* * Other constants */ SGE_TRM = (1 << 31), /* Last SGE in chain */ - PRB_SOFT_RST = (1 << 7), /* Soft reset request (ign BSY?) */ + SGE_LNK = (1 << 30), /* linked list + Points to SGT, not SGE */ + SGE_DRD = (1 << 29), /* discard data read (/dev/null) + data address ignored */ /* board id */ BID_SIL3124 = 0, -- cgit v1.2.3 From 75b1f2f865c6e6c6c04e2779750192b8d3d504e8 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Wed, 16 Nov 2005 17:06:18 +0800 Subject: [PATCH] libata: honor the transfer cycle time speficied by the EIDE device The following code segment is not functional because the transfer cycle time speficied by the EIDE device is later overwritten by ata_timing_quantize(): /* * If the drive is an EIDE drive, it can tell us it needs extended * PIO/MW_DMA cycle timing. */ if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */ memset(&p, 0, sizeof(p)); (snip) ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B); <== uninitialized "t" is used here } /* * Convert the timing to bus clock counts. */ ata_timing_quantize(s, t, T, UT); <== t is overwritten by quantized s The patch has been submitted for ide-timing.h before: http://marc.theaimsgroup.com/?l=linux-ide&m=110820013425454&w=2 Resubmitted for libata. Changes: - Minor fix to honor the following transfer cycle time speficied by the device - id[65]: Minimum Multiword DMA transfer cycle time per word - id[67]: Minimum PIO transfer cycle time without flow control - id[68]: Minimum PIO transfer cycle time with IORDY Signed-off-by: Albert Lee ======= Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index ba1eb8b38e0..bb604dfbdef 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1570,11 +1570,13 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, /* * Find the mode. - */ + */ if (!(s = ata_timing_find_mode(speed))) return -EINVAL; + memcpy(t, s, sizeof(*s)); + /* * If the drive is an EIDE drive, it can tell us it needs extended * PIO/MW_DMA cycle timing. @@ -1595,7 +1597,7 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, * Convert the timing to bus clock counts. */ - ata_timing_quantize(s, t, T, UT); + ata_timing_quantize(t, t, T, UT); /* * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T -- cgit v1.2.3 From c2cd76ff106b8bd9c0a754c6439c74e86fd2aba7 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 16 Nov 2005 09:23:30 -0500 Subject: [libata ahci] tone down ATAPI errors ATA devices don't generate many errors, so the preferred method is to printk() when they occur. ATAPI devices generate tons of exceptions during the normal course of operation, so this change skips logging the most common class of errors. --- drivers/scsi/ahci.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 894e7113e0b..5386c0d6101 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -558,23 +558,25 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) pp->cmd_slot[0].opts |= cpu_to_le32(n_elem << 16); } -static void ahci_intr_error(struct ata_port *ap, u32 irq_stat) +static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) { void __iomem *mmio = ap->host_set->mmio_base; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); u32 tmp; int work; - printk(KERN_WARNING "ata%u: port reset, " - "p_is %x is %x pis %x cmd %x tf %x ss %x se %x\n", - ap->id, - irq_stat, - readl(mmio + HOST_IRQ_STAT), - readl(port_mmio + PORT_IRQ_STAT), - readl(port_mmio + PORT_CMD), - readl(port_mmio + PORT_TFDATA), - readl(port_mmio + PORT_SCR_STAT), - readl(port_mmio + PORT_SCR_ERR)); + if ((ap->device[0].class != ATA_DEV_ATAPI) || + ((irq_stat & PORT_IRQ_TF_ERR) == 0)) + printk(KERN_WARNING "ata%u: port reset, " + "p_is %x is %x pis %x cmd %x tf %x ss %x se %x\n", + ap->id, + irq_stat, + readl(mmio + HOST_IRQ_STAT), + readl(port_mmio + PORT_IRQ_STAT), + readl(port_mmio + PORT_CMD), + readl(port_mmio + PORT_TFDATA), + readl(port_mmio + PORT_SCR_STAT), + readl(port_mmio + PORT_SCR_ERR)); /* stop DMA */ tmp = readl(port_mmio + PORT_CMD); @@ -632,7 +634,7 @@ static void ahci_eng_timeout(struct ata_port *ap) printk(KERN_ERR "ata%u: BUG: timeout without command\n", ap->id); } else { - ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT)); + ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT)); /* hack alert! We cannot use the supplied completion * function from inside the ->eh_strategy_handler() thread. @@ -677,7 +679,7 @@ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc) err_mask = AC_ERR_HOST_BUS; /* command processing has stopped due to error; restart */ - ahci_intr_error(ap, status); + ahci_restart_port(ap, status); if (qc) ata_qc_complete(qc, err_mask); -- cgit v1.2.3 From 7bdd720869ff75700b48b132ee71852615b55808 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 16 Nov 2005 11:06:59 -0500 Subject: [libata] bump versions --- drivers/scsi/ahci.c | 2 +- drivers/scsi/ata_piix.c | 2 +- drivers/scsi/libata.h | 2 +- drivers/scsi/sata_promise.c | 2 +- drivers/scsi/sata_qstor.c | 2 +- drivers/scsi/sata_svw.c | 2 +- drivers/scsi/sata_sx4.c | 2 +- drivers/scsi/sata_vsc.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 5386c0d6101..83467a05dc8 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -48,7 +48,7 @@ #include #define DRV_NAME "ahci" -#define DRV_VERSION "1.01" +#define DRV_VERSION "1.2" enum { diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 855428ff37e..333d69dd84e 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -50,7 +50,7 @@ #include #define DRV_NAME "ata_piix" -#define DRV_VERSION "1.04" +#define DRV_VERSION "1.05" enum { PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 74a84e0ec0a..8ebaa694d18 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -29,7 +29,7 @@ #define __LIBATA_H__ #define DRV_NAME "libata" -#define DRV_VERSION "1.12" /* must be exactly four chars */ +#define DRV_VERSION "1.20" /* must be exactly four chars */ struct ata_scsi_args { u16 *id; diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index 242d906987a..8a8e3e3ef0e 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -46,7 +46,7 @@ #include "sata_promise.h" #define DRV_NAME "sata_promise" -#define DRV_VERSION "1.02" +#define DRV_VERSION "1.03" enum { diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c index 4a6d3067d23..a8987f5ff5c 100644 --- a/drivers/scsi/sata_qstor.c +++ b/drivers/scsi/sata_qstor.c @@ -41,7 +41,7 @@ #include #define DRV_NAME "sata_qstor" -#define DRV_VERSION "0.04" +#define DRV_VERSION "0.05" enum { QS_PORTS = 4, diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index 57e5a9d964c..6e7f7c83a75 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -54,7 +54,7 @@ #endif /* CONFIG_PPC_OF */ #define DRV_NAME "sata_svw" -#define DRV_VERSION "1.06" +#define DRV_VERSION "1.07" /* Taskfile registers offsets */ #define K2_SATA_TF_CMD_OFFSET 0x00 diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index b4bbe48acab..dcc3ad9a9d6 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -46,7 +46,7 @@ #include "sata_promise.h" #define DRV_NAME "sata_sx4" -#define DRV_VERSION "0.7" +#define DRV_VERSION "0.8" enum { diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 77a6e4b9262..fcfa486965b 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -47,7 +47,7 @@ #include #define DRV_NAME "sata_vsc" -#define DRV_VERSION "1.0" +#define DRV_VERSION "1.1" /* Interrupt register offsets (from chip base address) */ #define VSC_SATA_INT_STAT_OFFSET 0x00 -- cgit v1.2.3 From 64f043d80752a8e5f0d55255e7bb9a1a05af206f Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 17 Nov 2005 10:50:01 -0500 Subject: [libata] add timeout to commands for which we call wait_completion() --- drivers/scsi/libata-core.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index bb604dfbdef..665ae79e1fd 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1046,6 +1046,30 @@ static unsigned int ata_pio_modes(const struct ata_device *adev) return modes; } +static int ata_qc_wait_err(struct ata_queued_cmd *qc, + struct completion *wait) +{ + int rc = 0; + + if (wait_for_completion_timeout(wait, 30 * HZ) < 1) { + /* timeout handling */ + unsigned int err_mask = ac_err_mask(ata_chk_status(qc->ap)); + + if (!err_mask) { + printk(KERN_WARNING "ata%u: slow completion (cmd %x)\n", + qc->ap->id, qc->tf.command); + } else { + printk(KERN_WARNING "ata%u: qc timeout (cmd %x)\n", + qc->ap->id, qc->tf.command); + rc = -EIO; + } + + ata_qc_complete(qc, err_mask); + } + + return rc; +} + /** * ata_dev_identify - obtain IDENTIFY x DEVICE page * @ap: port on which device we wish to probe resides @@ -1125,7 +1149,7 @@ retry: if (rc) goto err_out; else - wait_for_completion(&wait); + ata_qc_wait_err(qc, &wait); spin_lock_irqsave(&ap->host_set->lock, flags); ap->ops->tf_read(ap, &qc->tf); @@ -2269,7 +2293,7 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev) if (rc) ata_port_disable(ap); else - wait_for_completion(&wait); + ata_qc_wait_err(qc, &wait); DPRINTK("EXIT\n"); } @@ -2317,7 +2341,7 @@ static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev) if (rc) goto err_out; - wait_for_completion(&wait); + ata_qc_wait_err(qc, &wait); swap_buf_le16(dev->id, ATA_ID_WORDS); @@ -2373,7 +2397,7 @@ static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev) if (rc) ata_port_disable(ap); else - wait_for_completion(&wait); + ata_qc_wait_err(qc, &wait); DPRINTK("EXIT\n"); } -- cgit v1.2.3 From 22374677d18c5eeefd3a283431d312b8c44fef02 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 17 Nov 2005 10:59:48 -0500 Subject: [libata sata_mv] SATA probe, DMA boundary fixes - DMA boundary was being handled incorrectly. Copied the code from ata_fill_sg(), since Marvell has the same DMA boundary needs. (we can't use ata_fill_sg directly since we have different hardware descriptors) - cleaned up the SATA phy reset code, to deal with various errata --- drivers/scsi/sata_mv.c | 88 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 70 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 722ab537b7a..ee0634da087 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -321,6 +321,7 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in); static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); static void mv_phy_reset(struct ata_port *ap); +static void __mv_phy_reset(struct ata_port *ap, int can_sleep); static void mv_host_stop(struct ata_host_set *host_set); static int mv_port_start(struct ata_port *ap); static void mv_port_stop(struct ata_port *ap); @@ -362,7 +363,7 @@ static struct scsi_host_template mv_sht = { .eh_strategy_handler = ata_scsi_error, .can_queue = MV_USE_Q_DEPTH, .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = MV_MAX_SG_CT, + .sg_tablesize = MV_MAX_SG_CT / 2, .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, @@ -893,20 +894,30 @@ static void mv_fill_sg(struct ata_queued_cmd *qc) struct scatterlist *sg; ata_for_each_sg(sg, qc) { - u32 sg_len; dma_addr_t addr; + u32 sg_len, len, offset; addr = sg_dma_address(sg); sg_len = sg_dma_len(sg); - pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff); - pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16); - assert(0 == (sg_len & ~MV_DMA_BOUNDARY)); - pp->sg_tbl[i].flags_size = cpu_to_le32(sg_len); - if (ata_sg_is_last(sg, qc)) - pp->sg_tbl[i].flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL); + while (sg_len) { + offset = addr & MV_DMA_BOUNDARY; + len = sg_len; + if ((offset + sg_len) > 0x10000) + len = 0x10000 - offset; - i++; + pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff); + pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16); + pp->sg_tbl[i].flags_size = cpu_to_le32(len); + + sg_len -= len; + addr += len; + + if (!sg_len && ata_sg_is_last(sg, qc)) + pp->sg_tbl[i].flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL); + + i++; + } } } @@ -1693,11 +1704,19 @@ static void mv_stop_and_reset(struct ata_port *ap) mv_channel_reset(hpriv, mmio, ap->port_no); - mv_phy_reset(ap); + __mv_phy_reset(ap, 0); +} + +static inline void __msleep(unsigned int msec, int can_sleep) +{ + if (can_sleep) + msleep(msec); + else + mdelay(msec); } /** - * mv_phy_reset - Perform eDMA reset followed by COMRESET + * __mv_phy_reset - Perform eDMA reset followed by COMRESET * @ap: ATA channel to manipulate * * Part of this is taken from __sata_phy_reset and modified to @@ -1707,13 +1726,16 @@ static void mv_stop_and_reset(struct ata_port *ap) * Inherited from caller. This is coded to safe to call at * interrupt level, i.e. it does not sleep. */ -static void mv_phy_reset(struct ata_port *ap) +static void __mv_phy_reset(struct ata_port *ap, int can_sleep) { struct mv_port_priv *pp = ap->private_data; + struct mv_host_priv *hpriv = ap->host_set->private_data; void __iomem *port_mmio = mv_ap_base(ap); struct ata_taskfile tf; struct ata_device *dev = &ap->device[0]; unsigned long timeout; + int retry = 5; + u32 sstatus; VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio); @@ -1721,18 +1743,28 @@ static void mv_phy_reset(struct ata_port *ap) "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); - /* proceed to init communications via the scr_control reg */ + /* Issue COMRESET via SControl */ +comreset_retry: scr_write_flush(ap, SCR_CONTROL, 0x301); - mdelay(1); + __msleep(1, can_sleep); + scr_write_flush(ap, SCR_CONTROL, 0x300); - timeout = jiffies + (HZ * 1); + __msleep(20, can_sleep); + + timeout = jiffies + msecs_to_jiffies(200); do { - mdelay(10); - if ((scr_read(ap, SCR_STATUS) & 0xf) != 1) + sstatus = scr_read(ap, SCR_STATUS) & 0x3; + if ((sstatus == 3) || (sstatus == 0)) break; + + __msleep(1, can_sleep); } while (time_before(jiffies, timeout)); - mv_scr_write(ap, SCR_ERROR, mv_scr_read(ap, SCR_ERROR)); + /* work around errata */ + if (IS_60XX(hpriv) && + (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) && + (retry-- > 0)) + goto comreset_retry; DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x " "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), @@ -1748,6 +1780,21 @@ static void mv_phy_reset(struct ata_port *ap) } ap->cbl = ATA_CBL_SATA; + /* even after SStatus reflects that device is ready, + * it seems to take a while for link to be fully + * established (and thus Status no longer 0x80/0x7F), + * so we poll a bit for that, here. + */ + retry = 20; + while (1) { + u8 drv_stat = ata_check_status(ap); + if ((drv_stat != 0x80) && (drv_stat != 0x7f)) + break; + __msleep(500, can_sleep); + if (retry-- <= 0) + break; + } + tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr); tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr); tf.lbal = readb((void __iomem *) ap->ioaddr.lbal_addr); @@ -1766,6 +1813,11 @@ static void mv_phy_reset(struct ata_port *ap) VPRINTK("EXIT\n"); } +static void mv_phy_reset(struct ata_port *ap) +{ + __mv_phy_reset(ap, 1); +} + /** * mv_eng_timeout - Routine called by libata when SCSI times out I/O * @ap: ATA channel to manipulate -- cgit v1.2.3 From a2c91a8819e315e9fd1aef3ff57badb6c1be3f80 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 17 Nov 2005 05:44:44 -0500 Subject: [libata sata_mv] handle lack of hardware nIEN support Handle errata (it was unintentional on this h/w, whereas its intentional on others) whereby the nIEN bit in Device Control is ignored, leading to a situation where a hardware interrupt completes the qc before the polling code has a chance to. This will get fixed The Right Way(tm) once Albert Lee's irq-pio branch is merged, as the more natural PIO method on this hardware is interrupt-driven. --- drivers/scsi/sata_mv.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index ee0634da087..ac184e60797 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -1219,6 +1219,10 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, handled++; } + if (ap && + (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) + continue; + err_mask = ac_err_mask(ata_status); shift = port << 1; /* (port * 2) */ @@ -1237,7 +1241,8 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, VPRINTK("port %u IRQ found for qc, " "ata_status 0x%x\n", port,ata_status); /* mark qc status appropriately */ - ata_qc_complete(qc, err_mask); + if (!(qc->tf.ctl & ATA_NIEN)) + ata_qc_complete(qc, err_mask); } } } -- cgit v1.2.3