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, ®4042); DPRINTK("reg4042 = 0x%04x\n", reg4042); sitre = (reg4042 & 0x4000) ? 1 : 0; pci_read_config_byte(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); pci_read_config_byte(dev, 0x54, ®54); pci_read_config_byte(dev, 0x55, ®55); 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 + -
显示快捷键?