1
Hi,
1
Hi,
2
2
3
Resurrecting an old series [1], now that we have an in-tree user for it.
3
Another revision after the feedback from Ilpo.
4
Few tweaks here and there, the biggest change is the removal of the
5
loop in pci_iov_vf_bar_get_sizes().
6
7
v6 can be found here:
8
https://lore.kernel.org/linux-pci/20250320110854.3866284-1-michal.winiarski@intel.com/
4
9
5
For regular BAR, drivers can use pci_resize_resource to resize it to the
10
For regular BAR, drivers can use pci_resize_resource to resize it to the
6
desired size provided that it is supported by the hardware, which the
11
desired size provided that it is supported by the hardware, which the
7
driver can query using pci_rebar_get_possible_sizes.
12
driver can query using pci_rebar_get_possible_sizes.
8
This series expands the API to work with IOV BAR as well.
13
This series expands the API to work with IOV BAR as well.
9
It also adds the additional API to allow extending the VF BAR within the
14
It also adds the additional API for drivers to change the VF BAR size
10
original resource boundary.
15
without resizing the entire underlying reservation (within the original
16
resource boundary).
11
17
12
Thanks,
18
Thanks,
13
-Michał
19
-Michał
14
20
15
[1] https://lore.kernel.org/all/20211215141626.3090807-1-michal.winiarski@intel.com/
21
v6 -> v7:
22
- Eliminate the loop in pci_iov_vf_bar_get_sizes() (Ilpo)
23
- Use helper variable for indexes (Ilpo)
24
- Kerneldoc formatting (Ilpo)
25
- Refer to latest PCI spec (Ilpo)
26
- Commit message wording (Ilpo)
16
27
17
v1 -> v2:
28
v5 -> v6:
18
- Add pci_iov_resource_extend() and usage in Xe driver
29
- Rebased on latest pci/next
19
- Reduce the number of ifdefs (Christian)
30
- Cache the VF resizable BAR capability position to avoid multiple
20
- Drop patch 2/2 from v1 (Christian)
31
lookups (Ilpo)
21
- Add a helper to avoid upsetting static analysis tools (Krzysztof)
32
- Use pci_resource_n helper (Ilpo)
33
34
v4 -> v5:
35
- Rename pci_resource_to/from_iov helpers and add WARN if called without
36
CONFIG_PCI_IOV (Ilpo)
37
- Reword kerneldoc for pci_iov_vf_bar_get_sizes (Bjorn)
38
- Reword commit message for VF BAR size check, extract the additional
39
size check to separate conditional (Bjorn)
40
41
v3 -> v4:
42
- Change the approach to extending the BAR (Christian)
43
- Tidy the commit messages, use 80 line limit where necessary (Bjorn)
44
- Add kerneldocs to exported functions (Bjorn)
45
- Add pci_resource_to_iov() / pci_resource_from_iov() helpers (Ilpo)
46
- Use FIELD_GET(), tidy whitespace (Ilpo)
22
47
23
v2 -> v3:
48
v2 -> v3:
24
- Extract introducing pci_resource_is_iov to separate commit and
49
- Extract introducing pci_resource_is_iov to separate commit and
25
use it elsewhere in PCI subsystem (Christian)
50
use it elsewhere in PCI subsystem (Christian)
26
- Extract restoring VF rebar state to separate commit (Christian)
51
- Extract restoring VF rebar state to separate commit (Christian)
27
- Reorganize memory decoding check (Christian)
52
- Reorganize memory decoding check (Christian)
28
- Don't use dev_WARN (Ilpo)
53
- Don't use dev_WARN (Ilpo)
29
- Fix build without CONFIG_PCI_IOV (CI)
54
- Fix build without CONFIG_PCI_IOV (CI)
30
55
31
Michał Winiarski (5):
56
v1 -> v2:
57
- Add pci_iov_resource_extend() and usage in Xe driver
58
- Reduce the number of ifdefs (Christian)
59
- Drop patch 2/2 from v1 (Christian)
60
- Add a helper to avoid upsetting static analysis tools (Krzysztof)
61
62
Michał Winiarski (6):
32
PCI/IOV: Restore VF resizable BAR state after reset
63
PCI/IOV: Restore VF resizable BAR state after reset
33
PCI: Add a helper to identify IOV resources
64
PCI: Add a helper to convert between VF BAR number and IOV resource
34
PCI: Allow IOV resources to be resized in pci_resize_resource
65
PCI: Allow IOV resources to be resized in pci_resize_resource()
35
PCI/IOV: Allow extending VF BAR within original resource boundary
66
PCI/IOV: Check that VF BAR fits within the reservation
36
drm/xe/pf: Extend the VF LMEM BAR
67
PCI: Allow drivers to control VF BAR size
68
drm/xe/pf: Set VF LMEM BAR size
37
69
38
drivers/gpu/drm/xe/regs/xe_bars.h | 1 +
70
drivers/gpu/drm/xe/regs/xe_bars.h | 1 +
39
drivers/gpu/drm/xe/xe_sriov_pf.c | 8 ++
71
drivers/gpu/drm/xe/xe_pci_sriov.c | 22 +++++
40
drivers/pci/iov.c | 141 +++++++++++++++++++++++++++++-
72
drivers/pci/iov.c | 149 +++++++++++++++++++++++++++---
41
drivers/pci/pci.c | 9 +-
73
drivers/pci/pci.c | 10 +-
42
drivers/pci/pci.h | 27 +++++-
74
drivers/pci/pci.h | 29 ++++++
43
drivers/pci/setup-bus.c | 5 +-
75
drivers/pci/setup-bus.c | 3 +-
44
drivers/pci/setup-res.c | 37 ++++++--
76
drivers/pci/setup-res.c | 35 ++++++-
45
include/linux/pci.h | 3 +
77
include/linux/pci.h | 6 ++
46
include/uapi/linux/pci_regs.h | 1 +
78
include/uapi/linux/pci_regs.h | 9 ++
47
9 files changed, 213 insertions(+), 19 deletions(-)
79
9 files changed, 246 insertions(+), 18 deletions(-)
48
80
49
--
81
--
50
2.47.0
82
2.49.0
51
83
diff view generated by jsdifflib
1
Similar to regular resizable BAR, VF BAR can also be resized, e.g. by
1
Similar to regular resizable BAR, VF BAR can also be resized, e.g. by
2
the system firmware, or the PCI subsystem itself.
2
the system firmware or the PCI subsystem itself.
3
4
The capability layout is the same as PCI_EXT_CAP_ID_REBAR.
5
3
Add the capability ID and restore it as a part of IOV state.
6
Add the capability ID and restore it as a part of IOV state.
4
See PCIe r4.0, sec 9.3.7.4.
7
8
See PCIe r6.2, sec 7.8.7.
5
9
6
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
10
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
11
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
12
Reviewed-by: Christian König <christian.koenig@amd.com>
7
---
13
---
8
drivers/pci/iov.c | 29 ++++++++++++++++++++++++++++-
14
drivers/pci/iov.c | 30 +++++++++++++++++++++++++++++-
9
include/uapi/linux/pci_regs.h | 1 +
15
drivers/pci/pci.h | 1 +
10
2 files changed, 29 insertions(+), 1 deletion(-)
16
include/uapi/linux/pci_regs.h | 9 +++++++++
17
3 files changed, 39 insertions(+), 1 deletion(-)
11
18
12
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
19
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
13
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
14
--- a/drivers/pci/iov.c
21
--- a/drivers/pci/iov.c
15
+++ b/drivers/pci/iov.c
22
+++ b/drivers/pci/iov.c
...
...
19
26
20
+#include <linux/bitfield.h>
27
+#include <linux/bitfield.h>
21
#include <linux/pci.h>
28
#include <linux/pci.h>
22
#include <linux/slab.h>
29
#include <linux/slab.h>
23
#include <linux/export.h>
30
#include <linux/export.h>
31
@@ -XXX,XX +XXX,XX @@ static int sriov_init(struct pci_dev *dev, int pos)
32
    pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
