|
| 1 | +// SPDX-License-Identifier: MIT |
| 2 | +/* |
| 3 | + * Copyright © 2025 Intel Corporation |
| 4 | + */ |
| 5 | + |
| 6 | +#include <linux/pci.h> |
| 7 | +#include <linux/types.h> |
| 8 | + |
| 9 | +#include <drm/drm_print.h> |
| 10 | + |
| 11 | +#include "regs/xe_bars.h" |
| 12 | +#include "xe_device_types.h" |
| 13 | +#include "xe_module.h" |
| 14 | +#include "xe_pci_rebar.h" |
| 15 | + |
| 16 | +static void resize_bar(struct xe_device *xe, int resno, resource_size_t size) |
| 17 | +{ |
| 18 | + struct pci_dev *pdev = to_pci_dev(xe->drm.dev); |
| 19 | + int bar_size = pci_rebar_bytes_to_size(size); |
| 20 | + int ret; |
| 21 | + |
| 22 | + ret = pci_resize_resource(pdev, resno, bar_size, 0); |
| 23 | + if (ret) { |
| 24 | + drm_info(&xe->drm, "Failed to resize BAR%d to %dM (%pe). Consider enabling 'Resizable BAR' support in your BIOS\n", |
| 25 | + resno, 1 << bar_size, ERR_PTR(ret)); |
| 26 | + return; |
| 27 | + } |
| 28 | + |
| 29 | + drm_info(&xe->drm, "BAR%d resized to %dM\n", resno, 1 << bar_size); |
| 30 | +} |
| 31 | + |
| 32 | +/* |
| 33 | + * xe_pci_rebar_resize - Resize the LMEMBAR |
| 34 | + * @xe: xe device instance |
| 35 | + * |
| 36 | + * If vram_bar_size module param is set, attempt to set to the requested size |
| 37 | + * else set to maximum possible size. |
| 38 | + */ |
| 39 | +void xe_pci_rebar_resize(struct xe_device *xe) |
| 40 | +{ |
| 41 | + int force_vram_bar_size = xe_modparam.force_vram_bar_size; |
| 42 | + struct pci_dev *pdev = to_pci_dev(xe->drm.dev); |
| 43 | + struct pci_bus *root = pdev->bus; |
| 44 | + resource_size_t current_size; |
| 45 | + resource_size_t rebar_size; |
| 46 | + struct resource *root_res; |
| 47 | + int max_size, i; |
| 48 | + u32 pci_cmd; |
| 49 | + |
| 50 | + /* gather some relevant info */ |
| 51 | + current_size = pci_resource_len(pdev, LMEM_BAR); |
| 52 | + |
| 53 | + if (force_vram_bar_size < 0) |
| 54 | + return; |
| 55 | + |
| 56 | + /* set to a specific size? */ |
| 57 | + if (force_vram_bar_size) { |
| 58 | + rebar_size = pci_rebar_bytes_to_size(force_vram_bar_size * |
| 59 | + (resource_size_t)SZ_1M); |
| 60 | + |
| 61 | + if (!pci_rebar_size_supported(pdev, LMEM_BAR, rebar_size)) { |
| 62 | + drm_info(&xe->drm, |
| 63 | + "Requested size: %lluMiB is not supported by rebar sizes: 0x%llx. Leaving default: %lluMiB\n", |
| 64 | + (u64)pci_rebar_size_to_bytes(rebar_size) >> 20, |
| 65 | + pci_rebar_get_possible_sizes(pdev, LMEM_BAR), |
| 66 | + (u64)current_size >> 20); |
| 67 | + return; |
| 68 | + } |
| 69 | + |
| 70 | + rebar_size = pci_rebar_size_to_bytes(rebar_size); |
| 71 | + if (rebar_size == current_size) |
| 72 | + return; |
| 73 | + } else { |
| 74 | + max_size = pci_rebar_get_max_size(pdev, LMEM_BAR); |
| 75 | + if (max_size < 0) |
| 76 | + return; |
| 77 | + rebar_size = pci_rebar_size_to_bytes(max_size); |
| 78 | + |
| 79 | + /* only resize if larger than current */ |
| 80 | + if (rebar_size <= current_size) |
| 81 | + return; |
| 82 | + } |
| 83 | + |
| 84 | + drm_info(&xe->drm, "Attempting to resize bar from %lluMiB -> %lluMiB\n", |
| 85 | + (u64)current_size >> 20, (u64)rebar_size >> 20); |
| 86 | + |
| 87 | + while (root->parent) |
| 88 | + root = root->parent; |
| 89 | + |
| 90 | + pci_bus_for_each_resource(root, root_res, i) { |
| 91 | + if (root_res && root_res->flags & (IORESOURCE_MEM | IORESOURCE_MEM_64) && |
| 92 | + (u64)root_res->start > 0x100000000ul) |
| 93 | + break; |
| 94 | + } |
| 95 | + |
| 96 | + if (!root_res) { |
| 97 | + drm_info(&xe->drm, "Can't resize VRAM BAR - platform support is missing. Consider enabling 'Resizable BAR' support in your BIOS\n"); |
| 98 | + return; |
| 99 | + } |
| 100 | + |
| 101 | + pci_read_config_dword(pdev, PCI_COMMAND, &pci_cmd); |
| 102 | + pci_write_config_dword(pdev, PCI_COMMAND, pci_cmd & ~PCI_COMMAND_MEMORY); |
| 103 | + |
| 104 | + resize_bar(xe, LMEM_BAR, rebar_size); |
| 105 | + |
| 106 | + pci_assign_unassigned_bus_resources(pdev->bus); |
| 107 | + pci_write_config_dword(pdev, PCI_COMMAND, pci_cmd); |
| 108 | +} |
0 commit comments