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

📄 sata_mv.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * sata_mv.c - Marvell SATA support * * Copyright 2005: EMC Corporation, all rights reserved. * Copyright 2005 Red Hat, Inc.  All rights reserved. * * Please ALWAYS copy linux-ide@vger.kernel.org on emails. * * 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; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * *//*  sata_mv TODO list:  1) Needs a full errata audit for all chipsets.  I implemented most  of the errata workarounds found in the Marvell vendor driver, but  I distinctly remember a couple workarounds (one related to PCI-X)  are still needed.  4) Add NCQ support (easy to intermediate, once new-EH support appears)  5) Investigate problems with PCI Message Signalled Interrupts (MSI).  6) Add port multiplier support (intermediate)  8) Develop a low-power-consumption strategy, and implement it.  9) [Experiment, low priority] See if ATAPI can be supported using  "unknown FIS" or "vendor-specific FIS" support, or something creative  like that.  10) [Experiment, low priority] Investigate interrupt coalescing.  Quite often, especially with PCI Message Signalled Interrupts (MSI),  the overhead reduced by interrupt mitigation is quite often not  worth the latency cost.  11) [Experiment, Marvell value added] Is it possible to use target  mode to cross-connect two Linux boxes with Marvell cards?  If so,  creating LibATA target mode support would be very interesting.  Target mode, for those without docs, is the ability to directly  connect two SATA controllers.  13) Verify that 7042 is fully supported.  I only have a 6042.*/#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/dma-mapping.h>#include <linux/device.h>#include <scsi/scsi_host.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <linux/libata.h>#define DRV_NAME	"sata_mv"#define DRV_VERSION	"1.01"enum {	/* BAR's are enumerated in terms of pci_resource_start() terms */	MV_PRIMARY_BAR		= 0,	/* offset 0x10: memory space */	MV_IO_BAR		= 2,	/* offset 0x18: IO space */	MV_MISC_BAR		= 3,	/* offset 0x1c: FLASH, NVRAM, SRAM */	MV_MAJOR_REG_AREA_SZ	= 0x10000,	/* 64KB */	MV_MINOR_REG_AREA_SZ	= 0x2000,	/* 8KB */	MV_PCI_REG_BASE		= 0,	MV_IRQ_COAL_REG_BASE	= 0x18000,	/* 6xxx part only */	MV_IRQ_COAL_CAUSE		= (MV_IRQ_COAL_REG_BASE + 0x08),	MV_IRQ_COAL_CAUSE_LO		= (MV_IRQ_COAL_REG_BASE + 0x88),	MV_IRQ_COAL_CAUSE_HI		= (MV_IRQ_COAL_REG_BASE + 0x8c),	MV_IRQ_COAL_THRESHOLD		= (MV_IRQ_COAL_REG_BASE + 0xcc),	MV_IRQ_COAL_TIME_THRESHOLD	= (MV_IRQ_COAL_REG_BASE + 0xd0),	MV_SATAHC0_REG_BASE	= 0x20000,	MV_FLASH_CTL		= 0x1046c,	MV_GPIO_PORT_CTL	= 0x104f0,	MV_RESET_CFG		= 0x180d8,	MV_PCI_REG_SZ		= MV_MAJOR_REG_AREA_SZ,	MV_SATAHC_REG_SZ	= MV_MAJOR_REG_AREA_SZ,	MV_SATAHC_ARBTR_REG_SZ	= MV_MINOR_REG_AREA_SZ,		/* arbiter */	MV_PORT_REG_SZ		= MV_MINOR_REG_AREA_SZ,	MV_MAX_Q_DEPTH		= 32,	MV_MAX_Q_DEPTH_MASK	= MV_MAX_Q_DEPTH - 1,	/* CRQB needs alignment on a 1KB boundary. Size == 1KB	 * CRPB needs alignment on a 256B boundary. Size == 256B	 * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB	 * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B	 */	MV_CRQB_Q_SZ		= (32 * MV_MAX_Q_DEPTH),	MV_CRPB_Q_SZ		= (8 * MV_MAX_Q_DEPTH),	MV_MAX_SG_CT		= 176,	MV_SG_TBL_SZ		= (16 * MV_MAX_SG_CT),	MV_PORT_PRIV_DMA_SZ	= (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),	MV_PORTS_PER_HC		= 4,	/* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */	MV_PORT_HC_SHIFT	= 2,	/* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */	MV_PORT_MASK		= 3,	/* Host Flags */	MV_FLAG_DUAL_HC		= (1 << 30),  /* two SATA Host Controllers */	MV_FLAG_IRQ_COALESCE	= (1 << 29),  /* IRQ coalescing capability */	MV_COMMON_FLAGS		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |				  ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |				  ATA_FLAG_PIO_POLLING,	MV_6XXX_FLAGS		= MV_FLAG_IRQ_COALESCE,	CRQB_FLAG_READ		= (1 << 0),	CRQB_TAG_SHIFT		= 1,	CRQB_IOID_SHIFT		= 6,	/* CRQB Gen-II/IIE IO Id shift */	CRQB_HOSTQ_SHIFT	= 17,	/* CRQB Gen-II/IIE HostQueTag shift */	CRQB_CMD_ADDR_SHIFT	= 8,	CRQB_CMD_CS		= (0x2 << 11),	CRQB_CMD_LAST		= (1 << 15),	CRPB_FLAG_STATUS_SHIFT	= 8,	CRPB_IOID_SHIFT_6	= 5,	/* CRPB Gen-II IO Id shift */	CRPB_IOID_SHIFT_7	= 7,	/* CRPB Gen-IIE IO Id shift */	EPRD_FLAG_END_OF_TBL	= (1 << 31),	/* PCI interface registers */	PCI_COMMAND_OFS		= 0xc00,	PCI_MAIN_CMD_STS_OFS	= 0xd30,	STOP_PCI_MASTER		= (1 << 2),	PCI_MASTER_EMPTY	= (1 << 3),	GLOB_SFT_RST		= (1 << 4),	MV_PCI_MODE		= 0xd00,	MV_PCI_EXP_ROM_BAR_CTL	= 0xd2c,	MV_PCI_DISC_TIMER	= 0xd04,	MV_PCI_MSI_TRIGGER	= 0xc38,	MV_PCI_SERR_MASK	= 0xc28,	MV_PCI_XBAR_TMOUT	= 0x1d04,	MV_PCI_ERR_LOW_ADDRESS	= 0x1d40,	MV_PCI_ERR_HIGH_ADDRESS	= 0x1d44,	MV_PCI_ERR_ATTRIBUTE	= 0x1d48,	MV_PCI_ERR_COMMAND	= 0x1d50,	PCI_IRQ_CAUSE_OFS	= 0x1d58,	PCI_IRQ_MASK_OFS	= 0x1d5c,	PCI_UNMASK_ALL_IRQS	= 0x7fffff,	/* bits 22-0 */	PCIE_IRQ_CAUSE_OFS	= 0x1900,	PCIE_IRQ_MASK_OFS	= 0x1910,	PCIE_UNMASK_ALL_IRQS	= 0x70a,	/* assorted bits */	HC_MAIN_IRQ_CAUSE_OFS	= 0x1d60,	HC_MAIN_IRQ_MASK_OFS	= 0x1d64,	PORT0_ERR		= (1 << 0),	/* shift by port # */	PORT0_DONE		= (1 << 1),	/* shift by port # */	HC0_IRQ_PEND		= 0x1ff,	/* bits 0-8 = HC0's ports */	HC_SHIFT		= 9,		/* bits 9-17 = HC1's ports */	PCI_ERR			= (1 << 18),	TRAN_LO_DONE		= (1 << 19),	/* 6xxx: IRQ coalescing */	TRAN_HI_DONE		= (1 << 20),	/* 6xxx: IRQ coalescing */	PORTS_0_3_COAL_DONE	= (1 << 8),	PORTS_4_7_COAL_DONE	= (1 << 17),	PORTS_0_7_COAL_DONE	= (1 << 21),	/* 6xxx: IRQ coalescing */	GPIO_INT		= (1 << 22),	SELF_INT		= (1 << 23),	TWSI_INT		= (1 << 24),	HC_MAIN_RSVD		= (0x7f << 25),	/* bits 31-25 */	HC_MAIN_RSVD_5		= (0x1fff << 19), /* bits 31-19 */	HC_MAIN_MASKED_IRQS	= (TRAN_LO_DONE | TRAN_HI_DONE |				   PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |				   HC_MAIN_RSVD),	HC_MAIN_MASKED_IRQS_5	= (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |				   HC_MAIN_RSVD_5),	/* SATAHC registers */	HC_CFG_OFS		= 0,	HC_IRQ_CAUSE_OFS	= 0x14,	CRPB_DMA_DONE		= (1 << 0),	/* shift by port # */	HC_IRQ_COAL		= (1 << 4),	/* IRQ coalescing */	DEV_IRQ			= (1 << 8),	/* shift by port # */	/* Shadow block registers */	SHD_BLK_OFS		= 0x100,	SHD_CTL_AST_OFS		= 0x20,		/* ofs from SHD_BLK_OFS */	/* SATA registers */	SATA_STATUS_OFS		= 0x300,  /* ctrl, err regs follow status */	SATA_ACTIVE_OFS		= 0x350,	PHY_MODE3		= 0x310,	PHY_MODE4		= 0x314,	PHY_MODE2		= 0x330,	MV5_PHY_MODE		= 0x74,	MV5_LT_MODE		= 0x30,	MV5_PHY_CTL		= 0x0C,	SATA_INTERFACE_CTL	= 0x050,	MV_M2_PREAMP_MASK	= 0x7e0,	/* Port registers */	EDMA_CFG_OFS		= 0,	EDMA_CFG_Q_DEPTH	= 0,			/* queueing disabled */	EDMA_CFG_NCQ		= (1 << 5),	EDMA_CFG_NCQ_GO_ON_ERR	= (1 << 14),		/* continue on error */	EDMA_CFG_RD_BRST_EXT	= (1 << 11),		/* read burst 512B */	EDMA_CFG_WR_BUFF_LEN	= (1 << 13),		/* write buffer 512B */	EDMA_ERR_IRQ_CAUSE_OFS	= 0x8,	EDMA_ERR_IRQ_MASK_OFS	= 0xc,	EDMA_ERR_D_PAR		= (1 << 0),	/* UDMA data parity err */	EDMA_ERR_PRD_PAR	= (1 << 1),	/* UDMA PRD parity err */	EDMA_ERR_DEV		= (1 << 2),	/* device error */	EDMA_ERR_DEV_DCON	= (1 << 3),	/* device disconnect */	EDMA_ERR_DEV_CON	= (1 << 4),	/* device connected */	EDMA_ERR_SERR		= (1 << 5),	/* SError bits [WBDST] raised */	EDMA_ERR_SELF_DIS	= (1 << 7),	/* Gen II/IIE self-disable */	EDMA_ERR_SELF_DIS_5	= (1 << 8),	/* Gen I self-disable */	EDMA_ERR_BIST_ASYNC	= (1 << 8),	/* BIST FIS or Async Notify */	EDMA_ERR_TRANS_IRQ_7	= (1 << 8),	/* Gen IIE transprt layer irq */	EDMA_ERR_CRQB_PAR	= (1 << 9),	/* CRQB parity error */	EDMA_ERR_CRPB_PAR	= (1 << 10),	/* CRPB parity error */	EDMA_ERR_INTRL_PAR	= (1 << 11),	/* internal parity error */	EDMA_ERR_IORDY		= (1 << 12),	/* IORdy timeout */	EDMA_ERR_LNK_CTRL_RX	= (0xf << 13),	/* link ctrl rx error */	EDMA_ERR_LNK_CTRL_RX_2	= (1 << 15),	EDMA_ERR_LNK_DATA_RX	= (0xf << 17),	/* link data rx error */	EDMA_ERR_LNK_CTRL_TX	= (0x1f << 21),	/* link ctrl tx error */	EDMA_ERR_LNK_DATA_TX	= (0x1f << 26),	/* link data tx error */	EDMA_ERR_TRANS_PROTO	= (1 << 31),	/* transport protocol error */	EDMA_ERR_OVERRUN_5	= (1 << 5),	EDMA_ERR_UNDERRUN_5	= (1 << 6),	EDMA_EH_FREEZE		= EDMA_ERR_D_PAR |				  EDMA_ERR_PRD_PAR |				  EDMA_ERR_DEV_DCON |				  EDMA_ERR_DEV_CON |				  EDMA_ERR_SERR |				  EDMA_ERR_SELF_DIS |				  EDMA_ERR_CRQB_PAR |				  EDMA_ERR_CRPB_PAR |				  EDMA_ERR_INTRL_PAR |				  EDMA_ERR_IORDY |				  EDMA_ERR_LNK_CTRL_RX_2 |				  EDMA_ERR_LNK_DATA_RX |				  EDMA_ERR_LNK_DATA_TX |				  EDMA_ERR_TRANS_PROTO,	EDMA_EH_FREEZE_5	= EDMA_ERR_D_PAR |				  EDMA_ERR_PRD_PAR |				  EDMA_ERR_DEV_DCON |				  EDMA_ERR_DEV_CON |				  EDMA_ERR_OVERRUN_5 |				  EDMA_ERR_UNDERRUN_5 |				  EDMA_ERR_SELF_DIS_5 |				  EDMA_ERR_CRQB_PAR |				  EDMA_ERR_CRPB_PAR |				  EDMA_ERR_INTRL_PAR |				  EDMA_ERR_IORDY,	EDMA_REQ_Q_BASE_HI_OFS	= 0x10,	EDMA_REQ_Q_IN_PTR_OFS	= 0x14,		/* also contains BASE_LO */	EDMA_REQ_Q_OUT_PTR_OFS	= 0x18,	EDMA_REQ_Q_PTR_SHIFT	= 5,	EDMA_RSP_Q_BASE_HI_OFS	= 0x1c,	EDMA_RSP_Q_IN_PTR_OFS	= 0x20,	EDMA_RSP_Q_OUT_PTR_OFS	= 0x24,		/* also contains BASE_LO */	EDMA_RSP_Q_PTR_SHIFT	= 3,	EDMA_CMD_OFS		= 0x28,		/* EDMA command register */	EDMA_EN			= (1 << 0),	/* enable EDMA */	EDMA_DS			= (1 << 1),	/* disable EDMA; self-negated */	ATA_RST			= (1 << 2),	/* reset trans/link/phy */	EDMA_IORDY_TMOUT	= 0x34,	EDMA_ARB_CFG		= 0x38,	/* Host private flags (hp_flags) */	MV_HP_FLAG_MSI		= (1 << 0),	MV_HP_ERRATA_50XXB0	= (1 << 1),	MV_HP_ERRATA_50XXB2	= (1 << 2),	MV_HP_ERRATA_60X1B2	= (1 << 3),	MV_HP_ERRATA_60X1C0	= (1 << 4),	MV_HP_ERRATA_XX42A0	= (1 << 5),	MV_HP_GEN_I		= (1 << 6),	/* Generation I: 50xx */	MV_HP_GEN_II		= (1 << 7),	/* Generation II: 60xx */	MV_HP_GEN_IIE		= (1 << 8),	/* Generation IIE: 6042/7042 */	MV_HP_PCIE		= (1 << 9),	/* PCIe bus/regs: 7042 */	/* Port private flags (pp_flags) */	MV_PP_FLAG_EDMA_EN	= (1 << 0),	/* is EDMA engine enabled? */	MV_PP_FLAG_HAD_A_RESET	= (1 << 2),	/* 1st hard reset complete? */};#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)#define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)enum {	/* DMA boundary 0xffff is required by the s/g splitting	 * we need on /length/ in mv_fill-sg().	 */	MV_DMA_BOUNDARY		= 0xffffU,	/* mask of register bits containing lower 32 bits	 * of EDMA request queue DMA address	 */	EDMA_REQ_Q_BASE_LO_MASK	= 0xfffffc00U,	/* ditto, for response queue */	EDMA_RSP_Q_BASE_LO_MASK	= 0xffffff00U,};enum chip_type {	chip_504x,	chip_508x,	chip_5080,	chip_604x,	chip_608x,	chip_6042,	chip_7042,};/* Command ReQuest Block: 32B */struct mv_crqb {	__le32			sg_addr;	__le32			sg_addr_hi;	__le16			ctrl_flags;	__le16			ata_cmd[11];};struct mv_crqb_iie {	__le32			addr;	__le32			addr_hi;	__le32			flags;	__le32			len;	__le32			ata_cmd[4];};/* Command ResPonse Block: 8B */struct mv_crpb {	__le16			id;	__le16			flags;	__le32			tmstmp;};/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */struct mv_sg {	__le32			addr;	__le32			flags_size;	__le32			addr_hi;	__le32			reserved;};struct mv_port_priv {	struct mv_crqb		*crqb;	dma_addr_t		crqb_dma;	struct mv_crpb		*crpb;	dma_addr_t		crpb_dma;	struct mv_sg		*sg_tbl;	dma_addr_t		sg_tbl_dma;	unsigned int		req_idx;	unsigned int		resp_idx;	u32			pp_flags;};struct mv_port_signal {	u32			amps;	u32			pre;};struct mv_host_priv {	u32			hp_flags;	struct mv_port_signal	signal[8];	const struct mv_hw_ops	*ops;	u32			irq_cause_ofs;	u32			irq_mask_ofs;	u32			unmask_all_irqs;};struct mv_hw_ops {	void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio,			   unsigned int port);	void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);	void (*read_preamp)(struct mv_host_priv *hpriv, int idx,			   void __iomem *mmio);	int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,			unsigned int n_hc);	void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);	void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);};static void mv_irq_clear(struct ata_port *ap);static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);static int mv_port_start(struct ata_port *ap);static void mv_port_stop(struct ata_port *ap);static void mv_qc_prep(struct ata_queued_cmd *qc);static void mv_qc_prep_iie(struct ata_queued_cmd *qc);static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);static void mv_error_handler(struct ata_port *ap);static void mv_post_int_cmd(struct ata_queued_cmd *qc);static void mv_eh_freeze(struct ata_port *ap);static void mv_eh_thaw(struct ata_port *ap);static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,			   unsigned int port);static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,			   void __iomem *mmio);static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,			unsigned int n_hc);static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,			   unsigned int port);static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,			   void __iomem *mmio);static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,			unsigned int n_hc);static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,			     unsigned int port_no);static struct scsi_host_template mv5_sht = {	.module			= THIS_MODULE,	.name			= DRV_NAME,	.ioctl			= ata_scsi_ioctl,	.queuecommand		= ata_scsi_queuecmd,	.can_queue		= ATA_DEF_QUEUE,	.this_id		= ATA_SHT_THIS_ID,	.sg_tablesize		= MV_MAX_SG_CT / 2,	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,	.emulated		= ATA_SHT_EMULATED,	.use_clustering		= 1,	.proc_name		= DRV_NAME,	.dma_boundary		= MV_DMA_BOUNDARY,	.slave_configure	= ata_scsi_slave_config,	.slave_destroy		= ata_scsi_slave_destroy,	.bios_param		= ata_std_bios_param,};static struct scsi_host_template mv6_sht = {	.module			= THIS_MODULE,	.name			= DRV_NAME,	.ioctl			= ata_scsi_ioctl,	.queuecommand		= ata_scsi_queuecmd,	.can_queue		= ATA_DEF_QUEUE,	.this_id		= ATA_SHT_THIS_ID,	.sg_tablesize		= MV_MAX_SG_CT / 2,	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,	.emulated		= ATA_SHT_EMULATED,	.use_clustering		= 1,	.proc_name		= DRV_NAME,	.dma_boundary		= MV_DMA_BOUNDARY,	.slave_configure	= ata_scsi_slave_config,

⌨️ 快捷键说明

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