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
15 #include <asm/processor.h>
19 #define PCI_MPS_SAFE 0
20 #define PCI_MPS_PEER2PEER 1
22 static int pci_mps_find_safe(struct udevice
*bus
, unsigned int *min_mps
,
33 for (device_find_first_child(bus
, &dev
);
35 device_find_next_child(&dev
)) {
36 addr
= dm_pci_find_capability(dev
, PCI_CAP_ID_EXP
);
40 res
= dm_pci_read_config32(dev
, addr
+ PCI_EXP_DEVCAP
,
44 mpss
= (unsigned int)(regval
& PCI_EXP_DEVCAP_PAYLOAD
);
53 static int pci_mps_set_bus(struct udevice
*bus
, unsigned int target
)
56 u32 mpss
, target_mps
= (u32
)(target
<< 5);
60 for (device_find_first_child(bus
, &dev
);
62 device_find_next_child(&dev
)) {
63 addr
= dm_pci_find_capability(dev
, PCI_CAP_ID_EXP
);
67 res
= dm_pci_read_config32(dev
, addr
+ PCI_EXP_DEVCAP
,
72 /* Do not set device above its maximum MPSS */
73 mpss
= (mpss
& PCI_EXP_DEVCAP_PAYLOAD
) << 5;
74 if (target_mps
< mpss
)
75 mps
= (u16
)target_mps
;
78 res
= dm_pci_clrset_config16(dev
, addr
+ PCI_EXP_DEVCTL
,
79 PCI_EXP_DEVCTL_PAYLOAD
, mps
);
86 * Sets the MPS of each PCI Express device to the specified policy.
88 static int pci_mps_set(int policy
)
92 /* 0 = 128B, min value for hotplug */
95 if (policy
== PCI_MPS_SAFE
) {
96 unsigned int min_mps
= PCI_EXP_DEVCAP_PAYLOAD_4096B
, n
= 0;
98 /* Find maximum MPS supported by all devices */
100 uclass_get_device_by_seq(UCLASS_PCI
, i
, &bus
) == 0 &&
103 res
= pci_mps_find_safe(bus
, &min_mps
, &n
);
105 /* If no devices were found, do not reconfigure */
111 /* This message is checked by the sandbox test */
112 printf("Setting MPS of all devices to %uB\n", 128U << mps
);
114 uclass_get_device_by_seq(UCLASS_PCI
, i
, &bus
) == 0 && res
== 0;
116 res
= pci_mps_set_bus(bus
, mps
);
122 * PCI MPS tuning commands
128 static int do_pci_mps(struct cmd_tbl
*cmdtp
, int flag
, int argc
, char *const argv
[])
138 ret
= pci_mps_set(PCI_MPS_SAFE
);
140 case 'p': /* peer2peer/hotplug */
141 ret
= pci_mps_set(PCI_MPS_PEER2PEER
);
143 default: /* usage, help */
149 return CMD_RET_USAGE
;
152 /***************************************************/
154 U_BOOT_LONGHELP(pci_mps
,
156 " - Set PCI Express MPS of all devices to safe values\n"
157 "pci_mps peer2peer\n"
158 " - Set PCI Express MPS of all devices to support hotplug and peer-to-peer DMA\n");
160 U_BOOT_CMD(pci_mps
, 2, 0, do_pci_mps
,
161 "configure PCI Express MPS", pci_mps_help_text
);