33
    if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END)
34
        iov->link = PCI_DEVFN(PCI_SLOT(dev->devfn), iov->link);
35
+    iov->vf_rebar_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VF_REBAR);
36
37
    if (pdev)
38
        iov->dev = pci_dev_get(pdev);
24
@@ -XXX,XX +XXX,XX @@ static void sriov_release(struct pci_dev *dev)
39
@@ -XXX,XX +XXX,XX @@ static void sriov_release(struct pci_dev *dev)
25
    dev->sriov = NULL;
40
    dev->sriov = NULL;
26
}
41
}
27
42
28
+static void sriov_restore_vf_rebar_state(struct pci_dev *dev)
43
+static void sriov_restore_vf_rebar_state(struct pci_dev *dev)
29
+{
44
+{
30
+    unsigned int pos, nbars, i;
45
+    unsigned int pos, nbars, i;
31
+    u32 ctrl;
46
+    u32 ctrl;
32
+
47
+
33
+    pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VF_REBAR);
48
+    pos = dev->sriov->vf_rebar_cap;
34
+    if (!pos)
49
+    if (!pos)
35
+        return;
50
+        return;
36
+
51
+
37
+    pci_read_config_dword(dev, pos + PCI_REBAR_CTRL, &ctrl);
52
+    pci_read_config_dword(dev, pos + PCI_VF_REBAR_CTRL, &ctrl);
38
+    nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, ctrl);
53
+    nbars = FIELD_GET(PCI_VF_REBAR_CTRL_NBAR_MASK, ctrl);
39
+
54
+
40
+    for (i = 0; i < nbars; i++, pos += 8) {
55
+    for (i = 0; i < nbars; i++, pos += 8) {
41
+        int bar_idx, size;
56
+        int bar_idx, size;
42
+
57
+
43
+        pci_read_config_dword(dev, pos + PCI_REBAR_CTRL, &ctrl);
58
+        pci_read_config_dword(dev, pos + PCI_VF_REBAR_CTRL, &ctrl);
44
+        bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX;
59
+        bar_idx = FIELD_GET(PCI_VF_REBAR_CTRL_BAR_IDX, ctrl);
45
+        size = pci_rebar_bytes_to_size(dev->sriov->barsz[bar_idx]);
60
+        size = pci_rebar_bytes_to_size(dev->sriov->barsz[bar_idx]);
46
+        ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
61
+        ctrl &= ~PCI_VF_REBAR_CTRL_BAR_SIZE;
47
+        ctrl |= FIELD_PREP(PCI_REBAR_CTRL_BAR_SIZE, size);
62
+        ctrl |= FIELD_PREP(PCI_VF_REBAR_CTRL_BAR_SIZE, size);
48
+        pci_write_config_dword(dev, pos + PCI_REBAR_CTRL, ctrl);
63
+        pci_write_config_dword(dev, pos + PCI_VF_REBAR_CTRL, ctrl);
49
+    }
64
+    }
50
+}
65
+}
51
+
66
+
52
static void sriov_restore_state(struct pci_dev *dev)
67
static void sriov_restore_state(struct pci_dev *dev)
53
{
68
{
...
...
62
        sriov_restore_state(dev);
77
        sriov_restore_state(dev);
63
+    }
78
+    }
64
}
79
}
65
80
66
/**
81
/**
82
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
83
index XXXXXXX..XXXXXXX 100644
84
--- a/drivers/pci/pci.h
85
+++ b/drivers/pci/pci.h
86
@@ -XXX,XX +XXX,XX @@ struct pci_sriov {
87
    u16        subsystem_vendor; /* VF subsystem vendor */
88
    u16        subsystem_device; /* VF subsystem device */
89
    resource_size_t    barsz[PCI_SRIOV_NUM_BARS];    /* VF BAR size */
90
+    u16        vf_rebar_cap;    /* VF Resizable BAR capability offset */
91
    bool        drivers_autoprobe; /* Auto probing of VFs by driver */
92
};
93
67
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
94
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
68
index XXXXXXX..XXXXXXX 100644
95
index XXXXXXX..XXXXXXX 100644
69
--- a/include/uapi/linux/pci_regs.h
96
--- a/include/uapi/linux/pci_regs.h
70
+++ b/include/uapi/linux/pci_regs.h
97
+++ b/include/uapi/linux/pci_regs.h
71
@@ -XXX,XX +XXX,XX @@
98
@@ -XXX,XX +XXX,XX @@
...
...
74
#define PCI_EXT_CAP_ID_DVSEC    0x23    /* Designated Vendor-Specific */
101
#define PCI_EXT_CAP_ID_DVSEC    0x23    /* Designated Vendor-Specific */
75
+#define PCI_EXT_CAP_ID_VF_REBAR 0x24    /* VF Resizable BAR */
102
+#define PCI_EXT_CAP_ID_VF_REBAR 0x24    /* VF Resizable BAR */
76
#define PCI_EXT_CAP_ID_DLF    0x25    /* Data Link Feature */
103
#define PCI_EXT_CAP_ID_DLF    0x25    /* Data Link Feature */
77
#define PCI_EXT_CAP_ID_PL_16GT    0x26    /* Physical Layer 16.0 GT/s */
104
#define PCI_EXT_CAP_ID_PL_16GT    0x26    /* Physical Layer 16.0 GT/s */
78
#define PCI_EXT_CAP_ID_NPEM    0x29    /* Native PCIe Enclosure Management */
105
#define PCI_EXT_CAP_ID_NPEM    0x29    /* Native PCIe Enclosure Management */
106
@@ -XXX,XX +XXX,XX @@
107
#define PCI_DVSEC_HEADER2        0x8 /* Designated Vendor-Specific Header2 */
108
#define PCI_DVSEC_HEADER2_ID(x)        ((x) & 0xffff)
109
110
+/* VF Resizable BARs, same layout as PCI_REBAR */
111
+#define PCI_VF_REBAR_CAP    PCI_REBAR_CAP
112
+#define PCI_VF_REBAR_CAP_SIZES        PCI_REBAR_CAP_SIZES
113
+#define PCI_VF_REBAR_CTRL    PCI_REBAR_CTRL
114
+#define PCI_VF_REBAR_CTRL_BAR_IDX    PCI_REBAR_CTRL_BAR_IDX
115
+#define PCI_VF_REBAR_CTRL_NBAR_MASK    PCI_REBAR_CTRL_NBAR_MASK
116
+#define PCI_VF_REBAR_CTRL_BAR_SIZE    PCI_REBAR_CTRL_BAR_SIZE
117
+
118
/* Data Link Feature */
119
#define PCI_DLF_CAP        0x04    /* Capabilities Register */
120
#define PCI_DLF_EXCHANGE_ENABLE    0x80000000 /* Data Link Feature Exchange Enable */
79
--
121
--
80
2.47.0
122
2.49.0
81
123
diff view generated by jsdifflib
1
There are multiple places where special handling is required for IOV
1
There are multiple places where conversions between IOV resources and
2
resources.
2
corresponding VF BAR numbers are done.
3
Extract it to a helper and drop a few ifdefs.
4
3
4
Extract the logic to pci_resource_num_from_vf_bar() and
5
pci_resource_num_to_vf_bar() helpers.
6
7
Suggested-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
5
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
8
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
9
Acked-by: Christian König <christian.koenig@amd.com>
6
---
10
---
7
drivers/pci/pci.h | 18 ++++++++++++++----
11
drivers/pci/iov.c | 26 ++++++++++++++++----------
8
drivers/pci/setup-bus.c | 5 +----
12
drivers/pci/pci.h | 19 +++++++++++++++++++
9
drivers/pci/setup-res.c | 4 +---
13
drivers/pci/setup-bus.c | 3 ++-
10
3 files changed, 16 insertions(+), 11 deletions(-)
14
3 files changed, 37 insertions(+), 11 deletions(-)
11
15
16
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/drivers/pci/iov.c
19
+++ b/drivers/pci/iov.c
20
@@ -XXX,XX +XXX,XX @@ resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
21
    if (!dev->is_physfn)
