summaryrefslogtreecommitdiff
path: root/drivers/pci/pci_sandbox.c
diff options
context:
space:
mode:
authorBin Meng <bmeng.cn@gmail.com>2018-08-03 11:14:45 +0300
committerSimon Glass <sjg@chromium.org>2018-08-08 14:49:31 +0300
commit4345998ae9dfad7ba0beb54ad4322134557504a9 (patch)
treebb4e8d49af00eb5cc0028ff9efa73dc2f0b61207 /drivers/pci/pci_sandbox.c
parented698aa7dee0fd078b4eb2fc54e64cfeaa68061a (diff)
downloadu-boot-4345998ae9dfad7ba0beb54ad4322134557504a9.tar.xz
pci: sandbox: Support dynamically binding device driver
At present all emulated sandbox pci devices must be present in the device tree in order to be used. The real world pci uclass driver supports pci device driver matching, and we should add such support on sandbox too. Signed-off-by: Bin Meng <bmeng.cn@gmail.com> Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/pci/pci_sandbox.c')
-rw-r--r--drivers/pci/pci_sandbox.c78
1 files changed, 72 insertions, 6 deletions
diff --git a/drivers/pci/pci_sandbox.c b/drivers/pci/pci_sandbox.c
index 67cd733e61..119a98d061 100644
--- a/drivers/pci/pci_sandbox.c
+++ b/drivers/pci/pci_sandbox.c
@@ -10,15 +10,27 @@
#include <inttypes.h>
#include <pci.h>
+#define FDT_DEV_INFO_CELLS 4
+#define FDT_DEV_INFO_SIZE (FDT_DEV_INFO_CELLS * sizeof(u32))
+
+#define SANDBOX_PCI_DEVFN(d, f) ((d << 3) | f)
+
+struct sandbox_pci_priv {
+ struct {
+ u16 vendor;
+ u16 device;
+ } vendev[256];
+};
+
static int sandbox_pci_write_config(struct udevice *bus, pci_dev_t devfn,
uint offset, ulong value,
enum pci_size_t size)
{
struct dm_pci_emul_ops *ops;
- struct udevice *emul;
+ struct udevice *container, *emul;
int ret;
- ret = sandbox_pci_get_emul(bus, devfn, &emul);
+ ret = sandbox_pci_get_emul(bus, devfn, &container, &emul);
if (ret)
return ret == -ENODEV ? 0 : ret;
ops = pci_get_emul_ops(emul);
@@ -33,14 +45,31 @@ static int sandbox_pci_read_config(struct udevice *bus, pci_dev_t devfn,
enum pci_size_t size)
{
struct dm_pci_emul_ops *ops;
- struct udevice *emul;
+ struct udevice *container, *emul;
+ struct sandbox_pci_priv *priv = dev_get_priv(bus);
int ret;
/* Prepare the default response */
*valuep = pci_get_ff(size);
- ret = sandbox_pci_get_emul(bus, devfn, &emul);
- if (ret)
- return ret == -ENODEV ? 0 : ret;
+ ret = sandbox_pci_get_emul(bus, devfn, &container, &emul);
+ if (ret) {
+ if (!container) {
+ u16 vendor, device;
+
+ devfn = SANDBOX_PCI_DEVFN(PCI_DEV(devfn),
+ PCI_FUNC(devfn));
+ vendor = priv->vendev[devfn].vendor;
+ device = priv->vendev[devfn].device;
+ if (offset == PCI_VENDOR_ID && vendor)
+ *valuep = vendor;
+ else if (offset == PCI_DEVICE_ID && device)
+ *valuep = device;
+
+ return 0;
+ } else {
+ return ret == -ENODEV ? 0 : ret;
+ }
+ }
ops = pci_get_emul_ops(emul);
if (!ops || !ops->read_config)
return -ENOSYS;
@@ -48,6 +77,41 @@ static int sandbox_pci_read_config(struct udevice *bus, pci_dev_t devfn,
return ops->read_config(emul, offset, valuep, size);
}
+static int sandbox_pci_probe(struct udevice *dev)
+{
+ struct sandbox_pci_priv *priv = dev_get_priv(dev);
+ const fdt32_t *cell;
+ u8 pdev, pfn, devfn;
+ int len;
+
+ cell = ofnode_get_property(dev_ofnode(dev), "sandbox,dev-info", &len);
+ if (!cell)
+ return 0;
+
+ if ((len % FDT_DEV_INFO_SIZE) == 0) {
+ int num = len / FDT_DEV_INFO_SIZE;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ debug("dev info #%d: %02x %02x %04x %04x\n", i,
+ fdt32_to_cpu(cell[0]), fdt32_to_cpu(cell[1]),
+ fdt32_to_cpu(cell[2]), fdt32_to_cpu(cell[3]));
+
+ pdev = fdt32_to_cpu(cell[0]);
+ pfn = fdt32_to_cpu(cell[1]);
+ if (pdev > 31 || pfn > 7)
+ continue;
+ devfn = SANDBOX_PCI_DEVFN(pdev, pfn);
+ priv->vendev[devfn].vendor = fdt32_to_cpu(cell[2]);
+ priv->vendev[devfn].device = fdt32_to_cpu(cell[3]);
+
+ cell += FDT_DEV_INFO_CELLS;
+ }
+ }
+
+ return 0;
+}
+
static const struct dm_pci_ops sandbox_pci_ops = {
.read_config = sandbox_pci_read_config,
.write_config = sandbox_pci_write_config,
@@ -63,6 +127,8 @@ U_BOOT_DRIVER(pci_sandbox) = {
.id = UCLASS_PCI,
.of_match = sandbox_pci_ids,
.ops = &sandbox_pci_ops,
+ .probe = sandbox_pci_probe,
+ .priv_auto_alloc_size = sizeof(struct sandbox_pci_priv),
/* Attach an emulator if we can */
.child_post_bind = dm_scan_fdt_dev,