Commit 36d0d3b4b4974f4183609ac8b4d77a1f46acba55

Authored by Simon Glass
1 parent 537849aaa1

dm: sandbox: pci: Add a PCI emulation uclass

Since sandbox does not have real devices (unless it borrows those from the
host) it must use emulations. Provide a uclass which permits PCI operations
to be passed through to an emulation device.

Signed-off-by: Simon Glass <sjg@chromium.org>

Showing 4 changed files with 177 additions and 0 deletions Side-by-side Diff

drivers/pci/Makefile
... ... @@ -8,6 +8,7 @@
8 8 ifneq ($(CONFIG_DM_PCI),)
9 9 obj-$(CONFIG_PCI) += pci-uclass.o pci_compat.o
10 10 obj-$(CONFIG_PCI_SANDBOX) += pci_sandbox.o
  11 +obj-$(CONFIG_SANDBOX) += pci-emul-uclass.o
11 12 else
12 13 obj-$(CONFIG_PCI) += pci.o
13 14 endif
drivers/pci/pci-emul-uclass.c
  1 +/*
  2 + * Copyright (c) 2014 Google, Inc
  3 + * Written by Simon Glass <sjg@chromium.org>
  4 + *
  5 + * SPDX-License-Identifier: GPL-2.0+
  6 + */
  7 +
  8 +#include <common.h>
  9 +#include <dm.h>
  10 +#include <fdtdec.h>
  11 +#include <libfdt.h>
  12 +#include <pci.h>
  13 +#include <dm/lists.h>
  14 +
  15 +DECLARE_GLOBAL_DATA_PTR;
  16 +
  17 +struct sandbox_pci_priv {
  18 + int dev_count;
  19 +};
  20 +
  21 +int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn,
  22 + struct udevice **emulp)
  23 +{
  24 + struct udevice *dev;
  25 + int ret;
  26 +
  27 + ret = pci_bus_find_devfn(bus, find_devfn, &dev);
  28 + if (ret) {
  29 + debug("%s: Could not find emulator for dev %x\n", __func__,
  30 + find_devfn);
  31 + return ret;
  32 + }
  33 +
  34 + ret = device_find_first_child(dev, emulp);
  35 + if (ret)
  36 + return ret;
  37 +
  38 + return *emulp ? 0 : -ENODEV;
  39 +}
  40 +
  41 +static int sandbox_pci_emul_post_probe(struct udevice *dev)
  42 +{
  43 + struct sandbox_pci_priv *priv = dev->uclass->priv;
  44 +
  45 + priv->dev_count++;
  46 + sandbox_set_enable_pci_map(true);
  47 +
  48 + return 0;
  49 +}
  50 +
  51 +static int sandbox_pci_emul_pre_remove(struct udevice *dev)
  52 +{
  53 + struct sandbox_pci_priv *priv = dev->uclass->priv;
  54 +
  55 + priv->dev_count--;
  56 + sandbox_set_enable_pci_map(priv->dev_count > 0);
  57 +
  58 + return 0;
  59 +}
  60 +
  61 +UCLASS_DRIVER(pci_emul) = {
  62 + .id = UCLASS_PCI_EMUL,
  63 + .name = "pci_emul",
  64 + .post_probe = sandbox_pci_emul_post_probe,
  65 + .pre_remove = sandbox_pci_emul_pre_remove,
  66 + .priv_auto_alloc_size = sizeof(struct sandbox_pci_priv),
  67 +};
include/dm/uclass-id.h
... ... @@ -20,6 +20,7 @@
20 20 UCLASS_TEST_BUS,
21 21 UCLASS_SPI_EMUL, /* sandbox SPI device emulator */
22 22 UCLASS_I2C_EMUL, /* sandbox I2C device emulator */
  23 + UCLASS_PCI_EMUL, /* sandbox PCI device emulator */
