From ec79c56300c15fb32ad22596eacbdea0d218d9f5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 12 Feb 2021 18:06:51 +0000 Subject: hw/display/sm501: Remove dead code for non-32-bit RGB surfaces For a long time now the UI layer has guaranteed that the console surface is always 32 bits per pixel RGB. Remove the legacy dead code from the sm501 display device which was handling the possibility that the console surface was some other format. Signed-off-by: Peter Maydell Message-Id: <20210212180653.27588-2-peter.maydell@linaro.org> Acked-by: BALATON Zoltan Signed-off-by: David Gibson --- hw/display/sm501.c | 91 ++++-------------------------------------------------- 1 file changed, 6 insertions(+), 85 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 8966b69bc7..aba447c18b 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -1558,89 +1558,9 @@ typedef void draw_hwc_line_func(uint8_t *d, const uint8_t *s, int width, const uint8_t *palette, int c_x, int c_y); -#define DEPTH 8 -#include "sm501_template.h" - -#define DEPTH 15 -#include "sm501_template.h" - -#define BGR_FORMAT -#define DEPTH 15 -#include "sm501_template.h" - -#define DEPTH 16 -#include "sm501_template.h" - -#define BGR_FORMAT -#define DEPTH 16 -#include "sm501_template.h" - #define DEPTH 32 #include "sm501_template.h" -#define BGR_FORMAT -#define DEPTH 32 -#include "sm501_template.h" - -static draw_line_func *draw_line8_funcs[] = { - draw_line8_8, - draw_line8_15, - draw_line8_16, - draw_line8_32, - draw_line8_32bgr, - draw_line8_15bgr, - draw_line8_16bgr, -}; - -static draw_line_func *draw_line16_funcs[] = { - draw_line16_8, - draw_line16_15, - draw_line16_16, - draw_line16_32, - draw_line16_32bgr, - draw_line16_15bgr, - draw_line16_16bgr, -}; - -static draw_line_func *draw_line32_funcs[] = { - draw_line32_8, - draw_line32_15, - draw_line32_16, - draw_line32_32, - draw_line32_32bgr, - draw_line32_15bgr, - draw_line32_16bgr, -}; - -static draw_hwc_line_func *draw_hwc_line_funcs[] = { - draw_hwc_line_8, - draw_hwc_line_15, - draw_hwc_line_16, - draw_hwc_line_32, - draw_hwc_line_32bgr, - draw_hwc_line_15bgr, - draw_hwc_line_16bgr, -}; - -static inline int get_depth_index(DisplaySurface *surface) -{ - switch (surface_bits_per_pixel(surface)) { - default: - case 8: - return 0; - case 15: - return 1; - case 16: - return 2; - case 32: - if (is_surface_bgr(surface)) { - return 4; - } else { - return 3; - } - } -} - static void sm501_update_display(void *opaque) { SM501State *s = (SM501State *)opaque; @@ -1652,7 +1572,6 @@ static void sm501_update_display(void *opaque) int height = get_height(s, crt); int src_bpp = get_bpp(s, crt); int dst_bpp = surface_bytes_per_pixel(surface); - int dst_depth_index = get_depth_index(surface); draw_line_func *draw_line = NULL; draw_hwc_line_func *draw_hwc_line = NULL; int full_update = 0; @@ -1662,6 +1581,8 @@ static void sm501_update_display(void *opaque) uint8_t hwc_palette[3 * 3]; uint8_t *hwc_src = NULL; + assert(dst_bpp == 4); /* Output is always 32-bit RGB */ + if (!((crt ? s->dc_crt_control : s->dc_panel_control) & SM501_DC_CRT_CONTROL_ENABLE)) { return; @@ -1674,13 +1595,13 @@ static void sm501_update_display(void *opaque) /* choose draw_line function */ switch (src_bpp) { case 1: - draw_line = draw_line8_funcs[dst_depth_index]; + draw_line = draw_line8_32; break; case 2: - draw_line = draw_line16_funcs[dst_depth_index]; + draw_line = draw_line16_32; break; case 4: - draw_line = draw_line32_funcs[dst_depth_index]; + draw_line = draw_line32_32; break; default: qemu_log_mask(LOG_GUEST_ERROR, "sm501: update display" @@ -1691,7 +1612,7 @@ static void sm501_update_display(void *opaque) /* set up to draw hardware cursor */ if (is_hwc_enabled(s, crt)) { /* choose cursor draw line function */ - draw_hwc_line = draw_hwc_line_funcs[dst_depth_index]; + draw_hwc_line = draw_hwc_line_32; hwc_src = get_hwc_address(s, crt); c_x = get_hwc_x(s, crt); c_y = get_hwc_y(s, crt); -- cgit v1.2.3-55-g7522 From 36144df315ca614a40a45daded8bc5c691fcc3e7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 12 Feb 2021 18:06:52 +0000 Subject: hw/display/sm501: Expand out macros in template header Now that we only include sm501_template.h for the DEPTH==32 case, we can expand out the uses of the BPP, PIXEL_TYPE and PIXEL_NAME macros in that header. Signed-off-by: Peter Maydell Message-Id: <20210212180653.27588-3-peter.maydell@linaro.org> Acked-by: BALATON Zoltan Signed-off-by: David Gibson --- hw/display/sm501_template.h | 60 +++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 43 deletions(-) diff --git a/hw/display/sm501_template.h b/hw/display/sm501_template.h index a60abad019..28537a05d9 100644 --- a/hw/display/sm501_template.h +++ b/hw/display/sm501_template.h @@ -22,28 +22,8 @@ * THE SOFTWARE. */ -#if DEPTH == 8 -#define BPP 1 -#define PIXEL_TYPE uint8_t -#elif DEPTH == 15 || DEPTH == 16 -#define BPP 2 -#define PIXEL_TYPE uint16_t -#elif DEPTH == 32 -#define BPP 4 -#define PIXEL_TYPE uint32_t -#else -#error unsupport depth -#endif - -#ifdef BGR_FORMAT -#define PIXEL_NAME glue(DEPTH, bgr) -#else -#define PIXEL_NAME DEPTH -#endif /* BGR_FORMAT */ - - -static void glue(draw_line8_, PIXEL_NAME)( - uint8_t *d, const uint8_t *s, int width, const uint32_t *pal) +static void draw_line8_32(uint8_t *d, const uint8_t *s, int width, + const uint32_t *pal) { uint8_t v, r, g, b; do { @@ -51,14 +31,14 @@ static void glue(draw_line8_, PIXEL_NAME)( r = (pal[v] >> 16) & 0xff; g = (pal[v] >> 8) & 0xff; b = (pal[v] >> 0) & 0xff; - *(PIXEL_TYPE *)d = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); + *(uint32_t *)d = rgb_to_pixel32(r, g, b); s++; - d += BPP; + d += 4; } while (--width != 0); } -static void glue(draw_line16_, PIXEL_NAME)( - uint8_t *d, const uint8_t *s, int width, const uint32_t *pal) +static void draw_line16_32(uint8_t *d, const uint8_t *s, int width, + const uint32_t *pal) { uint16_t rgb565; uint8_t r, g, b; @@ -68,14 +48,14 @@ static void glue(draw_line16_, PIXEL_NAME)( r = (rgb565 >> 8) & 0xf8; g = (rgb565 >> 3) & 0xfc; b = (rgb565 << 3) & 0xf8; - *(PIXEL_TYPE *)d = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); + *(uint32_t *)d = rgb_to_pixel32(r, g, b); s += 2; - d += BPP; + d += 4; } while (--width != 0); } -static void glue(draw_line32_, PIXEL_NAME)( - uint8_t *d, const uint8_t *s, int width, const uint32_t *pal) +static void draw_line32_32(uint8_t *d, const uint8_t *s, int width, + const uint32_t *pal) { uint8_t r, g, b; @@ -83,17 +63,17 @@ static void glue(draw_line32_, PIXEL_NAME)( r = s[2]; g = s[1]; b = s[0]; - *(PIXEL_TYPE *)d = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); + *(uint32_t *)d = rgb_to_pixel32(r, g, b); s += 4; - d += BPP; + d += 4; } while (--width != 0); } /** * Draw hardware cursor image on the given line. */ -static void glue(draw_hwc_line_, PIXEL_NAME)(uint8_t *d, const uint8_t *s, - int width, const uint8_t *palette, int c_x, int c_y) +static void draw_hwc_line_32(uint8_t *d, const uint8_t *s, int width, + const uint8_t *palette, int c_x, int c_y) { int i; uint8_t r, g, b, v, bitset = 0; @@ -101,7 +81,7 @@ static void glue(draw_hwc_line_, PIXEL_NAME)(uint8_t *d, const uint8_t *s, /* get cursor position */ assert(0 <= c_y && c_y < SM501_HWC_HEIGHT); s += SM501_HWC_WIDTH * c_y / 4; /* 4 pixels per byte */ - d += c_x * BPP; + d += c_x * 4; for (i = 0; i < SM501_HWC_WIDTH && c_x + i < width; i++) { /* get pixel value */ @@ -118,14 +98,8 @@ static void glue(draw_hwc_line_, PIXEL_NAME)(uint8_t *d, const uint8_t *s, r = palette[v * 3 + 0]; g = palette[v * 3 + 1]; b = palette[v * 3 + 2]; - *(PIXEL_TYPE *)d = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); + *(uint32_t *)d = rgb_to_pixel32(r, g, b); } - d += BPP; + d += 4; } } - -#undef DEPTH -#undef BPP -#undef PIXEL_TYPE -#undef PIXEL_NAME -#undef BGR_FORMAT -- cgit v1.2.3-55-g7522 From f7b5c16182fcb90bd312c81d0a5f63926c1dc367 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 12 Feb 2021 18:06:53 +0000 Subject: hw/display/sm501: Inline template header into C file We no longer need to include sm501_template.h multiple times, so we can simply inline its contents into sm501.c. Signed-off-by: Peter Maydell Message-Id: <20210212180653.27588-4-peter.maydell@linaro.org> Acked-by: BALATON Zoltan Signed-off-by: David Gibson --- hw/display/sm501.c | 83 +++++++++++++++++++++++++++++++++- hw/display/sm501_template.h | 105 -------------------------------------------- 2 files changed, 81 insertions(+), 107 deletions(-) delete mode 100644 hw/display/sm501_template.h diff --git a/hw/display/sm501.c b/hw/display/sm501.c index aba447c18b..8789722ef2 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -1558,8 +1558,87 @@ typedef void draw_hwc_line_func(uint8_t *d, const uint8_t *s, int width, const uint8_t *palette, int c_x, int c_y); -#define DEPTH 32 -#include "sm501_template.h" +static void draw_line8_32(uint8_t *d, const uint8_t *s, int width, + const uint32_t *pal) +{ + uint8_t v, r, g, b; + do { + v = ldub_p(s); + r = (pal[v] >> 16) & 0xff; + g = (pal[v] >> 8) & 0xff; + b = (pal[v] >> 0) & 0xff; + *(uint32_t *)d = rgb_to_pixel32(r, g, b); + s++; + d += 4; + } while (--width != 0); +} + +static void draw_line16_32(uint8_t *d, const uint8_t *s, int width, + const uint32_t *pal) +{ + uint16_t rgb565; + uint8_t r, g, b; + + do { + rgb565 = lduw_le_p(s); + r = (rgb565 >> 8) & 0xf8; + g = (rgb565 >> 3) & 0xfc; + b = (rgb565 << 3) & 0xf8; + *(uint32_t *)d = rgb_to_pixel32(r, g, b); + s += 2; + d += 4; + } while (--width != 0); +} + +static void draw_line32_32(uint8_t *d, const uint8_t *s, int width, + const uint32_t *pal) +{ + uint8_t r, g, b; + + do { + r = s[2]; + g = s[1]; + b = s[0]; + *(uint32_t *)d = rgb_to_pixel32(r, g, b); + s += 4; + d += 4; + } while (--width != 0); +} + +/** + * Draw hardware cursor image on the given line. + */ +static void draw_hwc_line_32(uint8_t *d, const uint8_t *s, int width, + const uint8_t *palette, int c_x, int c_y) +{ + int i; + uint8_t r, g, b, v, bitset = 0; + + /* get cursor position */ + assert(0 <= c_y && c_y < SM501_HWC_HEIGHT); + s += SM501_HWC_WIDTH * c_y / 4; /* 4 pixels per byte */ + d += c_x * 4; + + for (i = 0; i < SM501_HWC_WIDTH && c_x + i < width; i++) { + /* get pixel value */ + if (i % 4 == 0) { + bitset = ldub_p(s); + s++; + } + v = bitset & 3; + bitset >>= 2; + + /* write pixel */ + if (v) { + v--; + r = palette[v * 3 + 0]; + g = palette[v * 3 + 1]; + b = palette[v * 3 + 2]; + *(uint32_t *)d = rgb_to_pixel32(r, g, b); + } + d += 4; + } +} static void sm501_update_display(void *opaque) { diff --git a/hw/display/sm501_template.h b/hw/display/sm501_template.h deleted file mode 100644 index 28537a05d9..0000000000 --- a/hw/display/sm501_template.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Pixel drawing function templates for QEMU SM501 Device - * - * Copyright (c) 2008 Shin-ichiro KAWASAKI - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -static void draw_line8_32(uint8_t *d, const uint8_t *s, int width, - const uint32_t *pal) -{ - uint8_t v, r, g, b; - do { - v = ldub_p(s); - r = (pal[v] >> 16) & 0xff; - g = (pal[v] >> 8) & 0xff; - b = (pal[v] >> 0) & 0xff; - *(uint32_t *)d = rgb_to_pixel32(r, g, b); - s++; - d += 4; - } while (--width != 0); -} - -static void draw_line16_32(uint8_t *d, const uint8_t *s, int width, - const uint32_t *pal) -{ - uint16_t rgb565; - uint8_t r, g, b; - - do { - rgb565 = lduw_le_p(s); - r = (rgb565 >> 8) & 0xf8; - g = (rgb565 >> 3) & 0xfc; - b = (rgb565 << 3) & 0xf8; - *(uint32_t *)d = rgb_to_pixel32(r, g, b); - s += 2; - d += 4; - } while (--width != 0); -} - -static void draw_line32_32(uint8_t *d, const uint8_t *s, int width, - const uint32_t *pal) -{ - uint8_t r, g, b; - - do { - r = s[2]; - g = s[1]; - b = s[0]; - *(uint32_t *)d = rgb_to_pixel32(r, g, b); - s += 4; - d += 4; - } while (--width != 0); -} - -/** - * Draw hardware cursor image on the given line. - */ -static void draw_hwc_line_32(uint8_t *d, const uint8_t *s, int width, - const uint8_t *palette, int c_x, int c_y) -{ - int i; - uint8_t r, g, b, v, bitset = 0; - - /* get cursor position */ - assert(0 <= c_y && c_y < SM501_HWC_HEIGHT); - s += SM501_HWC_WIDTH * c_y / 4; /* 4 pixels per byte */ - d += c_x * 4; - - for (i = 0; i < SM501_HWC_WIDTH && c_x + i < width; i++) { - /* get pixel value */ - if (i % 4 == 0) { - bitset = ldub_p(s); - s++; - } - v = bitset & 3; - bitset >>= 2; - - /* write pixel */ - if (v) { - v--; - r = palette[v * 3 + 0]; - g = palette[v * 3 + 1]; - b = palette[v * 3 + 2]; - *(uint32_t *)d = rgb_to_pixel32(r, g, b); - } - d += 4; - } -} -- cgit v1.2.3-55-g7522 From 382907b10077ed4cff48d9afe219a023887c0522 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 11 Feb 2021 19:52:40 -0300 Subject: spapr_drc.c: do not call spapr_drc_detach() in drc_isolate_logical() drc_isolate_logical() is used to move the DRC from the "Configured" to the "Available" state, erroring out if the DRC is in the unexpected "Unisolate" state and doing nothing (with RTAS_OUT_SUCCESS) if the DRC is already in "Available" or in "Unusable" state. When moving from "Configured" to "Available", the DRC is moved to the LOGICAL_AVAILABLE state, a drc->unplug_requested check is done and, if true, spapr_drc_detach() is called. What spapr_drc_detach() does then is: - set drc->unplug_requested to true. In fact, this is the only place where unplug_request is set to true; - does nothing else if drc->state != drck->empty_state. If the DRC state is equal to drck->empty_state, spapr_drc_release() is called. For logical DRCs, drck->empty_state = LOGICAL_UNUSABLE. In short, calling spapr_drc_detach() in drc_isolate_logical() does nothing. It'll set unplug_request to true again ('again' since it was already true - otherwise the function wouldn't be called), and will return without calling spapr_drc_release() because the DRC is not in LOGICAL_UNUSABLE, since drc_isolate_logical() just moved it to LOGICAL_AVAILABLE. The only place where the logical DRC is released is when called from drc_set_unusable(), when it is moved to the "Unusable" state. As it should, according to PAPR. Even though calling spapr_drc_detach() in drc_isolate_logical() is benign, removing it will avoid further thought about the matter. So let's go ahead and do that. As a note, this logic was introduced in commit bbf5c878ab76. Since then, the DRC handling code was refactored and enhanced, and PAPR itself went through some changes in the DRC area as well. It is expected that some assumptions we had back then are now deprecated. Signed-off-by: Daniel Henrique Barboza Message-Id: <20210211225246.17315-2-danielhb413@gmail.com> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/ppc/spapr_drc.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 8571d5bafe..84bd3c881f 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -132,19 +132,6 @@ static uint32_t drc_isolate_logical(SpaprDrc *drc) drc->state = SPAPR_DRC_STATE_LOGICAL_AVAILABLE; - /* if we're awaiting release, but still in an unconfigured state, - * it's likely the guest is still in the process of configuring - * the device and is transitioning the devices to an ISOLATED - * state as a part of that process. so we only complete the - * removal when this transition happens for a device in a - * configured state, as suggested by the state diagram from PAPR+ - * 2.7, 13.4 - */ - if (drc->unplug_requested) { - uint32_t drc_index = spapr_drc_index(drc); - trace_spapr_drc_set_isolation_state_finalizing(drc_index); - spapr_drc_detach(drc); - } return RTAS_OUT_SUCCESS; } -- cgit v1.2.3-55-g7522 From b88e0a57e6577f22620873d2363671b53faf77a5 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Fri, 19 Feb 2021 14:56:20 +1100 Subject: pseries: Update SLOF firmware image This is mostly compiler warnings fixed but while doing this, a bug in MIN() in tcgbios was found. Alexey Kardashevskiy (14): helpers: Define MIN() libc: Compile with -Wextra elf: Compile with -Wextra usb: Compile with -Wextra veth: Compile with -Wextra virtio: Compile with -Wextra e1000: Compile with -Wextra libnet: Compile with -Wextra libhv: Compile with -Wextra libnvram: Compile with -Wextra libtpm: Compile with -Wextra slof/prim: Compile with -Wextra Makefile: Actually compile with -Wextra version: update to 20210217 Thomas Huth (1): virtio-serial: Remove superfluous serial-* words Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson --- pc-bios/README | 2 +- pc-bios/slof.bin | Bin 968368 -> 968888 bytes roms/SLOF | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index db7129ef64..c101c9a04f 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,7 +14,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/aik/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20200717. + built from git tag qemu-slof-20210217. - sgabios (the Serial Graphics Adapter option ROM) provides a means for legacy x86 software to communicate with an attached serial console as diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin index 448dcada36..3f3918a9e1 100644 Binary files a/pc-bios/slof.bin and b/pc-bios/slof.bin differ diff --git a/roms/SLOF b/roms/SLOF index e18ddad851..33a7322de1 160000 --- a/roms/SLOF +++ b/roms/SLOF @@ -1 +1 @@ -Subproject commit e18ddad8516ff2cfe36ec130200318f7251aa78c +Subproject commit 33a7322de13e9dca4b38851a345a58d37e7a441d -- cgit v1.2.3-55-g7522 From 66d10d32ace18da3eacf2d8ee72c6076e87f9e72 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 22 Feb 2021 16:45:27 -0300 Subject: spapr_drc.c: use spapr_drc_release() in isolate_physical/set_unusable When moving a physical DRC to "Available", drc_isolate_physical() will move the DRC state to STATE_PHYSICAL_POWERON and, if the DRC is marked for unplug, call spapr_drc_detach(). For physical DRCs, drck->empty_state is STATE_PHYSICAL_POWERON, meaning that we're sure that spapr_drc_detach() will end up calling spapr_drc_release() in the end. Likewise, for logical DRCs, drc_set_unusable will move the DRC to "Unusable" state, setting drc->state to STATE_LOGICAL_UNUSABLE, which is the drck->empty_state for logical DRCs. spapr_drc_detach() will call spapr_drc_release() in this case as well. In both scenarios, spapr_drc_detach() is being used as a spapr_drc_release(), wrapper, where we also set unplug_requested (which is already true, otherwise spapr_drc_detach() wouldn't be called in the first place) and check if drc->state == drck->empty_state, which we also know it's guaranteed to be true because we just set it. Just use spapr_drc_release() in these functions to be clear of our intentions in both these functions. Reviewed-by: Greg Kurz Reviewed-by: David Gibson Signed-off-by: Daniel Henrique Barboza Message-Id: <20210222194531.62717-2-danielhb413@gmail.com> Signed-off-by: David Gibson --- hw/ppc/spapr_drc.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 84bd3c881f..555a25517d 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -50,6 +50,20 @@ uint32_t spapr_drc_index(SpaprDrc *drc) | (drc->id & DRC_INDEX_ID_MASK); } +static void spapr_drc_release(SpaprDrc *drc) +{ + SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + + drck->release(drc->dev); + + drc->unplug_requested = false; + g_free(drc->fdt); + drc->fdt = NULL; + drc->fdt_start_offset = 0; + object_property_del(OBJECT(drc), "device"); + drc->dev = NULL; +} + static uint32_t drc_isolate_physical(SpaprDrc *drc) { switch (drc->state) { @@ -68,7 +82,7 @@ static uint32_t drc_isolate_physical(SpaprDrc *drc) if (drc->unplug_requested) { uint32_t drc_index = spapr_drc_index(drc); trace_spapr_drc_set_isolation_state_finalizing(drc_index); - spapr_drc_detach(drc); + spapr_drc_release(drc); } return RTAS_OUT_SUCCESS; @@ -209,7 +223,7 @@ static uint32_t drc_set_unusable(SpaprDrc *drc) if (drc->unplug_requested) { uint32_t drc_index = spapr_drc_index(drc); trace_spapr_drc_set_allocation_state_finalizing(drc_index); - spapr_drc_detach(drc); + spapr_drc_release(drc); } return RTAS_OUT_SUCCESS; @@ -372,20 +386,6 @@ void spapr_drc_attach(SpaprDrc *drc, DeviceState *d) NULL, 0); } -static void spapr_drc_release(SpaprDrc *drc) -{ - SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - - drck->release(drc->dev); - - drc->unplug_requested = false; - g_free(drc->fdt); - drc->fdt = NULL; - drc->fdt_start_offset = 0; - object_property_del(OBJECT(drc), "device"); - drc->dev = NULL; -} - void spapr_drc_detach(SpaprDrc *drc) { SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); -- cgit v1.2.3-55-g7522 From a03509cd2baf48b1e947d9eb203ccb95bd99e5fb Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 22 Feb 2021 16:45:28 -0300 Subject: spapr: rename spapr_drc_detach() to spapr_drc_unplug_request() spapr_drc_detach() is not the best name for what the function does. The function does not detach the DRC, it makes an uncommited attempt to do it. It'll mark the DRC as pending unplug, via the 'unplug_request' flag, and only if the DRC state is drck->empty_state it will detach the DRC, via spapr_drc_release(). This is a contrast with its pair spapr_drc_attach(), where the function is indeed creating the DRC QOM object. If you know what spapr_drc_attach() does, you can be misled into thinking that spapr_drc_detach() is removing the DRC from QEMU internal state, which isn't true. The current role of this function is better described as a request for detach, since there's no guarantee that we're going to detach the DRC in the end. Rename the function to spapr_drc_unplug_request to reflect what is is doing. The initial idea was to change the name to spapr_drc_detach_request(), and later on change the unplug_request flag to detach_request. However, unplug_request is a migratable boolean for a long time now and renaming it is not worth the trouble. spapr_drc_unplug_request() setting drc->unplug_request is more natural than spapr_drc_detach_request setting drc->unplug_request. Reviewed-by: Greg Kurz Reviewed-by: David Gibson Signed-off-by: Daniel Henrique Barboza Message-Id: <20210222194531.62717-3-danielhb413@gmail.com> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 6 +++--- hw/ppc/spapr_drc.c | 4 ++-- hw/ppc/spapr_pci.c | 4 ++-- hw/ppc/trace-events | 2 +- include/hw/ppc/spapr_drc.h | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 85fe65f894..b066df68cb 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3654,7 +3654,7 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, addr / SPAPR_MEMORY_BLOCK_SIZE); g_assert(drc); - spapr_drc_detach(drc); + spapr_drc_unplug_request(drc); addr += SPAPR_MEMORY_BLOCK_SIZE; } @@ -3722,7 +3722,7 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, g_assert(drc); if (!spapr_drc_unplug_requested(drc)) { - spapr_drc_detach(drc); + spapr_drc_unplug_request(drc); spapr_hotplug_req_remove_by_index(drc); } } @@ -3985,7 +3985,7 @@ static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev, assert(drc); if (!spapr_drc_unplug_requested(drc)) { - spapr_drc_detach(drc); + spapr_drc_unplug_request(drc); spapr_hotplug_req_remove_by_index(drc); } } diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 555a25517d..67041fb212 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -386,11 +386,11 @@ void spapr_drc_attach(SpaprDrc *drc, DeviceState *d) NULL, 0); } -void spapr_drc_detach(SpaprDrc *drc) +void spapr_drc_unplug_request(SpaprDrc *drc) { SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - trace_spapr_drc_detach(spapr_drc_index(drc)); + trace_spapr_drc_unplug_request(spapr_drc_index(drc)); g_assert(drc->dev); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index f1c7479816..b00e9609ae 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1723,12 +1723,12 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler, * functions, even if their unplug weren't requested * beforehand. */ - spapr_drc_detach(func_drc); + spapr_drc_unplug_request(func_drc); } } } - spapr_drc_detach(drc); + spapr_drc_unplug_request(drc); /* if this isn't func 0, defer unplug event. otherwise signal removal * for all present functions diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 1e91984526..b4bbfbb013 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -50,7 +50,7 @@ spapr_drc_set_allocation_state(uint32_t index, int state) "drc: 0x%"PRIx32", sta spapr_drc_set_allocation_state_finalizing(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_set_configured(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_attach(uint32_t index) "drc: 0x%"PRIx32 -spapr_drc_detach(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_unplug_request(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_awaiting_quiesce(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_reset(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_realize(uint32_t index) "drc: 0x%"PRIx32 diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h index 8982927d5c..02a63b3666 100644 --- a/include/hw/ppc/spapr_drc.h +++ b/include/hw/ppc/spapr_drc.h @@ -243,7 +243,7 @@ int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask); * beforehand (eg. check drc->dev at pre-plug). */ void spapr_drc_attach(SpaprDrc *drc, DeviceState *d); -void spapr_drc_detach(SpaprDrc *drc); +void spapr_drc_unplug_request(SpaprDrc *drc); /* * Reset all DRCs, causing pending hot-plug/unplug requests to complete. -- cgit v1.2.3-55-g7522 From a4ee352fe025bd1308eb77b11b3b60542af8a370 Mon Sep 17 00:00:00 2001 From: Cédric Le Goater Date: Mon, 22 Feb 2021 14:39:56 +0100 Subject: docs/system: Extend PPC section This moves the current documentation in files specific to each platform family. PowerNV machine is updated, the other machines need to be done. Signed-off-by: Cédric Le Goater Message-Id: <20210222133956.156001-1-clg@kaod.org> Reviewed-by: Greg Kurz [dwg: Trivial capitalization fix] Signed-off-by: David Gibson --- docs/system/ppc/embedded.rst | 10 +++ docs/system/ppc/powermac.rst | 34 ++++++++ docs/system/ppc/powernv.rst | 193 +++++++++++++++++++++++++++++++++++++++++++ docs/system/ppc/prep.rst | 18 ++++ docs/system/ppc/pseries.rst | 12 +++ docs/system/target-ppc.rst | 53 ++++-------- 6 files changed, 282 insertions(+), 38 deletions(-) create mode 100644 docs/system/ppc/embedded.rst create mode 100644 docs/system/ppc/powermac.rst create mode 100644 docs/system/ppc/powernv.rst create mode 100644 docs/system/ppc/prep.rst create mode 100644 docs/system/ppc/pseries.rst diff --git a/docs/system/ppc/embedded.rst b/docs/system/ppc/embedded.rst new file mode 100644 index 0000000000..cfffbda24d --- /dev/null +++ b/docs/system/ppc/embedded.rst @@ -0,0 +1,10 @@ +Embedded family boards +====================== + +- ``bamboo`` bamboo +- ``mpc8544ds`` mpc8544ds +- ``ppce500`` generic paravirt e500 platform +- ``ref405ep`` ref405ep +- ``sam460ex`` aCube Sam460ex +- ``taihu`` taihu +- ``virtex-ml507`` Xilinx Virtex ML507 reference design diff --git a/docs/system/ppc/powermac.rst b/docs/system/ppc/powermac.rst new file mode 100644 index 0000000000..04334ba210 --- /dev/null +++ b/docs/system/ppc/powermac.rst @@ -0,0 +1,34 @@ +PowerMac family boards (``g3beige``, ``mac99``) +================================================================== + +Use the executable ``qemu-system-ppc`` to simulate a complete PowerMac +PowerPC system. + +- ``g3beige`` Heathrow based PowerMAC +- ``mac99`` Mac99 based PowerMAC + +Supported devices +----------------- + +QEMU emulates the following PowerMac peripherals: + + * UniNorth or Grackle PCI Bridge + * PCI VGA compatible card with VESA Bochs Extensions + * 2 PMAC IDE interfaces with hard disk and CD-ROM support + * NE2000 PCI adapters + * Non Volatile RAM + * VIA-CUDA with ADB keyboard and mouse. + + +Missing devices +--------------- + + * To be identified + +Firmware +-------- + +Since version 0.9.1, QEMU uses OpenBIOS https://www.openbios.org/ for +the g3beige and mac99 PowerMac and the 40p machines. OpenBIOS is a free +(GPL v2) portable firmware implementation. The goal is to implement a +100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. diff --git a/docs/system/ppc/powernv.rst b/docs/system/ppc/powernv.rst new file mode 100644 index 0000000000..43c58bc32e --- /dev/null +++ b/docs/system/ppc/powernv.rst @@ -0,0 +1,193 @@ +PowerNV family boards (``powernv8``, ``powernv9``) +================================================================== + +PowerNV (as Non-Virtualized) is the "baremetal" platform using the +OPAL firmware. It runs Linux on IBM and OpenPOWER systems and it can +be used as an hypervisor OS, running KVM guests, or simply as a host +OS. + +The PowerNV QEMU machine tries to emulate a PowerNV system at the +level of the skiboot firmware, which loads the OS and provides some +runtime services. Power Systems have a lower firmware (HostBoot) that +does low level system initialization, like DRAM training. This is +beyond the scope of what QEMU addresses today. + +Supported devices +----------------- + + * Multi processor support for POWER8, POWER8NVL and POWER9. + * XSCOM, serial communication sideband bus to configure chiplets + * Simple LPC Controller + * Processor Service Interface (PSI) Controller + * Interrupt Controller, XICS (POWER8) and XIVE (POWER9) + * POWER8 PHB3 PCIe Host bridge and POWER9 PHB4 PCIe Host bridge + * Simple OCC is an on-chip microcontroller used for power management + tasks + * iBT device to handle BMC communication, with the internal BMC + simulator provided by QEMU or an external BMC such as an Aspeed + QEMU machine. + * PNOR containing the different firmware partitions. + +Missing devices +--------------- + +A lot is missing, among which : + + * POWER10 processor + * XIVE2 (POWER10) interrupt controller + * I2C controllers (yet to be merged) + * NPU/NPU2/NPU3 controllers + * EEH support for PCIe Host bridge controllers + * NX controller + * VAS controller + * chipTOD (Time Of Day) + * Self Boot Engine (SBE). + * FSI bus + +Firmware +-------- + +The OPAL firmware (OpenPower Abstraction Layer) for OpenPower systems +includes the runtime services `skiboot` and the bootloader kernel and +initramfs `skiroot`. Source code can be found on GitHub: + + https://github.com/open-power. + +Prebuilt images of `skiboot` and `skiboot` are made available on the `OpenPOWER `__ site. To boot a POWER9 machine, use the `witherspoon `__ images. For POWER8, use +the `palmetto `__ images. + +QEMU includes a prebuilt image of `skiboot` which is updated when a +more recent version is required by the models. + +Boot options +------------ + +Here is a simple setup with one e1000e NIC : + +.. code-block:: bash + + $ qemu-system-ppc64 -m 2G -machine powernv9 -smp 2,cores=2,threads=1 \ + -accel tcg,thread=single \ + -device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0 \ + -netdev user,id=net0,hostfwd=::20022-:22,hostname=pnv \ + -kernel ./zImage.epapr \ + -initrd ./rootfs.cpio.xz \ + -nographic + +and a SATA disk : + +.. code-block:: bash + + -device ich9-ahci,id=sata0,bus=pcie.1,addr=0x0 \ + -drive file=./ubuntu-ppc64le.qcow2,if=none,id=drive0,format=qcow2,cache=none \ + -device ide-hd,bus=sata0.0,unit=0,drive=drive0,id=ide,bootindex=1 \ + +Complex PCIe configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Six PHBs are defined per chip (POWER9) but no default PCI layout is +provided (to be compatible with libvirt). One PCI device can be added +on any of the available PCIe slots using command line options such as: + +.. code-block:: bash + + -device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0 + -netdev bridge,id=net0,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=hostnet0 + + -device megasas,id=scsi0,bus=pcie.0,addr=0x0 + -drive file=./ubuntu-ppc64le.qcow2,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none + -device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2 + +Here is a full example with two different storage controllers on +different PHBs, each with a disk, the second PHB is empty : + +.. code-block:: bash + + $ qemu-system-ppc64 -m 2G -machine powernv9 -smp 2,cores=2,threads=1 -accel tcg,thread=single \ + -kernel ./zImage.epapr -initrd ./rootfs.cpio.xz -bios ./skiboot.lid \ + \ + -device megasas,id=scsi0,bus=pcie.0,addr=0x0 \ + -drive file=./rhel7-ppc64le.qcow2,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none \ + -device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2 \ + \ + -device pcie-pci-bridge,id=bridge1,bus=pcie.1,addr=0x0 \ + \ + -device ich9-ahci,id=sata0,bus=bridge1,addr=0x1 \ + -drive file=./ubuntu-ppc64le.qcow2,if=none,id=drive0,format=qcow2,cache=none \ + -device ide-hd,bus=sata0.0,unit=0,drive=drive0,id=ide,bootindex=1 \ + -device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=bridge1,addr=0x2 \ + -netdev bridge,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=net0 \ + -device nec-usb-xhci,bus=bridge1,addr=0x7 \ + \ + -serial mon:stdio -nographic + +You can also use VIRTIO devices : + +.. code-block:: bash + + -drive file=./fedora-ppc64le.qcow2,if=none,snapshot=on,id=drive0 \ + -device virtio-blk-pci,drive=drive0,id=blk0,bus=pcie.0 \ + \ + -netdev tap,helper=/usr/lib/qemu/qemu-bridge-helper,br=virbr0,id=netdev0 \ + -device virtio-net-pci,netdev=netdev0,id=net0,bus=pcie.1 \ + \ + -fsdev local,id=fsdev0,path=$HOME,security_model=passthrough \ + -device virtio-9p-pci,fsdev=fsdev0,mount_tag=host,bus=pcie.2 + +Multi sockets +~~~~~~~~~~~~~ + +The number of sockets is deduced from the number of CPUs and the +number of cores. ``-smp 2,cores=1`` will define a machine with 2 +sockets of 1 core, whereas ``-smp 2,cores=2`` will define a machine +with 1 socket of 2 cores. ``-smp 8,cores=2``, 4 sockets of 2 cores. + +BMC configuration +~~~~~~~~~~~~~~~~~ + +OpenPOWER systems negotiate the shutdown and reboot with their +BMC. The QEMU PowerNV machine embeds an IPMI BMC simulator using the +iBT interface and should offer the same power features. + +If you want to define your own BMC, use ``-nodefaults`` and specify +one on the command line : + +.. code-block:: bash + + -device ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10 + +The files `palmetto-SDR.bin `__ +and `palmetto-FRU.bin `__ +define a Sensor Data Record repository and a Field Replaceable Unit +inventory for a palmetto BMC. They can be used to extend the QEMU BMC +simulator. + +.. code-block:: bash + + -device ipmi-bmc-sim,sdrfile=./palmetto-SDR.bin,fruareasize=256,frudatafile=./palmetto-FRU.bin,id=bmc0 \ + -device isa-ipmi-bt,bmc=bmc0,irq=10 + +The PowerNV machine can also be run with an external IPMI BMC device +connected to a remote QEMU machine acting as BMC, using these options +: + +.. code-block:: bash + + -chardev socket,id=ipmi0,host=localhost,port=9002,reconnect=10 \ + -device ipmi-bmc-extern,id=bmc0,chardev=ipmi0 \ + -device isa-ipmi-bt,bmc=bmc0,irq=10 \ + -nodefaults + +NVRAM +~~~~~ + +Use a MTD drive to add a PNOR to the machine, and get a NVRAM : + +.. code-block:: bash + + -drive file=./witherspoon.pnor,format=raw,if=mtd + +CAVEATS +------- + + * No support for multiple HW threads (SMT=1). Same as pseries. + * CPU can hang when doing intensive I/Os. Use ``-append powersave=off`` in that case. diff --git a/docs/system/ppc/prep.rst b/docs/system/ppc/prep.rst new file mode 100644 index 0000000000..bd9eb8eabd --- /dev/null +++ b/docs/system/ppc/prep.rst @@ -0,0 +1,18 @@ +Prep machine (``40p``) +================================================================== + +Use the executable ``qemu-system-ppc`` to simulate a complete 40P (PREP) + +Supported devices +----------------- + +QEMU emulates the following 40P (PREP) peripherals: + + * PCI Bridge + * PCI VGA compatible card with VESA Bochs Extensions + * 2 IDE interfaces with hard disk and CD-ROM support + * Floppy disk + * PCnet network adapters + * Serial port + * PREP Non Volatile RAM + * PC compatible keyboard and mouse. diff --git a/docs/system/ppc/pseries.rst b/docs/system/ppc/pseries.rst new file mode 100644 index 0000000000..932d4dd17d --- /dev/null +++ b/docs/system/ppc/pseries.rst @@ -0,0 +1,12 @@ +pSeries family boards (``pseries``) +=================================== + +Supported devices +----------------- + +Missing devices +--------------- + + +Firmware +-------- diff --git a/docs/system/target-ppc.rst b/docs/system/target-ppc.rst index a2f04c533c..67905b8f2a 100644 --- a/docs/system/target-ppc.rst +++ b/docs/system/target-ppc.rst @@ -3,45 +3,22 @@ PowerPC System emulator ----------------------- -Use the executable ``qemu-system-ppc`` to simulate a complete 40P (PREP) -or PowerMac PowerPC system. +Board-specific documentation +============================ -QEMU emulates the following PowerMac peripherals: +You can get a complete list by running ``qemu-system-ppc64 --machine +help``. -- UniNorth or Grackle PCI Bridge +.. + This table of contents should be kept sorted alphabetically + by the title text of each file, which isn't the same ordering + as an alphabetical sort by filename. -- PCI VGA compatible card with VESA Bochs Extensions +.. toctree:: + :maxdepth: 1 -- 2 PMAC IDE interfaces with hard disk and CD-ROM support - -- NE2000 PCI adapters - -- Non Volatile RAM - -- VIA-CUDA with ADB keyboard and mouse. - -QEMU emulates the following 40P (PREP) peripherals: - -- PCI Bridge - -- PCI VGA compatible card with VESA Bochs Extensions - -- 2 IDE interfaces with hard disk and CD-ROM support - -- Floppy disk - -- PCnet network adapters - -- Serial port - -- PREP Non Volatile RAM - -- PC compatible keyboard and mouse. - -Since version 0.9.1, QEMU uses OpenBIOS https://www.openbios.org/ for -the g3beige and mac99 PowerMac and the 40p machines. OpenBIOS is a free -(GPL v2) portable firmware implementation. The goal is to implement a -100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. - -More information is available at -http://perso.magic.fr/l_indien/qemu-ppc/. + ppc/embedded + ppc/powermac + ppc/powernv + ppc/prep + ppc/pseries -- cgit v1.2.3-55-g7522 From 936fda4d771fdc51d3640bdb0cc8ceec14165730 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 22 Feb 2021 16:40:35 -0300 Subject: target/ppc: Fix bcdsub. emulation when result overflows The commit d03b174a83 (target/ppc: simplify bcdadd/sub functions) meant to simplify some of the code but it inadvertently altered the way the CR6 field is set after the operation has overflowed. The CR6 bits are set based on the *unbounded* result of the operation, so we need to look at the result before returning from bcd_add_mag, otherwise we will look at 0 when it overflows. Consider the following subtraction: v0 = 0x9999999999999999999999999999999c (maximum positive BCD value) v1 = 0x0000000000000000000000000000001d (negative one BCD value) bcdsub. v0,v0,v1,0 The Power ISA 2.07B says: If the unbounded result is greater than zero, do the following. If PS=0, the sign code of the result is set to 0b1100. If PS=1, the sign code of the result is set to 0b1111. If the operation overflows, CR field 6 is set to 0b0101. Otherwise, CR field 6 is set to 0b0100. POWER9 hardware: vr0 = 0x0000000000000000000000000000000c (positive zero BCD value) cr6 = 0b0101 (0x5) (positive, overflow) QEMU: vr0 = 0x0000000000000000000000000000000c (positive zero BCD value) cr6 = 0b0011 (0x3) (zero, overflow) <--- wrong This patch reverts the part of d03b174a83 that introduced the problem and adds a test-case to avoid further regressions: before: $ make run-tcg-tests-ppc64le-linux-user (...) TEST bcdsub on ppc64le bcdsub: qemu/tests/tcg/ppc64le/bcdsub.c:58: test_bcdsub_gt: Assertion `(cr >> 4) == ((1 << 2) | (1 << 0))' failed. Fixes: d03b174a83 (target/ppc: simplify bcdadd/sub functions) Reported-by: Paul Clarke Signed-off-by: Fabiano Rosas Message-Id: <20210222194035.2723056-1-farosas@linux.ibm.com> Signed-off-by: David Gibson --- target/ppc/int_helper.c | 13 +++- tests/tcg/configure.sh | 6 ++ tests/tcg/ppc64/Makefile.target | 13 ++++ tests/tcg/ppc64le/Makefile.target | 12 ++++ tests/tcg/ppc64le/bcdsub.c | 130 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 tests/tcg/ppc64/Makefile.target create mode 100644 tests/tcg/ppc64le/Makefile.target create mode 100644 tests/tcg/ppc64le/bcdsub.c diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 0b682a1f94..429de28494 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -2175,14 +2175,17 @@ static int bcd_cmp_mag(ppc_avr_t *a, ppc_avr_t *b) return 0; } -static void bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid, +static int bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid, int *overflow) { int carry = 0; int i; + int is_zero = 1; + for (i = 1; i <= 31; i++) { uint8_t digit = bcd_get_digit(a, i, invalid) + bcd_get_digit(b, i, invalid) + carry; + is_zero &= (digit == 0); if (digit > 9) { carry = 1; digit -= 10; @@ -2194,6 +2197,7 @@ static void bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid, } *overflow = carry; + return is_zero; } static void bcd_sub_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid, @@ -2225,14 +2229,15 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) int sgnb = bcd_get_sgn(b); int invalid = (sgna == 0) || (sgnb == 0); int overflow = 0; + int zero = 0; uint32_t cr = 0; ppc_avr_t result = { .u64 = { 0, 0 } }; if (!invalid) { if (sgna == sgnb) { result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps); - bcd_add_mag(&result, a, b, &invalid, &overflow); - cr = bcd_cmp_zero(&result); + zero = bcd_add_mag(&result, a, b, &invalid, &overflow); + cr = (sgna > 0) ? CRF_GT : CRF_LT; } else { int magnitude = bcd_cmp_mag(a, b); if (magnitude > 0) { @@ -2255,6 +2260,8 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) cr = CRF_SO; } else if (overflow) { cr |= CRF_SO; + } else if (zero) { + cr |= CRF_EQ; } *r = result; diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh index 36b8a73a54..ce304f4933 100755 --- a/tests/tcg/configure.sh +++ b/tests/tcg/configure.sh @@ -251,6 +251,12 @@ for target in $target_list; do echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak fi ;; + ppc*) + if do_compiler "$target_compiler" $target_compiler_cflags \ + -mpower8-vector -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_POWER8_VECTOR=y" >> $config_target_mak + fi + ;; esac enabled_cross_compilers="$enabled_cross_compilers $target_compiler" diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target new file mode 100644 index 0000000000..0c6a4585fc --- /dev/null +++ b/tests/tcg/ppc64/Makefile.target @@ -0,0 +1,13 @@ +# -*- Mode: makefile -*- +# +# ppc64 specific tweaks + +VPATH += $(SRC_PATH)/tests/tcg/ppc64 +VPATH += $(SRC_PATH)/tests/tcg/ppc64le + +ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER8_VECTOR),) +PPC64_TESTS=bcdsub +endif +bcdsub: CFLAGS += -mpower8-vector + +TESTS += $(PPC64_TESTS) diff --git a/tests/tcg/ppc64le/Makefile.target b/tests/tcg/ppc64le/Makefile.target new file mode 100644 index 0000000000..1acfcff94a --- /dev/null +++ b/tests/tcg/ppc64le/Makefile.target @@ -0,0 +1,12 @@ +# -*- Mode: makefile -*- +# +# ppc64le specific tweaks + +VPATH += $(SRC_PATH)/tests/tcg/ppc64le + +ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER8_VECTOR),) +PPC64LE_TESTS=bcdsub +endif +bcdsub: CFLAGS += -mpower8-vector + +TESTS += $(PPC64LE_TESTS) diff --git a/tests/tcg/ppc64le/bcdsub.c b/tests/tcg/ppc64le/bcdsub.c new file mode 100644 index 0000000000..8c188cae6d --- /dev/null +++ b/tests/tcg/ppc64le/bcdsub.c @@ -0,0 +1,130 @@ +#include +#include +#include + +#define CRF_LT (1 << 3) +#define CRF_GT (1 << 2) +#define CRF_EQ (1 << 1) +#define CRF_SO (1 << 0) +#define UNDEF 0 + +#define BCDSUB(vra, vrb, ps) \ + asm ("bcdsub. %1,%2,%3,%4;" \ + "mfocrf %0,0b10;" \ + : "=r" (cr), "=v" (vrt) \ + : "v" (vra), "v" (vrb), "i" (ps) \ + : ); + +#define TEST(vra, vrb, ps, exp_res, exp_cr6) \ + do { \ + __int128 vrt = 0; \ + int cr = 0; \ + BCDSUB(vra, vrb, ps); \ + if (exp_res) \ + assert(vrt == exp_res); \ + assert((cr >> 4) == exp_cr6); \ + } while (0) + + +/* + * Unbounded result is equal to zero: + * sign = (PS) ? 0b1111 : 0b1100 + * CR6 = 0b0010 + */ +void test_bcdsub_eq(void) +{ + __int128 a, b; + + /* maximum positive BCD value */ + a = b = (((__int128) 0x9999999999999999) << 64 | 0x999999999999999c); + + TEST(a, b, 0, 0xc, CRF_EQ); + TEST(a, b, 1, 0xf, CRF_EQ); +} + +/* + * Unbounded result is greater than zero: + * sign = (PS) ? 0b1111 : 0b1100 + * CR6 = (overflow) ? 0b0101 : 0b0100 + */ +void test_bcdsub_gt(void) +{ + __int128 a, b, c; + + /* maximum positive BCD value */ + a = (((__int128) 0x9999999999999999) << 64 | 0x999999999999999c); + + /* negative one BCD value */ + b = (__int128) 0x1d; + + TEST(a, b, 0, 0xc, (CRF_GT | CRF_SO)); + TEST(a, b, 1, 0xf, (CRF_GT | CRF_SO)); + + c = (((__int128) 0x9999999999999999) << 64 | 0x999999999999998c); + + TEST(c, b, 0, a, CRF_GT); + TEST(c, b, 1, (a | 0x3), CRF_GT); +} + +/* + * Unbounded result is less than zero: + * sign = 0b1101 + * CR6 = (overflow) ? 0b1001 : 0b1000 + */ +void test_bcdsub_lt(void) +{ + __int128 a, b; + + /* positive zero BCD value */ + a = (__int128) 0xc; + + /* positive one BCD value */ + b = (__int128) 0x1c; + + TEST(a, b, 0, 0x1d, CRF_LT); + TEST(a, b, 1, 0x1d, CRF_LT); + + /* maximum negative BCD value */ + a = (((__int128) 0x9999999999999999) << 64 | 0x999999999999999d); + + /* positive one BCD value */ + b = (__int128) 0x1c; + + TEST(a, b, 0, 0xd, (CRF_LT | CRF_SO)); + TEST(a, b, 1, 0xd, (CRF_LT | CRF_SO)); +} + +void test_bcdsub_invalid(void) +{ + __int128 a, b; + + /* positive one BCD value */ + a = (__int128) 0x1c; + b = 0xf00; + + TEST(a, b, 0, UNDEF, CRF_SO); + TEST(a, b, 1, UNDEF, CRF_SO); + + TEST(b, a, 0, UNDEF, CRF_SO); + TEST(b, a, 1, UNDEF, CRF_SO); + + a = 0xbad; + + TEST(a, b, 0, UNDEF, CRF_SO); + TEST(a, b, 1, UNDEF, CRF_SO); +} + +int main(void) +{ + struct sigaction action; + + action.sa_handler = _exit; + sigaction(SIGABRT, &action, NULL); + + test_bcdsub_eq(); + test_bcdsub_gt(); + test_bcdsub_lt(); + test_bcdsub_invalid(); + + return 0; +} -- cgit v1.2.3-55-g7522 From 51254ffb320183a4636635840c23ee0e3a1efffa Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 22 Feb 2021 16:45:29 -0300 Subject: spapr_drc.c: introduce unplug_timeout_timer The LoPAR spec provides no way for the guest kernel to report failure of hotplug/hotunplug events. This wouldn't be bad if those operations were granted to always succeed, but that's far for the reality. What ends up happening is that, in the case of a failed hotunplug, regardless of whether it was a QEMU error or a guest misbehavior, the pSeries machine is retaining the unplug state of the device in the running guest. This state is cleanup in machine reset, where it is assumed that this state represents a device that is pending unplug, and the device is hotunpluged from the board. Until the reset occurs, any hotunplug operation of the same device is forbid because there is a pending unplug state. This behavior has at least one undesirable side effect. A long standing pending unplug state is, more often than not, the result of a hotunplug error. The user had to dealt with it, since retrying to unplug the device is noy allowed, and then in the machine reset we're removing the device from the guest. This means that we're failing the user twice - failed to hotunplug when asked, then hotunplugged without notice. Solutions to this problem range between trying to predict when the hotunplug will fail and forbid the operation from the QEMU layer, from opening up the IRQ queue to allow for multiple hotunplug attempts, from telling the users to 'reboot the machine if something goes wrong'. The first solution is flawed because we can't fully predict guest behavior from QEMU, the second solution is a trial and error remediation that counts on a hope that the unplug will eventually succeed, and the third is ... well. This patch introduces a crude, but effective solution to hotunplug errors in the pSeries machine. For each unplug done, we'll timeout after some time. If a certain amount of time passes, we'll cleanup the hotunplug state from the machine. During the timeout period, any unplug operations in the same device will still be blocked. After that, we'll assume that the guest failed the operation, and allow the user to try again. If the timeout is too short we'll prevent legitimate hotunplug situations to occur, so we'll need to overestimate the regular time an unplug operation takes to succeed to account that. The true solution for the hotunplug errors in the pSeries machines is a PAPR change to allow for the guest to warn the platform about it. For now, the work done in this timeout design can be used for the new PAPR 'abort hcall' in the future, given that for both cases we'll need code to cleanup the existing unplug states of the DRCs. At this moment we're adding the basic wiring of the timer into the DRC. Next patch will use the timer to timeout failed CPU hotunplugs. Signed-off-by: Daniel Henrique Barboza Message-Id: <20210222194531.62717-4-danielhb413@gmail.com> Signed-off-by: David Gibson --- hw/ppc/spapr_drc.c | 40 ++++++++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr_drc.h | 4 ++++ 2 files changed, 44 insertions(+) diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 67041fb212..27adbc5c30 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -57,6 +57,8 @@ static void spapr_drc_release(SpaprDrc *drc) drck->release(drc->dev); drc->unplug_requested = false; + timer_del(drc->unplug_timeout_timer); + g_free(drc->fdt); drc->fdt = NULL; drc->fdt_start_offset = 0; @@ -370,6 +372,17 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, } while (fdt_depth != 0); } +static void spapr_drc_start_unplug_timeout_timer(SpaprDrc *drc) +{ + SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + + if (drck->unplug_timeout_seconds != 0) { + timer_mod(drc->unplug_timeout_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + drck->unplug_timeout_seconds * 1000); + } +} + void spapr_drc_attach(SpaprDrc *drc, DeviceState *d) { trace_spapr_drc_attach(spapr_drc_index(drc)); @@ -475,11 +488,23 @@ static bool spapr_drc_needed(void *opaque) spapr_drc_unplug_requested(drc); } +static int spapr_drc_post_load(void *opaque, int version_id) +{ + SpaprDrc *drc = opaque; + + if (drc->unplug_requested) { + spapr_drc_start_unplug_timeout_timer(drc); + } + + return 0; +} + static const VMStateDescription vmstate_spapr_drc = { .name = "spapr_drc", .version_id = 1, .minimum_version_id = 1, .needed = spapr_drc_needed, + .post_load = spapr_drc_post_load, .fields = (VMStateField []) { VMSTATE_UINT32(state, SpaprDrc), VMSTATE_END_OF_LIST() @@ -490,6 +515,15 @@ static const VMStateDescription vmstate_spapr_drc = { } }; +static void drc_unplug_timeout_cb(void *opaque) +{ + SpaprDrc *drc = opaque; + + if (drc->unplug_requested) { + drc->unplug_requested = false; + } +} + static void drc_realize(DeviceState *d, Error **errp) { SpaprDrc *drc = SPAPR_DR_CONNECTOR(d); @@ -512,6 +546,11 @@ static void drc_realize(DeviceState *d, Error **errp) object_property_add_alias(root_container, link_name, drc->owner, child_name); g_free(link_name); + + drc->unplug_timeout_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, + drc_unplug_timeout_cb, + drc); + vmstate_register(VMSTATE_IF(drc), spapr_drc_index(drc), &vmstate_spapr_drc, drc); trace_spapr_drc_realize_complete(spapr_drc_index(drc)); @@ -529,6 +568,7 @@ static void drc_unrealize(DeviceState *d) name = g_strdup_printf("%x", spapr_drc_index(drc)); object_property_del(root_container, name); g_free(name); + timer_free(drc->unplug_timeout_timer); } SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type, diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h index 02a63b3666..38ec4c8091 100644 --- a/include/hw/ppc/spapr_drc.h +++ b/include/hw/ppc/spapr_drc.h @@ -187,6 +187,8 @@ typedef struct SpaprDrc { bool unplug_requested; void *fdt; int fdt_start_offset; + + QEMUTimer *unplug_timeout_timer; } SpaprDrc; struct SpaprMachineState; @@ -209,6 +211,8 @@ typedef struct SpaprDrcClass { int (*dt_populate)(SpaprDrc *drc, struct SpaprMachineState *spapr, void *fdt, int *fdt_start_offset, Error **errp); + + int unplug_timeout_seconds; } SpaprDrcClass; typedef struct SpaprDrcPhysical { -- cgit v1.2.3-55-g7522 From d1c2e3ce3d5a5424651967bce1cf1f4caa0c6d91 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 22 Feb 2021 16:45:30 -0300 Subject: spapr_drc.c: add hotunplug timeout for CPUs There is a reliable way to make a CPU hotunplug fail in the pseries machine. Hotplug a CPU A, then offline all other CPUs inside the guest but A. When trying to hotunplug A the guest kernel will refuse to do it, because A is now the last online CPU of the guest. PAPR has no 'error callback' in this situation to report back to the platform, so the guest kernel will deny the unplug in silent and QEMU will never know what happened. The unplug pending state of A will remain until the guest is shutdown or rebooted. Previous attempts of fixing it (see [1] and [2]) were aimed at trying to mitigate the effects of the problem. In [1] we were trying to guess which guest CPUs were online to forbid hotunplug of the last online CPU in the QEMU layer, avoiding the scenario described above because QEMU is now failing in behalf of the guest. This is not robust because the last online CPU of the guest can change while we're in the middle of the unplug process, and our initial assumptions are now invalid. In [2] we were accepting that our unplug process is uncertain and the user should be allowed to spam the IRQ hotunplug queue of the guest in case the CPU hotunplug fails. This patch presents another alternative, using the timeout infrastructure introduced in the previous patch. CPU hotunplugs in the pSeries machine will now timeout after 15 seconds. This is a long time for a single CPU unplug to occur, regardless of guest load - although the user is *strongly* encouraged to *not* hotunplug devices from a guest under high load - and we can be sure that something went wrong if it takes longer than that for the guest to release the CPU (the same can't be said about memory hotunplug - more on that in the next patch). Timing out the unplug operation will reset the unplug state of the CPU and allow the user to try it again, regardless of the error situation that prevented the hotunplug to occur. Of all the not so pretty fixes/mitigations for CPU hotunplug errors in pSeries, timing out the operation is an admission that we have no control in the process, and must assume the worst case if the operation doesn't succeed in a sensible time frame. [1] https://lists.gnu.org/archive/html/qemu-devel/2021-01/msg03353.html [2] https://lists.gnu.org/archive/html/qemu-devel/2021-01/msg04400.html Reported-by: Xujun Ma Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1911414 Reviewed-by: David Gibson Signed-off-by: Daniel Henrique Barboza Message-Id: <20210222194531.62717-5-danielhb413@gmail.com> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 4 ++++ hw/ppc/spapr_drc.c | 13 +++++++++++++ include/hw/ppc/spapr_drc.h | 1 + 3 files changed, 18 insertions(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index b066df68cb..ecce8abf14 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3724,6 +3724,10 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, if (!spapr_drc_unplug_requested(drc)) { spapr_drc_unplug_request(drc); spapr_hotplug_req_remove_by_index(drc); + } else { + error_setg(errp, "core-id %d unplug is still pending, %d seconds " + "timeout remaining", + cc->core_id, spapr_drc_unplug_timeout_remaining_sec(drc)); } } diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 27adbc5c30..fd2e45640f 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -409,6 +409,8 @@ void spapr_drc_unplug_request(SpaprDrc *drc) drc->unplug_requested = true; + spapr_drc_start_unplug_timeout_timer(drc); + if (drc->state != drck->empty_state) { trace_spapr_drc_awaiting_quiesce(spapr_drc_index(drc)); return; @@ -417,6 +419,16 @@ void spapr_drc_unplug_request(SpaprDrc *drc) spapr_drc_release(drc); } +int spapr_drc_unplug_timeout_remaining_sec(SpaprDrc *drc) +{ + if (drc->unplug_requested && timer_pending(drc->unplug_timeout_timer)) { + return (qemu_timeout_ns_to_ms(drc->unplug_timeout_timer->expire_time) - + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)) / 1000; + } + + return 0; +} + bool spapr_drc_reset(SpaprDrc *drc) { SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); @@ -710,6 +722,7 @@ static void spapr_drc_cpu_class_init(ObjectClass *k, void *data) drck->drc_name_prefix = "CPU "; drck->release = spapr_core_release; drck->dt_populate = spapr_core_dt_populate; + drck->unplug_timeout_seconds = 15; } static void spapr_drc_pci_class_init(ObjectClass *k, void *data) diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h index 38ec4c8091..26599c385a 100644 --- a/include/hw/ppc/spapr_drc.h +++ b/include/hw/ppc/spapr_drc.h @@ -248,6 +248,7 @@ int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask); */ void spapr_drc_attach(SpaprDrc *drc, DeviceState *d); void spapr_drc_unplug_request(SpaprDrc *drc); +int spapr_drc_unplug_timeout_remaining_sec(SpaprDrc *drc); /* * Reset all DRCs, causing pending hot-plug/unplug requests to complete. -- cgit v1.2.3-55-g7522 From fe1831eff8a41e96044fe98a6b0e232daa22ef83 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 22 Feb 2021 16:45:31 -0300 Subject: spapr_drc.c: use DRC reconfiguration to cleanup DIMM unplug state Handling errors in memory hotunplug in the pSeries machine is more complex than any other device type, because there are all the complications that other devices has, and more. For instance, determining a timeout for a DIMM hotunplug must consider if it's a Hash-MMU or a Radix-MMU guest, because Hash guests takes longer to hotunplug DIMMs. The size of the DIMM is also a factor, given that longer DIMMs naturally takes longer to be hotunplugged from the kernel. And there's also the guest memory usage to be considered: if there's a process that is consuming memory that would be lost by the DIMM unplug, the kernel will postpone the unplug process until the process finishes, and then initiate the regular hotunplug process. The first two considerations are manageable, but the last one is a deal breaker. There is no sane way for the pSeries machine to determine the memory load in the guest when attempting a DIMM hotunplug - and even if there was a way, the guest can start using all the RAM in the middle of the unplug process and invalidate our previous assumptions - and in result we can't even begin to calculate a timeout for the operation. This means that we can't implement a viable timeout mechanism for memory unplug in pSeries. Going back to why we would consider an unplug timeout, the reason is that we can't know if the kernel is giving up the unplug. Turns out that, sometimes, we can. Consider a failed memory hotunplug attempt where the kernel will error out with the following message: 'pseries-hotplug-mem: Memory indexed-count-remove failed, adding any removed LMBs' This happens when there is a LMB that the kernel gave up in removing, and the LMBs previously marked for removal are now being added back. This happens in the pseries kernel in [1], dlpar_memory_remove_by_ic() into dlpar_add_lmb(), and after that update_lmb_associativity_index(). In this function, the kernel is configuring the LMB DRC connector again. Note that this is a valid usage in LOPAR, as stated in section "ibm,configure-connector RTAS Call": 'A subsequent sequence of calls to ibm,configure-connector with the same entry from the “ibm,drc-indexes” or “ibm,drc-info” property will restart the configuration of devices which were not completely configured.' We can use this kernel behavior in our favor. If a DRC connector reconfiguration for a LMB that we marked as unplug pending happens, this indicates that the kernel changed its mind about the unplug and is reasserting that it will keep using all the LMBs of the DIMM. In this case, it's safe to assume that the whole DIMM device unplug was cancelled. This patch hops into rtas_ibm_configure_connector() and, in the scenario described above, clear the unplug state for the DIMM device. This will not solve all the problems we still have with memory unplug, but it will cover this case where the kernel reconfigures LMBs after a failed unplug. We are a bit more resilient, without using an unreliable timeout, and we didn't make the remaining error cases any worse. [1] arch/powerpc/platforms/pseries/hotplug-memory.c Signed-off-by: Daniel Henrique Barboza Message-Id: <20210222194531.62717-6-danielhb413@gmail.com> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 43 +++++++++++++++++++++++++++++++++++++++++++ hw/ppc/spapr_drc.c | 10 ++++++++++ include/hw/ppc/spapr.h | 2 ++ 3 files changed, 55 insertions(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index ecce8abf14..6eaddb12cb 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3575,6 +3575,49 @@ static SpaprDimmState *spapr_recover_pending_dimm_state(SpaprMachineState *ms, return spapr_pending_dimm_unplugs_add(ms, avail_lmbs, dimm); } +void spapr_clear_pending_dimm_unplug_state(SpaprMachineState *spapr, + DeviceState *dev) +{ + SpaprDimmState *ds; + PCDIMMDevice *dimm; + SpaprDrc *drc; + uint32_t nr_lmbs; + uint64_t size, addr_start, addr; + int i; + + if (!dev) { + return; + } + + dimm = PC_DIMM(dev); + ds = spapr_pending_dimm_unplugs_find(spapr, dimm); + + /* + * 'ds == NULL' would mean that the DIMM doesn't have a pending + * unplug state, but one of its DRC is marked as unplug_requested. + * This is bad and weird enough to g_assert() out. + */ + g_assert(ds); + + spapr_pending_dimm_unplugs_remove(spapr, ds); + + size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort); + nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE; + + addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP, + &error_abort); + + addr = addr_start; + for (i = 0; i < nr_lmbs; i++) { + drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, + addr / SPAPR_MEMORY_BLOCK_SIZE); + g_assert(drc); + + drc->unplug_requested = false; + addr += SPAPR_MEMORY_BLOCK_SIZE; + } +} + /* Callback to be called during DRC release. */ void spapr_lmb_release(DeviceState *dev) { diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index fd2e45640f..8c4997d795 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -1230,6 +1230,16 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu, drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + /* + * This indicates that the kernel is reconfiguring a LMB due to + * a failed hotunplug. Clear the pending unplug state for the whole + * DIMM. + */ + if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_LMB && + drc->unplug_requested) { + spapr_clear_pending_dimm_unplug_state(spapr, drc->dev); + } + if (!drc->fdt) { void *fdt; int fdt_size; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index ccbeeca1de..d6edeaaaff 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -847,6 +847,8 @@ int spapr_hpt_shift_for_ramsize(uint64_t ramsize); int spapr_reallocate_hpt(SpaprMachineState *spapr, int shift, Error **errp); void spapr_clear_pending_events(SpaprMachineState *spapr); void spapr_clear_pending_hotplug_events(SpaprMachineState *spapr); +void spapr_clear_pending_dimm_unplug_state(SpaprMachineState *spapr, + DeviceState *dev); int spapr_max_server_number(SpaprMachineState *spapr); void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex, uint64_t pte0, uint64_t pte1); -- cgit v1.2.3-55-g7522 From f149c9b7f942c56f30e66be034f669b95255474e Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 28 Feb 2021 13:04:31 +0800 Subject: hw/net: fsl_etsec: Fix build error when HEX_DUMP is on "qemu-common.h" should be included to provide the forward declaration of qemu_hexdump() when HEX_DUMP is on. Signed-off-by: Bin Meng Message-Id: <20210228050431.24647-1-bmeng.cn@gmail.com> Signed-off-by: David Gibson --- hw/net/fsl_etsec/etsec.c | 1 + hw/net/fsl_etsec/rings.c | 1 + 2 files changed, 2 insertions(+) diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index 93886bba60..bd9d62b559 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -27,6 +27,7 @@ */ #include "qemu/osdep.h" +#include "qemu-common.h" #include "hw/sysbus.h" #include "hw/irq.h" #include "hw/ptimer.h" diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c index fe055d3381..d6be0d7d18 100644 --- a/hw/net/fsl_etsec/rings.c +++ b/hw/net/fsl_etsec/rings.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "qemu-common.h" #include "net/checksum.h" #include "qemu/log.h" #include "etsec.h" -- cgit v1.2.3-55-g7522 From e5943b00d35efc68ca72ed304cfca98a9f3a647c Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 24 Feb 2021 17:28:39 +0800 Subject: hw/ppc: e500: Add missing in the eTSEC node The eTSEC node should provide an empty property in the eTSEC node, otherwise of_translate_address() in the Linux kernel fails to get the eTSEC register base, reporting: OF: ** translation for device /platform@f00000000/ethernet@0/queue-group ** OF: bus is default (na=1, ns=1) on /platform@f00000000/ethernet@0 OF: translating address: 00000000 OF: parent bus is default (na=1, ns=1) on /platform@f00000000 OF: no ranges; cannot translate Per devicetree spec v0.3 [1] chapter 2.3.8: If the property is not present in a bus node, it is assumed that no mapping exists between children of the node and the parent address space. This is why of_translate_address() aborts the address translation. Apparently U-Boot devicetree parser seems to be tolerant with missing as this was not noticed when testing with U-Boot. The empty property is present in all kernel shipped dtsi files for eTSEC, Let's add it to conform with the spec. [1] https://github.com/devicetree-org/devicetree-specification/releases/download/v0.3/devicetree-specification-v0.3.pdf Fixes: fdfb7f2cdb2d ("e500: Add support for eTSEC in device tree") Signed-off-by: Bin Meng Message-Id: <1614158919-9473-1-git-send-email-bmeng.cn@gmail.com> Signed-off-by: David Gibson --- hw/ppc/e500.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 01517a6c6c..1d94485ac8 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -231,6 +231,7 @@ static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data) assert(irq2 >= 0); qemu_fdt_add_subnode(fdt, node); + qemu_fdt_setprop(fdt, node, "ranges", NULL, 0); qemu_fdt_setprop_string(fdt, node, "device_type", "network"); qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2"); qemu_fdt_setprop_string(fdt, node, "model", "eTSEC"); -- cgit v1.2.3-55-g7522 From 7420033ec460e7b9906bf05fbe1a0d3830536657 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Fri, 26 Feb 2021 13:32:59 -0300 Subject: spapr.c: add 'unplug already in progress' message for PHB unplug Both CPU hotunplug and PC_DIMM unplug reports an user warning, mentioning that the hotunplug is in progress, if consecutive 'device_del' are issued in quick succession. Do the same for PHBs in spapr_phb_unplug_request(). Signed-off-by: Daniel Henrique Barboza Message-Id: <20210226163301.419727-4-danielhb413@gmail.com> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/ppc/spapr.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 6eaddb12cb..aca3ef9d58 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4034,6 +4034,10 @@ static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev, if (!spapr_drc_unplug_requested(drc)) { spapr_drc_unplug_request(drc); spapr_hotplug_req_remove_by_index(drc); + } else { + error_setg(errp, + "PCI Host Bridge unplug already in progress for device %s", + dev->id); } } -- cgit v1.2.3-55-g7522 From e35dfbd22780aafbcd4b6da5130a00fc085fd5de Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Fri, 26 Feb 2021 13:33:00 -0300 Subject: spapr_pci.c: add 'unplug already in progress' message for PCI unplug Hotunplug for all other devices are warning the user when the hotunplug is already in progress. Do the same for PCI devices in spapr_pci_unplug_request(). Signed-off-by: Daniel Henrique Barboza Message-Id: <20210226163301.419727-5-danielhb413@gmail.com> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/ppc/spapr_pci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index b00e9609ae..feba18cb12 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1743,6 +1743,10 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler, } } } + } else { + error_setg(errp, + "PCI device unplug already in progress for device %s", + drc->dev->id); } } -- cgit v1.2.3-55-g7522 From 4515a5f786024fabf0bef4cf3d28adf5647e6e82 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 1 Mar 2021 09:41:33 -0300 Subject: qemu_timer.c: add timer_deadline_ms() helper The pSeries machine is using QEMUTimer internals to return the timeout in seconds for a timer object, in hw/ppc/spapr.c, function spapr_drc_unplug_timeout_remaining_sec(). Create a helper in qemu-timer.c to retrieve the deadline for a QEMUTimer object, in ms, to avoid exposing timer internals to the PPC code. CC: Paolo Bonzini Acked-by: Paolo Bonzini Signed-off-by: Daniel Henrique Barboza Message-Id: <20210301124133.23800-2-danielhb413@gmail.com> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/ppc/spapr_drc.c | 5 ++--- include/qemu/timer.h | 8 ++++++++ util/qemu-timer.c | 13 +++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 8c4997d795..98b626acf9 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -421,9 +421,8 @@ void spapr_drc_unplug_request(SpaprDrc *drc) int spapr_drc_unplug_timeout_remaining_sec(SpaprDrc *drc) { - if (drc->unplug_requested && timer_pending(drc->unplug_timeout_timer)) { - return (qemu_timeout_ns_to_ms(drc->unplug_timeout_timer->expire_time) - - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)) / 1000; + if (drc->unplug_requested) { + return timer_deadline_ms(drc->unplug_timeout_timer) / 1000; } return 0; diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 1678238384..5e76e3f8c2 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -795,6 +795,14 @@ static inline int64_t get_max_clock_jump(void) return 60 * NANOSECONDS_PER_SECOND; } +/** + * timer_deadline_ms: + * + * Returns the remaining miliseconds for @timer to expire, or zero + * if the timer is no longer pending. + */ +int64_t timer_deadline_ms(QEMUTimer *timer); + /* * Low level clock functions */ diff --git a/util/qemu-timer.c b/util/qemu-timer.c index 81c28af517..02424bc1b6 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -243,6 +243,19 @@ int64_t timerlist_deadline_ns(QEMUTimerList *timer_list) return delta; } +/* + * Returns the time remaining for the deadline, in ms. + */ +int64_t timer_deadline_ms(QEMUTimer *timer) +{ + if (timer_pending(timer)) { + return qemu_timeout_ns_to_ms(timer->expire_time) - + qemu_clock_get_ms(timer->timer_list->clock->type); + } + + return 0; +} + /* Calculate the soonest deadline across all timerlists attached * to the clock. This is used for the icount timeout so we * ignore whether or not the clock should be used in deadline -- cgit v1.2.3-55-g7522 From 09db2216aa06be8bacd0101723d9c257f75c803f Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov Date: Wed, 3 Mar 2021 17:08:51 +0300 Subject: target/ppc: fix icount support on Book-e vms accessing SPRs Failing to guard SPR access with gen_io_start/gen_stop_exception causes "Bad icount read" exceptions when running VMs with e500mc and e500v2 CPUs with an icount parameter. Cc: David Gibson Cc: Greg Kurz Cc: Paolo Bonzini Signed-off-by: Vitaly Cheptsov Message-Id: <20210303140851.78383-1-cheptsov@ispras.ru> Signed-off-by: David Gibson --- target/ppc/translate_init.c.inc | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc index e7324e85cd..09c9ae2c98 100644 --- a/target/ppc/translate_init.c.inc +++ b/target/ppc/translate_init.c.inc @@ -567,35 +567,71 @@ static void spr_write_601_ubatl(DisasContext *ctx, int sprn, int gprn) #if !defined(CONFIG_USER_ONLY) static void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_helper_load_40x_pit(cpu_gpr[gprn], cpu_env); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_stop_exception(ctx); + } } static void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_helper_store_40x_pit(cpu_env, cpu_gpr[gprn]); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_stop_exception(ctx); + } } static void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_store_spr(sprn, cpu_gpr[gprn]); gen_helper_store_40x_dbcr0(cpu_env, cpu_gpr[gprn]); /* We must stop translation as we may have rebooted */ gen_stop_exception(ctx); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_stop_exception(ctx); + } } static void spr_write_40x_sler(DisasContext *ctx, int sprn, int gprn) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_helper_store_40x_sler(cpu_env, cpu_gpr[gprn]); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_stop_exception(ctx); + } } static void spr_write_booke_tcr(DisasContext *ctx, int sprn, int gprn) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_helper_store_booke_tcr(cpu_env, cpu_gpr[gprn]); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_stop_exception(ctx); + } } static void spr_write_booke_tsr(DisasContext *ctx, int sprn, int gprn) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_helper_store_booke_tsr(cpu_env, cpu_gpr[gprn]); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_stop_exception(ctx); + } } #endif -- cgit v1.2.3-55-g7522 From 41c8ad3d920d6f1741b34bfdfaa72b43b45209b5 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 2 Mar 2021 11:10:18 -0300 Subject: spapr.c: remove duplicated assert in spapr_memory_unplug_request() We are asserting the existence of the first DRC LMB after sending unplug requests to all LMBs of the DIMM, where every DRC is being asserted inside the loop. This means that the first DRC is being asserted twice. Remove the duplicated assert. Signed-off-by: Daniel Henrique Barboza Message-Id: <20210302141019.153729-2-danielhb413@gmail.com> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index aca3ef9d58..b579830832 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3703,7 +3703,6 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr_start / SPAPR_MEMORY_BLOCK_SIZE); - g_assert(drc); spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB, nr_lmbs, spapr_drc_index(drc)); } -- cgit v1.2.3-55-g7522 From eb7f80fd26d73e7e1af105431da58971b1dba517 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 2 Mar 2021 11:10:19 -0300 Subject: spapr.c: send QAPI event when memory hotunplug fails Recent changes allowed the pSeries machine to rollback the hotunplug process for the DIMM when the guest kernel signals, via a reconfiguration of the DR connector, that it's not going to release the LMBs. Let's also warn QAPI listerners about it. One place to do it would be right after the unplug state is cleaned up, spapr_clear_pending_dimm_unplug_state(). This would mean that the function is now doing more than cleaning up the pending dimm state though. This patch does the following changes in spapr.c: - send a QAPI event to inform that we experienced a failure in the hotunplug of the DIMM; - rename spapr_clear_pending_dimm_unplug_state() to spapr_memory_unplug_rollback(). This is a better fit for what the function is now doing, and it makes callers care more about what the function goal is and less about spapr.c internals such as clearing the pending dimm unplug state. Reviewed-by: Greg Kurz Signed-off-by: Daniel Henrique Barboza Message-Id: <20210302141019.153729-3-danielhb413@gmail.com> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 13 +++++++++++-- hw/ppc/spapr_drc.c | 5 ++--- include/hw/ppc/spapr.h | 3 +-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index b579830832..d56418ca29 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -28,6 +28,7 @@ #include "qemu-common.h" #include "qemu/datadir.h" #include "qapi/error.h" +#include "qapi/qapi-events-machine.h" #include "qapi/visitor.h" #include "sysemu/sysemu.h" #include "sysemu/hostmem.h" @@ -3575,14 +3576,14 @@ static SpaprDimmState *spapr_recover_pending_dimm_state(SpaprMachineState *ms, return spapr_pending_dimm_unplugs_add(ms, avail_lmbs, dimm); } -void spapr_clear_pending_dimm_unplug_state(SpaprMachineState *spapr, - DeviceState *dev) +void spapr_memory_unplug_rollback(SpaprMachineState *spapr, DeviceState *dev) { SpaprDimmState *ds; PCDIMMDevice *dimm; SpaprDrc *drc; uint32_t nr_lmbs; uint64_t size, addr_start, addr; + g_autofree char *qapi_error = NULL; int i; if (!dev) { @@ -3616,6 +3617,14 @@ void spapr_clear_pending_dimm_unplug_state(SpaprMachineState *spapr, drc->unplug_requested = false; addr += SPAPR_MEMORY_BLOCK_SIZE; } + + /* + * Tell QAPI that something happened and the memory + * hotunplug wasn't successful. + */ + qapi_error = g_strdup_printf("Memory hotunplug rejected by the guest " + "for device %s", dev->id); + qapi_event_send_mem_unplug_error(dev->id, qapi_error); } /* Callback to be called during DRC release. */ diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 98b626acf9..8a71b03800 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -1231,12 +1231,11 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu, /* * This indicates that the kernel is reconfiguring a LMB due to - * a failed hotunplug. Clear the pending unplug state for the whole - * DIMM. + * a failed hotunplug. Rollback the DIMM unplug process. */ if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_LMB && drc->unplug_requested) { - spapr_clear_pending_dimm_unplug_state(spapr, drc->dev); + spapr_memory_unplug_rollback(spapr, drc->dev); } if (!drc->fdt) { diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index d6edeaaaff..47cebaf3ac 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -847,8 +847,7 @@ int spapr_hpt_shift_for_ramsize(uint64_t ramsize); int spapr_reallocate_hpt(SpaprMachineState *spapr, int shift, Error **errp); void spapr_clear_pending_events(SpaprMachineState *spapr); void spapr_clear_pending_hotplug_events(SpaprMachineState *spapr); -void spapr_clear_pending_dimm_unplug_state(SpaprMachineState *spapr, - DeviceState *dev); +void spapr_memory_unplug_rollback(SpaprMachineState *spapr, DeviceState *dev); int spapr_max_server_number(SpaprMachineState *spapr); void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex, uint64_t pte0, uint64_t pte1); -- cgit v1.2.3-55-g7522