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

📄 ahci.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		  ahci_postreset);}static void ahci_post_internal_cmd(struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	/* make DMA engine forget about the failed command */	if (qc->flags & ATA_QCFLAG_FAILED)		ahci_kick_engine(ap, 1);}static void ahci_pmp_attach(struct ata_port *ap){	void __iomem *port_mmio = ahci_port_base(ap);	struct ahci_port_priv *pp = ap->private_data;	u32 cmd;	cmd = readl(port_mmio + PORT_CMD);	cmd |= PORT_CMD_PMP;	writel(cmd, port_mmio + PORT_CMD);	pp->intr_mask |= PORT_IRQ_BAD_PMP;	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);}static void ahci_pmp_detach(struct ata_port *ap){	void __iomem *port_mmio = ahci_port_base(ap);	struct ahci_port_priv *pp = ap->private_data;	u32 cmd;	cmd = readl(port_mmio + PORT_CMD);	cmd &= ~PORT_CMD_PMP;	writel(cmd, port_mmio + PORT_CMD);	pp->intr_mask &= ~PORT_IRQ_BAD_PMP;	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);}static int ahci_port_resume(struct ata_port *ap){	ahci_power_up(ap);	ahci_start_port(ap);	if (ap->nr_pmp_links)		ahci_pmp_attach(ap);	else		ahci_pmp_detach(ap);	return 0;}#ifdef CONFIG_PMstatic int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg){	const char *emsg = NULL;	int rc;	rc = ahci_deinit_port(ap, &emsg);	if (rc == 0)		ahci_power_down(ap);	else {		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);		ahci_start_port(ap);	}	return rc;}static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg){	struct ata_host *host = dev_get_drvdata(&pdev->dev);	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];	u32 ctl;	if (mesg.event == PM_EVENT_SUSPEND) {		/* AHCI spec rev1.1 section 8.3.3:		 * Software must disable interrupts prior to requesting a		 * transition of the HBA to D3 state.		 */		ctl = readl(mmio + HOST_CTL);		ctl &= ~HOST_IRQ_EN;		writel(ctl, mmio + HOST_CTL);		readl(mmio + HOST_CTL); /* flush */	}	return ata_pci_device_suspend(pdev, mesg);}static int ahci_pci_device_resume(struct pci_dev *pdev){	struct ata_host *host = dev_get_drvdata(&pdev->dev);	int rc;	rc = ata_pci_device_do_resume(pdev);	if (rc)		return rc;	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {		rc = ahci_reset_controller(host);		if (rc)			return rc;		ahci_init_controller(host);	}	ata_host_resume(host);	return 0;}#endifstatic int ahci_port_start(struct ata_port *ap){	struct device *dev = ap->host->dev;	struct ahci_port_priv *pp;	void *mem;	dma_addr_t mem_dma;	int rc;	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);	if (!pp)		return -ENOMEM;	rc = ata_pad_alloc(ap, dev);	if (rc)		return rc;	mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,				  GFP_KERNEL);	if (!mem)		return -ENOMEM;	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);	/*	 * First item in chunk of DMA memory: 32-slot command table,	 * 32 bytes each in size	 */	pp->cmd_slot = mem;	pp->cmd_slot_dma = mem_dma;	mem += AHCI_CMD_SLOT_SZ;	mem_dma += AHCI_CMD_SLOT_SZ;	/*	 * Second item: Received-FIS area	 */	pp->rx_fis = mem;	pp->rx_fis_dma = mem_dma;	mem += AHCI_RX_FIS_SZ;	mem_dma += AHCI_RX_FIS_SZ;	/*	 * Third item: data area for storing a single command	 * and its scatter-gather table	 */	pp->cmd_tbl = mem;	pp->cmd_tbl_dma = mem_dma;	/*	 * Save off initial list of interrupts to be enabled.	 * This could be changed later	 */	pp->intr_mask = DEF_PORT_IRQ;	ap->private_data = pp;	/* engage engines, captain */	return ahci_port_resume(ap);}static void ahci_port_stop(struct ata_port *ap){	const char *emsg = NULL;	int rc;	/* de-initialize port */	rc = ahci_deinit_port(ap, &emsg);	if (rc)		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);}static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac){	int rc;	if (using_dac &&	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);		if (rc) {			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);			if (rc) {				dev_printk(KERN_ERR, &pdev->dev,					   "64-bit DMA enable failed\n");				return rc;			}		}	} else {		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);		if (rc) {			dev_printk(KERN_ERR, &pdev->dev,				   "32-bit DMA enable failed\n");			return rc;		}		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);		if (rc) {			dev_printk(KERN_ERR, &pdev->dev,				   "32-bit consistent DMA enable failed\n");			return rc;		}	}	return 0;}static void ahci_print_info(struct ata_host *host){	struct ahci_host_priv *hpriv = host->private_data;	struct pci_dev *pdev = to_pci_dev(host->dev);	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];	u32 vers, cap, impl, speed;	const char *speed_s;	u16 cc;	const char *scc_s;	vers = readl(mmio + HOST_VERSION);	cap = hpriv->cap;	impl = hpriv->port_map;	speed = (cap >> 20) & 0xf;	if (speed == 1)		speed_s = "1.5";	else if (speed == 2)		speed_s = "3";	else		speed_s = "?";	pci_read_config_word(pdev, 0x0a, &cc);	if (cc == PCI_CLASS_STORAGE_IDE)		scc_s = "IDE";	else if (cc == PCI_CLASS_STORAGE_SATA)		scc_s = "SATA";	else if (cc == PCI_CLASS_STORAGE_RAID)		scc_s = "RAID";	else		scc_s = "unknown";	dev_printk(KERN_INFO, &pdev->dev,		"AHCI %02x%02x.%02x%02x "		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"		,		(vers >> 24) & 0xff,		(vers >> 16) & 0xff,		(vers >> 8) & 0xff,		vers & 0xff,		((cap >> 8) & 0x1f) + 1,		(cap & 0x1f) + 1,		speed_s,		impl,		scc_s);	dev_printk(KERN_INFO, &pdev->dev,		"flags: "		"%s%s%s%s%s%s%s"		"%s%s%s%s%s%s%s\n"		,		cap & (1 << 31) ? "64bit " : "",		cap & (1 << 30) ? "ncq " : "",		cap & (1 << 29) ? "sntf " : "",		cap & (1 << 28) ? "ilck " : "",		cap & (1 << 27) ? "stag " : "",		cap & (1 << 26) ? "pm " : "",		cap & (1 << 25) ? "led " : "",		cap & (1 << 24) ? "clo " : "",		cap & (1 << 19) ? "nz " : "",		cap & (1 << 18) ? "only " : "",		cap & (1 << 17) ? "pmp " : "",		cap & (1 << 15) ? "pio " : "",		cap & (1 << 14) ? "slum " : "",		cap & (1 << 13) ? "part " : ""		);}/* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't * support PMP and the 4726 either directly exports the device * attached to the first downstream port or acts as a hardware storage * controller and emulate a single ATA device (can be RAID 0/1 or some * other configuration). * * When there's no device attached to the first downstream port of the * 4726, "Config Disk" appears, which is a pseudo ATA device to * configure the 4726.  However, ATA emulation of the device is very * lame.  It doesn't send signature D2H Reg FIS after the initial * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues. * * The following function works around the problem by always using * hardreset on the port and not depending on receiving signature FIS * afterward.  If signature FIS isn't received soon, ATA class is * assumed without follow-up softreset. */static void ahci_p5wdh_workaround(struct ata_host *host){	static struct dmi_system_id sysids[] = {		{			.ident = "P5W DH Deluxe",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR,					  "ASUSTEK COMPUTER INC"),				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),			},		},		{ }	};	struct pci_dev *pdev = to_pci_dev(host->dev);	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&	    dmi_check_system(sysids)) {		struct ata_port *ap = host->ports[1];		dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "			   "Deluxe on-board SIMG4726 workaround\n");		ap->ops = &ahci_p5wdh_ops;		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;	}}static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){	static int printed_version;	struct ata_port_info pi = ahci_port_info[ent->driver_data];	const struct ata_port_info *ppi[] = { &pi, NULL };	struct device *dev = &pdev->dev;	struct ahci_host_priv *hpriv;	struct ata_host *host;	int i, rc;	VPRINTK("ENTER\n");	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);	if (!printed_version++)		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");	/* acquire resources */	rc = pcim_enable_device(pdev);	if (rc)		return rc;	rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);	if (rc == -EBUSY)		pcim_pin_device(pdev);	if (rc)		return rc;	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {		u8 map;		/* ICH6s share the same PCI ID for both piix and ahci		 * modes.  Enabling ahci mode while MAP indicates		 * combined mode is a bad idea.  Yield to ata_piix.		 */		pci_read_config_byte(pdev, ICH_MAP, &map);		if (map & 0x3) {			dev_printk(KERN_INFO, &pdev->dev, "controller is in "				   "combined mode, can't enable AHCI mode\n");			return -ENODEV;		}	}	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);	if (!hpriv)		return -ENOMEM;	hpriv->flags |= (unsigned long)pi.private_data;	if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))		pci_intx(pdev, 1);	/* save initial config */	ahci_save_initial_config(pdev, hpriv);	/* prepare host */	if (hpriv->cap & HOST_CAP_NCQ)		pi.flags |= ATA_FLAG_NCQ;	if (hpriv->cap & HOST_CAP_PMP)		pi.flags |= ATA_FLAG_PMP;	host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));	if (!host)		return -ENOMEM;	host->iomap = pcim_iomap_table(pdev);	host->private_data = hpriv;	for (i = 0; i < host->n_ports; i++) {		struct ata_port *ap = host->ports[i];		void __iomem *port_mmio = ahci_port_base(ap);		ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");		ata_port_pbar_desc(ap, AHCI_PCI_BAR,				   0x100 + ap->port_no * 0x80, "port");		/* set initial link pm policy */		ap->pm_policy = NOT_AVAILABLE;		/* standard SATA port setup */		if (hpriv->port_map & (1 << i))			ap->ioaddr.cmd_addr = port_mmio;		/* disabled/not-implemented port */		else			ap->ops = &ata_dummy_port_ops;	}	/* apply workaround for ASUS P5W DH Deluxe mainboard */	ahci_p5wdh_workaround(host);	/* initialize adapter */	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);	if (rc)		return rc;	rc = ahci_reset_controller(host);	if (rc)		return rc;	ahci_init_controller(host);	ahci_print_info(host);	pci_set_master(pdev);	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,				 &ahci_sht);}static int __init ahci_init(void){	return pci_register_driver(&ahci_pci_driver);}static void __exit ahci_exit(void){	pci_unregister_driver(&ahci_pci_driver);}MODULE_AUTHOR("Jeff Garzik");MODULE_DESCRIPTION("AHCI SATA low-level driver");MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);MODULE_VERSION(DRV_VERSION);module_init(ahci_init);module_exit(ahci_exit);

⌨️ 快捷键说明

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