aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/arm/setup.c
Commit message (Collapse)AuthorAgeFilesLines
* xen/arm: Add CPU ID for Broadcom Brahma-B15Marc Carino2013-10-181-0/+1
| | | | | | | | | Let Xen recognize the Broadcom Brahma-B15 CPU by adding the appropriate MIDR mask to the initialization phase. Further, ensure that the console output properly reports the CPU manufacturer as "Broadcom Corporation". Signed-off-by: Marc Carino <marc.ceeeee@gmail.com> Acked-by: Ian Campbell <ian.campbell@citrix.com>
* xen: arm: move smp_init_cpus to smpboot.cIan Campbell2013-09-271-125/+0
| | | | | | | Seems like a better home. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Julien Grall <julien.grall@linaro.org>
* xen: arm: rewrite start of day page table and cpu bring upIan Campbell2013-09-271-7/+23
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This is unfortunately a rather large monolithic patch. Rather than bringing up all CPUs in lockstep as we setup paging and relocate Xen instead create a simplified set of dedicated boot time pagetables. This allows secondary CPUs to remain powered down or in the firmware until we actually want to enable them. The bringup is now done later on in C and can be driven by DT etc. I have included code for the vexpress platform, but other platforms will need to be added. The mechanism for deciding how to bring up a CPU differs between arm32 and arm64. On arm32 it is essentially a per-platform property, with the exception of PSCI which can be implemented globally (but isn't here). On arm64 there is a per-cpu property in the device tree. Secondary CPUs are brought up directly into the relocated Xen image, instead of relying on being able to launch on the unrelocated Xen and hoping that it hasn't been clobbered. As part of this change drop support for switching from secure mode to NS HYP as well as the early CPU kick. Xen now requires that it is launched in NS HYP mode and that firmware configure things such that secondary CPUs can be woken up by a primarly CPU in HYP mode. This may require fixes to bootloaders or the use of a boot wrapper. The changes done here (re)exposed an issue with relocating Xen and the compiler spilling values to the stack between the copy and the actual switch to the relocaed copy of Xen in setup_pagetables. Therefore switch to doing the copy and switch in a single asm function where we can control precisely what gets spilled to the stack etc. Since we now have a separate set of boot pagetables it is much easier to build the real Xen pagetables inplace before relocating rather than the more complex approach of rewriting the pagetables in the relocated copy before switching. This will also enable Xen to be loaded above the 4GB boundary on 64-bit. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> Acked-by: Julien Grall <julien.grall@linaro.org>
* xen: arm: make sure we stay within the memory bank during mm setupIan Campbell2013-09-271-3/+10
| | | | | | | | | | Otherwise if there is a module in another bank we can run off the end. Rename *n to *end to make it clearer what is happening. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> Acked-by: Julien Grall <julien.grall@linaro.org>
* xen: arm: Log the raw MIDR on boot.Ian Campbell2013-09-271-2/+3
| | | | | | Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Julien Grall <julien.grall@linaro.org> Acked-by: Tim Deegan <tim@xen.org>
* xen: arm: Load xen under 4GB on 32-bitIan Campbell2013-09-271-0/+8
| | | | | | | | We need to be able to use a 1:1 mapping during bring up. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Julien Grall <julien.grall@linaro.org> Acked-by: Tim Deegan <tim@xen.org>
* xen/arm: print the location of the Xen heap on 32 bitIan Campbell2013-09-261-2/+4
| | | | | | Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Reviewed-by: Julien Grall <julien.grall@linaro.org> Acked-by: Tim Deegan <tim@xen.org>
* xen/arm: Support dtb /memreserve/ regionsIan Campbell2013-09-261-4/+61
| | | | | | | | | | | | | This requires a mapping of the DTB during setup_mm. Previously this was in the BOOT_MISC slot, which is clobbered by setup_pagetables. Split it out into its own slot which can be preserved. Also handle these regions as part of consider_modules() and when adding pages to the heaps to ensure we do not locate any part of Xen or the heaps over them. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org>
* xen/arm: cope with modules outside of "visible" RAMIan Campbell2013-09-261-0/+6
| | | | | | | | | This can happen if modules are in a bank which we can't cope with e.g. due to being non-contiguous. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Reviewed-by: Julien Grall <julien.grall@linaro.org> Acked-by: Tim Deegan <tim@xen.org>
* xen/arm: do not relocate Xen outside of visible RAMIan Campbell2013-09-261-1/+9
| | | | | | | | | Since we do not handle non-contiguous banks of memory lets avoid relocating Xen into such a bank. Avoids issues such as free_init_memory releasing pages which are outside of the frametable. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org>
* xen/arm: Reserve FDT via early module mechanismIan Campbell2013-09-261-1/+2
| | | | | | | | | | This will stop us putting any heaps or relocating Xen itself over the FDT. The devicetree will be copied to allocated memory in setup_mm and the original copy will be freed by discard_initial_modules. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org>
* xen/arm: ensure the xenheap is 32MB alignedIan Campbell2013-09-261-1/+2
| | | | | | | | | | | | My patch 08693f5948d8 "xen: arm: reduce the size of the xen heap to max 1/8 RAM size" unintentionally violated the constraint that the xenheap must be 32MB aligned, since we only explicitly align the end of the heap and xenheap_pages was not a multiple of 32 pages. Round xenheap pages up to a 32MB boundary. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org>
* xen/arm: Dissociate logical and hardware CPU IDJulien Grall2013-09-261-1/+111
| | | | | | | | | | | Introduce cpu_logical_map to associate a logical CPU ID to an hardware CPU ID. This map will be filled during Xen boot via the device tree. Each CPU node contains a "reg" property which contains the hardware ID (ie MPIDR[0:23]). Also move /cpus parsing later so we can use the dt_* API. Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com>
* xen: arm: improve VMID allocation.Ian Campbell2013-09-211-0/+2
| | | | | | | | | | | | The VMID field is 8 bits. Rather than allowing only up to 256 VMs per host reboot before things start "acting strange" instead maintain a simple bitmap of used VMIDs and allocate them statically to guests upon creation. This limits us to 256 concurrent VMs which is a reasonable improvement. Eventually we will want a proper scheme to allocate VMIDs on context switch. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Julien Grall <julien.grall@linaro.org>
* xen/dts: Constify device_tree_flattenedJulien Grall2013-09-171-4/+8
| | | | | | | The Flat Device Tree is given by the bootloader. Xen doesn't need to modify it. Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com>
* xen/arm: use defines for boot module indexes instead of open coded numbersIan Campbell2013-08-271-4/+3
| | | | | Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Reviewed-by: Julien Grall <julien.grall@linaro.org>
* xen: arm: Use a direct mapping of RAM on arm64Ian Campbell2013-08-201-0/+77
| | | | | | | | | | | | We have plenty of virtual address space so we can avoid needing to map and unmap pages all the time. A totally arbitrarily chosen 32GB frame table leads to support for 5TB of RAM. I haven't tested with anything near that amount of RAM though. There is plenty of room to expand further when that becomes necessary. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
* xen: arm: reduce the size of the xen heap to max 1/8 RAM sizeIan Campbell2013-08-201-2/+2
| | | | | | | | | | | | | | | | | | | When building a 1GB dom0 on a system with 2GB RAM we are running out of domheap pages, while there are still plenty of xenheap pages spare. I would have sworn that when the domheap was exhausted we would fall back to allocating xenheap pages but this doesn't appear to be the case. It's possible that we have setup something incorrectly on ARM but alloc_domheap_pages pretty clearly tries to allocate memory from MEMZONE_XEN+1..zone_hi. Without the fallback from domheap to xenheap taking 1GB of any system with >1GB of RAM for xenheap is excessive so instead set a limit of 1/8 of the total amount of RAM. By way of comparison x86_32 used to have a static 12MB xenheap (which also included .text etc) and in theory supported up to 16GB RAM, by that measure 1/8 is plenty. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org>
* xen/arm: Initialize PERCPU variables at the beginning of start_xenJulien Grall2013-07-291-2/+3
| | | | | | | | | | | | | | | | PERCPU variables rely on HTPIDR (TPIDR_EL2) which is in an unknown state when a processor boot. For the boot CPU, the first use of PERCPU is in setup_pagetables. So initialize PERCPU and set the processor ID before. Bamvor Jian Zhang observed this failure on the sun6i processor which does not initialise HTPIDR and contributed a very similar patch. Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> [ ijc -- added last para of commit message ]
* xen: arm: enable aborts on all physical processors.Ian Campbell2013-07-191-0/+1
| | | | | | | | | | | | | | I'm not sure how this ended up in construct dom0 where it only affects the boot cpu and doesn't logically fit. Enable aborts at the same time as we enable interrupts. I'm not sure what the behaviour of an "abort worthy" operation while aborts are disable is, but it must surely be worse than calling do_unexpected_trap, which is what happens from now on. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org>
* xen/arm: Dummy implementation of multi-bank supportJulien Grall2013-07-171-6/+17
| | | | | | | | | | | | U-boot for the arndale board splits the memory in 8 contiguous banks and rewrites the memory node. So most of the memory is lost. As the frametable is only able to handle contiguous memory, use the first contiguous banks and warn if some of the memory banks are not used. Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com> [ ijc -- "some banks" -> "some memory banks" ]
* xen/arm: don't enable VFP on XEN during the bootJulien Grall2013-07-041-3/+0
| | | | | | | | | We can safely remove VFP support in XEN because: - the guest will enable VFP support when a process requires it - XEN doesn't use VFP Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com>
* xen/arm: Allow Xen to run on multiple platform without recompilationJulien Grall2013-05-131-0/+3
| | | | | | | | | | | | | | | | | | Xen can include various platform support (ie: exynos5, versatile express...) and choose during boot time a set of callbacks for the current board. These callbacks will be called in places where each board can have specific code. For the moment the callbacks are: - platform_init: additional initialization for the platform - platform_init_time: some platform (ie: Exynos 5) needs to initialize the timer with an uncommon way - platform_specific_mapping: add mapping to dom0 which are not specified in the device tree - platform_reset: reset the platform - platform_poweroff: poweroff the platform - platform_quirks: list of quirks for a specific board. Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com>
* xen/arm: Use device tree API in pl011 UART driverJulien Grall2013-05-131-4/+0
| | | | | | | | Allow UART driver to retrieve all its information in the device tree. It's possible to choose the pl011 driver via the Xen command line. Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com>
* xen/arm: Add generic UART to get the device in the device treeJulien Grall2013-05-131-1/+2
| | | | | | | | | | | | | This generic UART will find the right UART via xen command line with dtuart=myserial. "myserial" is the alias of the UART in the device tree. Xen will retrieve the information via the device tree and call the initialization function for this specific UART thanks to the device API. Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Keir Fraser <keir@xen.org>
* xen/arm: Introduce gic_irq_xlateJulien Grall2013-05-131-0/+1
| | | | | | | | This function translates an interrupt specifier to an IRQ number and IRQ type (ie: level trigger, edge trigger,...). It's GIC specific. Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com>
* xen/arm: Create a hierarchical device treeJulien Grall2013-05-131-0/+1
| | | | | | | | | Add function to parse the device tree and create a hierarchical tree. This code is based on drivers/of/base.c in linux source. Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com>
* xen/arm: Introduce ioremap_attr, ioremap_cache, ioremap_nocache, ioremap_wcJulien Grall2013-05-131-2/+2
| | | | | | | | | | | | Map physical range in virtual memory with a specific mapping attribute. Also add new mapping attributes for ARM: PAGE_HYPERVISOR_NOCACHE and PAGE_HYPERVISOR_WC. This function replaces early_ioremap which is only able to deal with 2Mb aligned mapping. Therefore, vmap initialization has been moved earlier. Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com>
* xen/arm: Switch to SYS_STATE_boot right after console setupJulien Grall2013-05-101-0/+2
| | | | | Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com>
* xen/arm: compile and initialize vmapStefano Stabellini2013-05-081-0/+3
| | | | | | | | | | | | | | | | | Rename EARLY_VMAP_VIRT_END and EARLY_VMAP_VIRT_START to VMAP_VIRT_END and VMAP_VIRT_START. Defining VMAP_VIRT_START triggers the compilation of common/vmap.c. Define PAGE_HYPERVISOR and MAP_SMALL_PAGES (unused on ARM, because we only support 4K pages so as a matter of fact it is always set). Implement map_pages_to_xen and destroy_xen_mappings. Call vm_init from start_xen. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com>
* arm: consolidate setup of hypervisor traps and second stage pagingIan Campbell2013-04-111-10/+3
| | | | | | | | In particular be sure to initisalise HCR_EL2 on secondary processors. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> [ ijc -- adjusted due to unapplied "trap guest WFI" by s/HCR_TWI// ]
* xen: arm: implement cpuinfoIan Campbell2013-02-221-27/+82
| | | | | | | | | | | | | | | | | | Use to: - Only context switch ThumbEE state if the processor implements it. In particular the ARMv8 FastModels do not. - Detect the generic timer, and therefore call identify_cpu before init_xen_time. Also improve the boot time messages a bit. I haven't added decoding for all of the CPUID words, it seems like overkill for the moment. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> Cc: stefano.stabellini@citrix.com
* xen: arm: Explicitly setup VPIDR & VMPIDR at start of dayIan Campbell2013-02-221-0/+5
| | | | | | | | | These are supposed to reset to the value of the underlying hardware but appears not to be on at least some v8 models. There's no harm in setting them explicitly. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org>
* xen: arm64: start of day changes to setup.cIan Campbell2013-02-221-18/+36
| | | | | Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org>
* gcov: Call constructors during initializationFrediano Ziglio2013-02-211-0/+2
| | | | | | This allow modules to set initializer functions. This is used by Gcc instrumentation code for profiling arcs and test coverage.
* Fix emacs local variable block to use correct C style variable.David Vrabel2013-02-211-1/+1
| | | | | | | The emacs variable to set the C style from a local variable block is c-file-style, not c-set-style. Signed-off-by: David Vrabel <david.vrabel@citrix.com
* xen: move XEN_SYSCTL_physinfo, XEN_SYSCTL_numainfo and ↵Stefano Stabellini2013-02-151-1/+1
| | | | | | | | | | | | | | | | | | | | | XEN_SYSCTL_topologyinfo to common code Move XEN_SYSCTL_physinfo, XEN_SYSCTL_numainfo and XEN_SYSCTL_topologyinfo from x86/sysctl.c to common/sysctl.c. The implementation of XEN_SYSCTL_physinfo is mostly generic but needs to fill in few arch specific details: introduce arch_do_physinfo to do that. The implementation of XEN_SYSCTL_physinfo relies on two global variables: total_pages and cpu_khz. Make them available on ARM. Implement node_spanned_pages and __node_distance on ARM, assuming 1 numa node for now. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Acked-by: Keir Fraser <keir@xen.org> Acked-by: Ian Campbell <ian.campbell@citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>
* xen/device_tree: introduce find_compatible_nodeStefano Stabellini2013-02-151-4/+3
| | | | | | | | | | | | | | | | | Introduce a find_compatible_node function that can be used by device drivers to find the node corresponding to their device in the device tree. Initialize device_tree_flattened early in start_xen, so that it is available before setup_mm. Get rid of fdt in the process. Also add device_tree_node_compatible to device_tree.h, that is currently missing. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> [ ijc - s/atag_paddr/fdt_paddr ] Committed-by: Ian Campbell <ian.campbell@citrix.com>
* xen/arm: move setup_mm right after setup_pagetablesStefano Stabellini2013-02-151-4/+3
| | | | | | | | | | | | | | At the moment we destroy the DTB mappings we have in setup_pagetables and we restore them only in setup_mm. Move setup_mm right after setup_pagetables. This ensures we have a valid DTB mapping while running the subsequent initialization code. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> [ ijc -- s/atag_paddr/fdt_paddr/ ] Committed-by: Ian Campbell <ian.campbell@citrix.com>
* xen: arm: rename atag_paddr argument fdt_paddrIan Campbell2013-02-151-3/+3
| | | | | | | | We don't support ATAGs and this is always actually an FDT address. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> Committed-by: Ian Campbell <ian.campbell@citrix.com>
* xen: arm32: Don't bother with the bootloader provided ARM-Linux machine typeIan Campbell2013-02-151-1/+0
| | | | | | | | | Everything is DTB based and on 64-bit there is no such concept even in Linux. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>
* arm: discard boot modules after building domain 0.Ian Campbell2013-01-211-0/+16
| | | | | | Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> Committed-by: Ian Campbell <ian.campbell@citrix.com>
* arm: avoid allocating the heaps over modules or xen itself.Ian Campbell2013-01-211-11/+78
| | | | | | Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> Committed-by: Ian Campbell <ian.campbell@citrix.com>
* arm: avoid placing Xen over any modules.Ian Campbell2013-01-211-7/+61
| | | | | | | | | | This will still fail if the modules are such that Xen is pushed out of the top 32M of RAM since it will then overlap with the domheap (or possibly xenheap). This will be dealt with later. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> Committed-by: Ian Campbell <ian.campbell@citrix.com>
* xen: arm: introduce arm32 as a subarch of arm.Ian Campbell2012-12-191-1/+1
| | | | | | | | | | | | | | - move 32-bit specific files into subarch specific arm32 subdirectory. - move gic.h to xen/include/asm-arm (it is needed from both subarch and generic code). - make the appropriate build and config file changes to support XEN_TARGET_ARCH=arm32. This prepares us for an eventual 64-bit subarch. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>
* xen: arm: initialise dom_{xen,io,cow}Ian Campbell2012-12-191-0/+2
| | | | | | | Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>
* xen: arm: Call init_xen_time earlierIan Campbell2012-12-191-2/+2
| | | | | | | | | | If we panic before calling init_xen_time then the "Rebooting in 5 seconds" delay ends up calling udelay which uses cntfrq before it has been initialised resulting in a divide by zero. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>
* arm: Tidy up flush_xen_dcache().Tim Deegan2012-11-231-0/+17
| | | | | | | | | | | | | | - Use a compile-time-constant check for whether we can safely flush just one cacheline. This reduces the common case from 28 instructions to three. - Pass an object to the macro, not a pointer, so we can detect attempts to flush arrays. - Decode CCSIDR correctly to get cacheline size. - Remove some redundant DSBs at the call sites. Signed-off-by: Tim Deegan <tim@xen.org> Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>
* xen/arm: get the number of cpus from device treeStefano Stabellini2012-11-191-1/+4
| | | | | | | | The system might have fewer cpus than the GIC supports. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>
* xen/arm: setup the fixmap in head.SStefano Stabellini2012-11-151-2/+0
| | | | | | | | | Setup the fixmap mapping directly in head.S rather than having a temporary mapping only to re-do it later in C. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>