From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id 6E8EC740034 for ; Mon, 21 Aug 2023 17:59:13 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=pl7pI2Y/2oSIyRJAGctE59C8Ldv3sWe/A4hNRccbaVg=; c=relaxed/simple; d=groups.io; h=Date:From:To:CC:Subject:Message-ID:References:MIME-Version:In-Reply-To:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Type:Content-Disposition; s=20140610; t=1692640751; v=1; b=WesyvRgkbnoq1Hhpfrt9q691SNvbhKnm/wGsPsFCg3VMRFnM5jMce8o5pcW6X5SsquluIMoJ Tn2/0seBsVFe4zxxjSFjei5IGEVg6Beujh7Fi5Cz5QsH37p6zwfUhJbMdjTZRU02Zk0QIRn5zbZ j77PRSyhcEOIehIEm7KzbJRQ= X-Received: by 127.0.0.2 with SMTP id p7ogYY7687511xkEB8Ozj4g3; Mon, 21 Aug 2023 10:59:11 -0700 X-Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) by mx.groups.io with SMTP id smtpd.web10.41.1692640751052503277 for ; Mon, 21 Aug 2023 10:59:11 -0700 X-Received: from pps.filterd (m0279868.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 37LHBweP008845; Mon, 21 Aug 2023 17:59:10 GMT X-Received: from nasanppmta03.qualcomm.com (i-global254.qualcomm.com [199.106.103.254]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3sjn2rcbs4-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 21 Aug 2023 17:59:10 +0000 X-Received: from nasanex01c.na.qualcomm.com (nasanex01c.na.qualcomm.com [10.45.79.139]) by NASANPPMTA03.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 37LHx9kG005567 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 21 Aug 2023 17:59:09 GMT X-Received: from qc-i7.hemma.eciton.net (10.80.80.8) by nasanex01c.na.qualcomm.com (10.45.79.139) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.36; Mon, 21 Aug 2023 10:59:07 -0700 Date: Mon, 21 Aug 2023 18:59:04 +0100 From: "Leif Lindholm" To: Marcin Juszkiewicz CC: , Ard Biesheuvel , Graeme Gregory , Shashi Mallela Subject: Re: [edk2-devel] [PATCH edk2-platforms v4 1/3] Platform/SbsaQemu: add GIC ITS support Message-ID: References: <20230821150757.128280-1-marcin.juszkiewicz@linaro.org> <20230821150757.128280-2-marcin.juszkiewicz@linaro.org> MIME-Version: 1.0 In-Reply-To: <20230821150757.128280-2-marcin.juszkiewicz@linaro.org> X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To nasanex01c.na.qualcomm.com (10.45.79.139) X-QCInternal: smtphost X-Proofpoint-GUID: SlygIj0ZcBr2ScQTFzDguQIXr6cpfj2g X-Proofpoint-ORIG-GUID: SlygIj0ZcBr2ScQTFzDguQIXr6cpfj2g Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,quic_llindhol@quicinc.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: PnwW8QP6sDksSE5CRSrfGfYqx7686176AA= Content-Type: text/plain; charset="us-ascii" Content-Disposition: inline X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=WesyvRgk; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=quicinc.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io On Mon, Aug 21, 2023 at 17:07:55 +0200, Marcin Juszkiewicz wrote: > From: Shashi Mallela > > SBSA Reference Platform has GIC ITS support. Let make use of it. > > Base address is read from TF-A via SMC call. > > GIC ITS allows us to have complex PCI Express setups. > > Co-authored-by: Marcin Juszkiewicz > Signed-off-by: Shashi Mallela > Signed-off-by: Marcin Juszkiewicz > --- > Silicon/Qemu/SbsaQemu/SbsaQemu.dec | 3 + > Platform/Qemu/SbsaQemu/SbsaQemu.dsc | 3 + > .../Qemu/SbsaQemu/AcpiTables/AcpiTables.inf | 2 + > .../SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.inf | 1 + > .../SbsaQemuPlatformDxe.inf | 1 + > .../Include/IndustryStandard/SbsaQemuAcpi.h | 11 ++ > .../Include/IndustryStandard/SbsaQemuSmc.h | 1 + > .../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c | 12 +- > .../SbsaQemuPlatformDxe/SbsaQemuPlatformDxe.c | 10 ++ > Silicon/Qemu/SbsaQemu/AcpiTables/Iort.aslc | 135 ++++++++++++++++++ > 10 files changed, 178 insertions(+), 1 deletion(-) > create mode 100644 Silicon/Qemu/SbsaQemu/AcpiTables/Iort.aslc > > diff --git a/Silicon/Qemu/SbsaQemu/SbsaQemu.dec b/Silicon/Qemu/SbsaQemu/SbsaQemu.dec > index 5182978cf56d..ff2a4721a131 100644 > --- a/Silicon/Qemu/SbsaQemu/SbsaQemu.dec > +++ b/Silicon/Qemu/SbsaQemu/SbsaQemu.dec > @@ -70,3 +70,6 @@ [PcdsDynamic.common] > > gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdPlatformVersionMajor|0x0|UINT32|0x0000011E > gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdPlatformVersionMinor|0x0|UINT32|0x0000011F > + > + # ARM Generic Interrupt Controller ITS > + gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdGicItsBase|0|UINT64|0x00000120 > diff --git a/Platform/Qemu/SbsaQemu/SbsaQemu.dsc b/Platform/Qemu/SbsaQemu/SbsaQemu.dsc > index b88729ad8ad6..4ae2479628b6 100644 > --- a/Platform/Qemu/SbsaQemu/SbsaQemu.dsc > +++ b/Platform/Qemu/SbsaQemu/SbsaQemu.dsc > @@ -523,6 +523,9 @@ [PcdsDynamicDefault.common] > gArmTokenSpaceGuid.PcdGicDistributorBase|0x40060000 > gArmTokenSpaceGuid.PcdGicRedistributorsBase|0x40080000 > > + # GIC ITS > + gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdGicItsBase|0 > + > # > # Set video resolution for boot options > # PlatformDxe can set the former at runtime. > diff --git a/Silicon/Qemu/SbsaQemu/AcpiTables/AcpiTables.inf b/Silicon/Qemu/SbsaQemu/AcpiTables/AcpiTables.inf > index 0501c670d565..554c5e4b6f9e 100644 > --- a/Silicon/Qemu/SbsaQemu/AcpiTables/AcpiTables.inf > +++ b/Silicon/Qemu/SbsaQemu/AcpiTables/AcpiTables.inf > @@ -22,6 +22,7 @@ [Sources] > Gtdt.aslc > Mcfg.aslc > Spcr.aslc > + Iort.aslc Please insert sorted. (as line after Gtdt.aslc) > > [Packages] > ArmPlatformPkg/ArmPlatformPkg.dec > @@ -75,3 +76,4 @@ [FixedPcd] > [Pcd] > gArmTokenSpaceGuid.PcdGicDistributorBase > gArmTokenSpaceGuid.PcdGicRedistributorsBase > + gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdGicItsBase > diff --git a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.inf b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.inf > index c1c33788567d..3ec7ffd8dd5c 100644 > --- a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.inf > +++ b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.inf > @@ -48,6 +48,7 @@ [Pcd] > > gArmTokenSpaceGuid.PcdGicDistributorBase > gArmTokenSpaceGuid.PcdGicRedistributorsBase > + gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdGicItsBase > > [Depex] > gEfiAcpiTableProtocolGuid ## CONSUMES > diff --git a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuPlatformDxe/SbsaQemuPlatformDxe.inf b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuPlatformDxe/SbsaQemuPlatformDxe.inf > index 545794a8c7ff..0e3b11d60426 100644 > --- a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuPlatformDxe/SbsaQemuPlatformDxe.inf > +++ b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuPlatformDxe/SbsaQemuPlatformDxe.inf > @@ -43,6 +43,7 @@ [Pcd] > > gArmTokenSpaceGuid.PcdGicDistributorBase > gArmTokenSpaceGuid.PcdGicRedistributorsBase > + gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdGicItsBase > > > [Depex] > diff --git a/Silicon/Qemu/SbsaQemu/Include/IndustryStandard/SbsaQemuAcpi.h b/Silicon/Qemu/SbsaQemu/Include/IndustryStandard/SbsaQemuAcpi.h > index 853b81b34df5..983d17f6fa50 100644 > --- a/Silicon/Qemu/SbsaQemu/Include/IndustryStandard/SbsaQemuAcpi.h > +++ b/Silicon/Qemu/SbsaQemu/Include/IndustryStandard/SbsaQemuAcpi.h > @@ -27,6 +27,7 @@ > #define SBSAQEMU_MADT_GIC_HBASE 0x2c010000 > #define SBSAQEMU_MADT_GIC_PMU_IRQ 23 > #define SBSAQEMU_MADT_GICR_SIZE 0x4000000 > +#define SBSAQEMU_MADT_GITS_SIZE 0x20000 > > // Macro for MADT GIC Redistributor Structure > #define SBSAQEMU_MADT_GICR_INIT() { \ > @@ -37,6 +38,16 @@ > SBSAQEMU_MADT_GICR_SIZE /* DiscoveryRangeLength */ \ > } > > +// Macro for MADT GIC ITS Structure > +#define SBSAQEMU_MADT_GIC_ITS_INIT(GicItsId) { \ > + EFI_ACPI_6_5_GIC_ITS, /* Type */ \ > + sizeof (EFI_ACPI_6_5_GIC_ITS_STRUCTURE), /* Length */ \ > + EFI_ACPI_RESERVED_WORD, /* Reserved */ \ > + GicItsId, /* GicItsId */ \ > + PcdGet64 (PcdGicItsBase), /* PhysicalBaseAddress */ \ > + EFI_ACPI_RESERVED_DWORD /* Reserved2 */ \ > + } > + > #define SBSAQEMU_ACPI_SCOPE_OP_MAX_LENGTH 5 > > #define SBSAQEMU_ACPI_SCOPE_NAME { '_', 'S', 'B', '_' } > diff --git a/Silicon/Qemu/SbsaQemu/Include/IndustryStandard/SbsaQemuSmc.h b/Silicon/Qemu/SbsaQemu/Include/IndustryStandard/SbsaQemuSmc.h > index 7fbd3bd887d0..7934875e4aba 100644 > --- a/Silicon/Qemu/SbsaQemu/Include/IndustryStandard/SbsaQemuSmc.h > +++ b/Silicon/Qemu/SbsaQemu/Include/IndustryStandard/SbsaQemuSmc.h > @@ -13,5 +13,6 @@ > > #define SIP_SVC_VERSION SMC_SIP_FUNCTION_ID(1) > #define SIP_SVC_GET_GIC SMC_SIP_FUNCTION_ID(100) > +#define SIP_SVC_GET_GIC_ITS SMC_SIP_FUNCTION_ID(101) > > #endif /* SBSA_QEMU_SMC_H_ */ > diff --git a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c > index ae5397bab768..961482269678 100644 > --- a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c > +++ b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c > @@ -91,6 +91,11 @@ AddMadtTable ( > // Initialize GIC Redistributor Structure > EFI_ACPI_6_0_GICR_STRUCTURE Gicr = SBSAQEMU_MADT_GICR_INIT(); > > + // Initialize GIC ITS Structure > + EFI_ACPI_6_5_GIC_ITS_STRUCTURE Gic_Its = SBSAQEMU_MADT_GIC_ITS_INIT(0); > + > + DEBUG ((DEBUG_ERROR, "itsBaseAddr is 0x%4x\n", PcdGet64 (PcdGicItsBase))); > + > // Get CoreCount which was determined eariler after parsing device tree > NumCores = PcdGet32 (PcdCoreCount); > > @@ -98,7 +103,8 @@ AddMadtTable ( > TableSize = sizeof (EFI_ACPI_6_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER) + > (sizeof (EFI_ACPI_6_0_GIC_STRUCTURE) * NumCores) + > sizeof (EFI_ACPI_6_0_GIC_DISTRIBUTOR_STRUCTURE) + > - sizeof (EFI_ACPI_6_0_GICR_STRUCTURE); > + sizeof (EFI_ACPI_6_0_GICR_STRUCTURE) + > + sizeof (EFI_ACPI_6_5_GIC_ITS_STRUCTURE); > > Status = gBS->AllocatePages ( > AllocateAnyPages, > @@ -138,6 +144,10 @@ AddMadtTable ( > CopyMem (New, &Gicr, sizeof (EFI_ACPI_6_0_GICR_STRUCTURE)); > New += sizeof (EFI_ACPI_6_0_GICR_STRUCTURE); > > + // GIC ITS Structure > + CopyMem (New, &Gic_Its, sizeof (EFI_ACPI_6_5_GIC_ITS_STRUCTURE)); > + New += sizeof (EFI_ACPI_6_5_GIC_ITS_STRUCTURE); > + > AcpiPlatformChecksum ((UINT8*) PageAddress, TableSize); > > Status = AcpiTable->InstallAcpiTable ( > diff --git a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuPlatformDxe/SbsaQemuPlatformDxe.c b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuPlatformDxe/SbsaQemuPlatformDxe.c > index f6a3e84483fe..ddcca2b7243c 100644 > --- a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuPlatformDxe/SbsaQemuPlatformDxe.c > +++ b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuPlatformDxe/SbsaQemuPlatformDxe.c > @@ -86,5 +86,15 @@ InitializeSbsaQemuPlatformDxe ( > > DEBUG ((DEBUG_INFO, "GICR base: 0x%x\n", Arg0)); > > + SmcResult = ArmCallSmc0 (SIP_SVC_GET_GIC_ITS, &Arg0, NULL, NULL); > + if (SmcResult == SMC_ARCH_CALL_SUCCESS) { > + Result = PcdSet64S (PcdGicItsBase, Arg0); > + ASSERT_RETURN_ERROR (Result); > + } > + > + Arg0 = PcdGet64 (PcdGicItsBase); > + > + DEBUG ((DEBUG_INFO, "GICI base: 0x%x\n", Arg0)); > + > return EFI_SUCCESS; > } > diff --git a/Silicon/Qemu/SbsaQemu/AcpiTables/Iort.aslc b/Silicon/Qemu/SbsaQemu/AcpiTables/Iort.aslc > new file mode 100644 > index 000000000000..ec4ce504efd1 > --- /dev/null > +++ b/Silicon/Qemu/SbsaQemu/AcpiTables/Iort.aslc > @@ -0,0 +1,135 @@ > +/** @file > + > + Copyright (c) 2023, Linaro Ltd. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > + > +#pragma pack(1) > + > +typedef struct { > + EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE Node; > + UINT32 Identifiers; > +} SBSA_EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE; > + > +typedef struct > +{ > + EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE SmmuNode; > + EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE SmmuIdMap; > +} SBSA_EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE; > + > +typedef struct > +{ > + EFI_ACPI_6_0_IO_REMAPPING_RC_NODE RcNode; > + EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE RcIdMap; > +} SBSA_EFI_ACPI_6_0_IO_REMAPPING_RC_NODE; > + > +typedef struct { > + EFI_ACPI_6_0_IO_REMAPPING_TABLE Iort; > + SBSA_EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE ItsNode; > + SBSA_EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE SmmuNode; > + SBSA_EFI_ACPI_6_0_IO_REMAPPING_RC_NODE RcNode; > +} SBSA_IO_REMAPPING_STRUCTURE; > + > +#pragma pack () > + > +STATIC SBSA_IO_REMAPPING_STRUCTURE Iort = { > + { > + SBSAQEMU_ACPI_HEADER(EFI_ACPI_6_0_IO_REMAPPING_TABLE_SIGNATURE, > + SBSA_IO_REMAPPING_STRUCTURE, > + EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00), > + 3, // NumNodes > + sizeof(EFI_ACPI_6_0_IO_REMAPPING_TABLE), // NodeOffset > + 0 // Reserved > + }, > + // SBSA_EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE > + { > + // EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE > + { > + // EFI_ACPI_6_0_IO_REMAPPING_NODE > + { > + EFI_ACPI_IORT_TYPE_ITS_GROUP, // Type > + sizeof (SBSA_EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE), // Length > + 0, // Revision > + 0, // Reserved > + 0, // NumIdMappings > + 0, // IdReference > + }, > + 1, // ITS count > + }, > + 0, // GIC ITS Identifiers > + }, > + // SMMU > + { > + // EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE > + { > + // EFI_ACPI_6_0_IO_REMAPPING_NODE > + { > + EFI_ACPI_IORT_TYPE_SMMUv3, // Type > + sizeof (SBSA_EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE), // Length > + 2, // Revision > + 0, // Reserved > + 1, // NumIdMapping > + OFFSET_OF (SBSA_EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE, SmmuIdMap), // IdReference > + }, > + 0x60050000, // Base address > + EFI_ACPI_IORT_SMMUv3_FLAG_COHAC_OVERRIDE, // Flags > + 0, // Reserved > + 0, // VATOS address > + EFI_ACPI_IORT_SMMUv3_MODEL_GENERIC, // SMMUv3 Model > + 74, // Event > + 75, // Pri > + 77, // Gerror > + 76, // Sync > + 0, // Proximity domain > + 1, // DevIDMappingIndex > + }, > + // EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE > + { > + 0x0000, // InputBase > + 0xffff, // NumIds > + 0x0000, // OutputBase > + OFFSET_OF (SBSA_IO_REMAPPING_STRUCTURE, ItsNode), // OutputReference > + 0, // Flags > + }, > + }, > + // SBSA_EFI_ACPI_6_0_IO_REMAPPING_RC_NODE > + { > + // EFI_ACPI_6_0_IO_REMAPPING_RC_NODE > + { > + // EFI_ACPI_6_0_IO_REMAPPING_NODE > + { > + EFI_ACPI_IORT_TYPE_ROOT_COMPLEX, // Type > + sizeof (SBSA_EFI_ACPI_6_0_IO_REMAPPING_RC_NODE), // Length > + 0, // Revision > + 0, // Reserved > + 1, // NumIdMappings > + OFFSET_OF (SBSA_EFI_ACPI_6_0_IO_REMAPPING_RC_NODE, RcIdMap) // IdReference > + }, > + 1, // CacheCoherent > + 0, // AllocationHints > + 0, // Reserved > + 0, // MemoryAccessFlags > + EFI_ACPI_IORT_ROOT_COMPLEX_ATS_UNSUPPORTED, // AtsAttribute > + 0x0, // PciSegmentNumber > + //0, //MemoryAddressSizeLimit > + }, > + // EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE > + { > + 0x0000, // InputBase > + 0xffff, // NumIds > + 0x0000, // OutputBase > + OFFSET_OF (SBSA_IO_REMAPPING_STRUCTURE, SmmuNode), // OutputReference > + 0, // Flags > + } > + } > +}; > + > +#pragma pack() Either this or the previous identical line is superfluous. I hope it's this one. > + > +VOID* CONST ReferenceAcpiTable = &Iort; > \ No newline at end of file ^ / Leif > -- > 2.41.0 > -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107931): https://edk2.groups.io/g/devel/message/107931 Mute This Topic: https://groups.io/mt/100874752/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=-