From patchwork Wed Feb 18 21:10:43 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 441156 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id AFBEC140111 for ; Thu, 19 Feb 2015 08:14:09 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id BE38C4B672; Wed, 18 Feb 2015 22:13:48 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 6aJThlVws-Kl; Wed, 18 Feb 2015 22:13:48 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 49B954B67B; Wed, 18 Feb 2015 22:13:28 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 0FA234A054 for ; Wed, 18 Feb 2015 22:13:17 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id evr0Jql5SgRk for ; Wed, 18 Feb 2015 22:13:16 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-ie0-f201.google.com (mail-ie0-f201.google.com [209.85.223.201]) by theia.denx.de (Postfix) with ESMTPS id 222DB4A056 for ; Wed, 18 Feb 2015 22:13:14 +0100 (CET) Received: by iecrd18 with SMTP id rd18so1396114iec.1 for ; Wed, 18 Feb 2015 13:13:13 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=3OxmO9mdq+Yi2MlwkPlCPNHl3+pbMgGsVIF33S+80Ac=; b=cz752l29RONmxjY+Dq6Uec6dQj98naHBWkGjnr8TRyHpPpAgxjV19xYqfUvFvIJUlJ CbjFSyC4BKAy876pD0tQ0HHe/JMwMe6jaMfuoywTGUR3F5RtLcQG5N6XkJh1uqr1gIgh NPWMQv/875dgOmGHpetF9zOFhQlTkfdlM62yPnvEbZ+u3e+J9HN7z1SW/lZ8YiGJ8502 dl8ZBx8XVZlydDflBs/LPhd2m26Hd4BZ+LKpCsgfXtVYsGjoJJ/+DWY3pBpOP8ug4dPc A2WMbMgEv+PdwKFrU0nCQgJ+NKjqKZNpG1Tg51BdkiFFW5MWKEdkZXy7FUnxuzQCjMQ5 rBqw== X-Gm-Message-State: ALoCoQkjsXWT2QfHmCmco+2GfhSYodKi6E+LSk3oWIn3yTD++TFEAPKmhOyT2NH0+0vNK5lRei37 X-Received: by 10.182.96.131 with SMTP id ds3mr1233359obb.35.1424293993483; Wed, 18 Feb 2015 13:13:13 -0800 (PST) Received: from corpmail-nozzle1-1.hot.corp.google.com ([100.108.1.104]) by gmr-mx.google.com with ESMTPS id kt5si4807400qcb.3.2015.02.18.13.13.12 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 18 Feb 2015 13:13:13 -0800 (PST) Received: from kaki.bld.corp.google.com ([172.29.216.32]) by corpmail-nozzle1-1.hot.corp.google.com with ESMTP id T5pbBGlN.2; Wed, 18 Feb 2015 13:13:13 -0800 Received: by kaki.bld.corp.google.com (Postfix, from userid 121222) id 80722221997; Wed, 18 Feb 2015 14:13:12 -0700 (MST) From: Simon Glass To: U-Boot Mailing List Date: Wed, 18 Feb 2015 14:10:43 -0700 Message-Id: <1424293849-22193-17-git-send-email-sjg@chromium.org> X-Mailer: git-send-email 2.2.0.rc0.207.ga3a616c In-Reply-To: <1424293849-22193-1-git-send-email-sjg@chromium.org> References: <1424293849-22193-1-git-send-email-sjg@chromium.org> Cc: Tom Rini Subject: [U-Boot] [PATCH 16/22] dm: sandbox: pci: Add a PCI emulation uclass X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" 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 --- drivers/pci/Makefile | 1 + drivers/pci/pci-emul-uclass.c | 67 ++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/pci.h | 108 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 drivers/pci/pci-emul-uclass.c diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 9e2e5f9..c1c2ae3 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -8,6 +8,7 @@ ifneq ($(CONFIG_DM_PCI),) obj-$(CONFIG_PCI) += pci-uclass.o pci_compat.o obj-$(CONFIG_PCI_SANDBOX) += pci_sandbox.o +obj-$(CONFIG_SANDBOX) += pci-emul-uclass.o else obj-$(CONFIG_PCI) += pci.o endif diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c new file mode 100644 index 0000000..0f8e3c9 --- /dev/null +++ b/drivers/pci/pci-emul-uclass.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct sandbox_pci_priv { + int dev_count; +}; + +int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, + struct udevice **emulp) +{ + struct udevice *dev; + int ret; + + ret = pci_bus_find_devfn(bus, find_devfn, &dev); + if (ret) { + debug("%s: Could not find emulator for dev %x\n", __func__, + find_devfn); + return ret; + } + + ret = device_find_first_child(dev, emulp); + if (ret) + return ret; + + return *emulp ? 0 : -ENODEV; +} + +static int sandbox_pci_emul_post_probe(struct udevice *dev) +{ + struct sandbox_pci_priv *priv = dev->uclass->priv; + + priv->dev_count++; + sandbox_set_enable_pci_map(true); + + return 0; +} + +static int sandbox_pci_emul_pre_remove(struct udevice *dev) +{ + struct sandbox_pci_priv *priv = dev->uclass->priv; + + priv->dev_count--; + sandbox_set_enable_pci_map(priv->dev_count > 0); + + return 0; +} + +UCLASS_DRIVER(pci_emul) = { + .id = UCLASS_PCI_EMUL, + .name = "pci_emul", + .post_probe = sandbox_pci_emul_post_probe, + .pre_remove = sandbox_pci_emul_pre_remove, + .priv_auto_alloc_size = sizeof(struct sandbox_pci_priv), +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index b984407..0b6e850 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -20,6 +20,7 @@ enum uclass_id { UCLASS_TEST_BUS, UCLASS_SPI_EMUL, /* sandbox SPI device emulator */ UCLASS_I2C_EMUL, /* sandbox I2C device emulator */ + UCLASS_PCI_EMUL, /* sandbox PCI device emulator */ UCLASS_SIMPLE_BUS, /* U-Boot uclasses start here */ diff --git a/include/pci.h b/include/pci.h index 07345fd..07b1e9a 100644 --- a/include/pci.h +++ b/include/pci.h @@ -992,6 +992,114 @@ static inline int pci_read_config_byte(pci_dev_t pcidev, int offset, return pci_read_config8(pcidev, offset, valuep); } +/** + * struct dm_pci_emul_ops - PCI device emulator operations + */ +struct dm_pci_emul_ops { + /** + * get_devfn(): Check which device and function this emulators + * + * @dev: device to check + * @return the device and function this emulates, or -ve on error + */ + int (*get_devfn)(struct udevice *dev); + /** + * read_config() - Read a PCI configuration value + * + * @dev: Emulated device to read from + * @offset: Byte offset within the device's configuration space + * @valuep: Place to put the returned value + * @size: Access size + * @return 0 if OK, -ve on error + */ + int (*read_config)(struct udevice *dev, uint offset, ulong *valuep, + enum pci_size_t size); + /** + * write_config() - Write a PCI configuration value + * + * @dev: Emulated device to write to + * @offset: Byte offset within the device's configuration space + * @value: Value to write + * @size: Access size + * @return 0 if OK, -ve on error + */ + int (*write_config)(struct udevice *dev, uint offset, ulong value, + enum pci_size_t size); + /** + * read_io() - Read a PCI I/O value + * + * @dev: Emulated device to read from + * @addr: I/O address to read + * @valuep: Place to put the returned value + * @size: Access size + * @return 0 if OK, -ENOENT if @addr is not mapped by this device, + * other -ve value on error + */ + int (*read_io)(struct udevice *dev, unsigned int addr, ulong *valuep, + enum pci_size_t size); + /** + * write_io() - Write a PCI I/O value + * + * @dev: Emulated device to write from + * @addr: I/O address to write + * @value: Value to write + * @size: Access size + * @return 0 if OK, -ENOENT if @addr is not mapped by this device, + * other -ve value on error + */ + int (*write_io)(struct udevice *dev, unsigned int addr, + ulong value, enum pci_size_t size); + /** + * map_physmem() - Map a device into sandbox memory + * + * @dev: Emulated device to map + * @addr: Memory address, normally corresponding to a PCI BAR. + * The device should have been configured to have a BAR + * at this address. + * @lenp: On entry, the size of the area to map, On exit it is + * updated to the size actually mapped, which may be less + * if the device has less space + * @ptrp: Returns a pointer to the mapped address. The device's + * space can be accessed as @lenp bytes starting here + * @return 0 if OK, -ENOENT if @addr is not mapped by this device, + * other -ve value on error + */ + int (*map_physmem)(struct udevice *dev, phys_addr_t addr, + unsigned long *lenp, void **ptrp); + /** + * unmap_physmem() - undo a memory mapping + * + * This must be called after map_physmem() to undo the mapping. + * Some devices can use this to check what has been written into + * their mapped memory and perform an operations they require on it. + * In this way, map/unmap can be used as a sort of handshake between + * the emulated device and its users. + * + * @dev: Emuated device to unmap + * @vaddr: Mapped memory address, as passed to map_physmem() + * @len: Size of area mapped, as returned by map_physmem() + * @return 0 if OK, -ve on error + */ + int (*unmap_physmem)(struct udevice *dev, const void *vaddr, + unsigned long len); +}; + +/* Get access to a PCI device emulator's operations */ +#define pci_get_emul_ops(dev) ((struct dm_pci_emul_ops *)(dev)->driver->ops) + +/** + * sandbox_pci_get_emul() - Get the emulation device for a PCI device + * + * Searches for a suitable emulator for the given PCI bus device + * + * @bus: PCI bus to search + * @find_devfn: PCI device and function address (PCI_DEVFN()) + * @emulp: Returns emulated device if found + * @return 0 if found, -ENODEV if not found + */ +int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, + struct udevice **emulp); + #endif #endif /* __ASSEMBLY__ */