22
        return 0;
23
24
-    return dev->sriov->barsz[resno - PCI_IOV_RESOURCES];
25
+    return dev->sriov->barsz[pci_resource_num_to_vf_bar(resno)];
26
}
27
28
static void pci_read_vf_config_common(struct pci_dev *virtfn)
29
@@ -XXX,XX +XXX,XX @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)
30
    virtfn->multifunction = 0;
31
32
    for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
33
-        res = &dev->resource[i + PCI_IOV_RESOURCES];
34
+        int idx = pci_resource_num_from_vf_bar(i);
35
+
36
+        res = &dev->resource[idx];
37
        if (!res->parent)
38
            continue;
39
        virtfn->resource[i].name = pci_name(virtfn);
40
        virtfn->resource[i].flags = res->flags;
41
-        size = pci_iov_resource_size(dev, i + PCI_IOV_RESOURCES);
42
+        size = pci_iov_resource_size(dev, idx);
43
        resource_set_range(&virtfn->resource[i],
44
                 res->start + size * id, size);
45
        rc = request_resource(res, &virtfn->resource[i]);
46
@@ -XXX,XX +XXX,XX @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
47
48
    nres = 0;
49
    for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
50
-        bars |= (1 << (i + PCI_IOV_RESOURCES));
51
-        res = &dev->resource[i + PCI_IOV_RESOURCES];
52
+        int idx = pci_resource_num_from_vf_bar(i);
53
+
54
+        bars |= (1 << idx);
55
+        res = &dev->resource[idx];
56
        if (res->parent)
57
            nres++;
58
    }
59
@@ -XXX,XX +XXX,XX @@ static int sriov_init(struct pci_dev *dev, int pos)
60
61
    nres = 0;
62
    for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
63
-        res = &dev->resource[i + PCI_IOV_RESOURCES];
64
-        res_name = pci_resource_name(dev, i + PCI_IOV_RESOURCES);
65
+        int idx = pci_resource_num_from_vf_bar(i);
66
+
67
+        res = &dev->resource[idx];
68
+        res_name = pci_resource_name(dev, idx);
69
70
        /*
71
         * If it is already FIXED, don't change it, something
72
@@ -XXX,XX +XXX,XX @@ static int sriov_init(struct pci_dev *dev, int pos)
73
    dev->is_physfn = 0;
74
failed:
75
    for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
76
-        res = &dev->resource[i + PCI_IOV_RESOURCES];
77
+        res = &dev->resource[pci_resource_num_from_vf_bar(i)];
78
        res->flags = 0;
79
    }
80
81
@@ -XXX,XX +XXX,XX @@ static void sriov_restore_state(struct pci_dev *dev)
82
    pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, ctrl);
83
84
    for (i = 0; i < PCI_SRIOV_NUM_BARS; i++)
85
-        pci_update_resource(dev, i + PCI_IOV_RESOURCES);
86
+        pci_update_resource(dev, pci_resource_num_from_vf_bar(i));
87
88
    pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz);
89
    pci_iov_set_numvfs(dev, iov->num_VFs);
90
@@ -XXX,XX +XXX,XX @@ void pci_iov_update_resource(struct pci_dev *dev, int resno)
91
{
92
    struct pci_sriov *iov = dev->is_physfn ? dev->sriov : NULL;
93
    struct resource *res = pci_resource_n(dev, resno);
94
-    int vf_bar = resno - PCI_IOV_RESOURCES;
95
+    int vf_bar = pci_resource_num_to_vf_bar(resno);
96
    struct pci_bus_region region;
97
    u16 cmd;
98
    u32 new;
12
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
99
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
13
index XXXXXXX..XXXXXXX 100644
100
index XXXXXXX..XXXXXXX 100644
14
--- a/drivers/pci/pci.h
101
--- a/drivers/pci/pci.h
15
+++ b/drivers/pci/pci.h
102
+++ b/drivers/pci/pci.h
16
@@ -XXX,XX +XXX,XX @@ void pci_iov_update_resource(struct pci_dev *dev, int resno);
103
@@ -XXX,XX +XXX,XX @@ static inline bool pci_resource_is_iov(int resno)
17
resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
104
{
18
void pci_restore_iov_state(struct pci_dev *dev);
105
    return resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END;
19
int pci_iov_bus_range(struct pci_bus *bus);
106
}
20
+static inline bool pci_resource_is_iov(int resno)
107
+static inline int pci_resource_num_from_vf_bar(int resno)
21
+{
108
+{
22
+    return resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END;
109
+    return resno + PCI_IOV_RESOURCES;
110
+}
111
+
112
+static inline int pci_resource_num_to_vf_bar(int resno)
113
+{
114
+    return resno - PCI_IOV_RESOURCES;
23
+}
115
+}
24
extern const struct attribute_group sriov_pf_dev_attr_group;
116
extern const struct attribute_group sriov_pf_dev_attr_group;
25
extern const struct attribute_group sriov_vf_dev_attr_group;
117
extern const struct attribute_group sriov_vf_dev_attr_group;
26
#else
118
#else
27
@@ -XXX,XX +XXX,XX @@ static inline int pci_iov_init(struct pci_dev *dev)
119
@@ -XXX,XX +XXX,XX @@ static inline bool pci_resource_is_iov(int resno)
120
{
121
    return false;
28
}
122
}
29
static inline void pci_iov_release(struct pci_dev *dev) { }
123
+static inline int pci_resource_num_from_vf_bar(int resno)
30
static inline void pci_iov_remove(struct pci_dev *dev) { }
31
+static inline void pci_iov_update_resource(struct pci_dev *dev, int resno) { }
32
+static inline resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno)
33
+{
124
+{
34
+    return 0;
125
+    WARN_ON_ONCE(1);
126
+    return -ENODEV;
35
+}
127
+}
36
static inline void pci_restore_iov_state(struct pci_dev *dev) { }
128
+static inline int pci_resource_num_to_vf_bar(int resno)
37
static inline int pci_iov_bus_range(struct pci_bus *bus)
38
{
39
    return 0;
40
}
41
-
42
+static inline bool pci_resource_is_iov(int resno)
43
+{
129
+{
44
+    return false;
130
+    WARN_ON_ONCE(1);
131
+    return -ENODEV;
45
+}
132
+}
46
#endif /* CONFIG_PCI_IOV */
133
#endif /* CONFIG_PCI_IOV */
47
134
48
#ifdef CONFIG_PCIE_PTM
135
#ifdef CONFIG_PCIE_TPH
49
@@ -XXX,XX +XXX,XX @@ unsigned long pci_cardbus_resource_alignment(struct resource *);
50
static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
51
                         struct resource *res)
52
{
53
-#ifdef CONFIG_PCI_IOV
54
    int resno = res - dev->resource;
55
56
-    if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END)
57
+    if (pci_resource_is_iov(resno))
58
        return pci_sriov_resource_alignment(dev, resno);
59
-#endif
60
    if (dev->class >> 8 == PCI_CLASS_BRIDGE_CARDBUS)
61
        return pci_cardbus_resource_alignment(res);
62
    return resource_alignment(res);
63
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
136
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
64
index XXXXXXX..XXXXXXX 100644
137
index XXXXXXX..XXXXXXX 100644
65
--- a/drivers/pci/setup-bus.c
138
--- a/drivers/pci/setup-bus.c
66
+++ b/drivers/pci/setup-bus.c
139
+++ b/drivers/pci/setup-bus.c
67
@@ -XXX,XX +XXX,XX @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
140
@@ -XXX,XX +XXX,XX @@ static int iov_resources_unassigned(struct pci_dev *dev, void *data)
68
             (r->flags & mask) != type3))
141
    bool *unassigned = data;
69
                continue;
142
70
            r_size = resource_size(r);
143
    for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
71
-#ifdef CONFIG_PCI_IOV
144
-        struct resource *r = &dev->resource[i + PCI_IOV_RESOURCES];
72
            /* Put SRIOV requested res to the optional list */
