[PATCH 8/8] x86, pci: export SETUP_PCI data via sysfs

2015-02-28 Thread Yinghai Lu
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

2015-02-28 Thread Yinghai Lu
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);
+