pci slot number

什么是 PCIe slot number?

PCIE槽位号码指的是PCI Express(Peripheral Component Interconnect Express)插槽的物理编号。PCIe插槽是一种用于连接扩展卡(如显卡、声卡、网卡等)的接口标准。计算机主板上通常会提供多个PCIe插槽,每个插槽都有一个唯一的编号。

PCIE槽位号码用于在主板上标识每个PCIe插槽的位置,以方便用户识别和安装扩展卡。比如,一个主板上可能标有PCIE slot 1、PCIE slot 2、PCIE slot 3等,这样用户就可以根据需要选择合适的插槽插入扩展卡。

PCIe Slot Capabilities Register

pci slot number_第1张图片

 

查看slot的两种方法

方法一:从/sys/bus/pci/slots/下获取

pci slot number_第2张图片

具体代码实现如下:

  if (p->phy_slot)
    printf("\tPhysical Slot: %s\n", p->phy_slot);

  while (entry = readdir(dir))
    {
      char namebuf[OBJNAMELEN], buf[16];
      FILE *file;
      unsigned int dom, bus, dev;
      int res = 0;
      struct pci_dev *d;

      /* ".", ".." or a special non-device perhaps */
      if (entry->d_name[0] == '.')
	continue;

      n = snprintf(namebuf, OBJNAMELEN, "%s/%s/%s", dirname, entry->d_name, "address");
      if (n < 0 || n >= OBJNAMELEN)
	a->error("File name too long");
      file = fopen(namebuf, "r");
      /*
       * Old versions of Linux had a fakephp which didn't have an 'address'
       * file.  There's no useful information to be gleaned from these
       * devices, pretend they're not there.
       */
      if (!file)
	continue;

      if (!fgets(buf, sizeof(buf), file) || (res = sscanf(buf, "%x:%x:%x", &dom, &bus, &dev)) < 3)
	{
	  /*
	   * In some cases, the slot is not tied to a specific device before
	   * a card gets inserted. This happens for example on IBM pSeries
	   * and we need not warn about it.
	   */
	  if (res != 2)
	    a->warning("sysfs_fill_slots: Couldn't parse entry address %s", buf);
	}
      else
	{
	  for (d = a->devices; d; d = d->next)
	    if (dom == (unsigned)d->domain && bus == d->bus && dev == d->dev && !d->phy_slot)
	      d->phy_slot = pci_set_property(d, PCI_FILL_PHYS_SLOT, entry->d_name);
	}
      fclose(file);
    }
  closedir(dir);
}

 方法二:从配置空间中获取获取然后打印出来

#define  PCI_EXP_SLTCAP_PSN	0xfff80000 /* Physical Slot Number */  

