[PATCH 8/8] x86, pci: export SETUP_PCI data via sysfs
So we could let kexec-tools to rebuild SETUP_PCI and pass it to second kernel. Now kexec-tools only can build SETUP_EFI and SETUP_E820EXT. Cc: Bjorn Helgaas Cc: linux-...@vger.kernel.org Signed-off-by: Yinghai Lu --- arch/x86/pci/common.c | 188 ++ 1 file changed, 188 insertions(+) diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 7b6fb94..bf0209a 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -682,6 +682,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; @@ -762,6 +764,192 @@ 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[] = { + _pci_vendor_attr.attr, + _pci_devid_attr.attr, + _pci_pcilen_attr.attr, + _pci_segment_attr.attr, + _pci_bus_attr.attr, + _pci_device_attr.attr, + _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 = _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 long start_pfn, end_pfn; + void *rom; + + if (off + count > entry->pcilen) + count = entry->pcilen - off; + + start_pfn = PFN_DOWN(entry->rom + off); + end_pfn = PFN_UP(entry->rom + off + count); + if (pfn_range_is_mapped(start_pfn,
[PATCH 8/8] x86, pci: export SETUP_PCI data via sysfs
So we could let kexec-tools to rebuild SETUP_PCI and pass it to second kernel. Now kexec-tools only can build SETUP_EFI and SETUP_E820EXT. Cc: Bjorn Helgaas bhelg...@google.com Cc: linux-...@vger.kernel.org Signed-off-by: Yinghai Lu ying...@kernel.org --- arch/x86/pci/common.c | 188 ++ 1 file changed, 188 insertions(+) diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 7b6fb94..bf0209a 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -682,6 +682,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; @@ -762,6 +764,192 @@ 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 long start_pfn, end_pfn; + void *rom; + + if (off + count entry-pcilen) + count = entry-pcilen - off; + + start_pfn = PFN_DOWN(entry-rom + off); + end_pfn = PFN_UP(entry-rom + off + count); +