Skip to content

Commit

Permalink
cmd: pci: Add command to set MPS of all PCIe devices
Browse files Browse the repository at this point in the history
Enable tuning of the PCI Express MPS (Maximum Payload Size) of
each device. The Maximum Read Request Size is not altered.

The SAFE method uses the largest MPS value supported by all devices in the
system for each device. This method is the same algorithm as used by Linux
pci=pcie_bus_safe.

The PEER2PEER method sets all devices to the minimal (128 byte) MPS, which
allows hot plug of devices later that might only support the minimum size,
and ensures compatibility of DMA between two devices on the bus.

Signed-off-by: Stephen Carlson <[email protected]>
  • Loading branch information
Stephen Carlson authored and trini committed Mar 30, 2023
1 parent 19213d7 commit 59b1c9b
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 0 deletions.
10 changes: 10 additions & 0 deletions cmd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1396,6 +1396,16 @@ config CMD_PCI
peripherals. Sub-commands allow bus enumeration, displaying and
changing configuration space and a few other features.

config CMD_PCI_MPS
bool "pci_mps - Configure PCI device MPS"
depends on PCI
help
Enables PCI Express Maximum Packet Size (MPS) tuning. This
command configures the PCI Express MPS of each endpoint to the
largest value supported by all devices below the root complex.
The Maximum Read Request Size will not be altered. This method is
the same algorithm as used by Linux pci=pcie_bus_safe.

config CMD_PINMUX
bool "pinmux - show pins muxing"
depends on PINCTRL
Expand Down
1 change: 1 addition & 0 deletions cmd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ obj-$(CONFIG_CMD_PART) += part.o
obj-$(CONFIG_CMD_PCAP) += pcap.o
ifdef CONFIG_PCI
obj-$(CONFIG_CMD_PCI) += pci.o
obj-$(CONFIG_CMD_PCI_MPS) += pci_mps.o
endif
obj-$(CONFIG_CMD_PINMUX) += pinmux.o
obj-$(CONFIG_CMD_PMC) += pmc.o
Expand Down
164 changes: 164 additions & 0 deletions cmd/pci_mps.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2022 Microsoft Corporation <www.microsoft.com>
* Stephen Carlson <[email protected]>
*
* PCI Express Maximum Packet Size (MPS) configuration
*/

#include <common.h>
#include <bootretry.h>
#include <cli.h>
#include <command.h>
#include <console.h>
#include <dm.h>
#include <init.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <pci.h>

#define PCI_MPS_SAFE 0
#define PCI_MPS_PEER2PEER 1

static int pci_mps_find_safe(struct udevice *bus, unsigned int *min_mps,
unsigned int *n)
{
struct udevice *dev;
int res = 0, addr;
unsigned int mpss;
u32 regval;

if (!min_mps || !n)
return -EINVAL;

for (device_find_first_child(bus, &dev);
dev;
device_find_next_child(&dev)) {
addr = dm_pci_find_capability(dev, PCI_CAP_ID_EXP);
if (addr <= 0)
continue;

res = dm_pci_read_config32(dev, addr + PCI_EXP_DEVCAP,
&regval);
if (res != 0)
return res;
mpss = (unsigned int)(regval & PCI_EXP_DEVCAP_PAYLOAD);
*n += 1;
if (mpss < *min_mps)
*min_mps = mpss;
}

return res;
}

static int pci_mps_set_bus(struct udevice *bus, unsigned int target)
{
struct udevice *dev;
u32 mpss, target_mps = (u32)(target << 5);
u16 mps;
int res = 0, addr;

for (device_find_first_child(bus, &dev);
dev && res == 0;
device_find_next_child(&dev)) {
addr = dm_pci_find_capability(dev, PCI_CAP_ID_EXP);
if (addr <= 0)
continue;

res = dm_pci_read_config32(dev, addr + PCI_EXP_DEVCAP,
&mpss);
if (res != 0)
return res;

/* Do not set device above its maximum MPSS */
mpss = (mpss & PCI_EXP_DEVCAP_PAYLOAD) << 5;
if (target_mps < mpss)
mps = (u16)target_mps;
else
mps = (u16)mpss;
res = dm_pci_clrset_config16(dev, addr + PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_PAYLOAD, mps);
}

return res;
}

/*
* Sets the MPS of each PCI Express device to the specified policy.
*/
static int pci_mps_set(int policy)
{
struct udevice *bus;
int i, res = 0;
/* 0 = 128B, min value for hotplug */
unsigned int mps = 0;

if (policy == PCI_MPS_SAFE) {
unsigned int min_mps = PCI_EXP_DEVCAP_PAYLOAD_4096B, n = 0;

/* Find maximum MPS supported by all devices */
for (i = 0;
uclass_get_device_by_seq(UCLASS_PCI, i, &bus) == 0 &&
res == 0;
i++)
res = pci_mps_find_safe(bus, &min_mps, &n);

/* If no devices were found, do not reconfigure */
if (n == 0)
return res;
mps = min_mps;
}

/* This message is checked by the sandbox test */
printf("Setting MPS of all devices to %uB\n", 128U << mps);
for (i = 0;
uclass_get_device_by_seq(UCLASS_PCI, i, &bus) == 0 && res == 0;
i++)
res = pci_mps_set_bus(bus, mps);

return res;
}

/*
* PCI MPS tuning commands
*
* Syntax:
* pci_mps safe
* pci_mps peer2peer
*/
static int do_pci_mps(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char cmd = 'u';
int ret = 0;

if (argc > 1)
cmd = argv[1][0];

switch (cmd) {
case 's': /* safe */
ret = pci_mps_set(PCI_MPS_SAFE);
break;
case 'p': /* peer2peer/hotplug */
ret = pci_mps_set(PCI_MPS_PEER2PEER);
break;
default: /* usage, help */
goto usage;
}

return ret;
usage:
return CMD_RET_USAGE;
}

/***************************************************/

#ifdef CONFIG_SYS_LONGHELP
static char pci_mps_help_text[] =
"safe\n"
" - Set PCI Express MPS of all devices to safe values\n"
"pci_mps peer2peer\n"
" - Set PCI Express MPS of all devices to support hotplug and peer-to-peer DMA\n";
#endif

U_BOOT_CMD(pci_mps, 2, 0, do_pci_mps,
"configure PCI Express MPS", pci_mps_help_text);
7 changes: 7 additions & 0 deletions include/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,13 @@
#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIe Bridge */
#define PCI_EXP_DEVCAP 4 /* Device capabilities */
#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */
#define PCI_EXP_DEVCAP_PAYLOAD 0x0007 /* Max payload size supported */
#define PCI_EXP_DEVCAP_PAYLOAD_128B 0x0000 /* 128 Bytes */
#define PCI_EXP_DEVCAP_PAYLOAD_256B 0x0001 /* 256 Bytes */
#define PCI_EXP_DEVCAP_PAYLOAD_512B 0x0002 /* 512 Bytes */
#define PCI_EXP_DEVCAP_PAYLOAD_1024B 0x0003 /* 1024 Bytes */
#define PCI_EXP_DEVCAP_PAYLOAD_2048B 0x0004 /* 2048 Bytes */
#define PCI_EXP_DEVCAP_PAYLOAD_4096B 0x0005 /* 4096 Bytes */
#define PCI_EXP_DEVCTL 8 /* Device Control */
#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */
#define PCI_EXP_DEVCTL_PAYLOAD_128B 0x0000 /* 128 Bytes */
Expand Down

0 comments on commit 59b1c9b

Please sign in to comment.