1 // SPDX-License-Identifier: GPL-2.0+
3 * (C) Copyright 2022 Microsoft Corporation <www.microsoft.com>
4 * Stephen Carlson <stcarlso@linux.microsoft.com>
6 * PCI Express Maximum Packet Size (MPS) configuration
10 #include <bootretry.h>
16 #include <asm/processor.h>
20 #define PCI_MPS_SAFE 0
21 #define PCI_MPS_PEER2PEER 1
23 static int pci_mps_find_safe(struct udevice *bus, unsigned int *min_mps,
34 for (device_find_first_child(bus, &dev);
36 device_find_next_child(&dev)) {
37 addr = dm_pci_find_capability(dev, PCI_CAP_ID_EXP);
41 res = dm_pci_read_config32(dev, addr + PCI_EXP_DEVCAP,
45 mpss = (unsigned int)(regval & PCI_EXP_DEVCAP_PAYLOAD);
54 static int pci_mps_set_bus(struct udevice *bus, unsigned int target)
57 u32 mpss, target_mps = (u32)(target << 5);
61 for (device_find_first_child(bus, &dev);
63 device_find_next_child(&dev)) {
64 addr = dm_pci_find_capability(dev, PCI_CAP_ID_EXP);
68 res = dm_pci_read_config32(dev, addr + PCI_EXP_DEVCAP,
73 /* Do not set device above its maximum MPSS */
74 mpss = (mpss & PCI_EXP_DEVCAP_PAYLOAD) << 5;
75 if (target_mps < mpss)
76 mps = (u16)target_mps;
79 res = dm_pci_clrset_config16(dev, addr + PCI_EXP_DEVCTL,
80 PCI_EXP_DEVCTL_PAYLOAD, mps);
87 * Sets the MPS of each PCI Express device to the specified policy.
89 static int pci_mps_set(int policy)
93 /* 0 = 128B, min value for hotplug */
96 if (policy == PCI_MPS_SAFE) {
97 unsigned int min_mps = PCI_EXP_DEVCAP_PAYLOAD_4096B, n = 0;
99 /* Find maximum MPS supported by all devices */
101 uclass_get_device_by_seq(UCLASS_PCI, i, &bus) == 0 &&
104 res = pci_mps_find_safe(bus, &min_mps, &n);
106 /* If no devices were found, do not reconfigure */
112 /* This message is checked by the sandbox test */
113 printf("Setting MPS of all devices to %uB\n", 128U << mps);
115 uclass_get_device_by_seq(UCLASS_PCI, i, &bus) == 0 && res == 0;
117 res = pci_mps_set_bus(bus, mps);
123 * PCI MPS tuning commands
129 static int do_pci_mps(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
139 ret = pci_mps_set(PCI_MPS_SAFE);
141 case 'p': /* peer2peer/hotplug */
142 ret = pci_mps_set(PCI_MPS_PEER2PEER);
144 default: /* usage, help */
150 return CMD_RET_USAGE;
153 /***************************************************/
155 #ifdef CONFIG_SYS_LONGHELP
156 static char pci_mps_help_text[] =
158 " - Set PCI Express MPS of all devices to safe values\n"
159 "pci_mps peer2peer\n"
160 " - Set PCI Express MPS of all devices to support hotplug and peer-to-peer DMA\n";
163 U_BOOT_CMD(pci_mps, 2, 0, do_pci_mps,
164 "configure PCI Express MPS", pci_mps_help_text);