⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sata_mv.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -