ia64/linux-2.6.18-xen.hg

changeset 822:fb46e5625c61

PCI: initialize and release SR-IOV capability

If a device has the SR-IOV capability, initialize it (set the ARI
Capable Hierarchy in the lowest numbered PF if necessary; calculate
the System Page Size for the VF MMIO, probe the VF Offset, Stride
and BARs). A lock for the VF bus allocation is also initialized if
a PF is the lowest numbered PF.

Signed-off-by: Yu Zhao <yu.zhao@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Mar 18 11:39:04 2009 +0000 (2009-03-18)
parents 6669e480cb59
children 589a78a593f3
files drivers/pci/Kconfig drivers/pci/Makefile drivers/pci/iov.c drivers/pci/pci.c drivers/pci/pci.h drivers/pci/probe.c include/linux/pci.h include/linux/pci_regs.h
line diff
     1.1 --- a/drivers/pci/Kconfig	Tue Mar 17 14:27:31 2009 +0000
     1.2 +++ b/drivers/pci/Kconfig	Wed Mar 18 11:39:04 2009 +0000
     1.3 @@ -37,3 +37,12 @@ config PCI_GUESTDEV
     1.4  	help
     1.5  	  Say Y here if you want to reserve PCI device for passthrough.
     1.6  
     1.7 +config PCI_IOV
     1.8 +	bool "PCI IOV support"
     1.9 +	depends on PCI
    1.10 +	help
    1.11 +	  PCI-SIG I/O Virtualization (IOV) Specifications support.
    1.12 +	  Single Root IOV: allows the creation of virtual PCI devices
    1.13 +	  that share the physical resources from a real device.
    1.14 +
    1.15 +	  When in doubt, say N.
     2.1 --- a/drivers/pci/Makefile	Tue Mar 17 14:27:31 2009 +0000
     2.2 +++ b/drivers/pci/Makefile	Wed Mar 18 11:39:04 2009 +0000
     2.3 @@ -16,6 +16,8 @@ obj-$(CONFIG_HOTPLUG) += hotplug.o
     2.4  # Build the PCI Hotplug drivers if we were asked to
     2.5  obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
     2.6  
     2.7 +obj-$(CONFIG_PCI_IOV) += iov.o
     2.8 +
     2.9  #
    2.10  # Some architectures use the generic PCI setup functions
    2.11  #
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/drivers/pci/iov.c	Wed Mar 18 11:39:04 2009 +0000
     3.3 @@ -0,0 +1,175 @@
     3.4 +/*
     3.5 + * drivers/pci/iov.c
     3.6 + *
     3.7 + * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
     3.8 + *
     3.9 + * PCI Express I/O Virtualization (IOV) support.
    3.10 + *   Single Root IOV 1.0
    3.11 + */
    3.12 +
    3.13 +#include <linux/pci.h>
    3.14 +#include <linux/mutex.h>
    3.15 +#include <linux/string.h>
    3.16 +#include <linux/delay.h>
    3.17 +#include "pci.h"
    3.18 +
    3.19 +
    3.20 +static int sriov_init(struct pci_dev *dev, int pos)
    3.21 +{
    3.22 +	int i;
    3.23 +	int rc;
    3.24 +	int nres;
    3.25 +	u32 pgsz;
    3.26 +	u16 ctrl, total, offset, stride;
    3.27 +	struct pci_sriov *iov;
    3.28 +	struct resource *res;
    3.29 +	struct pci_dev *pdev;
    3.30 +
    3.31 +	pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl);
    3.32 +	if (ctrl & PCI_SRIOV_CTRL_VFE) {
    3.33 +		pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, 0);
    3.34 +		ssleep(1);
    3.35 +	}
    3.36 +
    3.37 +	pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total);
    3.38 +	if (!total)
    3.39 +		return 0;
    3.40 +
    3.41 +	list_for_each_entry(pdev, &dev->bus->devices, bus_list)
    3.42 +		if (pdev->is_physfn)
    3.43 +			break;
    3.44 +	if (list_empty(&dev->bus->devices) || !pdev->is_physfn)
    3.45 +		pdev = NULL;
    3.46 +
    3.47 +	ctrl = 0;
    3.48 +	if (!pdev && pci_ari_enabled(dev->bus))
    3.49 +		ctrl |= PCI_SRIOV_CTRL_ARI;
    3.50 +
    3.51 +	pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl);
    3.52 +	pci_write_config_word(dev, pos + PCI_SRIOV_NUM_VF, total);
    3.53 +	pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset);
    3.54 +	pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride);
    3.55 +	if (!offset || (total > 1 && !stride))
    3.56 +		return -EIO;
    3.57 +
    3.58 +	pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &pgsz);
    3.59 +	i = PAGE_SHIFT > 12 ? PAGE_SHIFT - 12 : 0;
    3.60 +	pgsz &= ~((1 << i) - 1);
    3.61 +	if (!pgsz)
    3.62 +		return -EIO;
    3.63 +
    3.64 +	pgsz &= ~(pgsz - 1);
    3.65 +	pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz);
    3.66 +
    3.67 +	nres = 0;
    3.68 +	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
    3.69 +		res = dev->resource + PCI_IOV_RESOURCES + i;
    3.70 +		i += __pci_read_base(dev, pci_bar_unknown, res,
    3.71 +				     pos + PCI_SRIOV_BAR + i * 4);
    3.72 +		if (!res->flags)
    3.73 +			continue;
    3.74 +		if ((res->end - res->start + 1) & (PAGE_SIZE - 1)) {
    3.75 +			rc = -EIO;
    3.76 +			goto failed;
    3.77 +		}
    3.78 +		res->end = res->start + (res->end - res->start + 1) * total - 1;
    3.79 +		nres++;
    3.80 +	}
    3.81 +
    3.82 +	iov = kzalloc(sizeof(*iov), GFP_KERNEL);
    3.83 +	if (!iov) {
    3.84 +		rc = -ENOMEM;
    3.85 +		goto failed;
    3.86 +	}
    3.87 +
    3.88 +	iov->pos = pos;
    3.89 +	iov->nres = nres;
    3.90 +	iov->ctrl = ctrl;
    3.91 +	iov->total = total;
    3.92 +	iov->offset = offset;
    3.93 +	iov->stride = stride;
    3.94 +	iov->pgsz = pgsz;
    3.95 +	iov->self = dev;
    3.96 +	pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
    3.97 +	pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
    3.98 +
    3.99 +	if (pdev)
   3.100 +		iov->dev = pci_dev_get(pdev);
   3.101 +	else {
   3.102 +		iov->dev = dev;
   3.103 +		mutex_init(&iov->lock);
   3.104 +	}
   3.105 +
   3.106 +	dev->sriov = iov;
   3.107 +	dev->is_physfn = 1;
   3.108 +
   3.109 +	return 0;
   3.110 +
   3.111 +failed:
   3.112 +	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
   3.113 +		res = dev->resource + PCI_IOV_RESOURCES + i;
   3.114 +		res->flags = 0;
   3.115 +	}
   3.116 +
   3.117 +	return rc;
   3.118 +}
   3.119 +
   3.120 +static void sriov_release(struct pci_dev *dev)
   3.121 +{
   3.122 +	if (dev == dev->sriov->dev)
   3.123 +		mutex_destroy(&dev->sriov->lock);
   3.124 +	else
   3.125 +		pci_dev_put(dev->sriov->dev);
   3.126 +
   3.127 +	kfree(dev->sriov);
   3.128 +	dev->sriov = NULL;
   3.129 +}
   3.130 +
   3.131 +/**
   3.132 + * pci_iov_init - initialize the IOV capability
   3.133 + * @dev: the PCI device
   3.134 + *
   3.135 + * Returns 0 on success, or negative on failure.
   3.136 + */
   3.137 +int pci_iov_init(struct pci_dev *dev)
   3.138 +{
   3.139 +	int pos;
   3.140 +
   3.141 +	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
   3.142 +	if (pos)
   3.143 +		return sriov_init(dev, pos);
   3.144 +
   3.145 +	return -ENODEV;
   3.146 +}
   3.147 +
   3.148 +/**
   3.149 + * pci_iov_release - release resources used by the IOV capability
   3.150 + * @dev: the PCI device
   3.151 + */
   3.152 +void pci_iov_release(struct pci_dev *dev)
   3.153 +{
   3.154 +	if (dev->is_physfn)
   3.155 +		sriov_release(dev);
   3.156 +}
   3.157 +
   3.158 +/**
   3.159 + * pci_iov_resource_bar - get position of the SR-IOV BAR
   3.160 + * @dev: the PCI device
   3.161 + * @resno: the resource number
   3.162 + * @type: the BAR type to be filled in
   3.163 + *
   3.164 + * Returns position of the BAR encapsulated in the SR-IOV capability.
   3.165 + */
   3.166 +int pci_iov_resource_bar(struct pci_dev *dev, int resno,
   3.167 +			 enum pci_bar_type *type)
   3.168 +{
   3.169 +	if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END)
   3.170 +		return 0;
   3.171 +
   3.172 +	BUG_ON(!dev->is_physfn);
   3.173 +
   3.174 +	*type = pci_bar_unknown;
   3.175 +
   3.176 +	return dev->sriov->pos + PCI_SRIOV_BAR +
   3.177 +		4 * (resno - PCI_IOV_RESOURCES);
   3.178 +}
     4.1 --- a/drivers/pci/pci.c	Tue Mar 17 14:27:31 2009 +0000
     4.2 +++ b/drivers/pci/pci.c	Wed Mar 18 11:39:04 2009 +0000
     4.3 @@ -1048,12 +1048,19 @@ pci_set_consistent_dma_mask(struct pci_d
     4.4   */
     4.5  int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
     4.6  {
     4.7 +	int reg;
     4.8 +
     4.9  	if (resno < PCI_ROM_RESOURCE) {
    4.10  		*type = pci_bar_unknown;
    4.11  		return PCI_BASE_ADDRESS_0 + 4 * resno;
    4.12  	} else if (resno == PCI_ROM_RESOURCE) {
    4.13  		*type = pci_bar_mem32;
    4.14  		return dev->rom_base_reg;
    4.15 +	} else if (resno < PCI_BRIDGE_RESOURCES) {
    4.16 +		/* device specific resource */
    4.17 +		reg = pci_iov_resource_bar(dev, resno, type);
    4.18 +		if (reg)
    4.19 +			return reg;
    4.20  	}
    4.21  
    4.22  	dev_err(&dev->dev, "BAR: invalid resource #%d\n", resno);
     5.1 --- a/drivers/pci/pci.h	Tue Mar 17 14:27:31 2009 +0000
     5.2 +++ b/drivers/pci/pci.h	Wed Mar 18 11:39:04 2009 +0000
     5.3 @@ -132,3 +132,40 @@ static inline int pci_ari_enabled(struct
     5.4  {
     5.5  	return bus->self && bus->self->ari_enabled;
     5.6  }
     5.7 +
     5.8 +/* Single Root I/O Virtualization */
     5.9 +struct pci_sriov {
    5.10 +	int pos;		/* capability position */
    5.11 +	int nres;		/* number of resources */
    5.12 +	u32 cap;		/* SR-IOV Capabilities */
    5.13 +	u16 ctrl;		/* SR-IOV Control */
    5.14 +	u16 total;		/* total VFs associated with the PF */
    5.15 +	u16 offset;		/* first VF Routing ID offset */
    5.16 +	u16 stride;		/* following VF stride */
    5.17 +	u32 pgsz;		/* page size for BAR alignment */
    5.18 +	u8 link;		/* Function Dependency Link */
    5.19 +	struct pci_dev *dev;	/* lowest numbered PF */
    5.20 +	struct pci_dev *self;	/* this PF */
    5.21 +	struct mutex lock;	/* lock for VF bus */
    5.22 +};
    5.23 +
    5.24 +#ifdef CONFIG_PCI_IOV
    5.25 +extern int pci_iov_init(struct pci_dev *dev);
    5.26 +extern void pci_iov_release(struct pci_dev *dev);
    5.27 +extern int pci_iov_resource_bar(struct pci_dev *dev, int resno,
    5.28 +				enum pci_bar_type *type);
    5.29 +#else
    5.30 +static inline int pci_iov_init(struct pci_dev *dev)
    5.31 +{
    5.32 +	return -ENODEV;
    5.33 +}
    5.34 +static inline void pci_iov_release(struct pci_dev *dev)
    5.35 +
    5.36 +{
    5.37 +}
    5.38 +static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno,
    5.39 +				       enum pci_bar_type *type)
    5.40 +{
    5.41 +	return 0;
    5.42 +}
    5.43 +#endif /* CONFIG_PCI_IOV */
     6.1 --- a/drivers/pci/probe.c	Tue Mar 17 14:27:31 2009 +0000
     6.2 +++ b/drivers/pci/probe.c	Wed Mar 18 11:39:04 2009 +0000
     6.3 @@ -765,6 +765,9 @@ static void pci_release_dev(struct devic
     6.4  	struct pci_dev *pci_dev;
     6.5  
     6.6  	pci_dev = to_pci_dev(dev);
     6.7 +
     6.8 +	pci_iov_release(pci_dev);
     6.9 +
    6.10  	kfree(pci_dev);
    6.11  }
    6.12  
    6.13 @@ -892,6 +895,9 @@ void __devinit pci_device_add(struct pci
    6.14  	/* Alternative Routing-ID Forwarding */
    6.15  	pci_enable_ari(dev);
    6.16  
    6.17 +	/* Single Root I/O Virtualization */
    6.18 +	pci_iov_init(dev);
    6.19 +
    6.20  	/*
    6.21  	 * Add the device to our list of discovered devices
    6.22  	 * and the bus list for fixup functions, etc.
     7.1 --- a/include/linux/pci.h	Tue Mar 17 14:27:31 2009 +0000
     7.2 +++ b/include/linux/pci.h	Wed Mar 18 11:39:04 2009 +0000
     7.3 @@ -77,6 +77,12 @@ enum {
     7.4  	/* #6: expansion ROM resource */
     7.5  	PCI_ROM_RESOURCE,
     7.6  
     7.7 +	/* device specific resources */
     7.8 +#ifdef CONFIG_PCI_IOV
     7.9 +	PCI_IOV_RESOURCES,
    7.10 +	PCI_IOV_RESOURCE_END = PCI_IOV_RESOURCES + PCI_SRIOV_NUM_BARS - 1,
    7.11 +#endif
    7.12 +
    7.13  	/* resources assigned to buses behind the bridge */
    7.14  #define PCI_BRIDGE_RESOURCE_NUM 4
    7.15  
    7.16 @@ -128,6 +134,8 @@ struct pci_cap_saved_state {
    7.17  	u32 data[0];
    7.18  };
    7.19  
    7.20 +struct pci_sriov;
    7.21 +
    7.22  /*
    7.23   * The pci_dev structure is used to describe PCI devices.
    7.24   */
    7.25 @@ -189,13 +197,17 @@ struct pci_dev {
    7.26  	unsigned int	broken_parity_status:1;	/* Device generates false positive parity */
    7.27  	unsigned int 	msi_enabled:1;
    7.28  	unsigned int	msix_enabled:1;
    7.29 +	unsigned int	ari_enabled:1;	/* ARI forwarding */
    7.30 +	unsigned int	is_physfn:1;
    7.31  
    7.32  	u32		saved_config_space[16]; /* config space saved at suspend time */
    7.33  	struct hlist_head saved_cap_space;
    7.34  	struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */
    7.35  	int rom_attr_enabled;		/* has display of the rom attribute been enabled? */
    7.36  	struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
    7.37 -	unsigned int	ari_enabled:1;	/* ARI forwarding */
    7.38 +#ifdef CONFIG_PCI_IOV
    7.39 +	struct pci_sriov *sriov;	/* SR-IOV capability related */
    7.40 +#endif
    7.41  };
    7.42  
    7.43  #define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)
     8.1 --- a/include/linux/pci_regs.h	Tue Mar 17 14:27:31 2009 +0000
     8.2 +++ b/include/linux/pci_regs.h	Wed Mar 18 11:39:04 2009 +0000
     8.3 @@ -332,6 +332,7 @@
     8.4  #define  PCI_EXP_TYPE_UPSTREAM	0x5	/* Upstream Port */
     8.5  #define  PCI_EXP_TYPE_DOWNSTREAM 0x6	/* Downstream Port */
     8.6  #define  PCI_EXP_TYPE_PCI_BRIDGE 0x7	/* PCI/PCI-X Bridge */
     8.7 +#define  PCI_EXP_TYPE_RC_END	0x9	/* Root Complex Integrated Endpoint */
     8.8  #define PCI_EXP_FLAGS_SLOT	0x0100	/* Slot implemented */
     8.9  #define PCI_EXP_FLAGS_IRQ	0x3e00	/* Interrupt message number */
    8.10  #define PCI_EXP_DEVCAP		4	/* Device capabilities */
    8.11 @@ -393,6 +394,7 @@
    8.12  #define PCI_EXT_CAP_ID_DSN	3
    8.13  #define PCI_EXT_CAP_ID_PWR	4
    8.14  #define PCI_EXT_CAP_ID_ARI	14
    8.15 +#define PCI_EXT_CAP_ID_SRIOV	16
    8.16  
    8.17  /* Advanced Error Reporting */
    8.18  #define PCI_ERR_UNCOR_STATUS	4	/* Uncorrectable Error Status */
    8.19 @@ -478,4 +480,35 @@
    8.20  #define  PCI_ARI_CTRL_ACS	0x0002	/* ACS Function Groups Enable */
    8.21  #define  PCI_ARI_CTRL_FG(x)	(((x) >> 4) & 7) /* Function Group */
    8.22  
    8.23 +/* Single Root I/O Virtualization */
    8.24 +#define PCI_SRIOV_CAP		0x04	/* SR-IOV Capabilities */
    8.25 +#define  PCI_SRIOV_CAP_VFM	0x01	/* VF Migration Capable */
    8.26 +#define  PCI_SRIOV_CAP_INTR(x)	((x) >> 21) /* Interrupt Message Number */
    8.27 +#define PCI_SRIOV_CTRL		0x08	/* SR-IOV Control */
    8.28 +#define  PCI_SRIOV_CTRL_VFE	0x01	/* VF Enable */
    8.29 +#define  PCI_SRIOV_CTRL_VFM	0x02	/* VF Migration Enable */
    8.30 +#define  PCI_SRIOV_CTRL_INTR	0x04	/* VF Migration Interrupt Enable */
    8.31 +#define  PCI_SRIOV_CTRL_MSE	0x08	/* VF Memory Space Enable */
    8.32 +#define  PCI_SRIOV_CTRL_ARI	0x10	/* ARI Capable Hierarchy */
    8.33 +#define PCI_SRIOV_STATUS	0x0a	/* SR-IOV Status */
    8.34 +#define  PCI_SRIOV_STATUS_VFM	0x01	/* VF Migration Status */
    8.35 +#define PCI_SRIOV_INITIAL_VF	0x0c	/* Initial VFs */
    8.36 +#define PCI_SRIOV_TOTAL_VF	0x0e	/* Total VFs */
    8.37 +#define PCI_SRIOV_NUM_VF	0x10	/* Number of VFs */
    8.38 +#define PCI_SRIOV_FUNC_LINK	0x12	/* Function Dependency Link */
    8.39 +#define PCI_SRIOV_VF_OFFSET	0x14	/* First VF Offset */
    8.40 +#define PCI_SRIOV_VF_STRIDE	0x16	/* Following VF Stride */
    8.41 +#define PCI_SRIOV_VF_DID	0x1a	/* VF Device ID */
    8.42 +#define PCI_SRIOV_SUP_PGSIZE	0x1c	/* Supported Page Sizes */
    8.43 +#define PCI_SRIOV_SYS_PGSIZE	0x20	/* System Page Size */
    8.44 +#define PCI_SRIOV_BAR		0x24	/* VF BAR0 */
    8.45 +#define  PCI_SRIOV_NUM_BARS	6	/* Number of VF BARs */
    8.46 +#define PCI_SRIOV_VFM		0x3c	/* VF Migration State Array Offset*/
    8.47 +#define  PCI_SRIOV_VFM_BIR(x)	((x) & 7)	/* State BIR */
    8.48 +#define  PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7)	/* State Offset */
    8.49 +#define  PCI_SRIOV_VFM_UA	0x0	/* Inactive.Unavailable */
    8.50 +#define  PCI_SRIOV_VFM_MI	0x1	/* Dormant.MigrateIn */
    8.51 +#define  PCI_SRIOV_VFM_MO	0x2	/* Active.MigrateOut */
    8.52 +#define  PCI_SRIOV_VFM_AV	0x3	/* Active.Available */
    8.53 +
    8.54  #endif /* LINUX_PCI_REGS_H */