145
+        int idx = pci_resource_num_from_vf_bar(i);
73
-            if (realloc_head && i >= PCI_IOV_RESOURCES &&
146
+        struct resource *r = &dev->resource[idx];
74
-                    i <= PCI_IOV_RESOURCE_END) {
147
        struct pci_bus_region region;
75
+            if (realloc_head && pci_resource_is_iov(i)) {
148
76
                add_align = max(pci_resource_alignment(dev, r), add_align);
149
        /* Not assigned or rejected by kernel? */
77
                r->end = r->start - 1;
78
                add_to_list(realloc_head, dev, r, r_size, 0 /* Don't care */);
79
                children_add_size += r_size;
80
                continue;
81
            }
82
-#endif
83
            /*
84
             * aligns[0] is for 1MB (since bridge memory
85
             * windows are always at least 1MB aligned), so
86
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/drivers/pci/setup-res.c
89
+++ b/drivers/pci/setup-res.c
90
@@ -XXX,XX +XXX,XX @@ void pci_update_resource(struct pci_dev *dev, int resno)
91
{
92
    if (resno <= PCI_ROM_RESOURCE)
93
        pci_std_update_resource(dev, resno);
94
-#ifdef CONFIG_PCI_IOV
95
-    else if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END)
96
+    else if (pci_resource_is_iov(resno))
97
        pci_iov_update_resource(dev, resno);
98
-#endif
99
}
100
101
int pci_claim_resource(struct pci_dev *dev, int resource)
102
--
150
--
103
2.47.0
151
2.49.0
104
152
diff view generated by jsdifflib
1
Similar to regular resizable BAR, VF BAR can also be resized.
1
Similar to regular resizable BAR, VF BAR can also be resized.
2
The structures are very similar, which means we can reuse most of the
2
3
implementation. See PCIe r4.0, sec 9.3.7.4.
3
The capability layout is the same as PCI_EXT_CAP_ID_REBAR, which means
4
we can reuse most of the implementation, the only difference being
5
resource size calculation (which is multiplied by total VFs) and memory
6
decoding (which is controlled by a separate VF MSE field in SR-IOV cap).
7
8
Extend the pci_resize_resource() function to accept IOV resources.
9
10
See PCIe r6.2, sec 7.8.7.
4
11
5
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
12
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
6
---
13
---
7
drivers/pci/iov.c | 20 ++++++++++++++++++++
14
drivers/pci/iov.c | 21 +++++++++++++++++++++
8
drivers/pci/pci.c | 9 ++++++++-
15
drivers/pci/pci.c | 10 +++++++++-
9
drivers/pci/pci.h | 8 ++++++++
16
drivers/pci/pci.h | 9 +++++++++
10
drivers/pci/setup-res.c | 33 ++++++++++++++++++++++++++++-----
17
drivers/pci/setup-res.c | 35 ++++++++++++++++++++++++++++++-----
11
4 files changed, 64 insertions(+), 6 deletions(-)
18
4 files changed, 69 insertions(+), 6 deletions(-)
12
19
13
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
20
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
14
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
15
--- a/drivers/pci/iov.c
22
--- a/drivers/pci/iov.c
16
+++ b/drivers/pci/iov.c
23
+++ b/drivers/pci/iov.c
17
@@ -XXX,XX +XXX,XX @@ resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
24
@@ -XXX,XX +XXX,XX @@ resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
18
    return dev->sriov->barsz[resno - PCI_IOV_RESOURCES];
25
    return dev->sriov->barsz[pci_resource_num_to_vf_bar(resno)];
19
}
26
}
20
27
21
+void pci_iov_resource_set_size(struct pci_dev *dev, int resno, resource_size_t size)
28
+void pci_iov_resource_set_size(struct pci_dev *dev, int resno,
29
+             resource_size_t size)
22
+{
30
+{
23
+    if (!pci_resource_is_iov(resno)) {
31
+    if (!pci_resource_is_iov(resno)) {
24
+        pci_warn(dev, "%s is not an IOV resource\n",
32
+        pci_warn(dev, "%s is not an IOV resource\n",
25
+             pci_resource_name(dev, resno));
33
+             pci_resource_name(dev, resno));
26
+        return;
34
+        return;
27
+    }
35
+    }
28
+
36
+
29
+    dev->sriov->barsz[resno - PCI_IOV_RESOURCES] = size;
37
+    dev->sriov->barsz[pci_resource_num_to_vf_bar(resno)] = size;
30
+}
38
+}
31
+
39
+
32
+bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev)
40
+bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev)
33
+{
41
+{
34
+    u16 cmd;
42
+    u16 cmd;
...
...
43
    struct pci_dev *physfn = virtfn->physfn;
51
    struct pci_dev *physfn = virtfn->physfn;
44
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
52
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
45
index XXXXXXX..XXXXXXX 100644
53
index XXXXXXX..XXXXXXX 100644
46
--- a/drivers/pci/pci.c
54
--- a/drivers/pci/pci.c
47
+++ b/drivers/pci/pci.c
55
+++ b/drivers/pci/pci.c
48
@@ -XXX,XX +XXX,XX @@ void pci_acs_init(struct pci_dev *dev)
56
@@ -XXX,XX +XXX,XX @@ static int pci_rebar_find_pos(struct pci_dev *pdev, int bar)
49
*/
50
static int pci_rebar_find_pos(struct pci_dev *pdev, int bar)
51
{
52
+    int cap = PCI_EXT_CAP_ID_REBAR;
53
    unsigned int pos, nbars, i;
57
    unsigned int pos, nbars, i;
54
    u32 ctrl;
58
    u32 ctrl;
55
59
56
-    pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR);
60
-    pos = pdev->rebar_cap;
57
+#ifdef CONFIG_PCI_IOV
58
+    if (pci_resource_is_iov(bar)) {
61
+    if (pci_resource_is_iov(bar)) {
59
+        cap = PCI_EXT_CAP_ID_VF_REBAR;
62
+        if (!pdev->physfn)
60
+        bar -= PCI_IOV_RESOURCES;
63
+            return -ENOTSUPP;
64
+        pos = pdev->sriov->vf_rebar_cap;
65
+        bar = pci_resource_num_to_vf_bar(bar);
66
+    } else {
67
+        pos = pdev->rebar_cap;
61
+    }
68
+    }
62
+#endif
69
+
63
+    pos = pci_find_ext_capability(pdev, cap);
64
    if (!pos)
70
    if (!pos)
65
        return -ENOTSUPP;
71
        return -ENOTSUPP;
66
72
67
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
73
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
68
index XXXXXXX..XXXXXXX 100644
74
index XXXXXXX..XXXXXXX 100644
69
--- a/drivers/pci/pci.h
75
--- a/drivers/pci/pci.h
70
+++ b/drivers/pci/pci.h
76
+++ b/drivers/pci/pci.h
71
@@ -XXX,XX +XXX,XX @@ static inline bool pci_resource_is_iov(int resno)
77
@@ -XXX,XX +XXX,XX @@ void pci_iov_update_resource(struct pci_dev *dev, int resno);
78
resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
79
void pci_restore_iov_state(struct pci_dev *dev);
80
int pci_iov_bus_range(struct pci_bus *bus);
81
+void pci_iov_resource_set_size(struct pci_dev *dev, int resno,
82
+             resource_size_t size);
83
+bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev);
84
static inline bool pci_resource_is_iov(int resno)
72
{
85
{
73
    return resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END;
86
    return resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END;
74
}
87
@@ -XXX,XX +XXX,XX @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
75
+void pci_iov_resource_set_size(struct pci_dev *dev, int resno, resource_size_t size);
76
+bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev);
77
extern const struct attribute_group sriov_pf_dev_attr_group;
78
extern const struct attribute_group sriov_vf_dev_attr_group;
79
#else
80
@@ -XXX,XX +XXX,XX @@ static inline bool pci_resource_is_iov(int resno)
81
{
88
{
82
    return false;
89
    return 0;
83
}
90
}
84
+static inline void pci_iov_resource_set_size(struct pci_dev *dev, int resno,
91
+static inline void pci_iov_resource_set_size(struct pci_dev *dev, int resno,
85
+                     resource_size_t size) { }
92
+                     resource_size_t size) { }
86
+static inline bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev)
93
+static inline bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev)
87
+{
94
+{
88
+    return false;
95
+    return false;
89
+}
96
+}
90
#endif /* CONFIG_PCI_IOV */
97
static inline bool pci_resource_is_iov(int resno)
91
98
{
92
#ifdef CONFIG_PCIE_PTM
99
    return false;
93
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
100
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
94
index XXXXXXX..XXXXXXX 100644
101
index XXXXXXX..XXXXXXX 100644
95
--- a/drivers/pci/setup-res.c
102
--- a/drivers/pci/setup-res.c
96
+++ b/drivers/pci/setup-res.c
103
+++ b/drivers/pci/setup-res.c
97
@@ -XXX,XX +XXX,XX @@ void pci_release_resource(struct pci_dev *dev, int resno)
104
@@ -XXX,XX +XXX,XX @@ void pci_release_resource(struct pci_dev *dev, int resno)
98
}
105
}
99
EXPORT_SYMBOL(pci_release_resource);
106
EXPORT_SYMBOL(pci_release_resource);
100
107
101
+static bool pci_resize_is_memory_decoding_enabled(struct pci_dev *dev, int resno)
108
+static bool pci_resize_is_memory_decoding_enabled(struct pci_dev *dev,
109
+                         int resno)
102
+{
110
+{
103
+    u16 cmd;
111
+    u16 cmd;
104
+
112
+
105
+    if (pci_resource_is_iov(resno))
113
+    if (pci_resource_is_iov(resno))
106
+        return pci_iov_is_memory_decoding_enabled(dev);
114
+        return pci_iov_is_memory_decoding_enabled(dev);
107
+
115
+
108
+    pci_read_config_word(dev, PCI_COMMAND, &cmd);
116
+    pci_read_config_word(dev, PCI_COMMAND, &cmd);
109
+
117
+
110
+    return cmd & PCI_COMMAND_MEMORY;
118
+    return cmd & PCI_COMMAND_MEMORY;
111
+}
119
+}
112
+
120
+
113
+static void pci_resize_resource_set_size(struct pci_dev *dev, int resno, int size)
121
+static void pci_resize_resource_set_size(struct pci_dev *dev, int resno,
122
+                     int size)
114
+{
123
+{
115
+    resource_size_t res_size = pci_rebar_size_to_bytes(size);
124
+    resource_size_t res_size = pci_rebar_size_to_bytes(size);
116
+    struct resource *res = dev->resource + resno;
125
+    struct resource *res = pci_resource_n(dev, resno);
117
+
126
+
118
+    if (!pci_resource_is_iov(resno)) {
127
+    if (!pci_resource_is_iov(resno)) {
119
+        res->end = res->start + res_size - 1;
128
+        resource_set_size(res, res_size);
120
+    } else {
129
+    } else {
121
+        res->end = res->start + res_size * pci_sriov_get_totalvfs(dev) - 1;
130
+        resource_set_size(res, res_size * pci_sriov_get_totalvfs(dev));
122
+        pci_iov_resource_set_size(dev, resno, res_size);
131
+        pci_iov_resource_set_size(dev, resno, res_size);
123
+    }
132
+    }
124
+}
133
+}
125
+
134
+
126
int pci_resize_resource(struct pci_dev *dev, int resno, int size)
135
int pci_resize_resource(struct pci_dev *dev, int resno, int size)
127
{
136
{
128
    struct resource *res = dev->resource + resno;
137
    struct resource *res = pci_resource_n(dev, resno);
129
    struct pci_host_bridge *host;
138
    struct pci_host_bridge *host;
130
    int old, ret;
139
    int old, ret;
131
    u32 sizes;
140
    u32 sizes;
132
-    u16 cmd;
141
-    u16 cmd;
133
142
...
...
145
    sizes = pci_rebar_get_possible_sizes(dev, resno);
154
    sizes = pci_rebar_get_possible_sizes(dev, resno);
146
@@ -XXX,XX +XXX,XX @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size)
155
@@ -XXX,XX +XXX,XX @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size)
147
    if (ret)