printf("\t\t\tSlot #%d, PowerLimit %.3fW; Interlock%c NoCompl%c\n",
	(t & PCI_EXP_SLTCAP_PSN) >> 19,

ACPI(根据文档猜测的)

PCIE Slot number和ACPI关系

PCIE槽位号码和ACPI(Advanced Configuration and Power Interface)之间存在一定的联系。

ACPI是一种电源管理和硬件配置标准,用于操作系统与计算机硬件之间的通信。它提供了一种机制,使操作系统可以了解计算机的硬件配置和功能,并控制电源管理和设备驱动等方面的操作。

在ACPI中,PCIE槽位号码可以用于标识和配置PCIe插槽上的设备。操作系统通过解析ACPI表和信息,可以了解主板上每个PCIe插槽所安装的设备类型、资源分配情况等,并相应地进行初始化和配置。

通过ACPI,操作系统可以自动检测和管理PCIe插槽上的设备,包括为其分配适当的驱动程序、分配资源、进行电源管理等。操作系统可以根据PCIe槽位号码和ACPI信息,确定哪些设备被插入了哪个插槽,并据此进行相关的配置和控制。

因此,PCIE槽位号码是ACPI机制的一部分,用于提供操作系统对PCIe插槽上设备的管理和配置能力。

ACPI _SUN(Slot User Number) 定义slot id

在ACPI中,Slot user number是指用于标识和区分PCI插槽的用户定义的编号。每个PCI插槽都可以分配一个唯一的Slot user number,用于在操作系统和硬件设备之间进行通信和识别。

Slot user number可以由主板制造商或系统集成商自定义和分配。它在ACPI表中的Device Object的_SUN(Slot User Number)字段中进行定义和记录。

通过Slot user number,操作系统可以识别和区分不同的PCI插槽,并在需要的时候进行相关操作,比如配置设备驱动程序、分配资源等。

需要注意的是,Slot user number与PCIe槽位号码(PCIE slot number)不是相同的概念。PCIe槽位号码通常是由主板制造商在物理槽位上标识的编号,而Slot user number是一个ACPI中的编码,用于操作系统层面的管理和识别。

在一般情况下,Slot user number不会直接转换为PCIE slot number。这是因为Slot user number是在ACPI表中定义的用户自定义编号,而PCIE slot number是主板或系统制造商在物理槽位上标识的编号。

Slot user number主要在操作系统层面用于识别和区分PCI插槽,而PCIE slot number主要用于物理槽位的标识和组织。它们在不同的层面和用途上有所区别。

当操作系统需要识别和管理PCI插槽上的设备时,通常会使用Slot user number。操作系统在读取ACPI表的信息时可以获取Slot user number,并据此进行相关操作。

然而,有些操作系统或软件可能提供了针对Slot user number与PCIE slot number之间的映射或转换功能。通过这种转换,操作系统可以将Slot user number转换为对应的PCIE slot number,以更直接地进行物理槽位的标识和管理。

pci slot number_第3张图片

/*
 * struct slot - slot information for each *physical* slot
 */
struct slot {
	struct hotplug_slot	hotplug_slot;
	struct acpiphp_slot	*acpi_slot;
	unsigned int sun;	/* ACPI _SUN (Slot User Number) value */
};

SMBIOS System Slots (Type 9)定义slot id

Type 9 refers to the System Slots structure in the SMBIOS (System Management BIOS) specification. The Type 9 structure provides information about the various slots on the motherboard where expansion cards can be inserted.

The Type 9 structure typically includes the following information for each slot:

  1. Slot Designation: A string that identifies the slot's name or label (e.g., "PCI Slot 1").
  2. Slot Type: The type of slot, such as PCI, AGP, PCIe, etc.
  3. Slot Data Bus Width: The number of data bits supported by the slot, typically 16, 32, or 64.
  4. Current Usage: The current usage of the slot, such as "Available", "In use", or "Unknown".
  5. Slot Length: The physical length of the slot, expressed in millimeters.
  6. Slot ID: A unique identifier for the slot.
  7. Slot Characteristics: A set of bit flags that describe various characteristics of the slot, such as whether it supports hot-plugging or is shared.

pci slot number_第4张图片

查看smbios type 9

dmidecode -t 9查看slot信息

pci slot number_第5张图片

PCI Switch分配slot id

PCIe Switch固件可以用于分配PCIe Slot Number。PCIe Switch是一种用于管理多个PCIe设备连接的硬件,它可以在主板上提供额外的PCIe插槽,并通过固件进行配置和管理。

在PCIe Switch固件中,可以设置每个PCIe插槽的Slot Number。Slot Number是一个由固件分配的唯一标识符,用于在系统中识别和区分各个PCIe插槽。通过配置PCIe Switch固件中的设置,可以为每个插槽分配不同的Slot Number。

通过为每个插槽分配独立的Slot Number,可以提供更灵活的硬件配置和管理。系统软件可以通过Slot Number来标识和访问特定插槽上的设备,进行驱动配置、资源分配和设备管理等操作。

需要注意的是,PCIe Switch固件的功能和配置可能因不同的设备和厂商而有所差异。

内核相关函数介绍

/sys/bus/pci/slots目录创建

static int pci_slot_init(void)
{
	struct kset *pci_bus_kset;

	pci_bus_kset = bus_get_kset(&pci_bus_type);
	pci_slots_kset = kset_create_and_add("slots", NULL,
						&pci_bus_kset->kobj);
	if (!pci_slots_kset) {
		pr_err("PCI: Slot initialization failure\n");
		return -ENOMEM;
	}
	return 0;
}

subsys_initcall(pci_slot_init);

调用pci_create_slot注册slot

/*
 * Check whether handle has an associated slot and create PCI slot if it has.
 */
static acpi_status
register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
{
	int device;
	unsigned long long sun;
	char name[SLOT_NAME_SIZE];
	struct acpi_pci_slot *slot;
	struct pci_slot *pci_slot;
	struct pci_bus *pci_bus = context;

	device = check_slot(handle, &sun);
	if (device < 0)
		return AE_OK;

	/*
	 * There may be multiple PCI functions associated with the same slot.
	 * Check whether PCI slot has already been created for this PCI device.
	 */
	list_for_each_entry(slot, &slot_list, list) {
		pci_slot = slot->pci_slot;
		if (pci_slot->bus == pci_bus && pci_slot->number == device)
			return AE_OK;
	}

	slot = kmalloc(sizeof(*slot), GFP_KERNEL);
	if (!slot)
		return AE_OK;

	snprintf(name, sizeof(name), "%llu", sun);
	pci_slot = pci_create_slot(pci_bus, device, name, NULL);
	if (IS_ERR(pci_slot)) {
		pr_err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot));
		kfree(slot);
		return AE_OK;
	}

	slot->pci_slot = pci_slot;
	list_add(&slot->list, &slot_list);

	get_device(&pci_bus->dev);

	pr_debug("%p, pci_bus: %x, device: %d, name: %s\n",
		 pci_slot, pci_bus->number, device, name);

	return AE_OK;
}

用于创建或增加物理PCI槽位的引用计数

函数接受四个参数:parent表示父桥的struct pci_busslot_nr表示PCI设备的槽位号,name表示在/sys/bus/pci/slots/中显示的用户可见字符串,hotplug表示调用者是否是热插拔驱动程序。

/**
 * pci_create_slot - create or increment refcount for physical PCI slot
 * @parent: struct pci_bus of parent bridge
 * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder
 * @name: user visible string presented in /sys/bus/pci/slots/
 * @hotplug: set if caller is hotplug driver, NULL otherwise
 *
 * PCI slots have first class attributes such as address, speed, width,
 * and a &struct pci_slot is used to manage them. This interface will
 * either return a new &struct pci_slot to the caller, or if the pci_slot
 * already exists, its refcount will be incremented.
 *
 * Slots are uniquely identified by a @pci_bus, @slot_nr tuple.
 *
 * There are known platforms with broken firmware that assign the same
 * name to multiple slots. Workaround these broken platforms by renaming
 * the slots on behalf of the caller. If firmware assigns name N to
 * multiple slots:
 *
 * The first slot is assigned N
 * The second slot is assigned N-1
 * The third slot is assigned N-2
 * etc.
 *
 * Placeholder slots:
 * In most cases, @pci_bus, @slot_nr will be sufficient to uniquely identify
 * a slot. There is one notable exception - pSeries (rpaphp), where the
 * @slot_nr cannot be determined until a device is actually inserted into
 * the slot. In this scenario, the caller may pass -1 for @slot_nr.
 *
 * The following semantics are imposed when the caller passes @slot_nr ==
 * -1. First, we no longer check for an existing %struct pci_slot, as there
 * may be many slots with @slot_nr of -1.  The other change in semantics is
 * user-visible, which is the 'address' parameter presented in sysfs will
 * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the
 * %struct pci_bus and bb is the bus number. In other words, the devfn of
 * the 'placeholder' slot will not be displayed.
 */
struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
				 const char *name,
				 struct hotplug_slot *hotplug)
{
	struct pci_dev *dev;
	struct pci_slot *slot;
	int err = 0;
	char *slot_name = NULL;

	mutex_lock(&pci_slot_mutex);

	if (slot_nr == -1)
		goto placeholder;

	/*
	 * Hotplug drivers are allowed to rename an existing slot,
	 * but only if not already claimed.
	 */
	slot = get_slot(parent, slot_nr);
	if (slot) {
		if (hotplug) {
			if ((err = slot->hotplug ? -EBUSY : 0)
			     || (err = rename_slot(slot, name))) {
				kobject_put(&slot->kobj);
				slot = NULL;
				goto err;
			}
		}
		goto out;
	}

placeholder:
	slot = kzalloc(sizeof(*slot), GFP_KERNEL);
	if (!slot) {
		err = -ENOMEM;
		goto err;
	}

	slot->bus = parent;
	slot->number = slot_nr;

	slot->kobj.kset = pci_slots_kset;

	slot_name = make_slot_name(name);
	if (!slot_name) {
		err = -ENOMEM;
		kfree(slot);
		goto err;
	}

	err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL,
				   "%s", slot_name);
	if (err) {
		kobject_put(&slot->kobj);
		goto err;
	}

	INIT_LIST_HEAD(&slot->list);
	list_add(&slot->list, &parent->slots);

	down_read(&pci_bus_sem);
	list_for_each_entry(dev, &parent->devices, bus_list)
		if (PCI_SLOT(dev->devfn) == slot_nr)
			dev->slot = slot;
	up_read(&pci_bus_sem);

	dev_dbg(&parent->dev, "dev %02x, created physical slot %s\n",
		slot_nr, pci_slot_name(slot));

out:
	kfree(slot_name);
	mutex_unlock(&pci_slot_mutex);
	return slot;
err:
	slot = ERR_PTR(err);
	goto out;
}
EXPORT_SYMBOL_GPL(pci_create_slot);

/sys/bus/pci/slots 目录下创建的插槽文件夹具有唯一的名称,以避免名称冲突。如果存在相同的插槽名,函数会在名称末尾添加一个连字符和递增的数字,直到找到一个唯一的名称。

static char *make_slot_name(const char *name)
{
	char *new_name;
	int len, max, dup;

	new_name = kstrdup(name, GFP_KERNEL);
	if (!new_name)
		return NULL;

	/*
	 * Make sure we hit the realloc case the first time through the
	 * loop.  'len' will be strlen(name) + 3 at that point which is
	 * enough space for "name-X" and the trailing NUL.
	 */
	len = strlen(name) + 2;
	max = 1;
	dup = 1;

	for (;;) {
		struct kobject *dup_slot;
		dup_slot = kset_find_obj(pci_slots_kset, new_name);
		if (!dup_slot)
			break;
		kobject_put(dup_slot);
		if (dup == max) {
			len++;
			max *= 10;
			kfree(new_name);
			new_name = kmalloc(len, GFP_KERNEL);
			if (!new_name)
				break;
		}
		sprintf(new_name, "%s-%d", name, dup++);
	}

	return new_name;
}

 

你可能感兴趣的:(pci,pci,slot)