// SPDX-License-Identifier: GPL-2.0-or-later /* * drivers/ata/sata_dwc_460ex.c * * Synopsys DesignWare Cores (DWC) SATA host driver * * Author: Mark Miesfeld <mmiesfeld@amcc.com> * * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr@denx.de> * Copyright 2008 DENX Software Engineering * * Based on versions provided by AMCC and Synopsys which are: * Copyright 2006 Applied Micro Circuits Corporation * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED
*/
/* * Allow one extra special slot for commands and DMA management * to account for libata internal commands.
*/ #define SATA_DWC_QCMD_MAX (ATA_MAX_QUEUE + 1)
struct sata_dwc_device_port { struct sata_dwc_device *hsdev; int cmd_issued[SATA_DWC_QCMD_MAX]; int dma_pending[SATA_DWC_QCMD_MAX];
hsdev->dma = devm_kzalloc(dev, sizeof(*hsdev->dma), GFP_KERNEL); if (!hsdev->dma) return -ENOMEM;
hsdev->dma->dev = dev;
hsdev->dma->id = pdev->id;
/* Get SATA DMA interrupt number */
hsdev->dma->irq = irq_of_parse_and_map(np, 1); if (!hsdev->dma->irq) {
dev_err(dev, "no SATA DMA irq\n"); return -ENODEV;
}
/* Get physical SATA DMA register base address */
hsdev->dma->regs = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(hsdev->dma->regs)) return PTR_ERR(hsdev->dma->regs);
staticvoid sata_dwc_dma_exit_old(struct sata_dwc_device *hsdev)
{ if (!hsdev->dma) return;
dw_dma_remove(hsdev->dma);
}
#endif
staticconstchar *get_prot_descript(u8 protocol)
{ switch (protocol) { case ATA_PROT_NODATA: return"ATA no data"; case ATA_PROT_PIO: return"ATA PIO"; case ATA_PROT_DMA: return"ATA DMA"; case ATA_PROT_NCQ: return"ATA NCQ"; case ATA_PROT_NCQ_NODATA: return"ATA NCQ no data"; case ATAPI_PROT_NODATA: return"ATAPI no data"; case ATAPI_PROT_PIO: return"ATAPI PIO"; case ATAPI_PROT_DMA: return"ATAPI DMA"; default: return"unknown";
}
}
spin_lock_irqsave(&host->lock, flags);
ap = host->ports[port];
hsdevp = HSDEVP_FROM_AP(ap);
tag = ap->link.active_tag;
/* * Each DMA command produces 2 interrupts. Only * complete the command after both interrupts have been * seen. (See sata_dwc_isr())
*/
hsdevp->dma_interrupt_count++;
sata_dwc_clear_dmacr(hsdevp, tag);
if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_NONE) {
dev_err(ap->dev, "DMA not pending tag=0x%02x pending=%d\n",
tag, hsdevp->dma_pending[tag]);
}
if ((hsdevp->dma_interrupt_count % 2) == 0)
sata_dwc_dma_xfer_complete(ap);
/* Convert SG list to linked list of items (LLIs) for AHB DMA */
desc = dmaengine_prep_slave_sg(hsdevp->chan, qc->sg, qc->n_elem,
qc->dma_dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
/* Check for error interrupt */ if (intpr & SATA_DWC_INTPR_ERR) {
sata_dwc_error_intr(ap, hsdev, intpr);
handled = 1; goto DONE;
}
/* Check for DMA SETUP FIS (FP DMA) interrupt */ if (intpr & SATA_DWC_INTPR_NEWFP) {
clear_interrupt_bit(hsdev, SATA_DWC_INTPR_NEWFP);
tag = (u8)(sata_dwc_readl(&hsdev->sata_dwc_regs->fptagr));
dev_dbg(ap->dev, "%s: NEWFP tag=%d\n", __func__, tag); if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_PEND)
dev_warn(ap->dev, "CMD tag=%d not pending?\n", tag);
hsdev->sactive_issued |= qcmd_tag_to_mask(tag);
qc = ata_qc_from_tag(ap, tag); if (unlikely(!qc)) {
dev_err(ap->dev, "failed to get qc");
handled = 1; goto DONE;
} /* * Start FP DMA for NCQ command. At this point the tag is the * active tag. It is the tag that matches the command about to * be completed.
*/
trace_ata_bmdma_start(ap, &qc->tf, tag);
qc->ap->link.active_tag = tag;
sata_dwc_bmdma_start_by_tag(qc, tag);
/* If no sactive issued and tag_mask is zero then this is not NCQ */ if (hsdev->sactive_issued == 0 && tag_mask == 0) { if (ap->link.active_tag == ATA_TAG_POISON)
tag = 0; else
tag = ap->link.active_tag;
qc = ata_qc_from_tag(ap, tag);
/* DEV interrupt w/ no active qc? */ if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
dev_err(ap->dev, "%s interrupt with no active qc qc=%p\n",
__func__, qc);
ap->ops->sff_check_status(ap);
handled = 1; goto DONE;
}
status = ap->ops->sff_check_status(ap);
dev_dbg(ap->dev, "%s non-NCQ cmd interrupt, protocol: %s\n",
__func__, get_prot_descript(qc->tf.protocol));
DRVSTILLBUSY: if (ata_is_dma(qc->tf.protocol)) { /* * Each DMA transaction produces 2 interrupts. The DMAC * transfer complete interrupt and the SATA controller * operation done interrupt. The command should be * completed only after both interrupts are seen.
*/
hsdevp->dma_interrupt_count++; if (hsdevp->dma_pending[tag] == \
SATA_DWC_DMA_PENDING_NONE) {
dev_err(ap->dev, "%s: DMA not pending intpr=0x%08x status=0x%08x pending=%d\n",
__func__, intpr, status,
hsdevp->dma_pending[tag]);
}
/* * This is a NCQ command. At this point we need to figure out for which * tags we have gotten a completion interrupt. One interrupt may serve * as completion for more than one operation when commands are queued * (NCQ). We need to process each completed command.
*/
if ((tag_mask | hsdev->sactive_issued) != hsdev->sactive_issued) {
dev_warn(ap->dev, "Bad tag mask? sactive=0x%08x sactive_issued=0x%08x tag_mask=0x%08x\n",
sactive, hsdev->sactive_issued, tag_mask);
}
/* read just to clear ... not bad if currently still busy */
status = ap->ops->sff_check_status(ap);
dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status);
tag = 0; while (tag_mask) { while (!(tag_mask & 0x00000001)) {
tag++;
tag_mask <<= 1;
}
tag_mask &= (~0x00000001);
qc = ata_qc_from_tag(ap, tag); if (unlikely(!qc)) {
dev_err(ap->dev, "failed to get qc");
handled = 1; goto DONE;
}
/* To be picked up by completion functions */
qc->ap->link.active_tag = tag;
hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT;
/* * Check to see if any commands completed while we were processing our * initial set of completed commands (read status clears interrupts, * so we might miss a completed command interrupt if one came in while * we were processing --we read status as part of processing a completed * command).
*/
sata_dwc_scr_read(&ap->link, SCR_ACTIVE, &sactive2); if (sactive2 != sactive) {
dev_dbg(ap->dev, "More completed - sactive=0x%x sactive2=0x%x\n",
sactive, sactive2);
}
handled = 1;
if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX) {
dmacr = SATA_DWC_DMACR_RX_CLEAR(dmacr);
sata_dwc_writel(&hsdev->sata_dwc_regs->dmacr, dmacr);
} elseif (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX) {
dmacr = SATA_DWC_DMACR_TX_CLEAR(dmacr);
sata_dwc_writel(&hsdev->sata_dwc_regs->dmacr, dmacr);
} else { /* * This should not happen, it indicates the driver is out of * sync. If it does happen, clear dmacr anyway.
*/
dev_err(hsdev->dev, "%s DMA protocol RX and TX DMA not pending tag=0x%02x pending=%d dmacr: 0x%08x\n",
__func__, tag, hsdevp->dma_pending[tag], dmacr);
sata_dwc_writel(&hsdev->sata_dwc_regs->dmacr,
SATA_DWC_DMACR_TXRXCH_CLEAR);
}
}
/* * Function : sata_dwc_exec_command_by_tag * arguments : ata_port *ap, ata_taskfile *tf, u8 tag, u32 cmd_issued * Return value : None * This function keeps track of individual command tag ids and calls * ata_exec_command in libata
*/ staticvoid sata_dwc_exec_command_by_tag(struct ata_port *ap, struct ata_taskfile *tf,
u8 tag, u32 cmd_issued)
{ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
hsdevp->cmd_issued[tag] = cmd_issued;
/* * Clear SError before executing a new command. * sata_dwc_scr_write and read can not be used here. Clearing the PM * managed SError register for the disk needs to be done before the * task file is loaded.
*/
clear_serror(ap);
ata_sff_exec_command(ap, tf);
}
staticvoid sata_dwc_dev_select(struct ata_port *ap, unsignedint device)
{ /* SATA DWC is master only */
}
/* * scsi mid-layer and libata interface structures
*/ staticconststruct scsi_host_template sata_dwc_sht = {
ATA_NCQ_SHT(DRV_NAME), /* * test-only: Currently this driver doesn't handle NCQ * correctly. We enable NCQ but set the queue depth to a * max of 1. This will get fixed in in a future release.
*/
.sg_tablesize = LIBATA_MAX_PRD, /* .can_queue = ATA_MAX_QUEUE, */ /* * Make sure a LLI block is not created that will span 8K max FIS * boundary. If the block spans such a FIS boundary, there is a chance * that a DMA burst will cross that boundary -- this results in an * error in the host controller.
*/
.dma_boundary = 0x1fff /* ATA_DMA_BOUNDARY */,
};
/* Ioremap SATA registers */
base = devm_platform_get_and_ioremap_resource(ofdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base);
dev_dbg(dev, "ioremap done for SATA register address\n");
/* Synopsys DWC SATA specific Registers */
hsdev->sata_dwc_regs = base + SATA_DWC_REG_OFFSET;
hsdev->dmadr = res->start + SATA_DWC_REG_OFFSET + offsetof(struct sata_dwc_regs, dmadr);
/* Setup port */
host->ports[0]->ioaddr.cmd_addr = base;
host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET;
sata_dwc_setup_port(&host->ports[0]->ioaddr, base);
/* Read the ID and Version Registers */
idr = sata_dwc_readl(&hsdev->sata_dwc_regs->idr);
versionr = sata_dwc_readl(&hsdev->sata_dwc_regs->versionr);
dev_notice(dev, "id %d, controller version %c.%c%c\n", idr, ver[0], ver[1], ver[2]);
/* Save dev for later use in dev_xxx() routines */
hsdev->dev = dev;
/* Enable SATA Interrupts */
sata_dwc_enable_interrupts(hsdev);
/* Get SATA interrupt number */
irq = irq_of_parse_and_map(np, 0); if (!irq) {
dev_err(dev, "no SATA DMA irq\n"); return -ENODEV;
}
#ifdef CONFIG_SATA_DWC_OLD_DMA if (!of_property_present(np, "dmas")) {
err = sata_dwc_dma_init_old(ofdev, hsdev); if (err) return err;
} #endif
hsdev->phy = devm_phy_optional_get(dev, "sata-phy"); if (IS_ERR(hsdev->phy)) return PTR_ERR(hsdev->phy);
err = phy_init(hsdev->phy); if (err) goto error_out;
/* * Now, register with libATA core, this will also initiate the * device discovery process, invoking our port_start() handler & * error_handler() to execute a dummy Softreset EH session
*/
err = ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht); if (err)
dev_err(dev, "failed to activate host");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.