156
    if (ret)
148
        return ret;
157
        return ret;
149
158
150
-    res->end = res->start + pci_rebar_size_to_bytes(size) - 1;
159
-    resource_set_size(res, pci_rebar_size_to_bytes(size));
151
+    pci_resize_resource_set_size(dev, resno, size);
160
+    pci_resize_resource_set_size(dev, resno, size);
152
161
153
    /* Check if the new config works by trying to assign everything. */
162
    /* Check if the new config works by trying to assign everything. */
154
    if (dev->bus->self) {
163
    if (dev->bus->self) {
155
@@ -XXX,XX +XXX,XX @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size)
164
@@ -XXX,XX +XXX,XX @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size)
156
165
157
error_resize:
166
error_resize:
158
    pci_rebar_set_size(dev, resno, old);
167
    pci_rebar_set_size(dev, resno, old);
159
-    res->end = res->start + pci_rebar_size_to_bytes(old) - 1;
168
-    resource_set_size(res, pci_rebar_size_to_bytes(old));
160
+    pci_resize_resource_set_size(dev, resno, old);
169
+    pci_resize_resource_set_size(dev, resno, old);
161
    return ret;
170
    return ret;
162
}
171
}
163
EXPORT_SYMBOL(pci_resize_resource);
172
EXPORT_SYMBOL(pci_resize_resource);
164
--
173
--
165
2.47.0
174
2.49.0
166
175
diff view generated by jsdifflib
New patch
1
When the resource representing VF MMIO BAR reservation is created, its
2
size is always large enough to accommodate the BAR of all SR-IOV Virtual
3
Functions that can potentially be created (total VFs). If for whatever
4
reason it's not possible to accommodate all VFs - the resource is not
5
assigned and no VFs can be created.
1
6
7
An upcoming change will allow VF BAR size to be modified by drivers at
8
a later point in time, which means that the check for resource
9
assignment is no longer sufficient.
10
11
Add an additional check that verifies that VF BAR for all enabled VFs
12
fits within the underlying reservation resource.
13
14
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
15
---
16
drivers/pci/iov.c | 3 +++
17
1 file changed, 3 insertions(+)
18
19
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/drivers/pci/iov.c
22
+++ b/drivers/pci/iov.c
23
@@ -XXX,XX +XXX,XX @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
24
    nres = 0;
25
    for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
26
        int idx = pci_resource_num_from_vf_bar(i);
27
+        resource_size_t vf_bar_sz = pci_iov_resource_size(dev, idx);
28
29
        bars |= (1 << idx);
30
        res = &dev->resource[idx];
31
+        if (vf_bar_sz * nr_virtfn > resource_size(res))
32
+            continue;
33
        if (res->parent)
34
            nres++;
35
    }
36
--
37
2.49.0
38
diff view generated by jsdifflib
1
VF MMIO resource reservation, either created by system firmware and
1
Drivers could leverage the fact that the VF BAR MMIO reservation is
2
inherited by Linux PCI subsystem or created by the subsystem itself,
2
created for total number of VFs supported by the device by resizing the
3
contains enough space to fit the BAR of all SR-IOV Virtual Functions
3
BAR to larger size when smaller number of VFs is enabled.
4
that can potentially be created (total VFs supported by the device).
4
5
This can be leveraged when the device is exposing lower than optimal BAR
5
Add a pci_iov_vf_bar_set_size() function to control the size and a
6
size as a default, allowing access to the entire resource when lower
6
pci_iov_vf_bar_get_sizes() helper to get the VF BAR sizes that will
7
number of VFs are created.
7
allow up to num_vfs to be successfully enabled with the current
8
It is achieved by dynamically resizing the BAR to largest possible value
8
underlying reservation size.
9
that allows to fit all newly created VFs within the original resource
10
boundary.
11
9
12
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
10
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
13
---
11
---
14
drivers/pci/iov.c | 92 ++++++++++++++++++++++++++++++++++++++++++++-
12
drivers/pci/iov.c | 69 +++++++++++++++++++++++++++++++++++++++++++++
15
drivers/pci/pci.h | 1 +
13
include/linux/pci.h | 6 ++++
16
include/linux/pci.h | 3 ++
14
2 files changed, 75 insertions(+)
17
3 files changed, 95 insertions(+), 1 deletion(-)
18
15
19
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
16
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
20
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
21
--- a/drivers/pci/iov.c
18
--- a/drivers/pci/iov.c
22
+++ b/drivers/pci/iov.c
19
+++ b/drivers/pci/iov.c
23
@@ -XXX,XX +XXX,XX @@ bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev)
20
@@ -XXX,XX +XXX,XX @@ int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn)
24
    return cmd & PCI_SRIOV_CTRL_MSE;
21
    return nr_virtfn;
