8000 PCI: Expose PCIe Resizable BAR support via sysfs · raspberrypi/linux@91fa127 · GitHub
[go: up one dir, main page]

Skip to content

Commit 91fa127

Browse files
awilliambjorn-helgaas
authored andcommitted
PCI: Expose PCIe Resizable BAR support via sysfs
Add a simple sysfs interface to Resizable BAR support, largely for the purposes of assigning such devices to a VM through VFIO. Resizable BARs present a difficult feature to expose to a VM through emulation, as resizing a BAR is done on the host. It can fail, and often does, but we have no means via emulation of a PCIe REBAR capability to handle the error cases. A vfio-pci specific ioctl interface is also cumbersome as there are often multiple devices within the same bridge aperture and handling them is a challenge. In the interface proposed here, expanding a BAR potentially requires such devices to be soft-removed during the resize operation and rescanned after, in order for all the necessary resources to be released. A pci-sysfs interface is also more universal than a vfio specific interface. Please see the ABI documentation update for usage. Link: https://lore.kernel.org/r/166336088796.3597940.14973499936692558556.stgit@omen Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Christian König <christian.koenig@amd.com> Cc: Krzysztof Wilczyński <kw@linux.com>
1 parent 568035b commit 91fa127

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed

Documentation/ABI/testing/sysfs-bus-pci

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,3 +457,36 @@ Description:
457457

