Документация U-Boot 2024. Исходные тексты


  Doc     Cmd     Rst     Src  

U-Boot. Исходные тексты команд: pci_mps.c
// SPDX-License-Identifier: GPL-2.0+
/*
 * (C) Copyright 2022 Microsoft Corporation <www.microsoft.com>
 * Stephen Carlson <stcarlso@linux.microsoft.com>
 *
 * 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;
}

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

U_BOOT_LONGHELP(pci_mps,
	"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");

U_BOOT_CMD(pci_mps, 2, 0, do_pci_mps,
	   "configure PCI Express MPS", pci_mps_help_text);


  Doc     Cmd     Rst     Src