Support for setting up qdev models for use by the fdt-generic framwork. A single fdt init function is shared by all qdev models and the qdev model registers a handler function that maps fdt properties to qdev properties. Support for basic interrupt controllers and nics is there.
Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwa...@petalogix.com> --- Makefile.objs | 1 + hw/fdt_generic_qdev.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ hw/fdt_generic_qdev.h | 46 ++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 0 deletions(-) create mode 100644 hw/fdt_generic_qdev.c create mode 100644 hw/fdt_generic_qdev.h diff --git a/Makefile.objs b/Makefile.objs index 9fd18ff..9d5100a 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -222,6 +222,7 @@ hw-obj-$(CONFIG_USB_REDIR) += usb-redir.o hw-obj-$(CONFIG_FDT) += fdt_generic.o hw-obj-$(CONFIG_FDT) += fdt_generic_util.o +hw-obj-$(CONFIG_FDT) += fdt_generic_qdev.o # PPC devices hw-obj-$(CONFIG_OPENPIC) += openpic.o diff --git a/hw/fdt_generic_qdev.c b/hw/fdt_generic_qdev.c new file mode 100644 index 0000000..53b32ab --- /dev/null +++ b/hw/fdt_generic_qdev.c @@ -0,0 +1,75 @@ +#include "fdt_generic_qdev.h" +#include "fdt_generic_util.h" +#include "net.h" + +#define D(a) + +int fdt_init_qdev(char *node_path, FDTMachineInfo *fdti, void *opaque) +{ + int err; + qemu_irq irq; + target_phys_addr_t base; + DeviceState *dev; + FDTQDevOps *ops = opaque; + struct FDTQDevPropMapping *props = + (ops && ops->map) ? ops->map(node_path, fdti) : NULL; + struct FDTQDevPropMapping *propsi; + + /* create the device */ + if (!ops || !ops->dev_name) { + return 1; + } + dev = qdev_create(NULL, ops->dev_name); + D(fprintf(stderr, "FDT: Creating QDEV model %s %s %d\n", + ops->dev_name, ops->is_nic ? "(nic)" : "", ops->is_intc);) + /* connect nic if appropriate */ + if (ops->is_nic) { + qemu_check_nic_model(&nd_table[0], ops->dev_name); + qdev_set_nic_properties(dev, &nd_table[0]); + } + /* connect custom properties */ + for (propsi = props; propsi && propsi->name; propsi++) { + enum PropertyType type; + if (!qdev_prop_get_type(dev, propsi->name, &type)) { + qdev_prop_set(dev, propsi->name, &propsi->src, type); + D(fprintf(stderr, "\tFDT: setting qdev prop %s %d (u32) %p (p)\n", + propsi->name, propsi->src.u32, propsi->src.p);) + } + if (propsi->freesrc) { + g_free(propsi->src.p); + } + } + qdev_init_nofail(dev); + /* map slave attachment */ + base = qemu_devtree_getprop(fdti->fdt, NULL, node_path, "reg", 0, 0); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + /* connect irq */ + { + char irq_info[1024]; + /* FIXME: add support for multiple IRQs */ + irq = fdt_get_irq_info(fdti, node_path, 0, &err, irq_info); + /* INTCs inferr their top level, if no IRQ connection specified */ + if (err && ops->is_intc) { + irq = fdti->irq_base[0]; + err = 0; + } + if (!err) { + sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + fprintf(stderr, "FDT: (%s) connected irq %s\n", ops->dev_name, irq_info); + } + } + /* create interrupt controller connections if appropriate */ + if (ops->is_intc) { + int i; + qemu_irq *irqs = g_malloc0(sizeof(*irqs) * ops->is_intc); + for (i = 0; i < ops->is_intc; i++) { + irqs[i] = qdev_get_gpio_in(dev, i); + } + fdt_init_set_opaque(fdti, node_path, irqs); + } + + if (props) { + g_free(props); + } + return 0; +} diff --git a/hw/fdt_generic_qdev.h b/hw/fdt_generic_qdev.h new file mode 100644 index 0000000..fe140b3 --- /dev/null +++ b/hw/fdt_generic_qdev.h @@ -0,0 +1,46 @@ +#ifndef FDT_GENERIC_QDEV_H +#define FDT_GENERIC_QDEV_H + +#include "fdt_generic.h" +#include "qdev.h" + +typedef struct FDTQDevPropMapping { + const char *name; + union { + /* TODO: add support for structure type QDEV props */ + uint8_t u8; + uint16_t u16; + uint32_t u32; + void *p; + } src; + int freesrc; +} FDTQDevPropMapping; + +typedef FDTQDevPropMapping* (*FDTQDevMapFn)(char *, FDTMachineInfo *); + +typedef struct FDTQDevOps { + const char *dev_name; + /* TODO: implement */ + const int *irq_map; + const int is_nic; + /* FIXME: Add mechanism for dynamically chnginging number of intc IRQs */ + const int is_intc; + FDTQDevMapFn map; +} FDTQDevOps; + +/* FDT init functions for qdev models */ + +int fdt_init_qdev(char *, FDTMachineInfo *, void *); + +/* statically register a FDTQDevMapFn as being associate with a compatibility */ + +#define fdt_qdev_register_compatibility_n(ops, compat, n) \ +static void __attribute__((constructor)) \ +function ## n ## _register_imp (void) { \ + add_to_compat_table(fdt_init_qdev, compat, ops); \ +} + +#define fdt_qdev_register_compatibility(ops, compat) \ +fdt_qdev_register_compatibility_n(ops, compat, 0); + +#endif /* FDT_GENERIC_QDEV_H */ -- 1.7.3.2