458458
The file is writable if the PF is bound to a driver that
459459
implements ->sriov_set_msix_vec_count().
460+
461+
What: /sys/bus/pci/devices/.../resourceN_resize
462+
Date: September 2022
463+
Contact: Alex Williamson <alex.williamson@redhat.com>
464+
Description:
465+
These files provide an interface to PCIe Resizable BAR support.
466+
A file is created for each BAR resource (N) supported by the
467+
PCIe Resizable BAR extended capability of the device. Reading
468+
each file exposes the bitmap of available resource sizes:
469+
470+
# cat resource1_resize
471+
00000000000001c0
472+
473+
The bitmap represents supported resource sizes for the BAR,
474+
where bit0 = 1MB, bit1 = 2MB, bit2 = 4MB, etc. In the above
475+
example the device supports 64MB, 128MB, and 256MB BAR sizes.
476+
477+
When writing the file, the user provides the bit position of
478+
the desired resource size, for example:
479+
480+
# echo 7 > resource1_resize
481+
482+
This indicates to set the size value corresponding to bit 7,
483+
128MB. The resulting size is 2 ^ (bit# + 20). This definition
484+
matches the PCIe specification of this capability.
485+
486+
In order to make use of resource resizing, all PCI drivers must
487+
be unbound from the device and peer devices under the same
488+
parent bridge may need to be soft removed. In the case of
489+
VGA devices, writing a resize value will remove low level
490+
console drivers from the device. Raw users of pci-sysfs
491+
resourceN attributes must be terminated prior to resizing.
492+
Success of the resizing operation is not guaranteed.

drivers/pci/pci-sysfs.c

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <linux/pm_runtime.h>
2929
#include <linux/msi.h>
3030
#include <linux/of.h>
31+
#include <linux/aperture.h>
3132
#include "pci.h"
3233

3334
static int sysfs_initialized; /* = 0 */
@@ -1373,6 +1374,112 @@ static const struct attribute_group pci_dev_reset_attr_group = {
13731374
.is_visible = pci_dev_reset_attr_is_visible,
13741375
};
13751376

1377+
#define pci_dev_resource_resize_attr(n) \
1378+
static ssize_t resource##n##_resize_show(struct device *dev, \
1379+
struct device_attribute *attr, \
1380+
char * buf) \
1381+
{ \
1382+
struct pci_dev *pdev = to_pci_dev(dev); \
1383+
ssize_t ret; \
1384+
\
1385+
pci_config_pm_runtime_get(pdev); \
1386+
\
1387+
ret = sysfs_emit(buf, "%016llx\n", \
1388+
(u64)pci_rebar_get_possible_sizes(pdev, n)); \
1389+
\
1390+
pci_config_pm_runtime_put(pdev); \
1391+
\
1392+
return ret; \
1393+
} \
1394+
\
1395+
static ssize_t resource##n##_resize_store(struct device *dev, \
1396+
struct device_attribute *attr,\
1397+
const char *buf, size_t count)\
1398+
{ \
1399+
struct pci_dev *pdev = to_pci_dev(dev); \
1400+
unsigned long size, flags; \
1401+
int ret, i; \
1402+
u16 cmd; \
1403+
\
1404+
if (kstrtoul(buf, 0, &size) < 0) \
1405+
return -EINVAL; \
1406+
\
1407+
device_lock(dev); \
1408+
if (dev->driver) { \
1409+
ret = -EBUSY; \
1410+
goto unlock; \
1411+
} \
1412+
\
1413+
pci_config_pm_runtime_get(pdev); \
1414+
\
1415+
if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { \
1416+
ret = aperture_remove_conflicting_pci_devices(pdev, \
1417+
"resourceN_resize"); \
1418+
if (ret) \
1419+
goto pm_put; \
1420+
} \
1421+
\
1422+
pci_read_config_word(pdev, PCI_COMMAND, &cmd); \
1423+
pci_write_config_word(pdev, PCI_COMMAND, \
1424+
cmd & ~PCI_COMMAND_MEMORY); \
1425+
\
1426+
flags = pci_resource_flags(pdev, n); \
1427+
\
1428+
pci_remove_resource_files(pdev); \
1429+
\
1430+
for (i = 0; i < PCI_STD_NUM_BARS; i++) { \
1431+
if (pci_resource_len(pdev, i) && \
1432+
pci_resource_flags(pdev, i) == flags) \
1433+
pci_release_resource(pdev, i); \
1434+
} \
1435+
\
1436+
ret = pci_resize_resource(pdev, n, size); \
1437+
\
1438+
pci_assign_unassigned_bus_resources(pdev->bus); \
1439+
\
1440+
if (pci_create_resource_files(pdev)) \
1441+
pci_warn(pdev, "Failed to recreate resource files after BAR resizing\n");\
1442+
\
1443+
pci_write_config_word(pdev, PCI_COMMAND, cmd); \
1444+
pm_put: \
1445+
pci_config_pm_runtime_put(pdev); \
1446+
unlock: \
1447+
device_unlock(dev); \
1448+
\
1449+
return ret ? ret : count; \
1450+
} \
1451+
static DEVICE_ATTR_RW(resource##n##_resize)
1452+
1453+
pci_dev_resource_resize_attr(0);
1454+
pci_dev_resource_resize_attr(1);
1455+
pci_dev_resource_resize_attr(2);
1456+
pci_dev_resource_resize_attr(3);
1457+
pci_dev_resource_resize_attr(4);
1458+
pci_dev_resource_resize_attr(5);
1459+
1460+
static struct attribute *resource_resize_attrs[] = {
1461+
&dev_attr_resource0_resize.attr,
1462+
&dev_attr_resource1_resize.attr,
1463+
&dev_attr_resource2_resize.attr,
1464+
&dev_attr_resource3_resize.attr,
1465+
&dev_attr_resource4_resize.attr,
1466+
&dev_attr_resource5_resize.attr,
1467+
NULL,
1468+
};
1469+
1470+
static umode_t resource_resize_is_visible(struct kobject *kobj,
1471+
struct attribute *a, int n)
1472+
{
1473+
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
1474+
1475+
return pci_rebar_get_current_size(pdev, n) < 0 ? 0 : a->mode;
1476+
}
1477+
1478+
static const struct attribute_group pci_dev_resource_resize_group = {
1479+
.attrs = resource_resize_attrs,
1480+
.is_visible = resource_resize_is_visible,
1481+
};
1482+
13761483
int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev)
13771484
{
13781485
if (!sysfs_initialized)
@@ -1494,6 +1601,7 @@ const struct attribute_group *pci_dev_groups[] = {
14941601
#ifdef CONFIG_ACPI
14951602
&pci_dev_acpi_attr_group,
14961603
#endif
1604+
&pci_dev_resource_resize_group,
14971605
NULL,
14981606
};
14991607

0 commit comments

Comments
 (0)
0