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 <bhelg...@google.com>
Cc: linux-...@vger.kernel.org
Signed-off-by: Yinghai Lu <ying...@kernel.org>
---
 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 4d6b128..9112d92 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -656,6 +656,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;
@@ -777,6 +779,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-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to