23 24 UCLASS_SIMPLE_BUS,
24 25  
25 26 /* U-Boot uclasses start here */
... ... @@ -992,6 +992,114 @@
992 992 return pci_read_config8(pcidev, offset, valuep);
993 993 }
994 994  
  995 +/**
  996 + * struct dm_pci_emul_ops - PCI device emulator operations
  997 + */
  998 +struct dm_pci_emul_ops {
  999 + /**
  1000 + * get_devfn(): Check which device and function this emulators
  1001 + *
  1002 + * @dev: device to check
  1003 + * @return the device and function this emulates, or -ve on error
  1004 + */
  1005 + int (*get_devfn)(struct udevice *dev);
  1006 + /**
  1007 + * read_config() - Read a PCI configuration value
  1008 + *
  1009 + * @dev: Emulated device to read from
  1010 + * @offset: Byte offset within the device's configuration space
  1011 + * @valuep: Place to put the returned value
  1012 + * @size: Access size
  1013 + * @return 0 if OK, -ve on error
  1014 + */
  1015 + int (*read_config)(struct udevice *dev, uint offset, ulong *valuep,
  1016 + enum pci_size_t size);
  1017 + /**
  1018 + * write_config() - Write a PCI configuration value
  1019 + *
  1020 + * @dev: Emulated device to write to
  1021 + * @offset: Byte offset within the device's configuration space
  1022 + * @value: Value to write
  1023 + * @size: Access size
  1024 + * @return 0 if OK, -ve on error
  1025 + */
  1026 + int (*write_config)(struct udevice *dev, uint offset, ulong value,
  1027 + enum pci_size_t size);
  1028 + /**
  1029 + * read_io() - Read a PCI I/O value
  1030 + *
  1031 + * @dev: Emulated device to read from
  1032 + * @addr: I/O address to read
  1033 + * @valuep: Place to put the returned value
  1034 + * @size: Access size
  1035 + * @return 0 if OK, -ENOENT if @addr is not mapped by this device,
  1036 + * other -ve value on error
  1037 + */
  1038 + int (*read_io)(struct udevice *dev, unsigned int addr, ulong *valuep,
  1039 + enum pci_size_t size);
  1040 + /**
  1041 + * write_io() - Write a PCI I/O value
  1042 + *
  1043 + * @dev: Emulated device to write from
  1044 + * @addr: I/O address to write
  1045 + * @value: Value to write
  1046 + * @size: Access size
  1047 + * @return 0 if OK, -ENOENT if @addr is not mapped by this device,
  1048 + * other -ve value on error
  1049 + */
  1050 + int (*write_io)(struct udevice *dev, unsigned int addr,
  1051 + ulong value, enum pci_size_t size);
  1052 + /**
  1053 + * map_physmem() - Map a device into sandbox memory
  1054 + *
  1055 + * @dev: Emulated device to map
  1056 + * @addr: Memory address, normally corresponding to a PCI BAR.
  1057 + * The device should have been configured to have a BAR
  1058 + * at this address.
  1059 + * @lenp: On entry, the size of the area to map, On exit it is
  1060 + * updated to the size actually mapped, which may be less
  1061 + * if the device has less space
  1062 + * @ptrp: Returns a pointer to the mapped address. The device's
  1063 + * space can be accessed as @lenp bytes starting here
  1064 + * @return 0 if OK, -ENOENT if @addr is not mapped by this device,
  1065 + * other -ve value on error
  1066 + */
  1067 + int (*map_physmem)(struct udevice *dev, phys_addr_t addr,
  1068 + unsigned long *lenp, void **ptrp);
  1069 + /**
  1070 + * unmap_physmem() - undo a memory mapping
  1071 + *
  1072 + * This must be called after map_physmem() to undo the mapping.
  1073 + * Some devices can use this to check what has been written into
  1074 + * their mapped memory and perform an operations they require on it.
  1075 + * In this way, map/unmap can be used as a sort of handshake between
  1076 + * the emulated device and its users.
  1077 + *
  1078 + * @dev: Emuated device to unmap
  1079 + * @vaddr: Mapped memory address, as passed to map_physmem()
  1080 + * @len: Size of area mapped, as returned by map_physmem()
  1081 + * @return 0 if OK, -ve on error
  1082 + */
  1083 + int (*unmap_physmem)(struct udevice *dev, const void *vaddr,
  1084 + unsigned long len);
  1085 +};
  1086 +
  1087 +/* Get access to a PCI device emulator's operations */
  1088 +#define pci_get_emul_ops(dev) ((struct dm_pci_emul_ops *)(dev)->driver->ops)
  1089 +
  1090 +/**
  1091 + * sandbox_pci_get_emul() - Get the emulation device for a PCI device
  1092 + *
  1093 + * Searches for a suitable emulator for the given PCI bus device
  1094 + *
  1095 + * @bus: PCI bus to search
  1096 + * @find_devfn: PCI device and function address (PCI_DEVFN())
  1097 + * @emulp: Returns emulated device if found
  1098 + * @return 0 if found, -ENODEV if not found
  1099 + */
  1100 +int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn,
  1101 + struct udevice **emulp);
  1102 +
995 1103 #endif
996 1104  
997 1105 #endif /* __ASSEMBLY__ */