25
}
22
}
26
23
EXPORT_SYMBOL_GPL(pci_sriov_configure_simple);
27
+static void pci_iov_resource_do_extend(struct pci_dev *dev, int resno, u16 num_vfs)
24
+
25
+/**
26
+ * pci_iov_vf_bar_set_size - set a new size for a VF BAR
27
+ * @dev: the PCI device
28
+ * @resno: the resource number
29
+ * @size: new size as defined in the spec (0=1MB, 31=128TB)
30
+ *
31
+ * Set the new size of a VF BAR that supports VF resizable BAR capability.
32
+ * Unlike pci_resize_resource(), this does not cause the resource that
33
+ * reserves the MMIO space (originally up to total_VFs) to be resized, which
34
+ * means that following calls to pci_enable_sriov() can fail if the resources
35
+ * no longer fit.
36
+ *
37
+ * Return: 0 on success, or negative on failure.
38
+ */
39
+int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size)
28
+{
40
+{
29
+    resource_size_t size;
41
+    int ret;
30
+    int ret, old, i;
31
+    u32 sizes;
42
+    u32 sizes;
32
+
43
+
33
+    pci_config_pm_runtime_get(dev);
44
+    if (!pci_resource_is_iov(resno))
45
+        return -EINVAL;
34
+
46
+
35
+    if (pci_iov_is_memory_decoding_enabled(dev)) {
47
+    if (pci_iov_is_memory_decoding_enabled(dev))
36
+        ret = -EBUSY;
48
+        return -EBUSY;
37
+        goto err;
38
+    }
39
+
49
+
40
+    sizes = pci_rebar_get_possible_sizes(dev, resno);
50
+    sizes = pci_rebar_get_possible_sizes(dev, resno);
41
+    if (!sizes) {
51
+    if (!sizes)
42
+        ret = -ENOTSUPP;
43
+        goto err;
44
+    }
45
+
46
+    old = pci_rebar_get_current_size(dev, resno);
47
+    if (old < 0) {
48
+        ret = old;
49
+        goto err;
50
+    }
51
+
52
+    while (sizes > 0) {
53
+        i = __fls(sizes);
54
+        size = pci_rebar_size_to_bytes(i);
55
+        if (size * num_vfs <= pci_resource_len(dev, resno)) {
56
+            if (i != old) {
57
+                ret = pci_rebar_set_size(dev, resno, size);
58
+                if (ret)
59
+                    goto err;
60
+
61
+                pci_iov_resource_set_size(dev, resno, size);
62
+                pci_iov_update_resource(dev, resno);
63
+            }
64
+            break;
65
+        }
66
+        sizes &= ~BIT(i);
67
+    }
68
+
69
+    pci_config_pm_runtime_put(dev);
70
+
71
+    return;
72
+
73
+err:
74
+    pci_warn(dev, "Failed to extend %s: %d\n",
75
+         pci_resource_name(dev, resno), ret);
76
+
77
+    pci_config_pm_runtime_put(dev);
78
+}
79
+
80
+static void pci_iov_resource_do_restore(struct pci_dev *dev, int resno)
81
+{
82
+    if (dev->sriov->rebar_extend[resno - PCI_IOV_RESOURCES])
83
+        pci_iov_resource_do_extend(dev, resno, dev->sriov->total_VFs);
84
+}
85
+
86
+int pci_iov_resource_extend(struct pci_dev *dev, int resno, bool enable)
87
+{
88
+    if (!pci_resource_is_iov(resno)) {
89
+        pci_warn(dev, "%s is not an IOV resource\n",
90
+             pci_resource_name(dev, resno));
91
+
92
+        return -ENODEV;
93
+    }
94
+
95
+    if (!pci_rebar_get_possible_sizes(dev, resno))
96
+        return -ENOTSUPP;
52
+        return -ENOTSUPP;
97
+
53
+
98
+    if (!enable)
54
+    if (!(sizes & BIT(size)))
99
+        pci_iov_resource_do_restore(dev, resno);
55
+        return -EINVAL;
100
+
56
+
101
+    dev->sriov->rebar_extend[resno - PCI_IOV_RESOURCES] = enable;
57
+    ret = pci_rebar_set_size(dev, resno, size);
58
+    if (ret)
59
+        return ret;
60
+
61
+    pci_iov_resource_set_size(dev, resno, pci_rebar_size_to_bytes(size));
102
+
62
+
103
+    return 0;
63
+    return 0;
104
+}
64
+}
105
+EXPORT_SYMBOL_GPL(pci_iov_resource_extend);
65
+EXPORT_SYMBOL_GPL(pci_iov_vf_bar_set_size);
106
+
66
+
107
static void pci_read_vf_config_common(struct pci_dev *virtfn)
67
+/**
108
{
68
+ * pci_iov_vf_bar_get_sizes - get VF BAR sizes allowing to create up to num_vfs
109
    struct pci_dev *physfn = virtfn->physfn;
69
+ * @dev: the PCI device
110
@@ -XXX,XX +XXX,XX @@ static ssize_t sriov_numvfs_store(struct device *dev,
70
+ * @resno: the resource number
111
                 const char *buf, size_t count)
71
+ * @num_vfs: number of VFs
112
{
72
+ *
113
    struct pci_dev *pdev = to_pci_dev(dev);
73
+ * Get the sizes of a VF resizable BAR that can accommodate @num_vfs within
114
-    int ret = 0;
74
+ * the currently assigned size of the resource @resno.
115
+    int i, ret = 0;
75
+ *
116
    u16 num_vfs;
76
+ * Return: A bitmask of sizes in format defined in the spec (bit 0=1MB,
117
77
+ * bit 31=128TB).
118
    if (kstrtou16(buf, 0, &num_vfs) < 0)
78
+ */
119
@@ -XXX,XX +XXX,XX @@ static ssize_t sriov_numvfs_store(struct device *dev,
79
+u32 pci_iov_vf_bar_get_sizes(struct pci_dev *dev, int resno, int num_vfs)
120
        goto exit;
80
+{
121
    }
81
+    resource_size_t vf_len = pci_resource_len(dev, resno);
122
82
+    u32 sizes;
123
+    for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
124
+        if (pdev->sriov->rebar_extend[i])
125
+            pci_iov_resource_do_extend(pdev, i + PCI_IOV_RESOURCES, num_vfs);
126
+    }
127
+
83
+
128
    ret = pdev->driver->sriov_configure(pdev, num_vfs);
84
+    if (!num_vfs)
129
    if (ret < 0)
85
+        return 0;
130
        goto exit;
