quirks.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,029 行 · 第 1/3 页
C
1,029 行
/* * VIA northbridges care about PCI_INTERRUPT_LINE */int interrupt_line_quirk;static void __devinit quirk_via_bridge(struct pci_dev *pdev){ if(pdev->devfn == 0) interrupt_line_quirk = 1;}DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_bridge );/* * Serverworks CSB5 IDE does not fully support native mode */static void __init quirk_svwks_csb5ide(struct pci_dev *pdev){ u8 prog; pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog); if (prog & 5) { prog &= ~5; pdev->class &= ~5; pci_write_config_byte(pdev, PCI_CLASS_PROG, prog); /* need to re-assign BARs for compat mode */ quirk_ide_bases(pdev); }}DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide );/* This was originally an Alpha specific thing, but it really fits here. * The i82375 PCI/EISA bridge appears as non-classified. Fix that. */static void __init quirk_eisa_bridge(struct pci_dev *dev){ dev->class = PCI_CLASS_BRIDGE_EISA << 8;}DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge );/* * On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge * is not activated. The myth is that Asus said that they do not want the * users to be irritated by just another PCI Device in the Win98 device * manager. (see the file prog/hotplug/README.p4b in the lm_sensors * package 2.7.0 for details) * * The SMBus PCI Device can be activated by setting a bit in the ICH LPC * bridge. Unfortunately, this device has no subvendor/subdevice ID. So it * becomes necessary to do this tweak in two steps -- I've chosen the Host * bridge as trigger. */static int __initdata asus_hides_smbus = 0;static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev){ if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK)) { if (dev->device == PCI_DEVICE_ID_INTEL_82845_HB) switch(dev->subsystem_device) { case 0x8070: /* P4B */ case 0x8088: /* P4B533 */ case 0x1626: /* L3C notebook */ asus_hides_smbus = 1; } if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) switch(dev->subsystem_device) { case 0x80b1: /* P4GE-V */ case 0x80b2: /* P4PE */ case 0x8093: /* P4B533-V */ asus_hides_smbus = 1; } if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB) switch(dev->subsystem_device) { case 0x8030: /* P4T533 */ asus_hides_smbus = 1; } if (dev->device == PCI_DEVICE_ID_INTEL_7205_0) switch (dev->subsystem_device) { case 0x8070: /* P4G8X Deluxe */ asus_hides_smbus = 1; } if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB) switch (dev->subsystem_device) { case 0x1751: /* M2N notebook */ asus_hides_smbus = 1; } } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) { if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) switch(dev->subsystem_device) { case 0x088C: /* HP Compaq nc8000 */ case 0x0890: /* HP Compaq nc6000 */ asus_hides_smbus = 1; } if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) switch (dev->subsystem_device) { case 0x12bc: /* HP D330L */ asus_hides_smbus = 1; } }}DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asus_hides_smbus_hostbridge );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus_hides_smbus_hostbridge );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge );static void __init asus_hides_smbus_lpc(struct pci_dev *dev){ u16 val; if (likely(!asus_hides_smbus)) return; pci_read_config_word(dev, 0xF2, &val); if (val & 0x8) { pci_write_config_word(dev, 0xF2, val & (~0x8)); pci_read_config_word(dev, 0xF2, &val); if (val & 0x8) printk(KERN_INFO "PCI: i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val); else printk(KERN_INFO "PCI: Enabled i801 SMBus device\n"); }}DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc );/* * SiS 96x south bridge: BIOS typically hides SMBus device... */static void __init quirk_sis_96x_smbus(struct pci_dev *dev){ u8 val = 0; printk(KERN_INFO "Enabling SiS 96x SMBus.\n"); pci_read_config_byte(dev, 0x77, &val); pci_write_config_byte(dev, 0x77, val & ~0x10); pci_read_config_byte(dev, 0x77, &val);}/* * ... This is further complicated by the fact that some SiS96x south * bridges pretend to be 85C503/5513 instead. In that case see if we * spotted a compatible north bridge to make sure. * (pci_find_device doesn't work yet) * * We can also enable the sis96x bit in the discovery register.. */static int __devinitdata sis_96x_compatible = 0;#define SIS_DETECT_REGISTER 0x40static void __init quirk_sis_503(struct pci_dev *dev){ u8 reg; u16 devid; pci_read_config_byte(dev, SIS_DETECT_REGISTER, ®); pci_write_config_byte(dev, SIS_DETECT_REGISTER, reg | (1 << 6)); pci_read_config_word(dev, PCI_DEVICE_ID, &devid); if (((devid & 0xfff0) != 0x0960) && (devid != 0x0018)) { pci_write_config_byte(dev, SIS_DETECT_REGISTER, reg); return; } /* Make people aware that we changed the config.. */ printk(KERN_WARNING "Uncovering SIS%x that hid as a SIS503 (compatible=%d)\n", devid, sis_96x_compatible); /* * Ok, it now shows up as a 96x.. The 96x quirks are after * the 503 quirk in the quirk table, so they'll automatically * run and enable things like the SMBus device */ dev->device = devid;}static void __init quirk_sis_96x_compatible(struct pci_dev *dev){ sis_96x_compatible = 1;}DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_645, quirk_sis_96x_compatible );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, quirk_sis_96x_compatible );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_648, quirk_sis_96x_compatible );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, quirk_sis_96x_compatible );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_compatible );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, quirk_sis_96x_compatible );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );#ifdef CONFIG_X86_IO_APICstatic void __init quirk_alder_ioapic(struct pci_dev *pdev){ int i; if ((pdev->class >> 8) != 0xff00) return; /* the first BAR is the location of the IO APIC...we must * not touch this (and it's already covered by the fixmap), so * forcibly insert it into the resource tree */ if (pci_resource_start(pdev, 0) && pci_resource_len(pdev, 0)) insert_resource(&iomem_resource, &pdev->resource[0]); /* The next five BARs all seem to be rubbish, so just clean * them out */ for (i=1; i < 6; i++) { memset(&pdev->resource[i], 0, sizeof(pdev->resource[i])); }}DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic );#endif#ifdef CONFIG_SCSI_SATAstatic void __init quirk_intel_ide_combined(struct pci_dev *pdev){ u8 prog, comb, tmp; int ich = 0; /* * Narrow down to Intel SATA PCI devices. */ switch (pdev->device) { /* PCI ids taken from drivers/scsi/ata_piix.c */ case 0x24d1: case 0x24df: case 0x25a3: case 0x25b0: ich = 5; break; case 0x2651: case 0x2652: case 0x2653: ich = 6; break; default: /* we do not handle this PCI device */ return; } /* * Read combined mode register. */ pci_read_config_byte(pdev, 0x90, &tmp); /* combined mode reg */ if (ich == 5) { tmp &= 0x6; /* interesting bits 2:1, PATA primary/secondary */ if (tmp == 0x4) /* bits 10x */ comb = (1 << 0); /* SATA port 0, PATA port 1 */ else if (tmp == 0x6) /* bits 11x */ comb = (1 << 2); /* PATA port 0, SATA port 1 */ else return; /* not in combined mode */ } else { WARN_ON(ich != 6); tmp &= 0x3; /* interesting bits 1:0 */ if (tmp & (1 << 0)) comb = (1 << 2); /* PATA port 0, SATA port 1 */ else if (tmp & (1 << 1)) comb = (1 << 0); /* SATA port 0, PATA port 1 */ else return; /* not in combined mode */ } /* * Read programming interface register. * (Tells us if it's legacy or native mode) */ pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog); /* if SATA port is in native mode, we're ok. */ if (prog & comb) return; /* SATA port is in legacy mode. Reserve port so that * IDE driver does not attempt to use it. If request_region * fails, it will be obvious at boot time, so we don't bother * checking return values. */ if (comb == (1 << 0)) request_region(0x1f0, 8, "libata"); /* port 0 */ else request_region(0x170, 8, "libata"); /* port 1 */}DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_combined );#endif /* CONFIG_SCSI_SATA */int pciehp_msi_quirk;static void __devinit quirk_pciehp_msi(struct pci_dev *pdev){ pciehp_msi_quirk = 1;}DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_pciehp_msi );static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end){ while (f < end) { if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) && (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) { pr_debug(KERN_INFO "PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev)); f->hook(dev); } f++; }}extern struct pci_fixup __start_pci_fixups_header[];extern struct pci_fixup __end_pci_fixups_header[];extern struct pci_fixup __start_pci_fixups_final[];extern struct pci_fixup __end_pci_fixups_final[];void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev){ struct pci_fixup *start, *end; switch(pass) { case pci_fixup_header: start = __start_pci_fixups_header; end = __end_pci_fixups_header; break; case pci_fixup_final: start = __start_pci_fixups_final; end = __end_pci_fixups_final; break; default: /* stupid compiler warning, you would think with an enum... */ return; } pci_do_fixups(dev, start, end);}EXPORT_SYMBOL(pciehp_msi_quirk);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?