[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1425456048-16236-16-git-send-email-yinghai@kernel.org>
Date: Wed, 4 Mar 2015 00:00:48 -0800
From: Yinghai Lu <yinghai@...nel.org>
To: Matt Fleming <matt.fleming@...el.com>,
"H. Peter Anvin" <hpa@...or.com>,
Bjorn Helgaas <bhelgaas@...gle.com>
Cc: Thomas Gleixner <tglx@...utronix.de>,
Ingo Molnar <mingo@...hat.com>, Jiri Kosina <jkosina@...e.cz>,
Borislav Petkov <bp@...e.de>, Baoquan He <bhe@...hat.com>,
linux-kernel@...r.kernel.org, linux-efi@...r.kernel.org,
linux-pci@...r.kernel.org, Yinghai Lu <yinghai@...nel.org>
Subject: [PATCH v2 15/15] 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 already build SETUP_EFI and SETUP_E820EXT.
Cc: Bjorn Helgaas <bhelgaas@...gle.com>
Cc: linux-pci@...r.kernel.org
Signed-off-by: Yinghai Lu <yinghai@...nel.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 a5de331..fb4765b 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;
@@ -803,6 +805,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 majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists