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

📄 sata_fsl.c

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