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

📄 ata_piix.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 *	Set MW/UDMA mode for device, in host controller PCI config space. * *	LOCKING: *	None (inherited from caller). */static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev){	do_pata_set_dmamode(ap, adev, 0);}/** *	ich_set_dmamode - Initialize host controller PATA DMA timings *	@ap: Port whose timings we are configuring *	@adev: um * *	Set MW/UDMA mode for device, in host controller PCI config space. * *	LOCKING: *	None (inherited from caller). */static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev){	do_pata_set_dmamode(ap, adev, 1);}#ifdef CONFIG_PMstatic int piix_broken_suspend(void){	static const struct dmi_system_id sysids[] = {		{			.ident = "TECRA M3",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M3"),			},		},		{			.ident = "TECRA M3",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),				DMI_MATCH(DMI_PRODUCT_NAME, "Tecra M3"),			},		},		{			.ident = "TECRA M4",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),				DMI_MATCH(DMI_PRODUCT_NAME, "Tecra M4"),			},		},		{			.ident = "TECRA M5",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M5"),			},		},		{			.ident = "TECRA M7",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M7"),			},		},		{			.ident = "TECRA A8",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A8"),			},		},		{			.ident = "Satellite R25",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),				DMI_MATCH(DMI_PRODUCT_NAME, "Satellite R25"),			},		},		{			.ident = "Satellite U200",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),				DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U200"),			},		},		{			.ident = "Satellite U200",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),				DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE U200"),			},		},		{			.ident = "Satellite Pro U200",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),				DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE PRO U200"),			},		},		{			.ident = "Satellite U205",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),				DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U205"),			},		},		{			.ident = "SATELLITE U205",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),				DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE U205"),			},		},		{			.ident = "Portege M500",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),				DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M500"),			},		},		{ }	/* terminate list */	};	static const char *oemstrs[] = {		"Tecra M3,",	};	int i;	if (dmi_check_system(sysids))		return 1;	for (i = 0; i < ARRAY_SIZE(oemstrs); i++)		if (dmi_find_device(DMI_DEV_TYPE_OEM_STRING, oemstrs[i], NULL))			return 1;	return 0;}static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg){	struct ata_host *host = dev_get_drvdata(&pdev->dev);	unsigned long flags;	int rc = 0;	rc = ata_host_suspend(host, mesg);	if (rc)		return rc;	/* Some braindamaged ACPI suspend implementations expect the	 * controller to be awake on entry; otherwise, it burns cpu	 * cycles and power trying to do something to the sleeping	 * beauty.	 */	if (piix_broken_suspend() && mesg.event == PM_EVENT_SUSPEND) {		pci_save_state(pdev);		/* mark its power state as "unknown", since we don't		 * know if e.g. the BIOS will change its device state		 * when we suspend.		 */		if (pdev->current_state == PCI_D0)			pdev->current_state = PCI_UNKNOWN;		/* tell resume that it's waking up from broken suspend */		spin_lock_irqsave(&host->lock, flags);		host->flags |= PIIX_HOST_BROKEN_SUSPEND;		spin_unlock_irqrestore(&host->lock, flags);	} else		ata_pci_device_do_suspend(pdev, mesg);	return 0;}static int piix_pci_device_resume(struct pci_dev *pdev){	struct ata_host *host = dev_get_drvdata(&pdev->dev);	unsigned long flags;	int rc;	if (host->flags & PIIX_HOST_BROKEN_SUSPEND) {		spin_lock_irqsave(&host->lock, flags);		host->flags &= ~PIIX_HOST_BROKEN_SUSPEND;		spin_unlock_irqrestore(&host->lock, flags);		pci_set_power_state(pdev, PCI_D0);		pci_restore_state(pdev);		/* PCI device wasn't disabled during suspend.  Use		 * pci_reenable_device() to avoid affecting the enable		 * count.		 */		rc = pci_reenable_device(pdev);		if (rc)			dev_printk(KERN_ERR, &pdev->dev, "failed to enable "				   "device after resume (%d)\n", rc);	} else		rc = ata_pci_device_do_resume(pdev);	if (rc == 0)		ata_host_resume(host);	return rc;}#endifstatic u8 piix_vmw_bmdma_status(struct ata_port *ap){	return ata_bmdma_status(ap) & ~ATA_DMA_ERR;}#define AHCI_PCI_BAR 5#define AHCI_GLOBAL_CTL 0x04#define AHCI_ENABLE (1 << 31)static int piix_disable_ahci(struct pci_dev *pdev){	void __iomem *mmio;	u32 tmp;	int rc = 0;	/* BUG: pci_enable_device has not yet been called.  This	 * works because this device is usually set up by BIOS.	 */	if (!pci_resource_start(pdev, AHCI_PCI_BAR) ||	    !pci_resource_len(pdev, AHCI_PCI_BAR))		return 0;	mmio = pci_iomap(pdev, AHCI_PCI_BAR, 64);	if (!mmio)		return -ENOMEM;	tmp = ioread32(mmio + AHCI_GLOBAL_CTL);	if (tmp & AHCI_ENABLE) {		tmp &= ~AHCI_ENABLE;		iowrite32(tmp, mmio + AHCI_GLOBAL_CTL);		tmp = ioread32(mmio + AHCI_GLOBAL_CTL);		if (tmp & AHCI_ENABLE)			rc = -EIO;	}	pci_iounmap(pdev, mmio);	return rc;}/** *	piix_check_450nx_errata	-	Check for problem 450NX setup *	@ata_dev: the PCI device to check * *	Check for the present of 450NX errata #19 and errata #25. If *	they are found return an error code so we can turn off DMA */static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev){	struct pci_dev *pdev = NULL;	u16 cfg;	int no_piix_dma = 0;	while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev)) != NULL) {		/* Look for 450NX PXB. Check for problem configurations		   A PCI quirk checks bit 6 already */		pci_read_config_word(pdev, 0x41, &cfg);		/* Only on the original revision: IDE DMA can hang */		if (pdev->revision == 0x00)			no_piix_dma = 1;		/* On all revisions below 5 PXB bus lock must be disabled for IDE */		else if (cfg & (1<<14) && pdev->revision < 5)			no_piix_dma = 2;	}	if (no_piix_dma)		dev_printk(KERN_WARNING, &ata_dev->dev, "450NX errata present, disabling IDE DMA.\n");	if (no_piix_dma == 2)		dev_printk(KERN_WARNING, &ata_dev->dev, "A BIOS update may resolve this.\n");	return no_piix_dma;}static void __devinit piix_init_pcs(struct pci_dev *pdev,				    struct ata_port_info *pinfo,				    const struct piix_map_db *map_db){	u16 pcs, new_pcs;	pci_read_config_word(pdev, ICH5_PCS, &pcs);	new_pcs = pcs | map_db->port_enable;	if (new_pcs != pcs) {		DPRINTK("updating PCS from 0x%x to 0x%x\n", pcs, new_pcs);		pci_write_config_word(pdev, ICH5_PCS, new_pcs);		msleep(150);	}}static void __devinit piix_init_sata_map(struct pci_dev *pdev,					 struct ata_port_info *pinfo,					 const struct piix_map_db *map_db){	struct piix_host_priv *hpriv = pinfo[0].private_data;	const int *map;	int i, invalid_map = 0;	u8 map_value;	pci_read_config_byte(pdev, ICH5_PMR, &map_value);	map = map_db->map[map_value & map_db->mask];	dev_printk(KERN_INFO, &pdev->dev, "MAP [");	for (i = 0; i < 4; i++) {		switch (map[i]) {		case RV:			invalid_map = 1;			printk(" XX");			break;		case NA:			printk(" --");			break;		case IDE:			WARN_ON((i & 1) || map[i + 1] != IDE);			pinfo[i / 2] = piix_port_info[ich_pata_100];			pinfo[i / 2].private_data = hpriv;			i++;			printk(" IDE IDE");			break;		default:			printk(" P%d", map[i]);			if (i & 1)				pinfo[i / 2].flags |= ATA_FLAG_SLAVE_POSS;			break;		}	}	printk(" ]\n");	if (invalid_map)		dev_printk(KERN_ERR, &pdev->dev,			   "invalid MAP value %u\n", map_value);	hpriv->map = map;}static void piix_iocfg_bit18_quirk(struct pci_dev *pdev){	static const struct dmi_system_id sysids[] = {		{			/* Clevo M570U sets IOCFG bit 18 if the cdrom			 * isn't used to boot the system which			 * disables the channel.			 */			.ident = "M570U",			.matches = {				DMI_MATCH(DMI_SYS_VENDOR, "Clevo Co."),				DMI_MATCH(DMI_PRODUCT_NAME, "M570U"),			},		},		{ }	/* terminate list */	};	u32 iocfg;	if (!dmi_check_system(sysids))		return;	/* The datasheet says that bit 18 is NOOP but certain systems	 * seem to use it to disable a channel.  Clear the bit on the	 * affected systems.	 */	pci_read_config_dword(pdev, PIIX_IOCFG, &iocfg);	if (iocfg & (1 << 18)) {		dev_printk(KERN_INFO, &pdev->dev,			   "applying IOCFG bit18 quirk\n");		iocfg &= ~(1 << 18);		pci_write_config_dword(pdev, PIIX_IOCFG, iocfg);	}}/** *	piix_init_one - Register PIIX ATA PCI device with kernel services *	@pdev: PCI device to register *	@ent: Entry in piix_pci_tbl matching with @pdev * *	Called from kernel PCI layer.  We probe for combined mode (sigh), *	and then hand over control to libata, for it to do the rest. * *	LOCKING: *	Inherited from PCI layer (may sleep). * *	RETURNS: *	Zero on success, or -ERRNO value. */static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){	static int printed_version;	struct device *dev = &pdev->dev;	struct ata_port_info port_info[2];	const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] };	struct piix_host_priv *hpriv;	unsigned long port_flags;	if (!printed_version++)		dev_printk(KERN_DEBUG, &pdev->dev,			   "version " DRV_VERSION "\n");	/* no hotplugging support (FIXME) */	if (!in_module_init)		return -ENODEV;	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);	if (!hpriv)		return -ENOMEM;	port_info[0] = piix_port_info[ent->driver_data];	port_info[1] = piix_port_info[ent->driver_data];	port_info[0].private_data = hpriv;	port_info[1].private_data = hpriv;	port_flags = port_info[0].flags;	if (port_flags & PIIX_FLAG_AHCI) {		u8 tmp;		pci_read_config_byte(pdev, PIIX_SCC, &tmp);		if (tmp == PIIX_AHCI_DEVICE) {			int rc = piix_disable_ahci(pdev);			if (rc)				return rc;		}	}	/* Initialize SATA map */	if (port_flags & ATA_FLAG_SATA) {		piix_init_sata_map(pdev, port_info,				   piix_map_db_table[ent->driver_data]);		piix_init_pcs(pdev, port_info,			      piix_map_db_table[ent->driver_data]);	}	/* apply IOCFG bit18 quirk */	piix_iocfg_bit18_quirk(pdev);	/* On ICH5, some BIOSen disable the interrupt using the	 * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.	 * On ICH6, this bit has the same effect, but only when	 * MSI is disabled (and it is disabled, as we don't use	 * message-signalled interrupts currently).	 */	if (port_flags & PIIX_FLAG_CHECKINTR)		pci_intx(pdev, 1);	if (piix_check_450nx_errata(pdev)) {		/* This writes into the master table but it does not		   really matter for this errata as we will apply it to		   all the PIIX devices on the board */		port_info[0].mwdma_mask = 0;		port_info[0].udma_mask = 0;		port_info[1].mwdma_mask = 0;		port_info[1].udma_mask = 0;	}	return ata_pci_init_one(pdev, ppi);}static int __init piix_init(void){	int rc;	DPRINTK("pci_register_driver\n");	rc = pci_register_driver(&piix_pci_driver);	if (rc)		return rc;	in_module_init = 0;	DPRINTK("done\n");	return 0;}static void __exit piix_exit(void){	pci_unregister_driver(&piix_pci_driver);}module_init(piix_init);module_exit(piix_exit);

⌨️ 快捷键说明

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