PCI: restore saved SR-IOV state
[linux-2.6] / drivers / pci / iov.c
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
17 static 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
51 found:
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
112 failed:
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
121 static 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 static void sriov_restore_state(struct pci_dev *dev)
133 {
134         int i;
135         u16 ctrl;
136         struct pci_sriov *iov = dev->sriov;
137
138         pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &ctrl);
139         if (ctrl & PCI_SRIOV_CTRL_VFE)
140                 return;
141
142         for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++)
143                 pci_update_resource(dev, i);
144
145         pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz);
146         pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
147         if (iov->ctrl & PCI_SRIOV_CTRL_VFE)
148                 msleep(100);
149 }
150
151 /**
152  * pci_iov_init - initialize the IOV capability
153  * @dev: the PCI device
154  *
155  * Returns 0 on success, or negative on failure.
156  */
157 int pci_iov_init(struct pci_dev *dev)
158 {
159         int pos;
160
161         if (!dev->is_pcie)
162                 return -ENODEV;
163
164         pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
165         if (pos)
166                 return sriov_init(dev, pos);
167
168         return -ENODEV;
169 }
170
171 /**
172  * pci_iov_release - release resources used by the IOV capability
173  * @dev: the PCI device
174  */
175 void pci_iov_release(struct pci_dev *dev)
176 {
177         if (dev->is_physfn)
178                 sriov_release(dev);
179 }
180
181 /**
182  * pci_iov_resource_bar - get position of the SR-IOV BAR
183  * @dev: the PCI device
184  * @resno: the resource number
185  * @type: the BAR type to be filled in
186  *
187  * Returns position of the BAR encapsulated in the SR-IOV capability.
188  */
189 int pci_iov_resource_bar(struct pci_dev *dev, int resno,
190                          enum pci_bar_type *type)
191 {
192         if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END)
193                 return 0;
194
195         BUG_ON(!dev->is_physfn);
196
197         *type = pci_bar_unknown;
198
199         return dev->sriov->pos + PCI_SRIOV_BAR +
200                 4 * (resno - PCI_IOV_RESOURCES);
201 }
202
203 /**
204  * pci_restore_iov_state - restore the state of the IOV capability
205  * @dev: the PCI device
206  */
207 void pci_restore_iov_state(struct pci_dev *dev)
208 {
209         if (dev->is_physfn)
210                 sriov_restore_state(dev);
211 }