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