Commit 126034fa authored by Niklas Schnelle's avatar Niklas Schnelle Committed by Heiko Carstens
Browse files

s390/pci: Use topology ID for multi-function devices



The newly introduced topology ID (TID) field in the CLP Query PCI
Function explicitly identifies groups of PCI functions whose RIDs belong
to the same (sub-)topology. When available use the TID instead of the
PCHID to match zPCI busses/domains for multi-function devices. Note that
currently only a single PCI bus per TID is supported. This change is
required because in future machines the PCHID will not identify a PCI
card but a specific port in the case of some multi-port NICs while from
a PCI point of view the entire card is a subtopology.

Reviewed-by: default avatarGerd Bayer <gbayer@linux.ibm.com>
Signed-off-by: default avatarNiklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
parent 0467cdde
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -107,9 +107,10 @@ struct zpci_bus {
	struct list_head	resources;
	struct list_head	bus_next;
	struct resource		bus_resource;
	int			pchid;
	int			topo;		/* TID if topo_is_tid, PCHID otherwise */
	int			domain_nr;
	bool			multifunction;
	u8			multifunction	: 1;
	u8			topo_is_tid	: 1;
	enum pci_bus_speed	max_bus_speed;
};

@@ -131,6 +132,7 @@ struct zpci_dev {
	u16		pchid;		/* physical channel ID */
	u16		maxstbl;	/* Maximum store block size */
	u16		rid;		/* RID as supplied by firmware */
	u16		tid;		/* Topology for which RID is valid */
	u8		pfgid;		/* function group ID */
	u8		pft;		/* pci function type */
	u8		port;
@@ -141,7 +143,8 @@ struct zpci_dev {
	u8		is_physfn	: 1;
	u8		util_str_avail	: 1;
	u8		irqs_registered	: 1;
	u8		reserved	: 2;
	u8		tid_avail	: 1;
	u8		reserved	: 1;
	unsigned int	devfn;		/* DEVFN part of the RID*/

	u8 pfip[CLP_PFIP_NR_SEGMENTS];	/* pci function internal path */
+5 −3
Original line number Diff line number Diff line
@@ -110,7 +110,8 @@ struct clp_req_query_pci {
struct clp_rsp_query_pci {
	struct clp_rsp_hdr hdr;
	u16 vfn;			/* virtual fn number */
	u16			:  3;
	u16			:  2;
	u16 tid_avail		:  1;
	u16 rid_avail		:  1;
	u16 is_physfn		:  1;
	u16 reserved1		:  1;
@@ -130,8 +131,9 @@ struct clp_rsp_query_pci {
	u64 edma;			/* end dma as */
#define ZPCI_RID_MASK_DEVFN 0x00ff
	u16 rid;			/* BUS/DEVFN PCI address */
	u16 reserved0;
	u32 reserved[10];
	u32 reserved0;
	u16 tid;
	u32 reserved[9];
	u32 uid;			/* user defined id */
	u8 util_str[CLP_UTIL_STR_LEN];	/* utility string */
	u32 reserved2[16];
+10 −7
Original line number Diff line number Diff line
@@ -232,13 +232,13 @@ static void zpci_bus_put(struct zpci_bus *zbus)
	kref_put(&zbus->kref, zpci_bus_release);
}

static struct zpci_bus *zpci_bus_get(int pchid)
static struct zpci_bus *zpci_bus_get(int topo, bool topo_is_tid)
{
	struct zpci_bus *zbus;

	mutex_lock(&zbus_list_lock);
	list_for_each_entry(zbus, &zbus_list, bus_next) {
		if (pchid == zbus->pchid) {
		if (topo_is_tid == zbus->topo_is_tid && topo == zbus->topo) {
			kref_get(&zbus->kref);
			goto out_unlock;
		}
@@ -249,7 +249,7 @@ static struct zpci_bus *zpci_bus_get(int pchid)
	return zbus;
}

static struct zpci_bus *zpci_bus_alloc(int pchid)
static struct zpci_bus *zpci_bus_alloc(int topo, bool topo_is_tid)
{
	struct zpci_bus *zbus;

@@ -257,7 +257,8 @@ static struct zpci_bus *zpci_bus_alloc(int pchid)
	if (!zbus)
		return NULL;

	zbus->pchid = pchid;
	zbus->topo = topo;
	zbus->topo_is_tid = topo_is_tid;
	INIT_LIST_HEAD(&zbus->bus_next);
	mutex_lock(&zbus_list_lock);
	list_add_tail(&zbus->bus_next, &zbus_list);
@@ -321,8 +322,9 @@ static int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev)

int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops)
{
	bool topo_is_tid = zdev->tid_avail;
	struct zpci_bus *zbus = NULL;
	int rc = -EBADF;
	int topo, rc = -EBADF;

	if (zpci_nb_devices == ZPCI_NR_DEVICES) {
		pr_warn("Adding PCI function %08x failed because the configured limit of %d is reached\n",
@@ -333,11 +335,12 @@ int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops)
	if (zdev->devfn >= ZPCI_FUNCTIONS_PER_BUS)
		return -EINVAL;

	topo = topo_is_tid ? zdev->tid : zdev->pchid;
	if (!s390_pci_no_rid && zdev->rid_available)
		zbus = zpci_bus_get(zdev->pchid);
		zbus = zpci_bus_get(topo, topo_is_tid);

	if (!zbus) {
		zbus = zpci_bus_alloc(zdev->pchid);
		zbus = zpci_bus_alloc(topo, topo_is_tid);
		if (!zbus)
			return -ENOMEM;
	}
+3 −0
Original line number Diff line number Diff line
@@ -170,6 +170,9 @@ static int clp_store_query_pci_fn(struct zpci_dev *zdev,
		zdev->rid = response->rid;
	if (!s390_pci_no_rid && zdev->rid_available)
		zdev->devfn = response->rid & ZPCI_RID_MASK_DEVFN;
	zdev->tid_avail = response->tid_avail;
	if (zdev->tid_avail)
		zdev->tid = response->tid;

	memcpy(zdev->pfip, response->pfip, sizeof(zdev->pfip));
	if (response->util_str_avail) {