===== arch/i386/pci/fixup.c 1.19 vs edited ===== --- 1.19/arch/i386/pci/fixup.c Thu Jun 3 10:58:17 2004 +++ edited/arch/i386/pci/fixup.c Thu Aug 5 00:20:08 2004 @@ -237,6 +237,29 @@ } } +static void __devinit pci_fixup_video(struct pci_dev *pdev) +{ + struct pci_dev *bridge; + struct pci_bus *bus; + u16 l; + + if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) + return; + + /* Is VGA routed to us? */ + bus = pdev->bus; + while (bus) { + bridge = bus->self; + if (bridge) { + pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &l); + if (!(l & PCI_BRIDGE_CTL_VGA)) + return; + } + bus = bus->parent; + } + pdev->resource[PCI_ROM_RESOURCE].flags |= PCI_ROM_SHADOW; +} + struct pci_fixup pcibios_fixups[] = { { .pass = PCI_FIXUP_HEADER, @@ -345,6 +368,12 @@ .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NFORCE2, .hook = pci_fixup_nforce2 + }, + { + .pass = PCI_FIXUP_FINAL, + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .hook = pci_fixup_video }, { .pass = 0 } }; ===== drivers/pci/pci-sysfs.c 1.10 vs edited ===== --- 1.10/drivers/pci/pci-sysfs.c Fri Jun 4 09:23:04 2004 +++ edited/drivers/pci/pci-sysfs.c Thu Aug 5 00:45:04 2004 @@ -164,6 +164,95 @@ return count; } +/** + * pci_enable_rom - enable ROM decoding for a PCI device + * @dev: PCI device to enable + * + * Enable ROM decoding on @dev. This involves simply turning on the last + * bit of the PCI ROM BAR. Note that some cards may share address decoders + * between the ROM and other resources, so enabling it may disable access + * to MMIO registers or other card memory. + */ +static void +pci_enable_rom(struct pci_dev *dev) +{ + u32 rom_addr; + + pci_read_config_dword(dev, dev->rom_base_reg, &rom_addr); + rom_addr |= PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, dev->rom_base_reg, rom_addr); +} + +/** + * pci_disable_rom - disable ROM decoding for a PCI device + * @dev: PCI device to disable + * + * Disable ROM decoding on a PCI device by turning off the last bit in the + * ROM BAR. + */ +static void +pci_disable_rom(struct pci_dev *dev) +{ + u32 rom_addr; + + pci_read_config_dword(dev, dev->rom_base_reg, &rom_addr); + rom_addr &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, dev->rom_base_reg, rom_addr); +} + +/** + * pci_read_rom - read a PCI ROM + * @kobj: kernel object handle + * @buf: where to put the data we read from the ROM + * @off: file offset + * @count: number of bytes to read + * + * Put @count bytes starting at @off into @buf from the ROM in the PCI + * device corresponding to @kobj. + */ +static ssize_t +pci_read_rom(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); + loff_t start; + size_t size; + unsigned char *rom; + struct resource *res = &dev->resource[PCI_ROM_RESOURCE]; + + if (res->flags & PCI_ROM_SHADOW) { /* PCI_ROM_SHADOW only set on x86 */ + start = (unsigned char *)0xC0000; /* primary video rom always starts here */ + size = 0x20000; /* cover C000:0 through E000:0 */ + } else { + /* assign the ROM an address if it doesn't have one */ + if (res->parent == NULL) + pci_assign_resource(dev, PCI_ROM_RESOURCE); + + start = pci_resource_start(dev, PCI_ROM_RESOURCE); + size = pci_resource_len(dev, PCI_ROM_RESOURCE); + + /* Enable ROM space decodes */ + pci_enable_rom(dev); + } + if (off >= size) + return 0; + + if (off + count > size) + count = size - off; + + rom = ioremap(start, size); + if (rom) { + memcpy_fromio(buf, rom + off, count); + iounmap(rom); + } else + count = 0; + + /* Disable again before continuing, leave enabled if pci=rom */ + if (!(res->flags & (PCI_ROM_ADDRESS_ENABLE|PCI_ROM_SHADOW))) + pci_disable_rom(dev); + + return count; +} + static struct bin_attribute pci_config_attr = { .attr = { .name = "config", @@ -186,13 +275,49 @@ .write = pci_write_config, }; -void pci_create_sysfs_dev_files (struct pci_dev *pdev) +static struct bin_attribute rom_attr = { + .attr = { + .name = "rom", + .mode = S_IRUSR, + .owner = THIS_MODULE, + }, + /* .size is set individually for each device, sysfs copies it into dentry */ + .read = pci_read_rom, +}; + +void pci_create_sysfs_dev_files(struct pci_dev *pdev) { if (pdev->cfg_size < 4096) sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); else sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); + /* If the device has a ROM, try to expose it in sysfs. */ + if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { + struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; + if (res->flags & PCI_ROM_SHADOW) { + rom_attr.size = 0x20000; /* cover C000:0 through E000:0 */ + } else + rom_attr.size = pci_resource_len(pdev, PCI_ROM_RESOURCE); + sysfs_create_bin_file(&pdev->dev.kobj, &rom_attr); + } /* add platform-specific attributes */ pcibios_add_platform_entries(pdev); +} + +/** + * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files + * @pdev: device whose entries we should free + * + * Cleanup when @pdev is removed from sysfs. + */ +void pci_remove_sysfs_dev_files(struct pci_dev *pdev) +{ + if (pdev->cfg_size < 4096) + sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); + else + sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); + + if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) + sysfs_remove_bin_file(&pdev->dev.kobj, &rom_attr); } ===== drivers/pci/pci.h 1.12 vs edited ===== --- 1.12/drivers/pci/pci.h Fri Jun 4 09:23:04 2004 +++ edited/drivers/pci/pci.h Tue Aug 3 17:05:19 2004 @@ -3,6 +3,7 @@ extern int pci_hotplug (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); extern void pci_create_sysfs_dev_files(struct pci_dev *pdev); +extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, unsigned long size, unsigned long align, unsigned long min, unsigned int type_mask, ===== drivers/pci/probe.c 1.65 vs edited ===== --- 1.65/drivers/pci/probe.c Fri May 21 14:45:27 2004 +++ edited/drivers/pci/probe.c Thu Aug 5 00:10:06 2004 @@ -157,6 +157,7 @@ #endif } } + if (rom) { dev->rom_base_reg = rom; res = &dev->resource[PCI_ROM_RESOURCE]; ===== drivers/pci/remove.c 1.3 vs edited ===== --- 1.3/drivers/pci/remove.c Tue Feb 3 12:17:30 2004 +++ edited/drivers/pci/remove.c Thu Aug 5 00:11:05 2004 @@ -26,6 +26,7 @@ static void pci_destroy_dev(struct pci_dev *dev) { pci_proc_detach_device(dev); + pci_remove_sysfs_dev_files(dev); device_unregister(&dev->dev); /* Remove the device from the device lists, and prevent any further ===== include/linux/pci.h 1.132 vs edited ===== --- 1.132/include/linux/pci.h Mon Aug 2 04:00:43 2004 +++ edited/include/linux/pci.h Thu Aug 5 00:13:54 2004 @@ -102,6 +102,8 @@ #define PCI_SUBSYSTEM_ID 0x2e #define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ #define PCI_ROM_ADDRESS_ENABLE 0x01 +#define PCI_ROM_SHADOW 0x02 /* resource flag, ROM is copy at C000:0 */ +#define PCI_ROM_COPY 0x04 /* resource flag, ROM is alloc'd copy */ #define PCI_ROM_ADDRESS_MASK (~0x7ffUL) #define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */