soc/intel/xeon_sp: Add device find utils

For Xeon-SP, it's common pattern to find devices under specific
socket, stack and domain. This patch adds util function for
these operations.

TEST=intel/archercity CRB

Change-Id: I163eacae363334919fd66d571b7e0415e77bd52d
Signed-off-by: Shuo Liu <shuo.liu@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/81043
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Lean Sheng Tan <sheng.tan@9elements.com>
This commit is contained in:
Shuo Liu
2024-03-04 23:59:48 +08:00
committed by Lean Sheng Tan
parent 873112ac34
commit 7f92210485
2 changed files with 107 additions and 11 deletions

View File

@ -25,31 +25,115 @@ static const STACK_RES *domain_to_stack_res(const struct device *dev)
}
/**
* Find a device of a given vendor and type for the specified socket.
* Find all device of a given vendor and type for the specified socket.
* The function iterates over all PCI domains of the specified socket
* and matches the PCI vendor and device ID.
*
* @param socket The socket where to search for the device.
* @param vendor A PCI vendor ID (e.g. 0x8086 for Intel).
* @param device A PCI device ID.
* @return Pointer to the device struct.
* @param from The device pointer to start search from.
*
* @return Pointer to the device struct. When there are multiple device
* instances, the caller should continue search upon a non-NULL match.
*/
struct device *dev_find_all_devices_on_socket(uint8_t socket, u16 vendor, u16 device,
struct device *from)
{
return dev_find_all_devices_on_stack(socket, XEONSP_STACK_MAX, vendor, device, from);
}
/*
* Find device of a given vendor and type for the specified socket.
* The function will return at the 1st match.
*/
struct device *dev_find_device_on_socket(uint8_t socket, u16 vendor, u16 device)
{
struct device *domain, *dev = NULL;
union xeon_domain_path dn;
while ((dev = dev_find_device(vendor, device, dev))) {
domain = dev_get_pci_domain(dev);
if (!domain)
continue;
dn.domain_path = domain->path.domain.domain;
if (dn.socket != socket)
continue;
return dev;
return dev_find_all_devices_on_socket(socket, vendor, device, NULL);
}
return NULL;
static int filter_device_on_stack(struct device *dev, uint8_t socket, uint8_t stack,
u16 vendor, u16 device)
{
struct device *domain = dev_get_pci_domain(dev);
if (!domain)
return 0;
if (dev->path.type != DEVICE_PATH_PCI)
return 0;
union xeon_domain_path dn;
dn.domain_path = domain->path.domain.domain;
if (socket != XEONSP_SOCKET_MAX && dn.socket != socket)
return 0;
if (stack != XEONSP_STACK_MAX && dn.stack != stack)
return 0;
if (vendor != XEONSP_VENDOR_MAX && dev->vendor != vendor)
return 0;
if (device != XEONSP_DEVICE_MAX && dev->device != device)
return 0;
return 1;
};
/**
* Find all device of a given vendor and type for the specified socket and stack.
*
* @param socket The socket where to search for the device.
* XEONSP_SOCKET_MAX indicates any socket.
* @param stack The stack where to search for the device.
* XEONSP_STACK_MAX indicates any stack.
* @param vendor A PCI vendor ID (e.g. 0x8086 for Intel).
* XEONSP_VENDOR_MAX indicates any vendor.
* @param device A PCI device ID.
* XEONSP_DEVICE_MAX indicates any device.
* @param from The device pointer to start search from.
*
* @return Pointer to the device struct. When there are multiple device
* instances, the caller should continue search upon a non-NULL match.
*/
struct device *dev_find_all_devices_on_stack(uint8_t socket, uint8_t stack,
u16 vendor, u16 device, struct device *from)
{
if (!from)
from = all_devices;
else
from = from->next;
while (from && (!filter_device_on_stack(from, socket, stack,
vendor, device)))
from = from->next;
return from;
}
/**
* Find all device of a given vendor and type for the specific domain
* Only the direct child of the input domain is iterated
*
* @param domain Pointer to the input domain
* @param vendor A PCI vendor ID
* XEONSP_VENDOR_MAX indicates any vendor
* @param vendor A PCI device ID
* XEONSP_DEVICE_MAX indicates any vendor
* @param from The device pointer to start search from.
*
* @return Pointer to the device struct. When there are multiple device
* instances, the caller should continue search upon a non-NULL match.
*/
struct device *dev_find_all_devices_on_domain(struct device *domain, u16 vendor,
u16 device, struct device *from)
{
struct device *dev = from;
while ((dev = dev_bus_each_child(domain->downstream, dev))) {
if (vendor != XEONSP_VENDOR_MAX && dev->vendor != vendor)
continue;
if (device != XEONSP_DEVICE_MAX && dev->device != device)
continue;
break;
}
return dev;
}
/**

View File

@ -16,6 +16,10 @@ union xeon_domain_path {
};
};
#define XEONSP_STACK_MAX UINT8_MAX
#define XEONSP_SOCKET_MAX UINT8_MAX
#define XEONSP_DEVICE_MAX UINT16_MAX
#define XEONSP_VENDOR_MAX UINT16_MAX
static inline void init_xeon_domain_path(struct device_path *path, int socket,
int stack, int bus)
@ -50,7 +54,15 @@ void attach_iio_stacks(void);
void soc_create_ioat_domains(union xeon_domain_path path, struct bus *bus, const STACK_RES *sr);
void soc_create_cxl_domains(const union xeon_domain_path dp, struct bus *bus, const STACK_RES *sr);
struct device *dev_find_device_on_socket(uint8_t socket, u16 vendor, u16 device);
struct device *dev_find_all_devices_on_socket(uint8_t socket,
u16 vendor, u16 device, struct device *from);
struct device *dev_find_all_devices_on_stack(uint8_t socket, uint8_t stack,
u16 vendor, u16 device, struct device *from);
struct device *dev_find_all_devices_on_domain(struct device *domain,
u16 vendor, u16 device, struct device *from);
int iio_pci_domain_socket_from_dev(struct device *dev);
int iio_pci_domain_stack_from_dev(struct device *dev);