131
@@ -XXX,XX +XXX,XX @@ static int sriov_init(struct pci_dev *dev, int pos)
132
133
static void sriov_release(struct pci_dev *dev)
134
{
135
+    int i;
136
+
86
+
137
    BUG_ON(dev->sriov->num_VFs);
87
+    do_div(vf_len, num_vfs);
138
88
+    sizes = (roundup_pow_of_two(vf_len + 1) - 1) >> ilog2(SZ_1M);
139
+    for (i = 0; i < PCI_SRIOV_NUM_BARS; i++)
140
+        pci_iov_resource_do_restore(dev, i + PCI_IOV_RESOURCES);
141
+
89
+
142
    if (dev != dev->sriov->dev)
90
+    return sizes & pci_rebar_get_possible_sizes(dev, resno);
143
        pci_dev_put(dev->sriov->dev);
91
+}
144
92
+EXPORT_SYMBOL_GPL(pci_iov_vf_bar_get_sizes);
145
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
146
index XXXXXXX..XXXXXXX 100644
147
--- a/drivers/pci/pci.h
148
+++ b/drivers/pci/pci.h
149
@@ -XXX,XX +XXX,XX @@ struct pci_sriov {
150
    u16        subsystem_vendor; /* VF subsystem vendor */
151
    u16        subsystem_device; /* VF subsystem device */
152
    resource_size_t    barsz[PCI_SRIOV_NUM_BARS];    /* VF BAR size */
153
+    bool        rebar_extend[PCI_SRIOV_NUM_BARS];    /* Resize VF BAR */
154
    bool        drivers_autoprobe; /* Auto probing of VFs by driver */
155
};
156
157
diff --git a/include/linux/pci.h b/include/linux/pci.h
93
diff --git a/include/linux/pci.h b/include/linux/pci.h
158
index XXXXXXX..XXXXXXX 100644
94
index XXXXXXX..XXXXXXX 100644
159
--- a/include/linux/pci.h
95
--- a/include/linux/pci.h
160
+++ b/include/linux/pci.h
96
+++ b/include/linux/pci.h
161
@@ -XXX,XX +XXX,XX @@ int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
97
@@ -XXX,XX +XXX,XX @@ int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
162
int pci_sriov_get_totalvfs(struct pci_dev *dev);
98
int pci_sriov_get_totalvfs(struct pci_dev *dev);
163
int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn);
99
int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn);
164
resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno);
100
resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno);
165
+int pci_iov_resource_extend(struct pci_dev *dev, int resno, bool enable);
101
+int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size);
102
+u32 pci_iov_vf_bar_get_sizes(struct pci_dev *dev, int resno, int num_vfs);
166
void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe);
103
void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe);
167
104
168
/* Arch may override these (weak) */
105
/* Arch may override these (weak) */
169
@@ -XXX,XX +XXX,XX @@ static inline int pci_sriov_get_totalvfs(struct pci_dev *dev)
106
@@ -XXX,XX +XXX,XX @@ static inline int pci_sriov_get_totalvfs(struct pci_dev *dev)
170
#define pci_sriov_configure_simple    NULL
107
#define pci_sriov_configure_simple    NULL
171
static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
108
static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
172
{ return 0; }
109
{ return 0; }
173
+static inline int pci_iov_resource_extend(struct pci_dev *dev, int resno, bool enable)
110
+static inline int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size)
174
+{ return -ENODEV; }
111
+{ return -ENODEV; }
112
+static inline u32 pci_iov_vf_bar_get_sizes(struct pci_dev *dev, int resno, int num_vfs)
113
+{ return 0; }
175
static inline void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe) { }
114
static inline void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe) { }
176
#endif
115
#endif
177
116
178
--
117
--
179
2.47.0
118
2.49.0
180
119
diff view generated by jsdifflib
1
Opt into extending the VF BAR.
1
LMEM is partitioned between multiple VFs and we expect that the more
2
LMEM is partitioned between multiple VFs, and we expect that the more
3
VFs we have, the less LMEM is assigned to each VF.
2
VFs we have, the less LMEM is assigned to each VF.
4
This means that we can achieve full LMEM BAR access without the need to
3
This means that we can achieve full LMEM BAR access without the need to
5
attempt full VF LMEM BAR resize via pci_resize_resource().
4
attempt full VF LMEM BAR resize via pci_resize_resource().
6
5
6
Always try to set the largest possible BAR size that allows to fit the
7
number of enabled VFs and inform the user in case the resize attempt is
8
not successful.
9
7
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
10
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
11
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
8
---
12
---
9
drivers/gpu/drm/xe/regs/xe_bars.h | 1 +
13
drivers/gpu/drm/xe/regs/xe_bars.h | 1 +
10
drivers/gpu/drm/xe/xe_sriov_pf.c | 8 ++++++++
14
drivers/gpu/drm/xe/xe_pci_sriov.c | 22 ++++++++++++++++++++++
11
2 files changed, 9 insertions(+)
15
2 files changed, 23 insertions(+)
12
16
13
diff --git a/drivers/gpu/drm/xe/regs/xe_bars.h b/drivers/gpu/drm/xe/regs/xe_bars.h
17
diff --git a/drivers/gpu/drm/xe/regs/xe_bars.h b/drivers/gpu/drm/xe/regs/xe_bars.h
14
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
15
--- a/drivers/gpu/drm/xe/regs/xe_bars.h
19
--- a/drivers/gpu/drm/xe/regs/xe_bars.h
16
+++ b/drivers/gpu/drm/xe/regs/xe_bars.h
20
+++ b/drivers/gpu/drm/xe/regs/xe_bars.h
...
...
19
#define GTTMMADR_BAR            0 /* MMIO + GTT */
23
#define GTTMMADR_BAR            0 /* MMIO + GTT */
20
#define LMEM_BAR            2 /* VRAM */
24
#define LMEM_BAR            2 /* VRAM */
21
+#define VF_LMEM_BAR            9 /* VF VRAM */
25
+#define VF_LMEM_BAR            9 /* VF VRAM */
22
26
23
#endif
27
#endif
24
diff --git a/drivers/gpu/drm/xe/xe_sriov_pf.c b/drivers/gpu/drm/xe/xe_sriov_pf.c
28
diff --git a/drivers/gpu/drm/xe/xe_pci_sriov.c b/drivers/gpu/drm/xe/xe_pci_sriov.c
25
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
26
--- a/drivers/gpu/drm/xe/xe_sriov_pf.c
30
--- a/drivers/gpu/drm/xe/xe_pci_sriov.c
27
+++ b/drivers/gpu/drm/xe/xe_sriov_pf.c
31
+++ b/drivers/gpu/drm/xe/xe_pci_sriov.c
28
@@ -XXX,XX +XXX,XX @@
32
@@ -XXX,XX +XXX,XX @@
33
* Copyright © 2023-2024 Intel Corporation
29
*/
34
*/
30
35
31
#include <drm/drm_managed.h>
36
+#include <linux/bitops.h>
32
+#include <linux/pci.h>
37
+#include <linux/pci.h>
33
38
+
34
+#include "regs/xe_bars.h"
39
+#include "regs/xe_bars.h"
35
#include "xe_assert.h"
40
#include "xe_assert.h"
36
#include "xe_device.h"
41
#include "xe_device.h"
37
#include "xe_module.h"
42
#include "xe_gt_sriov_pf_config.h"
38
@@ -XXX,XX +XXX,XX @@ bool xe_sriov_pf_readiness(struct xe_device *xe)
43
@@ -XXX,XX +XXX,XX @@ static void pf_link_vfs(struct xe_device *xe, int num_vfs)
39
*/
44
    }
40
int xe_sriov_pf_init_early(struct xe_device *xe)
45
}
46
47
+static int resize_vf_vram_bar(struct xe_device *xe, int num_vfs)
48
+{
49
+    struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
50
+    u32 sizes;
51
+
52
+    sizes = pci_iov_vf_bar_get_sizes(pdev, VF_LMEM_BAR, num_vfs);
53
+    if (!sizes)
54
+        return 0;
55
+
56
+    return pci_iov_vf_bar_set_size(pdev, VF_LMEM_BAR, __fls(sizes));
57
+}
58
+
59
static int pf_enable_vfs(struct xe_device *xe, int num_vfs)
41
{
60
{
42
+    int err;
61
    struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
62
@@ -XXX,XX +XXX,XX @@ static int pf_enable_vfs(struct xe_device *xe, int num_vfs)
63
    if (err < 0)
64
        goto failed;
65
66
+    if (IS_DGFX(xe)) {
67
+        err = resize_vf_vram_bar(xe, num_vfs);
68
+        if (err)
69
+            xe_sriov_info(xe, "Failed to set VF LMEM BAR size: %d\n", err);
70
+    }
43
+
71
+
44
    xe_assert(xe, IS_SRIOV_PF(xe));
72
    err = pci_enable_sriov(pdev, num_vfs);
45
73
    if (err < 0)
46
+    err = pci_iov_resource_extend(to_pci_dev(xe->drm.dev), VF_LMEM_BAR, true);
74
        goto failed;
47
+    if (err)
48
+        xe_sriov_info(xe, "Failed to extend VF LMEM BAR: %d", err);
49
+
50
    return drmm_mutex_init(&xe->drm, &xe->sriov.pf.master_lock);
51
}
52
53
--
75
--
54
2.47.0
76
2.49.0
55
77
diff view generated by jsdifflib