So we could let kexec-tools to rebuild SETUP_PCI and pass it to second kernel if needed. Now kexec-tools already build SETUP_EFI and SETUP_E820EXT. Cc: Bjorn Helgaas <bhelgaas@xxxxxxxxxx> Cc: linux-pci@xxxxxxxxxxxxxxx Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx> --- arch/x86/pci/common.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 15e1b3f..502e707 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -685,6 +685,8 @@ void __init add_pci(u64 pa_data) struct firmware_setup_pci_entry { struct list_head list; + struct kobject kobj; + struct bin_attribute *rom_attr; uint16_t vendor; uint16_t devid; uint64_t pcilen; @@ -806,6 +808,179 @@ int pcibios_add_device(struct pci_dev *dev) return 0; } +#ifdef CONFIG_SYSFS +static inline struct firmware_setup_pci_entry * +to_setup_pci_entry(struct kobject *kobj) +{ + return container_of(kobj, struct firmware_setup_pci_entry, kobj); +} + +static ssize_t vendor_show(struct firmware_setup_pci_entry *entry, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%04llx\n", + (unsigned long long)entry->vendor); +} + +static ssize_t devid_show(struct firmware_setup_pci_entry *entry, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%04llx\n", + (unsigned long long)entry->devid); +} + +static ssize_t pcilen_show(struct firmware_setup_pci_entry *entry, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%llx\n", + (unsigned long long)entry->pcilen); +} + +static ssize_t segment_show(struct firmware_setup_pci_entry *entry, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%04llx\n", + (unsigned long long)entry->segment); +} + +static ssize_t bus_show(struct firmware_setup_pci_entry *entry, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%02llx\n", + (unsigned long long)entry->bus); +} + +static ssize_t device_show(struct firmware_setup_pci_entry *entry, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%02llx\n", + (unsigned long long)entry->device); +} + +static ssize_t function_show(struct firmware_setup_pci_entry *entry, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%1llx\n", + (unsigned long long)entry->function); +} + +struct setup_pci_attribute { + struct attribute attr; + ssize_t (*show)(struct firmware_setup_pci_entry *entry, char *buf); +}; + +static inline struct setup_pci_attribute *to_setup_pci_attr( + struct attribute *attr) +{ + return container_of(attr, struct setup_pci_attribute, attr); +} + +static ssize_t setup_pci_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct firmware_setup_pci_entry *entry = to_setup_pci_entry(kobj); + struct setup_pci_attribute *setup_pci_attr = to_setup_pci_attr(attr); + + return setup_pci_attr->show(entry, buf); +} + +static struct setup_pci_attribute setup_pci_vendor_attr = __ATTR_RO(vendor); +static struct setup_pci_attribute setup_pci_devid_attr = __ATTR_RO(devid); +static struct setup_pci_attribute setup_pci_pcilen_attr = __ATTR_RO(pcilen); +static struct setup_pci_attribute setup_pci_segment_attr = __ATTR_RO(segment); +static struct setup_pci_attribute setup_pci_bus_attr = __ATTR_RO(bus); +static struct setup_pci_attribute setup_pci_device_attr = __ATTR_RO(device); +static struct setup_pci_attribute setup_pci_function_attr = __ATTR_RO(function); + +/* + * These are default attributes that are added for every memmap entry. + */ +static struct attribute *def_attrs[] = { + &setup_pci_vendor_attr.attr, + &setup_pci_devid_attr.attr, + &setup_pci_pcilen_attr.attr, + &setup_pci_segment_attr.attr, + &setup_pci_bus_attr.attr, + &setup_pci_device_attr.attr, + &setup_pci_function_attr.attr, + NULL +}; + +static const struct sysfs_ops setup_pci_attr_ops = { + .show = setup_pci_attr_show, +}; + +static struct kobj_type __refdata setup_pci_ktype = { + .sysfs_ops = &setup_pci_attr_ops, + .default_attrs = def_attrs, +}; + +static ssize_t setup_pci_rom_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct firmware_setup_pci_entry *entry = to_setup_pci_entry(kobj); + + if (off >= entry->pcilen) + count = 0; + else { + unsigned char *rom = phys_to_virt(entry->romdata); + + if (off + count > entry->pcilen) + count = entry->pcilen - off; + + memcpy(buf, rom + off, count); + } + + return count; +} + +static int __init add_sysfs_fw_setup_pci_entry( + struct firmware_setup_pci_entry *entry) +{ + int retval = 0; + static int setup_pci_entries_nr; + static struct kset *setup_pci_kset; + struct bin_attribute *attr; + + kobject_init(&entry->kobj, &setup_pci_ktype); + + if (!setup_pci_kset) { + setup_pci_kset = kset_create_and_add("setup_pci", NULL, + firmware_kobj); + if (!setup_pci_kset) + return -ENOMEM; + } + + entry->kobj.kset = setup_pci_kset; + retval = kobject_add(&entry->kobj, NULL, "%d", setup_pci_entries_nr++); + if (retval) { + kobject_put(&entry->kobj); + return retval; + } + + attr = kzalloc(sizeof(*attr), GFP_ATOMIC); + if (!attr) + return -ENOMEM; + + sysfs_bin_attr_init(attr); + attr->size = entry->pcilen; + attr->attr.name = "rom"; + attr->attr.mode = S_IRUSR; + attr->read = setup_pci_rom_read; + retval = sysfs_create_bin_file(&entry->kobj, attr); + if (retval) + kfree(attr); + entry->rom_attr = attr; + + return retval; +} + +static int __init firmware_setup_pci_init(void) +{ + struct firmware_setup_pci_entry *entry; + + list_for_each_entry(entry, &setup_pci_entries, list) + add_sysfs_fw_setup_pci_entry(entry); + + return 0; +} +late_initcall(firmware_setup_pci_init); +#endif + int pcibios_enable_device(struct pci_dev *dev, int mask) { int err; -- 1.8.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html