cmd: fdt: Use env_set_hex() for "get addr" and "get size"
[platform/kernel/u-boot.git] / cmd / pci_mps.c
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
23 static 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                                            &regval);
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
54 static 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  */
89 static 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  */
129 static 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;
149 usage:
150         return CMD_RET_USAGE;
151 }
152
153 /***************************************************/
154
155 #ifdef CONFIG_SYS_LONGHELP
156 static char pci_mps_help_text[] =
157         "safe\n"
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";
161 #endif
162
163 U_BOOT_CMD(pci_mps, 2, 0, do_pci_mps,
164            "configure PCI Express MPS", pci_mps_help_text);