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

📄 pcifixup.c

📁 PCI总线在DOS操作系统下的驱动程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	 *
	 *	VIA only apply this fix when an SB Live! is present but under
	 *	both Linux and Windows this isnt enough, and we have seen
	 *	corruption without SB Live! but with things like 3 UDMA IDE
	 *	controllers. So we ignore that bit of the VIA recommendation..
	 */

	pci_read_config_byte(dev, 0x76, &busarb);
	/* Set bit 4 and bi 5 of byte 76 to 0x01 
	   "Master priority rotation on every PCI master grant */
	busarb &= ~(1<<5);
	busarb |= (1<<4);
	pci_write_config_byte(dev, 0x76, busarb);

	#ifdef DEBUG_VERSION
		safe_printf("Applying VIA southbridge workaround.\n");
	#endif
}

/*
 *	VIA Apollo VP3 needs ETBF on BT848/878
 */
 
void quirk_viaetbf(struct pci_dev far * dev)
{
	if((pci_pci_problems & PCIPCI_VIAETBF) == 0)
	{
		#ifdef DEBUG_VERSION
			safe_printf("Limiting direct PCI/PCI transfers.\n");
		#endif

		pci_pci_problems |= PCIPCI_VIAETBF;
	}
}

void quirk_vsfx(struct pci_dev far * dev)
{
	if( (pci_pci_problems & PCIPCI_VSFX) == 0)
	{
		#ifdef DEBUG_VERSION
			safe_printf("Limiting direct PCI/PCI transfers.\n");
		#endif
		pci_pci_problems |= PCIPCI_VSFX;
	}
}


/*
 *	Natoma has some interesting boundary conditions with Zoran stuff
 *	at least
 */
 
void quirk_natoma(struct pci_dev far * dev)
{
	if( (pci_pci_problems & PCIPCI_NATOMA) == 0)
	{
		#ifdef DEBUG_VERSION
			safe_printf("Limiting direct PCI/PCI transfers.\n");
		#endif
		pci_pci_problems |= PCIPCI_NATOMA;
	}
}

/*
 *  S3 868 and 968 chips report region size equal to 32M, but they decode 64M.
 *  If it's needed, re-allocate the region.
 */

void quirk_s3_64M(struct pci_dev far * dev)
{
	struct resource far * r = &dev->resource[0];

	if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) 
	{
		r->start = 0;
		r->end = 0x3ffffff;
	}
}

void quirk_io_region(struct pci_dev far * dev, unsigned long region, unsigned long size, 
	long nr)
{
	region &= ~(size - 1);
	if (region) 
	{
		struct resource far * res = dev->resource + nr;

		res->name = dev->name;
		res->start = region;
		res->end = region + size - 1;
		res->flags = IORESOURCE_IO;
		pci_claim_resource(dev, nr);
	}
}	

/*
 * Let's make the southbridge information explicit instead
 * of having to worry about people probing the ACPI areas,
 * for example.. (Yes, it happens, and if you read the wrong
 * ACPI register it will put the machine to sleep with no
 * way of waking it up again. Bummer).
 *
 * ALI M7101: Two IO regions pointed to by words at
 *	0xE0 (64 bytes of ACPI registers)
 *	0xE2 (32 bytes of SMB registers)
 */
void quirk_ali7101_acpi(struct pci_dev far * dev)
{
	u16 region;

	pci_read_config_word(dev, 0xE0, &region);
	quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES);
	pci_read_config_word(dev, 0xE2, &region);
	quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1);
}

/*
 * PIIX4 ACPI: Two IO regions pointed to by longwords at
 *	0x40 (64 bytes of ACPI registers)
 *	0x90 (32 bytes of SMB registers)
 */
void quirk_piix4_acpi(struct pci_dev far * dev)
{
	u32 region;

	pci_read_config_dword(dev, 0x40, &region);
	quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES);
	pci_read_config_dword(dev, 0x90, &region);
	quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1);
}

/*
 * VIA ACPI: One IO region pointed to by longword at
 *	0x48 or 0x20 (256 bytes of ACPI registers)
 */
void quirk_vt82c586_acpi(struct pci_dev far * dev)
{
	u8 rev;
	u32 region;

	pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
	if (rev & 0x10) 
	{
		pci_read_config_dword(dev, 0x48, &region);
		region &= PCI_BASE_ADDRESS_IO_MASK;
		quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES);
	}
}

/*
 * VIA VT82C686 ACPI: Three IO region pointed to by (long)words at
 *	0x48 (256 bytes of ACPI registers)
 *	0x70 (128 bytes of hardware monitoring register)
 *	0x90 (16 bytes of SMB registers)
 */
