aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/Kconfig10
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/iov.c182
-rw-r--r--drivers/pci/pci.c7
-rw-r--r--drivers/pci/pci.h37
-rw-r--r--drivers/pci/probe.c4
-rw-r--r--include/linux/pci.h11
-rw-r--r--include/linux/pci_regs.h33
8 files changed, 286 insertions, 0 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 2a4501dd2515..fdc864f9cf23 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -59,3 +59,13 @@ config HT_IRQ
59 This allows native hypertransport devices to use interrupts. 59 This allows native hypertransport devices to use interrupts.
60 60
61 If unsure say Y. 61 If unsure say Y.
62
63config PCI_IOV
64 bool "PCI IOV support"
65 depends on PCI
66 help
67 I/O Virtualization is a PCI feature supported by some devices
68 which allows them to create virtual devices which share their
69 physical resources.
70
71 If unsure, say N.
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 3d07ce24f6a8..ba6af162fd39 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -29,6 +29,8 @@ obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o
29 29
30obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o 30obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o
31 31
32obj-$(CONFIG_PCI_IOV) += iov.o
33
32# 34#
33# Some architectures use the generic PCI setup functions 35# Some architectures use the generic PCI setup functions
34# 36#
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
new file mode 100644
index 000000000000..66cc414ed15f
--- /dev/null
+++ b/drivers/pci/iov.c
@@ -0,0 +1,182 @@
1/*
2 * drivers/pci/iov.c
3 *
4 * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
5 *
6 * PCI Express I/O Virtualization (IOV) support.
7 * Single Root IOV 1.0
8 */
9
10#include <linux/pci.h>
11#include <linux/mutex.h>
12#include <linux/string.h>
13#include <linux/delay.h>
14#include "pci.h"
15
16
17static int sriov_init(struct pci_dev *dev, int pos)
18{
19 int i;
20 int rc;
21 int nres;
22 u32 pgsz;
23 u16 ctrl, total, offset, stride;
24 struct pci_sriov *iov;
25 struct resource *res;
26 struct pci_dev *pdev;
27
28 if (dev->pcie_type != PCI_EXP_TYPE_RC_END &&
29 dev->pcie_type != PCI_EXP_TYPE_ENDPOINT)
30 return -ENODEV;
31
32 pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl);
33 if (ctrl & PCI_SRIOV_CTRL_VFE) {
34 pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, 0);
35 ssleep(1);
36 }
37
38 pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total);
39 if (!total)
40 return 0;
41
42 ctrl = 0;
43 list_for_each_entry(pdev, &dev->bus->devices, bus_list)
44 if (pdev->is_physfn)
45 goto found;
46
47 pdev = NULL;
48 if (pci_ari_enabled(dev->bus))
49 ctrl |= PCI_SRIOV_CTRL_ARI;
50
51found:
52 pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl);
53 pci_write_config_word(dev, pos + PCI_SRIOV_NUM_VF, total);
54 pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset);
55 pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride);
56 if (!offset || (total > 1 && !stride))
57 return -EIO;
58
59 pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &pgsz);
60 i = PAGE_SHIFT > 12 ? PAGE_SHIFT - 12 : 0;
61 pgsz &= ~((1 << i) - 1);
62 if (!pgsz)
63 return -EIO;
64
65 pgsz &= ~(pgsz - 1);
66 pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz);
67
68 nres = 0;
69 for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
70 res = dev->resource + PCI_IOV_RESOURCES + i;
71 i += __pci_read_base(dev, pci_bar_unknown, res,
72 pos + PCI_SRIOV_BAR + i * 4);
73 if (!res->flags)
74 continue;
75 if (resource_size(res) & (PAGE_SIZE - 1)) {
76 rc = -EIO;
77 goto failed;
78 }
79 res->end = res->start + resource_size(res) * total - 1;
80 nres++;
81 }
82
83 iov = kzalloc(sizeof(*iov), GFP_KERNEL);
84 if (!iov) {
85 rc = -ENOMEM;
86 goto failed;
87 }
88
89 iov->pos = pos;
90 iov->nres = nres;
91 iov->ctrl = ctrl;
92 iov->total = total;
93 iov->offset = offset;
94 iov->stride = stride;
95 iov->pgsz = pgsz;
96 iov->self = dev;
97 pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
98 pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
99
100 if (pdev)
101 iov->dev = pci_dev_get(pdev);
102 else {
103 iov->dev = dev;
104 mutex_init(&iov->lock);
105 }
106
107 dev->sriov = iov;
108 dev->is_physfn = 1;
109
110 return 0;
111
112failed:
113 for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
114 res = dev->resource + PCI_IOV_RESOURCES + i;
115 res->flags = 0;
116 }
117
118 return rc;
119}
120
121static void sriov_release(struct pci_dev *dev)
122{
123 if (dev == dev->sriov->dev)
124 mutex_destroy(&dev->sriov->lock);
125 else
126 pci_dev_put(dev->sriov->dev);
127
128 kfree(dev->sriov);
129 dev->sriov = NULL;
130}
131
132/**
133 * pci_iov_init - initialize the IOV capability
134 * @dev: the PCI device
135 *
136 * Returns 0 on success, or negative on failure.
137 */
138int pci_iov_init(struct pci_dev *dev)
139{
140 int pos;
141
142 if (!dev->is_pcie)
143 return -ENODEV;
144
145 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
146 if (pos)
147 return sriov_init(dev, pos);
148
149 return -ENODEV;
150}
151
152/**
153 * pci_iov_release - release resources used by the IOV capability
154 * @dev: the PCI device
155 */
156void pci_iov_release(struct pci_dev *dev)
157{
158 if (dev->is_physfn)
159 sriov_release(dev);
160}
161
162/**
163 * pci_iov_resource_bar - get position of the SR-IOV BAR
164 * @dev: the PCI device
165 * @resno: the resource number
166 * @type: the BAR type to be filled in
167 *
168 * Returns position of the BAR encapsulated in the SR-IOV capability.
169 */
170int pci_iov_resource_bar(struct pci_dev *dev, int resno,
171 enum pci_bar_type *type)
172{
173 if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END)
174 return 0;
175
176 BUG_ON(!dev->is_physfn);
177
178 *type = pci_bar_unknown;
179
180 return dev->sriov->pos + PCI_SRIOV_BAR +
181 4 * (resno - PCI_IOV_RESOURCES);
182}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a35a8b2ba631..2b3201ec2b05 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2360,12 +2360,19 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags)
2360 */ 2360 */
2361int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type) 2361int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
2362{ 2362{
2363 int reg;
2364
2363 if (resno < PCI_ROM_RESOURCE) { 2365 if (resno < PCI_ROM_RESOURCE) {
2364 *type = pci_bar_unknown; 2366 *type = pci_bar_unknown;
2365 return PCI_BASE_ADDRESS_0 + 4 * resno; 2367 return PCI_BASE_ADDRESS_0 + 4 * resno;
2366 } else if (resno == PCI_ROM_RESOURCE) { 2368 } else if (resno == PCI_ROM_RESOURCE) {
2367 *type = pci_bar_mem32; 2369 *type = pci_bar_mem32;
2368 return dev->rom_base_reg; 2370 return dev->rom_base_reg;
2371 } else if (resno < PCI_BRIDGE_RESOURCES) {
2372 /* device specific resource */
2373 reg = pci_iov_resource_bar(dev, resno, type);
2374 if (reg)
2375 return reg;
2369 } 2376 }
2370 2377
2371 dev_err(&dev->dev, "BAR: invalid resource #%d\n", resno); 2378 dev_err(&dev->dev, "BAR: invalid resource #%d\n", resno);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 2cd1cba7236f..7d5327c986f5 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -201,4 +201,41 @@ resource_size_t pci_specified_resource_alignment(struct pci_dev *dev);
201extern void pci_disable_bridge_window(struct pci_dev *dev); 201extern void pci_disable_bridge_window(struct pci_dev *dev);
202#endif 202#endif
203 203
204/* Single Root I/O Virtualization */
205struct pci_sriov {
206 int pos; /* capability position */
207 int nres; /* number of resources */
208 u32 cap; /* SR-IOV Capabilities */
209 u16 ctrl; /* SR-IOV Control */
210 u16 total; /* total VFs associated with the PF */
211 u16 offset; /* first VF Routing ID offset */
212 u16 stride; /* following VF stride */
213 u32 pgsz; /* page size for BAR alignment */
214 u8 link; /* Function Dependency Link */
215 struct pci_dev *dev; /* lowest numbered PF */
216 struct pci_dev *self; /* this PF */
217 struct mutex lock; /* lock for VF bus */
218};
219
220#ifdef CONFIG_PCI_IOV
221extern int pci_iov_init(struct pci_dev *dev);
222extern void pci_iov_release(struct pci_dev *dev);
223extern int pci_iov_resource_bar(struct pci_dev *dev, int resno,
224 enum pci_bar_type *type);
225#else
226static inline int pci_iov_init(struct pci_dev *dev)
227{
228 return -ENODEV;
229}
230static inline void pci_iov_release(struct pci_dev *dev)
231
232{
233}
234static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno,
235 enum pci_bar_type *type)
236{
237 return 0;
238}
239#endif /* CONFIG_PCI_IOV */
240
204#endif /* DRIVERS_PCI_H */ 241#endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 579a56c8181f..0471f6ea1466 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -785,6 +785,7 @@ static int pci_setup_device(struct pci_dev * dev)
785static void pci_release_capabilities(struct pci_dev *dev) 785static void pci_release_capabilities(struct pci_dev *dev)
786{ 786{
787 pci_vpd_release(dev); 787 pci_vpd_release(dev);
788 pci_iov_release(dev);
788} 789}
789 790
790/** 791/**
@@ -979,6 +980,9 @@ static void pci_init_capabilities(struct pci_dev *dev)
979 980
980 /* Alternative Routing-ID Forwarding */ 981 /* Alternative Routing-ID Forwarding */
981 pci_enable_ari(dev); 982 pci_enable_ari(dev);
983
984 /* Single Root I/O Virtualization */
985 pci_iov_init(dev);
982} 986}
983 987
984void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) 988void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1f6c5ddaae36..8ce2f2d9ab63 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -93,6 +93,12 @@ enum {
93 /* #6: expansion ROM resource */ 93 /* #6: expansion ROM resource */
94 PCI_ROM_RESOURCE, 94 PCI_ROM_RESOURCE,
95 95
96 /* device specific resources */
97#ifdef CONFIG_PCI_IOV
98 PCI_IOV_RESOURCES,
99 PCI_IOV_RESOURCE_END = PCI_IOV_RESOURCES + PCI_SRIOV_NUM_BARS - 1,
100#endif
101
96 /* resources assigned to buses behind the bridge */ 102 /* resources assigned to buses behind the bridge */
97#define PCI_BRIDGE_RESOURCE_NUM 4 103#define PCI_BRIDGE_RESOURCE_NUM 4
98 104
@@ -180,6 +186,7 @@ struct pci_cap_saved_state {
180 186
181struct pcie_link_state; 187struct pcie_link_state;
182struct pci_vpd; 188struct pci_vpd;
189struct pci_sriov;
183 190
184/* 191/*
185 * The pci_dev structure is used to describe PCI devices. 192 * The pci_dev structure is used to describe PCI devices.
@@ -257,6 +264,7 @@ struct pci_dev {
257 unsigned int is_managed:1; 264 unsigned int is_managed:1;
258 unsigned int is_pcie:1; 265 unsigned int is_pcie:1;
259 unsigned int state_saved:1; 266 unsigned int state_saved:1;
267 unsigned int is_physfn:1;
260 pci_dev_flags_t dev_flags; 268 pci_dev_flags_t dev_flags;
261 atomic_t enable_cnt; /* pci_enable_device has been called */ 269 atomic_t enable_cnt; /* pci_enable_device has been called */
262 270
@@ -270,6 +278,9 @@ struct pci_dev {
270 struct list_head msi_list; 278 struct list_head msi_list;
271#endif 279#endif
272 struct pci_vpd *vpd; 280 struct pci_vpd *vpd;
281#ifdef CONFIG_PCI_IOV
282 struct pci_sriov *sriov; /* SR-IOV capability related */
283#endif
273}; 284};
274 285
275extern struct pci_dev *alloc_pci_dev(void); 286extern struct pci_dev *alloc_pci_dev(void);
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index b647a4df59fc..d4e663877f45 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -375,6 +375,7 @@
375#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ 375#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */
376#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ 376#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */
377#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */ 377#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */
378#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */
378#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ 379#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */
379#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ 380#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */
380#define PCI_EXP_DEVCAP 4 /* Device capabilities */ 381#define PCI_EXP_DEVCAP 4 /* Device capabilities */
@@ -498,6 +499,7 @@
498#define PCI_EXT_CAP_ID_DSN 3 499#define PCI_EXT_CAP_ID_DSN 3
499#define PCI_EXT_CAP_ID_PWR 4 500#define PCI_EXT_CAP_ID_PWR 4
500#define PCI_EXT_CAP_ID_ARI 14 501#define PCI_EXT_CAP_ID_ARI 14
502#define PCI_EXT_CAP_ID_SRIOV 16
501 503
502/* Advanced Error Reporting */ 504/* Advanced Error Reporting */
503#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ 505#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */
@@ -615,4 +617,35 @@
615#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */ 617#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */
616#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */ 618#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */
617 619
620/* Single Root I/O Virtualization */
621#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */
622#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */
623#define PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */
624#define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */
625#define PCI_SRIOV_CTRL_VFE 0x01 /* VF Enable */
626#define PCI_SRIOV_CTRL_VFM 0x02 /* VF Migration Enable */
627#define PCI_SRIOV_CTRL_INTR 0x04 /* VF Migration Interrupt Enable */
628#define PCI_SRIOV_CTRL_MSE 0x08 /* VF Memory Space Enable */
629#define PCI_SRIOV_CTRL_ARI 0x10 /* ARI Capable Hierarchy */
630#define PCI_SRIOV_STATUS 0x0a /* SR-IOV Status */
631#define PCI_SRIOV_STATUS_VFM 0x01 /* VF Migration Status */
632#define PCI_SRIOV_INITIAL_VF 0x0c /* Initial VFs */
633#define PCI_SRIOV_TOTAL_VF 0x0e /* Total VFs */
634#define PCI_SRIOV_NUM_VF 0x10 /* Number of VFs */
635#define PCI_SRIOV_FUNC_LINK 0x12 /* Function Dependency Link */
636#define PCI_SRIOV_VF_OFFSET 0x14 /* First VF Offset */
637#define PCI_SRIOV_VF_STRIDE 0x16 /* Following VF Stride */
638#define PCI_SRIOV_VF_DID 0x1a /* VF Device ID */
639#define PCI_SRIOV_SUP_PGSIZE 0x1c /* Supported Page Sizes */
640#define PCI_SRIOV_SYS_PGSIZE 0x20 /* System Page Size */
641#define PCI_SRIOV_BAR 0x24 /* VF BAR0 */
642#define PCI_SRIOV_NUM_BARS 6 /* Number of VF BARs */
643#define PCI_SRIOV_VFM 0x3c /* VF Migration State Array Offset*/
644#define PCI_SRIOV_VFM_BIR(x) ((x) & 7) /* State BIR */
645#define PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7) /* State Offset */
646#define PCI_SRIOV_VFM_UA 0x0 /* Inactive.Unavailable */
647#define PCI_SRIOV_VFM_MI 0x1 /* Dormant.MigrateIn */
648#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */
649#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */
650
618#endif /* LINUX_PCI_REGS_H */ 651#endif /* LINUX_PCI_REGS_H */