sata_sx4.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,500 行 · 第 1/3 页

C
1,500
字号
/* *  sata_sx4.c - Promise SATA * *  Maintained by:  Jeff Garzik <jgarzik@pobox.com> *  		    Please ALWAYS copy linux-ide@vger.kernel.org *		    on emails. * *  Copyright 2003-2004 Red Hat, Inc. * *  The contents of this file are subject to the Open *  Software License version 1.1 that can be found at *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein *  by reference. * *  Alternatively, the contents of this file may be used under the terms *  of the GNU General Public License version 2 (the "GPL") as distributed *  in the kernel source COPYING file, in which case the provisions of *  the GPL are applicable instead of the above.  If you wish to allow *  the use of your version of this file only under the terms of the *  GPL and not to allow others to use your version of this file under *  the OSL, indicate your decision by deleting the provisions above and *  replace them with the notice and other provisions required by the GPL. *  If you do not delete the provisions above, a recipient may use your *  version of this file under either the OSL or the GPL. * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/sched.h>#include "scsi.h"#include <scsi/scsi_host.h>#include <linux/libata.h>#include <asm/io.h>#include "sata_promise.h"#define DRV_NAME	"sata_sx4"#define DRV_VERSION	"0.50"enum {	PDC_PRD_TBL		= 0x44,	/* Direct command DMA table addr */	PDC_PKT_SUBMIT		= 0x40, /* Command packet pointer addr */	PDC_HDMA_PKT_SUBMIT	= 0x100, /* Host DMA packet pointer addr */	PDC_INT_SEQMASK		= 0x40,	/* Mask of asserted SEQ INTs */	PDC_HDMA_CTLSTAT	= 0x12C, /* Host DMA control / status */	PDC_20621_SEQCTL	= 0x400,	PDC_20621_SEQMASK	= 0x480,	PDC_20621_GENERAL_CTL	= 0x484,	PDC_20621_PAGE_SIZE	= (32 * 1024),	/* chosen, not constant, values; we design our own DIMM mem map */	PDC_20621_DIMM_WINDOW	= 0x0C,	/* page# for 32K DIMM window */	PDC_20621_DIMM_BASE	= 0x00200000,	PDC_20621_DIMM_DATA	= (64 * 1024),	PDC_DIMM_DATA_STEP	= (256 * 1024),	PDC_DIMM_WINDOW_STEP	= (8 * 1024),	PDC_DIMM_HOST_PRD	= (6 * 1024),	PDC_DIMM_HOST_PKT	= (128 * 0),	PDC_DIMM_HPKT_PRD	= (128 * 1),	PDC_DIMM_ATA_PKT	= (128 * 2),	PDC_DIMM_APKT_PRD	= (128 * 3),	PDC_DIMM_HEADER_SZ	= PDC_DIMM_APKT_PRD + 128,	PDC_PAGE_WINDOW		= 0x40,	PDC_PAGE_DATA		= PDC_PAGE_WINDOW +				  (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE),	PDC_PAGE_SET		= PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE,	PDC_CHIP0_OFS		= 0xC0000, /* offset of chip #0 */	PDC_20621_ERR_MASK	= (1<<19) | (1<<20) | (1<<21) | (1<<22) |				  (1<<23),	board_20621		= 0,	/* FastTrak S150 SX4 */	PDC_RESET		= (1 << 11), /* HDMA reset */	PDC_MAX_HDMA		= 32,	PDC_HDMA_Q_MASK		= (PDC_MAX_HDMA - 1),	PDC_DIMM0_SPD_DEV_ADDRESS     = 0x50,	PDC_DIMM1_SPD_DEV_ADDRESS     = 0x51,	PDC_MAX_DIMM_MODULE           = 0x02,	PDC_I2C_CONTROL_OFFSET        = 0x48,	PDC_I2C_ADDR_DATA_OFFSET      = 0x4C,	PDC_DIMM0_CONTROL_OFFSET      = 0x80,	PDC_DIMM1_CONTROL_OFFSET      = 0x84,	PDC_SDRAM_CONTROL_OFFSET      = 0x88,	PDC_I2C_WRITE                 = 0x00000000,	PDC_I2C_READ                  = 0x00000040,		PDC_I2C_START                 = 0x00000080,	PDC_I2C_MASK_INT              = 0x00000020,	PDC_I2C_COMPLETE              = 0x00010000,	PDC_I2C_NO_ACK                = 0x00100000,	PDC_DIMM_SPD_SUBADDRESS_START = 0x00,	PDC_DIMM_SPD_SUBADDRESS_END   = 0x7F,	PDC_DIMM_SPD_ROW_NUM          = 3,	PDC_DIMM_SPD_COLUMN_NUM       = 4,	PDC_DIMM_SPD_MODULE_ROW       = 5,	PDC_DIMM_SPD_TYPE             = 11,	PDC_DIMM_SPD_FRESH_RATE       = 12,         	PDC_DIMM_SPD_BANK_NUM         = 17,		PDC_DIMM_SPD_CAS_LATENCY      = 18,	PDC_DIMM_SPD_ATTRIBUTE        = 21,    	PDC_DIMM_SPD_ROW_PRE_CHARGE   = 27,	PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,      	PDC_DIMM_SPD_RAS_CAS_DELAY    = 29,	PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,	PDC_DIMM_SPD_SYSTEM_FREQ      = 126,	PDC_CTL_STATUS		      = 0x08,		PDC_DIMM_WINDOW_CTLR	      = 0x0C,	PDC_TIME_CONTROL              = 0x3C,	PDC_TIME_PERIOD               = 0x40,	PDC_TIME_COUNTER              = 0x44,	PDC_GENERAL_CTLR	      = 0x484,	PCI_PLL_INIT                  = 0x8A531824,	PCI_X_TCOUNT                  = 0xEE1E5CFF};struct pdc_port_priv {	u8			dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];	u8			*pkt;	dma_addr_t		pkt_dma;};struct pdc_host_priv {	void			*dimm_mmio;	unsigned int		doing_hdma;	unsigned int		hdma_prod;	unsigned int		hdma_cons;	struct {		struct ata_queued_cmd *qc;		unsigned int	seq;		unsigned long	pkt_ofs;	} hdma[32];};static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs);static void pdc_eng_timeout(struct ata_port *ap);static void pdc_20621_phy_reset (struct ata_port *ap);static int pdc_port_start(struct ata_port *ap);static void pdc_port_stop(struct ata_port *ap);static void pdc20621_qc_prep(struct ata_queued_cmd *qc);static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);static void pdc20621_host_stop(struct ata_host_set *host_set);static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);static int pdc20621_detect_dimm(struct ata_probe_ent *pe);static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, 				      u32 device, u32 subaddr, u32 *pdata);static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);#ifdef ATA_VERBOSE_DEBUGstatic void pdc20621_get_from_dimm(struct ata_probe_ent *pe, 				   void *psource, u32 offset, u32 size);#endifstatic void pdc20621_put_to_dimm(struct ata_probe_ent *pe, 				 void *psource, u32 offset, u32 size);static void pdc20621_irq_clear(struct ata_port *ap);static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);static Scsi_Host_Template pdc_sata_sht = {	.module			= THIS_MODULE,	.name			= DRV_NAME,	.ioctl			= ata_scsi_ioctl,	.queuecommand		= ata_scsi_queuecmd,	.eh_strategy_handler	= ata_scsi_error,	.can_queue		= ATA_DEF_QUEUE,	.this_id		= ATA_SHT_THIS_ID,	.sg_tablesize		= LIBATA_MAX_PRD,	.max_sectors		= ATA_MAX_SECTORS,	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,	.emulated		= ATA_SHT_EMULATED,	.use_clustering		= ATA_SHT_USE_CLUSTERING,	.proc_name		= DRV_NAME,	.dma_boundary		= ATA_DMA_BOUNDARY,	.slave_configure	= ata_scsi_slave_config,	.bios_param		= ata_std_bios_param,};static struct ata_port_operations pdc_20621_ops = {	.port_disable		= ata_port_disable,	.tf_load		= pdc_tf_load_mmio,	.tf_read		= ata_tf_read,	.check_status		= ata_check_status,	.exec_command		= pdc_exec_command_mmio,	.dev_select		= ata_std_dev_select,	.phy_reset		= pdc_20621_phy_reset,	.qc_prep		= pdc20621_qc_prep,	.qc_issue		= pdc20621_qc_issue_prot,	.eng_timeout		= pdc_eng_timeout,	.irq_handler		= pdc20621_interrupt,	.irq_clear		= pdc20621_irq_clear,	.port_start		= pdc_port_start,	.port_stop		= pdc_port_stop,	.host_stop		= pdc20621_host_stop,};static struct ata_port_info pdc_port_info[] = {	/* board_20621 */	{		.sht		= &pdc_sata_sht,		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |				  ATA_FLAG_SRST | ATA_FLAG_MMIO,		.pio_mask	= 0x1f, /* pio0-4 */		.mwdma_mask	= 0x07, /* mwdma0-2 */		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */		.port_ops	= &pdc_20621_ops,	},};static struct pci_device_id pdc_sata_pci_tbl[] = {	{ PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	  board_20621 },	{ }	/* terminate list */};static struct pci_driver pdc_sata_pci_driver = {	.name			= DRV_NAME,	.id_table		= pdc_sata_pci_tbl,	.probe			= pdc_sata_init_one,	.remove			= ata_pci_remove_one,};static void pdc20621_host_stop(struct ata_host_set *host_set){	struct pdc_host_priv *hpriv = host_set->private_data;	void *dimm_mmio = hpriv->dimm_mmio;	iounmap(dimm_mmio);	kfree(hpriv);}static int pdc_port_start(struct ata_port *ap){	struct pci_dev *pdev = ap->host_set->pdev;	struct pdc_port_priv *pp;	int rc;	rc = ata_port_start(ap);	if (rc)		return rc;	pp = kmalloc(sizeof(*pp), GFP_KERNEL);	if (!pp) {		rc = -ENOMEM;		goto err_out;	}	memset(pp, 0, sizeof(*pp));	pp->pkt = pci_alloc_consistent(pdev, 128, &pp->pkt_dma);	if (!pp->pkt) {		rc = -ENOMEM;		goto err_out_kfree;	}	ap->private_data = pp;	return 0;err_out_kfree:	kfree(pp);err_out:	ata_port_stop(ap);	return rc;}static void pdc_port_stop(struct ata_port *ap){	struct pci_dev *pdev = ap->host_set->pdev;	struct pdc_port_priv *pp = ap->private_data;	ap->private_data = NULL;	pci_free_consistent(pdev, 128, pp->pkt, pp->pkt_dma);	kfree(pp);	ata_port_stop(ap);}static void pdc_20621_phy_reset (struct ata_port *ap){	VPRINTK("ENTER\n");        ap->cbl = ATA_CBL_SATA;        ata_port_probe(ap);        ata_bus_reset(ap);}static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,				    	   unsigned int portno,					   unsigned int total_len){	u32 addr;	unsigned int dw = PDC_DIMM_APKT_PRD >> 2;	u32 *buf32 = (u32 *) buf;	/* output ATA packet S/G table */	addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +	       (PDC_DIMM_DATA_STEP * portno);	VPRINTK("ATA sg addr 0x%x, %d\n", addr, addr);	buf32[dw] = cpu_to_le32(addr);	buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);	VPRINTK("ATA PSG @ %x == (0x%x, 0x%x)\n",		PDC_20621_DIMM_BASE +		       (PDC_DIMM_WINDOW_STEP * portno) +		       PDC_DIMM_APKT_PRD,		buf32[dw], buf32[dw + 1]);}static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,				    	    unsigned int portno,					    unsigned int total_len){	u32 addr;	unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;	u32 *buf32 = (u32 *) buf;	/* output Host DMA packet S/G table */	addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +	       (PDC_DIMM_DATA_STEP * portno);	buf32[dw] = cpu_to_le32(addr);	buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);	VPRINTK("HOST PSG @ %x == (0x%x, 0x%x)\n",		PDC_20621_DIMM_BASE +		       (PDC_DIMM_WINDOW_STEP * portno) +		       PDC_DIMM_HPKT_PRD,		buf32[dw], buf32[dw + 1]);}static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,					    unsigned int devno, u8 *buf,					    unsigned int portno){	unsigned int i, dw;	u32 *buf32 = (u32 *) buf;	u8 dev_reg;	unsigned int dimm_sg = PDC_20621_DIMM_BASE +			       (PDC_DIMM_WINDOW_STEP * portno) +			       PDC_DIMM_APKT_PRD;	VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);	i = PDC_DIMM_ATA_PKT;	/*	 * Set up ATA packet	 */	if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))		buf[i++] = PDC_PKT_READ;	else if (tf->protocol == ATA_PROT_NODATA)		buf[i++] = PDC_PKT_NODATA;	else		buf[i++] = 0;	buf[i++] = 0;			/* reserved */	buf[i++] = portno + 1;		/* seq. id */	buf[i++] = 0xff;		/* delay seq. id */	/* dimm dma S/G, and next-pkt */	dw = i >> 2;	if (tf->protocol == ATA_PROT_NODATA)		buf32[dw] = 0;	else		buf32[dw] = cpu_to_le32(dimm_sg);	buf32[dw + 1] = 0;	i += 8;	if (devno == 0)		dev_reg = ATA_DEVICE_OBS;	else		dev_reg = ATA_DEVICE_OBS | ATA_DEV1;	/* select device */	buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;	buf[i++] = dev_reg;	/* device control register */	buf[i++] = (1 << 5) | PDC_REG_DEVCTL;	buf[i++] = tf->ctl;	return i;}static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,				     unsigned int portno){	unsigned int dw;	u32 tmp, *buf32 = (u32 *) buf;	unsigned int host_sg = PDC_20621_DIMM_BASE +			       (PDC_DIMM_WINDOW_STEP * portno) +			       PDC_DIMM_HOST_PRD;	unsigned int dimm_sg = PDC_20621_DIMM_BASE +			       (PDC_DIMM_WINDOW_STEP * portno) +			       PDC_DIMM_HPKT_PRD;	VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);	VPRINTK("host_sg == 0x%x, %d\n", host_sg, host_sg);	dw = PDC_DIMM_HOST_PKT >> 2;	/*	 * Set up Host DMA packet	 */	if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))		tmp = PDC_PKT_READ;	else		tmp = 0;	tmp |= ((portno + 1 + 4) << 16);	/* seq. id */	tmp |= (0xff << 24);			/* delay seq. id */	buf32[dw + 0] = cpu_to_le32(tmp);	buf32[dw + 1] = cpu_to_le32(host_sg);	buf32[dw + 2] = cpu_to_le32(dimm_sg);	buf32[dw + 3] = 0;	VPRINTK("HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)\n",		PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) +			PDC_DIMM_HOST_PKT,		buf32[dw + 0],		buf32[dw + 1],		buf32[dw + 2],		buf32[dw + 3]);}static void pdc20621_dma_prep(struct ata_queued_cmd *qc){	struct scatterlist *sg = qc->sg;	struct ata_port *ap = qc->ap;	struct pdc_port_priv *pp = ap->private_data;	void *mmio = ap->host_set->mmio_base;	struct pdc_host_priv *hpriv = ap->host_set->private_data;	void *dimm_mmio = hpriv->dimm_mmio;	unsigned int portno = ap->port_no;	unsigned int i, last, idx, total_len = 0, sgt_len;	u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];	assert(qc->flags & ATA_QCFLAG_DMAMAP);	VPRINTK("ata%u: ENTER\n", ap->id);	/* hard-code chip #0 */	mmio += PDC_CHIP0_OFS;	/*	 * Build S/G table	 */	last = qc->n_elem;	idx = 0;	for (i = 0; i < last; i++) {		buf[idx++] = cpu_to_le32(sg_dma_address(&sg[i]));		buf[idx++] = cpu_to_le32(sg_dma_len(&sg[i]));		total_len += sg[i].length;	}	buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);	sgt_len = idx * 4;	/*	 * Build ATA, host DMA packets	 */	pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);	pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);	pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);	i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);	if (qc->tf.flags & ATA_TFLAG_LBA48)		i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);	else		i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);	pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);	/* copy three S/G tables and two packets to DIMM MMIO window */	memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),		    &pp->dimm_buf, PDC_DIMM_HEADER_SZ);	memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +		    PDC_DIMM_HOST_PRD,		    &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);	/* force host FIFO dump */	writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);	readl(dimm_mmio);	/* MMIO PCI posting flush */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?