1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2022 Microsoft Corporation <www.microsoft.com> 4 * Stephen Carlson <stcarlso@linux.microsoft.com> 5 * 6 * PCI Express Maximum Packet Size (MPS) configuration 7 */ 8 9#include <common.h> 10#include <bootretry.h> 11#include <cli.h> 12#include <command.h> 13#include <console.h> 14#include <dm.h> 15#include <init.h> 16#include <asm/processor.h> 17#include <asm/io.h> 18#include <pci.h> 19 20#define PCI_MPS_SAFE 0 21#define PCI_MPS_PEER2PEER 1 22 23static int pci_mps_find_safe(struct udevice *bus, unsigned int *min_mps, 24 unsigned int *n) 25{ 26 struct udevice *dev; 27 int res = 0, addr; 28 unsigned int mpss; 29 u32 regval; 30 31 if (!min_mps || !n) 32 return -EINVAL; 33 34 for (device_find_first_child(bus, &dev); 35 dev; 36 device_find_next_child(&dev)) { 37 addr = dm_pci_find_capability(dev, PCI_CAP_ID_EXP); 38 if (addr <= 0) 39 continue; 40 41 res = dm_pci_read_config32(dev, addr + PCI_EXP_DEVCAP, 42 ®val); 43 if (res != 0) 44 return res; 45 mpss = (unsigned int)(regval & PCI_EXP_DEVCAP_PAYLOAD); 46 *n += 1; 47 if (mpss < *min_mps) 48 *min_mps = mpss; 49 } 50 51 return res; 52} 53 54static int pci_mps_set_bus(struct udevice *bus, unsigned int target) 55{ 56 struct udevice *dev; 57 u32 mpss, target_mps = (u32)(target << 5); 58 u16 mps; 59 int res = 0, addr; 60 61 for (device_find_first_child(bus, &dev); 62 dev && res == 0; 63 device_find_next_child(&dev)) { 64 addr = dm_pci_find_capability(dev, PCI_CAP_ID_EXP); 65 if (addr <= 0) 66 continue; 67 68 res = dm_pci_read_config32(dev, addr + PCI_EXP_DEVCAP, 69 &mpss); 70 if (res != 0) 71 return res; 72 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; 77 else 78 mps = (u16)mpss; 79 res = dm_pci_clrset_config16(dev, addr + PCI_EXP_DEVCTL, 80 PCI_EXP_DEVCTL_PAYLOAD, mps); 81 } 82 83 return res; 84} 85 86/* 87 * Sets the MPS of each PCI Express device to the specified policy. 88 */ 89static int pci_mps_set(int policy) 90{ 91 struct udevice *bus; 92 int i, res = 0; 93 /* 0 = 128B, min value for hotplug */ 94 unsigned int mps = 0; 95 96 if (policy == PCI_MPS_SAFE) { 97 unsigned int min_mps = PCI_EXP_DEVCAP_PAYLOAD_4096B, n = 0; 98 99 /* Find maximum MPS supported by all devices */ 100 for (i = 0; 101 uclass_get_device_by_seq(UCLASS_PCI, i, &bus) == 0 && 102 res == 0; 103 i++) 104 res = pci_mps_find_safe(bus, &min_mps, &n); 105 106 /* If no devices were found, do not reconfigure */ 107 if (n == 0) 108 return res; 109 mps = min_mps; 110 } 111 112 /* This message is checked by the sandbox test */ 113 printf("Setting MPS of all devices to %uB\n", 128U << mps); 114 for (i = 0; 115 uclass_get_device_by_seq(UCLASS_PCI, i, &bus) == 0 && res == 0; 116 i++) 117 res = pci_mps_set_bus(bus, mps); 118 119 return res; 120} 121 122/* 123 * PCI MPS tuning commands 124 * 125 * Syntax: 126 * pci_mps safe 127 * pci_mps peer2peer 128 */ 129static int do_pci_mps(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) 130{ 131 char cmd = 'u'; 132 int ret = 0; 133 134 if (argc > 1) 135 cmd = argv[1][0]; 136 137 switch (cmd) { 138 case 's': /* safe */ 139 ret = pci_mps_set(PCI_MPS_SAFE); 140 break; 141 case 'p': /* peer2peer/hotplug */ 142 ret = pci_mps_set(PCI_MPS_PEER2PEER); 143 break; 144 default: /* usage, help */ 145 goto usage; 146 } 147 148 return ret; 149usage: 150 return CMD_RET_USAGE; 151} 152 153/***************************************************/ 154 155U_BOOT_LONGHELP(pci_mps, 156 "safe\n" 157 " - Set PCI Express MPS of all devices to safe values\n" 158 "pci_mps peer2peer\n" 159 " - Set PCI Express MPS of all devices to support hotplug and peer-to-peer DMA\n"); 160 161U_BOOT_CMD(pci_mps, 2, 0, do_pci_mps, 162 "configure PCI Express MPS", pci_mps_help_text); 163