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, &reg);	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 + -
显示快捷键?