diff -ur linux-2.6.11/drivers/pci/Kconfig linux-2.6.11-new/drivers/pci/Kconfig --- linux-2.6.11/drivers/pci/Kconfig 2005-03-01 23:37:51.000000000 -0800 +++ linux-2.6.11-new/drivers/pci/Kconfig 2005-04-01 07:19:32.000000000 -0800 @@ -47,3 +47,38 @@ When in doubt, say Y. +choice + prompt "Enable PCI Master Abort Mode" + depends on PCI + default PCI_MASTER_ABORT_DEFAULT + help + On PCI systems, when a bus is unavailable to a bus master, a + master abort occurs. Older bridges satisfy the master request + with all 0xFF's. This can lead to silent data corruption. Newer + bridges can send a target abort to the bus master. Some PCI + hardware cannot handle the target abort. Some x86 BIOSes configure + the buses in a suboptimal way. This option allows you to override + the BIOS setting. If unsure chose default. This choice can be + overridden at boot time with the pci_enable_master_abort={default, + enable, disable} + +config PCI_MASTER_ABORT_DEFAULT + bool "Default" + help + Choose this option if you are unsure, or believe your + firmware does the right thing. + +config PCI_MASTER_ABORT_ENABLE + bool "Enable" + help + Choose this option if it is more important for you to prevent + silent data loss than to have more hardware configurations work. + + +config PCI_MASTER_ABORT_DISABLE + bool "Disable" + help + Choose this option if it is more important for you to have more + hardware configurations work than to prevent silent data loss. + +endchoice diff -ur linux-2.6.11/drivers/pci/probe.c linux-2.6.11-new/drivers/pci/probe.c --- linux-2.6.11/drivers/pci/probe.c 2005-03-01 23:38:13.000000000 -0800 +++ linux-2.6.11-new/drivers/pci/probe.c 2005-04-05 12:07:53.000000000 -0700 @@ -28,6 +28,15 @@ LIST_HEAD(pci_devices); +/* used to force master abort mode on or off at runtime. + PCI_MASTER_ABORT_DEFAULT means leave alone, the BIOS got it correct. + PCI_MASTER_ABORT_ENABLE means turn it on everywhere. + PCI_MASTER_ABORT_DISABLE means turn it off everywhere. +*/ + +static int pci_enable_master_abort=PCI_MASTER_ABORT_VAL; + + #ifdef HAVE_PCI_LEGACY /** * pci_create_legacy_files - create legacy I/O port and memory files @@ -429,6 +438,20 @@ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT); + /* Some BIOSes disable master abort mode, even though it's + usually a good thing (prevents silent data corruption). + Unfortunately some hardware (buggy e-1000 chips for + example) require Master Abort Mode to be off, or they will + not function properly. So we enable master abort mode + unless the user told us not to. The default value + for pci_enable_master_abort is set in the config file, + but can be overridden at setup time. */ + if (pci_enable_master_abort == PCI_MASTER_ABORT_ENABLE) { + bctl |= PCI_BRIDGE_CTL_MASTER_ABORT; + } else if (pci_enable_master_abort == PCI_MASTER_ABORT_DISABLE) { + bctl &= ~PCI_BRIDGE_CTL_MASTER_ABORT; + } + pci_enable_crs(dev); if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus) { @@ -932,6 +955,22 @@ kfree(b); return NULL; } + +static int __devinit pci_enable_master_abort_setup(char *str) +{ + if (strcmp(str, "enable") == 0) { + pci_enable_master_abort = PCI_MASTER_ABORT_ENABLE; + } else if (strcmp(str, "disable") == 0) { + pci_enable_master_abort = PCI_MASTER_ABORT_DISABLE; + } else if (strcmp(str, "default") == 0) { + pci_enable_master_abort = PCI_MASTER_ABORT_DEFAULT; + } else { + printk (KERN_ERR "PCI: Unknown Master Abort Mode (%s).", str); + } +} + +__setup("pci_enable_master_abort=", pci_enable_master_abort_setup); + EXPORT_SYMBOL(pci_scan_bus_parented); #ifdef CONFIG_HOTPLUG diff -ur linux-2.6.11/include/linux/pci.h linux-2.6.11-new/include/linux/pci.h --- linux-2.6.11/include/linux/pci.h 2005-03-01 23:38:08.000000000 -0800 +++ linux-2.6.11-new/include/linux/pci.h 2005-04-01 07:19:18.000000000 -0800 @@ -1064,5 +1064,17 @@ #define PCIPCI_VSFX 16 #define PCIPCI_ALIMAGIK 32 +#define PCI_MASTER_ABORT_DEFAULT 0 +#define PCI_MASTER_ABORT_ENABLE 1 +#define PCI_MASTER_ABORT_DISABLE 2 + +#if defined(CONFIG_PCI_MASTER_ABORT_ENABLE) +# define PCI_MASTER_ABORT_VAL PCI_MASTER_ABORT_ENABLE +#elif defined(CONFIG_PCI_MASTER_ABORT_DISABLE) +# define PCI_MASTER_ABORT_VAL PCI_MASTER_ABORT_DISABLE +#else +# define PCI_MASTER_ABORT_VAL PCI_MASTER_ABORT_DEFAULT +#endif + #endif /* __KERNEL__ */ #endif /* LINUX_PCI_H */