diff options
Diffstat (limited to 'drivers/ata/sata_mv.c')
-rw-r--r-- | drivers/ata/sata_mv.c | 203 |
1 files changed, 119 insertions, 84 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index fb8a749423c..8ec520885b9 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -35,8 +35,6 @@ 6) Add port multiplier support (intermediate) - 7) Test and verify 3.0 Gbps support - 8) Develop a low-power-consumption strategy, and implement it. 9) [Experiment, low priority] See if ATAPI can be supported using @@ -227,26 +225,26 @@ enum { EDMA_ERR_IRQ_CAUSE_OFS = 0x8, EDMA_ERR_IRQ_MASK_OFS = 0xc, - EDMA_ERR_D_PAR = (1 << 0), - EDMA_ERR_PRD_PAR = (1 << 1), - EDMA_ERR_DEV = (1 << 2), - EDMA_ERR_DEV_DCON = (1 << 3), - EDMA_ERR_DEV_CON = (1 << 4), - EDMA_ERR_SERR = (1 << 5), + EDMA_ERR_D_PAR = (1 << 0), /* UDMA data parity err */ + EDMA_ERR_PRD_PAR = (1 << 1), /* UDMA PRD parity err */ + EDMA_ERR_DEV = (1 << 2), /* device error */ + EDMA_ERR_DEV_DCON = (1 << 3), /* device disconnect */ + EDMA_ERR_DEV_CON = (1 << 4), /* device connected */ + EDMA_ERR_SERR = (1 << 5), /* SError bits [WBDST] raised */ EDMA_ERR_SELF_DIS = (1 << 7), /* Gen II/IIE self-disable */ EDMA_ERR_SELF_DIS_5 = (1 << 8), /* Gen I self-disable */ - EDMA_ERR_BIST_ASYNC = (1 << 8), + EDMA_ERR_BIST_ASYNC = (1 << 8), /* BIST FIS or Async Notify */ EDMA_ERR_TRANS_IRQ_7 = (1 << 8), /* Gen IIE transprt layer irq */ - EDMA_ERR_CRBQ_PAR = (1 << 9), - EDMA_ERR_CRPB_PAR = (1 << 10), - EDMA_ERR_INTRL_PAR = (1 << 11), - EDMA_ERR_IORDY = (1 << 12), - EDMA_ERR_LNK_CTRL_RX = (0xf << 13), + EDMA_ERR_CRQB_PAR = (1 << 9), /* CRQB parity error */ + EDMA_ERR_CRPB_PAR = (1 << 10), /* CRPB parity error */ + EDMA_ERR_INTRL_PAR = (1 << 11), /* internal parity error */ + EDMA_ERR_IORDY = (1 << 12), /* IORdy timeout */ + EDMA_ERR_LNK_CTRL_RX = (0xf << 13), /* link ctrl rx error */ EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15), - EDMA_ERR_LNK_DATA_RX = (0xf << 17), - EDMA_ERR_LNK_CTRL_TX = (0x1f << 21), - EDMA_ERR_LNK_DATA_TX = (0x1f << 26), - EDMA_ERR_TRANS_PROTO = (1 << 31), + EDMA_ERR_LNK_DATA_RX = (0xf << 17), /* link data rx error */ + EDMA_ERR_LNK_CTRL_TX = (0x1f << 21), /* link ctrl tx error */ + EDMA_ERR_LNK_DATA_TX = (0x1f << 26), /* link data tx error */ + EDMA_ERR_TRANS_PROTO = (1 << 31), /* transport protocol error */ EDMA_ERR_OVERRUN_5 = (1 << 5), EDMA_ERR_UNDERRUN_5 = (1 << 6), EDMA_EH_FREEZE = EDMA_ERR_D_PAR | @@ -255,7 +253,7 @@ enum { EDMA_ERR_DEV_CON | EDMA_ERR_SERR | EDMA_ERR_SELF_DIS | - EDMA_ERR_CRBQ_PAR | + EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR | EDMA_ERR_IORDY | @@ -270,7 +268,7 @@ enum { EDMA_ERR_OVERRUN_5 | EDMA_ERR_UNDERRUN_5 | EDMA_ERR_SELF_DIS_5 | - EDMA_ERR_CRBQ_PAR | + EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR | EDMA_ERR_IORDY, @@ -286,10 +284,10 @@ enum { EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */ EDMA_RSP_Q_PTR_SHIFT = 3, - EDMA_CMD_OFS = 0x28, - EDMA_EN = (1 << 0), - EDMA_DS = (1 << 1), - ATA_RST = (1 << 2), + EDMA_CMD_OFS = 0x28, /* EDMA command register */ + EDMA_EN = (1 << 0), /* enable EDMA */ + EDMA_DS = (1 << 1), /* disable EDMA; self-negated */ + ATA_RST = (1 << 2), /* reset trans/link/phy */ EDMA_IORDY_TMOUT = 0x34, EDMA_ARB_CFG = 0x38, @@ -301,14 +299,13 @@ enum { MV_HP_ERRATA_60X1B2 = (1 << 3), MV_HP_ERRATA_60X1C0 = (1 << 4), MV_HP_ERRATA_XX42A0 = (1 << 5), - MV_HP_GEN_I = (1 << 6), - MV_HP_GEN_II = (1 << 7), - MV_HP_GEN_IIE = (1 << 8), + MV_HP_GEN_I = (1 << 6), /* Generation I: 50xx */ + MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */ + MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */ /* Port private flags (pp_flags) */ - MV_PP_FLAG_EDMA_EN = (1 << 0), - MV_PP_FLAG_EDMA_DS_ACT = (1 << 1), - MV_PP_FLAG_HAD_A_RESET = (1 << 2), + MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */ + MV_PP_FLAG_HAD_A_RESET = (1 << 2), /* 1st hard reset complete? */ }; #define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I) @@ -318,8 +315,12 @@ enum { enum { MV_DMA_BOUNDARY = 0xffffffffU, + /* mask of register bits containing lower 32 bits + * of EDMA request queue DMA address + */ EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U, + /* ditto, for response queue */ EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U, }; @@ -403,10 +404,10 @@ 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 int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val); +static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); +static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val); +static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); static int mv_port_start(struct ata_port *ap); static void mv_port_stop(struct ata_port *ap); static void mv_qc_prep(struct ata_queued_cmd *qc); @@ -823,7 +824,7 @@ static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv, } /** - * mv_stop_dma - Disable eDMA engine + * __mv_stop_dma - Disable eDMA engine * @ap: ATA channel to manipulate * * Verify the local cache of the eDMA state is accurate with a @@ -832,7 +833,7 @@ static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv, * LOCKING: * Inherited from caller. */ -static int mv_stop_dma(struct ata_port *ap) +static int __mv_stop_dma(struct ata_port *ap) { void __iomem *port_mmio = mv_ap_base(ap); struct mv_port_priv *pp = ap->private_data; @@ -865,6 +866,18 @@ static int mv_stop_dma(struct ata_port *ap) return err; } +static int mv_stop_dma(struct ata_port *ap) +{ + unsigned long flags; + int rc; + + spin_lock_irqsave(&ap->host->lock, flags); + rc = __mv_stop_dma(ap); + spin_unlock_irqrestore(&ap->host->lock, flags); + + return rc; +} + #ifdef ATA_DEBUG static void mv_dump_mem(void __iomem *start, unsigned bytes) { @@ -961,22 +974,26 @@ static unsigned int mv_scr_offset(unsigned int sc_reg_in) return ofs; } -static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in) +static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val) { unsigned int ofs = mv_scr_offset(sc_reg_in); - if (0xffffffffU != ofs) - return readl(mv_ap_base(ap) + ofs); - else - return (u32) ofs; + if (ofs != 0xffffffffU) { + *val = readl(mv_ap_base(ap) + ofs); + return 0; + } else + return -EINVAL; } -static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) +static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) { unsigned int ofs = mv_scr_offset(sc_reg_in); - if (0xffffffffU != ofs) + if (ofs != 0xffffffffU) { writelfl(val, mv_ap_base(ap) + ofs); + return 0; + } else + return -EINVAL; } static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv, @@ -1029,6 +1046,7 @@ static int mv_port_start(struct ata_port *ap) void __iomem *port_mmio = mv_ap_base(ap); void *mem; dma_addr_t mem_dma; + unsigned long flags; int rc; pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); @@ -1067,10 +1085,14 @@ static int mv_port_start(struct ata_port *ap) pp->sg_tbl = mem; pp->sg_tbl_dma = mem_dma; + spin_lock_irqsave(&ap->host->lock, flags); + mv_edma_cfg(ap, hpriv, port_mmio); mv_set_edma_ptrs(port_mmio, hpriv, pp); + spin_unlock_irqrestore(&ap->host->lock, flags); + /* Don't turn on EDMA here...do it before DMA commands only. Else * we'll be unable to send non-data, PIO, etc due to restricted access * to shadow regs. @@ -1090,11 +1112,7 @@ static int mv_port_start(struct ata_port *ap) */ static void mv_port_stop(struct ata_port *ap) { - unsigned long flags; - - spin_lock_irqsave(&ap->host->lock, flags); mv_stop_dma(ap); - spin_unlock_irqrestore(&ap->host->lock, flags); } /** @@ -1325,7 +1343,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc) * port. Turn off EDMA so there won't be problems accessing * shadow block, etc registers. */ - mv_stop_dma(ap); + __mv_stop_dma(ap); return ata_qc_issue_prot(qc); } @@ -1393,16 +1411,16 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) if (edma_err_cause & EDMA_ERR_DEV) err_mask |= AC_ERR_DEV; if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR | - EDMA_ERR_CRBQ_PAR | EDMA_ERR_CRPB_PAR | + EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR)) { err_mask |= AC_ERR_ATA_BUS; action |= ATA_EH_HARDRESET; - ata_ehi_push_desc(ehi, ", parity error"); + ata_ehi_push_desc(ehi, "parity error"); } if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) { ata_ehi_hotplugged(ehi); ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ? - ", dev disconnect" : ", dev connect"); + "dev disconnect" : "dev connect"); } if (IS_GEN_I(hpriv)) { @@ -1411,7 +1429,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) if (edma_err_cause & EDMA_ERR_SELF_DIS_5) { struct mv_port_priv *pp = ap->private_data; pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; - ata_ehi_push_desc(ehi, ", EDMA self-disable"); + ata_ehi_push_desc(ehi, "EDMA self-disable"); } } else { eh_freeze_mask = EDMA_EH_FREEZE; @@ -1419,7 +1437,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) if (edma_err_cause & EDMA_ERR_SELF_DIS) { struct mv_port_priv *pp = ap->private_data; pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; - ata_ehi_push_desc(ehi, ", EDMA self-disable"); + ata_ehi_push_desc(ehi, "EDMA self-disable"); } if (edma_err_cause & EDMA_ERR_SERR) { @@ -1489,33 +1507,30 @@ static void mv_intr_edma(struct ata_port *ap) while (1) { u16 status; + unsigned int tag; /* get s/w response queue last-read pointer, and compare */ out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK; if (in_index == out_index) break; - /* 50xx: get active ATA command */ - if (IS_GEN_I(hpriv)) - qc = ata_qc_from_tag(ap, ap->active_tag); + if (IS_GEN_I(hpriv)) + tag = ap->active_tag; - /* 60xx: get active ATA command via tag, to enable support - * for queueing. this works transparently for queued and - * non-queued modes. + /* Gen II/IIE: get active ATA command via tag, to enable + * support for queueing. this works transparently for + * queued and non-queued modes. */ - else { - unsigned int tag; + else if (IS_GEN_II(hpriv)) + tag = (le16_to_cpu(pp->crpb[out_index].id) + >> CRPB_IOID_SHIFT_6) & 0x3f; - if (IS_GEN_II(hpriv)) - tag = (le16_to_cpu(pp->crpb[out_index].id) - >> CRPB_IOID_SHIFT_6) & 0x3f; - else - tag = (le16_to_cpu(pp->crpb[out_index].id) - >> CRPB_IOID_SHIFT_7) & 0x3f; + else /* IS_GEN_IIE */ + tag = (le16_to_cpu(pp->crpb[out_index].id) + >> CRPB_IOID_SHIFT_7) & 0x3f; - qc = ata_qc_from_tag(ap, tag); - } + qc = ata_qc_from_tag(ap, tag); /* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS * bits (WARNING: might not necessarily be associated @@ -1535,7 +1550,7 @@ static void mv_intr_edma(struct ata_port *ap) ata_qc_complete(qc); } - /* advance software response queue pointer, to + /* advance software response queue pointer, to * indicate (after the loop completes) to hardware * that we have consumed a response queue entry. */ @@ -1741,26 +1756,30 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in) return ofs; } -static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in) +static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val) { void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; void __iomem *addr = mv5_phy_base(mmio, ap->port_no); unsigned int ofs = mv5_scr_offset(sc_reg_in); - if (ofs != 0xffffffffU) - return readl(addr + ofs); - else - return (u32) ofs; + if (ofs != 0xffffffffU) { + *val = readl(addr + ofs); + return 0; + } else + return -EINVAL; } -static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) +static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) { void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; void __iomem *addr = mv5_phy_base(mmio, ap->port_no); unsigned int ofs = mv5_scr_offset(sc_reg_in); - if (ofs != 0xffffffffU) + if (ofs != 0xffffffffU) { writelfl(val, addr + ofs); + return 0; + } else + return -EINVAL; } static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio) @@ -2138,9 +2157,17 @@ static void mv_phy_reset(struct ata_port *ap, unsigned int *class, VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio); - 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)); +#ifdef DEBUG + { + u32 sstatus, serror, scontrol; + + mv_scr_read(ap, SCR_STATUS, &sstatus); + mv_scr_read(ap, SCR_ERROR, &serror); + mv_scr_read(ap, SCR_CONTROL, &scontrol); + DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x " + "SCtrl 0x%08x\n", status, serror, scontrol); + } +#endif /* Issue COMRESET via SControl */ comreset_retry: @@ -2164,9 +2191,17 @@ comreset_retry: (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), - mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); +#ifdef DEBUG + { + u32 sstatus, serror, scontrol; + + mv_scr_read(ap, SCR_STATUS, &sstatus); + mv_scr_read(ap, SCR_ERROR, &serror); + mv_scr_read(ap, SCR_CONTROL, &scontrol); + DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x " + "SCtrl 0x%08x\n", sstatus, serror, scontrol); + } +#endif if (ata_port_offline(ap)) { *class = ATA_DEV_NONE; @@ -2209,7 +2244,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline) struct mv_port_priv *pp = ap->private_data; struct ata_eh_context *ehc = &ap->eh_context; int rc; - + rc = mv_stop_dma(ap); if (rc) ehc->i.action |= ATA_EH_HARDRESET; |