diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 137679a..7035646 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -14,7 +14,9 @@ i2c0 = "/i2c@0"; mmc0 = "/mmc0"; mmc1 = "/mmc1"; - pci0 = &pci; + pci0 = &pci0; + pci1 = &pci1; + pci2 = &pci2; remoteproc1 = &rproc_1; remoteproc2 = &rproc_2; rtc0 = &rtc_0; @@ -295,13 +297,48 @@ compatible = "sandbox,mmc"; }; - pci: pci-controller { + pci0: pci-controller0 { compatible = "sandbox,pci"; device_type = "pci"; #address-cells = <3>; #size-cells = <2>; ranges = <0x02000000 0 0x10000000 0x10000000 0 0x2000 0x01000000 0 0x20000000 0x20000000 0 0x2000>; + pci@0,0 { + compatible = "pci-generic"; + reg = <0x0000 0 0 0 0>; + emul@0,0 { + compatible = "sandbox,swap-case"; + }; + }; + pci@1f,0 { + compatible = "pci-generic"; + reg = <0xf800 0 0 0 0>; + emul@1f,0 { + compatible = "sandbox,swap-case"; + }; + }; + }; + + pci1: pci-controller1 { + compatible = "sandbox,pci"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x02000000 0 0x30000000 0x30000000 0 0x2000 + 0x01000000 0 0x40000000 0x40000000 0 0x2000>; + sandbox,dev-info = <0x08 0x00 0x1234 0x5678 + 0x0c 0x00 0x1234 0x5678>; + }; + + pci2: pci-controller2 { + compatible = "sandbox,pci"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x02000000 0 0x50000000 0x50000000 0 0x2000 + 0x01000000 0 0x60000000 0x60000000 0 0x2000>; + sandbox,dev-info = <0x08 0x00 0x1234 0x5678>; pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>; diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 08863bf..c8ae52b 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -16,6 +16,18 @@ #define SANDBOX_PCI_CLASS_CODE PCI_CLASS_CODE_COMM #define SANDBOX_PCI_CLASS_SUB_CODE PCI_CLASS_SUB_CODE_COMM_SERIAL +#define PCI_CAP_ID_PM_OFFSET 0x50 +#define PCI_CAP_ID_EXP_OFFSET 0x60 +#define PCI_CAP_ID_MSIX_OFFSET 0x70 + +#define PCI_EXT_CAP_ID_ERR_OFFSET 0x100 +#define PCI_EXT_CAP_ID_VC_OFFSET 0x200 +#define PCI_EXT_CAP_ID_DSN_OFFSET 0x300 + +/* Useful for PCI_VDEVICE() macro */ +#define PCI_VENDOR_ID_SANDBOX SANDBOX_PCI_VENDOR_ID +#define SWAP_CASE_DRV_DATA 0x55aa + #define SANDBOX_CLK_RATE 32768 /* System controller driver data */ diff --git a/doc/driver-model/pci-info.txt b/doc/driver-model/pci-info.txt index 52b4389..e1701d1 100644 --- a/doc/driver-model/pci-info.txt +++ b/doc/driver-model/pci-info.txt @@ -133,3 +133,31 @@ When this bus is scanned we will end up with something like this: When accesses go to the pci@1f,0 device they are forwarded to its child, the emulator. + +The sandbox PCI drivers also support dynamic driver binding, allowing device +driver to declare the driver binding information via U_BOOT_PCI_DEVICE(), +eliminating the need to provide any device tree node under the host controller +node. It is required a "sandbox,dev-info" property must be provided in the +host controller node for this functionality to work. + + pci1: pci-controller1 { + compatible = "sandbox,pci"; + ... + sandbox,dev-info = <0x08 0x00 0x1234 0x5678 + 0x0c 0x00 0x1234 0x5678>; + }; + +The "sandbox,dev-info" property specifies all dynamic PCI devices on this bus. +Each dynamic PCI device is encoded as 4 cells a group. The first and second +cells are PCI device number and function number respectively. The third and +fourth cells are PCI vendor ID and device ID respectively. + +When this bus is scanned we will end up with something like this: + + pci [ + ] pci_sandbo |-- pci-controller1 + pci_emul [ ] sandbox_sw | |-- sandbox_swap_case_emul + pci_emul [ ] sandbox_sw | `-- sandbox_swap_case_emul + +Note the difference from the statically declared device nodes is that the +device is directly attached to the host controller, instead of via a container +device like pci@1f,0. diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 2937539..0cfb0fb 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -623,6 +623,42 @@ fail: return ret; } +int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device) +{ + const char *list, *end; + int len; + + list = ofnode_get_property(node, "compatible", &len); + if (!list) + return -ENOENT; + + end = list + len; + while (list < end) { + len = strlen(list); + if (len >= strlen("pciVVVV,DDDD")) { + char *s = strstr(list, "pci"); + + /* + * check if the string is something like pciVVVV,DDDD.RR + * or just pciVVVV,DDDD + */ + if (s && s[7] == ',' && + (s[12] == '.' || s[12] == 0)) { + s += 3; + *vendor = simple_strtol(s, NULL, 16); + + s += 5; + *device = simple_strtol(s, NULL, 16); + + return 0; + } + } + list += (len + 1); + } + + return -ENOENT; +} + int ofnode_read_addr_cells(ofnode node) { if (ofnode_is_np(node)) diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c index b777404..bffb809 100644 --- a/drivers/misc/swap_case.c +++ b/drivers/misc/swap_case.c @@ -118,6 +118,27 @@ static int sandbox_swap_case_read_config(struct udevice *emul, uint offset, *valuep = result; break; } + case PCI_CAPABILITY_LIST: + *valuep = PCI_CAP_ID_PM_OFFSET; + break; + case PCI_CAP_ID_PM_OFFSET: + *valuep = (PCI_CAP_ID_EXP_OFFSET << 8) | PCI_CAP_ID_PM; + break; + case PCI_CAP_ID_EXP_OFFSET: + *valuep = (PCI_CAP_ID_MSIX_OFFSET << 8) | PCI_CAP_ID_EXP; + break; + case PCI_CAP_ID_MSIX_OFFSET: + *valuep = PCI_CAP_ID_MSIX; + break; + case PCI_EXT_CAP_ID_ERR_OFFSET: + *valuep = (PCI_EXT_CAP_ID_VC_OFFSET << 20) | PCI_EXT_CAP_ID_ERR; + break; + case PCI_EXT_CAP_ID_VC_OFFSET: + *valuep = (PCI_EXT_CAP_ID_DSN_OFFSET << 20) | PCI_EXT_CAP_ID_VC; + break; + case PCI_EXT_CAP_ID_DSN_OFFSET: + *valuep = PCI_EXT_CAP_ID_DSN; + break; } return 0; @@ -142,6 +163,8 @@ static int sandbox_swap_case_write_config(struct udevice *emul, uint offset, debug("w bar %d=%lx\n", barnum, value); *bar = value; + /* space indicator (bit#0) is read-only */ + *bar |= barinfo[barnum].type; break; } } @@ -157,11 +180,11 @@ static int sandbox_swap_case_find_bar(struct udevice *emul, unsigned int addr, for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) { unsigned int size = barinfo[barnum].size; + u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE; - if (addr >= plat->bar[barnum] && - addr < plat->bar[barnum] + size) { + if (addr >= base && addr < base + size) { *barnump = barnum; - *offsetp = addr - plat->bar[barnum]; + *offsetp = addr - base; return 0; } } @@ -283,3 +306,10 @@ U_BOOT_DRIVER(sandbox_swap_case_emul) = { .priv_auto_alloc_size = sizeof(struct swap_case_priv), .platdata_auto_alloc_size = sizeof(struct swap_case_platdata), }; + +static struct pci_device_id sandbox_swap_case_supported[] = { + { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_DEVICE_ID), SWAP_CASE_DRV_DATA }, + {}, +}; + +U_BOOT_PCI_DEVICE(sandbox_swap_case_emul, sandbox_swap_case_supported); diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c index 79e2c14..3822758 100644 --- a/drivers/pci/pci-emul-uclass.c +++ b/drivers/pci/pci-emul-uclass.c @@ -11,33 +11,39 @@ #include #include -struct sandbox_pci_priv { +struct sandbox_pci_emul_priv { int dev_count; }; int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, - struct udevice **emulp) + struct udevice **containerp, struct udevice **emulp) { struct udevice *dev; int ret; - ret = pci_bus_find_devfn(bus, find_devfn, &dev); + *containerp = NULL; + ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(find_devfn), &dev); if (ret) { debug("%s: Could not find emulator for dev %x\n", __func__, find_devfn); return ret; } + *containerp = dev; - ret = device_find_first_child(dev, emulp); - if (ret) - return ret; + if (device_get_uclass_id(dev) == UCLASS_PCI_GENERIC) { + ret = device_find_first_child(dev, emulp); + if (ret) + return ret; + } else { + *emulp = dev; + } return *emulp ? 0 : -ENODEV; } static int sandbox_pci_emul_post_probe(struct udevice *dev) { - struct sandbox_pci_priv *priv = dev->uclass->priv; + struct sandbox_pci_emul_priv *priv = dev->uclass->priv; priv->dev_count++; sandbox_set_enable_pci_map(true); @@ -47,7 +53,7 @@ static int sandbox_pci_emul_post_probe(struct udevice *dev) static int sandbox_pci_emul_pre_remove(struct udevice *dev) { - struct sandbox_pci_priv *priv = dev->uclass->priv; + struct sandbox_pci_emul_priv *priv = dev->uclass->priv; priv->dev_count--; sandbox_set_enable_pci_map(priv->dev_count > 0); @@ -60,5 +66,5 @@ UCLASS_DRIVER(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), + .priv_auto_alloc_size = sizeof(struct sandbox_pci_emul_priv), }; diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 46e9c71..e9671d9 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -690,7 +690,7 @@ static int pci_find_and_bind_driver(struct udevice *parent, if (ret) goto error; debug("%s: Match found: %s\n", __func__, drv->name); - dev->driver_data = find_id->driver_data; + dev->driver_data = id->driver_data; *devp = dev; return 0; } @@ -745,6 +745,8 @@ int pci_bind_bus_devices(struct udevice *bus) struct udevice *dev; ulong class; + if (!PCI_FUNC(bdf)) + found_multi = false; if (PCI_FUNC(bdf) && !found_multi) continue; /* Check only the first access, we don't expect problems */ @@ -987,19 +989,18 @@ static int pci_uclass_child_post_bind(struct udevice *dev) if (!dev_of_valid(dev)) return 0; - /* - * We could read vendor, device, class if available. But for now we - * just check the address. - */ pplat = dev_get_parent_platdata(dev); + + /* Extract vendor id and device id if available */ + ofnode_read_pci_vendev(dev_ofnode(dev), &pplat->vendor, &pplat->device); + + /* Extract the devfn from fdt_pci_addr */ ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG, "reg", &addr); - if (ret) { if (ret != -ENOENT) return -EINVAL; } else { - /* extract the devfn from fdt_pci_addr */ pplat->devfn = addr.phys_hi & 0xff00; } @@ -1319,6 +1320,74 @@ void *dm_pci_map_bar(struct udevice *dev, int bar, int flags) return dm_pci_bus_to_virt(dev, pci_bus_addr, flags, 0, MAP_NOCACHE); } +int dm_pci_find_capability(struct udevice *dev, int cap) +{ + u16 status; + u8 header_type; + int ttl = PCI_FIND_CAP_TTL; + u8 id; + u16 ent; + u8 pos; + + dm_pci_read_config16(dev, PCI_STATUS, &status); + if (!(status & PCI_STATUS_CAP_LIST)) + return 0; + + dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type); + if ((header_type & 0x7f) == PCI_HEADER_TYPE_CARDBUS) + pos = PCI_CB_CAPABILITY_LIST; + else + pos = PCI_CAPABILITY_LIST; + + dm_pci_read_config8(dev, pos, &pos); + while (ttl--) { + if (pos < PCI_STD_HEADER_SIZEOF) + break; + pos &= ~3; + dm_pci_read_config16(dev, pos, &ent); + + id = ent & 0xff; + if (id == 0xff) + break; + if (id == cap) + return pos; + pos = (ent >> 8); + } + + return 0; +} + +int dm_pci_find_ext_capability(struct udevice *dev, int cap) +{ + u32 header; + int ttl; + int pos = PCI_CFG_SPACE_SIZE; + + /* minimum 8 bytes per capability */ + ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; + + dm_pci_read_config32(dev, pos, &header); + /* + * If we have no capabilities, this is indicated by cap ID, + * cap version and next pointer all being 0. + */ + if (header == 0) + return 0; + + while (ttl--) { + if (PCI_EXT_CAP_ID(header) == cap) + return pos; + + pos = PCI_EXT_CAP_NEXT(header); + if (pos < PCI_CFG_SPACE_SIZE) + break; + + dm_pci_read_config32(dev, pos, &header); + } + + return 0; +} + UCLASS_DRIVER(pci) = { .id = UCLASS_PCI, .name = "pci", diff --git a/drivers/pci/pci_sandbox.c b/drivers/pci/pci_sandbox.c index 67cd733..119a98d 100644 --- a/drivers/pci/pci_sandbox.c +++ b/drivers/pci/pci_sandbox.c @@ -10,15 +10,27 @@ #include #include +#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, diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index cd08a7e..ab36b74 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -586,6 +586,19 @@ int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, const char *propname, struct fdt_pci_addr *addr); /** + * ofnode_read_pci_vendev() - look up PCI vendor and device id + * + * Look at the compatible property of a device node that represents a PCI + * device and extract pci vendor id and device id from it. + * + * @param node node to examine + * @param vendor vendor id of the pci device + * @param device device id of the pci device + * @return 0 if ok, negative on error + */ +int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device); + +/** * ofnode_read_addr_cells() - Get the number of address cells for a node * * This walks back up the tree to find the closest #address-cells property diff --git a/include/dm/uclass.h b/include/dm/uclass.h index 9fbaa7d..0e882ce 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -302,7 +302,7 @@ int uclass_first_device_err(enum uclass_id id, struct udevice **devp); int uclass_next_device(struct udevice **devp); /** - * uclass_first_device() - Get the first device in a uclass + * uclass_first_device_check() - Get the first device in a uclass * * The device returned is probed if necessary, and ready for use * @@ -318,7 +318,7 @@ int uclass_next_device(struct udevice **devp); int uclass_first_device_check(enum uclass_id id, struct udevice **devp); /** - * uclass_next_device() - Get the next device in a uclass + * uclass_next_device_check() - Get the next device in a uclass * * The device returned is probed if necessary, and ready for use * diff --git a/include/pci.h b/include/pci.h index 8e27cbf..938a839 100644 --- a/include/pci.h +++ b/include/pci.h @@ -17,6 +17,7 @@ * Under PCI, each device has 256 bytes of configuration address space, * of which the first 64 bytes are standardized as follows: */ +#define PCI_STD_HEADER_SIZEOF 64 #define PCI_VENDOR_ID 0x00 /* 16 bits */ #define PCI_DEVICE_ID 0x02 /* 16 bits */ #define PCI_COMMAND 0x04 /* 16 bits */ @@ -271,21 +272,6 @@ #define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ #define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */ -/* From 440ep */ -#define PCI_ERREN 0x48 /* Error Enable */ -#define PCI_ERRSTS 0x49 /* Error Status */ -#define PCI_BRDGOPT1 0x4A /* PCI Bridge Options 1 */ -#define PCI_PLBSESR0 0x4C /* PCI PLB Slave Error Syndrome 0 */ -#define PCI_PLBSESR1 0x50 /* PCI PLB Slave Error Syndrome 1 */ -#define PCI_PLBSEAR 0x54 /* PCI PLB Slave Error Address */ -#define PCI_CAPID 0x58 /* Capability Identifier */ -#define PCI_NEXTITEMPTR 0x59 /* Next Item Pointer */ -#define PCI_PMC 0x5A /* Power Management Capabilities */ -#define PCI_PMCSR 0x5C /* Power Management Control Status */ -#define PCI_PMCSRBSE 0x5E /* PMCSR PCI to PCI Bridge Support Extensions */ -#define PCI_BRDGOPT2 0x60 /* PCI Bridge Options 2 */ -#define PCI_PMSCRR 0x64 /* Power Management State Change Request Re. */ - /* Header type 2 (CardBus bridges) */ #define PCI_CB_CAPABILITY_LIST 0x14 /* 0x15 reserved */ @@ -333,7 +319,21 @@ #define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ #define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ -#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ +#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ +#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ +#define PCI_CAP_ID_VNDR 0x09 /* Vendor-Specific */ +#define PCI_CAP_ID_DBG 0x0A /* Debug port */ +#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ +#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ +#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ +#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ +#define PCI_CAP_ID_SECDEV 0x0F /* Secure Device */ +#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ +#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ +#define PCI_CAP_ID_SATA 0x12 /* SATA Data/Index Conf. */ +#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ +#define PCI_CAP_ID_EA 0x14 /* PCI Enhanced Allocation */ +#define PCI_CAP_ID_MAX PCI_CAP_ID_EA #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ #define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ #define PCI_CAP_SIZEOF 4 @@ -449,6 +449,10 @@ #define PCI_EXT_CAP_ID_SECPCI 0x19 /* Secondary PCIe Capability */ #define PCI_EXT_CAP_ID_PMUX 0x1A /* Protocol Multiplexing */ #define PCI_EXT_CAP_ID_PASID 0x1B /* Process Address Space ID */ +#define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */ +#define PCI_EXT_CAP_ID_L1SS 0x1E /* L1 PM Substates */ +#define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */ +#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PTM /* Include the ID list */ @@ -1308,6 +1312,51 @@ pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t addr, */ void *dm_pci_map_bar(struct udevice *dev, int bar, int flags); +/** + * dm_pci_find_capability() - find a capability + * + * Tell if a device supports a given PCI capability. Returns the + * address of the requested capability structure within the device's + * PCI configuration space or 0 in case the device does not support it. + * + * Possible values for @cap: + * + * %PCI_CAP_ID_MSI Message Signalled Interrupts + * %PCI_CAP_ID_PCIX PCI-X + * %PCI_CAP_ID_EXP PCI Express + * %PCI_CAP_ID_MSIX MSI-X + * + * See PCI_CAP_ID_xxx for the complete capability ID codes. + * + * @dev: PCI device to query + * @cap: capability code + * @return: capability address or 0 if not supported + */ +int dm_pci_find_capability(struct udevice *dev, int cap); + +/** + * dm_pci_find_ext_capability() - find an extended capability + * + * Tell if a device supports a given PCI express extended capability. + * Returns the address of the requested extended capability structure + * within the device's PCI configuration space or 0 in case the device + * does not support it. + * + * Possible values for @cap: + * + * %PCI_EXT_CAP_ID_ERR Advanced Error Reporting + * %PCI_EXT_CAP_ID_VC Virtual Channel + * %PCI_EXT_CAP_ID_DSN Device Serial Number + * %PCI_EXT_CAP_ID_PWR Power Budgeting + * + * See PCI_EXT_CAP_ID_xxx for the complete extended capability ID codes. + * + * @dev: PCI device to query + * @cap: extended capability code + * @return: extended capability address or 0 if not supported + */ +int dm_pci_find_ext_capability(struct udevice *dev, int cap); + #define dm_pci_virt_to_bus(dev, addr, flags) \ dm_pci_phys_to_bus(dev, (virt_to_phys(addr)), (flags)) #define dm_pci_bus_to_virt(dev, addr, flags, len, map_flags) \ @@ -1456,11 +1505,12 @@ struct dm_pci_emul_ops { * * @bus: PCI bus to search * @find_devfn: PCI device and function address (PCI_DEVFN()) + * @containerp: Returns container device if found * @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); + struct udevice **containerp, struct udevice **emulp); #endif /* CONFIG_DM_PCI */ diff --git a/scripts/dtc/pylibfdt/libfdt.i_shipped b/scripts/dtc/pylibfdt/libfdt.i_shipped index e180ee9..0f17c58 100644 --- a/scripts/dtc/pylibfdt/libfdt.i_shipped +++ b/scripts/dtc/pylibfdt/libfdt.i_shipped @@ -18,7 +18,8 @@ * a struct called fdt_property. That struct causes swig to create a class in * libfdt.py called fdt_property(), which confuses things. */ -static int _fdt_property(void *fdt, const char *name, const char *val, int len) +static int fdt_property_stub(void *fdt, const char *name, const char *val, + int len) { return fdt_property(fdt, name, val, len); } @@ -54,6 +55,7 @@ import struct # Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors, # instead of raising an exception. QUIET_NOTFOUND = (NOTFOUND,) +QUIET_NOSPACE = (NOSPACE,) class FdtException(Exception): @@ -119,23 +121,18 @@ def check_err_null(val, quiet=()): raise FdtException(val) return val +class FdtRo(object): + """Class for a read-only device-tree -class Fdt: - """Device tree class, supporting all operations - - The Fdt object is created is created from a device tree binary file, - e.g. with something like: + This is a base class used by FdtRw (read-write access) and FdtSw + (sequential-write access). It implements read-only access to the + device tree. - fdt = Fdt(open("filename.dtb").read()) - - Operations can then be performed using the methods in this class. Each - method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...). + Here are the three classes and when you should use them: - All methods raise an FdtException if an error occurs. To avoid this - behaviour a 'quiet' parameter is provided for some functions. This - defaults to empty, but you can pass a list of errors that you expect. - If one of these errors occurs, the function will return an error number - (e.g. -NOTFOUND). + FdtRo - read-only access to an existing FDT + FdtRw - read-write access to an existing FDT (most common case) + FdtSw - for creating a new FDT, as well as allowing read-only access """ def __init__(self, data): self._fdt = bytearray(data) @@ -157,12 +154,14 @@ class Fdt: Args: nodeoffset: Node offset of previous node - depth: On input, the depth of the node at nodeoffset. On output, the - depth of the returned node + depth: The depth of the node at nodeoffset. This is used to + calculate the depth of the returned node quiet: Errors to ignore (empty to raise on all errors) Returns: - The offset of the next node, if any + Typle: + Offset of the next node, if any, else a -ve error + Depth of the returned node, if any, else undefined Raises: FdtException if no more nodes found or other error occurs @@ -205,7 +204,7 @@ class Fdt: Returns: Magic word """ - return fdt_magic(self._fdt) & 0xffffffff + return fdt_magic(self._fdt) def totalsize(self): """Return the total size of the device tree @@ -213,7 +212,7 @@ class Fdt: Returns: Total tree size in bytes """ - return check_err(fdt_totalsize(self._fdt)) + return fdt_totalsize(self._fdt) def off_dt_struct(self): """Return the start of the device-tree struct area @@ -221,7 +220,7 @@ class Fdt: Returns: Start offset of struct area """ - return check_err(fdt_off_dt_struct(self._fdt)) + return fdt_off_dt_struct(self._fdt) def off_dt_strings(self): """Return the start of the device-tree string area @@ -229,7 +228,7 @@ class Fdt: Returns: Start offset of string area """ - return check_err(fdt_off_dt_strings(self._fdt)) + return fdt_off_dt_strings(self._fdt) def off_mem_rsvmap(self): """Return the start of the memory reserve map @@ -237,7 +236,7 @@ class Fdt: Returns: Start offset of memory reserve map """ - return check_err(fdt_off_mem_rsvmap(self._fdt)) + return fdt_off_mem_rsvmap(self._fdt) def version(self): """Return the version of the device tree @@ -245,7 +244,7 @@ class Fdt: Returns: Version number of the device tree """ - return check_err(fdt_version(self._fdt)) + return fdt_version(self._fdt) def last_comp_version(self): """Return the last compatible version of the device tree @@ -253,7 +252,7 @@ class Fdt: Returns: Last compatible version number of the device tree """ - return check_err(fdt_last_comp_version(self._fdt)) + return fdt_last_comp_version(self._fdt) def boot_cpuid_phys(self): """Return the physical boot CPU ID @@ -261,7 +260,7 @@ class Fdt: Returns: Physical boot CPU ID """ - return check_err(fdt_boot_cpuid_phys(self._fdt)) + return fdt_boot_cpuid_phys(self._fdt) def size_dt_strings(self): """Return the start of the device-tree string area @@ -269,7 +268,7 @@ class Fdt: Returns: Start offset of string area """ - return check_err(fdt_size_dt_strings(self._fdt)) + return fdt_size_dt_strings(self._fdt) def size_dt_struct(self): """Return the start of the device-tree struct area @@ -277,7 +276,7 @@ class Fdt: Returns: Start offset of struct area """ - return check_err(fdt_size_dt_struct(self._fdt)) + return fdt_size_dt_struct(self._fdt) def num_mem_rsv(self, quiet=()): """Return the number of memory reserve-map records @@ -398,26 +397,90 @@ class Fdt: return pdata return Property(pdata[0], pdata[1]) - def get_property(self, nodeoffset, prop_name, quiet=()): - """Obtains a property by name + def getprop(self, nodeoffset, prop_name, quiet=()): + """Get a property from a node Args: - nodeoffset: Offset to the node to check + nodeoffset: Node offset containing property to get prop_name: Name of property to get quiet: Errors to ignore (empty to raise on all errors) Returns: - Property object, or None if not found + Value of property as a Property object (which can be used as a + bytearray/string), or -ve error number. On failure, returns an + integer error Raises: - FdtException on error (e.g. invalid prop_offset or device - tree format) + FdtError if any error occurs (e.g. the property is not found) """ - pdata = check_err_null( - fdt_get_property(self._fdt, nodeoffset, prop_name), quiet) + pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name), + quiet) if isinstance(pdata, (int)): return pdata - return Property(pdata[0], pdata[1]) + return Property(prop_name, bytearray(pdata[0])) + + def get_phandle(self, nodeoffset): + """Get the phandle of a node + + Args: + nodeoffset: Node offset to check + + Returns: + phandle of node, or 0 if the node has no phandle or another error + occurs + """ + return fdt_get_phandle(self._fdt, nodeoffset) + + def parent_offset(self, nodeoffset, quiet=()): + """Get the offset of a node's parent + + Args: + nodeoffset: Node offset to check + quiet: Errors to ignore (empty to raise on all errors) + + Returns: + The offset of the parent node, if any + + Raises: + FdtException if no parent found or other error occurs + """ + return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet) + + def node_offset_by_phandle(self, phandle, quiet=()): + """Get the offset of a node with the given phandle + + Args: + phandle: Phandle to search for + quiet: Errors to ignore (empty to raise on all errors) + + Returns: + The offset of node with that phandle, if any + + Raises: + FdtException if no node found or other error occurs + """ + return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet) + + +class Fdt(FdtRo): + """Device tree class, supporting all operations + + The Fdt object is created is created from a device tree binary file, + e.g. with something like: + + fdt = Fdt(open("filename.dtb").read()) + + Operations can then be performed using the methods in this class. Each + method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...). + + All methods raise an FdtException if an error occurs. To avoid this + behaviour a 'quiet' parameter is provided for some functions. This + defaults to empty, but you can pass a list of errors that you expect. + If one of these errors occurs, the function will return an error number + (e.g. -NOTFOUND). + """ + def __init__(self, data): + FdtRo.__init__(self, data) @staticmethod def create_empty_tree(size, quiet=()): @@ -435,18 +498,18 @@ class Fdt: return err return Fdt(data) - def open_into(self, size, quiet=()): + def resize(self, size, quiet=()): """Move the device tree into a larger or smaller space This creates a new device tree of size @size and moves the existing device tree contents over to that. It can be used to create more space - in a device tree. + in a device tree. Note that the Fdt object remains the same, but it + now has a new bytearray holding the contents. Args: size: Required new size of device tree in bytes """ fdt = bytearray(size) - fdt[:len(self._fdt)] = self._fdt err = check_err(fdt_open_into(self._fdt, fdt, size), quiet) if err: return err @@ -460,6 +523,9 @@ class Fdt: Args: quiet: Errors to ignore (empty to raise on all errors) + Returns: + Error code, or 0 if OK + Raises: FdtException if any error occurs """ @@ -469,79 +535,12 @@ class Fdt: del self._fdt[self.totalsize():] return err - def getprop(self, nodeoffset, prop_name, quiet=()): - """Get a property from a node - - Args: - nodeoffset: Node offset containing property to get - prop_name: Name of property to get - quiet: Errors to ignore (empty to raise on all errors) - - Returns: - Value of property as a string, or -ve error number - - Raises: - FdtError if any error occurs (e.g. the property is not found) - """ - pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name), - quiet) - if isinstance(pdata, (int)): - return pdata - return str(pdata[0]) - - def getprop_obj(self, nodeoffset, prop_name, quiet=()): - """Get a property from a node as a Property object - - Args: - nodeoffset: Node offset containing property to get - prop_name: Name of property to get - quiet: Errors to ignore (empty to raise on all errors) - - Returns: - Property object, or None if not found - - Raises: - FdtError if any error occurs (e.g. the property is not found) - """ - pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name), - quiet) - if isinstance(pdata, (int)): - return None - return Property(prop_name, bytearray(pdata[0])) - - def get_phandle(self, nodeoffset): - """Get the phandle of a node - - Args: - nodeoffset: Node offset to check - - Returns: - phandle of node, or 0 if the node has no phandle or another error - occurs - """ - return fdt_get_phandle(self._fdt, nodeoffset) - - def parent_offset(self, nodeoffset, quiet=()): - """Get the offset of a node's parent - - Args: - nodeoffset: Node offset to check - quiet: Errors to ignore (empty to raise on all errors) - - Returns: - The offset of the parent node, if any - - Raises: - FdtException if no parent found or other error occurs - """ - return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet) - def set_name(self, nodeoffset, name, quiet=()): """Set the name of a node Args: nodeoffset: Node offset of node to update - name: New node name + name: New node name (string without \0) Returns: Error code, or 0 if OK @@ -549,6 +548,8 @@ class Fdt: Raises: FdtException if no parent found or other error occurs """ + if chr(0) in name: + raise ValueError('Property contains embedded nul characters') return check_err(fdt_set_name(self._fdt, nodeoffset, name), quiet) def setprop(self, nodeoffset, prop_name, val, quiet=()): @@ -613,7 +614,8 @@ class Fdt: Args: nodeoffset: Node offset containing the property to create/update prop_name: Name of property - val: Value to write (string without nul terminator) + val: Value to write (string without nul terminator). Unicode is + supposed by encoding to UTF-8 quiet: Errors to ignore (empty to raise on all errors) Returns: @@ -622,7 +624,7 @@ class Fdt: Raises: FdtException if no parent found or other error occurs """ - val += '\0' + val = val.encode('utf-8') + '\0' return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name, val, len(val)), quiet) @@ -638,21 +640,6 @@ class Fdt: """ return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name)) - def node_offset_by_phandle(self, phandle, quiet=()): - """Get the offset of a node with the given phandle - - Args: - phandle: Phandle to search for - quiet: Errors to ignore (empty to raise on all errors) - - Returns: - The offset of node with that phandle, if any - - Raises: - FdtException if no node found or other error occurs - """ - return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet) - def del_node(self, nodeoffset): """Delete a node @@ -696,16 +683,20 @@ class Property(bytearray): return self.as_cell('q') def as_str(self): - return self[:-1] + """Unicode is supported by decoding from UTF-8""" + if self[-1] != 0: + raise ValueError('Property lacks nul termination') + if 0 in self[:-1]: + raise ValueError('Property contains embedded nul characters') + return self[:-1].decode('utf-8') -class FdtSw(object): +class FdtSw(FdtRo): """Software interface to create a device tree from scratch The methods in this class work by adding to an existing 'partial' device tree buffer of a fixed size created by instantiating this class. When the - tree is complete, call finish() to complete the device tree so that it can - be used. + tree is complete, call as_fdt() to obtain a device tree ready to be used. Similarly with nodes, a new node is started with begin_node() and finished with end_node(). @@ -713,58 +704,87 @@ class FdtSw(object): The context manager functions can be used to make this a bit easier: # First create the device tree with a node and property: - with FdtSw(small_size) as sw: - with sw.AddNode('node'): - sw.property_u32('reg', 2) - fdt = sw.AsFdt() + sw = FdtSw() + with sw.add_node('node'): + sw.property_u32('reg', 2) + fdt = sw.as_fdt() # Now we can use it as a real device tree fdt.setprop_u32(0, 'reg', 3) + + The size hint provides a starting size for the space to be used by the + device tree. This will be increased automatically as needed as new items + are added to the tree. """ - def __init__(self, size, quiet=()): - fdtrw = bytearray(size) - err = check_err(fdt_create(fdtrw, size)) - if err: - return err - self._fdtrw = fdtrw + INC_SIZE = 1024 # Expand size by this much when out of space - def __enter__(self): - """Contact manager to use to create a device tree via software""" - return self + def __init__(self, size_hint=None): + """Create a new FdtSw object - def __exit__(self, type, value, traceback): - check_err(fdt_finish(self._fdtrw)) + Args: + size_hint: A hint as to the initial size to use + + Raises: + ValueError if size_hint is negative - def AsFdt(self): + Returns: + FdtSw object on success, else integer error code (if not raising) + """ + if not size_hint: + size_hint = self.INC_SIZE + fdtsw = bytearray(size_hint) + err = check_err(fdt_create(fdtsw, size_hint)) + if err: + return err + self._fdt = fdtsw + + def as_fdt(self): """Convert a FdtSw into an Fdt so it can be accessed as normal - Note that finish() must be called before this function will work. If - you are using the context manager (see 'with' code in the FdtSw class - comment) then this will happen automatically. + Creates a new Fdt object from the work-in-progress device tree. This + does not call fdt_finish() on the current object, so it is possible to + add more nodes/properties and call as_fdt() again to get an updated + tree. Returns: Fdt object allowing access to the newly created device tree """ - return Fdt(self._fdtrw) + fdtsw = bytearray(self._fdt) + check_err(fdt_finish(fdtsw)) + return Fdt(fdtsw) - def resize(self, size, quiet=()): + def check_space(self, val): + """Check if we need to add more space to the FDT + + This should be called with the error code from an operation. If this is + -NOSPACE then the FDT will be expanded to have more space, and True will + be returned, indicating that the operation needs to be tried again. + + Args: + val: Return value from the operation that was attempted + + Returns: + True if the operation must be retried, else False + """ + if check_err(val, QUIET_NOSPACE) < 0: + self.resize(len(self._fdt) + self.INC_SIZE) + return True + return False + + def resize(self, size): """Resize the buffer to accommodate a larger tree Args: size: New size of tree - quiet: Errors to ignore (empty to raise on all errors) Raises: - FdtException if no node found or other error occurs + FdtException on any error """ fdt = bytearray(size) - fdt[:len(self._fdtrw)] = self._fdtrw - err = check_err(fdt_resize(self._fdtrw, fdt, size), quiet) - if err: - return err - self._fdtrw = fdt + err = check_err(fdt_resize(self._fdt, fdt, size)) + self._fdt = fdt - def add_reservemap_entry(self, addr, size, quiet=()): + def add_reservemap_entry(self, addr, size): """Add a new memory reserve map entry Once finished adding, you must call finish_reservemap(). @@ -772,26 +792,24 @@ class FdtSw(object): Args: addr: 64-bit start address size: 64-bit size - quiet: Errors to ignore (empty to raise on all errors) Raises: - FdtException if no node found or other error occurs + FdtException on any error """ - return check_err(fdt_add_reservemap_entry(self._fdtrw, addr, size), - quiet) + while self.check_space(fdt_add_reservemap_entry(self._fdt, addr, + size)): + pass - def finish_reservemap(self, quiet=()): + def finish_reservemap(self): """Indicate that there are no more reserve map entries to add - Args: - quiet: Errors to ignore (empty to raise on all errors) - Raises: - FdtException if no node found or other error occurs + FdtException on any error """ - return check_err(fdt_finish_reservemap(self._fdtrw), quiet) + while self.check_space(fdt_finish_reservemap(self._fdt)): + pass - def begin_node(self, name, quiet=()): + def begin_node(self, name): """Begin a new node Use this before adding properties to the node. Then call end_node() to @@ -800,14 +818,14 @@ class FdtSw(object): Args: name: Name of node to begin - quiet: Errors to ignore (empty to raise on all errors) Raises: - FdtException if no node found or other error occurs + FdtException on any error """ - return check_err(fdt_begin_node(self._fdtrw, name), quiet) + while self.check_space(fdt_begin_node(self._fdt, name)): + pass - def property_string(self, name, string, quiet=()): + def property_string(self, name, string): """Add a property with a string value The string will be nul-terminated when written to the device tree @@ -815,14 +833,14 @@ class FdtSw(object): Args: name: Name of property to add string: String value of property - quiet: Errors to ignore (empty to raise on all errors) Raises: - FdtException if no node found or other error occurs + FdtException on any error """ - return check_err(fdt_property_string(self._fdtrw, name, string), quiet) + while self.check_space(fdt_property_string(self._fdt, name, string)): + pass - def property_u32(self, name, val, quiet=()): + def property_u32(self, name, val): """Add a property with a 32-bit value Write a single-cell value to the device tree @@ -830,14 +848,14 @@ class FdtSw(object): Args: name: Name of property to add val: Value of property - quiet: Errors to ignore (empty to raise on all errors) Raises: - FdtException if no node found or other error occurs + FdtException on any error """ - return check_err(fdt_property_u32(self._fdtrw, name, val), quiet) + while self.check_space(fdt_property_u32(self._fdt, name, val)): + pass - def property_u64(self, name, val, quiet=()): + def property_u64(self, name, val): """Add a property with a 64-bit value Write a double-cell value to the device tree in big-endian format @@ -845,14 +863,14 @@ class FdtSw(object): Args: name: Name of property to add val: Value of property - quiet: Errors to ignore (empty to raise on all errors) Raises: - FdtException if no node found or other error occurs + FdtException on any error """ - return check_err(fdt_property_u64(self._fdtrw, name, val), quiet) + while self.check_space(fdt_property_u64(self._fdt, name, val)): + pass - def property_cell(self, name, val, quiet=()): + def property_cell(self, name, val): """Add a property with a single-cell value Write a single-cell value to the device tree @@ -863,11 +881,12 @@ class FdtSw(object): quiet: Errors to ignore (empty to raise on all errors) Raises: - FdtException if no node found or other error occurs + FdtException on any error """ - return check_err(fdt_property_cell(self._fdtrw, name, val), quiet) + while self.check_space(fdt_property_cell(self._fdt, name, val)): + pass - def property(self, name, val, quiet=()): + def property(self, name, val): """Add a property Write a new property with the given value to the device tree. The value @@ -879,11 +898,13 @@ class FdtSw(object): quiet: Errors to ignore (empty to raise on all errors) Raises: - FdtException if no node found or other error occurs + FdtException on any error """ - return check_err(_fdt_property(self._fdtrw, name, val, len(val)), quiet) + while self.check_space(fdt_property_stub(self._fdt, name, val, + len(val))): + pass - def end_node(self, quiet=()): + def end_node(self): """End a node Use this after adding properties to a node to close it off. You can also @@ -893,24 +914,12 @@ class FdtSw(object): quiet: Errors to ignore (empty to raise on all errors) Raises: - FdtException if no node found or other error occurs - """ - return check_err(fdt_end_node(self._fdtrw), quiet) - - def finish(self, quiet=()): - """Finish writing the device tree - - This closes off the device tree ready for use - - Args: - quiet: Errors to ignore (empty to raise on all errors) - - Raises: - FdtException if no node found or other error occurs + FdtException on any error """ - return check_err(fdt_finish(self._fdtrw), quiet) + while self.check_space(fdt_end_node(self._fdt)): + pass - def AddNode(self, name): + def add_node(self, name): """Create a new context for adding a node When used in a 'with' clause this starts a new node and finishes it @@ -919,7 +928,7 @@ class FdtSw(object): Args: name: Name of node to add """ - return NodeAdder(self._fdtrw, name) + return NodeAdder(self, name) class NodeAdder(): @@ -927,26 +936,30 @@ class NodeAdder(): This allows you to add nodes in a more natural way: - with fdtsw.AddNode('name'): + with fdtsw.add_node('name'): fdtsw.property_string('test', 'value') The node is automatically completed with a call to end_node() when the context exits. """ - def __init__(self, fdt, name): - self._fdt = fdt + def __init__(self, fdtsw, name): + self._fdt = fdtsw self._name = name def __enter__(self): - check_err(fdt_begin_node(self._fdt, self._name)) + self._fdt.begin_node(self._name) def __exit__(self, type, value, traceback): - check_err(fdt_end_node(self._fdt)) + self._fdt.end_node() %} %rename(fdt_property) fdt_property_func; -typedef int fdt32_t; +/* + * fdt32_t is a big-endian 32-bit value defined to uint32_t in libfdt_env.h + * so use the same type here. + */ +typedef uint32_t fdt32_t; %include "libfdt/fdt.h" @@ -1039,16 +1052,17 @@ typedef int fdt32_t; %warnfilter(302) fdt_property; /* These are macros in the header so have to be redefined here */ -int fdt_magic(const void *fdt); -int fdt_totalsize(const void *fdt); -int fdt_off_dt_struct(const void *fdt); -int fdt_off_dt_strings(const void *fdt); -int fdt_off_mem_rsvmap(const void *fdt); -int fdt_version(const void *fdt); -int fdt_last_comp_version(const void *fdt); -int fdt_boot_cpuid_phys(const void *fdt); -int fdt_size_dt_strings(const void *fdt); -int fdt_size_dt_struct(const void *fdt); +uint32_t fdt_magic(const void *fdt); +uint32_t fdt_totalsize(const void *fdt); +uint32_t fdt_off_dt_struct(const void *fdt); +uint32_t fdt_off_dt_strings(const void *fdt); +uint32_t fdt_off_mem_rsvmap(const void *fdt); +uint32_t fdt_version(const void *fdt); +uint32_t fdt_last_comp_version(const void *fdt); +uint32_t fdt_boot_cpuid_phys(const void *fdt); +uint32_t fdt_size_dt_strings(const void *fdt); +uint32_t fdt_size_dt_struct(const void *fdt); + int fdt_property_string(void *fdt, const char *name, const char *val); int fdt_property_cell(void *fdt, const char *name, uint32_t val); @@ -1056,6 +1070,6 @@ int fdt_property_cell(void *fdt, const char *name, uint32_t val); * This function has a stub since the name fdt_property is used for both a * function and a struct, which confuses SWIG. */ -int _fdt_property(void *fdt, const char *name, const char *val, int len); +int fdt_property_stub(void *fdt, const char *name, const char *val, int len); %include <../libfdt/libfdt.h> diff --git a/test/dm/pci.c b/test/dm/pci.c index 47b5d22..8699700 100644 --- a/test/dm/pci.c +++ b/test/dm/pci.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -20,28 +21,71 @@ static int dm_test_pci_base(struct unit_test_state *uts) } DM_TEST(dm_test_pci_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -/* Test that sandbox PCI bus numbering works correctly */ -static int dm_test_pci_busnum(struct unit_test_state *uts) +/* Test that sandbox PCI bus numbering and device works correctly */ +static int dm_test_pci_busdev(struct unit_test_state *uts) { struct udevice *bus; + struct udevice *swap; + u16 vendor, device; + /* Test bus#0 and its devices */ ut_assertok(uclass_get_device_by_seq(UCLASS_PCI, 0, &bus)); + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x00, 0), &swap)); + vendor = 0; + ut_assertok(dm_pci_read_config16(swap, PCI_VENDOR_ID, &vendor)); + ut_asserteq(SANDBOX_PCI_VENDOR_ID, vendor); + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap)); + device = 0; + ut_assertok(dm_pci_read_config16(swap, PCI_DEVICE_ID, &device)); + ut_asserteq(SANDBOX_PCI_DEVICE_ID, device); + + /* Test bus#1 and its devices */ + ut_assertok(uclass_get_device_by_seq(UCLASS_PCI, 1, &bus)); + + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(1, 0x08, 0), &swap)); + vendor = 0; + ut_assertok(dm_pci_read_config16(swap, PCI_VENDOR_ID, &vendor)); + ut_asserteq(SANDBOX_PCI_VENDOR_ID, vendor); + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(1, 0x0c, 0), &swap)); + device = 0; + ut_assertok(dm_pci_read_config16(swap, PCI_DEVICE_ID, &device)); + ut_asserteq(SANDBOX_PCI_DEVICE_ID, device); + return 0; } -DM_TEST(dm_test_pci_busnum, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); +DM_TEST(dm_test_pci_busdev, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); /* Test that we can use the swapcase device correctly */ static int dm_test_pci_swapcase(struct unit_test_state *uts) { - struct udevice *emul, *swap; + struct udevice *swap; ulong io_addr, mem_addr; char *ptr; - /* Check that asking for the device automatically fires up PCI */ - ut_assertok(uclass_get_device(UCLASS_PCI_EMUL, 0, &emul)); + /* Check that asking for the device 0 automatically fires up PCI */ + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x00, 0), &swap)); + + /* First test I/O */ + io_addr = dm_pci_read_bar32(swap, 0); + outb(2, io_addr); + ut_asserteq(2, inb(io_addr)); + + /* + * Now test memory mapping - note we must unmap and remap to cause + * the swapcase emulation to see our data and response. + */ + mem_addr = dm_pci_read_bar32(swap, 1); + ptr = map_sysmem(mem_addr, 20); + strcpy(ptr, "This is a TesT"); + unmap_sysmem(ptr); + + ptr = map_sysmem(mem_addr, 20); + ut_asserteq_str("tHIS IS A tESt", ptr); + unmap_sysmem(ptr); + + /* Check that asking for the device 1 automatically fires up PCI */ ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap)); - ut_assert(device_active(swap)); /* First test I/O */ io_addr = dm_pci_read_bar32(swap, 0); @@ -64,3 +108,115 @@ static int dm_test_pci_swapcase(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_pci_swapcase, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test that we can dynamically bind the device driver correctly */ +static int dm_test_pci_drvdata(struct unit_test_state *uts) +{ + struct udevice *bus, *swap; + + /* Check that asking for the device automatically fires up PCI */ + ut_assertok(uclass_get_device_by_seq(UCLASS_PCI, 1, &bus)); + + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(1, 0x08, 0), &swap)); + ut_asserteq(SWAP_CASE_DRV_DATA, swap->driver_data); + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(1, 0x0c, 0), &swap)); + ut_asserteq(SWAP_CASE_DRV_DATA, swap->driver_data); + + return 0; +} +DM_TEST(dm_test_pci_drvdata, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test that devices on PCI bus#2 can be accessed correctly */ +static int dm_test_pci_mixed(struct unit_test_state *uts) +{ + /* PCI bus#2 has both statically and dynamic declared devices */ + struct udevice *bus, *swap; + u16 vendor, device; + ulong io_addr, mem_addr; + char *ptr; + + ut_assertok(uclass_get_device_by_seq(UCLASS_PCI, 2, &bus)); + + /* Test the dynamic device */ + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(2, 0x08, 0), &swap)); + vendor = 0; + ut_assertok(dm_pci_read_config16(swap, PCI_VENDOR_ID, &vendor)); + ut_asserteq(SANDBOX_PCI_VENDOR_ID, vendor); + + /* First test I/O */ + io_addr = dm_pci_read_bar32(swap, 0); + outb(2, io_addr); + ut_asserteq(2, inb(io_addr)); + + /* + * Now test memory mapping - note we must unmap and remap to cause + * the swapcase emulation to see our data and response. + */ + mem_addr = dm_pci_read_bar32(swap, 1); + ptr = map_sysmem(mem_addr, 30); + strcpy(ptr, "This is a TesT oN dYNAMIc"); + unmap_sysmem(ptr); + + ptr = map_sysmem(mem_addr, 30); + ut_asserteq_str("tHIS IS A tESt On DynamiC", ptr); + unmap_sysmem(ptr); + + /* Test the static device */ + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(2, 0x1f, 0), &swap)); + device = 0; + ut_assertok(dm_pci_read_config16(swap, PCI_DEVICE_ID, &device)); + ut_asserteq(SANDBOX_PCI_DEVICE_ID, device); + + /* First test I/O */ + io_addr = dm_pci_read_bar32(swap, 0); + outb(2, io_addr); + ut_asserteq(2, inb(io_addr)); + + /* + * Now test memory mapping - note we must unmap and remap to cause + * the swapcase emulation to see our data and response. + */ + mem_addr = dm_pci_read_bar32(swap, 1); + ptr = map_sysmem(mem_addr, 30); + strcpy(ptr, "This is a TesT oN sTATIc"); + unmap_sysmem(ptr); + + ptr = map_sysmem(mem_addr, 30); + ut_asserteq_str("tHIS IS A tESt On StatiC", ptr); + unmap_sysmem(ptr); + + return 0; +} +DM_TEST(dm_test_pci_mixed, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test looking up PCI capability and extended capability */ +static int dm_test_pci_cap(struct unit_test_state *uts) +{ + struct udevice *bus, *swap; + int cap; + + ut_assertok(uclass_get_device_by_seq(UCLASS_PCI, 0, &bus)); + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap)); + + /* look up PCI_CAP_ID_EXP */ + cap = dm_pci_find_capability(swap, PCI_CAP_ID_EXP); + ut_asserteq(PCI_CAP_ID_EXP_OFFSET, cap); + + /* look up PCI_CAP_ID_PCIX */ + cap = dm_pci_find_capability(swap, PCI_CAP_ID_PCIX); + ut_asserteq(0, cap); + + ut_assertok(uclass_get_device_by_seq(UCLASS_PCI, 1, &bus)); + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(1, 0x08, 0), &swap)); + + /* look up PCI_EXT_CAP_ID_DSN */ + cap = dm_pci_find_ext_capability(swap, PCI_EXT_CAP_ID_DSN); + ut_asserteq(PCI_EXT_CAP_ID_DSN_OFFSET, cap); + + /* look up PCI_EXT_CAP_ID_SRIOV */ + cap = dm_pci_find_ext_capability(swap, PCI_EXT_CAP_ID_SRIOV); + ut_asserteq(0, cap); + + return 0; +} +DM_TEST(dm_test_pci_cap, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py index d36179b..55baa38 100644 --- a/tools/dtoc/fdt.py +++ b/tools/dtoc/fdt.py @@ -287,7 +287,7 @@ class Node: fdt_obj = self._fdt._fdt_obj if fdt_obj.setprop_u32(self.Offset(), prop_name, 0, (libfdt.NOSPACE,)) == -libfdt.NOSPACE: - fdt_obj.open_into(fdt_obj.totalsize() + 1024) + fdt_obj.resize(fdt_obj.totalsize() + 1024) fdt_obj.setprop_u32(self.Offset(), prop_name, 0) self.props[prop_name] = Prop(self, -1, prop_name, '\0' * 4) self._fdt.Invalidate() diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py index 6fe03ac..e88d19f 100755 --- a/tools/dtoc/test_fdt.py +++ b/tools/dtoc/test_fdt.py @@ -233,7 +233,7 @@ class TestProp(unittest.TestCase): Return fdt.Prop object for this property """ - p = self.fdt.get_property(self.node.Offset(), prop_name) + p = self.fdt.getprop(self.node.Offset(), prop_name) return fdt.Prop(self.node, -1, prop_name, p) def testMakeProp(self): diff --git a/tools/patman/test/0002-fdt-Correct-cast-for-sandbox-in-fdtdec_setup_memory_.patch b/tools/patman/test/0002-fdt-Correct-cast-for-sandbox-in-fdtdec_setup_mem_siz.patch similarity index 100% rename from tools/patman/test/0002-fdt-Correct-cast-for-sandbox-in-fdtdec_setup_memory_.patch rename to tools/patman/test/0002-fdt-Correct-cast-for-sandbox-in-fdtdec_setup_mem_siz.patch