📄 sata_fsl.c
字号:
/* * drivers/ata/sata_fsl.c * * Freescale 3.0Gbps SATA device driver * * Author: Ashish Kalra <ashish.kalra@freescale.com> * Li Yang <leoli@freescale.com> * * Copyright (c) 2006-2007 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/platform_device.h>#include <scsi/scsi_host.h>#include <scsi/scsi_cmnd.h>#include <linux/libata.h>#include <asm/io.h>#include <linux/of_platform.h>/* Controller information */enum { SATA_FSL_QUEUE_DEPTH = 16, SATA_FSL_MAX_PRD = 63, SATA_FSL_MAX_PRD_USABLE = SATA_FSL_MAX_PRD - 1, SATA_FSL_MAX_PRD_DIRECT = 16, /* Direct PRDT entries */ SATA_FSL_HOST_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ), SATA_FSL_HOST_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY, SATA_FSL_MAX_CMDS = SATA_FSL_QUEUE_DEPTH, SATA_FSL_CMD_HDR_SIZE = 16, /* 4 DWORDS */ SATA_FSL_CMD_SLOT_SIZE = (SATA_FSL_MAX_CMDS * SATA_FSL_CMD_HDR_SIZE), /* * SATA-FSL host controller supports a max. of (15+1) direct PRDEs, and * chained indirect PRDEs upto a max count of 63. * We are allocating an array of 63 PRDEs contigiously, but PRDE#15 will * be setup as an indirect descriptor, pointing to it's next * (contigious) PRDE. Though chained indirect PRDE arrays are * supported,it will be more efficient to use a direct PRDT and * a single chain/link to indirect PRDE array/PRDT. */ SATA_FSL_CMD_DESC_CFIS_SZ = 32, SATA_FSL_CMD_DESC_SFIS_SZ = 32, SATA_FSL_CMD_DESC_ACMD_SZ = 16, SATA_FSL_CMD_DESC_RSRVD = 16, SATA_FSL_CMD_DESC_SIZE = (SATA_FSL_CMD_DESC_CFIS_SZ + SATA_FSL_CMD_DESC_SFIS_SZ + SATA_FSL_CMD_DESC_ACMD_SZ + SATA_FSL_CMD_DESC_RSRVD + SATA_FSL_MAX_PRD * 16), SATA_FSL_CMD_DESC_OFFSET_TO_PRDT = (SATA_FSL_CMD_DESC_CFIS_SZ + SATA_FSL_CMD_DESC_SFIS_SZ + SATA_FSL_CMD_DESC_ACMD_SZ + SATA_FSL_CMD_DESC_RSRVD), SATA_FSL_CMD_DESC_AR_SZ = (SATA_FSL_CMD_DESC_SIZE * SATA_FSL_MAX_CMDS), SATA_FSL_PORT_PRIV_DMA_SZ = (SATA_FSL_CMD_SLOT_SIZE + SATA_FSL_CMD_DESC_AR_SZ), /* * MPC8315 has two SATA controllers, SATA1 & SATA2 * (one port per controller) * MPC837x has 2/4 controllers, one port per controller */ SATA_FSL_MAX_PORTS = 1, SATA_FSL_IRQ_FLAG = IRQF_SHARED,};/** Host Controller command register set - per port*/enum { CQ = 0, CA = 8, CC = 0x10, CE = 0x18, DE = 0x20, CHBA = 0x24, HSTATUS = 0x28, HCONTROL = 0x2C, CQPMP = 0x30, SIGNATURE = 0x34, ICC = 0x38, /* * Host Status Register (HStatus) bitdefs */ ONLINE = (1 << 31), GOING_OFFLINE = (1 << 30), BIST_ERR = (1 << 29), FATAL_ERR_HC_MASTER_ERR = (1 << 18), FATAL_ERR_PARITY_ERR_TX = (1 << 17), FATAL_ERR_PARITY_ERR_RX = (1 << 16), FATAL_ERR_DATA_UNDERRUN = (1 << 13), FATAL_ERR_DATA_OVERRUN = (1 << 12), FATAL_ERR_CRC_ERR_TX = (1 << 11), FATAL_ERR_CRC_ERR_RX = (1 << 10), FATAL_ERR_FIFO_OVRFL_TX = (1 << 9), FATAL_ERR_FIFO_OVRFL_RX = (1 << 8), FATAL_ERROR_DECODE = FATAL_ERR_HC_MASTER_ERR | FATAL_ERR_PARITY_ERR_TX | FATAL_ERR_PARITY_ERR_RX | FATAL_ERR_DATA_UNDERRUN | FATAL_ERR_DATA_OVERRUN | FATAL_ERR_CRC_ERR_TX | FATAL_ERR_CRC_ERR_RX | FATAL_ERR_FIFO_OVRFL_TX | FATAL_ERR_FIFO_OVRFL_RX, INT_ON_FATAL_ERR = (1 << 5), INT_ON_PHYRDY_CHG = (1 << 4), INT_ON_SIGNATURE_UPDATE = (1 << 3), INT_ON_SNOTIFY_UPDATE = (1 << 2), INT_ON_SINGL_DEVICE_ERR = (1 << 1), INT_ON_CMD_COMPLETE = 1, INT_ON_ERROR = INT_ON_FATAL_ERR | INT_ON_PHYRDY_CHG | INT_ON_SINGL_DEVICE_ERR, /* * Host Control Register (HControl) bitdefs */ HCONTROL_ONLINE_PHY_RST = (1 << 31), HCONTROL_FORCE_OFFLINE = (1 << 30), HCONTROL_PARITY_PROT_MOD = (1 << 14), HCONTROL_DPATH_PARITY = (1 << 12), HCONTROL_SNOOP_ENABLE = (1 << 10), HCONTROL_PMP_ATTACHED = (1 << 9), HCONTROL_COPYOUT_STATFIS = (1 << 8), IE_ON_FATAL_ERR = (1 << 5), IE_ON_PHYRDY_CHG = (1 << 4), IE_ON_SIGNATURE_UPDATE = (1 << 3), IE_ON_SNOTIFY_UPDATE = (1 << 2), IE_ON_SINGL_DEVICE_ERR = (1 << 1), IE_ON_CMD_COMPLETE = 1, DEFAULT_PORT_IRQ_ENABLE_MASK = IE_ON_FATAL_ERR | IE_ON_PHYRDY_CHG | IE_ON_SIGNATURE_UPDATE | IE_ON_SINGL_DEVICE_ERR | IE_ON_CMD_COMPLETE, EXT_INDIRECT_SEG_PRD_FLAG = (1 << 31), DATA_SNOOP_ENABLE = (1 << 22),};/* * SATA Superset Registers */enum { SSTATUS = 0, SERROR = 4, SCONTROL = 8, SNOTIFY = 0xC,};/* * Control Status Register Set */enum { TRANSCFG = 0, TRANSSTATUS = 4, LINKCFG = 8, LINKCFG1 = 0xC, LINKCFG2 = 0x10, LINKSTATUS = 0x14, LINKSTATUS1 = 0x18, PHYCTRLCFG = 0x1C, COMMANDSTAT = 0x20,};/* PHY (link-layer) configuration control */enum { PHY_BIST_ENABLE = 0x01,};/* * Command Header Table entry, i.e, command slot * 4 Dwords per command slot, command header size == 64 Dwords. */struct cmdhdr_tbl_entry { u32 cda; u32 prde_fis_len; u32 ttl; u32 desc_info;};/* * Description information bitdefs */enum { VENDOR_SPECIFIC_BIST = (1 << 10), CMD_DESC_SNOOP_ENABLE = (1 << 9), FPDMA_QUEUED_CMD = (1 << 8), SRST_CMD = (1 << 7), BIST = (1 << 6), ATAPI_CMD = (1 << 5),};/* * Command Descriptor */struct command_desc { u8 cfis[8 * 4]; u8 sfis[8 * 4]; u8 acmd[4 * 4]; u8 fill[4 * 4]; u32 prdt[SATA_FSL_MAX_PRD_DIRECT * 4]; u32 prdt_indirect[(SATA_FSL_MAX_PRD - SATA_FSL_MAX_PRD_DIRECT) * 4];};/* * Physical region table descriptor(PRD) */struct prde { u32 dba; u8 fill[2 * 4]; u32 ddc_and_ext;};/* * ata_port private data * This is our per-port instance data. */struct sata_fsl_port_priv { struct cmdhdr_tbl_entry *cmdslot; dma_addr_t cmdslot_paddr; struct command_desc *cmdentry; dma_addr_t cmdentry_paddr; /* * SATA FSL controller has a Status FIS which should contain the * received D2H FIS & taskfile registers. This SFIS is present in * the command descriptor, and to have a ready reference to it, * we are caching it here, quite similar to what is done in H/W on * AHCI compliant devices by copying taskfile fields to a 32-bit * register. */ struct ata_taskfile tf;};/* * ata_port->host_set private data */struct sata_fsl_host_priv { void __iomem *hcr_base; void __iomem *ssr_base; void __iomem *csr_base; int irq;};static inline unsigned int sata_fsl_tag(unsigned int tag, void __iomem *hcr_base){ /* We let libATA core do actual (queue) tag allocation */ /* all non NCQ/queued commands should have tag#0 */ if (ata_tag_internal(tag)) { DPRINTK("mapping internal cmds to tag#0\n"); return 0; } if (unlikely(tag >= SATA_FSL_QUEUE_DEPTH)) { DPRINTK("tag %d invalid : out of range\n", tag); return 0; } if (unlikely((ioread32(hcr_base + CQ)) & (1 << tag))) { DPRINTK("tag %d invalid : in use!!\n", tag); return 0; } return tag;}static void sata_fsl_setup_cmd_hdr_entry(struct sata_fsl_port_priv *pp, unsigned int tag, u32 desc_info, u32 data_xfer_len, u8 num_prde, u8 fis_len){ dma_addr_t cmd_descriptor_address; cmd_descriptor_address = pp->cmdentry_paddr + tag * SATA_FSL_CMD_DESC_SIZE; /* NOTE: both data_xfer_len & fis_len are Dword counts */ pp->cmdslot[tag].cda = cpu_to_le32(cmd_descriptor_address); pp->cmdslot[tag].prde_fis_len = cpu_to_le32((num_prde << 16) | (fis_len << 2)); pp->cmdslot[tag].ttl = cpu_to_le32(data_xfer_len & ~0x03); pp->cmdslot[tag].desc_info = cpu_to_le32(desc_info | (tag & 0x1F)); VPRINTK("cda=0x%x, prde_fis_len=0x%x, ttl=0x%x, di=0x%x\n", pp->cmdslot[tag].cda, pp->cmdslot[tag].prde_fis_len, pp->cmdslot[tag].ttl, pp->cmdslot[tag].desc_info);}static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc, u32 *ttl, dma_addr_t cmd_desc_paddr){ struct scatterlist *sg; unsigned int num_prde = 0; u32 ttl_dwords = 0; /* * NOTE : direct & indirect prdt's are contigiously allocated */ struct prde *prd = (struct prde *)&((struct command_desc *) cmd_desc)->prdt; struct prde *prd_ptr_to_indirect_ext = NULL; unsigned indirect_ext_segment_sz = 0; dma_addr_t indirect_ext_segment_paddr; VPRINTK("SATA FSL : cd = 0x%x, prd = 0x%x\n", cmd_desc, prd); indirect_ext_segment_paddr = cmd_desc_paddr + SATA_FSL_CMD_DESC_OFFSET_TO_PRDT + SATA_FSL_MAX_PRD_DIRECT * 16; ata_for_each_sg(sg, qc) { dma_addr_t sg_addr = sg_dma_address(sg); u32 sg_len = sg_dma_len(sg); VPRINTK("SATA FSL : fill_sg, sg_addr = 0x%x, sg_len = %d\n", sg_addr, sg_len); /* warn if each s/g element is not dword aligned */ if (sg_addr & 0x03) ata_port_printk(qc->ap, KERN_ERR, "s/g addr unaligned : 0x%x\n", sg_addr); if (sg_len & 0x03) ata_port_printk(qc->ap, KERN_ERR, "s/g len unaligned : 0x%x\n", sg_len); if ((num_prde == (SATA_FSL_MAX_PRD_DIRECT - 1)) && (qc->n_iter + 1 != qc->n_elem)) { VPRINTK("setting indirect prde\n"); prd_ptr_to_indirect_ext = prd; prd->dba = cpu_to_le32(indirect_ext_segment_paddr); indirect_ext_segment_sz = 0; ++prd; ++num_prde; } ttl_dwords += sg_len; prd->dba = cpu_to_le32(sg_addr); prd->ddc_and_ext = cpu_to_le32(DATA_SNOOP_ENABLE | (sg_len & ~0x03)); VPRINTK("sg_fill, ttl=%d, dba=0x%x, ddc=0x%x\n", ttl_dwords, prd->dba, prd->ddc_and_ext); ++num_prde; ++prd; if (prd_ptr_to_indirect_ext) indirect_ext_segment_sz += sg_len; } if (prd_ptr_to_indirect_ext) { /* set indirect extension flag along with indirect ext. size */ prd_ptr_to_indirect_ext->ddc_and_ext = cpu_to_le32((EXT_INDIRECT_SEG_PRD_FLAG | DATA_SNOOP_ENABLE | (indirect_ext_segment_sz & ~0x03))); } *ttl = ttl_dwords; return num_prde;}static void sata_fsl_qc_prep(struct ata_queued_cmd *qc){ struct ata_port *ap = qc->ap; struct sata_fsl_port_priv *pp = ap->private_data; struct sata_fsl_host_priv *host_priv = ap->host->private_data; void __iomem *hcr_base = host_priv->hcr_base; unsigned int tag = sata_fsl_tag(qc->tag, hcr_base); struct command_desc *cd; u32 desc_info = CMD_DESC_SNOOP_ENABLE; u32 num_prde = 0; u32 ttl_dwords = 0; dma_addr_t cd_paddr; cd = (struct command_desc *)pp->cmdentry + tag; cd_paddr = pp->cmdentry_paddr + tag * SATA_FSL_CMD_DESC_SIZE; ata_tf_to_fis(&qc->tf, 0, 1, (u8 *) &cd->cfis); VPRINTK("Dumping cfis : 0x%x, 0x%x, 0x%x\n", cd->cfis[0], cd->cfis[1], cd->cfis[2]); if (qc->tf.protocol == ATA_PROT_NCQ) { VPRINTK("FPDMA xfer,Sctor cnt[0:7],[8:15] = %d,%d\n", cd->cfis[3], cd->cfis[11]); } /* setup "ACMD - atapi command" in cmd. desc. if this is ATAPI cmd */ if (is_atapi_taskfile(&qc->tf)) { desc_info |= ATAPI_CMD; memset((void *)&cd->acmd, 0, 32); memcpy((void *)&cd->acmd, qc->cdb, qc->dev->cdb_len); } if (qc->flags & ATA_QCFLAG_DMAMAP) num_prde = sata_fsl_fill_sg(qc, (void *)cd, &ttl_dwords, cd_paddr); if (qc->tf.protocol == ATA_PROT_NCQ) desc_info |= FPDMA_QUEUED_CMD; sata_fsl_setup_cmd_hdr_entry(pp, tag, desc_info, ttl_dwords, num_prde, 5); VPRINTK("SATA FSL : xx_qc_prep, di = 0x%x, ttl = %d, num_prde = %d\n", desc_info, ttl_dwords, num_prde);}static unsigned int sata_fsl_qc_issue(struct ata_queued_cmd *qc){ struct ata_port *ap = qc->ap; struct sata_fsl_host_priv *host_priv = ap->host->private_data; void __iomem *hcr_base = host_priv->hcr_base; unsigned int tag = sata_fsl_tag(qc->tag, hcr_base); VPRINTK("xx_qc_issue called,CQ=0x%x,CA=0x%x,CE=0x%x,CC=0x%x\n", ioread32(CQ + hcr_base), ioread32(CA + hcr_base), ioread32(CE + hcr_base), ioread32(CC + hcr_base)); /* Simply queue command to the controller/device */ iowrite32(1 << tag, CQ + hcr_base); VPRINTK("xx_qc_issue called, tag=%d, CQ=0x%x, CA=0x%x\n", tag, ioread32(CQ + hcr_base), ioread32(CA + hcr_base)); VPRINTK("CE=0x%x, DE=0x%x, CC=0x%x, CmdStat = 0x%x\n", ioread32(CE + hcr_base), ioread32(DE + hcr_base), ioread32(CC + hcr_base), ioread32(COMMANDSTAT + csr_base)); return 0;}static int sata_fsl_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -