linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Bjorn Helgaas <bhelgaas@google.com>
To: Jordan Hargrave <jharg93@gmail.com>
Cc: jdelvare@suse.de, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org, Jordan_Hargrave@dell.com
Subject: Re: [PATCH] Add support for reading SMBIOS Slot number for PCI devices
Date: Tue, 21 Jul 2015 13:09:19 -0500	[thread overview]
Message-ID: <20150721180919.GE21967@google.com> (raw)
In-Reply-To: <1436565766-21820-1-git-send-email-jordan_hargrave@dell.com>

On Fri, Jul 10, 2015 at 05:02:46PM -0500, Jordan Hargrave wrote:
> From: Jordan Hargrave <Jordan_Hargrave@dell.com>
> 
> There currently isn't an easy way to determine which PCI devices belong to
> system slots.  This patch adds support to read SMBIOS Type 9 (System Slots).
> 
> Signed-off-by: Jordan Hargrave <Jordan_Hargrave@dell.com>
> ---
>  drivers/firmware/dmi_scan.c | 39 ++++++++++++++++++++
>  drivers/pci/pci-label.c     | 89 +++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/dmi.h         |  1 +
>  3 files changed, 129 insertions(+)
> 
> diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
> index ac1ce4a..8f95897 100644
> --- a/drivers/firmware/dmi_scan.c
> +++ b/drivers/firmware/dmi_scan.c
> @@ -356,6 +356,41 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm)
>  	dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1)));
>  }
>  
> +static void __init dmi_save_dev_slot(int instance, int segment, int bus, int devfn, const char *name)
> +{
> +	struct dmi_dev_onboard *slot;
> +	
> +	slot = dmi_alloc(sizeof(*slot) + strlen(name) + 1);
> +	if (!slot) {
> +		printk(KERN_ERR "dmi_save_system_slot: out of memory.\n");

You've got lots of data that might be useful in the printk: segment, bus,
devfn, name.

> +		return;
> +	}
> +	slot->instance = instance;
> +	slot->segment = segment;
> +	slot->bus = bus;
> +	slot->devfn = devfn;
> +
> +	strcpy((char *)&slot[1], name);
> +	slot->dev.type = DMI_DEV_TYPE_SYSTEM_SLOT;
> +	slot->dev.name = (char *)&slot[1];
> +	slot->dev.device_data = slot;
> +
> +	list_add(&slot->dev.list, &dmi_devices);
> +}
> +
> +
> +static void __init dmi_save_system_slot(const struct dmi_header *dm)
> +{
> +	const char *name;
> +	const u8 *d = (u8*)dm;
> +	
> +	if (dm->type == DMI_ENTRY_SYSTEM_SLOT && dm->length >= 0x11) {
> +		name = dmi_string_nosave(dm, *(d + 0x04));
> +		dmi_save_dev_slot(*(u16 *)(d + 0x09), *(u16 *)(d + 0xD), 
> +				  *(d + 0xF), *(d + 0x10), name);
> +	}
> +}
> +
>  static void __init count_mem_devices(const struct dmi_header *dm, void *v)
>  {
>  	if (dm->type != DMI_ENTRY_MEM_DEVICE)
> @@ -437,6 +472,10 @@ static void __init dmi_decode(const struct dmi_header *dm, void *dummy)
>  		break;
>  	case 41:	/* Onboard Devices Extended Information */
>  		dmi_save_extended_devices(dm);
> +		break;
> +	case 9:         /* System Slots */
> +		dmi_save_system_slot(dm);
> +		break;
>  	}
>  }
>  
> diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c
> index 024b5c1..38dfb45 100644
> --- a/drivers/pci/pci-label.c
> +++ b/drivers/pci/pci-label.c
> @@ -125,14 +125,103 @@ static struct attribute_group smbios_attr_group = {
>  	.is_visible = smbios_instance_string_exist,
>  };
>  
> +static int smbios_getslot(struct pci_dev *pdev)
> +{
> +	struct pci_dev *sdev;
> +	struct dmi_dev_onboard *dslot;
> +	const struct dmi_device *dmi;
> +	u8 sub, sec, bus;
> +
> +	dmi = NULL;
> +	if (pdev->is_virtfn) {
> +		/* Get Physical device for SR-IOV */
> +		pdev = pdev->physfn;
> +	}

Use pci_physfn().

> +	bus = pdev->bus->number;
> +	while ((dmi = dmi_find_device(DMI_DEV_TYPE_SYSTEM_SLOT, NULL, dmi)) != NULL) {

This loop doesn't match my naive expectation of how we should find a slot.
I expected something like:

  - Look for DMI info that's an exact match for my D:B:D.F
  - Walk bridges upstream towards the root, looking for a subtree that
    includes pdev

> +		sec = sub = -1;
> +
> +		dslot = dmi->device_data;
> +		sdev = pci_get_domain_bus_and_slot(dslot->segment, dslot->bus, dslot->devfn);

This acquires a reference on the dev returned, so you need to dispose of
that somewhere.

> +		if (sdev == NULL)
> +			continue;
> +
> +		if (sdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
> +			pci_read_config_byte(sdev, PCI_SECONDARY_BUS, &sec);
> +			pci_read_config_byte(sdev, PCI_SUBORDINATE_BUS, &sub);

We should not have to read this out of config space; busn_res in struct
pci_bus has this information already.

> +			if (bus >= sec && bus <= sub) {
> +				/* device is child of bridge */
> +				return dslot->instance;

If you have a slot name for 0000:00:00.0 and a device at 0001:00:00.0, this
will erroneously associate the domain 0 name with the domain 1 device.

> +			}
> +		}
> +		if (pci_domain_nr(sdev->bus) == pci_domain_nr(pdev->bus) &&
> +		    sdev->bus->number == pdev->bus->number &&
> +		    PCI_SLOT(sdev->devfn) == PCI_SLOT(pdev->devfn)) {
> +			/* Match domain:bus:dev.  If PCIE root, only match function */

The PCIe part of this comment doesn't seem to match the code.

> +			if (PCI_FUNC(sdev->devfn) == PCI_FUNC(pdev->devfn) ||
> +			    pci_pcie_type(sdev) != PCI_EXP_TYPE_ROOT_PORT) {
> +				return dslot->instance;
> +			}
> +		}
> +	}
> +	return -ENODEV;
> +}
> + 
> +static ssize_t smbiosslot_show(struct device *dev,
> +			       struct device_attribute *attr, char *buf)
> +{
> + 	struct pci_dev *pdev;
> +	int slot;
> + 
> + 	pdev = to_pci_dev(dev);
> +	slot = smbios_getslot(pdev);
> +	if (slot > 0) {
> +		return scnprintf(buf, PAGE_SIZE, "%d\n", slot);
> +	}
> +	return 0;
> +}
> +
> +static umode_t smbios_slot_exist(struct kobject *kobj, struct attribute *attr,
> +				 int n)
> +{
> +	struct device *dev;
> +	struct pci_dev *pdev;
> +
> +	dev = container_of(kobj, struct device, kobj);
> +	pdev = to_pci_dev(dev);
> +
> +	return (smbios_getslot(pdev) > 0) ? S_IRUGO : 0;
> +}
> +
> +static struct device_attribute smbios_attr_slot = {
> +	.attr = {.name = "slot", .mode = 0444},
> +	.show = smbiosslot_show,
> +};
> +
> +static struct attribute *smbios_slot_attributes[] = {
> +	&smbios_attr_slot.attr,
> +	NULL,
> +};
> +
> +static struct attribute_group smbios_slot_attr_group = {
> +	.attrs = smbios_slot_attributes,
> +	.is_visible = smbios_slot_exist,
> +};
> +
>  static int pci_create_smbiosname_file(struct pci_dev *pdev)
>  {
> +	int rc;
> +
> +	rc = sysfs_create_group(&pdev->dev.kobj, &smbios_slot_attr_group);
> +	if (rc != 0)
> +		return rc;
>  	return sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group);
>  }
>  
>  static void pci_remove_smbiosname_file(struct pci_dev *pdev)
>  {
>  	sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group);
> +	sysfs_remove_group(&pdev->dev.kobj, &smbios_slot_attr_group);
>  }
>  #else
>  static inline int pci_create_smbiosname_file(struct pci_dev *pdev)
> diff --git a/include/linux/dmi.h b/include/linux/dmi.h
> index 5055ac3..09f42e7 100644
> --- a/include/linux/dmi.h
> +++ b/include/linux/dmi.h
> @@ -22,6 +22,7 @@ enum dmi_device_type {
>  	DMI_DEV_TYPE_IPMI = -1,
>  	DMI_DEV_TYPE_OEM_STRING = -2,
>  	DMI_DEV_TYPE_DEV_ONBOARD = -3,
> +	DMI_DEV_TYPE_SYSTEM_SLOT = -4,
>  };
>  
>  enum dmi_entry_type {
> -- 
> 1.8.3.1
> 

  parent reply	other threads:[~2015-07-21 18:09 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-07-10 22:02 [PATCH] Add support for reading SMBIOS Slot number for PCI devices Jordan Hargrave
2015-07-13  7:35 ` Jean Delvare
     [not found]   ` <CAC1AzdfFjPrfvg2iBYXY5JDKhbVH3LPQdh5LzyjMaBFSNDBi6Q@mail.gmail.com>
2015-07-13 15:11     ` Jordan Hargrave
2015-07-21 16:57     ` Bjorn Helgaas
2015-07-21 17:31       ` Jordan Hargrave
2015-07-22  1:09         ` Bjorn Helgaas
2015-07-22 20:07           ` Jordan Hargrave
2015-07-23 17:24             ` Bjorn Helgaas
2015-07-24  2:31               ` Jordan Hargrave
2015-07-24  3:11                 ` Jordan Hargrave
2015-11-10 14:40                   ` Jordan Hargrave
2015-07-21 18:09 ` Bjorn Helgaas [this message]
2015-07-21 18:56   ` Jordan Hargrave

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150721180919.GE21967@google.com \
    --to=bhelgaas@google.com \
    --cc=Jordan_Hargrave@dell.com \
    --cc=jdelvare@suse.de \
    --cc=jharg93@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).