From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44078) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1buwWW-0002Cx-91 for qemu-devel@nongnu.org; Fri, 14 Oct 2016 03:03:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1buwWS-0005Ez-Tr for qemu-devel@nongnu.org; Fri, 14 Oct 2016 03:03:20 -0400 Date: Fri, 14 Oct 2016 17:43:32 +1100 From: David Gibson Message-ID: <20161014064332.GV28562@umbus> References: <1475479496-16158-1-git-send-email-clg@kaod.org> <1475479496-16158-21-git-send-email-clg@kaod.org> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="gYb7txo4D4wAJl1C" Content-Disposition: inline In-Reply-To: <1475479496-16158-21-git-send-email-clg@kaod.org> Subject: Re: [Qemu-devel] [PATCH v4 20/20] ppc/pnv: add support for POWER9 LPC Controller List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: =?iso-8859-1?Q?C=E9dric?= Le Goater Cc: qemu-ppc@nongnu.org, Benjamin Herrenschmidt , qemu-devel@nongnu.org --gYb7txo4D4wAJl1C Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Mon, Oct 03, 2016 at 09:24:56AM +0200, C=E9dric Le Goater wrote: > The LPC Controller on POWER9 is very similar to the one found on > POWER8 but accesses are now done via on MMIOs, without the XSCOM and > ECCB logic. The device tree is populated differently so we add a > PnvLpcClass and a couple of methods for the purpose. >=20 > LPC interrupts routing is missing. This is Work In Progress but it > gives us a P9 console and, more important, a first idea of what > changes we should consider for the following models. >=20 > Signed-off-by: C=E9dric Le Goater > --- > hw/ppc/pnv.c | 32 +++--- > hw/ppc/pnv_lpc.c | 255 +++++++++++++++++++++++++++++++++++++++++= +++--- > include/hw/ppc/pnv.h | 9 +- > include/hw/ppc/pnv_lpc.h | 33 ++++++ > 4 files changed, 304 insertions(+), 25 deletions(-) >=20 > diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c > index 5b70ccf66fac..d5ef4f8ddb53 100644 > --- a/hw/ppc/pnv.c > +++ b/hw/ppc/pnv.c > @@ -237,6 +237,8 @@ static void powernv_populate_chip(PnvChip *chip, void= *fdt) > xics_native_populate_icp(chip, fdt, 0, pnv_core->pir, smt); > } > =20 > + pnv_lpc_populate(chip, fdt, 0); > + > /* Put all the memory in one node on chip 0 until we find a way to > * specify different ranges for each chip > */ > @@ -355,7 +357,7 @@ static void pnv_lpc_isa_irq_handler(void *opaque, int= n, int level) > =20 > static ISABus *pnv_isa_create(PnvChip *chip) > { > - PnvLpcController *lpc =3D &chip->lpc; > + PnvLpcController *lpc =3D chip->lpc; > ISABus *isa_bus; > qemu_irq *irqs; > PnvChipClass *pcc =3D PNV_CHIP_GET_CLASS(chip); > @@ -653,9 +655,6 @@ static void pnv_chip_init(Object *obj) > =20 > chip->xscom_base =3D pcc->xscom_base; > =20 > - object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC); > - object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL); > - > object_initialize(&chip->xics, sizeof(chip->xics), TYPE_XICS_NATIVE); > object_property_add_child(obj, "xics", OBJECT(&chip->xics), NULL); > =20 > @@ -667,11 +666,6 @@ static void pnv_chip_init(Object *obj) > object_property_add_const_link(OBJECT(&chip->occ), "psi", > OBJECT(&chip->psi), &error_abort); > =20 > - /* > - * The LPC controller needs PSI to generate interrupts > - */ > - object_property_add_const_link(OBJECT(&chip->lpc), "psi", > - OBJECT(&chip->psi), &error_abort); > } > =20 > static void pnv_chip_realize(DeviceState *dev, Error **errp) > @@ -757,10 +751,24 @@ static void pnv_chip_realize(DeviceState *dev, Erro= r **errp) > xics_insert_ics(XICS_COMMON(&chip->xics), &chip->psi.ics); > =20 > /* Create LPC controller */ > - object_property_set_bool(OBJECT(&chip->lpc), true, "realized", > + typename =3D g_strdup_printf(TYPE_PNV_LPC "-%s", pcc->cpu_model); > + chip->lpc =3D PNV_LPC(object_new(typename)); Urgh. I think doing object_new() from realize is frowned upon. Unfortunately, I don't know what the right way to do this is :/. > + object_property_add_child(OBJECT(chip), "lpc", OBJECT(chip->lpc), NU= LL); > + > + /* The LPC controller needs PSI to generate interrupts */ > + object_property_add_const_link(OBJECT(chip->lpc), "psi", > + OBJECT(&chip->psi), &error_abort); > + object_property_set_bool(OBJECT(chip->lpc), true, "realized", > &error_fatal); > - memory_region_add_subregion(&chip->xscom, PNV_XSCOM_LPC_BASE << 3, > - &chip->lpc.xscom_regs); > + > + if (PNV_CHIP_GET_CLASS(chip)->chip_type !=3D PNV_CHIP_POWER9) { > + memory_region_add_subregion(&chip->xscom, PNV_XSCOM_LPC_BASE << = 3, > + &chip->lpc->xscom_regs); > + } else { > + memory_region_add_subregion(get_system_memory(), PNV_POWER9_LPCM= _BASE, > + &chip->lpc->xscom_regs); > + } > + > =20 > /* Create the simplified OCC model */ > object_property_set_bool(OBJECT(&chip->occ), true, "realized", > diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c > index 8b78b0a1e414..93ccc656120c 100644 > --- a/hw/ppc/pnv_lpc.c > +++ b/hw/ppc/pnv_lpc.c > @@ -28,6 +28,7 @@ > #include "hw/ppc/fdt.h" > =20 > #include > +#include "exec/address-spaces.h" > =20 > enum { > ECCB_CTL =3D 0, > @@ -91,6 +92,88 @@ enum { > #define LPC_HC_REGS_OPB_SIZE 0x00001000 > =20 > =20 > +int pnv_lpc_populate(PnvChip *chip, void *fdt, int offset) > +{ > + PnvLpcClass *plc =3D PNV_LPC_GET_CLASS(chip->lpc); > + > + if (plc->populate) { > + return plc->populate(chip, fdt, offset); > + } > + return 0; > +} > + > +static int pnv_lpc_power9_populate(PnvChip *chip, void *fdt, int root_of= fset) > +{ > + const char compat[] =3D "ibm,power9-lpcm-opb\0simple-bus"; > + const char lpc_compat[] =3D "ibm,power9-lpc\0ibm,lpc"; > + char *name; > + int offset, lpcm_offset; > + /* should depend on a MMIO base address of the chip */ > + uint64_t lpcm_addr =3D PNV_POWER9_LPCM_BASE; > + /* TODO: build the ranges properly, array of : > + * { offset, addr hi, addr low, size } > + */ > + uint32_t ranges[4] =3D { 0, > + cpu_to_be32(lpcm_addr >> 32), > + cpu_to_be32((uint32_t)lpcm_addr), > + cpu_to_be32(PNV_POWER9_LPCM_SIZE / 2), > + }; > + uint32_t reg[2]; > + > + /* > + * OPB bus > + */ > + name =3D g_strdup_printf("lpcm-opb@%"PRIx64, lpcm_addr); > + lpcm_offset =3D fdt_add_subnode(fdt, root_offset, name); > + _FDT(lpcm_offset); > + g_free(name); > + _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#address-cells", 1))); > + _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#size-cells", 1))); > + _FDT((fdt_setprop(fdt, lpcm_offset, "compatible", compat, sizeof(com= pat)))); > + _FDT((fdt_setprop_cell(fdt, lpcm_offset, "ibm,chip-id", chip->chip_i= d))); > + _FDT((fdt_setprop(fdt, lpcm_offset, "ranges", ranges, sizeof(ranges))= )); > + > + /* > + * OPB Master registers > + */ > + name =3D g_strdup_printf("opb-master@%x", LPC_OPB_REGS_OPB_ADDR); > + offset =3D fdt_add_subnode(fdt, lpcm_offset, name); > + _FDT(offset); > + g_free(name); > + > + reg[0] =3D cpu_to_be32(LPC_OPB_REGS_OPB_ADDR); > + reg[1] =3D cpu_to_be32(LPC_OPB_REGS_OPB_SIZE); > + _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)))); > + _FDT((fdt_setprop_string(fdt, offset, "compatible", > + "ibm,power9-lpcm-opb-master"))); > + > + /* > + * LPC Host Controller registers > + */ > + name =3D g_strdup_printf("lpc-controller@%x", LPC_HC_REGS_OPB_ADDR); > + offset =3D fdt_add_subnode(fdt, lpcm_offset, name); > + _FDT(offset); > + g_free(name); > + > + reg[0] =3D cpu_to_be32(LPC_HC_REGS_OPB_ADDR); > + reg[1] =3D cpu_to_be32(LPC_HC_REGS_OPB_SIZE); > + _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)))); > + _FDT((fdt_setprop_string(fdt, offset, "compatible", > + "ibm,power9-lpc-controller"))); > + > + name =3D g_strdup_printf("lpc@%x", LPC_FW_OPB_ADDR); > + offset =3D fdt_add_subnode(fdt, lpcm_offset, name); > + _FDT(offset); > + g_free(name); > + _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2))); > + _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1))); > + _FDT((fdt_setprop(fdt, offset, "primary", NULL, 0))); > + _FDT((fdt_setprop(fdt, offset, "compatible", lpc_compat, > + sizeof(lpc_compat)))); > + > + return 0; > +} > + > /* > * TODO: the "primary" cell should only be added on chip 0. This is > * how skiboot chooses the default LPC controller on multichip > @@ -99,7 +182,8 @@ enum { > * It would be easly done if we can change the populate() interface to > * replace the PnvXScomInterface parameter by a PnvChip one > */ > -static int pnv_lpc_populate(PnvXScomInterface *dev, void *fdt, int xscom= _offset) > +static int pnv_lpc_power8_populate(PnvXScomInterface *dev, void *fdt, > + int xscom_offset) > { > const char compat[] =3D "ibm,power8-lpc\0ibm,lpc"; > char *name; > @@ -249,6 +333,74 @@ static const MemoryRegionOps pnv_lpc_xscom_ops =3D { > .endianness =3D DEVICE_BIG_ENDIAN, > }; > =20 > +static uint64_t pnv_lpc_mmio_read(void *opaque, hwaddr addr, unsigned si= ze) > +{ > + PnvLpcController *lpc =3D PNV_LPC(opaque); > + uint64_t val =3D 0; > + uint32_t opb_addr =3D addr & ECCB_CTL_ADDR_MASK; > + MemTxResult result; > + > + switch (size) { > + case 4: > + val =3D address_space_ldl(&lpc->opb_as, opb_addr, MEMTXATTRS_UNS= PECIFIED, > + &result); > + break; > + case 1: > + val =3D address_space_ldub(&lpc->opb_as, opb_addr, MEMTXATTRS_UN= SPECIFIED, > + &result); > + break; > + default: > + qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%" > + HWADDR_PRIx " invalid size %d\n", addr, size); > + return 0; > + } > + > + if (result !=3D MEMTX_OK) { > + qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%" > + HWADDR_PRIx "\n", addr); > + } > + > + return val; > +} > + > +static void pnv_lpc_mmio_write(void *opaque, hwaddr addr, > + uint64_t val, unsigned size) > +{ > + PnvLpcController *lpc =3D PNV_LPC(opaque); > + uint32_t opb_addr =3D addr & ECCB_CTL_ADDR_MASK; > + MemTxResult result; > + > + switch (size) { > + case 4: > + address_space_stl(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPEC= IFIED, > + &result); > + break; > + case 1: > + address_space_stb(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPEC= IFIED, > + &result); > + break; > + default: > + qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%" > + HWADDR_PRIx " invalid size %d\n", addr, size); > + return; > + } > + > + if (result !=3D MEMTX_OK) { > + qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%" > + HWADDR_PRIx "\n", addr); > + } > +} > + > +static const MemoryRegionOps pnv_lpc_mmio_ops =3D { > + .read =3D pnv_lpc_mmio_read, > + .write =3D pnv_lpc_mmio_write, > + .impl =3D { > + .min_access_size =3D 1, > + .max_access_size =3D 4, > + }, > + .endianness =3D DEVICE_BIG_ENDIAN, > +}; > + > void pnv_lpc_eval_irqs(PnvLpcController *lpc) > { > bool lpc_to_opb_irq =3D false; > @@ -426,9 +578,29 @@ static const MemoryRegionOps opb_master_ops =3D { > }, > }; > =20 > +static void pnv_lpc_power8_realize(DeviceState *dev, Error **errp) > +{ > + PnvLpcController *lpc =3D PNV_LPC(dev); > + > + /* XScom region for LPC registers */ > + memory_region_init_io(&lpc->xscom_regs, OBJECT(dev), > + &pnv_lpc_xscom_ops, lpc, "xscom-lpc", > + PNV_XSCOM_LPC_SIZE << 3); > +} > + > +static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp) > +{ > + PnvLpcController *lpc =3D PNV_LPC(dev); > + > + /* Initialize MMIO region */ > + memory_region_init_io(&lpc->xscom_regs, OBJECT(dev), &pnv_lpc_mmio_o= ps, lpc, > + "lpcm", PNV_POWER9_LPCM_SIZE); > +} > + > static void pnv_lpc_realize(DeviceState *dev, Error **errp) > { > PnvLpcController *lpc =3D PNV_LPC(dev); > + PnvLpcClass *plc =3D PNV_LPC_GET_CLASS(dev); > Object *obj; > Error *error =3D NULL; > =20 > @@ -470,11 +642,6 @@ static void pnv_lpc_realize(DeviceState *dev, Error = **errp) > memory_region_add_subregion(&lpc->opb_mr, LPC_HC_REGS_OPB_ADDR, > &lpc->lpc_hc_regs); > =20 > - /* XScom region for LPC registers */ > - memory_region_init_io(&lpc->xscom_regs, OBJECT(dev), > - &pnv_lpc_xscom_ops, lpc, "xscom-lpc", > - PNV_XSCOM_LPC_SIZE << 3); > - > /* get PSI object from chip */ > obj =3D object_property_get_link(OBJECT(dev), "psi", &error); > if (!obj) { > @@ -483,32 +650,96 @@ static void pnv_lpc_realize(DeviceState *dev, Error= **errp) > return; > } > lpc->psi =3D PNV_PSI(obj); > + > + plc->realize(dev, errp); > } > =20 > -static void pnv_lpc_class_init(ObjectClass *klass, void *data) > +static void pnv_lpc_power8_class_init(ObjectClass *klass, void *data) > { > DeviceClass *dc =3D DEVICE_CLASS(klass); > PnvXScomInterfaceClass *xdc =3D PNV_XSCOM_INTERFACE_CLASS(klass); > + PnvLpcClass *plc =3D PNV_LPC_CLASS(klass); > =20 > - xdc->populate =3D pnv_lpc_populate; > + xdc->populate =3D pnv_lpc_power8_populate; > =20 > dc->realize =3D pnv_lpc_realize; > + plc->realize =3D pnv_lpc_power8_realize; > } > =20 > -static const TypeInfo pnv_lpc_info =3D { > - .name =3D TYPE_PNV_LPC, > - .parent =3D TYPE_DEVICE, > +static const TypeInfo pnv_lpc_power8e_info =3D { > + .name =3D TYPE_PNV_LPC_POWER8E, > + .parent =3D TYPE_PNV_LPC, > .instance_size =3D sizeof(PnvLpcController), > - .class_init =3D pnv_lpc_class_init, > + .class_init =3D pnv_lpc_power8_class_init, > + .interfaces =3D (InterfaceInfo[]) { > + { TYPE_PNV_XSCOM_INTERFACE }, > + { } > + } > +}; > + > +static const TypeInfo pnv_lpc_power8_info =3D { > + .name =3D TYPE_PNV_LPC_POWER8, > + .parent =3D TYPE_PNV_LPC, > + .instance_size =3D sizeof(PnvLpcController), > + .class_init =3D pnv_lpc_power8_class_init, > + .interfaces =3D (InterfaceInfo[]) { > + { TYPE_PNV_XSCOM_INTERFACE }, > + { } > + } > +}; > + > +static const TypeInfo pnv_lpc_power8nvl_info =3D { > + .name =3D TYPE_PNV_LPC_POWER8NVL, > + .parent =3D TYPE_PNV_LPC, > + .instance_size =3D sizeof(PnvLpcController), > + .class_init =3D pnv_lpc_power8_class_init, > .interfaces =3D (InterfaceInfo[]) { > { TYPE_PNV_XSCOM_INTERFACE }, > { } > } > }; > =20 > +static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc =3D DEVICE_CLASS(klass); > + PnvLpcClass *plc =3D PNV_LPC_CLASS(klass); > + > + dc->realize =3D pnv_lpc_realize; > + plc->realize =3D pnv_lpc_power9_realize; > + plc->populate =3D pnv_lpc_power9_populate; > +} > + > +static const TypeInfo pnv_lpc_power9_info =3D { > + .name =3D TYPE_PNV_LPC_POWER9, > + .parent =3D TYPE_PNV_LPC, > + .instance_size =3D sizeof(PnvLpcController), > + .class_init =3D pnv_lpc_power9_class_init, > +}; > + > +static void pnv_lpc_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc =3D DEVICE_CLASS(klass); > + > + dc->realize =3D pnv_lpc_realize; > + dc->desc =3D "PowerNV LPC Controller"; > +} > + > +static const TypeInfo pnv_lpc_info =3D { > + .name =3D TYPE_PNV_LPC, > + .parent =3D TYPE_DEVICE, > + .class_init =3D pnv_lpc_class_init, > + .class_size =3D sizeof(PnvLpcClass), > + .abstract =3D true, > +}; > + > + > static void pnv_lpc_register_types(void) > { > type_register_static(&pnv_lpc_info); > + type_register_static(&pnv_lpc_power8e_info); > + type_register_static(&pnv_lpc_power8_info); > + type_register_static(&pnv_lpc_power8nvl_info); > + type_register_static(&pnv_lpc_power9_info); > } > =20 > type_init(pnv_lpc_register_types) > diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h > index ed3316501326..361af311a92e 100644 > --- a/include/hw/ppc/pnv.h > +++ b/include/hw/ppc/pnv.h > @@ -57,7 +57,7 @@ typedef struct PnvChip { > uint64_t cores_mask; > void *cores; > =20 > - PnvLpcController lpc; > + PnvLpcController *lpc; > XICSNative xics; > PnvPsiController psi; > PnvOCC occ; > @@ -154,4 +154,11 @@ typedef struct PnvMachineState { > #define PNV_PSIHB_BAR_SIZE 0x0000000000100000ull > =20 > =20 > +/* > + * POWER9 MMIO regions > + */ > +#define PNV_POWER9_MMIO_BASE 0x006000000000000ull > +#define PNV_POWER9_LPCM_BASE (PNV_POWER9_MMIO_BASE + 0x30000000000ull) > +#define PNV_POWER9_LPCM_SIZE 0x100000000ull > + > #endif /* _PPC_PNV_H */ > diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h > index fc348dca50ca..510fab2fd115 100644 > --- a/include/hw/ppc/pnv_lpc.h > +++ b/include/hw/ppc/pnv_lpc.h > @@ -22,8 +22,13 @@ > #define TYPE_PNV_LPC "pnv-lpc" > #define PNV_LPC(obj) \ > OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV_LPC) > +#define PNV_LPC_CLASS(klass) \ > + OBJECT_CLASS_CHECK(PnvLpcClass, (klass), TYPE_PNV_LPC) > +#define PNV_LPC_GET_CLASS(obj) \ > + OBJECT_GET_CLASS(PnvLpcClass, (obj), TYPE_PNV_LPC) > =20 > typedef struct PnvPsiController PnvPsiController; > +typedef struct PnvChip PnvChip; > =20 > typedef struct PnvLpcController { > DeviceState parent; > @@ -68,7 +73,35 @@ typedef struct PnvLpcController { > MemoryRegion xscom_regs; > } PnvLpcController; > =20 > +typedef struct PnvLpcClass { > + DeviceClass parent_class; > + > + int (*populate)(PnvChip *chip, void *fdt, int offset); > + void (*realize)(DeviceState *dev, Error **errp); > +} PnvLpcClass; > + > + > +#define TYPE_PNV_LPC_POWER8E TYPE_PNV_LPC "-POWER8E" > +#define PNV_LPC_POWER8E(obj) \ > + OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV_LPC_POWER8E) > + > +#define TYPE_PNV_LPC_POWER8 TYPE_PNV_LPC "-POWER8" > +#define PNV_LPC_POWER8(obj) \ > + OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV_LPC_POWER8) > + > +#define TYPE_PNV_LPC_POWER8NVL TYPE_PNV_LPC "-POWER8NVL" > +#define PNV_LPC_POWER8NVL(obj) \ > + OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV_LPC_POWER8NVL) > + > +#define TYPE_PNV_LPC_POWER9 TYPE_PNV_LPC "-POWER9" > +#define PNV_LPC_POWER9(obj) \ > + OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV_LPC_POWER9) > + > + > + > #define LPC_HC_IRQ_SERIRQ0 0x80000000 /* all bits down to .= =2E. */ > void pnv_lpc_eval_irqs(PnvLpcController *lpc); > =20 > +int pnv_lpc_populate(PnvChip *chip, void *fdt, int root_offset); > + > #endif /* _PPC_PNV_LPC_H */ --=20 David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson --gYb7txo4D4wAJl1C Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBCAAGBQJYAH6UAAoJEGw4ysog2bOSC1kQAMCUYx9wc4rs5XEWf9qJApY9 CQHh8scf9AEE56IbWpqB08JB/kGgVOUdZ5bXTZP3Hcx2RFRkbqnNvH00hCO85GVy 9MGOf0qNZJOxDQl1YUU3n2UXWmcTKD+Y25afx2+hmYC2ufhr45N3fhb1C7up6El4 uOHuBFvp8j9x2pYgqHvJjIjusC4Q0kDvfnrW+/gvZrufEz8kzx7c2ysOTE6lse3X uK0AIl/2y0Bibfc5wHTG5oNo1rgEyXzD+92gS/pJzkPfJbVk1DeMkrH0/ysiOv0T FfEqB0CA/D6TMWST49Vzk27LnUKLXXcokdX5V1CXk1VJtt6weq02KUIVIal1nY7b YPKncH8hjVWuZS1c9ouepRfyov14A4acDppU+lVOyXa8JL9fatQKIqpQJiXLNpsl Ng4xZ7q3eaT9lbipUsiPjxQuxbYeWBAkEo7eC8bQUSop8E0WHFdNfexmQPJAiAN0 /gBNBhccUrHoGhfmWeXkQKtrDShJe0N8M+FL2TE4di9B8N2RaDzPchCrI9jEGX3U xKh4ouLzf1Gt46tuH67tGHAlDljsBaHdtZ+oyXOAf9xNaSy+3DFjrDUwuJ1tByIa IzAvpg4dkPkPRhKCSgQRKK/EH57nkaAMObVqc4w2qXo8VK1tEM0vARTWRqmxABDK 8mgvHJ7zRQ8LPAjxS8Mr =dYXm -----END PGP SIGNATURE----- --gYb7txo4D4wAJl1C--