📄 sata_mv.c
字号:
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(hpriv->irq_cause_ofs); ZERO(hpriv->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 ZEROstatic 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, unsigned int n_hc){ 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){ void __iomem *port_mmio; u32 tmp; tmp = readl(mmio + MV_RESET_CFG); if ((tmp & (1 << 0)) == 0) { hpriv->signal[idx].amps = 0x7 << 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 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 *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); int fix_phy_mode4 = 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 m4; m4 = readl(port_mmio + PHY_MODE4); if (hp_flags & MV_HP_ERRATA_60X1B2) tmp = readl(port_mmio + 0x310); m4 = (m4 & ~(1 << 1)) | (1 << 0); writel(m4, port_mmio + PHY_MODE4); if (hp_flags & MV_HP_ERRATA_60X1B2) 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[port].amps; m2 |= hpriv->signal[port].pre; m2 &= ~(1 << 16); /* according to mvSata 3.6.1, some IIE values are fixed */ if (IS_GEN_IIE(hpriv)) { m2 &= ~0xC30FF01F; m2 |= 0x0000900F; } 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_GEN_II(hpriv)) { u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL); ifctl |= (1 << 7); /* enable gen2i speed */ ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */ 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_GEN_I(hpriv)) mdelay(1);}/** * 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 * not sleep since this routine gets called from interrupt level. * * LOCKING: * 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, unsigned int *class, unsigned long deadline){ struct mv_port_priv *pp = ap->private_data; struct mv_host_priv *hpriv = ap->host->private_data; void __iomem *port_mmio = mv_ap_base(ap); int retry = 5; u32 sstatus; VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);#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", sstatus, serror, scontrol); }#endif /* Issue COMRESET via SControl */comreset_retry: sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x301); msleep(1); sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x300); msleep(20); do { sata_scr_read(&ap->link, SCR_STATUS, &sstatus); if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0)) break; msleep(1); } while (time_before(jiffies, deadline)); /* work around errata */ if (IS_GEN_II(hpriv) && (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) && (retry-- > 0)) goto comreset_retry;#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_link_offline(&ap->link)) { *class = ATA_DEV_NONE; return; } /* 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); if (retry-- <= 0) break; if (time_after(jiffies, deadline)) break; } /* FIXME: if we passed the deadline, the following * code probably produces an invalid result */ /* finally, read device signature from TF registers */ *class = ata_dev_try_classify(ap->link.device, 1, NULL); writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); WARN_ON(pp->pp_flags & MV_PP_FLAG_EDMA_EN); VPRINTK("EXIT\n");}static int mv_prereset(struct ata_link *link, unsigned long deadline){ struct ata_port *ap = link->ap; struct mv_port_priv *pp = ap->private_data; struct ata_eh_context *ehc = &link->eh_context; int rc; rc = mv_stop_dma(ap); if (rc) ehc->i.action |= ATA_EH_HARDRESET; if (!(pp->pp_flags & MV_PP_FLAG_HAD_A_RESET)) { pp->pp_flags |= MV_PP_FLAG_HAD_A_RESET; ehc->i.action |= ATA_EH_HARDRESET; } /* if we're about to do hardreset, nothing more to do */ if (ehc->i.action & ATA_EH_HARDRESET) return 0; if (ata_link_online(link)) rc = ata_wait_ready(ap, deadline); else rc = -ENODEV; return rc;}static int mv_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline){ struct ata_port *ap = link->ap; struct mv_host_priv *hpriv = ap->host->private_data; void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; mv_stop_dma(ap); mv_channel_reset(hpriv, mmio, ap->port_no); mv_phy_reset(ap, class, deadline); return 0;}static void mv_postreset(struct ata_link *link, unsigned int *classes){ struct ata_port *ap = link->ap; u32 serr; /* print link status */ sata_print_link_status(link); /* clear SError */ sata_scr_read(link, SCR_ERROR, &serr); sata_scr_write_flush(link, SCR_ERROR, serr); /* bail out if no device is present */ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { DPRINTK("EXIT, no device\n"); return; } /* set up device control */ iowrite8(ap->ctl, ap->ioaddr.ctl_addr);}static void mv_error_handler(struct ata_port *ap){ ata_do_eh(ap, mv_prereset, ata_std_softreset, mv_hardreset, mv_postreset);}static void mv_post_int_cmd(struct ata_queued_cmd *qc){ mv_stop_dma(qc->ap);}static void mv_eh_freeze(struct ata_port *ap){ void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; unsigned int hc = (ap->port_no > 3) ? 1 : 0; u32 tmp, mask; unsigned int shift; /* FIXME: handle coalescing completion events properly */ shift = ap->port_no * 2; if (hc > 0) shift++; mask = 0x3 << shift; /* disable assertion of portN err, done events */ tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS); writelfl(tmp & ~mask, mmio + HC_MAIN_IRQ_MASK_OFS);}static void mv_eh_thaw(struct ata_port *ap){ void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; unsigned int hc = (ap->port_no > 3) ? 1 : 0; void __iomem *hc_mmio = mv_hc_base(mmio, hc); void __iomem *port_mmio = mv_ap_base(ap); u32 tmp, mask, hc_irq_cause; unsigned int shift, hc_port_no = ap->port_no; /* FIXME: handle coalescing completion events properly */ shift = ap->port_no * 2; if (hc > 0) { shift++; hc_port_no -= 4; } mask = 0x3 << shift; /* clear EDMA errors on this port */ writel(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); /* clear pending irq events */ hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS); hc_irq_cause &= ~(1 << hc_port_no); /* clear CRPB-done */ hc_irq_cause &= ~(1 << (hc_port_no + 8)); /* clear Device int */ writel(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS); /* enable assertion of portN err, done events */ tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS); writelfl(tmp | mask, mmio + HC_MAIN_IRQ_MASK_OFS);}/** * mv_port_init - Perform some early initialization on a single port. * @port: libata data structure storing shadow register addresses * @port_mmio: base address of the port * * Initialize shadow register mmio addresses, clear outstanding * interrupts on the port, and unmask interrupts for the future * start of the port. * * LOCKING: * Inherited from caller. */static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio){ void __iomem *shd_base = port_mmio + SHD_BLK_OFS; unsigned serr_ofs; /* PIO related setup */ port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA); 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->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; /* unused: */ port->cmd_addr = port->bmdma_addr = port->scr_addr = NULL; /* Clear any currently outstanding port interrupt conditions */ serr_ofs = mv_scr_offset(SCR_ERROR); writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs); writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); /* unmask all EDMA error interrupts */ writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -