diff options
author | jmbills <42755197+jmbills@users.noreply.github.com> | 2020-09-08 23:40:52 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-08 23:40:52 +0300 |
commit | c16fb8893b19075db4bcf3b5bf33c1db8c3ca2bd (patch) | |
tree | ca75379d317be9cc1757a00e0352a048b5d3200b /meta-openbmc-mods | |
parent | d81f2708c4462a62e3b5e8d08643eb2b8895dde7 (diff) | |
parent | f99301c1a626951ee7feee081a1494e795d0e243 (diff) | |
download | openbmc-c16fb8893b19075db4bcf3b5bf33c1db8c3ca2bd.tar.xz |
Merge pull request #47 from Intel-BMC/update
Update to internal 0.74
Diffstat (limited to 'meta-openbmc-mods')
62 files changed, 5630 insertions, 231 deletions
diff --git a/meta-openbmc-mods/meta-ast2500/conf/machine/include/intel-ast2500.inc b/meta-openbmc-mods/meta-ast2500/conf/machine/include/intel-ast2500.inc index 1889831c8..3e7bd152f 100644 --- a/meta-openbmc-mods/meta-ast2500/conf/machine/include/intel-ast2500.inc +++ b/meta-openbmc-mods/meta-ast2500/conf/machine/include/intel-ast2500.inc @@ -1,5 +1,8 @@ KMACHINE = "aspeed" -KERNEL_DEVICETREE = "${KMACHINE}-bmc-intel-ast2500.dtb" +KERNEL_DEVICETREE = " \ + ${KMACHINE}-bmc-intel-ast2500.dtb \ + ${KMACHINE}-bmc-intel-s2600wf.dtb \ + " require conf/machine/include/ast2500.inc require conf/machine/include/obmc-bsp-si-common.inc diff --git a/meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0045-Apply-WDT1-2-reset-mask-to-reset-needed-controller.patch b/meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0045-Apply-WDT1-2-reset-mask-to-reset-needed-controller.patch index ea7a582df..94e93db7f 100644 --- a/meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0045-Apply-WDT1-2-reset-mask-to-reset-needed-controller.patch +++ b/meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0045-Apply-WDT1-2-reset-mask-to-reset-needed-controller.patch @@ -23,13 +23,12 @@ in order to avoid the host hang. 1. SDRAM controller 2. AHB Bridges 3. Graphics CRT controller -4. Reset Video Engine -5. LPC controller -6. CRT mode 2D Engine -7. PWM controller -8. MCTP Controller -9. X- DMA Controller -10. SPI controller +4. LPC controller +5. CRT mode 2D Engine +6. PWM controller +7. MCTP Controller +8. X- DMA Controller +9. SPI controller Quick Step to reproduce: Stop the BMC in uboot and add below bootcmd command @@ -71,10 +70,10 @@ index b404353..97253f4 100644 str r1, [r0] ldr r0, =0x1e78501c @ restore normal mask setting - ldr r1, =0x023FFFF3 @ added 2016.09.06 -+ ldr r1, =0x023CD773 @ Changed 2020.06.18 ++ ldr r1, =0x023CDF73 @ Changed 2020.06.18 + str r1, [r0] + ldr r0, =0x1e78503c @ restore normal mask setting -+ ldr r1, =0x023CD773 @ Changed 2020.07.08 ++ ldr r1, =0x023CDF73 @ Changed 2020.07.08 str r1, [r0] b bypass_first_reset diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/CPC-Baseboard.json b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/CPC-Baseboard.json index 44eda0e66..94e7e7daa 100644 --- a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/CPC-Baseboard.json +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/CPC-Baseboard.json @@ -981,6 +981,30 @@ "Type": "IpmbSensor" }, { + "Address": 190, + "Class": "MESensor", + "Name": "Host Cpu Utilization", + "SensorType": "utilization", + "ScaleValue": 0.392, + "Type": "IpmbSensor" + }, + { + "Address": 191, + "Class": "MESensor", + "Name": "Host Pci Bandwidth Utilization", + "SensorType": "utilization", + "ScaleValue": 0.392, + "Type": "IpmbSensor" + }, + { + "Address": 192, + "Class": "MESensor", + "Name": "Host Memory Bandwidth Utilization", + "SensorType": "utilization", + "ScaleValue": 0.392, + "Type": "IpmbSensor" + }, + { "Address": "0x71", "Bus": 2, "ChannelNames": [ @@ -1433,7 +1457,7 @@ "Class": "temp", "FFGainCoefficient": 0.0, "FFOffCoefficient": 0.0, - "ICoefficient": -1.0, + "ICoefficient": -0.2, "ILimitMax": 100, "ILimitMin": 30, "Inputs": [ @@ -1444,9 +1468,9 @@ "OutLimitMax": 100, "OutLimitMin": 30, "Outputs": [], - "PCoefficient": -0.15, + "PCoefficient": -0.1, "PositiveHysteresis": 0.0, - "SetPoint": 80.0, + "SetPoint": 75.0, "SlewNeg": -1, "SlewPos": 0.0, "Type": "Pid", @@ -1458,7 +1482,7 @@ "Class": "temp", "FFGainCoefficient": 0.0, "FFOffCoefficient": 0.0, - "ICoefficient": -1.0, + "ICoefficient": -0.2, "ILimitMax": 100, "ILimitMin": 30, "Inputs": [ @@ -1469,9 +1493,9 @@ "OutLimitMax": 100, "OutLimitMin": 30, "Outputs": [], - "PCoefficient": -0.15, + "PCoefficient": -0.1, "PositiveHysteresis": 0.0, - "SetPoint": 80.0, + "SetPoint": 75.0, "SlewNeg": -1, "SlewPos": 0.0, "Type": "Pid", diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json index 12790632e..83e6deabe 100644 --- a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json @@ -2041,7 +2041,7 @@ "Class": "temp", "FFGainCoefficient": 0.0, "FFOffCoefficient": 0.0, - "ICoefficient": -1.0, + "ICoefficient": -0.2, "ILimitMax": 100, "ILimitMin": 30, "Inputs": [ @@ -2052,9 +2052,9 @@ "OutLimitMax": 100, "OutLimitMin": 30, "Outputs": [], - "PCoefficient": -0.15, + "PCoefficient": -0.1, "PositiveHysteresis": 0.0, - "SetPoint": 80.0, + "SetPoint": 75.0, "SlewNeg": -1, "SlewPos": 0.0, "Type": "Pid", @@ -2066,7 +2066,7 @@ "Class": "temp", "FFGainCoefficient": 0.0, "FFOffCoefficient": 0.0, - "ICoefficient": -1.0, + "ICoefficient": -2.0, "ILimitMax": 100, "ILimitMin": 30, "Inputs": [ @@ -2077,9 +2077,9 @@ "OutLimitMax": 100, "OutLimitMin": 30, "Outputs": [], - "PCoefficient": -0.15, + "PCoefficient": -0.1, "PositiveHysteresis": 0.0, - "SetPoint": 80.0, + "SetPoint": 75.0, "SlewNeg": -1, "SlewPos": 0.0, "Type": "Pid", diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WP-Baseboard.json b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WP-Baseboard.json index 7b128099f..573f1aec6 100644 --- a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WP-Baseboard.json +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WP-Baseboard.json @@ -1567,6 +1567,30 @@ "Type": "IpmbSensor" }, { + "Address": 190, + "Class": "MESensor", + "Name": "Host Cpu Utilization", + "SensorType": "utilization", + "ScaleValue": 0.392, + "Type": "IpmbSensor" + }, + { + "Address": 191, + "Class": "MESensor", + "Name": "Host Pci Bandwidth Utilization", + "SensorType": "utilization", + "ScaleValue": 0.392, + "Type": "IpmbSensor" + }, + { + "Address": 192, + "Class": "MESensor", + "Name": "Host Memory Bandwidth Utilization", + "SensorType": "utilization", + "ScaleValue": 0.392, + "Type": "IpmbSensor" + }, + { "EthIndex": 0, "Name": "Dedicated Management NIC", "Type": "NIC" @@ -2008,7 +2032,7 @@ "Class": "temp", "FFGainCoefficient": 0.0, "FFOffCoefficient": 0.0, - "ICoefficient": -1.0, + "ICoefficient": -0.2, "ILimitMax": 100, "ILimitMin": 30, "Inputs": [ @@ -2019,9 +2043,9 @@ "OutLimitMax": 100, "OutLimitMin": 30, "Outputs": [], - "PCoefficient": -0.15, + "PCoefficient": -0.1, "PositiveHysteresis": 0.0, - "SetPoint": 80.0, + "SetPoint": 75.0, "SlewNeg": -1, "SlewPos": 0.0, "Type": "Pid", @@ -2033,7 +2057,7 @@ "Class": "temp", "FFGainCoefficient": 0.0, "FFOffCoefficient": 0.0, - "ICoefficient": -1.0, + "ICoefficient": -0.2, "ILimitMax": 100, "ILimitMin": 30, "Inputs": [ @@ -2044,9 +2068,9 @@ "OutLimitMax": 100, "OutLimitMin": 30, "Outputs": [], - "PCoefficient": -0.15, + "PCoefficient": -0.1, "PositiveHysteresis": 0.0, - "SetPoint": 80.0, + "SetPoint": 75.0, "SlewNeg": -1, "SlewPos": 0.0, "Type": "Pid", diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0019-Apply-WDT-reset-mask-to-reset-needed-controller.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0019-Apply-WDT-reset-mask-to-reset-needed-controller.patch deleted file mode 100644 index b68975c40..000000000 --- a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0019-Apply-WDT-reset-mask-to-reset-needed-controller.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 5179bc2cba159b9167fee90a2c6a7ea2824df8ad Mon Sep 17 00:00:00 2001 -From: Suryakanth Sekar <suryakanth.sekar@linux.intel.com> -Date: Thu, 18 Jun 2020 05:32:48 +0530 -Subject: [PATCH] Apply WDT reset mask to reset needed controller - -Issue: -Whenever BIOS and BMC warm reset happens at a time. -BIOS is not booting. - -Root caused: -BMC resetting the LPC controller during BMC warm reset. -Which cause BIOS hang as BIOS cannot dump the BIOS serial data. - -Fix: -WDT reset mask has been updated from default to proper value, -such that controllers interacting with host will not be reset -during wdt reset operation. -This was missed earlier, causing BIOS to hang whenever BMC resets, -as BIOS was accessing the serial port (LPC controller). -De-coupling LPC controller will make sure BIOS serial port access -is not disturbed. -Reset mask is updated not to reset the following controllers -additionally on the default mask setting. -1. LPC controller -2. PWM controller -3. GPIO controller - -Quick Step to reproduce: -Stop the BMC in uboot and add below bootcmd command -setenv bootcmd "reset" -Do the System power ON or System warm reset. - -Tested: -1. Ran overnight continous BIOS and BMC warm reset on two SUTs. - -2. Ran the TestApp which dump the BIOS serial port continously and -do the BMC reset. - -3. Stop the BMC in uboot and add below bootcmd command -setenv bootcmd "reset" -Do the System Power ON or System warm reset. - -Signed-off-by: Suryakanth Sekar <suryakanth.sekar@linux.intel.com> -Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> ---- - arch/arm/mach-aspeed/ast2600/platform.S | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S -index d881ba8565f2..68eb0000922a 100644 ---- a/arch/arm/mach-aspeed/ast2600/platform.S -+++ b/arch/arm/mach-aspeed/ast2600/platform.S -@@ -66,6 +66,9 @@ - #define AST_MAC2_BASE (0x1E680000) - #define AST_MAC2_CTRL2 (AST_MAC2_BASE + 0x058) - -+#define AST_WDT1_BASE 0x1E785000 -+#define AST_WDT1_RESET_MASK2 (AST_WDT1_BASE + 0x020) -+ - #define AST_GPIO_BASE (0x1E780000) - #define AST_GPIOYZ_DATA_VALUE (AST_GPIO_BASE + 0x1E0) - -@@ -264,6 +267,12 @@ wait_lock: - str r1, [r0] - - 1: -+ /* disable LPC, PWM and GPIO2 resets on WDT1 reset */ -+ ldr r0, =AST_WDT1_RESET_MASK2 -+ ldr r1, [r0] -+ bic r1, #0x2A00 -+ str r1, [r0] -+ - /* release display port reset */ - ldr r0, =AST_SCU_SYSRST_CTRL_CLR - movw r1, #0x0000 --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0019-Apply-WDT1-2-reset-mask-to-reset-needed-controller.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0019-Apply-WDT1-2-reset-mask-to-reset-needed-controller.patch new file mode 100644 index 000000000..e7af35ff8 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0019-Apply-WDT1-2-reset-mask-to-reset-needed-controller.patch @@ -0,0 +1,98 @@ +From fa401cd64965d506ddeb94fd47eb694a8f2a3862 Mon Sep 17 00:00:00 2001 +From: Suryakanth Sekar <suryakanth.sekar@linux.intel.com> +Date: Thu, 18 Jun 2020 05:32:48 +0530 +Subject: [PATCH] Apply WDT1-2 reset mask to reset needed controller + +Issue: +BMC reset during BIOS serial port access causes BIOS hang. + +Root caused: +BMC resetting the LPC controller during BMC warm reset. +Which cause BIOS hang as BIOS cannot dump the BIOS serial data. + +Fix: +WDT reset mask has been updated from default to proper value, +such that controllers interacting with host will not be reset +during wdt reset operation. +This was missed earlier, causing BIOS to hang whenever BMC resets, +as BIOS was accessing the serial port (LPC controller). +De-coupling LPC controller will make sure BIOS serial port access +is not disturbed. +And also Reset mask is updated not to reset the following +additionally on the default mask setting. +1. LPC controller +2. PWM controller + +Quick Step to reproduce: + Stop the BMC in uboot and add below bootcmd command + setenv bootcmd "reset" + Do the System power ON or System warm reset. + + For WDT2: + boot the BMC and ran the /usr/bin/watch_dog_reset.sh + Do the System Power ON or System warm reset. + +Tested: + 1. Ran overnight continous BIOS and BMC warm reset on two SUTs. + + 2.Ran the TestApp which dump the BIOS serial port continously and + do the BMC reset. + + 3.Stop the BMC in uboot and add below bootcmd command + setenv bootcmd "reset" + Do the System Power ON or System warm reset. + + 4.Ran Over night AC cycle test. Completed +1000 in two systems. + + 5.Stopped at u-boot. + Issue protect off all command + Issue erase all command. + BMC should not hang and able to complete the "erase all" command + +Signed-off-by: Suryakanth Sekar <suryakanth.sekar@linux.intel.com> +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> +--- + arch/arm/mach-aspeed/ast2600/platform.S | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S +index d881ba8565f2..c77640138653 100644 +--- a/arch/arm/mach-aspeed/ast2600/platform.S ++++ b/arch/arm/mach-aspeed/ast2600/platform.S +@@ -66,6 +66,14 @@ + #define AST_MAC2_BASE (0x1E680000) + #define AST_MAC2_CTRL2 (AST_MAC2_BASE + 0x058) + ++#define AST_WDT1_BASE 0x1E785000 ++#define AST_WDT1_RESET_MASK1 (AST_WDT1_BASE + 0x01C) ++#define AST_WDT1_RESET_MASK2 (AST_WDT1_BASE + 0x020) ++ ++#define AST_WDT2_BASE 0x1E785040 ++#define AST_WDT2_RESET_MASK1 (AST_WDT2_BASE + 0x01C) ++#define AST_WDT2_RESET_MASK2 (AST_WDT2_BASE + 0x020) ++ + #define AST_GPIO_BASE (0x1E780000) + #define AST_GPIOYZ_DATA_VALUE (AST_GPIO_BASE + 0x1E0) + +@@ -264,6 +272,18 @@ wait_lock: + str r1, [r0] + + 1: ++ /* disable LPC and PWM resets on WDT1 reset */ ++ ldr r0, =AST_WDT1_RESET_MASK2 ++ ldr r1, [r0] ++ bic r1, #0x2800 ++ str r1, [r0] ++ ++ /* disable LPC and PWM resets on WDT2 reset */ ++ ldr r0, =AST_WDT2_RESET_MASK2 ++ ldr r1, [r0] ++ bic r1, #0x2800 ++ str r1, [r0] ++ + /* release display port reset */ + ldr r0, =AST_SCU_SYSRST_CTRL_CLR + movw r1, #0x0000 +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend index ce22b2057..c2cf07ab3 100644 --- a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend @@ -25,7 +25,7 @@ SRC_URI_append_intel-ast2600 = " \ file://0016-Add-system-reset-status-support.patch \ file://0017-Manufacturing-mode-physical-presence-detection.patch \ file://0018-Add-a-workaround-to-cover-VGA-memory-size-bug-in-A0.patch \ - file://0019-Apply-WDT-reset-mask-to-reset-needed-controller.patch \ + file://0019-Apply-WDT1-2-reset-mask-to-reset-needed-controller.patch \ file://0020-Add-BMC-running-indicator-LED-control.patch \ file://0022-Reboot-into-UBOOT-on-Watchdog-Failures.patch \ " diff --git a/meta-openbmc-mods/meta-ast2600/recipes-phosphor/configuration/entity-manager/AC-Baseboard.json b/meta-openbmc-mods/meta-ast2600/recipes-phosphor/configuration/entity-manager/AC-Baseboard.json index add4ca372..0ec6c3611 100644 --- a/meta-openbmc-mods/meta-ast2600/recipes-phosphor/configuration/entity-manager/AC-Baseboard.json +++ b/meta-openbmc-mods/meta-ast2600/recipes-phosphor/configuration/entity-manager/AC-Baseboard.json @@ -616,20 +616,6 @@ "Type": "FanRedundancy" }, { - "Direction": "Input", - "Index": 214, - "Name": "SMI Input", - "Polarity": "High", - "Type": "Gpio" - }, - { - "Direction": "Input", - "Index": 218, - "Name": "ID Button", - "Polarity": "Low", - "Type": "Gpio" - }, - { "Name": "System Fan connector 1", "Pwm": 0, "Tachs": [ diff --git a/meta-openbmc-mods/meta-common/classes/image_types_intel_pfr.bbclass b/meta-openbmc-mods/meta-common/classes/image_types_intel_pfr.bbclass index e961ae463..2161cdf8d 100644 --- a/meta-openbmc-mods/meta-common/classes/image_types_intel_pfr.bbclass +++ b/meta-openbmc-mods/meta-common/classes/image_types_intel_pfr.bbclass @@ -32,58 +32,89 @@ RC_IMAGE_OFFSET = "0x02a00000" # RC_IMAGE_PAGE= 0x02a00000/1024 = 0xA800 or 43008 RC_IMAGE_PAGE = "43008" -do_image_pfr () { - bbplain "Generating Intel PFR compliant BMC image" - - bbplain "Build Version = ${build_version}" - bbplain "Build Number = ${build_number}" - bbplain "Build Hash = ${build_hash}" - bbplain "Build SHA = ${SHA_NAME}" - - mkdir -p "${PFR_IMAGES_DIR}" - cd "${PFR_IMAGES_DIR}" - - # python script that does the creating PFM, BMC compressed and unsigned images from BMC 128MB raw binary file. - ${PFR_SCRIPT_DIR}/pfr_image.py ${PFR_CFG_DIR}/pfr_manifest.json ${DEPLOY_DIR_IMAGE}/image-mtd ${build_version} ${build_number} ${build_hash} ${SHA} +do_image_pfr_internal () { + local manifest_json="pfr_manifest${bld_suffix}.json" + local pfmconfig_xml="pfm_config${bld_suffix}.xml" + local bmcconfig_xml="bmc_config${bld_suffix}.xml" + local pfm_signed_bin="pfm_signed${bld_suffix}.bin" + local signed_cap_bin="bmc_signedcap${bld_suffix}.bin" + local unsigned_cap_bin="bmc_unsigned_cap${bld_suffix}.bin" + local unsigned_cap_align_bin="bmc_unsigned_cap${bld_suffix}.bin_aligned" + local output_bin="image-mtd-pfr${bld_suffix}" + + # python script that does creating PFM & BMC unsigned, compressed image (from BMC 128MB raw binary file). + ${PFR_SCRIPT_DIR}/pfr_image.py -m ${PFR_CFG_DIR}/${manifest_json} -i ${DEPLOY_DIR_IMAGE}/image-mtd -n ${build_version} -b ${build_number} \ + -h ${build_hash} -s ${SHA} -o ${output_bin} # sign the PFM region - ${PFR_SCRIPT_DIR}/blocksign -c ${PFR_CFG_DIR}/pfm_config.xml -o ${PFR_IMAGES_DIR}/pfm_signed.bin ${PFR_IMAGES_DIR}/pfm.bin -v + ${PFR_SCRIPT_DIR}/blocksign -c ${PFR_CFG_DIR}/${pfmconfig_xml} -o ${PFR_IMAGES_DIR}/${pfm_signed_bin} ${PFR_IMAGES_DIR}/pfm.bin -v # Add the signed PFM to rom image - dd bs=1k conv=notrunc seek=${PFM_OFFSET_PAGE} if=${PFR_IMAGES_DIR}/pfm_signed.bin of=${PFR_IMAGES_DIR}/image-mtd-pfr + dd bs=1k conv=notrunc seek=${PFM_OFFSET_PAGE} if=${PFR_IMAGES_DIR}/${pfm_signed_bin} of=${PFR_IMAGES_DIR}/${output_bin} # Create unsigned BMC update capsule - append with 1. pfm_signed, 2. pbc, 3. bmc compressed - dd if=${PFR_IMAGES_DIR}/pfm_signed.bin bs=1k >> ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin + dd if=${PFR_IMAGES_DIR}/${pfm_signed_bin} bs=1k >> ${PFR_IMAGES_DIR}/${unsigned_cap_bin} - dd if=${PFR_IMAGES_DIR}/pbc.bin bs=1k >> ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin + dd if=${PFR_IMAGES_DIR}/pbc.bin bs=1k >> ${PFR_IMAGES_DIR}/${unsigned_cap_bin} - dd if=${PFR_IMAGES_DIR}/bmc_compressed.bin bs=1k >> ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin + dd if=${PFR_IMAGES_DIR}/bmc_compressed.bin bs=1k >> ${PFR_IMAGES_DIR}/${unsigned_cap_bin} # Sign the BMC update capsule - ${PFR_SCRIPT_DIR}/blocksign -c ${PFR_CFG_DIR}/bmc_config.xml -o ${PFR_IMAGES_DIR}/bmc_signed_cap.bin ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin -v + ${PFR_SCRIPT_DIR}/blocksign -c ${PFR_CFG_DIR}/${bmcconfig_xml} -o ${PFR_IMAGES_DIR}/${signed_cap_bin} ${PFR_IMAGES_DIR}/${unsigned_cap_bin} -v # Add the signed bmc update capsule to full rom image @ 0x2a00000 - dd bs=1k conv=notrunc seek=${RC_IMAGE_PAGE} if=${PFR_IMAGES_DIR}/bmc_signed_cap.bin of=${PFR_IMAGES_DIR}/image-mtd-pfr - - # Append date and time to all the PFR images - mv ${PFR_IMAGES_DIR}/pfm_signed.bin ${PFR_IMAGES_DIR}/pfm_signed-${DATETIME}.bin - mv ${PFR_IMAGES_DIR}/pfm.bin ${PFR_IMAGES_DIR}/pfm-${DATETIME}.bin - mv ${PFR_IMAGES_DIR}/pbc.bin ${PFR_IMAGES_DIR}/pbc-${DATETIME}.bin - mv ${PFR_IMAGES_DIR}/bmc_compressed.bin ${PFR_IMAGES_DIR}/bmc_compressed-${DATETIME}.bin - mv ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin ${PFR_IMAGES_DIR}/bmc_unsigned_cap-${DATETIME}.bin - mv ${PFR_IMAGES_DIR}/bmc_signed_cap.bin ${PFR_IMAGES_DIR}/bmc_signed_cap-${DATETIME}.bin - mv ${PFR_IMAGES_DIR}/image-mtd-pfr ${PFR_IMAGES_DIR}/image-mtd-pfr-${DATETIME}.bin + dd bs=1k conv=notrunc seek=${RC_IMAGE_PAGE} if=${PFR_IMAGES_DIR}/${signed_cap_bin} of=${PFR_IMAGES_DIR}/${output_bin} + + # Rename all PFR output images by appending date and time, so that they don't meddle with subsequent call to this function. + mv ${PFR_IMAGES_DIR}/${pfm_signed_bin} ${PFR_IMAGES_DIR}/pfm_signed${bld_suffix}-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/${unsigned_cap_bin} ${PFR_IMAGES_DIR}/bmc_unsigned_cap${bld_suffix}-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/${unsigned_cap_align_bin} ${PFR_IMAGES_DIR}/bmc_unsigned_cap${bld_suffix}-${DATETIME}.bin_aligned + mv ${PFR_IMAGES_DIR}/${signed_cap_bin} ${PFR_IMAGES_DIR}/bmc_signed_cap${bld_suffix}-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/${output_bin} ${PFR_IMAGES_DIR}/image-mtd-pfr${bld_suffix}-${DATETIME}.bin + # Append date and time to all 'pfr_image.py' output binaries. + mv ${PFR_IMAGES_DIR}/pfm.bin ${PFR_IMAGES_DIR}/pfm${bld_suffix}-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/pfm.bin_aligned ${PFR_IMAGES_DIR}/pfm${bld_suffix}-${DATETIME}.bin_aligned + mv ${PFR_IMAGES_DIR}/pbc.bin ${PFR_IMAGES_DIR}/pbc${bld_suffix}-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/bmc_compressed.bin ${PFR_IMAGES_DIR}/bmc_compressed${bld_suffix}-${DATETIME}.bin # Use relative links. The build process removes some of the build # artifacts and that makes fully qualified pathes break. Relative links # work because of the 'cd "${PFR_IMAGES_DIR}"' at the start of this section. - ln -sf image-mtd-pfr-${DATETIME}.bin ${PFR_IMAGES_DIR}/image-mtd-pfr.bin - ln -sf image-mtd-pfr-${DATETIME}.bin ${PFR_IMAGES_DIR}/OBMC-${@ do_get_version(d)}-pfr-full.ROM - ln -sf bmc_signed_cap-${DATETIME}.bin ${PFR_IMAGES_DIR}/bmc_signed_cap.bin - ln -sf bmc_signed_cap-${DATETIME}.bin ${PFR_IMAGES_DIR}/OBMC-${@ do_get_version(d)}-pfr-oob.bin + ln -sf image-mtd-pfr${bld_suffix}-${DATETIME}.bin ${PFR_IMAGES_DIR}/image-mtd-pfr${bld_suffix}.bin + ln -sf image-mtd-pfr${bld_suffix}-${DATETIME}.bin ${PFR_IMAGES_DIR}/OBMC${bld_suffix}-${@ do_get_version(d)}-pfr-full.ROM + ln -sf bmc_signed_cap${bld_suffix}-${DATETIME}.bin ${PFR_IMAGES_DIR}/bmc_signed_cap${bld_suffix}.bin + ln -sf bmc_signed_cap${bld_suffix}-${DATETIME}.bin ${PFR_IMAGES_DIR}/OBMC${bld_suffix}-${@ do_get_version(d)}-pfr-oob.bin +} + +do_image_pfr () { + # PFR image, additional build components information suffix. + local bld_suffix="" + + bbplain "Generating Intel PFR compliant BMC image for '${PRODUCT_GENERATION}'" + + bbplain "Build Version = ${build_version}" + bbplain "Build Number = ${build_number}" + bbplain "Build Hash = ${build_hash}" + bbplain "Build SHA = ${SHA_NAME}" + + mkdir -p "${PFR_IMAGES_DIR}" + cd "${PFR_IMAGES_DIR}" + + # First, Build default image. + bld_suffix="" + do_image_pfr_internal + + if [ ${PRODUCT_GENERATION} = "wht" ]; then + #Build additional component images also, for whitley generation, if needed. + if ! [ -z ${BUILD_SEGD} ] && [ ${BUILD_SEGD} = "yes" ]; then + bld_suffix="_d" + do_image_pfr_internal + fi + fi } -do_image_pfr[vardepsexclude] += "DATE DATETIME" +# Include 'do_image_pfr_internal' in 'vardepsexclude';Else Taskhash mismatch error will occur. +do_image_pfr[vardepsexclude] += "do_image_pfr_internal DATE DATETIME BUILD_SEGD" do_image_pfr[vardeps] += "IPMI_MAJOR IPMI_MINOR IPMI_AUX13 IPMI_AUX14 IPMI_AUX15 IPMI_AUX16" do_image_pfr[depends] += " \ obmc-intel-pfr-image-native:do_populate_sysroot \ diff --git a/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb b/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb index 184f6c0f1..1a1a83dce 100644 --- a/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb +++ b/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb @@ -13,7 +13,7 @@ LICENSE = "Proprietary" LIC_FILES_CHKSUM = "file://LICENSE;md5=43c09494f6b77f344027eea0a1c22830" SRC_URI = "git://github.com/Intel-BMC/crashdump;protocol=git" -SRCREV = "wht-0.65" +SRCREV = "wht-0.9" S = "${WORKDIR}/git" diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb index 170fbdff9..093419202 100644 --- a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb @@ -2,7 +2,7 @@ SUMMARY = "libmctp" DESCRIPTION = "Implementation of MCTP (DTMF DSP0236)" SRC_URI = "git://github.com/openbmc/libmctp.git" -SRCREV = "3ac70d62571953be172a0d16976e383490d25059" +SRCREV = "96d5449211228c141b65dbe60a121c23f6c79cfb" PV = "0.1+git${SRCPV}" diff --git a/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend index 13171277b..cd2011b4a 100644 --- a/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend @@ -2,4 +2,4 @@ EXTRA_OECMAKE += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '-DINTEL_PF EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsecure', '-DBMC_VALIDATION_UNSECURE_FEATURE=ON', '', d)}" EXTRA_OECMAKE += "-DUSING_ENTITY_MANAGER_DECORATORS=OFF" SRC_URI = "git://github.com/openbmc/intel-ipmi-oem.git" -SRCREV = "2030d7c8ebb6ccdbc300bf4967647a3b496c9726" +SRCREV = "04a38ed10db3a0203aa7804bfea6fbd69dafdde8" diff --git a/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus/0001-sdbusplus-settable-timeout-value-for-async_method_ca.patch b/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus/0001-sdbusplus-settable-timeout-value-for-async_method_ca.patch new file mode 100644 index 000000000..82d39cea5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus/0001-sdbusplus-settable-timeout-value-for-async_method_ca.patch @@ -0,0 +1,134 @@ +From 42040cbbc6c6691cef3bee4e42808c3921be9766 Mon Sep 17 00:00:00 2001 +From: Konrad Sztyber <konrad.sztyber@intel.com> +Date: Fri, 27 Mar 2020 16:48:26 +0100 +Subject: [PATCH] sdbusplus: settable timeout value for async_method_call + +Added extra method, asio::connection::async_method_call_timed allowing +the user to specify the value of the timeout to be used for that call +(in microseconds). Using 0 as the timeout results in using the default +value, which is equivalent to calling asio::connection::async_method_call. + +Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com> +Change-Id: Id79772e46a77f62af5b39ec341648e34af6aaf99 +--- + sdbusplus/asio/connection.hpp | 51 +++++++++++++++++--- + sdbusplus/asio/detail/async_send_handler.hpp | 7 ++- + 2 files changed, 46 insertions(+), 12 deletions(-) + +diff --git a/sdbusplus/asio/connection.hpp b/sdbusplus/asio/connection.hpp +index b3ff4fd..ec07e4e 100644 +--- a/sdbusplus/asio/connection.hpp ++++ b/sdbusplus/asio/connection.hpp +@@ -84,7 +84,8 @@ class connection : public sdbusplus::bus::bus + inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler, + void(boost::system::error_code, + message::message&)) +- async_send(message::message& m, MessageHandler&& handler) ++ async_send(message::message& m, MessageHandler&& handler, ++ uint64_t timeout = 0) + { + boost::asio::async_completion< + MessageHandler, void(boost::system::error_code, message::message)> +@@ -92,12 +93,12 @@ class connection : public sdbusplus::bus::bus + detail::async_send_handler<typename boost::asio::async_result< + MessageHandler, void(boost::system::error_code, + message::message)>::completion_handler_type>( +- std::move(init.completion_handler))(get(), m); ++ std::move(init.completion_handler))(get(), m, timeout); + return init.result.get(); + } + + /** @brief Perform an asynchronous method call, with input parameter packing +- * and return value unpacking ++ * and return value unpacking. + * + * @param[in] handler - A function object that is to be called as a + * continuation for the async dbus method call. The +@@ -108,6 +109,8 @@ class connection : public sdbusplus::bus::bus + * @param[in] objpath - The object's path for the call. + * @param[in] interf - The object's interface to call. + * @param[in] method - The object's method to call. ++ * @param[in] timeout - The timeout for the method call in usec (0 results ++ * in using the default value). + * @param[in] a... - Optional parameters for the method call. + * + * @return immediate return of the internal handler registration. The +@@ -116,10 +119,12 @@ class connection : public sdbusplus::bus::bus + * complete. + */ + template <typename MessageHandler, typename... InputArgs> +- void async_method_call(MessageHandler&& handler, const std::string& service, +- const std::string& objpath, +- const std::string& interf, const std::string& method, +- const InputArgs&... a) ++ void async_method_call_timed(MessageHandler&& handler, ++ const std::string& service, ++ const std::string& objpath, ++ const std::string& interf, ++ const std::string& method, uint64_t timeout, ++ const InputArgs&... a) + { + using FunctionTuple = boost::callable_traits::args_t<MessageHandler>; + using FunctionTupleType = +@@ -184,7 +189,37 @@ class connection : public sdbusplus::bus::bus + applyHandler(ec, m); + return; + } +- async_send(m, std::forward<decltype(applyHandler)>(applyHandler)); ++ async_send(m, std::forward<decltype(applyHandler)>(applyHandler), ++ timeout); ++ } ++ ++ /** @brief Perform an asynchronous method call, with input parameter packing ++ * and return value unpacking. Uses the default timeout value. ++ * ++ * @param[in] handler - A function object that is to be called as a ++ * continuation for the async dbus method call. The ++ * arguments to parse on the return are deduced from ++ * the handler's signature and then passed in along ++ * with an error code and optional message::message ++ * @param[in] service - The service to call. ++ * @param[in] objpath - The object's path for the call. ++ * @param[in] interf - The object's interface to call. ++ * @param[in] method - The object's method to call. ++ * @param[in] a... - Optional parameters for the method call. ++ * ++ * @return immediate return of the internal handler registration. The ++ * result of the actual asynchronous call will get unpacked from ++ * the message and passed into the handler when the call is ++ * complete. ++ */ ++ template <typename MessageHandler, typename... InputArgs> ++ void async_method_call(MessageHandler&& handler, const std::string& service, ++ const std::string& objpath, ++ const std::string& interf, const std::string& method, ++ const InputArgs&... a) ++ { ++ async_method_call_timed(std::forward<MessageHandler>(handler), service, ++ objpath, interf, method, 0, a...); + } + + /** @brief Perform a yielding asynchronous method call, with input +diff --git a/sdbusplus/asio/detail/async_send_handler.hpp b/sdbusplus/asio/detail/async_send_handler.hpp +index bb896ad..cb91f51 100644 +--- a/sdbusplus/asio/detail/async_send_handler.hpp ++++ b/sdbusplus/asio/detail/async_send_handler.hpp +@@ -35,12 +35,11 @@ struct async_send_handler + {} + async_send_handler(Handler& handler) : handler_(handler) + {} +- void operator()(sd_bus* conn, message::message& mesg) ++ void operator()(sd_bus* conn, message::message& mesg, uint64_t timeout) + { + async_send_handler* context = new async_send_handler(std::move(*this)); +- // 0 is the default timeout +- int ec = +- sd_bus_call_async(conn, NULL, mesg.get(), &callback, context, 0); ++ int ec = sd_bus_call_async(conn, NULL, mesg.get(), &callback, context, ++ timeout); + if (ec < 0) + { + // add a deleter to context because handler may throw +-- +2.25.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus/0002-sdbusplus_Add_new_signal_and_extend_set_property_methods.patch b/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus/0002-sdbusplus_Add_new_signal_and_extend_set_property_methods.patch new file mode 100644 index 000000000..21c5b3afa --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus/0002-sdbusplus_Add_new_signal_and_extend_set_property_methods.patch @@ -0,0 +1,78 @@ +From 9589a690577bdb4d2b79894d1c6a9c8396af5c2a Mon Sep 17 00:00:00 2001 +From: Zhikui Ren <zhikui.ren@intel.com> +Date: Fri, 26 Jun 2020 17:42:47 -0700 +Subject: [PATCH] Add new_signal and extend set_property methods to + dbus_interface + +new_signal exports the same member function of sdbusplus::server::interface + +extend set_property to be able to return true only when the property value +is changed. default behavior remains unchanged - returns true when property +is updated successfully, value may be same or changed. + +With these two functions, dbus_interface can broadcast new signal when +a property is changed. This allows a customized message to be sent +when a property changes. + +Tested: +Build test code to use the two new method to create and send new_signal when +a property is changed. + +Signed-off-by: Zhikui Ren <zhikui.ren@intel.com> +Change-Id: I1815885bc77aad2c526b402f1386d4914479e738 + +%% original patch: 0002-sdbusplus_Add_new_signal_and_extend_set_property_methods.patch +--- + sdbusplus/asio/object_server.hpp | 21 +++++++++++++++++++-- + 1 file changed, 19 insertions(+), 2 deletions(-) + +diff --git a/sdbusplus/asio/object_server.hpp b/sdbusplus/asio/object_server.hpp +index 7a3e8e7..35199bc 100644 +--- a/sdbusplus/asio/object_server.hpp ++++ b/sdbusplus/asio/object_server.hpp +@@ -494,7 +494,7 @@ class dbus_interface + + return true; + } +- template <typename PropertyType> ++ template <typename PropertyType, bool changesOnly = false> + bool set_property(const std::string& name, const PropertyType& value) + { + if (!initialized_) +@@ -511,8 +511,12 @@ class dbus_interface + if (status != SetPropertyReturnValue::sameValueUpdated) + { + signal_property(name); ++ return true; ++ } ++ if constexpr (!changesOnly) ++ { ++ return true; + } +- return true; + } + } + return false; +@@ -720,6 +724,19 @@ class dbus_interface + return sd_bus_error_set_const(error, SD_BUS_ERROR_INVALID_ARGS, NULL); + } + ++ /** @brief Create a new signal message. ++ * ++ * @param[in] member - The signal name to create. ++ */ ++ auto new_signal(const char* member) ++ { ++ if (!initialized_) ++ { ++ return message::message(nullptr); ++ } ++ return interface_->new_signal(member); ++ } ++ + bool initialize(const bool skipPropertyChangedSignal = false) + { + // can only register once +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus_%.bbappend b/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus_%.bbappend new file mode 100644 index 000000000..c0b530840 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus_%.bbappend @@ -0,0 +1,6 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += " \ + file://0001-sdbusplus-settable-timeout-value-for-async_method_ca.patch \ + file://0002-sdbusplus_Add_new_signal_and_extend_set_property_methods.patch \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend b/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend index d25bb7753..6df8f5a89 100644 --- a/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend @@ -2,4 +2,4 @@ FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" # Use the latest to support obmc-ikvm properly SRC_URI = "git://github.com/LibVNC/libvncserver" -SRCREV = "38fd347afb6e2b720fdc0dc43bb3e5f179d0ce4e" +SRCREV = "b7195ce95c27255c14382bdc270b2972a7f9347b" diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0004-Connect-HID-gadget-device-dynamically.patch b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0004-Connect-HID-gadget-device-dynamically.patch new file mode 100644 index 000000000..0fe93c604 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0004-Connect-HID-gadget-device-dynamically.patch @@ -0,0 +1,494 @@ +From 9a0f78ab773b33fd0445b23358097ddcd175a58f Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 22 Jul 2020 23:39:18 -0700 +Subject: [PATCH] Connect HID gadget device dynamically + +Connecting HID gadget device statically from the beginning of this +service causes an issue on WHLK test. To prevent the issue, this +commit changes the HID gadget device handling as dynamic so that +the HID gadget device can be connected when this service has at +least one KVM client. + +Tested: /dev/hidg0 and /dev/hidg1 created only when at least one +KVM client is connected. + +Change-Id: I5f6596b9e4e297fb6b507000499fc041460659f7 +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + create_usbhid.sh | 278 ++++++++++++++++++++++++-------------------- + ikvm_input.cpp | 64 +++++++++- + ikvm_input.hpp | 14 +++ + ikvm_server.cpp | 2 + + start-ipkvm.service | 2 +- + 5 files changed, 230 insertions(+), 130 deletions(-) + +diff --git a/create_usbhid.sh b/create_usbhid.sh +index 656299102d7f..d1fa4e036bbe 100644 +--- a/create_usbhid.sh ++++ b/create_usbhid.sh +@@ -1,135 +1,157 @@ + #!/bin/sh + +-new_directory="/sys/kernel/config/usb_gadget/obmc_hid" ++hid_conf_directory="/sys/kernel/config/usb_gadget/obmc_hid" ++dev_name="1e6a0000.usb-vhub" + +-if [ -e "${new_directory}" ]; then +- exit 0 +-fi ++create_hid() { ++ # create gadget ++ mkdir "${hid_conf_directory}" ++ cd "${hid_conf_directory}" ++ ++ # add basic information ++ echo 0x0100 > bcdDevice ++ echo 0x0200 > bcdUSB ++ echo 0x0104 > idProduct # Multifunction Composite Gadget ++ echo 0x1d6b > idVendor # Linux Foundation ++ ++ # create English locale ++ mkdir strings/0x409 ++ ++ echo "OpenBMC" > strings/0x409/manufacturer ++ echo "virtual_input" > strings/0x409/product ++ echo "OBMC0001" > strings/0x409/serialnumber ++ ++ # Create HID keyboard function ++ mkdir functions/hid.0 ++ ++ echo 1 > functions/hid.0/protocol # 1: keyboard ++ echo 8 > functions/hid.0/report_length ++ echo 1 > functions/hid.0/subclass ++ ++ # Binary HID keyboard descriptor ++ # 0x05, 0x01, // USAGE_PAGE (Generic Desktop) ++ # 0x09, 0x06, // USAGE (Keyboard) ++ # 0xa1, 0x01, // COLLECTION (Application) ++ # 0x05, 0x07, // USAGE_PAGE (Keyboard) ++ # 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) ++ # 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) ++ # 0x15, 0x00, // LOGICAL_MINIMUM (0) ++ # 0x25, 0x01, // LOGICAL_MAXIMUM (1) ++ # 0x75, 0x01, // REPORT_SIZE (1) ++ # 0x95, 0x08, // REPORT_COUNT (8) ++ # 0x81, 0x02, // INPUT (Data,Var,Abs) ++ # 0x95, 0x01, // REPORT_COUNT (1) ++ # 0x75, 0x08, // REPORT_SIZE (8) ++ # 0x81, 0x03, // INPUT (Data,Var,Abs) ++ # 0x95, 0x05, // REPORT_COUNT (5) ++ # 0x75, 0x01, // REPORT_SIZE (1) ++ # 0x05, 0x08, // USAGE_PAGE (LEDs) ++ # 0x19, 0x01, // USAGE_MINIMUM (Num Lock) ++ # 0x29, 0x05, // USAGE_MAXIMUM (Kana) ++ # 0x91, 0x02, // OUTPUT (Data,Var,Abs) ++ # 0x95, 0x01, // REPORT_COUNT (1) ++ # 0x75, 0x03, // REPORT_SIZE (3) ++ # 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) ++ # 0x95, 0x06, // REPORT_COUNT (6) ++ # 0x75, 0x08, // REPORT_SIZE (8) ++ # 0x15, 0x00, // LOGICAL_MINIMUM (0) ++ # 0x25, 0x65, // LOGICAL_MAXIMUM (101) ++ # 0x05, 0x07, // USAGE_PAGE (Keyboard) ++ # 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) ++ # 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) ++ # 0x81, 0x00, // INPUT (Data,Ary,Abs) ++ # 0xc0 // END_COLLECTION ++ echo -ne '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x03\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x03\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' > functions/hid.0/report_desc ++ ++ # Create HID mouse function ++ mkdir functions/hid.1 ++ ++ echo 2 > functions/hid.1/protocol # 2: mouse ++ echo 5 > functions/hid.1/report_length ++ echo 1 > functions/hid.1/subclass ++ ++ # Binary HID mouse descriptor (absolute coordinate) ++ # 0x05, 0x01, // USAGE_PAGE (Generic Desktop) ++ # 0x09, 0x02, // USAGE (Mouse) ++ # 0xa1, 0x01, // COLLECTION (Application) ++ # 0x09, 0x01, // USAGE (Pointer) ++ # 0xa1, 0x00, // COLLECTION (Physical) ++ # 0x05, 0x09, // USAGE_PAGE (Button) ++ # 0x19, 0x01, // USAGE_MINIMUM (Button 1) ++ # 0x29, 0x03, // USAGE_MAXIMUM (Button 3) ++ # 0x15, 0x00, // LOGICAL_MINIMUM (0) ++ # 0x25, 0x01, // LOGICAL_MAXIMUM (1) ++ # 0x95, 0x03, // REPORT_COUNT (3) ++ # 0x75, 0x01, // REPORT_SIZE (1) ++ # 0x81, 0x02, // INPUT (Data,Var,Abs) ++ # 0x95, 0x01, // REPORT_COUNT (1) ++ # 0x75, 0x05, // REPORT_SIZE (5) ++ # 0x81, 0x03, // INPUT (Cnst,Var,Abs) ++ # 0x05, 0x01, // USAGE_PAGE (Generic Desktop) ++ # 0x09, 0x30, // USAGE (X) ++ # 0x09, 0x31, // USAGE (Y) ++ # 0x35, 0x00, // PHYSICAL_MINIMUM (0) ++ # 0x46, 0xff, 0x7f, // PHYSICAL_MAXIMUM (32767) ++ # 0x15, 0x00, // LOGICAL_MINIMUM (0) ++ # 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767) ++ # 0x65, 0x11, // UNIT (SI Lin:Distance) ++ # 0x55, 0x00, // UNIT_EXPONENT (0) ++ # 0x75, 0x10, // REPORT_SIZE (16) ++ # 0x95, 0x02, // REPORT_COUNT (2) ++ # 0x81, 0x02, // INPUT (Data,Var,Abs) ++ # 0xc0, // END_COLLECTION ++ # 0xc0 // END_COLLECTION ++ echo -ne '\x05\x01\x09\x02\xa1\x01\x09\x01\xa1\x00\x05\x09\x19\x01\x29\x03\x15\x00\x25\x01\x95\x03\x75\x01\x81\x02\x95\x01\x75\x05\x81\x03\x05\x01\x09\x30\x09\x31\x35\x00\x46\xff\x7f\x15\x00\x26\xff\x7f\x65\x11\x55\x00\x75\x10\x95\x02\x81\x02\xc0\xc0' > functions/hid.1/report_desc ++ ++ # Create configuration ++ mkdir configs/c.1 ++ mkdir configs/c.1/strings/0x409 ++ ++ echo 0x80 > configs/c.1/bmAttributes ++ echo 200 > configs/c.1/MaxPower ++ echo "" > configs/c.1/strings/0x409/configuration ++ ++ # Link HID functions to configuration ++ ln -s functions/hid.0 configs/c.1 ++ ln -s functions/hid.1 configs/c.1 ++} ++ ++connect_hid() { ++ if ! [[ `cat UDC` =~ "${dev_name}:p" ]]; then ++ i=0 ++ num_ports=5 ++ base_usb_dir="/sys/bus/platform/devices/${dev_name}/${dev_name}:p" ++ while [ $i -lt $num_ports ]; do ++ port=$(($i + 1)) ++ i=$port ++ if [ ! -e "${base_usb_dir}${port}/gadget/suspended" ]; then ++ break ++ fi ++ done ++ echo "${dev_name}:p${port}" > UDC ++ fi ++} ++ ++disconnect_hid() { ++ if [[ `cat UDC` =~ "${dev_name}:p" ]]; then ++ echo "" > UDC ++ fi ++} + +-# create gadget + original_directory="$(pwd)" +-mkdir "${new_directory}" +-cd "${new_directory}" +- +-# add basic information +-echo 0x0100 > bcdDevice +-echo 0x0200 > bcdUSB +-echo 0x0104 > idProduct # Multifunction Composite Gadget +-echo 0x1d6b > idVendor # Linux Foundation +- +-# create English locale +-mkdir strings/0x409 +- +-echo "OpenBMC" > strings/0x409/manufacturer +-echo "virtual_input" > strings/0x409/product +-echo "OBMC0001" > strings/0x409/serialnumber +- +-# Create HID keyboard function +-mkdir functions/hid.0 +- +-echo 1 > functions/hid.0/protocol # 1: keyboard +-echo 8 > functions/hid.0/report_length +-echo 1 > functions/hid.0/subclass +- +-# Binary HID keyboard descriptor +-# 0x05, 0x01, // USAGE_PAGE (Generic Desktop) +-# 0x09, 0x06, // USAGE (Keyboard) +-# 0xa1, 0x01, // COLLECTION (Application) +-# 0x05, 0x07, // USAGE_PAGE (Keyboard) +-# 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) +-# 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) +-# 0x15, 0x00, // LOGICAL_MINIMUM (0) +-# 0x25, 0x01, // LOGICAL_MAXIMUM (1) +-# 0x75, 0x01, // REPORT_SIZE (1) +-# 0x95, 0x08, // REPORT_COUNT (8) +-# 0x81, 0x02, // INPUT (Data,Var,Abs) +-# 0x95, 0x01, // REPORT_COUNT (1) +-# 0x75, 0x08, // REPORT_SIZE (8) +-# 0x81, 0x03, // INPUT (Data,Var,Abs) +-# 0x95, 0x05, // REPORT_COUNT (5) +-# 0x75, 0x01, // REPORT_SIZE (1) +-# 0x05, 0x08, // USAGE_PAGE (LEDs) +-# 0x19, 0x01, // USAGE_MINIMUM (Num Lock) +-# 0x29, 0x05, // USAGE_MAXIMUM (Kana) +-# 0x91, 0x02, // OUTPUT (Data,Var,Abs) +-# 0x95, 0x01, // REPORT_COUNT (1) +-# 0x75, 0x03, // REPORT_SIZE (3) +-# 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) +-# 0x95, 0x06, // REPORT_COUNT (6) +-# 0x75, 0x08, // REPORT_SIZE (8) +-# 0x15, 0x00, // LOGICAL_MINIMUM (0) +-# 0x25, 0x65, // LOGICAL_MAXIMUM (101) +-# 0x05, 0x07, // USAGE_PAGE (Keyboard) +-# 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) +-# 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) +-# 0x81, 0x00, // INPUT (Data,Ary,Abs) +-# 0xc0 // END_COLLECTION +-echo -ne '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x03\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x03\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' > functions/hid.0/report_desc +- +-# Create HID mouse function +-mkdir functions/hid.1 +- +-echo 2 > functions/hid.1/protocol # 2: mouse +-echo 5 > functions/hid.1/report_length +-echo 1 > functions/hid.1/subclass +- +-# Binary HID mouse descriptor (absolute coordinate) +-# 0x05, 0x01, // USAGE_PAGE (Generic Desktop) +-# 0x09, 0x02, // USAGE (Mouse) +-# 0xa1, 0x01, // COLLECTION (Application) +-# 0x09, 0x01, // USAGE (Pointer) +-# 0xa1, 0x00, // COLLECTION (Physical) +-# 0x05, 0x09, // USAGE_PAGE (Button) +-# 0x19, 0x01, // USAGE_MINIMUM (Button 1) +-# 0x29, 0x03, // USAGE_MAXIMUM (Button 3) +-# 0x15, 0x00, // LOGICAL_MINIMUM (0) +-# 0x25, 0x01, // LOGICAL_MAXIMUM (1) +-# 0x95, 0x03, // REPORT_COUNT (3) +-# 0x75, 0x01, // REPORT_SIZE (1) +-# 0x81, 0x02, // INPUT (Data,Var,Abs) +-# 0x95, 0x01, // REPORT_COUNT (1) +-# 0x75, 0x05, // REPORT_SIZE (5) +-# 0x81, 0x03, // INPUT (Cnst,Var,Abs) +-# 0x05, 0x01, // USAGE_PAGE (Generic Desktop) +-# 0x09, 0x30, // USAGE (X) +-# 0x09, 0x31, // USAGE (Y) +-# 0x35, 0x00, // PHYSICAL_MINIMUM (0) +-# 0x46, 0xff, 0x7f, // PHYSICAL_MAXIMUM (32767) +-# 0x15, 0x00, // LOGICAL_MINIMUM (0) +-# 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767) +-# 0x65, 0x11, // UNIT (SI Lin:Distance) +-# 0x55, 0x00, // UNIT_EXPONENT (0) +-# 0x75, 0x10, // REPORT_SIZE (16) +-# 0x95, 0x02, // REPORT_COUNT (2) +-# 0x81, 0x02, // INPUT (Data,Var,Abs) +-# 0xc0, // END_COLLECTION +-# 0xc0 // END_COLLECTION +-echo -ne '\x05\x01\x09\x02\xa1\x01\x09\x01\xa1\x00\x05\x09\x19\x01\x29\x03\x15\x00\x25\x01\x95\x03\x75\x01\x81\x02\x95\x01\x75\x05\x81\x03\x05\x01\x09\x30\x09\x31\x35\x00\x46\xff\x7f\x15\x00\x26\xff\x7f\x65\x11\x55\x00\x75\x10\x95\x02\x81\x02\xc0\xc0' > functions/hid.1/report_desc +- +-# Create configuration +-mkdir configs/c.1 +-mkdir configs/c.1/strings/0x409 +- +-echo 0x80 > configs/c.1/bmAttributes +-echo 200 > configs/c.1/MaxPower +-echo "" > configs/c.1/strings/0x409/configuration +- +-# Link HID functions to configuration +-ln -s functions/hid.0 configs/c.1 +-ln -s functions/hid.1 configs/c.1 +- +-# Enable gadget +-dev_name="1e6a0000.usb-vhub" +-i=0 +-num_ports=5 +-base_usb_dir="/sys/bus/platform/devices/${dev_name}/${dev_name}:p" +-while [ $i -lt $num_ports ]; do +- port=$(($i + 1)) +- i=$port +- if [ ! -e "${base_usb_dir}${port}/gadget/suspended" ]; then +- break +- fi +-done +-echo "${dev_name}:p${port}" > UDC ++ ++if [ ! -e "${hid_conf_directory}" ]; then ++ create_hid ++else ++ cd "${hid_conf_directory}" ++fi ++ ++if [ "$1" = "connect" ]; then ++ connect_hid ++elif [ "$1" = "disconnect" ]; then ++ disconnect_hid ++else ++ echo "Invalid option: $1. Use 'connect' or 'disconnect'." ++fi + + cd "${original_directory}" +diff --git a/ikvm_input.cpp b/ikvm_input.cpp +index df12f2715585..c4cce5088461 100644 +--- a/ikvm_input.cpp ++++ b/ikvm_input.cpp +@@ -16,6 +16,8 @@ + + #include "scancodes.hpp" + ++namespace fs = std::filesystem; ++ + namespace ikvm + { + +@@ -27,6 +29,54 @@ Input::Input(const std::string& kbdPath, const std::string& ptrPath) : + keyboardReport{0}, pointerReport{0}, keyboardPath(kbdPath), + pointerPath(ptrPath) + { ++ hidUdcStream.exceptions(std::ofstream::failbit | std::ofstream::badbit); ++ hidUdcStream.open(hidUdcPath, std::ios::out | std::ios::app); ++} ++ ++Input::~Input() ++{ ++ if (keyboardFd >= 0) ++ { ++ close(keyboardFd); ++ } ++ ++ if (pointerFd >= 0) ++ { ++ close(pointerFd); ++ } ++ ++ disconnect(); ++ hidUdcStream.close(); ++} ++ ++void Input::connect() ++{ ++ try ++ { ++ for (const auto& port : fs::directory_iterator(usbVirtualHubPath)) ++ { ++ if (fs::is_directory(port) && !fs::is_symlink(port) && ++ !fs::exists(port.path() / "gadget/suspended")) ++ { ++ const std::string portId = port.path().filename(); ++ hidUdcStream << portId << std::endl; ++ break; ++ } ++ } ++ } ++ catch (fs::filesystem_error& e) ++ { ++ log<level::ERR>("Failed to search USB virtual hub port", ++ entry("ERROR=%s", e.what())); ++ return; ++ } ++ catch (std::ofstream::failure& e) ++ { ++ log<level::ERR>("Failed to connect HID gadget", ++ entry("ERROR=%s", e.what())); ++ return; ++ } ++ + if (!keyboardPath.empty()) + { + keyboardFd = open(keyboardPath.c_str(), O_RDWR | O_CLOEXEC); +@@ -56,16 +106,28 @@ Input::Input(const std::string& kbdPath, const std::string& ptrPath) : + } + } + +-Input::~Input() ++void Input::disconnect() + { + if (keyboardFd >= 0) + { + close(keyboardFd); ++ keyboardFd = -1; + } + + if (pointerFd >= 0) + { + close(pointerFd); ++ pointerFd = -1; ++ } ++ ++ try ++ { ++ hidUdcStream << "" << std::endl; ++ } ++ catch (std::ofstream::failure& e) ++ { ++ log<level::ERR>("Failed to disconnect HID gadget", ++ entry("ERROR=%s", e.what())); + } + } + +diff --git a/ikvm_input.hpp b/ikvm_input.hpp +index 2adc7c106755..aae7cefbef6e 100644 +--- a/ikvm_input.hpp ++++ b/ikvm_input.hpp +@@ -2,6 +2,8 @@ + + #include <rfb/rfb.h> + ++#include <filesystem> ++#include <fstream> + #include <map> + #include <string> + +@@ -29,6 +31,10 @@ class Input + Input(Input&&) = default; + Input& operator=(Input&&) = default; + ++ /* @brief Connects HID gadget to host */ ++ void connect(); ++ /* @brief Disconnects HID gadget from host */ ++ void disconnect(); + /* + * @brief RFB client key event handler + * +@@ -72,6 +78,12 @@ class Input + 0x04, // left alt + 0x40 // right alt + }; ++ /* @brief Path to the HID gadget UDC */ ++ static constexpr const char* hidUdcPath = ++ "/sys/kernel/config/usb_gadget/obmc_hid/UDC"; ++ /* @brief Path to the USB virtual hub */ ++ static constexpr const char* usbVirtualHubPath = ++ "/sys/bus/platform/devices/1e6a0000.usb-vhub"; + /* + * @brief Translates a RFB-specific key code to HID modifier bit + * +@@ -109,6 +121,8 @@ class Input + * of which keys are down + */ + std::map<int, int> keysDown; ++ /* @brief Handle of the HID gadget UDC */ ++ std::ofstream hidUdcStream; + }; + + } // namespace ikvm +diff --git a/ikvm_server.cpp b/ikvm_server.cpp +index ebeaef049d04..1c2e981b7a72 100644 +--- a/ikvm_server.cpp ++++ b/ikvm_server.cpp +@@ -178,6 +178,7 @@ void Server::clientGone(rfbClientPtr cl) + + if (server->numClients-- == 1) + { ++ server->input.disconnect(); + rfbMarkRectAsModified(server->server, 0, 0, server->video.getWidth(), + server->video.getHeight()); + } +@@ -193,6 +194,7 @@ enum rfbNewClientAction Server::newClient(rfbClientPtr cl) + cl->clientFramebufferUpdateRequestHook = clientFramebufferUpdateRequest; + if (!server->numClients++) + { ++ server->input.connect(); + server->pendingResize = false; + server->frameCounter = 0; + } +diff --git a/start-ipkvm.service b/start-ipkvm.service +index 5f945b329a26..60234b231da3 100644 +--- a/start-ipkvm.service ++++ b/start-ipkvm.service +@@ -4,7 +4,7 @@ ConditionPathIsMountPoint=/sys/kernel/config + + [Service] + Restart=always +-ExecStartPre=/usr/bin/create_usbhid.sh ++ExecStartPre=/usr/bin/create_usbhid.sh disconnect + ExecStart=/usr/bin/obmc-ikvm -v /dev/video0 -k /dev/hidg0 -p /dev/hidg1 + + [Install] +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend index 8de421d18..baa93bc04 100644 --- a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend @@ -5,4 +5,5 @@ SRCREV = "861337e8ec92767c4c88237ec5db494a2a67fa8d" SRC_URI += " \ file://0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch \ + file://0004-Connect-HID-gadget-device-dynamically.patch \ " diff --git a/meta-openbmc-mods/meta-common/recipes-intel/host-misc-comm-manager/host-misc-comm-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-intel/host-misc-comm-manager/host-misc-comm-manager_git.bb index 0a07f5ab0..1a55391f9 100644 --- a/meta-openbmc-mods/meta-common/recipes-intel/host-misc-comm-manager/host-misc-comm-manager_git.bb +++ b/meta-openbmc-mods/meta-common/recipes-intel/host-misc-comm-manager/host-misc-comm-manager_git.bb @@ -11,7 +11,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" SRC_URI = "git://github.com/Intel-BMC/host-misc-comm-manager.git;protocol=ssh" -SRCREV = "7e14ddf805cda0cdf3db564081144d9532e555cd" +SRCREV = "17481c639999cda1bfc999fe1703290425c7ce45" inherit cmake systemd SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.Host.Misc.Manager.service" diff --git a/meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb index 3a25900d5..b161868f2 100644 --- a/meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb +++ b/meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb @@ -2,7 +2,7 @@ SUMMARY = "HSBP Manager" DESCRIPTION = "HSBP Manager monitors HSBPs through SMBUS" SRC_URI = "git://github.com/openbmc/s2600wf-misc.git" -SRCREV = "7045b4b283cf1405e832641fb79fcfb2b07c1acb" +SRCREV = "c66735b6e99f69a00c2b5a0b286eb1c37251ccca" PV = "0.1+git${SRCPV}" LICENSE = "Apache-2.0" diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_image.py b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_image.py index b69639f32..c077e5318 100755 --- a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_image.py +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_image.py @@ -14,7 +14,7 @@ # TODO: figure out if active and recovery actually have different sigs # TODO: build hashmap from payload manifest # TODO: figure out exact struct layout for PFR metadata -import os, hashlib, struct, json, sys, subprocess, mmap, io, array, binascii, copy, shutil, re +import os, hashlib, struct, json, sys, subprocess, mmap, io, array, binascii, copy, shutil, re, getopt from array import array from binascii import unhexlify from hashlib import sha1, sha256, sha384, sha512 @@ -84,7 +84,7 @@ class pfm_i2c(object): class pfr_bmc_image(object): # json_file, firmware_file - def __init__(self, manifest, firmware_file, build_ver, build_num, build_hash, sha): + def __init__(self, manifest, firmware_file, build_ver, build_num, build_hash, sha, output_filename): self.manifest = load_manifest(manifest) self.firmware_file = firmware_file @@ -98,7 +98,7 @@ class pfr_bmc_image(object): if self.sha == "1": self.pfm_spi_size_hash = 32 self.sha_version = 0x1 - self.pfr_rom_file = 'image-mtd-pfr' + self.pfr_rom_file = output_filename open(self.pfr_rom_file, 'a').close() self.page_size = PAGE_SIZE @@ -366,20 +366,59 @@ class pfr_bmc_image(object): # write the padding bytes at the end f.write(b'\xff' * padding_bytes) +def usage(prog): + sys.stderr.write(prog + + " -m manifest -i rom-image -n build_version -b build_number -h build_hash -s sha -o output_file_name\n") + def main(): - if len(sys.argv) != 7: #< pfr_image.py manifest.json> <update.bin> <build_version> <build_number> <build_hash> <sha> - print('usage: {} <manifest.json> <firmware.bin> <build_version> <build_number> <build_hash> <sha>'.format(sys.argv[0])) - return + try: + opts, args = getopt.getopt(sys.argv[1:], "m:i:n:b:h:s:o:", + ["manifest=", "image=", "build_version=","build_number=","build_hash=","sha=", "output_file_name="]) + except getopt.GetoptError as err: + sys.stderr.write(str(err) + "\n") + sys.exit(2) + json_file = None + firmware_file = None + build_ver = None + build_num = None + build_hash = None + sha = None + output_filename = None + + for o, a in opts: + if o in ("-m", "--manifest"): + json_file = a + elif o in ("-i", "--image"): + firmware_file = a + elif o in ("-n", "--build_version"): + build_ver = a + elif o in ("-b", "--build_number"): + build_num = a + elif o in ("-h", "--build_hash"): + build_hash = a + elif o in ("-s", "--sha"): + sha = a + elif o in ("-o", "--output_file_name"): + output_filename = a + else: + usage(sys.argv[0]) + assert False, "unhandled argument: " + o + + if json_file is None or firmware_file is None or build_ver is None or build_num is None or build_hash is None or sha is None or output_filename is None: + usage(sys.argv[0]) + sys.exit(-1) + + print("manifest: %s" % json_file) + print("image: %s" % firmware_file) + print("build_ver: %s" % build_ver) + print("build_number: %s" % build_num) + print("build_hash: %s" % build_hash) + print("Sha: %s" % sha) + print("output_filename: %s" % output_filename) - json_file = sys.argv[1] - firmware_file = sys.argv[2] - build_ver = sys.argv[3] - build_num = sys.argv[4] - build_hash = sys.argv[5] - sha = sys.argv[6] # function to generate BMC PFM, PBC header and BMC compressed image - pfr_bmc_image(json_file, firmware_file, build_ver, build_num, build_hash, sha) + pfr_bmc_image(json_file, firmware_file, build_ver, build_num, build_hash, sha ,output_filename) if __name__ == '__main__': main() diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/pfr-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/pfr-manager_%.bbappend index e91a996b5..c6dd34bb1 100644 --- a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/pfr-manager_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/pfr-manager_%.bbappend @@ -1,3 +1,5 @@ # Enable downstream autobump SRC_URI = "git://github.com/openbmc/pfr-manager" -SRCREV = "deab6540336c8f37f076d709d77dd41456ab1605" +SRCREV = "53b8700fd18873cffe7ee70b2306e7c66b2f7037" +DEPENDS += " libgpiod \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb index 46f14d3ed..631a70cef 100644 --- a/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb +++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb @@ -2,7 +2,7 @@ SUMMARY = "SMBIOS MDR version 2 service for Intel based platform" DESCRIPTION = "SMBIOS MDR version 2 service for Intel based platfrom" SRC_URI = "git://github.com/Intel-BMC/mdrv2.git;protocol=ssh" -SRCREV = "5ae0c19064f010c9981cc90f4ddb2031887de4dc" +SRCREV = "095102dfb5e2374834e33d1ec1a5e61388208a9e" S = "${WORKDIR}/git" @@ -15,6 +15,7 @@ inherit cmake pkgconfig inherit obmc-phosphor-systemd SYSTEMD_SERVICE_${PN} += "smbios-mdrv2.service" +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.cpuinfo.service" DEPENDS += " \ autoconf-archive-native \ @@ -25,7 +26,8 @@ DEPENDS += " \ phosphor-dbus-interfaces \ phosphor-dbus-interfaces-native \ phosphor-logging \ + libpeci \ + i2c-tools \ " - PACKAGECONFIG ??= "${@bb.utils.filter('DISTRO_FEATURES', 'smbios-no-dimm', d)}" PACKAGECONFIG[smbios-no-dimm] = "-DDIMM_DBUS=OFF, -DDIMM_DBUS=ON" diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-intel-s2600wf-dts-fixups.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-intel-s2600wf-dts-fixups.patch new file mode 100644 index 000000000..d88fc2383 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-intel-s2600wf-dts-fixups.patch @@ -0,0 +1,477 @@ +From 92c28f515166e4478dd447eb1d33409d14aed954 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Tue, 7 Jul 2020 22:27:10 -0700 +Subject: [PATCH] arm: dts: intel s2600wf dts fixups + +Add fixups for Intel S2600WF dts. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + .../arm/boot/dts/aspeed-bmc-intel-s2600wf.dts | 362 +++++++++++++++++- + 1 file changed, 343 insertions(+), 19 deletions(-) + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts b/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts +index 1deb30ec912c..daa85e947d48 100644 +--- a/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts +@@ -3,14 +3,20 @@ + /dts-v1/; + + #include "aspeed-g5.dtsi" ++#include <dt-bindings/gpio/aspeed-gpio.h> ++#include <dt-bindings/i2c/i2c.h> + + / { +- model = "S2600WF BMC"; ++ model = "Intel S2600WF BMC"; + compatible = "intel,s2600wf-bmc", "aspeed,ast2500"; + ++ aliases { ++ serial4 = &uart5; ++ }; ++ + chosen { + stdout-path = &uart5; +- bootargs = "earlyprintk"; ++ bootargs = "console=ttyS4,115200 earlyprintk"; + }; + + memory@80000000 { +@@ -26,6 +32,32 @@ + no-map; + reg = <0x7f000000 0x01000000>; + }; ++ ++ gfx_memory: framebuffer { ++ size = <0x01000000>; ++ alignment = <0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++ ++ video_engine_memory: jpegbuffer { ++ size = <0x02000000>; /* 32M */ ++ alignment = <0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++ ++ ramoops@9eff0000{ ++ compatible = "ramoops"; ++ reg = <0x9eff0000 0x10000>; ++ record-size = <0x2000>; ++ console-size = <0x2000>; ++ }; ++ }; ++ ++ vga-shared-memory { ++ compatible = "aspeed,ast2500-vga-sharedmem"; ++ reg = <0x9ff00000 0x100000>; + }; + + iio-hwmon { +@@ -36,6 +68,29 @@ + <&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>; + }; + ++ leds { ++ compatible = "gpio-leds"; ++ ++ identify { ++ default-state = "on"; ++ gpios = <&gpio ASPEED_GPIO(S, 6) GPIO_ACTIVE_LOW>; ++ }; ++ ++ status_amber { ++ default-state = "off"; ++ gpios = <&gpio ASPEED_GPIO(S, 5) GPIO_ACTIVE_LOW>; ++ }; ++ ++ status_green { ++ default-state = "keep"; ++ gpios = <&gpio ASPEED_GPIO(S, 4) GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ beeper { ++ compatible = "pwm-beeper"; ++ pwms = <&timer 5 1000000 0>; ++ }; + }; + + &fmc { +@@ -44,35 +99,204 @@ + status = "okay"; + m25p,fast-read; + label = "bmc"; +-#include "openbmc-flash-layout.dtsi" ++#include "openbmc-flash-layout-intel-64MB.dtsi" + }; + }; + +-&spi1 { ++&espi { + status = "okay"; +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_spi1_default>; ++}; + +- flash@0 { +- status = "okay"; +- m25p,fast-read; +- label = "pnor"; ++&jtag { ++ status = "okay"; ++}; ++ ++&peci0 { ++ status = "okay"; ++ gpios = <&gpio ASPEED_GPIO(F, 6) 0>; ++}; ++ ++&syscon { ++ uart-clock-high-speed; ++ status = "okay"; ++ ++ misc_control { ++ compatible = "aspeed,bmc-misc"; ++ uart_port_debug { ++ offset = <0x2c>; ++ bit-mask = <0x1>; ++ bit-shift = <10>; ++ read-only; ++ }; ++ p2a-bridge { ++ offset = <0x180>; ++ bit-mask = <0x1>; ++ bit-shift = <1>; ++ read-only; ++ }; ++ boot-2nd-flash { ++ offset = <0x70>; ++ bit-mask = <0x1>; ++ bit-shift = <17>; ++ read-only; ++ }; ++ chip_id { ++ offset = <0x150>; ++ bit-mask = <0x0fffffff 0xffffffff>; ++ bit-shift = <0>; ++ read-only; ++ reg-width = <64>; ++ hash-data = "d44f9b804976fa23c2e25d62f16154d26520a7e24c5555095fd1b55c027804f1570dcd16189739c640cd7d9a6ce14944a2c4eaf1dc429eed6940e8a83498a474"; ++ }; + }; + }; + +-&uart5 { ++&adc { + status = "okay"; + }; + +-&mac0 { ++&gpio { ++ status = "okay"; ++ /* Enable GPIOE0 and GPIOE2 pass-through by default */ ++ pinctrl-names = "pass-through"; ++ pinctrl-0 = <&pinctrl_gpie0_default ++ &pinctrl_gpie2_default>; ++ gpio-line-names = ++ /*A0-A7*/ "","","","","","","","", ++ /*B0-B7*/ "","","","","","","","", ++ /*C0-C7*/ "","","","","","","","", ++ /*D0-D7*/ "","","","","","","","", ++ /*E0-E7*/ "RESET_BUTTON","RESET_OUT","POWER_BUTTON","POWER_OUT","","","","", ++ /*F0-F7*/ "NMI_OUT","","","","CPU_ERR0","CPU_ERR1","","", ++ /*G0-G7*/ "CPU_ERR2","CPU_CATERR","PCH_BMC_THERMTRIP","LCP_ENTER_BUTTON","LCP_LEFT_BUTTON","FM_BMC_BOARD_SKU_ID5_N","","", ++ /*H0-H7*/ "","","","FM_NODE_ID_1","FM_NODE_ID_2","FM_NODE_ID_3","FM_NODE_ID_4","FM_240VA_STATUS", ++ /*I0-I7*/ "FM_SYS_FAN0_PRSNT_D_N","FM_SYS_FAN1_PRSNT_D_N","FM_SYS_FAN2_PRSNT_D_N","FM_SYS_FAN3_PRSNT_D_N","FM_SYS_FAN4_PRSNT_D_N","FM_SYS_FAN5_PRSNT_D_N","","", ++ /*J0-J7*/ "","","","","","","","", ++ /*K0-K7*/ "","","","","","","","", ++ /*L0-L7*/ "","","","","","","","", ++ /*M0-M7*/ "","","","","","","","", ++ /*N0-N7*/ "","","","","","","","", ++ /*O0-O7*/ "","","","","","","","", ++ /*P0-P7*/ "","","","","","","","", ++ /*Q0-Q7*/ "","","","","","","","PWR_DEBUG_N", ++ /*R0-R7*/ "","XDP_PRST_N","","","","","","CHASSIS_INTRUSION", ++ /*S0-S7*/ "REMOTE_DEBUG_ENABLE","SYSPWROK","RSMRST_N","","","","","", ++ /*T0-T7*/ "","","","","","","","", ++ /*U0-U7*/ "","","","","","","","", ++ /*V0-V7*/ "","","","","","","","", ++ /*W0-W7*/ "","","","","","","","", ++ /*X0-X7*/ "","","","","","","","", ++ /*Y0-Y7*/ "SIO_S3","SIO_S5","","SIO_ONCONTROL","","","","", ++ /*Z0-Z7*/ "","SIO_POWER_GOOD","","","","","","", ++ /*AA0-AA7*/ "P3VBAT_BRIDGE_EN","","","","PREQ_N","TCK_MUX_SEL","SMI","POST_COMPLETE", ++ /*AB0-AB7*/ "","NMI_BUTTON","ID_BUTTON","PS_PWROK","","","","", ++ /*AC0-AC7*/ "","","","","","","",""; ++}; ++ ++&sgpio { + status = "okay"; ++ gpio-line-names = ++ /* SGPIO output lines */ ++ /*OA0-OA7*/ "","","","","","","","", ++ /*OB0-OB7*/ "LED_CPU1_CH1_DIMM1_FAULT","LED_CPU1_CH1_DIMM2_FAULT","LED_CPU1_CH2_DIMM1_FAULT","LED_CPU1_CH2_DIMM2_FAULT","LED_CPU1_CH3_DIMM1_FAULT","LED_CPU1_CH3_DIMM2_FAULT","LED_CPU1_CH4_DIMM1_FAULT","LED_CPU1_CH4_DIMM2_FAULT", ++ /*OC0-OC7*/ "LED_CPU1_CH5_DIMM1_FAULT","LED_CPU1_CH5_DIMM2_FAULT","LED_CPU1_CH6_DIMM1_FAULT","LED_CPU1_CH6_DIMM2_FAULT","LED_FAN1_FAULT","LED_FAN2_FAULT","LED_FAN3_FAULT","LED_FAN4_FAULT", ++ /*OD0-OD7*/ "LED_FAN5_FAULT","LED_FAN6_FAULT","LED_FAN7_FAULT","LED_FAN8_FAULT","LED_CPU2_CH1_DIMM1_FAULT","LED_CPU1_CH1_DIMM2_FAULT","LED_CPU2_CH2_DIMM1_FAULT","LED_CPU2_CH2_DIMM2_FAULT", ++ /*OE0-OE7*/ "LED_CPU2_CH3_DIMM1_FAULT","LED_CPU2_CH3_DIMM2_FAULT","LED_CPU2_CH4_DIMM1_FAULT","LED_CPU2_CH4_DIMM2_FAULT","LED_CPU2_CH5_DIMM1_FAULT","LED_CPU2_CH5_DIMM2_FAULT","LED_CPU2_CH6_DIMM1_FAULT","LED_CPU2_CH6_DIMM2_FAULT", ++ /*OF0-OF7*/ "LED_CPU3_CH1_DIMM1_FAULT","LED_CPU3_CH1_DIMM2_FAULT","LED_CPU3_CH2_DIMM1_FAULT","LED_CPU3_CH2_DIMM2_FAULT","LED_CPU3_CH3_DIMM1_FAULT","LED_CPU3_CH3_DIMM2_FAULT","LED_CPU3_CH4_DIMM1_FAULT","LED_CPU3_CH4_DIMM2_FAULT", ++ /*OG0-OG7*/ "LED_CPU3_CH5_DIMM1_FAULT","LED_CPU3_CH5_DIMM2_FAULT","LED_CPU3_CH6_DIMM1_FAULT","LED_CPU3_CH6_DIMM2_FAULT","LED_CPU4_CH1_DIMM1_FAULT","LED_CPU4_CH1_DIMM2_FAULT","LED_CPU4_CH2_DIMM1_FAULT","LED_CPU4_CH2_DIMM2_FAULT", ++ /*OH0-OH7*/ "LED_CPU4_CH3_DIMM1_FAULT","LED_CPU4_CH3_DIMM2_FAULT","LED_CPU4_CH4_DIMM1_FAULT","LED_CPU4_CH4_DIMM2_FAULT","LED_CPU4_CH5_DIMM1_FAULT","LED_CPU4_CH5_DIMM2_FAULT","LED_CPU4_CH6_DIMM1_FAULT","LED_CPU4_CH6_DIMM2_FAULT", ++ /*OI0-OI7*/ "","","","","","","","", ++ /*OJ0-OJ7*/ "","","","","","","","", ++ /*DUMMY*/ "","","","","","","","", ++ /*DUMMY*/ "","","","","","","","", + ++ /* SGPIO input lines */ ++ /*IA0-IA7*/ "CPU1_PRESENCE","CPU1_THERMTRIP","CPU1_VRHOT","CPU1_FIVR_FAULT","CPU1_MEM_ABCD_VRHOT","CPU1_MEM_EFGH_VRHOT","","", ++ /*IB0-IB7*/ "CPU1_MISMATCH","CPU1_MEM_THERM_EVENT","CPU2_PRESENCE","CPU2_THERMTRIP","CPU2_VRHOT","CPU2_FIVR_FAULT","CPU2_MEM_ABCD_VRHOT","CPU2_MEM_EFGH_VRHOT", ++ /*IC0-IC7*/ "","","CPU2_MISMATCH","CPU2_MEM_THERM_EVENT","","","","", ++ /*ID0-ID7*/ "","","","","","","","", ++ /*IE0-IE7*/ "","","","","","","","", ++ /*IF0-IF7*/ "SGPIO_PLD_MINOR_REV_BIT0","SGPIO_PLD_MINOR_REV_BIT1","SGPIO_PLD_MINOR_REV_BIT2","SGPIO_PLD_MINOR_REV_BIT3","SGPIO_PLD_MAJOR_REV_BIT0","SGPIO_PLD_MAJOR_REV_BIT1","SGPIO_PLD_MAJOR_REV_BIT2","SGPIO_PLD_MAJOR_REV_BIT3", ++ /*IG0-IG7*/ "MAIN_PLD_MINOR_REV_BIT0","MAIN_PLD_MINOR_REV_BIT1","MAIN_PLD_MINOR_REV_BIT2","MAIN_PLD_MINOR_REV_BIT3","MAIN_PLD_MAJOR_REV_BIT0","MAIN_PLD_MAJOR_REV_BIT1","MAIN_PLD_MAJOR_REV_BIT2","MAIN_PLD_MAJOR_REV_BIT3", ++ /*IH0-IH7*/ "","","","","","","","", ++ /*II0-II7*/ "","","","","","","","", ++ /*IJ0-IJ7*/ "","","","","","","",""; ++}; ++ ++&kcs3 { ++ kcs_addr = <0xCA2>; ++ status = "okay"; ++}; ++ ++&kcs4 { ++ kcs_addr = <0xCA4>; ++ status = "okay"; ++}; ++ ++&sio_regs { ++ status = "okay"; ++ sio_status { ++ offset = <0x8C>; ++ bit-mask = <0x1F>; ++ bit-shift = <4>; ++ }; ++}; ++ ++&lpc_sio { ++ status = "okay"; ++}; ++ ++&lpc_snoop { ++ snoop-ports = <0x80>; ++ status = "okay"; ++}; ++ ++&mbox { ++ status = "okay"; ++}; ++ ++&uart_routing { ++ status = "okay"; ++}; ++ ++&uart1 { ++ status = "okay"; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_rmii1_default>; +- clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>, +- <&syscon ASPEED_CLK_MAC1RCLK>; +- clock-names = "MACCLK", "RCLK"; +- use-ncsi; ++ pinctrl-0 = <&pinctrl_txd1_default ++ &pinctrl_rxd1_default ++ &pinctrl_nrts1_default ++ &pinctrl_ndtr1_default ++ &pinctrl_ndsr1_default ++ &pinctrl_ncts1_default ++ &pinctrl_ndcd1_default ++ &pinctrl_nri1_default>; ++}; ++ ++&uart2 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_txd2_default ++ &pinctrl_rxd2_default ++ &pinctrl_nrts2_default ++ &pinctrl_ndtr2_default ++ &pinctrl_ndsr2_default ++ &pinctrl_ncts2_default ++ &pinctrl_ndcd2_default ++ &pinctrl_nri2_default>; ++}; ++ ++&uart3 { ++ status = "okay"; ++}; ++ ++&uart4 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <>; ++}; ++ ++&uart5 { ++ status = "okay"; + }; + + &mac1 { +@@ -82,44 +306,87 @@ + pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>; + }; + ++&mac0 { ++ status = "okay"; ++ use-ncsi; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_rmii1_default>; ++}; ++ ++&i2c0 { ++ multi-master; ++ general-call; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ + &i2c1 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; + status = "okay"; + }; + + &i2c2 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; + status = "okay"; + }; + + &i2c3 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; + status = "okay"; + }; + + &i2c4 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; + status = "okay"; + }; + + &i2c5 { ++ bus-frequency = <1000000>; ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; + status = "okay"; + }; + + &i2c6 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; + status = "okay"; + }; + + &i2c7 { ++ multi-master; ++ #retries = <3>; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; + status = "okay"; + }; + + &i2c13 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; + status = "okay"; + }; + + &gfx { + status = "okay"; ++ memory-region = <&gfx_memory>; + }; + +-&pinctrl { +- aspeed,external-nodes = <&gfx &lhc>; ++&vuart { ++ status = "okay"; + }; + + &pwm_tacho { +@@ -129,4 +396,61 @@ + &pinctrl_pwm2_default &pinctrl_pwm3_default + &pinctrl_pwm4_default &pinctrl_pwm5_default + &pinctrl_pwm6_default &pinctrl_pwm7_default>; ++ ++ fan@0 { ++ reg = <0x00>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x00 0x01>; ++ }; ++ fan@1 { ++ reg = <0x01>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x02 0x03>; ++ }; ++ fan@2 { ++ reg = <0x02>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x04 0x05>; ++ }; ++ fan@3 { ++ reg = <0x03>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x06 0x07>; ++ }; ++ fan@4 { ++ reg = <0x04>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x08 0x09>; ++ }; ++ fan@5 { ++ reg = <0x05>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x0A 0x0B>; ++ }; ++ fan@6 { ++ reg = <0x06>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x0C 0x0D>; ++ }; ++ fan@7 { ++ reg = <0x07>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x0E 0x0F>; ++ }; ++ ++}; ++ ++&timer { ++/* ++ * Available settings: ++ * fttmr010,pwm-outputs = <5>, <6>, <7>, <8>; ++ * pinctrl-0 = <&pinctrl_timer5_default &pinctrl_timer6_default ++ * &pinctrl_timer7_default &pinctrl_timer8_default>; ++ */ ++ fttmr010,pwm-outputs = <6>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_timer6_default>; ++ #pwm-cells = <3>; ++ status = "okay"; ++}; ++ ++&video { ++ status = "okay"; ++ memory-region = <&video_engine_memory>; ++}; ++ ++&vhub { ++ status = "okay"; + }; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0095-pwm-and-tach-driver-changes-for-ast2600.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0095-pwm-and-tach-driver-changes-for-ast2600.patch index 2d624d10f..badda2d60 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0095-pwm-and-tach-driver-changes-for-ast2600.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0095-pwm-and-tach-driver-changes-for-ast2600.patch @@ -21,7 +21,7 @@ index 1894f6ad5edb..9551a17e7f55 100644 #define PWM_RISING_RISING_BIT (0) //pwm rising point bit [7:0] +#define PWM_PERIOD_MAX 255 -+#define PWM_FALLING_DEFAULT 150 /* 58% */ ++#define PWM_FALLING_DEFAULT 255 /* 100% */ + #define ASPEED_TACHO_CTRL 0x08 //TACH0 General Register #define ASPEED_TACHO_CTRL_CH(x) ((x * 0x10) + 0x08) diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0116-watchdog-aspeed-fix-AST2600-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0116-watchdog-aspeed-fix-AST2600-support.patch index 3f71219de..33e142c30 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0116-watchdog-aspeed-fix-AST2600-support.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0116-watchdog-aspeed-fix-AST2600-support.patch @@ -1,31 +1,50 @@ -From f911c7c994bf57685254f3b92e03e999d9cf058a Mon Sep 17 00:00:00 2001 +From 02acccc7dd2ade8cf48aff2312ebb8752c8c98eb Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> Date: Thu, 25 Jun 2020 23:56:15 -0700 Subject: [PATCH] watchdog: aspeed: fix AST2600 support AST2600 provides different function of WDT0C[4] and it doesn't -provides WDT10[1] so this commit fixes driver to make it don't -use these register bits in case of AST2600. +provides WDT10[1] so this commit fixes driver to make it available +on AST2600. Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> --- - drivers/watchdog/aspeed_wdt.c | 13 +++++++------ - 1 file changed, 7 insertions(+), 6 deletions(-) + drivers/watchdog/aspeed_wdt.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c -index 7e00960651fa..5a74b439e3b1 100644 +index 7e00960651fa..b0afeb939686 100644 --- a/drivers/watchdog/aspeed_wdt.c +++ b/drivers/watchdog/aspeed_wdt.c -@@ -279,6 +279,8 @@ static int aspeed_wdt_probe(struct platform_device *pdev) +@@ -47,7 +47,8 @@ MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table); + #define WDT_CTRL_RESET_MODE_SOC (0x00 << 5) + #define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5) + #define WDT_CTRL_RESET_MODE_ARM_CPU (0x10 << 5) +-#define WDT_CTRL_1MHZ_CLK BIT(4) ++#define WDT_CTRL_1MHZ_CLK BIT(4) /* ast2400/2500 */ ++#define WDT_CTRL_WDT_RST_BY_SOC_RST BIT(4) /* ast2600 */ + #define WDT_CTRL_WDT_EXT BIT(3) + #define WDT_CTRL_WDT_INTR BIT(2) + #define WDT_CTRL_RESET_SYSTEM BIT(1) +@@ -277,12 +278,15 @@ static int aspeed_wdt_probe(struct platform_device *pdev) + * On clock rates: + * - ast2400 wdt can run at PCLK, or 1MHz * - ast2500 only runs at 1MHz, hard coding bit 4 to 1 - * - ast2600 always runs at 1MHz +- * - ast2600 always runs at 1MHz ++ * - ast2600 uses WDT0C[4] as 'Enable WDT to be reset by SOC reset' * -+ * Note: ast2600 uses WDT0C[4] as 'Enable WDT to be reset by SOC reset' -+ * * Set the ast2400 to run at 1MHz as it simplifies the driver. */ - if (of_device_is_compatible(np, "aspeed,ast2400-wdt")) -@@ -367,13 +369,12 @@ static int aspeed_wdt_probe(struct platform_device *pdev) +- if (of_device_is_compatible(np, "aspeed,ast2400-wdt")) ++ if (of_device_is_compatible(np, "aspeed,ast2400-wdt") || ++ of_device_is_compatible(np, "aspeed,ast2500-wdt")) + wdt->ctrl = WDT_CTRL_1MHZ_CLK; ++ else if (of_device_is_compatible(np, "aspeed,ast2600-wdt")) ++ wdt->ctrl = WDT_CTRL_WDT_RST_BY_SOC_RST; + + /* + * Control reset on a per-device basis to ensure the +@@ -367,13 +371,12 @@ static int aspeed_wdt_probe(struct platform_device *pdev) writel(duration - 1, wdt->base + WDT_RESET_WIDTH); } @@ -45,5 +64,5 @@ index 7e00960651fa..5a74b439e3b1 100644 dev_set_drvdata(dev, wdt); -- -2.7.4 +2.17.1 diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0118-Recalculate-AW-FCS-on-WrEndPointConfig-command.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0118-Recalculate-AW-FCS-on-WrEndPointConfig-command.patch new file mode 100644 index 000000000..af173e71d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0118-Recalculate-AW-FCS-on-WrEndPointConfig-command.patch @@ -0,0 +1,34 @@ +From 2453c89ead650ab8e21f13c1b0a1b4054e0e7067 Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@linux.intel.com> +Date: Mon, 27 Jul 2020 11:27:47 -0700 +Subject: [PATCH] Recalculate AW FCS on WrEndPointConfig command + +The WrEndPointConfig command requires recalculating the AW FCS +on retry, so set the has_aw_fcs parameter to true. + +Tested: +Ran a WrEndPointConfig command with C-states enabled to confirm +that it correctly retries the command: +peci_cmds WrEndpointConfigPCILocal 0 13 12 0 0x2d4 0x601e0 + +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + drivers/peci/peci-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c +index 426ee2be3271..ba561bf810f9 100644 +--- a/drivers/peci/peci-core.c ++++ b/drivers/peci/peci-core.c +@@ -1059,7 +1059,7 @@ static int peci_cmd_wr_end_pt_cfg(struct peci_adapter *adapter, void *vmsg) + return -EINVAL; + } + +- ret = peci_xfer_with_retries(adapter, msg, false); ++ ret = peci_xfer_with_retries(adapter, msg, true); + + out: + umsg->cc = msg->rx_buf[0]; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg index 5f453510a..077b83bac 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg @@ -13,6 +13,7 @@ CONFIG_PECI_ASPEED=y CONFIG_SENSORS_PECI_CPUTEMP=y CONFIG_SENSORS_PECI_DIMMTEMP=y CONFIG_SENSORS_PECI_CPUPOWER=y +CONFIG_SENSORS_PECI_DIMMPOWER=y CONFIG_CONFIGFS_FS=y CONFIG_BLK_DEV_RAM_SIZE=49152 CONFIG_MAGIC_SYSRQ=y diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend index b176446c3..8250ec919 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend @@ -8,6 +8,7 @@ do_compile_prepend(){ SRC_URI += " \ file://intel.cfg \ file://0001-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch \ + file://0001-arm-dts-intel-s2600wf-dts-fixups.patch \ file://0001-arm-dts-add-DTS-for-Intel-ast2600-platforms.patch \ file://0001-arm-dts-base-aspeed-g6-dtsi-fixups.patch \ file://0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch \ @@ -84,6 +85,7 @@ SRC_URI += " \ file://0112-AST2600-enable-UART-routing.patch \ file://0116-watchdog-aspeed-fix-AST2600-support.patch \ file://0117-Copy-raw-PECI-response-to-user-space-on-timeout.patch \ + file://0118-Recalculate-AW-FCS-on-WrEndPointConfig-command.patch \ " SRC_URI += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'file://0005-128MB-flashmap-for-PFR.patch', '', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend index e76c23fa6..cf402206b 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend @@ -1,6 +1,6 @@ # this is here just to bump faster than upstream SRC_URI = "git://github.com/openbmc/entity-manager.git" -SRCREV = "ac09fe44dba113aacee1d2fd995e137c0d5ea18e" +SRCREV = "e18edb5badc2e16181cfc464a6ccd0ef51dc4548" FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0028-MCTP-Daemon-D-Bus-interface-definition.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0028-MCTP-Daemon-D-Bus-interface-definition.patch index dc44d7a0d..e6afc0117 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0028-MCTP-Daemon-D-Bus-interface-definition.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0028-MCTP-Daemon-D-Bus-interface-definition.patch @@ -1,4 +1,4 @@ -From 9bcc45f1a4d872e9968fdebf675c5fff6921c2f3 Mon Sep 17 00:00:00 2001 +From 65d1772312a76ebfdac6391bb97287c62f18c43f Mon Sep 17 00:00:00 2001 From: "Kowalski, Mariusz" <mariusz.kowalski@intel.com> Date: Thu, 27 Feb 2020 15:48:56 +0100 Subject: [PATCH] MCTP Daemon D-Bus interface definition. @@ -12,14 +12,14 @@ Signed-off-by: Mariusz Kowalski <mariusz.kowalski@intel.com> Signed-off-by: Karol Wachowski <karol.wachowski@intel.com> Change-Id: Ida66f8ffcf00003655edcb0fb0112202797b8e1a --- - xyz/openbmc_project/MCTP/Base.interface.yaml | 231 ++++++++++++++++++ + xyz/openbmc_project/MCTP/Base.interface.yaml | 227 ++++++++++++++++++ .../MCTP/Binding/PCIe.interface.yaml | 29 +++ .../MCTP/Binding/SMBus.interface.yaml | 17 ++ .../MCTP/BusOwner.interface.yaml | 17 ++ - .../MCTP/Endpoint.interface.yaml | 19 ++ - xyz/openbmc_project/MCTP/README.md | 38 +++ + .../MCTP/Endpoint.interface.yaml | 13 + + xyz/openbmc_project/MCTP/README.md | 43 ++++ .../MCTP/SupportedMessageTypes.interface.yaml | 36 +++ - 7 files changed, 387 insertions(+) + 7 files changed, 382 insertions(+) create mode 100644 xyz/openbmc_project/MCTP/Base.interface.yaml create mode 100644 xyz/openbmc_project/MCTP/Binding/PCIe.interface.yaml create mode 100644 xyz/openbmc_project/MCTP/Binding/SMBus.interface.yaml @@ -30,10 +30,10 @@ Change-Id: Ida66f8ffcf00003655edcb0fb0112202797b8e1a diff --git a/xyz/openbmc_project/MCTP/Base.interface.yaml b/xyz/openbmc_project/MCTP/Base.interface.yaml new file mode 100644 -index 0000000..f27c1c7 +index 0000000..9438551 --- /dev/null +++ b/xyz/openbmc_project/MCTP/Base.interface.yaml -@@ -0,0 +1,231 @@ +@@ -0,0 +1,227 @@ +description: > + Mandatory interface for each instance of the MCTP Daemon to expose + the base MCTP daemon and medium type interfaces. @@ -153,10 +153,6 @@ index 0000000..f27c1c7 + type: boolean + description: Support for statically/dynamicly allocated IDs + -+ - name: Uuid -+ type: array[byte] -+ description: Guid - 16bytes -+ + - name: BindingMode + type: enum[self.BindingModeTypes] + description: Bus Owner / Endpoint / Bridge @@ -348,20 +344,14 @@ index 0000000..d46298e + description: Indicates Eid pool is managed by self diff --git a/xyz/openbmc_project/MCTP/Endpoint.interface.yaml b/xyz/openbmc_project/MCTP/Endpoint.interface.yaml new file mode 100644 -index 0000000..b7f9a67 +index 0000000..e4ba4d0 --- /dev/null +++ b/xyz/openbmc_project/MCTP/Endpoint.interface.yaml -@@ -0,0 +1,19 @@ +@@ -0,0 +1,13 @@ +description: + Interface exposed by discovered MCTP endpoints. + +properties: -+ - name: Uuid -+ type: array[byte] -+ description: > -+ Universally unique identifier (UUID), also referred to as a globally -+ unique ID (GUID), for the management controller or management device. -+ + - name: Mode + type: enum[xyz.openbmc_project.MCTP.Base.BindingModeTypes] + description: Endpoint / BusOwner / Bridge @@ -373,10 +363,10 @@ index 0000000..b7f9a67 + MCTP network within a platform. diff --git a/xyz/openbmc_project/MCTP/README.md b/xyz/openbmc_project/MCTP/README.md new file mode 100644 -index 0000000..3255ef2 +index 0000000..c819dbb --- /dev/null +++ b/xyz/openbmc_project/MCTP/README.md -@@ -0,0 +1,38 @@ +@@ -0,0 +1,43 @@ +# MCTP Daemon + +## Overview @@ -405,16 +395,21 @@ index 0000000..3255ef2 +4. Binding interface `xyz.openbmc_project.MCTP.Binding.PCIe` or +`xyz.openbmc_project.MCTP.Binding.SMBus` as per the physical medium in which +this MCTP Daemon is instantiated. ++5. Common UUID interface `xyz.openbmc_project.Common.UUID` which exposes UUID ++in RFC4122 format. + +#### Endpoint object +Exposed under the path `/xyz/openbmc_project/mctp/device/<eid>` with the +following interfaces. +1. `xyz.openbmc_project.MCTP.SupportedMessageTypes` which exposes supported MCTP +message types for the discovered MCTP Endpoint. -+2. `xyz.openbmc_project.MCTP.Endpoint` which exposes properties like UUID and endpoint -+mode (to identify Bus Owner or Bridge or Endpoint) for the discovered MCTP Endpoint. ++2. `xyz.openbmc_project.MCTP.Endpoint` which exposes properties like Network ID ++and endpoint mode (to identify Bus Owner or Bridge or Endpoint) for the discovered ++MCTP Endpoint. +3. `xyz.openbmc_project.MCTP.Bridge` available only for discovered MCTP Bridges to +expose properties like EID pool. (TBD) ++4. Common UUID interface `xyz.openbmc_project.Common.UUID` which exposes UUID ++in RFC4122 format. diff --git a/xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml b/xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml new file mode 100644 index 0000000..fa447ee diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend index 5efc383f0..2e4e23d40 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend @@ -5,6 +5,6 @@ SYSTEMD_SERVICE_${PN} = "phosphor-pid-control.service" EXTRA_OECONF = "--enable-configure-dbus=yes" SRC_URI = "git://github.com/openbmc/phosphor-pid-control.git" -SRCREV = "4b36f265a10048127d93e4b70916c181827c9af2" +SRCREV = "6fc301fbc3775730a0e69f215110ec93bd9026f3" FILES_${PN} = "${bindir}/swampd ${bindir}/setsensor" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0013-remove-image-file-on-pre-script-failures.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0013-remove-image-file-on-pre-script-failures.patch new file mode 100644 index 000000000..d5d0f513e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0013-remove-image-file-on-pre-script-failures.patch @@ -0,0 +1,40 @@ +From ae3a9616b44677f20b4ca534c3f55ccb478fdf55 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@intel.com> +Date: Thu, 16 Jul 2020 14:16:28 -0700 +Subject: [PATCH] remove image file on pre-script failures + +Multiple back-to-back updates of bad images will cause the software +manager to leave junk images hanging around. This is part of a fix that +will remove them if the software manager never gets around to launching +the fwupd.sh script. The other part is that the fwupd.sh script must +always delete the image file on exit, success or failure. + +Tested: posted a garbage file, saw that it was deleted even though + fwupd.sh was never invoked. + +Change-Id: I6b049916a3edcb48f9d4ebe0d4715b94214b4feb +Signed-off-by: Vernon Mauery <vernon.mauery@intel.com> +--- + watch.cpp | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/watch.cpp b/watch.cpp +index ccdf594..c738945 100644 +--- a/watch.cpp ++++ b/watch.cpp +@@ -106,6 +106,15 @@ int Watch::callback(sd_event_source* /* s */, int fd, uint32_t revents, + { + log<level::ERR>("Error processing image", + entry("IMAGE=%s", tarballPath.c_str())); ++ std::error_code ec{}; ++ fs::remove_all(tarballPath, ec); ++ if (!ec) ++ { ++ log<level::ERR>( ++ "Unable to remove image on processing failure", ++ entry("ERROR=%s", ec.message().c_str()), ++ entry("IMAGE=%s", tarballPath.c_str())); ++ } + } + } + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend index ae108bf70..623c4f77e 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend @@ -12,12 +12,13 @@ SRC_URI += "file://0001-Add-more-error-types.patch \ file://0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch \ file://0007-Adding-StandBySpare-for-firmware-activation.patch \ file://0008-item_updater-update-the-bmc_active-objectPath.patch \ + file://0009-Add-ApplyOptions-D-bus-property-under-Software.patch \ file://0011-Fix-for-RedudancyPriority-in-item_updater.patch \ + file://0013-remove-image-file-on-pre-script-failures.patch \ " SRC_URI_PFR = "file://0007-PFR-images-support.patch \ file://0008-PFR-image-HASH-verification.patch \ - file://0009-Add-ApplyOptions-D-bus-property-under-Software.patch \ file://0010-Add-error-reporting-to-pfr_image_manager.patch \ " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-Remove-QueryString.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-Remove-QueryString.patch new file mode 100644 index 000000000..238fb83c7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-Remove-QueryString.patch @@ -0,0 +1,621 @@ +From f8749b5898403ee04a623a5bc534bd939865e221 Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Wed, 22 Jul 2020 09:08:38 -0700 +Subject: [PATCH 1/1] Remove QueryString + +QueryString is an error-prone library that was +leftover from crow. Replace it with boost::url, +a header only library based and written by the +one of the authors of boost beast. + +Tested: Verified logging paging still worked +as expected + +Change-Id: I47c225089aa7d0f7d2299142f91806294f879381 +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + CMakeLists.txt | 2 + + CMakeLists.txt.in | 10 + + http/http_connection.h | 21 +- + http/http_request.h | 5 +- + http/query_string.h | 421 ----------------------------- + redfish-core/lib/event_service.hpp | 7 +- + redfish-core/lib/log_services.hpp | 20 +- + 7 files changed, 45 insertions(+), 441 deletions(-) + delete mode 100644 http/query_string.h + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 2886438..50483ad 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -280,6 +280,8 @@ add_definitions (-DBOOST_ALL_NO_LIB) + add_definitions (-DBOOST_NO_RTTI) + add_definitions (-DBOOST_NO_TYPEID) + add_definitions (-DBOOST_COROUTINES_NO_DEPRECATION_WARNING) ++add_definitions (-DBOOST_URL_STANDALONE) ++add_definitions (-DBOOST_URL_HEADER_ONLY) + + # sdbusplus + if (NOT ${YOCTO_DEPENDENCIES}) +diff --git a/CMakeLists.txt.in b/CMakeLists.txt.in +index d14910f..5cd73f6 100644 +--- a/CMakeLists.txt.in ++++ b/CMakeLists.txt.in +@@ -53,3 +53,13 @@ externalproject_add ( + cp -r "${CMAKE_BINARY_DIR}/nlohmann-json-src/include/nlohmann" + "${CMAKE_BINARY_DIR}/prefix/include" + ) ++ ++externalproject_add ( ++ Boost-URL GIT_REPOSITORY "https://github.com/CPPAlliance/url.git" GIT_TAG ++ a56ae0df6d3078319755fbaa67822b4fa7fd352b SOURCE_DIR ++ "${CMAKE_BINARY_DIR}/boost-url-src" BINARY_DIR ++ "${CMAKE_BINARY_DIR}/boost-url-build" CONFIGURE_COMMAND "" BUILD_COMMAND ++ "" INSTALL_COMMAND mkdir -p "${CMAKE_BINARY_DIR}/prefix/include" && ++ cp -r "${CMAKE_BINARY_DIR}/boost-url-src/include/boost" ++ "${CMAKE_BINARY_DIR}/prefix/include" ++) +diff --git a/http/http_connection.h b/http/http_connection.h +index 35bf99c..8dba3d6 100644 +--- a/http/http_connection.h ++++ b/http/http_connection.h +@@ -728,13 +728,9 @@ class Connection : + return; + } + +- // Compute the url parameters for the request +- req->url = req->target(); +- std::size_t index = req->url.find("?"); +- if (index != std::string_view::npos) +- { +- req->url = req->url.substr(0, index); +- } ++ req->urlView = boost::urls::url_view(req->target()); ++ req->url = req->urlView.encoded_path(); ++ + crow::authorization::authenticate(*req, res, session); + + bool loggedIn = req && req->session; +@@ -743,7 +739,16 @@ class Connection : + startDeadline(loggedInAttempts); + BMCWEB_LOG_DEBUG << "Starting slow deadline"; + +- req->urlParams = QueryString(std::string(req->target())); ++ req->urlParams = req->urlView.params(); ++ ++#ifdef BMCWEB_ENABLE_DEBUG ++ std::string paramList = ""; ++ for (const auto param : req->urlParams) ++ { ++ paramList += param->key() + " " + param->value() + " "; ++ } ++ BMCWEB_LOG_DEBUG << "QueryParams: " << paramList; ++#endif + } + else + { +diff --git a/http/http_request.h b/http/http_request.h +index 0691465..95f88c7 100644 +--- a/http/http_request.h ++++ b/http/http_request.h +@@ -1,7 +1,6 @@ + #pragma once + + #include "common.h" +-#include "query_string.h" + + #include "sessions.hpp" + +@@ -9,6 +8,7 @@ + #include <boost/beast/http.hpp> + #include <boost/beast/ssl/ssl_stream.hpp> + #include <boost/beast/websocket.hpp> ++#include <boost/url/url_view.hpp> + + namespace crow + { +@@ -24,7 +24,8 @@ struct Request + boost::beast::http::request<boost::beast::http::string_body>& req; + boost::beast::http::fields& fields; + std::string_view url{}; +- QueryString urlParams{}; ++ boost::urls::url_view urlView{}; ++ boost::urls::url_view::params_type urlParams{}; + bool isSecure{false}; + + const std::string& body; +diff --git a/http/query_string.h b/http/query_string.h +deleted file mode 100644 +index e980280..0000000 +--- a/http/query_string.h ++++ /dev/null +@@ -1,421 +0,0 @@ +-#pragma once +- +-#include <cstdio> +-#include <cstring> +-#include <iostream> +-#include <string> +-#include <vector> +- +-namespace crow +-{ +-// ---------------------------------------------------------------------------- +-// qs_parse (modified) +-// https://github.com/bartgrantham/qs_parse +-// ---------------------------------------------------------------------------- +-/* Similar to strncmp, but handles URL-encoding for either string */ +-int qsStrncmp(const char* s, const char* qs, size_t n); +- +-/* Finds the beginning of each key/value pair and stores a pointer in qs_kv. +- * Also decodes the value portion of the k/v pair *in-place*. In a future +- * enhancement it will also have a compile-time option of sorting qs_kv +- * alphabetically by key. */ +-size_t qsParse(char* qs, char* qs_kv[], size_t qs_kv_size); +- +-/* Used by qs_parse to decode the value portion of a k/v pair */ +-int qsDecode(char* qs); +- +-/* Looks up the value according to the key on a pre-processed query string +- * A future enhancement will be a compile-time option to look up the key +- * in a pre-sorted qs_kv array via a binary search. */ +-// char * qs_k2v(const char * key, char * qs_kv[], int qs_kv_size); +-char* qsK2v(const char* key, char* const* qs_kv, int qs_kv_size, int nth); +- +-/* Non-destructive lookup of value, based on key. User provides the +- * destinaton string and length. */ +-char* qsScanvalue(const char* key, const char* qs, char* val, size_t val_len); +- +-// TODO: implement sorting of the qs_kv array; for now ensure it's not compiled +-#undef _qsSORTING +- +-// isxdigit _is_ available in <ctype.h>, but let's avoid another header instead +-#define BMCWEB_QS_ISHEX(x) \ +- ((((x) >= '0' && (x) <= '9') || ((x) >= 'A' && (x) <= 'F') || \ +- ((x) >= 'a' && (x) <= 'f')) \ +- ? 1 \ +- : 0) +-#define BMCWEB_QS_HEX2DEC(x) \ +- (((x) >= '0' && (x) <= '9') \ +- ? (x)-48 \ +- : ((x) >= 'A' && (x) <= 'F') \ +- ? (x)-55 \ +- : ((x) >= 'a' && (x) <= 'f') ? (x)-87 : 0) +-#define BMCWEB_QS_ISQSCHR(x) \ +- ((((x) == '=') || ((x) == '#') || ((x) == '&') || ((x) == '\0')) ? 0 : 1) +- +-inline int qsStrncmp(const char* s, const char* qs, size_t n) +-{ +- int i = 0; +- char u1, u2; +- char unyb, lnyb; +- +- while (n-- > 0) +- { +- u1 = *s++; +- u2 = *qs++; +- +- if (!BMCWEB_QS_ISQSCHR(u1)) +- { +- u1 = '\0'; +- } +- if (!BMCWEB_QS_ISQSCHR(u2)) +- { +- u2 = '\0'; +- } +- +- if (u1 == '+') +- { +- u1 = ' '; +- } +- if (u1 == '%') // easier/safer than scanf +- { +- unyb = static_cast<char>(*s++); +- lnyb = static_cast<char>(*s++); +- if (BMCWEB_QS_ISHEX(unyb) && BMCWEB_QS_ISHEX(lnyb)) +- { +- u1 = static_cast<char>((BMCWEB_QS_HEX2DEC(unyb) * 16) + +- BMCWEB_QS_HEX2DEC(lnyb)); +- } +- else +- { +- u1 = '\0'; +- } +- } +- +- if (u2 == '+') +- { +- u2 = ' '; +- } +- if (u2 == '%') // easier/safer than scanf +- { +- unyb = static_cast<char>(*qs++); +- lnyb = static_cast<char>(*qs++); +- if (BMCWEB_QS_ISHEX(unyb) && BMCWEB_QS_ISHEX(lnyb)) +- { +- u2 = static_cast<char>((BMCWEB_QS_HEX2DEC(unyb) * 16) + +- BMCWEB_QS_HEX2DEC(lnyb)); +- } +- else +- { +- u2 = '\0'; +- } +- } +- +- if (u1 != u2) +- { +- return u1 - u2; +- } +- if (u1 == '\0') +- { +- return 0; +- } +- i++; +- } +- if (BMCWEB_QS_ISQSCHR(*qs)) +- { +- return -1; +- } +- else +- { +- return 0; +- } +-} +- +-inline size_t qsParse(char* qs, char* qs_kv[], size_t qs_kv_size) +-{ +- size_t i; +- size_t j; +- char* substrPtr; +- +- for (i = 0; i < qs_kv_size; i++) +- { +- qs_kv[i] = nullptr; +- } +- +- // find the beginning of the k/v substrings or the fragment +- substrPtr = qs + strcspn(qs, "?#"); +- if (substrPtr[0] != '\0') +- { +- substrPtr++; +- } +- else +- { +- return 0; // no query or fragment +- } +- +- i = 0; +- while (i < qs_kv_size) +- { +- qs_kv[i++] = substrPtr; +- j = strcspn(substrPtr, "&"); +- if (substrPtr[j] == '\0') +- { +- break; +- } +- substrPtr += j + 1; +- } +- +- // we only decode the values in place, the keys could have '='s in them +- // which will hose our ability to distinguish keys from values later +- for (j = 0; j < i; j++) +- { +- substrPtr = qs_kv[j] + strcspn(qs_kv[j], "=&#"); +- if (substrPtr[0] == '&' || substrPtr[0] == '\0') +- { // blank value: skip decoding +- substrPtr[0] = '\0'; +- } +- else +- { +- qsDecode(++substrPtr); +- } +- } +- +-#ifdef _qsSORTING +-// TODO: qsort qs_kv, using qs_strncmp() for the comparison +-#endif +- +- return i; +-} +- +-inline int qsDecode(char* qs) +-{ +- int i = 0, j = 0; +- +- while (BMCWEB_QS_ISQSCHR(qs[j])) +- { +- if (qs[j] == '+') +- { +- qs[i] = ' '; +- } +- else if (qs[j] == '%') // easier/safer than scanf +- { +- if (!BMCWEB_QS_ISHEX(qs[j + 1]) || !BMCWEB_QS_ISHEX(qs[j + 2])) +- { +- qs[i] = '\0'; +- return i; +- } +- qs[i] = static_cast<char>((BMCWEB_QS_HEX2DEC(qs[j + 1]) * 16) + +- BMCWEB_QS_HEX2DEC(qs[j + 2])); +- j += 2; +- } +- else +- { +- qs[i] = qs[j]; +- } +- i++; +- j++; +- } +- qs[i] = '\0'; +- +- return i; +-} +- +-inline char* qsK2v(const char* key, char* const* qs_kv, int qs_kv_size, +- int nth = 0) +-{ +- int i; +- size_t keyLen, skip; +- +- keyLen = strlen(key); +- +-#ifdef _qsSORTING +-// TODO: binary search for key in the sorted qs_kv +-#else // _qsSORTING +- for (i = 0; i < qs_kv_size; i++) +- { +- // we rely on the unambiguous '=' to find the value in our k/v pair +- if (qsStrncmp(key, qs_kv[i], keyLen) == 0) +- { +- skip = strcspn(qs_kv[i], "="); +- if (qs_kv[i][skip] == '=') +- { +- skip++; +- } +- // return (zero-char value) ? ptr to trailing '\0' : ptr to value +- if (nth == 0) +- { +- return qs_kv[i] + skip; +- } +- else +- { +- --nth; +- } +- } +- } +-#endif // _qsSORTING +- +- return nullptr; +-} +- +-inline char* qsScanvalue(const char* key, const char* qs, char* val, +- size_t val_len) +-{ +- size_t i, keyLen; +- const char* tmp; +- +- // find the beginning of the k/v substrings +- if ((tmp = strchr(qs, '?')) != nullptr) +- { +- qs = tmp + 1; +- } +- +- keyLen = strlen(key); +- while (qs[0] != '#' && qs[0] != '\0') +- { +- if (qsStrncmp(key, qs, keyLen) == 0) +- { +- break; +- } +- qs += strcspn(qs, "&") + 1; +- } +- +- if (qs[0] == '\0') +- { +- return nullptr; +- } +- +- qs += strcspn(qs, "=&#"); +- if (qs[0] == '=') +- { +- qs++; +- i = strcspn(qs, "&=#"); +- strncpy(val, qs, (val_len - 1) < (i + 1) ? (val_len - 1) : (i + 1)); +- qsDecode(val); +- } +- else +- { +- if (val_len > 0) +- { +- val[0] = '\0'; +- } +- } +- +- return val; +-} +-} // namespace crow +-// ---------------------------------------------------------------------------- +- +-namespace crow +-{ +-class QueryString +-{ +- public: +- static const size_t maxKeyValuePairsCount = 256; +- +- QueryString() = default; +- +- QueryString(const QueryString& qs) : url(qs.url) +- { +- for (auto p : qs.keyValuePairs) +- { +- keyValuePairs.push_back( +- const_cast<char*>(p - qs.url.c_str() + url.c_str())); +- } +- } +- +- QueryString& operator=(const QueryString& qs) +- { +- if (this == &qs) +- { +- return *this; +- } +- +- url = qs.url; +- keyValuePairs.clear(); +- for (auto p : qs.keyValuePairs) +- { +- keyValuePairs.push_back( +- const_cast<char*>(p - qs.url.c_str() + url.c_str())); +- } +- return *this; +- } +- +- QueryString& operator=(QueryString&& qs) +- { +- keyValuePairs = std::move(qs.keyValuePairs); +- auto* oldData = const_cast<char*>(qs.url.c_str()); +- url = std::move(qs.url); +- for (auto& p : keyValuePairs) +- { +- p += const_cast<char*>(url.c_str()) - oldData; +- } +- return *this; +- } +- +- explicit QueryString(std::string newUrl) : url(std::move(newUrl)) +- { +- if (url.empty()) +- { +- return; +- } +- +- keyValuePairs.resize(maxKeyValuePairsCount); +- +- size_t count = +- qsParse(&url[0], &keyValuePairs[0], maxKeyValuePairsCount); +- keyValuePairs.resize(count); +- } +- +- void clear() +- { +- keyValuePairs.clear(); +- url.clear(); +- } +- +- friend std::ostream& operator<<(std::ostream& os, const QueryString& qs) +- { +- os << "[ "; +- for (size_t i = 0; i < qs.keyValuePairs.size(); ++i) +- { +- if (i != 0u) +- { +- os << ", "; +- } +- os << qs.keyValuePairs[i]; +- } +- os << " ]"; +- return os; +- } +- +- char* get(const std::string& name) const +- { +- char* ret = qsK2v(name.c_str(), keyValuePairs.data(), +- static_cast<int>(keyValuePairs.size())); +- return ret; +- } +- +- std::vector<char*> getList(const std::string& name) const +- { +- std::vector<char*> ret; +- std::string plus = name + "[]"; +- char* element = nullptr; +- +- int count = 0; +- while (true) +- { +- element = qsK2v(plus.c_str(), keyValuePairs.data(), +- static_cast<int>(keyValuePairs.size()), count++); +- if (element == nullptr) +- { +- break; +- } +- ret.push_back(element); +- } +- return ret; +- } +- +- private: +- std::string url; +- std::vector<char*> keyValuePairs; +-}; +- +-} // namespace crow +diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp +index b27c6e0..8bd30f5 100644 +--- a/redfish-core/lib/event_service.hpp ++++ b/redfish-core/lib/event_service.hpp +@@ -445,13 +445,16 @@ class EventServiceSSE : public Node + subValue->protocol = "Redfish"; + subValue->retryPolicy = "TerminateAfterRetries"; + +- char* filters = req.urlParams.get("$filter"); +- if (filters == nullptr) ++ boost::urls::url_view::params_type::iterator it = ++ req.urlParams.find("$filter"); ++ if (it == req.urlParams.end()) + { + subValue->eventFormatType = "Event"; + } ++ + else + { ++ std::string filters = it->value(); + // Reading from query params. + bool status = readSSEQueryParams( + filters, subValue->eventFormatType, subValue->registryMsgIds, +diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp +index bee1a92..590243c 100644 +--- a/redfish-core/lib/log_services.hpp ++++ b/redfish-core/lib/log_services.hpp +@@ -218,12 +218,14 @@ static bool getEntryTimestamp(sd_journal* journal, std::string& entryTimestamp) + static bool getSkipParam(crow::Response& res, const crow::Request& req, + uint64_t& skip) + { +- char* skipParam = req.urlParams.get("$skip"); +- if (skipParam != nullptr) ++ boost::urls::url_view::params_type::iterator it = ++ req.urlParams.find("$skip"); ++ if (it != req.urlParams.end()) + { ++ std::string skipParam = it->value(); + char* ptr = nullptr; +- skip = std::strtoul(skipParam, &ptr, 10); +- if (*skipParam == '\0' || *ptr != '\0') ++ skip = std::strtoul(skipParam.c_str(), &ptr, 10); ++ if (skipParam.empty() || *ptr != '\0') + { + + messages::queryParameterValueTypeError(res, std::string(skipParam), +@@ -238,12 +240,14 @@ static constexpr const uint64_t maxEntriesPerPage = 1000; + static bool getTopParam(crow::Response& res, const crow::Request& req, + uint64_t& top) + { +- char* topParam = req.urlParams.get("$top"); +- if (topParam != nullptr) ++ boost::urls::url_view::params_type::iterator it = ++ req.urlParams.find("$top"); ++ if (it != req.urlParams.end()) + { ++ std::string topParam = it->value(); + char* ptr = nullptr; +- top = std::strtoul(topParam, &ptr, 10); +- if (*topParam == '\0' || *ptr != '\0') ++ top = std::strtoul(topParam.c_str(), &ptr, 10); ++ if (topParam.empty() || *ptr != '\0') + { + messages::queryParameterValueTypeError(res, std::string(topParam), + "$top"); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-bmcweb-handle-device-or-resource-busy-exception.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-bmcweb-handle-device-or-resource-busy-exception.patch new file mode 100644 index 000000000..761caabb7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-bmcweb-handle-device-or-resource-busy-exception.patch @@ -0,0 +1,219 @@ +From 5fa2fb4bd766b9c74b9edff4701408a002466b2a Mon Sep 17 00:00:00 2001 +From: Karol Wachowski <karol.wachowski@intel.com> +Date: Fri, 10 Jul 2020 09:54:06 +0000 +Subject: [PATCH] bmcweb handle device or resource busy exception + +Use async_method_call_timed() for mount/unmount dbus oprations. +Long mount/unmount times are supported by VirtualMedia service, +this works because of settable timeout property, available for each block +device. +Default dbus calls will timeout when mount/unmount timeout is long enough. + +Get mount/unmount timeout property and use it for mount/unmount calls. +Add handling of device or resource busy exception (EBUSY) that +can be thrown by VirtualMedia service during Mount/Unmount dbus operations. + +Tested: Verified that after mounting non-existing HTTPS resource + in proxy mode, VirtualMedia recovers restoring ready state + and returns EBUSY during that transition. + Verfied that resources can be mounted/unmounted in both legacy + and proxy mode. +Signed-off-by: Karol Wachowski <karol.wachowski@intel.com> +Change-Id: Ica62c34db0cce24c4c6169fc661edfde49e948d0 +--- + redfish-core/lib/virtual_media.hpp | 144 ++++++++++++++++++++++------- + 1 file changed, 110 insertions(+), 34 deletions(-) + +diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp +index 0b5eb1a..a0c63ad 100644 +--- a/redfish-core/lib/virtual_media.hpp ++++ b/redfish-core/lib/virtual_media.hpp +@@ -23,6 +23,8 @@ + // for GetObjectType and ManagedObjectType + #include <account_service.hpp> + ++#include <chrono> ++ + namespace redfish + + { +@@ -109,6 +111,26 @@ static void vmParseInterfaceObject(const DbusInterfaceType& interface, + } + } + ++/** ++ * @brief parses Timeout property and converts to microseconds ++ */ ++static std::optional<uint64_t> ++ vmParseTimeoutProperty(const std::variant<int>& timeoutProperty) ++{ ++ const int* timeoutValue = std::get_if<int>(&timeoutProperty); ++ if (timeoutValue) ++ { ++ constexpr int timeoutMarginSeconds = 10; ++ return std::chrono::duration_cast<std::chrono::microseconds>( ++ std::chrono::seconds(*timeoutValue + timeoutMarginSeconds)) ++ .count(); ++ } ++ else ++ { ++ return std::nullopt; ++ } ++} ++ + /** + * @brief Fill template for Virtual Media Item. + */ +@@ -806,22 +828,54 @@ class VirtualMediaActionInsertMedia : public Node + } + + crow::connections::systemBus->async_method_call( +- [asyncResp, secretPipe](const boost::system::error_code ec, +- bool success) { ++ [asyncResp, service, name, imageUrl, rw, unixFd, ++ secretPipe](const boost::system::error_code ec, ++ const std::variant<int> timeoutProperty) { + if (ec) + { + BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; + messages::internalError(asyncResp->res); ++ return; + } +- else if (!success) ++ ++ auto timeout = vmParseTimeoutProperty(timeoutProperty); ++ if (timeout == std::nullopt) + { +- BMCWEB_LOG_ERROR << "Service responded with error"; +- messages::generalError(asyncResp->res); ++ BMCWEB_LOG_ERROR << "Timeout property is empty."; ++ messages::internalError(asyncResp->res); ++ return; + } ++ ++ crow::connections::systemBus->async_method_call_timed( ++ [asyncResp, secretPipe](const boost::system::error_code ec, ++ bool success) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "Bad D-Bus request error: " ++ << ec; ++ if (ec == ++ boost::system::errc::device_or_resource_busy) ++ { ++ messages::resourceInUse(asyncResp->res); ++ } ++ else ++ { ++ messages::internalError(asyncResp->res); ++ } ++ } ++ else if (!success) ++ { ++ BMCWEB_LOG_ERROR << "Service responded with error"; ++ messages::generalError(asyncResp->res); ++ } ++ }, ++ service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, ++ "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", ++ *timeout, imageUrl, rw, unixFd); + }, + service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, +- "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw, +- unixFd); ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.VirtualMedia.MountPoint", "Timeout"); + } + }; + +@@ -955,38 +1009,60 @@ class VirtualMediaActionEjectMedia : public Node + const std::string& service, const std::string& name, + bool legacy) + { +- +- // Legacy mount requires parameter with image ++ std::string objectPath = "/xyz/openbmc_project/VirtualMedia/"; ++ std::string ifaceName = "xyz.openbmc_project.VirtualMedia"; + if (legacy) + { +- crow::connections::systemBus->async_method_call( +- [asyncResp](const boost::system::error_code ec) { +- if (ec) +- { +- BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; +- +- messages::internalError(asyncResp->res); +- return; +- } +- }, +- service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, +- "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount"); ++ objectPath += "Legacy/"; ++ ifaceName += ".Legacy"; + } +- else // proxy ++ else + { +- crow::connections::systemBus->async_method_call( +- [asyncResp](const boost::system::error_code ec) { +- if (ec) +- { +- BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; +- +- messages::internalError(asyncResp->res); +- return; +- } +- }, +- service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name, +- "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount"); ++ objectPath += "Proxy/"; ++ ifaceName += ".Proxy"; + } ++ objectPath += name; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp, service, name, objectPath, ++ ifaceName](const boost::system::error_code ec, ++ const std::variant<int> timeoutProperty) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ auto timeout = vmParseTimeoutProperty(timeoutProperty); ++ if (timeout == std::nullopt) ++ { ++ BMCWEB_LOG_ERROR << "Timeout property is empty."; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ crow::connections::systemBus->async_method_call_timed( ++ [asyncResp](const boost::system::error_code ec) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "Bad D-Bus request error: " ++ << ec; ++ if (ec == ++ boost::system::errc::device_or_resource_busy) ++ { ++ messages::resourceInUse(asyncResp->res); ++ } ++ else ++ { ++ messages::internalError(asyncResp->res); ++ } ++ return; ++ } ++ }, ++ service, objectPath, ifaceName, "Unmount", *timeout); ++ }, ++ service, objectPath, "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.VirtualMedia.MountPoint", "Timeout"); + } + }; + +-- +2.25.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch new file mode 100644 index 000000000..274dd044a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch @@ -0,0 +1,405 @@ +From f388587781c3d874b13b50ad39e8674f0bc08049 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Mon, 25 May 2020 16:14:39 +0530 +Subject: [PATCH] EventService: https client support + +Add https client support for push style +eventing. Using this BMC can push the event +logs/telemetry data to event listener over +secure http channel. + +Tested: + - Created subscription with https destination + url. Using SubmitTestEvent action set the + event and can see event on event listener. + - Validator passed. + +Change-Id: I44c3918b39baa2eb5fddda9d635f99aa280a422a +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + http/http_client.hpp | 270 +++++++++++++++++-------- + redfish-core/include/event_service_manager.hpp | 2 +- + 2 files changed, 186 insertions(+), 86 deletions(-) + +diff --git a/http/http_client.hpp b/http/http_client.hpp +index e6a7db1..27d2af3 100644 +--- a/http/http_client.hpp ++++ b/http/http_client.hpp +@@ -17,6 +17,7 @@ + #include <boost/asio/strand.hpp> + #include <boost/beast/core.hpp> + #include <boost/beast/http.hpp> ++#include <boost/beast/ssl.hpp> + #include <boost/beast/version.hpp> + + #include <cstdlib> +@@ -49,7 +50,10 @@ enum class ConnState + class HttpClient : public std::enable_shared_from_this<HttpClient> + { + private: +- boost::beast::tcp_stream conn; ++ boost::asio::io_context& ioc; ++ boost::asio::ssl::context ctx{boost::asio::ssl::context::tlsv12_client}; ++ std::shared_ptr<boost::beast::ssl_stream<boost::beast::tcp_stream>> sslConn; ++ std::shared_ptr<boost::beast::tcp_stream> conn; + boost::asio::steady_timer timer; + boost::beast::flat_buffer buffer; + boost::beast::http::request<boost::beast::http::string_body> req; +@@ -62,14 +66,37 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + std::string host; + std::string port; + std::string uri; ++ bool useSsl; + uint32_t retryCount; + uint32_t maxRetryAttempts; + uint32_t retryIntervalSecs; + std::string retryPolicyAction; + bool runningTimer; + ++ inline boost::beast::tcp_stream& getConn() ++ { ++ if (useSsl) ++ { ++ return (boost::beast::get_lowest_layer(*sslConn)); ++ } ++ else ++ { ++ return (*conn); ++ } ++ } ++ + void doConnect() + { ++ if (useSsl) ++ { ++ sslConn = std::make_shared< ++ boost::beast::ssl_stream<boost::beast::tcp_stream>>(ioc, ctx); ++ } ++ else ++ { ++ conn = std::make_shared<boost::beast::tcp_stream>(ioc); ++ } ++ + if (state == ConnState::connectInProgress) + { + return; +@@ -77,25 +104,53 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + state = ConnState::connectInProgress; + + BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port; +- // Set a timeout on the operation +- conn.expires_after(std::chrono::seconds(30)); +- conn.async_connect(endpoint, [self(shared_from_this())]( +- const boost::beast::error_code& ec, +- const boost::asio::ip::tcp::resolver:: +- results_type::endpoint_type& ep) { +- if (ec) +- { +- BMCWEB_LOG_ERROR << "Connect " << ep +- << " failed: " << ec.message(); +- self->state = ConnState::connectFailed; +- self->checkQueue(); +- return; +- } +- self->state = ConnState::connected; +- BMCWEB_LOG_DEBUG << "Connected to: " << ep; + +- self->checkQueue(); +- }); ++ auto respHandler = ++ [self(shared_from_this())](const boost::beast::error_code& ec, ++ const boost::asio::ip::tcp::resolver:: ++ results_type::endpoint_type& ep) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "Connect " << ep ++ << " failed: " << ec.message(); ++ self->state = ConnState::connectFailed; ++ self->checkQueue(); ++ return; ++ } ++ BMCWEB_LOG_DEBUG << "Connected to: " << ep; ++ if (self->useSsl) ++ { ++ self->performHandshake(); ++ } ++ else ++ { ++ self->state = ConnState::connected; ++ self->checkQueue(); ++ } ++ }; ++ ++ getConn().expires_after(std::chrono::seconds(30)); ++ getConn().async_connect(endpoint, std::move(respHandler)); ++ } ++ ++ void performHandshake() ++ { ++ sslConn->async_handshake( ++ boost::asio::ssl::stream_base::client, ++ [self(shared_from_this())](const boost::beast::error_code& ec) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "SSL handshake failed: " ++ << ec.message(); ++ self->state = ConnState::connectFailed; ++ self->doCloseAndCheckQueue(); ++ return; ++ } ++ self->state = ConnState::connected; ++ BMCWEB_LOG_DEBUG << "SSL Handshake successfull \n"; ++ ++ self->checkQueue(); ++ }); + } + + void sendMessage(const std::string& data) +@@ -108,7 +163,10 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + + BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; + +- req.version(static_cast<int>(11)); // HTTP 1.1 ++ req = {}; ++ res = {}; ++ ++ req.version(11); // HTTP 1.1 + req.target(uri); + req.method(boost::beast::http::verb::post); + +@@ -123,83 +181,121 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + req.body() = data; + req.prepare_payload(); + +- // Set a timeout on the operation +- conn.expires_after(std::chrono::seconds(30)); ++ auto respHandler = [self(shared_from_this())]( ++ const boost::beast::error_code& ec, ++ const std::size_t& bytesTransferred) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "sendMessage() failed: " << ec.message(); ++ self->state = ConnState::sendFailed; ++ self->doCloseAndCheckQueue(); ++ return; ++ } ++ BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " ++ << bytesTransferred; ++ boost::ignore_unused(bytesTransferred); + +- // Send the HTTP request to the remote host +- boost::beast::http::async_write( +- conn, req, +- [self(shared_from_this())](const boost::beast::error_code& ec, +- const std::size_t& bytesTransferred) { +- if (ec) +- { +- BMCWEB_LOG_ERROR << "sendMessage() failed: " +- << ec.message(); +- self->state = ConnState::sendFailed; +- self->checkQueue(); +- return; +- } +- BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " +- << bytesTransferred; +- boost::ignore_unused(bytesTransferred); ++ self->recvMessage(); ++ }; + +- self->recvMessage(); +- }); ++ getConn().expires_after(std::chrono::seconds(30)); ++ if (useSsl) ++ { ++ boost::beast::http::async_write(*sslConn, req, ++ std::move(respHandler)); ++ } ++ else ++ { ++ boost::beast::http::async_write(*conn, req, std::move(respHandler)); ++ } + } + + void recvMessage() + { +- // Receive the HTTP response +- boost::beast::http::async_read( +- conn, buffer, res, +- [self(shared_from_this())](const boost::beast::error_code& ec, +- const std::size_t& bytesTransferred) { +- if (ec) +- { +- BMCWEB_LOG_ERROR << "recvMessage() failed: " +- << ec.message(); +- self->state = ConnState::recvFailed; +- self->checkQueue(); +- return; +- } +- BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " +- << bytesTransferred; +- boost::ignore_unused(bytesTransferred); ++ auto respHandler = [self(shared_from_this())]( ++ const boost::beast::error_code& ec, ++ const std::size_t& bytesTransferred) { ++ if (ec && ec != boost::beast::http::error::partial_message) ++ { ++ BMCWEB_LOG_ERROR << "recvMessage() failed: " << ec.message(); ++ self->state = ConnState::recvFailed; ++ self->doCloseAndCheckQueue(); ++ return; ++ } ++ BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " ++ << bytesTransferred; ++ boost::ignore_unused(bytesTransferred); + +- // Discard received data. We are not interested. +- BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res; ++ // Discard received data. We are not interested. ++ BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res; + +- // Send is successful, Lets remove data from queue +- // check for next request data in queue. +- self->requestDataQueue.pop(); +- self->state = ConnState::idle; +- self->checkQueue(); +- }); ++ // Send is successful, Lets remove data from queue ++ // check for next request data in queue. ++ self->requestDataQueue.pop(); ++ self->state = ConnState::idle; ++ ++ if (ec == boost::beast::http::error::partial_message) ++ { ++ // Least bothered about recv message. Partial ++ // message means, already data is sent. Lets close ++ // connection and let next request open connection ++ // to avoid truncated stream. ++ self->state = ConnState::closed; ++ self->doCloseAndCheckQueue(); ++ return; ++ } ++ ++ self->checkQueue(); ++ }; ++ ++ getConn().expires_after(std::chrono::seconds(30)); ++ if (useSsl) ++ { ++ boost::beast::http::async_read(*sslConn, buffer, res, ++ std::move(respHandler)); ++ } ++ else ++ { ++ boost::beast::http::async_read(*conn, buffer, res, ++ std::move(respHandler)); ++ } + } + +- void doClose() ++ void doCloseAndCheckQueue() + { + boost::beast::error_code ec; +- conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); ++ getConn().cancel(); ++ getConn().expires_after(std::chrono::seconds(30)); ++ getConn().socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ++ ec); + +- state = ConnState::closed; +- // not_connected happens sometimes so don't bother reporting it. +- if (ec && ec != boost::beast::errc::not_connected) ++ if (ec && ec != boost::asio::error::eof) + { +- BMCWEB_LOG_ERROR << "shutdown failed: " << ec.message(); +- return; ++ // Many https server closes connection abruptly ++ // i.e witnout close_notify. More details are at ++ // https://github.com/boostorg/beast/issues/824 ++ if (ec == boost::asio::ssl::error::stream_truncated) ++ { ++ BMCWEB_LOG_DEBUG ++ << "doCloseAndCheckQueue(): Connection closed by server."; ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR << "doCloseAndCheckQueue() failed: " ++ << ec.message(); ++ } + } ++ ++ getConn().close(); + BMCWEB_LOG_DEBUG << "Connection closed gracefully"; ++ checkQueue(); ++ return; + } + + void checkQueue(const bool newRecord = false) + { + if (requestDataQueue.empty()) + { +- // TODO: Having issue in keeping connection alive. So lets close if +- // nothing to be transferred. +- doClose(); +- + BMCWEB_LOG_DEBUG << "requestDataQueue is empty\n"; + return; + } +@@ -257,17 +353,20 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + BMCWEB_LOG_DEBUG << "Attempt retry after " << retryIntervalSecs + << " seconds. RetryCount = " << retryCount; + timer.expires_after(std::chrono::seconds(retryIntervalSecs)); +- timer.async_wait([self = shared_from_this()]( +- const boost::system::error_code& ec) { +- self->runningTimer = false; +- self->connStateCheck(); +- }); ++ timer.async_wait( ++ [self = shared_from_this()](boost::system::error_code) { ++ self->runningTimer = false; ++ self->connStateCheck(); ++ }); + return; + } + else + { +- // reset retry count. +- retryCount = 0; ++ if (state == ConnState::idle) ++ { ++ // State idle means, previous attempt is successful. ++ retryCount = 0; ++ } + } + connStateCheck(); + +@@ -310,10 +409,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + public: + explicit HttpClient(boost::asio::io_context& ioc, const std::string& id, + const std::string& destIP, const std::string& destPort, +- const std::string& destUri) : +- conn(ioc), ++ const std::string& destUri, ++ const bool inUseSsl = true) : ++ ioc(ioc), + timer(ioc), subId(id), host(destIP), port(destPort), uri(destUri), +- retryCount(0), maxRetryAttempts(5), ++ useSsl(inUseSsl), retryCount(0), maxRetryAttempts(5), + retryPolicyAction("TerminateAfterRetries"), runningTimer(false) + { + boost::asio::ip::tcp::resolver resolver(ioc); +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 6362112..3ab2605 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -383,7 +383,7 @@ class Subscription + { + conn = std::make_shared<crow::HttpClient>( + crow::connections::systemBus->get_io_context(), id, host, port, +- path); ++ path, (uriProto == "https" ? true : false)); + } + + Subscription(const std::shared_ptr<crow::Request::Adaptor>& adaptor) : +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-VirtualMedia-fixes-for-Redfish-Service-Validator.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-VirtualMedia-fixes-for-Redfish-Service-Validator.patch new file mode 100644 index 000000000..52ff4e531 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-VirtualMedia-fixes-for-Redfish-Service-Validator.patch @@ -0,0 +1,122 @@ +From 49dc25100ab8a4220f81bc8f9b54808850fe1267 Mon Sep 17 00:00:00 2001 +From: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com> +Date: Wed, 8 Jul 2020 15:17:31 +0200 +Subject: [PATCH] VirtualMedia fixes for Redfish Service Validator + +Removes all warnings and errors for VirtualMedia +- rework for OemVirtualMedia +- minor adjustments for jsons + +Tested: +Redfish Service Validator ran with no errors and/or warnings + +Change-Id: Ic027166153a807a8bd3a6c04f042969f16e0dc6a +Signed-off-by: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com> +--- + redfish-core/lib/virtual_media.hpp | 4 +-- + .../v1/JsonSchemas/OemVirtualMedia/index.json | 28 +++---------------- + .../redfish/v1/schema/OemVirtualMedia_v1.xml | 12 ++++---- + 3 files changed, 12 insertions(+), 32 deletions(-) + +diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp +index 552e255..183abbe 100644 +--- a/redfish-core/lib/virtual_media.hpp ++++ b/redfish-core/lib/virtual_media.hpp +@@ -129,7 +129,7 @@ static nlohmann::json vmItemTemplate(const std::string& name, + item["MediaTypes"] = {"CD", "USBStick"}; + item["TransferMethod"] = "Stream"; + item["TransferProtocolType"] = nullptr; +- item["Oem"]["OpenBmc"]["WebSocketEndpoint"] = nullptr; ++ item["Oem"]["OpenBMC"]["WebSocketEndpoint"] = nullptr; + item["Oem"]["OpenBMC"]["@odata.type"] = + "#OemVirtualMedia.v1_0_0.VirtualMedia"; + +@@ -1039,7 +1039,7 @@ class VirtualMediaCollection : public Node + "#VirtualMediaCollection.VirtualMediaCollection"; + res.jsonValue["Name"] = "Virtual Media Services"; + res.jsonValue["@odata.id"] = +- "/redfish/v1/Managers/" + name + "/VirtualMedia/"; ++ "/redfish/v1/Managers/" + name + "/VirtualMedia"; + + crow::connections::systemBus->async_method_call( + [asyncResp, name](const boost::system::error_code ec, +diff --git a/static/redfish/v1/JsonSchemas/OemVirtualMedia/index.json b/static/redfish/v1/JsonSchemas/OemVirtualMedia/index.json +index 78bd8b7..9ae641a 100644 +--- a/static/redfish/v1/JsonSchemas/OemVirtualMedia/index.json ++++ b/static/redfish/v1/JsonSchemas/OemVirtualMedia/index.json +@@ -3,9 +3,10 @@ + "$schema": "http://redfish.dmtf.org/schemas/v1/redfish-schema-v1.json", + "copyright": "Copyright 2014-2019 DMTF. For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright", + "definitions": { +- "OpenBmc": { +- "additionalProperties": true, +- "description": "Oem properties for OpenBmc.", ++ "VirtualMedia": { ++ "additionalProperties": false, ++ "description": "OEM Extension for VirtualMedia", ++ "longDescription": "OEM Extension for VirtualMedia to support Proxy mode.", + "patternProperties": { + "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": { + "description": "This property shall specify a valid odata or Redfish property.", +@@ -32,27 +33,6 @@ + } + }, + "type": "object" +- }, +- "VirtualMedia": { +- "additionalProperties": false, +- "description": "OEM Extension for VirtualMedia", +- "longDescription": "OEM Extension for VirtualMedia to support Proxy mode.", +- "patternProperties": { +- "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": { +- "description": "This property shall specify a valid odata or Redfish property.", +- "type": [ +- "array", +- "boolean", +- "integer", +- "number", +- "null", +- "object", +- "string" +- ] +- } +- }, +- "properties": {}, +- "type": "object" + } + }, + "owningEntity": "OpenBMC", +diff --git a/static/redfish/v1/schema/OemVirtualMedia_v1.xml b/static/redfish/v1/schema/OemVirtualMedia_v1.xml +index 2b03a67..84afe73 100644 +--- a/static/redfish/v1/schema/OemVirtualMedia_v1.xml ++++ b/static/redfish/v1/schema/OemVirtualMedia_v1.xml +@@ -25,20 +25,20 @@ + <Annotation Term="Redfish.OwningEntity" String="OpenBMC"/> + <Annotation Term="Redfish.Release" String="1.0"/> + +- <ComplexType Name="OpenBmc" BaseType="Resource.OemObject"> +- <Annotation Term="OData.AdditionalProperties" Bool="true"/> +- <Annotation Term="OData.Description" String="Oem properties for OpenBmc." /> +- +- <Property Name="WebSocketEndpoint" Type="Edm.String"> ++ <Property Name="WebSocketEndpoint" Type="Edm.String"> + <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> + <Annotation Term="OData.Description" String="Indicates endpoint socket name and location."/> + <Annotation Term="OData.LongDescription" String="The value of this property shall be a structure ring indicating location and name of the socket used to communicate with nbd server."/> + </Property> +- </ComplexType> + + <EntityType Name="VirtualMedia" BaseType="Resource.OemObject" Abstract="true"> + <Annotation Term="OData.Description" String="OEM Extension for VirtualMedia"/> + <Annotation Term="OData.LongDescription" String="OEM Extension for VirtualMedia to support Proxy mode."/> ++ <Property Name="WebSocketEndpoint" Type="Edm.String"> ++ <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> ++ <Annotation Term="OData.Description" String="Indicates endpoint socket name and location."/> ++ <Annotation Term="OData.LongDescription" String="The value of this property shall be a structure ring indicating location and name of the socket used to communicate with nbd server."/> ++ </Property> + </EntityType> + </Schema> + +-- +2.25.0 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Fix-Image-and-ImageName-values-in-schema.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Fix-Image-and-ImageName-values-in-schema.patch new file mode 100644 index 000000000..c182822a6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Fix-Image-and-ImageName-values-in-schema.patch @@ -0,0 +1,38 @@ +From 15305d3a9db371af924482e5a6959bbf7812cf6c Mon Sep 17 00:00:00 2001 +From: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com> +Date: Wed, 29 Jul 2020 15:56:57 +0200 +Subject: [PATCH] Fix Image and ImageName values in schema + +According to design document and schema Image shall contain URL of +image location and ImageName only name of the image. + +Change-Id: Ie1a906c66aa2a10113c307eb1e7d2d7da2810fbd +Signed-off-by: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com> +--- + redfish-core/lib/virtual_media.hpp | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp +index 183abbe..0345e7b 100644 +--- a/redfish-core/lib/virtual_media.hpp ++++ b/redfish-core/lib/virtual_media.hpp +@@ -97,7 +97,15 @@ static void vmParseInterfaceObject(const DbusInterfaceType& interface, + std::get_if<std::string>(&imageUrlProperty->second); + if (imageUrlValue && !imageUrlValue->empty()) + { +- aResp->res.jsonValue["ImageName"] = *imageUrlValue; ++ std::size_t lastIndex = imageUrlValue->rfind("/"); ++ if (lastIndex == std::string::npos) ++ { ++ aResp->res.jsonValue["ImageName"] = *imageUrlValue; ++ } ++ ++ aResp->res.jsonValue["ImageName"] = ++ imageUrlValue->substr(lastIndex + 1); ++ aResp->res.jsonValue["Image"] = *imageUrlValue; + aResp->res.jsonValue["Inserted"] = *activeValue; + if (*activeValue == true) + { +-- +2.25.0 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Redfish-TelemetryService-schema-implementation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Redfish-TelemetryService-schema-implementation.patch new file mode 100644 index 000000000..3850c8fa8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Redfish-TelemetryService-schema-implementation.patch @@ -0,0 +1,913 @@ +From 7820421433349df28bd393e8d610d1848af0f1c8 Mon Sep 17 00:00:00 2001 +From: "Wludzik, Jozef" <jozef.wludzik@intel.com> +Date: Mon, 27 Apr 2020 17:24:15 +0200 +Subject: [PATCH 1/5] Redfish TelemetryService schema implementation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Added TelemetryService, MetricReports, MetricReportCollection, +MetricReportDefinition and MetricReportDefinitionCollection schemas +with GET method support. Added TelemetryService URI to root service. +Implemented communication with backend - MonitoringService. +Added schemes attributes that are supported by MonitoringService +design. User is able to fetch basic information about reports if +MonitoringService is present in OpenBMC. + +Tested: + - Succesfully passed RedfishServiceValidator.py + - Validated conversion to duration format using whole + range of uint32_t type + - Validated assigning value to JSON response using different + closures and std::functions types + +Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com> +Signed-off-by: Adrian Ambrożewicz <adrian.ambrozewicz@linux.intel.com> +Change-Id: Ie6b0b49f4ef5eeaef07d1209b6c349270c04d570 +--- + include/dbus_utility.hpp | 21 +++ + redfish-core/include/redfish.hpp | 10 ++ + redfish-core/include/utils/json_utils.hpp | 101 +++++++++++++ + redfish-core/include/utils/telemetry_utils.hpp | 100 +++++++++++++ + redfish-core/include/utils/time_utils.hpp | 97 +++++++++++++ + redfish-core/lib/metric_report.hpp | 149 +++++++++++++++++++ + redfish-core/lib/metric_report_definition.hpp | 193 +++++++++++++++++++++++++ + redfish-core/lib/service_root.hpp | 2 + + redfish-core/lib/telemetry_service.hpp | 92 ++++++++++++ + 9 files changed, 765 insertions(+) + create mode 100644 redfish-core/include/utils/telemetry_utils.hpp + create mode 100644 redfish-core/include/utils/time_utils.hpp + create mode 100644 redfish-core/lib/metric_report.hpp + create mode 100644 redfish-core/lib/metric_report_definition.hpp + create mode 100644 redfish-core/lib/telemetry_service.hpp + +diff --git a/include/dbus_utility.hpp b/include/dbus_utility.hpp +index e1360f7..3df88d8 100644 +--- a/include/dbus_utility.hpp ++++ b/include/dbus_utility.hpp +@@ -109,5 +109,26 @@ inline void checkDbusPathExists(const std::string& path, Callback&& callback) + std::array<std::string, 0>()); + } + ++template <typename Array, typename Callback> ++inline void getSubTreePaths(Callback&& callback, const std::string& path, ++ int depth, Array& interfaces) ++{ ++ crow::connections::systemBus->async_method_call( ++ callback, "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", path, depth, ++ interfaces); ++} ++ ++template <typename Callback> ++inline void getAllProperties(Callback&& callback, const std::string& service, ++ const std::string& path, ++ const std::string& interface) ++{ ++ crow::connections::systemBus->async_method_call( ++ callback, service, path, "org.freedesktop.DBus.Properties", "GetAll", ++ interface); ++} ++ + } // namespace utility + } // namespace dbus +diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp +index cc98e1a..3d4c117 100644 +--- a/redfish-core/include/redfish.hpp ++++ b/redfish-core/include/redfish.hpp +@@ -25,6 +25,8 @@ + #include "../lib/log_services.hpp" + #include "../lib/managers.hpp" + #include "../lib/message_registries.hpp" ++#include "../lib/metric_report.hpp" ++#include "../lib/metric_report_definition.hpp" + #include "../lib/network_protocol.hpp" + #include "../lib/pcie.hpp" + #include "../lib/power.hpp" +@@ -35,6 +37,7 @@ + #include "../lib/storage.hpp" + #include "../lib/systems.hpp" + #include "../lib/task.hpp" ++#include "../lib/telemetry_service.hpp" + #include "../lib/thermal.hpp" + #include "../lib/update_service.hpp" + #ifdef BMCWEB_ENABLE_VM_NBDPROXY +@@ -202,6 +205,13 @@ class RedfishService + nodes.emplace_back(std::make_unique<HypervisorInterface>(app)); + nodes.emplace_back(std::make_unique<HypervisorSystem>(app)); + ++ nodes.emplace_back(std::make_unique<TelemetryService>(app)); ++ nodes.emplace_back( ++ std::make_unique<MetricReportDefinitionCollection>(app)); ++ nodes.emplace_back(std::make_unique<MetricReportDefinition>(app)); ++ nodes.emplace_back(std::make_unique<MetricReportCollection>(app)); ++ nodes.emplace_back(std::make_unique<MetricReport>(app)); ++ + for (const auto& node : nodes) + { + node->initPrivileges(); +diff --git a/redfish-core/include/utils/json_utils.hpp b/redfish-core/include/utils/json_utils.hpp +index d578de4..fbb259d 100644 +--- a/redfish-core/include/utils/json_utils.hpp ++++ b/redfish-core/include/utils/json_utils.hpp +@@ -13,15 +13,19 @@ + // See the License for the specific language governing permissions and + // limitations under the License. + */ ++ + #pragma once + + #include <http_request.h> + #include <http_response.h> + ++#include <boost/container/flat_map.hpp> + #include <error_messages.hpp> + #include <nlohmann/json.hpp> + + #include <bitset> ++#include <string> ++#include <variant> + + namespace redfish + { +@@ -436,5 +440,102 @@ bool getValueFromJsonObject(nlohmann::json& jsonData, const std::string& key, + return details::unpackValue(jsonValue, key, value); + } + ++template <class T> ++struct IsStdFunction ++{ ++ static constexpr bool value = false; ++}; ++ ++template <class T> ++struct IsStdFunction<std::function<T>> ++{ ++ static constexpr bool value = true; ++}; ++ ++template <class T> ++constexpr bool is_std_function_v = IsStdFunction<T>::value; ++ ++/** ++ * @brief Assign dbus property to http response attribute if property is stored ++ * on the map. ++ */ ++template <typename T, typename S, typename... V> ++bool assignIfPresent( ++ const boost::container::flat_map<std::string, std::variant<V...>>& ret, ++ const char* propertyName, nlohmann::json& attribute, const S& convert) ++{ ++ if constexpr (is_std_function_v<S>) ++ { ++ if (!convert) ++ { ++ BMCWEB_LOG_ERROR << "Passed empty target as convert argument"; ++ return false; ++ } ++ } ++ ++ auto found = ret.find(propertyName); ++ if (found != ret.end()) ++ { ++ auto property = std::get_if<T>(&found->second); ++ if (property) ++ { ++ attribute = convert(*property); ++ return true; ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR << "Variant does not contain this type"; ++ } ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR << "Element not found in map"; ++ } ++ ++ return false; ++} ++ ++template <typename T, typename... V> ++bool assignIfPresent( ++ const boost::container::flat_map<std::string, std::variant<V...>>& ret, ++ const char* propertyName, nlohmann::json& attribute) ++{ ++ return assignIfPresent<T>(ret, propertyName, attribute, ++ [](const T& v) -> T { return v; }); ++} ++ ++template <typename T, typename... V> ++bool assignIfPresent( ++ const boost::container::flat_map<std::string, std::variant<V...>>& ret, ++ const char* attributeName, crow::Response& res) ++{ ++ return assignIfPresent<T>(ret, attributeName, res.jsonValue[attributeName]); ++} ++ ++/** ++ * @brief Translate dbusPaths received from ObjectMapper into Redfish ++ * collection members and fill http response with those information. ++ */ ++inline void dbusPathsToMembersArray(crow::Response& res, ++ const std::vector<std::string>& reports, ++ const char* path) ++{ ++ nlohmann::json& members = res.jsonValue["Members"]; ++ members = nlohmann::json::array(); ++ ++ for (const std::string& objpath : reports) ++ { ++ std::size_t lastPos = objpath.rfind("/"); ++ if (lastPos == std::string::npos) ++ { ++ BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath; ++ continue; ++ } ++ members.push_back({{"@odata.id", path + objpath.substr(lastPos + 1)}}); ++ } ++ ++ res.jsonValue["Members@odata.count"] = members.size(); ++} ++ + } // namespace json_util + } // namespace redfish +diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp +new file mode 100644 +index 0000000..05ed00f +--- /dev/null ++++ b/redfish-core/include/utils/telemetry_utils.hpp +@@ -0,0 +1,100 @@ ++/* ++// Copyright (c) 2018-2020 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++ ++#pragma once ++ ++namespace redfish ++{ ++ ++namespace telemetry ++{ ++ ++static constexpr const char* metricReportDefinitionUri = ++ "/redfish/v1/TelemetryService/MetricReportDefinitions/"; ++static constexpr const char* metricReportUri = ++ "/redfish/v1/TelemetryService/MetricReports/"; ++static constexpr const char* reportInterface = ++ "xyz.openbmc_project.MonitoringService.Report"; ++static constexpr const char* telemetryPath = ++ "/xyz/openbmc_project/MonitoringService/Reports/TelemetryService"; ++ ++static void getReportCollection(const std::shared_ptr<AsyncResp>& asyncResp, ++ const char* uri) ++{ ++ const std::array<const char*, 1> interfaces = {reportInterface}; ++ ++ dbus::utility::getSubTreePaths( ++ [asyncResp, uri](const boost::system::error_code ec, ++ const std::vector<std::string>& reports) { ++ if (ec == boost::system::errc::no_such_file_or_directory) ++ { ++ asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); ++ asyncResp->res.jsonValue["Members@odata.count"] = 0; ++ return; ++ } ++ ++ if (ec) ++ { ++ messages::internalError(asyncResp->res); ++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; ++ return; ++ } ++ ++ json_util::dbusPathsToMembersArray(asyncResp->res, reports, uri); ++ }, ++ telemetryPath, 1, interfaces); ++} ++ ++template <typename Callback> ++static void getReport(const std::shared_ptr<AsyncResp>& asyncResp, ++ const std::string& id, const char* schemaType, ++ const Callback&& callback) ++{ ++ const std::array<const char*, 1> interfaces = {reportInterface}; ++ ++ dbus::utility::getSubTreePaths( ++ [asyncResp, id, schemaType, ++ callback](const boost::system::error_code ec, ++ const std::vector<std::string>& reports) { ++ if (ec == boost::system::errc::no_such_file_or_directory) ++ { ++ messages::resourceNotFound(asyncResp->res, schemaType, id); ++ return; ++ } ++ ++ if (ec) ++ { ++ messages::internalError(asyncResp->res); ++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; ++ return; ++ } ++ ++ const std::string target = "/xyz/openbmc_project/" ++ "MonitoringService/Reports/" ++ "TelemetryService/" + ++ id; ++ auto path = std::find(reports.begin(), reports.end(), target); ++ if (path == std::end(reports)) ++ { ++ messages::resourceNotFound(asyncResp->res, schemaType, id); ++ return; ++ } ++ callback(asyncResp, *path, id); ++ }, ++ telemetryPath, 1, interfaces); ++} ++} // namespace telemetry ++} // namespace redfish +diff --git a/redfish-core/include/utils/time_utils.hpp b/redfish-core/include/utils/time_utils.hpp +new file mode 100644 +index 0000000..0256b3f +--- /dev/null ++++ b/redfish-core/include/utils/time_utils.hpp +@@ -0,0 +1,97 @@ ++/* ++// Copyright (c) 2020 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++ ++#pragma once ++ ++#include <boost/algorithm/string/trim.hpp> ++ ++#include <chrono> ++#include <cstdint> ++#include <string> ++#include <type_traits> ++ ++namespace redfish ++{ ++ ++namespace time_utils ++{ ++ ++namespace details ++{ ++ ++template <typename T> ++std::string toDurationFormatItem(std::chrono::milliseconds& duration, ++ const char* postfix) ++{ ++ const auto t = std::chrono::duration_cast<T>(duration); ++ if (t.count() == 0) ++ { ++ return ""; ++ } ++ ++ std::stringstream ss; ++ if constexpr (std::is_same<T, std::chrono::milliseconds>::value) ++ { ++ ss << static_cast<float>(t.count()) / ++ static_cast<float>(std::chrono::milliseconds::period::den); ++ } ++ else ++ { ++ ss << t.count(); ++ } ++ ss << postfix; ++ duration -= t; ++ return ss.str(); ++} ++ ++} // namespace details ++ ++/** ++ * @brief Convert time value into duration format that is based on ISO 8601. ++ * Pattern: "-?P(\\d+D)?(T(\\d+H)?(\\d+M)?(\\d+(.\\d+)?S)?)?" ++ * Reference: "Redfish Telemetry White Paper". ++ */ ++std::string toDurationFormat(const uint32_t ms) ++{ ++ std::chrono::milliseconds duration(ms); ++ if (duration.count() == 0) ++ { ++ return "PT0S"; ++ } ++ ++ std::string fmt; ++ fmt.reserve(sizeof("PxxxDTxxHxxMxx.xxxxxxS")); ++ ++ using Days = std::chrono::duration<int, std::ratio<24 * 60 * 60>>; ++ ++ fmt += "P"; ++ fmt += details::toDurationFormatItem<Days>(duration, "D"); ++ if (duration.count() == 0) ++ { ++ return fmt; ++ } ++ ++ fmt += "T"; ++ fmt += details::toDurationFormatItem<std::chrono::hours>(duration, "H"); ++ fmt += details::toDurationFormatItem<std::chrono::minutes>(duration, "M"); ++ fmt += ++ details::toDurationFormatItem<std::chrono::milliseconds>(duration, "S"); ++ ++ return fmt; ++} ++ ++} // namespace time_utils ++} // namespace redfish +diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp +new file mode 100644 +index 0000000..a52d680 +--- /dev/null ++++ b/redfish-core/lib/metric_report.hpp +@@ -0,0 +1,149 @@ ++/* ++// Copyright (c) 2018-2020 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++ ++#pragma once ++ ++#include "node.hpp" ++#include "utils/telemetry_utils.hpp" ++ ++#include <boost/container/flat_map.hpp> ++ ++#include <system_error> ++#include <variant> ++ ++namespace redfish ++{ ++ ++class MetricReportCollection : public Node ++{ ++ public: ++ MetricReportCollection(CrowApp& app) : Node(app, telemetry::metricReportUri) ++ { ++ entityPrivileges = { ++ {boost::beast::http::verb::get, {{"Login"}}}, ++ {boost::beast::http::verb::head, {{"Login"}}}, ++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::put, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; ++ } ++ ++ private: ++ void doGet(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>& params) override ++ { ++ res.jsonValue["@odata.type"] = ++ "#MetricReportCollection.MetricReportCollection"; ++ res.jsonValue["@odata.id"] = ++ "/redfish/v1/TelemetryService/MetricReports"; ++ res.jsonValue["Name"] = "Metric Report Collection"; ++ ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ telemetry::getReportCollection(asyncResp, telemetry::metricReportUri); ++ } ++}; ++ ++class MetricReport : public Node ++{ ++ public: ++ MetricReport(CrowApp& app) : ++ Node(app, std::string(telemetry::metricReportUri) + "<str>/", ++ std::string()) ++ { ++ entityPrivileges = { ++ {boost::beast::http::verb::get, {{"Login"}}}, ++ {boost::beast::http::verb::head, {{"Login"}}}, ++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::put, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; ++ } ++ ++ private: ++ void doGet(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>& params) override ++ { ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ ++ if (params.size() != 1) ++ { ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ const std::string& id = params[0]; ++ telemetry::getReport(asyncResp, id, schemaType, getReportProperties); ++ } ++ ++ using Readings = ++ std::vector<std::tuple<std::string, std::string, double, int32_t>>; ++ using MetricValues = std::vector<std::map<std::string, std::string>>; ++ ++ static MetricValues toMetricValues(const Readings& readings) ++ { ++ MetricValues metricValues; ++ ++ for (auto& [id, metadata, sensorValue, timestamp] : readings) ++ { ++ metricValues.push_back({ ++ {"MetricId", id}, ++ {"MetricProperty", metadata}, ++ {"MetricValue", std::to_string(sensorValue)}, ++ {"Timestamp", crow::utility::getDateTime(timestamp)}, ++ }); ++ } ++ ++ return metricValues; ++ } ++ ++ static void getReportProperties(const std::shared_ptr<AsyncResp> asyncResp, ++ const std::string& reportPath, ++ const std::string& id) ++ { ++ asyncResp->res.jsonValue["@odata.type"] = schemaType; ++ asyncResp->res.jsonValue["@odata.id"] = telemetry::metricReportUri + id; ++ asyncResp->res.jsonValue["Id"] = id; ++ asyncResp->res.jsonValue["Name"] = id; ++ asyncResp->res.jsonValue["MetricReportDefinition"]["@odata.id"] = ++ telemetry::metricReportDefinitionUri + id; ++ ++ dbus::utility::getAllProperties( ++ [asyncResp]( ++ const boost::system::error_code ec, ++ const boost::container::flat_map< ++ std::string, std::variant<Readings, int32_t>>& ret) { ++ if (ec) ++ { ++ messages::internalError(asyncResp->res); ++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; ++ return; ++ } ++ ++ json_util::assignIfPresent<int32_t>( ++ ret, "Timestamp", asyncResp->res.jsonValue["Timestamp"], ++ crow::utility::getDateTime); ++ json_util::assignIfPresent<Readings>( ++ ret, "Readings", asyncResp->res.jsonValue["MetricValues"], ++ toMetricValues); ++ }, ++ "xyz.openbmc_project.MonitoringService", reportPath, ++ "xyz.openbmc_project.MonitoringService.Report"); ++ } ++ ++ static constexpr const char* schemaType = ++ "#MetricReport.v1_3_0.MetricReport"; ++}; ++} // namespace redfish +diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp +new file mode 100644 +index 0000000..d82ae59 +--- /dev/null ++++ b/redfish-core/lib/metric_report_definition.hpp +@@ -0,0 +1,193 @@ ++/* ++// Copyright (c) 2018-2020 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++ ++#pragma once ++ ++#include "node.hpp" ++#include "utils/telemetry_utils.hpp" ++#include "utils/time_utils.hpp" ++ ++#include <boost/container/flat_map.hpp> ++ ++#include <system_error> ++#include <variant> ++ ++namespace redfish ++{ ++ ++class MetricReportDefinitionCollection : public Node ++{ ++ public: ++ MetricReportDefinitionCollection(CrowApp& app) : ++ Node(app, telemetry::metricReportDefinitionUri) ++ { ++ entityPrivileges = { ++ {boost::beast::http::verb::get, {{"Login"}}}, ++ {boost::beast::http::verb::head, {{"Login"}}}, ++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::put, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; ++ } ++ ++ private: ++ void doGet(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>& params) override ++ { ++ res.jsonValue["@odata.type"] = "#MetricReportDefinitionCollection." ++ "MetricReportDefinitionCollection"; ++ res.jsonValue["@odata.id"] = ++ "/redfish/v1/TelemetryService/MetricReportDefinitions"; ++ res.jsonValue["Name"] = "Metric Definition Collection"; ++ ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ telemetry::getReportCollection(asyncResp, ++ telemetry::metricReportDefinitionUri); ++ } ++}; ++ ++class MetricReportDefinition : public Node ++{ ++ public: ++ MetricReportDefinition(CrowApp& app) : ++ Node(app, std::string(telemetry::metricReportDefinitionUri) + "<str>/", ++ std::string()) ++ { ++ entityPrivileges = { ++ {boost::beast::http::verb::get, {{"Login"}}}, ++ {boost::beast::http::verb::head, {{"Login"}}}, ++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::put, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; ++ } ++ ++ private: ++ void doGet(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>& params) override ++ { ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ ++ if (params.size() != 1) ++ { ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ const std::string& id = params[0]; ++ ++ telemetry::getReport(asyncResp, id, schemaType, ++ getReportDefinitonProperties); ++ } ++ ++ static std::vector<std::string> ++ toReportActions(const std::vector<std::string>& actions) ++ { ++ const boost::container::flat_map<std::string, std::string> ++ reportActions = { ++ {"Event", "RedfishEvent"}, ++ {"Log", "LogToMetricReportsCollection"}, ++ }; ++ ++ std::vector<std::string> out; ++ for (auto& action : actions) ++ { ++ auto found = reportActions.find(action); ++ if (found != reportActions.end()) ++ { ++ out.emplace_back(found->second); ++ } ++ } ++ return out; ++ } ++ ++ using ReadingParameters = ++ std::vector<std::tuple<std::vector<sdbusplus::message::object_path>, ++ std::string, std::string, std::string>>; ++ using Metrics = std::vector<std::map< ++ std::string, std::variant<std::string, std::vector<std::string>>>>; ++ ++ static Metrics toMetrics(const ReadingParameters& params) ++ { ++ Metrics metrics; ++ ++ for (auto& [sensorPaths, operationType, id, metadata] : params) ++ { ++ metrics.push_back({ ++ {"MetricId", id}, ++ {"MetricProperties", std::vector<std::string>() = {metadata}}, ++ }); ++ } ++ ++ return metrics; ++ } ++ ++ static void ++ getReportDefinitonProperties(const std::shared_ptr<AsyncResp> asyncResp, ++ const std::string& reportPath, ++ const std::string& id) ++ { ++ asyncResp->res.jsonValue["@odata.type"] = schemaType; ++ asyncResp->res.jsonValue["@odata.id"] = ++ telemetry::metricReportDefinitionUri + id; ++ asyncResp->res.jsonValue["Id"] = id; ++ asyncResp->res.jsonValue["Name"] = id; ++ asyncResp->res.jsonValue["MetricReport"]["@odata.id"] = ++ telemetry::metricReportUri + id; ++ asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; ++ ++ dbus::utility::getAllProperties( ++ [asyncResp](const boost::system::error_code ec, ++ const boost::container::flat_map< ++ std::string, ++ std::variant<std::string, std::vector<std::string>, ++ uint32_t, ReadingParameters>>& ret) { ++ if (ec) ++ { ++ messages::internalError(asyncResp->res); ++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; ++ return; ++ } ++ ++ json_util::assignIfPresent<std::vector<std::string>>( ++ ret, "ReportAction", ++ asyncResp->res.jsonValue["ReportActions"], toReportActions); ++ auto assigned = json_util::assignIfPresent<std::string>( ++ ret, "ReportingType", ++ asyncResp->res.jsonValue["MetricReportDefinitionType"]); ++ if (assigned && ++ asyncResp->res.jsonValue["MetricReportDefinitionType"] == ++ "Periodic") ++ { ++ json_util::assignIfPresent<uint32_t>( ++ ret, "ScanPeriod", ++ asyncResp->res ++ .jsonValue["Schedule"]["RecurrenceInterval"], ++ time_utils::toDurationFormat); ++ } ++ json_util::assignIfPresent<ReadingParameters>( ++ ret, "ReadingParameters", ++ asyncResp->res.jsonValue["Metrics"], toMetrics); ++ }, ++ "xyz.openbmc_project.MonitoringService", reportPath, ++ "xyz.openbmc_project.MonitoringService.Report"); ++ } ++ ++ public: ++ static constexpr const char* schemaType = ++ "#MetricReportDefinition.v1_3_0.MetricReportDefinition"; ++}; ++} // namespace redfish +diff --git a/redfish-core/lib/service_root.hpp b/redfish-core/lib/service_root.hpp +index b6bd6e0..3302390 100644 +--- a/redfish-core/lib/service_root.hpp ++++ b/redfish-core/lib/service_root.hpp +@@ -69,6 +69,8 @@ class ServiceRoot : public Node + res.jsonValue["Tasks"] = {{"@odata.id", "/redfish/v1/TaskService"}}; + res.jsonValue["EventService"] = { + {"@odata.id", "/redfish/v1/EventService"}}; ++ res.jsonValue["TelemetryService"] = { ++ {"@odata.id", "/redfish/v1/TelemetryService"}}; + res.end(); + } + +diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp +new file mode 100644 +index 0000000..a410700 +--- /dev/null ++++ b/redfish-core/lib/telemetry_service.hpp +@@ -0,0 +1,92 @@ ++/* ++// Copyright (c) 2018-2020 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++ ++#pragma once ++ ++#include "node.hpp" ++#include "utils/time_utils.hpp" ++ ++#include <boost/container/flat_map.hpp> ++ ++#include <variant> ++ ++namespace redfish ++{ ++ ++class TelemetryService : public Node ++{ ++ public: ++ TelemetryService(CrowApp& app) : Node(app, "/redfish/v1/TelemetryService/") ++ { ++ entityPrivileges = { ++ {boost::beast::http::verb::get, {{"Login"}}}, ++ {boost::beast::http::verb::head, {{"Login"}}}, ++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::put, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; ++ } ++ ++ private: ++ void doGet(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>& params) override ++ { ++ res.jsonValue["@odata.type"] = ++ "#TelemetryService.v1_2_0.TelemetryService"; ++ res.jsonValue["@odata.id"] = "/redfish/v1/TelemetryService"; ++ res.jsonValue["Id"] = "TelemetryService"; ++ res.jsonValue["Name"] = "Telemetry Service"; ++ ++ res.jsonValue["LogService"]["@odata.id"] = ++ "/redfish/v1/Managers/bmc/LogServices/Journal"; ++ res.jsonValue["MetricReportDefinitions"]["@odata.id"] = ++ "/redfish/v1/TelemetryService/MetricReportDefinitions"; ++ res.jsonValue["MetricReports"]["@odata.id"] = ++ "/redfish/v1/TelemetryService/MetricReports"; ++ ++ getMonitoringServiceProperties(res); ++ } ++ ++ void getMonitoringServiceProperties(crow::Response& res) ++ { ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ dbus::utility::getAllProperties( ++ [asyncResp]( ++ const boost::system::error_code ec, ++ const boost::container::flat_map<std::string, ++ std::variant<uint32_t>>& ret) { ++ if (ec) ++ { ++ asyncResp->res.jsonValue["Status"]["State"] = "Absent"; ++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; ++ return; ++ } ++ ++ asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; ++ ++ json_util::assignIfPresent<uint32_t>(ret, "MaxReports", ++ asyncResp->res); ++ json_util::assignIfPresent<uint32_t>( ++ ret, "PollRateResolution", ++ asyncResp->res.jsonValue["MinCollectionInterval"], ++ time_utils::toDurationFormat); ++ }, ++ "xyz.openbmc_project.MonitoringService", ++ "/xyz/openbmc_project/MonitoringService/Reports", ++ "xyz.openbmc_project.MonitoringService.ReportsManagement"); ++ } ++}; ++} // namespace redfish +-- +2.16.6 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Add-support-for-POST-in-MetricReportDefinitions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Add-support-for-POST-in-MetricReportDefinitions.patch new file mode 100644 index 000000000..8a8690bf3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Add-support-for-POST-in-MetricReportDefinitions.patch @@ -0,0 +1,594 @@ +From 941be2c7d819b4a55d5a8b67948e53658d907789 Mon Sep 17 00:00:00 2001 +From: "Wludzik, Jozef" <jozef.wludzik@intel.com> +Date: Mon, 18 May 2020 11:56:57 +0200 +Subject: [PATCH 2/5] Add support for POST in MetricReportDefinitions + +Added POST action in MetricReportDefinitions node to allow user +to add new MetricReportDefinition. Using minimal set of +MetricReportDefinition parameters from user bmcweb converts it to +DBus call "AddReport" to MonitoringService that serves as a backend +for TelemetryService. + +Tested: + - Succesfully passed RedfishServiceValidator.py + - Validated good cases with different parameters for POST action + - Validated bad cases with different parameters for POST action + - Validated fromDurationFormat() with range of arguments starting + from PT0.0S up to P49D (it is an upper limit for uint32_t) + +Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com> +Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +Change-Id: I2fed96848594451e22fde686f8c066d7770cc65a +--- + redfish-core/include/utils/time_utils.hpp | 49 +++ + .../include/utils/validate_params_length.hpp | 109 +++++++ + redfish-core/lib/metric_report_definition.hpp | 347 +++++++++++++++++++++ + 3 files changed, 505 insertions(+) + create mode 100644 redfish-core/include/utils/validate_params_length.hpp + +diff --git a/redfish-core/include/utils/time_utils.hpp b/redfish-core/include/utils/time_utils.hpp +index 0256b3f..c365585 100644 +--- a/redfish-core/include/utils/time_utils.hpp ++++ b/redfish-core/include/utils/time_utils.hpp +@@ -57,6 +57,32 @@ std::string toDurationFormatItem(std::chrono::milliseconds& duration, + return ss.str(); + } + ++template <typename T> ++static long long fromDurationFormatItem(std::string_view& fmt, ++ const char* postfix) ++{ ++ auto pos = fmt.find(postfix); ++ if (pos == std::string::npos) ++ { ++ return 0; ++ } ++ ++ long out; ++ if constexpr (std::is_same<T, std::chrono::milliseconds>::value) ++ { ++ /* Half point is added to avoid numeric error on rounding */ ++ out = static_cast<long>(std::strtof(fmt.data(), nullptr) * ++ std::chrono::milliseconds::period::den + ++ 0.5f); ++ } ++ else ++ { ++ out = std::strtol(fmt.data(), nullptr, 10); ++ } ++ fmt.remove_prefix(pos + 1); ++ return std::chrono::milliseconds(T(out)).count(); ++} ++ + } // namespace details + + /** +@@ -93,5 +119,28 @@ std::string toDurationFormat(const uint32_t ms) + return fmt; + } + ++static uint32_t fromDurationFormat(std::string_view fmt) ++{ ++ if (fmt.empty() || fmt[0] != 'P') ++ { ++ return 0; ++ } ++ using Days = std::chrono::duration<int, std::ratio<24 * 60 * 60>>; ++ ++ fmt.remove_prefix(1); ++ auto out = details::fromDurationFormatItem<Days>(fmt, "D"); ++ if (fmt[0] != 'T') ++ { ++ return static_cast<uint32_t>(out); ++ } ++ ++ fmt.remove_prefix(1); ++ out += details::fromDurationFormatItem<std::chrono::hours>(fmt, "H"); ++ out += details::fromDurationFormatItem<std::chrono::minutes>(fmt, "M"); ++ out += details::fromDurationFormatItem<std::chrono::milliseconds>(fmt, "S"); ++ ++ return static_cast<uint32_t>(out); ++} ++ + } // namespace time_utils + } // namespace redfish +diff --git a/redfish-core/include/utils/validate_params_length.hpp b/redfish-core/include/utils/validate_params_length.hpp +new file mode 100644 +index 0000000..c4e0569 +--- /dev/null ++++ b/redfish-core/include/utils/validate_params_length.hpp +@@ -0,0 +1,109 @@ ++#pragma once ++ ++namespace redfish ++{ ++namespace detail ++{ ++template <class Limits, size_t... Seq> ++bool validateParamsLength(crow::Response& res, Limits&& limits, ++ std::index_sequence<Seq...>) ++{ ++ return (... && std::get<Seq>(limits).validate(res)); ++} ++} // namespace detail ++ ++template <class T> ++struct ItemSizeValidator ++{ ++ ItemSizeValidator(const T&& item, std::string_view name, size_t limit) : ++ item(std::forward<const T>(item)), name(name), limit(limit) ++ {} ++ ++ bool validate(crow::Response& res) const ++ { ++ return ItemSizeValidator<T>::validateItem(res, item, name, limit); ++ } ++ ++ private: ++ static bool validateItem(crow::Response& res, size_t item, ++ std::string_view name, size_t limit) ++ { ++ if (item > static_cast<size_t>(limit)) ++ { ++ messages::stringValueTooLong(res, std::string(name), ++ static_cast<int>(limit)); ++ return false; ++ } ++ return true; ++ } ++ ++ static bool validateItem(crow::Response& res, std::string_view item, ++ std::string_view name, size_t limit) ++ { ++ return validateItem(res, item.size(), name, limit); ++ } ++ ++ static bool validateItem(crow::Response& res, const std::string& item, ++ std::string_view name, size_t limit) ++ { ++ return validateItem(res, item.size(), name, limit); ++ } ++ ++ static bool validateItem(crow::Response& res, ++ const sdbusplus::message::object_path& item, ++ std::string_view name, size_t limit) ++ { ++ return validateItem(res, item.str.size(), name, limit); ++ } ++ ++ T item; ++ std::string_view name; ++ size_t limit; ++}; ++ ++template <class T> ++ItemSizeValidator(const T&, std::string_view, size_t) ++ -> ItemSizeValidator<const T&>; ++ ++ItemSizeValidator(const char*, std::string_view, size_t) ++ ->ItemSizeValidator<std::string_view>; ++ ++template <class ContainerT> ++struct ArrayItemsValidator ++{ ++ ArrayItemsValidator(const ContainerT& item, std::string_view name, ++ size_t limit) : ++ item(item), ++ name(name), limit(limit) ++ {} ++ ++ bool validate(crow::Response& res) const ++ { ++ return std::all_of( ++ item.begin(), item.end(), [&res, this](const auto& item) { ++ return ItemSizeValidator(item, name, limit).validate(res); ++ }); ++ } ++ ++ private: ++ const ContainerT& item; ++ std::string_view name; ++ size_t limit; ++}; ++ ++template <class T> ++bool validateParamLength(crow::Response& res, T&& item, std::string_view name, ++ size_t limit) ++{ ++ return ItemSizeValidator(std::forward<T>(item), name, limit).validate(res); ++} ++ ++template <class Limits> ++bool validateParamsLength(crow::Response& res, Limits&& limits) ++{ ++ return detail::validateParamsLength( ++ res, std::forward<Limits>(limits), ++ std::make_index_sequence<std::tuple_size_v<std::decay_t<Limits>>>()); ++} ++ ++} // namespace redfish +diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp +index d82ae59..ecbab0c 100644 +--- a/redfish-core/lib/metric_report_definition.hpp ++++ b/redfish-core/lib/metric_report_definition.hpp +@@ -17,16 +17,29 @@ + #pragma once + + #include "node.hpp" ++#include "sensors.hpp" + #include "utils/telemetry_utils.hpp" + #include "utils/time_utils.hpp" ++#include "utils/validate_params_length.hpp" + ++#include <boost/algorithm/string/join.hpp> ++#include <boost/algorithm/string/split.hpp> + #include <boost/container/flat_map.hpp> + ++#include <regex> + #include <system_error> ++#include <tuple> + #include <variant> + + namespace redfish + { ++static constexpr size_t maxShortParamLength = 255; ++static constexpr size_t maxLongParamLength = 1024; ++static constexpr size_t maxDbusNameLength = 255; ++static constexpr size_t maxArraySize = 100; ++static constexpr size_t maxReportIdLen = ++ maxDbusNameLength - std::string_view(telemetry::telemetryPath).size() - ++ std::string_view("/").size(); + + class MetricReportDefinitionCollection : public Node + { +@@ -57,6 +70,339 @@ class MetricReportDefinitionCollection : public Node + telemetry::getReportCollection(asyncResp, + telemetry::metricReportDefinitionUri); + } ++ ++ using ChassisSensorNode = std::pair<std::string, std::string>; ++ using DbusSensor = sdbusplus::message::object_path; ++ using DbusSensors = std::vector<DbusSensor>; ++ using MetricParam = ++ std::tuple<DbusSensors, std::string, std::string, std::string>; ++ using MetricParams = std::vector<MetricParam>; ++ /* ++ * AddReportArgs misses "Domain" parameter because it is constant for ++ * TelemetryService and equals "TelemetryService". ++ */ ++ using AddReportArgs = ++ std::tuple<std::string, std::string, std::vector<std::string>, uint32_t, ++ MetricParams>; ++ ++ void doPost(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>& params) override ++ { ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ AddReportArgs addReportArgs; ++ if (!getUserParameters(res, req, addReportArgs)) ++ { ++ return; ++ } ++ ++ boost::container::flat_set<ChassisSensorNode> chassisSensorSet; ++ auto unmatched = getChassisSensorNode( ++ std::get<MetricParams>(addReportArgs), chassisSensorSet); ++ if (unmatched) ++ { ++ messages::resourceNotFound(asyncResp->res, "MetricProperties", ++ *unmatched); ++ return; ++ } ++ ++ auto addReportReq = ++ std::make_shared<AddReport>(addReportArgs, asyncResp); ++ for (auto& [chassis, sensorType] : chassisSensorSet) ++ { ++ retrieveUriToDbusMap( ++ chassis, sensorType, ++ [asyncResp, addReportReq]( ++ const boost::beast::http::status status, ++ const boost::container::flat_map<std::string, std::string>& ++ uriToDbus) { *addReportReq += uriToDbus; }); ++ } ++ } ++ ++ static std::optional<std::string> ++ replaceReportActions(std::vector<std::string>& actions) ++ { ++ const boost::container::flat_map<std::string, std::string> ++ reportActions = { ++ {"RedfishEvent", "Event"}, ++ {"LogToMetricReportsCollection", "Log"}, ++ }; ++ ++ for (auto& action : actions) ++ { ++ auto found = reportActions.find(action); ++ if (found == reportActions.end()) ++ { ++ return action; ++ } ++ action = found->second; ++ } ++ return std::nullopt; ++ } ++ ++ static constexpr const std::array<const char*, 2> supportedDefinitionType = ++ {"Periodic", "OnRequest"}; ++ ++ static bool getUserParameters(crow::Response& res, const crow::Request& req, ++ AddReportArgs& params) ++ { ++ std::vector<nlohmann::json> metrics; ++ std::optional<nlohmann::json> schedule; ++ auto& [name, reportingType, reportActions, scanPeriod, metricParams] = ++ params; ++ if (!json_util::readJson(req, res, "Id", name, "Metrics", metrics, ++ "MetricReportDefinitionType", reportingType, ++ "ReportActions", reportActions, "Schedule", ++ schedule)) ++ { ++ return false; ++ } ++ ++ auto limits = std::make_tuple( ++ ItemSizeValidator(name, "Id", maxReportIdLen), ++ ItemSizeValidator(reportingType, "MetricReportDefinitionType", ++ maxShortParamLength), ++ ItemSizeValidator(reportActions.size(), "ReportActions.size()", ++ maxArraySize), ++ ArrayItemsValidator(reportActions, "ReportActions", ++ maxShortParamLength), ++ ItemSizeValidator(metrics.size(), "Metrics.size()", maxArraySize)); ++ ++ if (!validateParamsLength(res, std::move(limits))) ++ { ++ return false; ++ } ++ ++ constexpr const char* allowedCharactersInName = ++ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ++ "_"; ++ if (name.empty() || name.find_first_not_of(allowedCharactersInName) != ++ std::string::npos) ++ { ++ BMCWEB_LOG_ERROR << "Failed to match " << name ++ << " with allowed character " ++ << allowedCharactersInName; ++ messages::propertyValueFormatError(res, name, "Id"); ++ return false; ++ } ++ ++ if (!std::any_of( ++ supportedDefinitionType.begin(), supportedDefinitionType.end(), ++ [reportingType](auto& x) { return reportingType == x; })) ++ { ++ messages::propertyValueNotInList(res, reportingType, ++ "MetricReportDefinitionType"); ++ return false; ++ } ++ ++ auto unmatched = replaceReportActions(reportActions); ++ if (unmatched) ++ { ++ messages::propertyValueNotInList(res, *unmatched, "ReportActions"); ++ return false; ++ } ++ ++ if (reportingType == "Periodic") ++ { ++ if (!schedule) ++ { ++ messages::createFailedMissingReqProperties(res, "Schedule"); ++ return false; ++ } ++ ++ std::string interval; ++ if (!json_util::readJson(*schedule, res, "RecurrenceInterval", ++ interval)) ++ { ++ return false; ++ } ++ ++ if (!validateParamLength(res, interval, "RecurrenceInterval", ++ maxShortParamLength)) ++ { ++ return false; ++ } ++ ++ constexpr const char* durationPattern = ++ "-?P(\\d+D)?(T(\\d+H)?(\\d+M)?(\\d+(.\\d+)?S)?)?"; ++ if (!std::regex_match(interval, std::regex(durationPattern))) ++ { ++ messages::propertyValueFormatError(res, interval, ++ "RecurrenceInterval"); ++ return false; ++ } ++ ++ scanPeriod = time_utils::fromDurationFormat(interval); ++ } ++ ++ return fillMetricParams(metrics, res, metricParams); ++ } ++ ++ static bool fillMetricParams(std::vector<nlohmann::json>& metrics, ++ crow::Response& res, ++ MetricParams& metricParams) ++ { ++ metricParams.reserve(metrics.size()); ++ for (auto& m : metrics) ++ { ++ std::string metricId; ++ std::vector<std::string> metricProperties; ++ if (!json_util::readJson(m, res, "MetricId", metricId, ++ "MetricProperties", metricProperties)) ++ { ++ return false; ++ } ++ ++ auto limits = std::make_tuple( ++ ItemSizeValidator(metricId, "MetricId", maxLongParamLength), ++ ItemSizeValidator(metricProperties.size(), ++ "MetricProperties.size()", maxArraySize), ++ ArrayItemsValidator(metricProperties, "MetricProperties", ++ maxLongParamLength)); ++ ++ if (!validateParamsLength(res, std::move(limits))) ++ { ++ return false; ++ } ++ ++ DbusSensors dbusSensors; ++ dbusSensors.reserve(metricProperties.size()); ++ std::for_each( ++ metricProperties.begin(), metricProperties.end(), ++ [&dbusSensors](auto& x) { dbusSensors.emplace_back(x); }); ++ ++ metricParams.emplace_back( ++ dbusSensors, "SINGLE", metricId, ++ boost::algorithm::join(metricProperties, ", ")); ++ } ++ return true; ++ } ++ ++ static std::optional<std::string> getChassisSensorNode( ++ const MetricParams& metricParams, ++ boost::container::flat_set<ChassisSensorNode>& matched) ++ { ++ for (const auto& metricParam : metricParams) ++ { ++ const auto& sensors = std::get<DbusSensors>(metricParam); ++ for (const auto& sensor : sensors) ++ { ++ /* ++ * Support only following paths: ++ * "/redfish/v1/Chassis/<chassis>/Power#/..." ++ * "/redfish/v1/Chassis/<chassis>/Sensors/..." ++ * "/redfish/v1/Chassis/<chassis>/Thermal#/..." ++ */ ++ constexpr const char* uriPattern = ++ "\\/redfish\\/v1\\/Chassis\\/(\\w+)\\/" ++ "(Power|Sensors|Thermal)[#]?\\/.*"; ++ std::smatch m; ++ if (!std::regex_match(sensor.str, m, std::regex(uriPattern)) || ++ m.size() != 3) ++ { ++ BMCWEB_LOG_ERROR << "Failed to match " << sensor.str ++ << " with pattern " << uriPattern; ++ return sensor; ++ } ++ ++ BMCWEB_LOG_DEBUG << "Chassis=" << m[1] << ", Type=" << m[2]; ++ matched.emplace(m[1], m[2]); ++ } ++ } ++ return std::nullopt; ++ } ++ ++ static std::optional<std::string> replaceUriWithDbus( ++ const boost::container::flat_map<std::string, std::string>& uriToDbus, ++ MetricParams& metricParams) ++ { ++ for (auto& metricParam : metricParams) ++ { ++ auto& dbusSensors = std::get<DbusSensors>(metricParam); ++ for (auto& uri : dbusSensors) ++ { ++ auto dbus = uriToDbus.find(uri); ++ if (dbus == uriToDbus.end()) ++ { ++ BMCWEB_LOG_ERROR << "Failed to find DBus sensor " ++ "corresponding to URI " ++ << uri.str; ++ return uri; ++ } ++ uri = dbus->second; ++ } ++ } ++ return std::nullopt; ++ } ++ ++ static void addReport(std::shared_ptr<AsyncResp> asyncResp, ++ AddReportArgs args) ++ { ++ constexpr const char* domain = "TelemetryService"; ++ auto& [name, reportingType, reportActions, scanPeriod, metricParams] = ++ args; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp, name](const boost::system::error_code ec, ++ const std::string ret) { ++ if (ec == boost::system::errc::file_exists) ++ { ++ messages::resourceAlreadyExists( ++ asyncResp->res, "MetricReportDefinition", "Id", name); ++ return; ++ } ++ if (ec == boost::system::errc::too_many_files_open) ++ { ++ messages::createLimitReachedForResource(asyncResp->res); ++ return; ++ } ++ if (ec) ++ { ++ messages::internalError(asyncResp->res); ++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; ++ return; ++ } ++ ++ messages::created(asyncResp->res); ++ }, ++ "xyz.openbmc_project.MonitoringService", ++ "/xyz/openbmc_project/MonitoringService/Reports", ++ "xyz.openbmc_project.MonitoringService.ReportsManagement", ++ "AddReport", name, domain, reportingType, reportActions, scanPeriod, ++ metricParams); ++ } ++ ++ class AddReport ++ { ++ public: ++ AddReport(AddReportArgs& args, std::shared_ptr<AsyncResp>& asyncResp) : ++ asyncResp{asyncResp}, addReportArgs{args} ++ {} ++ ~AddReport() ++ { ++ auto unmatched = replaceUriWithDbus( ++ uriToDbus, std::get<MetricParams>(addReportArgs)); ++ if (unmatched) ++ { ++ messages::resourceNotFound(asyncResp->res, "MetricProperties", ++ *unmatched); ++ return; ++ } ++ ++ addReport(asyncResp, addReportArgs); ++ } ++ ++ AddReport& operator+=( ++ const boost::container::flat_map<std::string, std::string>& rhs) ++ { ++ this->uriToDbus.insert(rhs.begin(), rhs.end()); ++ return *this; ++ } ++ ++ private: ++ std::shared_ptr<AsyncResp> asyncResp; ++ AddReportArgs addReportArgs; ++ boost::container::flat_map<std::string, std::string> uriToDbus{}; ++ }; + }; + + class MetricReportDefinition : public Node +@@ -148,6 +494,7 @@ class MetricReportDefinition : public Node + asyncResp->res.jsonValue["MetricReport"]["@odata.id"] = + telemetry::metricReportUri + id; + asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; ++ asyncResp->res.jsonValue["ReportUpdates"] = "Overwrite"; + + dbus::utility::getAllProperties( + [asyncResp](const boost::system::error_code ec, +-- +2.16.6 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-DELETE-in-MetricReportDefinitions-st.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-DELETE-in-MetricReportDefinitions-st.patch new file mode 100644 index 000000000..4c49b0cd3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-DELETE-in-MetricReportDefinitions-st.patch @@ -0,0 +1,68 @@ +From 8b2f4a6fe57bf2410cdb22f8c3c695e98d583040 Mon Sep 17 00:00:00 2001 +From: "Wludzik, Jozef" <jozef.wludzik@intel.com> +Date: Mon, 18 May 2020 12:40:15 +0200 +Subject: [PATCH 3/5] Add support for DELETE in MetricReportDefinitions/<str> + +Added support for DELETE action in MetricReportDefinitions/<str> +node. It allows user to remove MetricReportDefinition together +with MetricReport connected to it. + +Tested: + - Succesfully passed RedfishServiceValidator.py + - Validated DELETE action by removing exisiting + MetricReportDefinitions from MonitoringService + - Validated DELETE action with negative cases when + MetricReportDefinition does not exist + +Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com> +Change-Id: Iffde9f7bbf2955376e9714ac8d833967bd25eaa3 +--- + redfish-core/lib/metric_report_definition.hpp | 32 +++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp +index ecbab0c..8e04ac8 100644 +--- a/redfish-core/lib/metric_report_definition.hpp ++++ b/redfish-core/lib/metric_report_definition.hpp +@@ -533,6 +533,38 @@ class MetricReportDefinition : public Node + "xyz.openbmc_project.MonitoringService.Report"); + } + ++ void doDelete(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>& params) override ++ { ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ if (params.size() != 1) ++ { ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ const std::string& id = params[0]; ++ telemetry::getReport(asyncResp, id, schemaType, deleteReport); ++ } ++ ++ static void deleteReport(const std::shared_ptr<AsyncResp>& asyncResp, ++ const std::string& path, const std::string& id) ++ { ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ asyncResp->res.result(boost::beast::http::status::no_content); ++ }, ++ "xyz.openbmc_project.MonitoringService", path, ++ "xyz.openbmc_project.Object.Delete", "Delete"); ++ } ++ + public: + static constexpr const char* schemaType = + "#MetricReportDefinition.v1_3_0.MetricReportDefinition"; +-- +2.16.6 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-OnRequest-in-MetricReportDefinition.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-OnRequest-in-MetricReportDefinition.patch new file mode 100644 index 000000000..e996ac585 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-OnRequest-in-MetricReportDefinition.patch @@ -0,0 +1,169 @@ +From 9fc7d722b3192df9940062185b40ebb0fabad518 Mon Sep 17 00:00:00 2001 +From: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +Date: Mon, 8 Jun 2020 15:16:10 +0200 +Subject: [PATCH 4/5] Add support for "OnRequest" in MetricReportDefinition + +Added support for "OnRequest" of ReportingType property in +MetricReportDefinition node. Now user is able to create +MetricReportDefinition that is updated on every GET request +on MetricReport. + +Tested: + - Succesfully passed RedfishServiceValidator.py + - Manually tested via curl + +Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +Change-Id: I1cdfe47e56fdc5ec9753558145d0bf3645160aaf +--- + include/dbus_utility.hpp | 30 +++++++++++++++ + redfish-core/include/utils/telemetry_utils.hpp | 8 ++-- + redfish-core/lib/metric_report.hpp | 53 +++++++++++++++++++++++++- + 3 files changed, 87 insertions(+), 4 deletions(-) + +diff --git a/include/dbus_utility.hpp b/include/dbus_utility.hpp +index 3df88d8..029d8d8 100644 +--- a/include/dbus_utility.hpp ++++ b/include/dbus_utility.hpp +@@ -17,6 +17,7 @@ + + #include <sdbusplus/message.hpp> + ++#include <functional> + #include <regex> + + namespace dbus +@@ -130,5 +131,34 @@ inline void getAllProperties(Callback&& callback, const std::string& service, + interface); + } + ++template <typename T> ++static void getProperty( ++ std::function<void(const boost::system::error_code&, const T&)> callback, ++ const std::string& service, const std::string& path, ++ const std::string& interface, const std::string& property) ++{ ++ crow::connections::systemBus->async_method_call( ++ [callback](const boost::system::error_code ec, ++ const std::variant<T>& value) { ++ if (ec) ++ { ++ callback(ec, T{}); ++ return; ++ } ++ ++ if (auto v = std::get_if<T>(&value)) ++ { ++ callback(ec, *v); ++ return; ++ } ++ ++ callback(boost::system::errc::make_error_code( ++ boost::system::errc::io_error), ++ T{}); ++ }, ++ service, path, "org.freedesktop.DBus.Properties", "Get", interface, ++ property); ++} ++ + } // namespace utility + } // namespace dbus +diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp +index 05ed00f..6c4e810 100644 +--- a/redfish-core/include/utils/telemetry_utils.hpp ++++ b/redfish-core/include/utils/telemetry_utils.hpp +@@ -26,6 +26,8 @@ static constexpr const char* metricReportDefinitionUri = + "/redfish/v1/TelemetryService/MetricReportDefinitions/"; + static constexpr const char* metricReportUri = + "/redfish/v1/TelemetryService/MetricReports/"; ++static constexpr const char* monitoringService = ++ "xyz.openbmc_project.MonitoringService"; + static constexpr const char* reportInterface = + "xyz.openbmc_project.MonitoringService.Report"; + static constexpr const char* telemetryPath = +@@ -66,9 +68,9 @@ static void getReport(const std::shared_ptr<AsyncResp>& asyncResp, + const std::array<const char*, 1> interfaces = {reportInterface}; + + dbus::utility::getSubTreePaths( +- [asyncResp, id, schemaType, +- callback](const boost::system::error_code ec, +- const std::vector<std::string>& reports) { ++ [asyncResp, id, schemaType, callback = std::move(callback)]( ++ const boost::system::error_code ec, ++ const std::vector<std::string>& reports) { + if (ec == boost::system::errc::no_such_file_or_directory) + { + messages::resourceNotFound(asyncResp->res, schemaType, id); +diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp +index a52d680..877e7f1 100644 +--- a/redfish-core/lib/metric_report.hpp ++++ b/redfish-core/lib/metric_report.hpp +@@ -85,7 +85,7 @@ class MetricReport : public Node + } + + const std::string& id = params[0]; +- telemetry::getReport(asyncResp, id, schemaType, getReportProperties); ++ telemetry::getReport(asyncResp, id, schemaType, updateReportIfRequired); + } + + using Readings = +@@ -143,6 +143,57 @@ class MetricReport : public Node + "xyz.openbmc_project.MonitoringService.Report"); + } + ++ template <typename Callback> ++ static void updateReport(Callback&& callback, ++ const std::shared_ptr<AsyncResp>& asyncResp, ++ const std::string& path) ++ { ++ crow::connections::systemBus->async_method_call( ++ [asyncResp, callback{std::move(callback)}]( ++ const boost::system::error_code& ec) { ++ if (ec) ++ { ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ callback(); ++ }, ++ telemetry::monitoringService, path, telemetry::reportInterface, ++ "Update"); ++ } ++ ++ static void ++ updateReportIfRequired(const std::shared_ptr<AsyncResp> asyncResp, ++ const std::string& reportPath, ++ const std::string& id) ++ { ++ dbus::utility::getProperty<std::string>( ++ [asyncResp, id, reportPath](const boost::system::error_code& ec, ++ const std::string& reportingType) { ++ if (ec) ++ { ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ if (reportingType == "OnRequest") ++ { ++ updateReport( ++ [asyncResp, reportPath, id] { ++ getReportProperties(asyncResp, reportPath, id); ++ }, ++ asyncResp, reportPath); ++ } ++ else ++ { ++ getReportProperties(asyncResp, reportPath, id); ++ } ++ }, ++ telemetry::monitoringService, reportPath, ++ telemetry::reportInterface, "ReportingType"); ++ } ++ + static constexpr const char* schemaType = + "#MetricReport.v1_3_0.MetricReport"; + }; +-- +2.16.6 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch new file mode 100644 index 000000000..f7da8a556 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch @@ -0,0 +1,535 @@ +From b1da8901b5985d6a77b63ca9eb0570b46528f0bd Mon Sep 17 00:00:00 2001 +From: "Wludzik, Jozef" <jozef.wludzik@intel.com> +Date: Mon, 8 Jun 2020 17:15:54 +0200 +Subject: [PATCH 5/5] Add support for MetricDefinition scheme + +Added MetricDefinition node to redfish core. Now user is able to +get all possible metrics that are present in system and are +supported by TelemetryService. + +Tested: + - Succesfully passed RedfishServiceValidator.py + - Validated a presence of MetricDefinition members + +Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com> +Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +Change-Id: I3086e1302e1ba2e5442d1367939fd5507a0cbc00 +--- + redfish-core/include/redfish.hpp | 3 + + redfish-core/include/utils/telemetry_utils.hpp | 2 + + redfish-core/lib/metric_definition.hpp | 300 +++++++++++++++++++++++++ + redfish-core/lib/metric_report.hpp | 65 +++++- + redfish-core/lib/sensors.hpp | 43 +++- + redfish-core/lib/telemetry_service.hpp | 2 + + 6 files changed, 402 insertions(+), 13 deletions(-) + create mode 100644 redfish-core/lib/metric_definition.hpp + +diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp +index 3d4c117..2a12bf9 100644 +--- a/redfish-core/include/redfish.hpp ++++ b/redfish-core/include/redfish.hpp +@@ -25,6 +25,7 @@ + #include "../lib/log_services.hpp" + #include "../lib/managers.hpp" + #include "../lib/message_registries.hpp" ++#include "../lib/metric_definition.hpp" + #include "../lib/metric_report.hpp" + #include "../lib/metric_report_definition.hpp" + #include "../lib/network_protocol.hpp" +@@ -206,6 +207,8 @@ class RedfishService + nodes.emplace_back(std::make_unique<HypervisorSystem>(app)); + + nodes.emplace_back(std::make_unique<TelemetryService>(app)); ++ nodes.emplace_back(std::make_unique<MetricDefinitionCollection>(app)); ++ nodes.emplace_back(std::make_unique<MetricDefinition>(app)); + nodes.emplace_back( + std::make_unique<MetricReportDefinitionCollection>(app)); + nodes.emplace_back(std::make_unique<MetricReportDefinition>(app)); +diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp +index 6c4e810..bb747c4 100644 +--- a/redfish-core/include/utils/telemetry_utils.hpp ++++ b/redfish-core/include/utils/telemetry_utils.hpp +@@ -22,6 +22,8 @@ namespace redfish + namespace telemetry + { + ++static constexpr const char* metricDefinitionUri = ++ "/redfish/v1/TelemetryService/MetricDefinitions/"; + static constexpr const char* metricReportDefinitionUri = + "/redfish/v1/TelemetryService/MetricReportDefinitions/"; + static constexpr const char* metricReportUri = +diff --git a/redfish-core/lib/metric_definition.hpp b/redfish-core/lib/metric_definition.hpp +new file mode 100644 +index 0000000..837a068 +--- /dev/null ++++ b/redfish-core/lib/metric_definition.hpp +@@ -0,0 +1,300 @@ ++/* ++// Copyright (c) 2018-2020 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++ ++#pragma once ++ ++#include "node.hpp" ++#include "sensors.hpp" ++#include "utils/telemetry_utils.hpp" ++ ++namespace redfish ++{ ++ ++namespace chassis ++{ ++template <typename F> ++static inline void getChassisNames(F&& callback) ++{ ++ const std::array<const char*, 2> interfaces = { ++ "xyz.openbmc_project.Inventory.Item.Board", ++ "xyz.openbmc_project.Inventory.Item.Chassis"}; ++ ++ dbus::utility::getSubTreePaths( ++ [callback{std::move(callback)}](const boost::system::error_code ec, ++ std::vector<std::string>& chassisList) { ++ if (ec) ++ { ++ return; ++ } ++ ++ std::vector<std::string> chassisNames; ++ chassisNames.reserve(chassisList.size()); ++ for (auto& chassisPath : chassisList) ++ { ++ auto pos = chassisPath.rfind("/"); ++ if (pos == std::string::npos) ++ { ++ continue; ++ } ++ chassisNames.push_back(chassisPath.substr(pos + 1)); ++ } ++ ++ callback(chassisNames); ++ }, ++ "/xyz/openbmc_project/inventory", 0, interfaces); ++} ++} // namespace chassis ++ ++class MetricDefinitionCollection : public Node ++{ ++ public: ++ MetricDefinitionCollection(CrowApp& app) : ++ Node(app, "/redfish/v1/TelemetryService/MetricDefinitions") ++ { ++ entityPrivileges = { ++ {boost::beast::http::verb::get, {{"Login"}}}, ++ {boost::beast::http::verb::head, {{"Login"}}}, ++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::put, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; ++ } ++ ++ private: ++ void doGet(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>& params) override ++ { ++ res.jsonValue["@odata.type"] = "#MetricDefinitionCollection." ++ "MetricDefinitionCollection"; ++ res.jsonValue["@odata.id"] = ++ "/redfish/v1/TelemetryService/MetricDefinitions"; ++ res.jsonValue["Name"] = "Metric Definition Collection"; ++ res.jsonValue["Members"] = nlohmann::json::array(); ++ res.jsonValue["Members@odata.count"] = sensors::dbus::types.size(); ++ ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ auto collectionReduce = std::make_shared<CollectionGather>(asyncResp); ++ chassis::getChassisNames( ++ [asyncResp, ++ collectionReduce](const std::vector<std::string>& chassisNames) { ++ for (auto& chassisName : chassisNames) ++ { ++ for (auto& [sensorNode, _] : sensors::dbus::types) ++ { ++ BMCWEB_LOG_INFO << "Chassis: " << chassisName ++ << " sensor: " << sensorNode; ++ retrieveUriToDbusMap( ++ chassisName, sensorNode.data(), ++ [asyncResp, collectionReduce]( ++ const boost::beast::http::status status, ++ const boost::container::flat_map< ++ std::string, std::string>& uriToDbus) { ++ *collectionReduce += uriToDbus; ++ }); ++ } ++ } ++ }); ++ } ++ ++ class CollectionGather ++ { ++ public: ++ CollectionGather(const std::shared_ptr<AsyncResp>& asyncResp) : ++ asyncResp{asyncResp} ++ { ++ dbusTypes.reserve(sensors::dbus::paths.size()); ++ } ++ ++ ~CollectionGather() ++ { ++ json_util::dbusPathsToMembersArray( ++ asyncResp->res, ++ std::vector<std::string>(dbusTypes.begin(), dbusTypes.end()), ++ telemetry::metricDefinitionUri); ++ } ++ ++ CollectionGather& operator+=( ++ const boost::container::flat_map<std::string, std::string>& rhs) ++ { ++ for (auto& [_, dbusSensor] : rhs) ++ { ++ auto pos = dbusSensor.rfind("/"); ++ if (pos == std::string::npos) ++ { ++ BMCWEB_LOG_ERROR << "Received invalid DBus Sensor Path = " ++ << dbusSensor; ++ continue; ++ } ++ ++ this->dbusTypes.insert(dbusSensor.substr(0, pos)); ++ } ++ return *this; ++ } ++ ++ private: ++ const std::shared_ptr<AsyncResp> asyncResp; ++ boost::container::flat_set<std::string> dbusTypes; ++ }; ++}; ++ ++class MetricDefinition : public Node ++{ ++ public: ++ MetricDefinition(CrowApp& app) : ++ Node(app, std::string(telemetry::metricDefinitionUri) + "<str>/", ++ std::string()) ++ { ++ entityPrivileges = { ++ {boost::beast::http::verb::get, {{"Login"}}}, ++ {boost::beast::http::verb::head, {{"Login"}}}, ++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::put, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; ++ } ++ ++ private: ++ void doGet(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>& params) override ++ { ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ if (params.size() != 1) ++ { ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ const std::string& id = params[0]; ++ ++ size_t sensorIndex = 0; ++ for (auto& name : sensors::dbus::names) ++ { ++ if (name == id) ++ { ++ break; ++ } ++ sensorIndex++; ++ } ++ if (sensorIndex >= sensors::dbus::max) ++ { ++ messages::resourceNotFound(asyncResp->res, schemaType, id); ++ return; ++ } ++ ++ auto definitionGather = ++ std::make_shared<DefinitionGather>(asyncResp, id); ++ chassis::getChassisNames( ++ [asyncResp, definitionGather, ++ sensorIndex](const std::vector<std::string>& chassisNames) { ++ for (auto& chassisName : chassisNames) ++ { ++ for (auto& [sensorNode, dbusPaths] : sensors::dbus::types) ++ { ++ auto found = ++ std::find(dbusPaths.begin(), dbusPaths.end(), ++ sensors::dbus::paths[sensorIndex]); ++ if (found == dbusPaths.end()) ++ { ++ continue; ++ } ++ ++ retrieveUriToDbusMap( ++ chassisName, sensorNode.data(), ++ [asyncResp, definitionGather]( ++ const boost::beast::http::status status, ++ const boost::container::flat_map< ++ std::string, std::string>& uriToDbus) { ++ *definitionGather += uriToDbus; ++ }); ++ } ++ } ++ }); ++ } ++ ++ class DefinitionGather ++ { ++ public: ++ DefinitionGather(const std::shared_ptr<AsyncResp>& asyncResp, ++ const std::string& id) : ++ id(id), ++ asyncResp{asyncResp} ++ {} ++ ~DefinitionGather() ++ { ++ if (redfishSensors.empty()) ++ { ++ messages::resourceNotFound(asyncResp->res, schemaType, id); ++ return; ++ } ++ ++ asyncResp->res.jsonValue["MetricProperties"] = ++ nlohmann::json::array(); ++ auto& members = asyncResp->res.jsonValue["MetricProperties"]; ++ for (auto& redfishSensor : redfishSensors) ++ { ++ members.push_back(redfishSensor); ++ } ++ ++ asyncResp->res.jsonValue["Id"] = id; ++ asyncResp->res.jsonValue["Name"] = id; ++ asyncResp->res.jsonValue["@odata.id"] = ++ telemetry::metricDefinitionUri + id; ++ asyncResp->res.jsonValue["@odata.type"] = schemaType; ++ asyncResp->res.jsonValue["MetricDataType"] = "Decimal"; ++ asyncResp->res.jsonValue["MetricType"] = "Numeric"; ++ asyncResp->res.jsonValue["Implementation"] = "PhysicalSensor"; ++ asyncResp->res.jsonValue["IsLinear"] = true; ++ asyncResp->res.jsonValue["TimestampAccuracy"] = "PT0.1S"; ++ auto unit = sensorUnits.find(id); ++ if (unit != sensorUnits.end()) ++ { ++ asyncResp->res.jsonValue["Units"] = unit->second; ++ } ++ } ++ ++ DefinitionGather& operator+=( ++ const boost::container::flat_map<std::string, std::string>& rhs) ++ { ++ for (auto& [redfishSensor, dbusSensor] : rhs) ++ { ++ if (dbusSensor.find(id) != std::string::npos) ++ { ++ this->redfishSensors.push_back(redfishSensor); ++ } ++ } ++ return *this; ++ } ++ ++ const std::string id; ++ ++ private: ++ const std::shared_ptr<AsyncResp> asyncResp; ++ std::vector<std::string> redfishSensors; ++ const boost::container::flat_map<std::string, std::string> sensorUnits = ++ {{sensors::dbus::names[sensors::dbus::voltage], "V"}, ++ {sensors::dbus::names[sensors::dbus::power], "W"}, ++ {sensors::dbus::names[sensors::dbus::current], "A"}, ++ {sensors::dbus::names[sensors::dbus::fan_tach], "RPM"}, ++ {sensors::dbus::names[sensors::dbus::temperature], "Cel"}, ++ {sensors::dbus::names[sensors::dbus::utilization], "%"}, ++ {sensors::dbus::names[sensors::dbus::fan_pwm], "Duty cycle"}}; ++ }; ++ ++ static constexpr const char* schemaType = ++ "#MetricDefinition.v1_0_3.MetricDefinition"; ++}; ++ ++} // namespace redfish +diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp +index 877e7f1..be72b18 100644 +--- a/redfish-core/lib/metric_report.hpp ++++ b/redfish-core/lib/metric_report.hpp +@@ -91,6 +91,9 @@ class MetricReport : public Node + using Readings = + std::vector<std::tuple<std::string, std::string, double, int32_t>>; + using MetricValues = std::vector<std::map<std::string, std::string>>; ++ using ReadingParameters = ++ std::vector<std::tuple<std::vector<sdbusplus::message::object_path>, ++ std::string, std::string, std::string>>; + + static MetricValues toMetricValues(const Readings& readings) + { +@@ -109,6 +112,49 @@ class MetricReport : public Node + return metricValues; + } + ++ static void addMetricDefinition(nlohmann::json& metrics, ++ const ReadingParameters& params) ++ { ++ for (auto& metric : metrics) ++ { ++ if (!metric.contains("MetricId")) ++ { ++ continue; ++ } ++ ++ auto& id = metric["MetricId"].get_ref<std::string&>(); ++ auto param = ++ std::find_if(params.begin(), params.end(), [id](const auto& x) { ++ return id == std::get<2>(x); ++ }); ++ if (param == params.end()) ++ { ++ continue; ++ } ++ ++ auto& dbusPaths = ++ std::get<std::vector<sdbusplus::message::object_path>>(*param); ++ if (dbusPaths.size() > 1) ++ { ++ continue; ++ } ++ ++ auto dbusPath = dbusPaths.begin(); ++ for (size_t i = 0; i < sensors::dbus::paths.size(); i++) ++ { ++ if (dbusPath->str.find(sensors::dbus::paths[i]) == ++ std::string::npos) ++ { ++ continue; ++ } ++ metric["MetricDefinition"]["@odata.id"] = ++ telemetry::metricDefinitionUri + ++ std::string(sensors::dbus::names[i]); ++ break; ++ } ++ } ++ } ++ + static void getReportProperties(const std::shared_ptr<AsyncResp> asyncResp, + const std::string& reportPath, + const std::string& id) +@@ -124,7 +170,8 @@ class MetricReport : public Node + [asyncResp]( + const boost::system::error_code ec, + const boost::container::flat_map< +- std::string, std::variant<Readings, int32_t>>& ret) { ++ std::string, ++ std::variant<Readings, int32_t, ReadingParameters>>& ret) { + if (ec) + { + messages::internalError(asyncResp->res); +@@ -138,6 +185,22 @@ class MetricReport : public Node + json_util::assignIfPresent<Readings>( + ret, "Readings", asyncResp->res.jsonValue["MetricValues"], + toMetricValues); ++ ++ auto found = ret.find("ReadingParameters"); ++ if (found != ret.end()) ++ { ++ auto params = ++ std::get_if<ReadingParameters>(&found->second); ++ if (params) ++ { ++ auto& jsonValue = asyncResp->res.jsonValue; ++ if (jsonValue.contains("MetricValues")) ++ { ++ addMetricDefinition(jsonValue["MetricValues"], ++ *params); ++ } ++ } ++ } + }, + "xyz.openbmc_project.MonitoringService", reportPath, + "xyz.openbmc_project.MonitoringService.Report"); +diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp +index f12bbe0..1fa1009 100644 +--- a/redfish-core/lib/sensors.hpp ++++ b/redfish-core/lib/sensors.hpp +@@ -53,20 +53,39 @@ static constexpr std::string_view thermal = "Thermal"; + + namespace dbus + { ++ ++enum Index ++{ ++ voltage = 0, ++ power, ++ current, ++ fan_tach, ++ temperature, ++ fan_pwm, ++ utilization, ++ max ++}; ++ ++static constexpr std::array<const char*, max> names = { ++ "voltage", "power", "current", "fan_tach", ++ "temperature", "fan_pwm", "utilization"}; ++ ++static constexpr std::array<const char*, max> paths = { ++ "/xyz/openbmc_project/sensors/voltage", ++ "/xyz/openbmc_project/sensors/power", ++ "/xyz/openbmc_project/sensors/current", ++ "/xyz/openbmc_project/sensors/fan_tach", ++ "/xyz/openbmc_project/sensors/temperature", ++ "/xyz/openbmc_project/sensors/fan_pwm", ++ "/xyz/openbmc_project/sensors/utilization"}; ++ + static const boost::container::flat_map<std::string_view, + std::vector<const char*>> +- types = {{node::power, +- {"/xyz/openbmc_project/sensors/voltage", +- "/xyz/openbmc_project/sensors/power"}}, +- {node::sensors, +- {"/xyz/openbmc_project/sensors/power", +- "/xyz/openbmc_project/sensors/current", +- "/xyz/openbmc_project/sensors/utilization"}}, +- {node::thermal, +- {"/xyz/openbmc_project/sensors/fan_tach", +- "/xyz/openbmc_project/sensors/temperature", +- "/xyz/openbmc_project/sensors/fan_pwm"}}}; +-} ++ types = { ++ {node::power, {paths[voltage], paths[power]}}, ++ {node::sensors, {paths[power], paths[current], paths[utilization]}}, ++ {node::thermal, {paths[fan_tach], paths[temperature], paths[fan_pwm]}}}; ++} // namespace dbus + } // namespace sensors + + /** +diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp +index a410700..79e4154 100644 +--- a/redfish-core/lib/telemetry_service.hpp ++++ b/redfish-core/lib/telemetry_service.hpp +@@ -52,6 +52,8 @@ class TelemetryService : public Node + + res.jsonValue["LogService"]["@odata.id"] = + "/redfish/v1/Managers/bmc/LogServices/Journal"; ++ res.jsonValue["MetricDefinitions"]["@odata.id"] = ++ "/redfish/v1/TelemetryService/MetricDefinitions"; + res.jsonValue["MetricReportDefinitions"]["@odata.id"] = + "/redfish/v1/TelemetryService/MetricReportDefinitions"; + res.jsonValue["MetricReports"]["@odata.id"] = +-- +2.16.6 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch new file mode 100644 index 000000000..75d49b6d6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch @@ -0,0 +1,78 @@ +From b71f087a173c36a16526156fa34581673e2b860c Mon Sep 17 00:00:00 2001 +From: "Wludzik, Jozef" <jozef.wludzik@intel.com> +Date: Fri, 24 Jul 2020 17:05:38 +0200 +Subject: [PATCH 6/6] Fix MetricReport timestamp for EventService + +Changed MetricReport timestamp type from std::string to int32_t. + +Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com> +Change-Id: I0a52b6963e7bedda89a216256f64764cd8799bf1 +--- + redfish-core/include/event_service_manager.hpp | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index d2f4f2a..dc04ccb 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -38,7 +38,7 @@ namespace redfish + { + + using ReadingsObjType = +- std::vector<std::tuple<std::string, std::string, double, std::string>>; ++ std::vector<std::tuple<std::string, std::string, double, int32_t>>; + using EventServiceConfig = std::tuple<bool, uint32_t, uint32_t>; + + static constexpr const char* eventFormatType = "Event"; +@@ -532,10 +532,12 @@ class Subscription + metricValuesArray.push_back({}); + nlohmann::json& entry = metricValuesArray.back(); + +- entry = {{"MetricId", std::get<0>(it)}, +- {"MetricProperty", std::get<1>(it)}, +- {"MetricValue", std::to_string(std::get<2>(it))}, +- {"Timestamp", std::get<3>(it)}}; ++ auto& [id, property, value, timestamp] = it; ++ ++ entry = {{"MetricId", id}, ++ {"MetricProperty", property}, ++ {"MetricValue", value}, ++ {"Timestamp", crow::utility::getDateTime(timestamp)}}; + } + + nlohmann::json msg = { +@@ -1266,7 +1268,7 @@ class EventServiceManager + [idStr{std::move(idStr)}]( + const boost::system::error_code ec, + boost::container::flat_map< +- std::string, std::variant<std::string, ReadingsObjType>>& ++ std::string, std::variant<int32_t, ReadingsObjType>>& + resp) { + if (ec) + { +@@ -1275,8 +1277,8 @@ class EventServiceManager + return; + } + +- const std::string* timestampPtr = +- std::get_if<std::string>(&resp["Timestamp"]); ++ const int32_t* timestampPtr = ++ std::get_if<int32_t>(&resp["Timestamp"]); + if (!timestampPtr) + { + BMCWEB_LOG_DEBUG << "Failed to Get timestamp."; +@@ -1303,8 +1305,9 @@ class EventServiceManager + std::shared_ptr<Subscription> entry = it.second; + if (entry->eventFormatType == metricReportFormatType) + { +- entry->filterAndSendReports(idStr, *timestampPtr, +- *readingsPtr); ++ entry->filterAndSendReports( ++ idStr, crow::utility::getDateTime(*timestampPtr), ++ *readingsPtr); + } + } + }, +-- +2.16.6 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README new file mode 100644 index 000000000..2929b0aec --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README @@ -0,0 +1,21 @@ +These patches are mirror of upstream TelemetryService implementation. +Until change is integrated they will be manually merged here to enable feature in Intel builds. + +Current revisions: +- Redfish TelemetryService schema implementation + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/31692/29 + +- Add support for POST in MetricReportDefinitions + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/32536/24 + +- Add support for DELETE in MetricReportDefinitions/<str> + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/32537/23 + +- Add support for "OnRequest" in MetricReportDefinition + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/33358/17 + +- Add support for MetricDefinition scheme + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/33363/20 + +- Temporary patch for EventService because of change in design + 0006-Fix-MetricReport-timestamp-for-EventService.patch diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend index 5c70f25d7..5a44eec78 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend @@ -1,6 +1,8 @@ # todo(james) remove nobranch SRC_URI = "git://github.com/openbmc/bmcweb.git" -SRCREV = "a502de3d661acf95613d4e4d27c9611f2c8148ea" +SRCREV = "6964c9820ad101d6fc30badd1ae353efea3dd094" + +DEPENDS += "boost-url" FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" @@ -13,14 +15,37 @@ GROUPADD_PARAM_${PN} = "web; redfish " SRC_URI += "file://0001-Firmware-update-support-for-StandBySpare.patch \ file://0002-Use-chip-id-based-UUID-for-Service-Root.patch \ file://0003-bmcweb-changes-for-setting-ApplyOptions-ClearCfg.patch \ + file://0004-Remove-QueryString.patch \ + file://0004-bmcweb-handle-device-or-resource-busy-exception.patch \ + file://0005-EventService-https-client-support.patch \ + file://0005-VirtualMedia-fixes-for-Redfish-Service-Validator.patch \ + file://0006-Fix-Image-and-ImageName-values-in-schema.patch \ +" + +# Temporary downstream mirror of upstream patches, see telemetry\README for details +SRC_URI += "file://telemetry/0001-Redfish-TelemetryService-schema-implementation.patch \ + file://telemetry/0002-Add-support-for-POST-in-MetricReportDefinitions.patch \ + file://telemetry/0003-Add-support-for-DELETE-in-MetricReportDefinitions-st.patch \ + file://telemetry/0004-Add-support-for-OnRequest-in-MetricReportDefinition.patch \ + file://telemetry/0005-Add-support-for-MetricDefinition-scheme.patch \ + file://telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch \ " +# Temporary fix: Move it to service file +do_install_append() { + install -d ${D}/var/lib/bmcweb +} + # Enable PFR support EXTRA_OECMAKE += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '-DBMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE=ON', '', d)}" -# Enable NBD_PROXY +# Enable NBD proxy embedded in bmcweb EXTRA_OECMAKE += " -DBMCWEB_ENABLE_VM_NBDPROXY=ON" +# Disable dependency on external nbd-proxy application +EXTRA_OECMAKE += " -DBMCWEB_ENABLE_VM_WEBSOCKET=OFF" +RDEPENDS_${PN}_remove += "jsnbd" + # Enable Validation unsecure based on IMAGE_FEATURES EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsecure', '-DBMCWEB_ENABLE_VALIDATION_UNSECURE_FEATURE=ON', '', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb index 055e9710e..43f0785e5 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb @@ -2,7 +2,7 @@ SUMMARY = "libmctp_intel" DESCRIPTION = "Implementation of MCTP(DMTF DSP0236)" SRC_URI = "git://github.com/Intel-BMC/libmctp.git;protocol=ssh" -SRCREV = "58581630af62fce296206e9d09da38cf1d6d1a0f" +SRCREV = "467717ed557169e86be2c694e616fbfa9f5982c7" S = "${WORKDIR}/git/" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-emulator.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-emulator.bb index 829bc1636..98d2d11e4 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-emulator.bb +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-emulator.bb @@ -5,7 +5,7 @@ LICENSE = "Apache-2.0" LIC_FILES_CHKSUM = "file://LICENSE;md5=bcd9ada3a943f58551867d72893cc9ab" SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh" -SRCREV = "cd15b3175e2dd8315d1e01634f2c8a24174c9b21" +SRCREV = "1bc2bddcff7104cc9040e9b2688761b2d9b32099" S = "${WORKDIR}/git/mctp_emulator/" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb index f20426ba1..740fd460e 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb @@ -5,7 +5,7 @@ LICENSE = "Apache-2.0" LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh" -SRCREV = "cd15b3175e2dd8315d1e01634f2c8a24174c9b21" +SRCREV = "1bc2bddcff7104cc9040e9b2688761b2d9b32099" S = "${WORKDIR}/git/mctpd/" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend index 67d8854d2..8ebca0b9e 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend @@ -1,4 +1,4 @@ # Enable downstream autobump SRC_URI = "git://github.com/openbmc/phosphor-sel-logger.git" -SRCREV = "761bf202ba9db9fe644f8f400a5e768abe1a70cf" +SRCREV = "25b26e162bd109b51aa09b16f26f9aa3d9d940fa" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend index 882547ea7..ac45a8114 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend @@ -1,4 +1,4 @@ -SRCREV = "5591cf0860895607bda0b8ae713e6b05ac0623b1" +SRCREV = "623723b9e827f52a05cfe2dac8b4ef5d285fb6af" #SRC_URI = "git://github.com/openbmc/dbus-sensors.git" DEPENDS_append = " libgpiod libmctp" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/service-config-manager/service-config-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/service-config-manager/service-config-manager_%.bbappend index 6d26a95a9..c34d7af43 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/service-config-manager/service-config-manager_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/service-config-manager/service-config-manager_%.bbappend @@ -1,5 +1,6 @@ inherit meson pkgconfig systemd -SRC_URI = "git://github.com/openbmc/service-config-manager" -SRCREV = "1a885d98eea964bd9a3d57152dcaae7d4808211f" +SRC_URI = "git://github.com/openbmc/service-config-manager;nobranch=1" +# Move to latest version, only when sdbusplus is bumped up +SRCREV = "0f2b1414d0dda4534008fc5eb0e939d99287c0eb" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb index e15525bba..3fe7a1782 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb @@ -1,7 +1,7 @@ SUMMARY = "Settings" SRC_URI = "git://github.com/Intel-BMC/settings.git;protocol=ssh" -SRCREV = "cf55f85c9cd676736356f06fc47a7e98abd297f3" +SRCREV = "5d2150656d23412c59acd4da7b9f155902f089d9" PV = "0.1+git${SRCPV}" LICENSE = "Apache-2.0" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb index ea8971eb4..e27f2295c 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb @@ -9,7 +9,7 @@ LICENSE = "Apache-2.0" LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" SRC_URI = "git://github.com/Intel-BMC/special-mode-manager.git;protocol=ssh" -SRCREV = "658d313be17b971aedae69e9edbba5f26667dd03" +SRCREV = "e9bcb94f78ec9dad22bc008e1abdb18f16f39a40" EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsecure', '-DBMC_VALIDATION_UNSECURE_FEATURE=ON', '', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb index 333611dbb..2b0f167c4 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb @@ -14,8 +14,7 @@ SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.VirtualMedia.service" DEPENDS = "udev boost nlohmann-json systemd sdbusplus" -# Needed for legacy mode -RDEPENDS_${PN} = "nbdkit" +RDEPENDS_${PN} = "nbd-client nbdkit" inherit cmake systemd diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend index ce46ec5cd..4a188f28e 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend @@ -1,4 +1,4 @@ SRC_URI = "git://github.com/Intel-BMC/phosphor-webui;protocol=ssh;branch=intel2" FILESEXTRAPATHS_prepend_intel := "${THISDIR}/${PN}:" -SRCREV = "7d6650577d28a52e7be47dd2106d9e0f3b6e1c59" +SRCREV = "3348cfbfd54e52a795516bc4a906e128c1bc6bcf" diff --git a/meta-openbmc-mods/meta-common/recipes-support/boost-url/boost-url_git.bb b/meta-openbmc-mods/meta-common/recipes-support/boost-url/boost-url_git.bb new file mode 100644 index 000000000..6d4635b66 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/boost-url/boost-url_git.bb @@ -0,0 +1,17 @@ +DESCRIPTION = "Boost.URL is a library for manipulating Uniform Resource Identifiers (URI) and Locators (URL)" +HOMEPAGE = "https://github.com/CPPAlliance/url" +SECTION = "libs" +LICENSE = "BSL-1.0" +LIC_FILES_CHKSUM = "file://LICENSE_1_0.txt;md5=e4224ccaecb14d942c71d31bef20d78c" + +SRC_URI = "git://github.com/CPPAlliance/url.git" + +SRCREV = "a56ae0df6d3078319755fbaa67822b4fa7fd352b" + +S = "${WORKDIR}/git" + +inherit cmake + +DEPENDS = "boost" + +BBCLASSEXTEND = "native nativesdk" diff --git a/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control_%.bbappend b/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control_%.bbappend index b107c8873..d2d918404 100755 --- a/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control_%.bbappend @@ -1,3 +1,7 @@ +# Enable downstream autobump +SRC_URI = "git://github.com/openbmc/x86-power-control.git;protocol=ssh" +SRCREV = "273d789718ce2a7aaf49424f9cefcd89226da2a7" + FILESEXTRAPATHS_append := "${THISDIR}/${PN}:" SRC_URI += " \ diff --git a/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor/0001-Filter-memory-thermtrip-events-based-on-DIMM-status.patch b/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor/0001-Filter-memory-thermtrip-events-based-on-DIMM-status.patch new file mode 100644 index 000000000..30859d1a4 --- /dev/null +++ b/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor/0001-Filter-memory-thermtrip-events-based-on-DIMM-status.patch @@ -0,0 +1,153 @@ +From 0253fd1d68d6a42c95c425b1a61fa2d53b2b2469 Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@intel.com> +Date: Wed, 22 Jul 2020 14:30:04 -0700 +Subject: [PATCH] Filter memory thermtrip events based on DIMM status + +There is a race-condition on shutdown that makes it difficult to +differentiate between a normal shutdown and a memory thermtrip +shutdown. This race-condition will be resolved in the CPLD for +future platforms but for now it requires a workaround. + +This workaround assumes that a memory thermtrip can only occur +if a DIMM temperature sensor has already reached a critical +threshold. When memory thermtrip asserts on shutdown, it only +logs an error if a DIMM is critical; otherwise it is treated +as a normal shutdown. + +Tested: +Memory thermtrip errors no longer log on each power-off. +Manually set a DIMM temperature above critical and verified +that the memory thermtrip event is logged. + +Change-Id: I9c38b41db30046499297ee24cc3a2790920b19d3 +Signed-off-by: Jason M. Bills <jason.m.bills@intel.com> +--- + src/host_error_monitor.cpp | 77 +++++++++++++++++++++++++++++++++++++- + 1 file changed, 75 insertions(+), 2 deletions(-) + +diff --git a/src/host_error_monitor.cpp b/src/host_error_monitor.cpp +index 1c6a2e70d..aa4a9b672 100644 +--- a/src/host_error_monitor.cpp ++++ b/src/host_error_monitor.cpp +@@ -17,6 +17,7 @@ + #include <systemd/sd-journal.h> + + #include <boost/asio/posix/stream_descriptor.hpp> ++#include <boost/container/flat_set.hpp> + #include <gpiod.hpp> + #include <sdbusplus/asio/object_server.hpp> + +@@ -36,6 +37,9 @@ static std::shared_ptr<sdbusplus::asio::dbus_interface> associationCATAssert; + + static const constexpr char* rootPath = "/xyz/openbmc_project/CallbackManager"; + ++static boost::container::flat_set<std::string> cpu1CriticalDIMMs; ++static boost::container::flat_set<std::string> cpu2CriticalDIMMs; ++ + static bool hostOff = true; + + static size_t caterrTimeoutMs = 2000; +@@ -258,6 +262,67 @@ static void initializeHostState() + "xyz.openbmc_project.State.Host", "CurrentHostState"); + } + ++static std::shared_ptr<sdbusplus::bus::match::match> ++ startDIMMThresholdEventMonitor() ++{ ++ return std::make_shared<sdbusplus::bus::match::match>( ++ *conn, ++ "type='signal',interface='org.freedesktop.DBus.Properties',member='" ++ "PropertiesChanged',arg0namespace='xyz.openbmc_project.Sensor." ++ "Threshold.Critical'", ++ [](sdbusplus::message::message& msg) { ++ std::string interfaceName; ++ boost::container::flat_map<std::string, std::variant<bool>> ++ propertiesChanged; ++ try ++ { ++ msg.read(interfaceName, propertiesChanged); ++ } ++ catch (std::exception& e) ++ { ++ std::cerr << "Unable to read threshold event\n"; ++ return; ++ } ++ // We only want to check for CriticalAlarmHigh ++ if (propertiesChanged.begin()->first != "CriticalAlarmHigh") ++ { ++ return; ++ } ++ const bool* alarm = ++ std::get_if<bool>(&(propertiesChanged.begin()->second)); ++ if (alarm == nullptr) ++ { ++ std::cerr << propertiesChanged.begin()->first ++ << " property invalid\n"; ++ return; ++ } ++ ++ // Get the sensor path and check if it's a DIMM sensor ++ std::string sensor = msg.get_path(); ++ if (sensor.find("DIMM") == std::string::npos) ++ { ++ // Not a DIMM sensor ++ return; ++ } ++ ++ // Determine which CPU the DIMM belongs to ++ boost::container::flat_set<std::string>& criticalDIMMs = ++ (sensor.find("CPU1") != std::string::npos) ? cpu1CriticalDIMMs ++ : cpu2CriticalDIMMs; ++ ++ if (*alarm) ++ { ++ // DIMM crossed a critical threshold, so store it ++ criticalDIMMs.insert(sensor); ++ } ++ else ++ { ++ // DIMM is no longer critical, so remove it ++ criticalDIMMs.erase(sensor); ++ } ++ }); ++} ++ + static std::shared_ptr<sdbusplus::bus::match::match> startHostStateMonitor() + { + return std::make_shared<sdbusplus::bus::match::match>( +@@ -826,7 +891,9 @@ static void cpu1MemtripHandler() + + bool cpu1Memtrip = + gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE; +- if (cpu1Memtrip) ++ ++ // Only log a memory thermtrip if a DIMM is critical ++ if (cpu1Memtrip && !cpu1CriticalDIMMs.empty()) + { + memThermTripLog(1); + } +@@ -886,7 +953,9 @@ static void cpu2MemtripHandler() + + bool cpu2Memtrip = + gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE; +- if (cpu2Memtrip) ++ ++ // Only log a memory thermtrip if a DIMM is critical ++ if (cpu2Memtrip && !cpu2CriticalDIMMs.empty()) + { + memThermTripLog(2); + } +@@ -1605,6 +1674,10 @@ int main(int argc, char* argv[]) + std::shared_ptr<sdbusplus::bus::match::match> hostStateMonitor = + host_error_monitor::startHostStateMonitor(); + ++ // Start tracking critical DIMM status ++ std::shared_ptr<sdbusplus::bus::match::match> dimmThresholdEventMonitor = ++ host_error_monitor::startDIMMThresholdEventMonitor(); ++ + // Request CPU1_MISMATCH GPIO events + if (!host_error_monitor::requestGPIOInput( + "CPU1_MISMATCH", host_error_monitor::cpu1MismatchLine)) +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor_%.bbappend b/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor_%.bbappend new file mode 100644 index 000000000..4b79757c0 --- /dev/null +++ b/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor_%.bbappend @@ -0,0 +1,5 @@ +FILESEXTRAPATHS_append := "${THISDIR}/${PN}:" + +SRC_URI += " \ + file://0001-Filter-memory-thermtrip-events-based-on-DIMM-status.patch \ + " |