ata_piix.c

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

C
669
字号
	/* TODO: this is vaguely wrong for ICH6 combined mode,	 * where only two of the four SATA ports are mapped	 * onto a single ATA channel.  It is also vaguely inaccurate	 * for ICH5, which has only two ports.  However, this is ok,	 * as further device presence detection code will handle	 * any false positives produced here.	 */	for (i = 0; i < 4; i++) {		mask = (PIIX_PORT_PRESENT << i) | (PIIX_PORT_ENABLED << i);		if ((orig_mask & mask) == mask)			if (combined || (i == ap->port_no))				return 1;	}	return 0;}/** *	piix_sata_phy_reset - Probe specified port on SATA host controller *	@ap: Port to probe * *	Probe SATA phy. * *	LOCKING: *	None (inherited from caller). */static void piix_sata_phy_reset(struct ata_port *ap){	if (!piix_sata_probe(ap)) {		ata_port_disable(ap);		printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id);		return;	}	ap->cbl = ATA_CBL_SATA;	ata_port_probe(ap);	ata_bus_reset(ap);}/** *	piix_set_piomode - Initialize host controller PATA PIO timings *	@ap: Port whose timings we are configuring *	@adev: um *	@pio: PIO mode, 0 - 4 * *	Set PIO mode for device, in host controller PCI config space. * *	LOCKING: *	None (inherited from caller). */static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev){	unsigned int pio	= adev->pio_mode - XFER_PIO_0;	struct pci_dev *dev	= ap->host_set->pdev;	unsigned int is_slave	= (adev->devno != 0);	unsigned int master_port= ap->port_no ? 0x42 : 0x40;	unsigned int slave_port	= 0x44;	u16 master_data;	u8 slave_data;	static const	 /* ISP  RTC */	u8 timings[][2]	= { { 0, 0 },			    { 0, 0 },			    { 1, 0 },			    { 2, 1 },			    { 2, 3 }, };	pci_read_config_word(dev, master_port, &master_data);	if (is_slave) {		master_data |= 0x4000;		/* enable PPE, IE and TIME */		master_data |= 0x0070;		pci_read_config_byte(dev, slave_port, &slave_data);		slave_data &= (ap->port_no ? 0x0f : 0xf0);		slave_data |=			(timings[pio][0] << 2) |			(timings[pio][1] << (ap->port_no ? 4 : 0));	} else {		master_data &= 0xccf8;		/* enable PPE, IE and TIME */		master_data |= 0x0007;		master_data |=			(timings[pio][0] << 12) |			(timings[pio][1] << 8);	}	pci_write_config_word(dev, master_port, master_data);	if (is_slave)		pci_write_config_byte(dev, slave_port, slave_data);}/** *	piix_set_dmamode - Initialize host controller PATA PIO timings *	@ap: Port whose timings we are configuring *	@adev: um *	@udma: udma mode, 0 - 6 * *	Set 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){	unsigned int udma	= adev->dma_mode; /* FIXME: MWDMA too */	struct pci_dev *dev	= ap->host_set->pdev;	u8 maslave		= ap->port_no ? 0x42 : 0x40;	u8 speed		= udma;	unsigned int drive_dn	= (ap->port_no ? 2 : 0) + adev->devno;	int a_speed		= 3 << (drive_dn * 4);	int u_flag		= 1 << drive_dn;	int v_flag		= 0x01 << drive_dn;	int w_flag		= 0x10 << drive_dn;	int u_speed		= 0;	int			sitre;	u16			reg4042, reg4a;	u8			reg48, reg54, reg55;	pci_read_config_word(dev, maslave, &reg4042);	DPRINTK("reg4042 = 0x%04x\n", reg4042);	sitre = (reg4042 & 0x4000) ? 1 : 0;	pci_read_config_byte(dev, 0x48, &reg48);	pci_read_config_word(dev, 0x4a, &reg4a);	pci_read_config_byte(dev, 0x54, &reg54);	pci_read_config_byte(dev, 0x55, &reg55);	switch(speed) {		case XFER_UDMA_4:		case XFER_UDMA_2:	u_speed = 2 << (drive_dn * 4); break;		case XFER_UDMA_6:		case XFER_UDMA_5:		case XFER_UDMA_3:		case XFER_UDMA_1:	u_speed = 1 << (drive_dn * 4); break;		case XFER_UDMA_0:	u_speed = 0 << (drive_dn * 4); break;		case XFER_MW_DMA_2:		case XFER_MW_DMA_1:	break;		default:			BUG();			return;	}	if (speed >= XFER_UDMA_0) {		if (!(reg48 & u_flag))			pci_write_config_byte(dev, 0x48, reg48 | u_flag);		if (speed == XFER_UDMA_5) {			pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);		} else {			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);		}		if ((reg4a & a_speed) != u_speed)			pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);		if (speed > XFER_UDMA_2) {			if (!(reg54 & v_flag))				pci_write_config_byte(dev, 0x54, reg54 | v_flag);		} else			pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);	} else {		if (reg48 & u_flag)			pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);		if (reg4a & a_speed)			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);		if (reg54 & v_flag)			pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);		if (reg55 & w_flag)			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);	}}/* move to PCI layer, integrate w/ MSI stuff */static void pci_enable_intx(struct pci_dev *pdev){	u16 pci_command;	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);	if (pci_command & PCI_COMMAND_INTX_DISABLE) {		pci_command &= ~PCI_COMMAND_INTX_DISABLE;		pci_write_config_word(pdev, PCI_COMMAND, pci_command);	}}#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 *mmio;	unsigned long addr;	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.	 */	addr = pci_resource_start(pdev, AHCI_PCI_BAR);	if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR))		return 0;		mmio = ioremap(addr, 64);	if (!mmio)		return -ENOMEM;		tmp = readl(mmio + AHCI_GLOBAL_CTL);	if (tmp & AHCI_ENABLE) {		tmp &= ~AHCI_ENABLE;		writel(tmp, mmio + AHCI_GLOBAL_CTL);		tmp = readl(mmio + AHCI_GLOBAL_CTL);		if (tmp & AHCI_ENABLE)			rc = -EIO;	}		iounmap(mmio);	return rc;}/** *	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 ata_port_info *port_info[2];	unsigned int combined = 0, n_ports = 1;	unsigned int pata_chan = 0, sata_chan = 0;	if (!printed_version++)		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");	/* no hotplugging support (FIXME) */	if (!in_module_init)		return -ENODEV;	port_info[0] = &piix_port_info[ent->driver_data];	port_info[1] = NULL;	if (port_info[0]->host_flags & PIIX_FLAG_AHCI) {		int rc = piix_disable_ahci(pdev);		if (rc)			return rc;	}	if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) {		u8 tmp;		pci_read_config_byte(pdev, ICH5_PMR, &tmp);		if (tmp & PIIX_COMB) {			combined = 1;			if (tmp & PIIX_COMB_PATA_P0)				sata_chan = 1;			else				pata_chan = 1;		}	}	/* 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_info[0]->host_flags & PIIX_FLAG_CHECKINTR)		pci_enable_intx(pdev);	if (combined) {		port_info[sata_chan] = &piix_port_info[ent->driver_data];		port_info[sata_chan]->host_flags |= ATA_FLAG_SLAVE_POSS;		port_info[pata_chan] = &piix_port_info[ich5_pata];		n_ports++;		printk(KERN_WARNING DRV_NAME ": combined mode detected\n");	}	return ata_pci_init_one(pdev, port_info, n_ports);}/** *	piix_init - * *	LOCKING: * *	RETURNS: * */static int __init piix_init(void){	int rc;	DPRINTK("pci_module_init\n");	rc = pci_module_init(&piix_pci_driver);	if (rc)		return rc;	in_module_init = 0;	DPRINTK("done\n");	return 0;}/** *	piix_exit - * *	LOCKING: * */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 + =
减小字号Ctrl + -
显示快捷键?