4 * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
6 * PCI Express I/O Virtualization (IOV) support.
10 #include <linux/pci.h>
11 #include <linux/mutex.h>
12 #include <linux/string.h>
13 #include <linux/delay.h>
17 static int sriov_init(struct pci_dev *dev, int pos)
23 u16 ctrl, total, offset, stride;
24 struct pci_sriov *iov;
28 if (dev->pcie_type != PCI_EXP_TYPE_RC_END &&
29 dev->pcie_type != PCI_EXP_TYPE_ENDPOINT)
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);
38 pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total);
43 list_for_each_entry(pdev, &dev->bus->devices, bus_list)
48 if (pci_ari_enabled(dev->bus))
49 ctrl |= PCI_SRIOV_CTRL_ARI;
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))
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);
66 pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz);
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);
75 if (resource_size(res) & (PAGE_SIZE - 1)) {
79 res->end = res->start + resource_size(res) * total - 1;
83 iov = kzalloc(sizeof(*iov), GFP_KERNEL);
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);
101 iov->dev = pci_dev_get(pdev);
104 mutex_init(&iov->lock);
113 for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
114 res = dev->resource + PCI_IOV_RESOURCES + i;
121 static void sriov_release(struct pci_dev *dev)
123 if (dev == dev->sriov->dev)
124 mutex_destroy(&dev->sriov->lock);
126 pci_dev_put(dev->sriov->dev);
133 * pci_iov_init - initialize the IOV capability
134 * @dev: the PCI device
136 * Returns 0 on success, or negative on failure.
138 int pci_iov_init(struct pci_dev *dev)
145 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
147 return sriov_init(dev, pos);
153 * pci_iov_release - release resources used by the IOV capability
154 * @dev: the PCI device
156 void pci_iov_release(struct pci_dev *dev)
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
168 * Returns position of the BAR encapsulated in the SR-IOV capability.
170 int pci_iov_resource_bar(struct pci_dev *dev, int resno,
171 enum pci_bar_type *type)
173 if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END)
176 BUG_ON(!dev->is_physfn);
178 *type = pci_bar_unknown;
180 return dev->sriov->pos + PCI_SRIOV_BAR +
181 4 * (resno - PCI_IOV_RESOURCES);