void quirk_vt82c686_acpi(struct pci_dev far * dev)
{
	u16 hm;
	u32 smb;

	quirk_vt82c586_acpi(dev);

	pci_read_config_word(dev, 0x70, &hm);
	hm &= PCI_BASE_ADDRESS_IO_MASK;
	quirk_io_region(dev, hm, 128, PCI_BRIDGE_RESOURCES + 1);

	pci_read_config_dword(dev, 0x90, &smb);
	smb &= PCI_BASE_ADDRESS_IO_MASK;
	quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2);
}

#ifdef CONFIG_X86_IO_APIC 
long nr_ioapics;

/*
 * VIA 686A/B: If an IO-APIC is active, we need to route all on-chip
 * devices to the external APIC.
 *
 * TODO: When we have device-specific interrupt routers,
 * this code will go away from quirks.
 */
void quirk_via_ioapic(struct pci_dev far * dev)
{
	u8 tmp;
	
	if (nr_ioapics < 1)
		tmp = 0;    /* nothing routed to external APIC */
	else
		tmp = 0x1f; /* all known bits (4-0) routed to external APIC */
		
	#ifdef DEBUG_VERSION
		safe_printf("PCI: %sbling Via external APIC routing\n",tmp == 0 ? "Disa" : "Ena");
	#endif		

	/* Offset 0x58: External APIC IRQ output control */
	pci_write_config_byte (dev, 0x58, tmp);
}

#endif /* CONFIG_X86_IO_APIC */

/*
 * Via 686A/B:  The PCI_INTERRUPT_LINE register for the on-chip
 * devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature:
 * when written, it makes an internal connection to the PIC.
 * For these devices, this register is defined to be 4 bits wide.
 * Normally this is fine.  However for IO-APIC motherboards, or
 * non-x86 architectures (yes Via exists on PPC among other places),
 * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get
 * interrupts delivered properly.
 *
 * TODO: When we have device-specific interrupt routers,
 * quirk_via_irqpic will go away from quirks.
 */

/*
 * FIXME: it is questionable that quirk_via_acpi
 * is needed.  It shows up as an ISA bridge, and does not
 * support the PCI_INTERRUPT_LINE register at all.  Therefore
 * it seems like setting the pci_dev's 'irq' to the
 * value of the ACPI SCI interrupt is only done for convenience.
 *	-jgarzik
 */
void quirk_via_acpi(struct pci_dev far * d)
{
	/*
	 * VIA ACPI device: SCI IRQ line in PCI config byte 0x42
	 */
	u8 irq;
	pci_read_config_byte(d, 0x42, &irq);
	irq &= 0xf;
	if (irq && (irq != 2))
		d->irq = irq;
}

void quirk_via_irqpic(struct pci_dev far * dev)
{
	u8 irq, new_irq = dev->irq & 0xf;

	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);

	if (new_irq != irq) 
	{
		#ifdef DEBUG_VERSION
			safe_printf("PCI: Via IRQ fixup for %s, from %d to %d\n",
		       dev->slot_name, irq, new_irq);
		#endif

		udelay(50);
		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
	}
}


/*
 * PIIX3 USB: We have to disable USB interrupts that are
 * hardwired to PIRQD# and may be shared with an
 * external device.
 *
 * Legacy Support Register (LEGSUP):
 *     bit13:  USB PIRQ Enable (USBPIRQDEN),
 *     bit4:   Trap/SMI On IRQ Enable (USBSMIEN).
 *
 * We mask out all r/wc bits, too.
 */
void quirk_piix3_usb(struct pci_dev far * dev)
{
	u16 legsup;

	pci_read_config_word(dev, 0xc0, &legsup);
	legsup &= 0x50ef;
	pci_write_config_word(dev, 0xc0, legsup);
}

/*
 * VIA VT82C598 has its device ID settable and many BIOSes
 * set it to the ID of VT82C597 for backward compatibility.
 * We need to switch it off to be able to recognize the real
 * type of the chip.
 */
void quirk_vt82c598_id(struct pci_dev far * dev)
{
	pci_write_config_byte(dev, 0xfc, 0);
	pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
}

/*
 * CardBus controllers have a legacy base address that enables them
 * to respond as i82365 pcmcia controllers.  We don't want them to
 * do this even if the Linux CardBus driver is not loaded, because
 * the Linux i82365 driver does not (and should not) handle CardBus.
 */
void quirk_cardbus_legacy(struct pci_dev far * dev)
{
	if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class)
		return;
	pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0);
}


extern struct pci_fixup pci_fixups[];

void pci_do_fixups(struct pci_dev far * dev, int pass, struct pci_fixup far * f)
{
	while (f->pass) 
	{
		if (f->pass == pass &&
 		    (f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
 		    (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) 
		{

			#ifdef DEBUG_VERSION
				safe_printf("PCI: Calling quirk %p for %s\n", f->hook, dev->slot_name);
			#endif

			f->hook(dev);
		}

		f++;
	}
}

void pci_fixup_device(int pass, struct pci_dev far * dev)
{
	pci_do_fixups(dev, pass, pcibios_fixups);
	pci_do_fixups(dev, pass, pci_fixups);
}

⌨️ 快捷键说明

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