|
28 | 28 | #include <linux/pm_runtime.h>
|
29 | 29 | #include <linux/msi.h>
|
30 | 30 | #include <linux/of.h>
|
| 31 | +#include <linux/aperture.h> |
31 | 32 | #include "pci.h"
|
32 | 33 |
|
33 | 34 | static int sysfs_initialized; /* = 0 */
|
@@ -1373,6 +1374,112 @@ static const struct attribute_group pci_dev_reset_attr_group = {
|
1373 | 1374 | .is_visible = pci_dev_reset_attr_is_visible,
|
1374 | 1375 | };
|
1375 | 1376 |
|
| 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 | + |
1376 | 1483 | int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev)
|
1377 | 1484 | {
|
1378 | 1485 | if (!sysfs_initialized)
|
@@ -1494,6 +1601,7 @@ const struct attribute_group *pci_dev_groups[] = {
|
1494 | 1601 | #ifdef CONFIG_ACPI
|
1495 | 1602 | &pci_dev_acpi_attr_group,
|
1496 | 1603 | #endif
|
| 1604 | + &pci_dev_resource_resize_group, |
1497 | 1605 | NULL,
|
1498 | 1606 | };
|
1499 | 1607 |
|
|
0 commit comments