[Skiboot] [PATCH v2 6/6] platforms/astbmc/witherspoon: Implement OpenCAPI support
Frederic Barrat
fbarrat at linux.ibm.com
Thu Aug 30 02:55:18 AEST 2018
Le 27/08/2018 à 10:55, Andrew Donnellan a écrit :
> OpenCAPI on Witherspoon is slightly more involved than on Zaius and ZZ, due
> to the OpenCAPI links using the SXM2 connectors that are used for NVLink
> GPUs.
>
> This patch adds the regular OpenCAPI platform information, and also a
> Witherspoon-specific presence detection callback that uses the previously
> added OCC GPU presence detection to figure out the device types plugged
> into each SXM2 socket.
>
> The SXM2 connectors are capable of carrying 2 OpenCAPI links, and future
> OpenCAPI devices are expected to make use of this. However, we don't yet
> support ganged links and the various implications that has for handling
> things like device reset, so for now, we only enable 1 brick per device.
>
> Signed-off-by: Andrew Donnellan <andrew.donnellan at au1.ibm.com>
>
> ---
> v1->v2:
> - update platform field names
> ---
> platforms/astbmc/witherspoon.c | 216 +++++++++++++++++++++++++++++++++-
> 1 file changed, 213 insertions(+), 3 deletions(-)
>
> diff --git a/platforms/astbmc/witherspoon.c b/platforms/astbmc/witherspoon.c
> index ce83ff9701d3..2d9cccb63def 100644
> --- a/platforms/astbmc/witherspoon.c
> +++ b/platforms/astbmc/witherspoon.c
> @@ -28,10 +28,18 @@
> #include <pci-slot.h>
> #include <phb4.h>
> #include <npu2.h>
> +#include <occ.h>
> +#include <i2c.h>
>
> #include "astbmc.h"
> #include "ast.h"
>
> +static enum {
> + WITHERSPOON_TYPE_UNKNOWN,
> + WITHERSPOON_TYPE_SEQUOIA,
> + WITHERSPOON_TYPE_REDBUD
> +} witherspoon_type;
> +
> /*
> * HACK: Hostboot doesn't export the correct data for the system VPD EEPROM
> * for this system. So we need to work around it here.
> @@ -50,8 +58,35 @@ static void vpd_dt_fixup(void)
> }
> }
>
> +static void witherspoon_create_ocapi_i2c_bus(void)
> +{
> + struct dt_node *xscom, *i2cm, *i2c_bus;
> + prlog(PR_DEBUG, "OCAPI: Adding I2C bus device node for OCAPI reset\n");
> + dt_for_each_compatible(dt_root, xscom, "ibm,xscom") {
> + i2cm = dt_find_by_name(xscom, "i2cm at a1000");
> + if (!i2cm) {
> + prlog(PR_ERR, "OCAPI: Failed to add I2C bus device node\n");
> + continue;
> + }
> +
> + if (dt_find_by_name(i2cm, "i2c-bus at 4"))
> + continue;
> +
> + i2c_bus = dt_new_addr(i2cm, "i2c-bus", 4);
> + dt_add_property_cells(i2c_bus, "reg", 4);
> + dt_add_property_cells(i2c_bus, "bus-frequency", 0x61a80);
> + dt_add_property_strings(i2c_bus, "compatible",
> + "ibm,opal-i2c", "ibm,power8-i2c-port",
> + "ibm,power9-i2c-port");
> + }
> +}
> +
> static bool witherspoon_probe(void)
> {
> + struct dt_node *np;
> + int highest_gpu_group_id = 0;
> + int gpu_group_id;
> +
> if (!dt_node_is_compatible(dt_root, "ibm,witherspoon"))
> return false;
>
> @@ -63,6 +98,26 @@ static bool witherspoon_probe(void)
>
> vpd_dt_fixup();
>
> + witherspoon_create_ocapi_i2c_bus();
> +
> + dt_for_each_compatible(dt_root, np, "ibm,npu-link") {
> + gpu_group_id = dt_prop_get_u32(np, "ibm,npu-group-id");
> + if (gpu_group_id > highest_gpu_group_id)
> + highest_gpu_group_id = gpu_group_id;
> + };
> +
> + switch (highest_gpu_group_id) {
> + case 1:
> + witherspoon_type = WITHERSPOON_TYPE_REDBUD;
> + break;
> + case 2:
> + witherspoon_type = WITHERSPOON_TYPE_SEQUOIA;
> + break;
> + default:
> + witherspoon_type = WITHERSPOON_TYPE_UNKNOWN;
> + prlog(PR_NOTICE, "PLAT: Unknown Witherspoon variant detected\n");
> + }
> +
Good find!
> return true;
> }
>
> @@ -154,14 +209,168 @@ static void witherspoon_pre_pci_fixup(void)
> phb4_pre_pci_fixup_witherspoon();
> }
>
> -static void witherspoon_npu2_device_detect(struct npu2 *npu)
> +static struct npu2_dev *find_link_index(struct npu2 *npu, uint32_t link_index)
> {
> - /* Stub until we implement real device detection */
> for (int i = 0; i < npu->total_devices; i++) {
> - npu->devices[i].type = NPU2_DEV_TYPE_NVLINK;
> + if (npu->devices[i].link_index == link_index)
> + return &npu->devices[i];
> }
> + prlog(PR_ERR, "PLAT: Could not find NPU link index %d\n", link_index);
> + return NULL;
> }
>
> +static void witherspoon_npu2_device_detect(struct npu2 *npu)
> +{
> + struct proc_chip *chip;
> + struct npu2_dev *dev;
> + uint8_t state;
> + uint64_t i2c_port_id = 0;
> + char port_name[17];
> + struct dt_node *dn;
> + int rc;
> +
> + bool gpu0_present, gpu1_present;
> +
> + if (witherspoon_type != WITHERSPOON_TYPE_REDBUD) {
> + prlog(PR_DEBUG, "PLAT: Setting all NPU links to NVLink, OpenCAPI only supported on Redbud\n");
> + for (int i = 0; i < npu->total_devices; i++) {
> + npu->devices[i].type = NPU2_DEV_TYPE_NVLINK;
> + }
> + return;
> + }
> + assert(npu->total_devices == 6);
> +
> + chip = get_chip(npu->chip_id);
> +
> + /* Find I2C port */
> + snprintf(port_name, sizeof(port_name), "p8_%08x_e%dp%d",
> + chip->id, platform.ocapi->i2c_engine,
> + platform.ocapi->i2c_port);
> + dt_for_each_compatible(dt_root, dn, "ibm,power9-i2c-port") {
> + if (streq(port_name, dt_prop_get(dn, "ibm,port-name"))) {
> + i2c_port_id = dt_prop_get_u32(dn, "ibm,opal-id");
> + break;
> + }
> + }
> +
> + if (!i2c_port_id) {
> + prlog(PR_ERR, "PLAT: Could not find NPU presence I2C port\n");
> + return;
> + }
> +
> + gpu0_present = occ_get_gpu_presence(chip, 0);
> + if (gpu0_present) {
> + prlog(PR_DEBUG, "PLAT: Chip %d GPU#0 slot present\n", chip->id);
> + }
> +
> + gpu1_present = occ_get_gpu_presence(chip, 1);
> + if (gpu1_present) {
> + prlog(PR_DEBUG, "PLAT: Chip %d GPU#1 slot present\n", chip->id);
> + }
> +
> + /* Set pins to input */
> + state = 0xff;
> + rc = i2c_request_send(i2c_port_id,
> + platform.ocapi->i2c_presence_addr, SMBUS_WRITE, 3,
> + 1, &state, 1, 120);
> + if (rc)
> + goto i2c_failed;
> +
> + /* Read the presence value */
> + state = 0x00;
> + rc = i2c_request_send(i2c_port_id,
> + platform.ocapi->i2c_presence_addr, SMBUS_READ, 0,
> + 1, &state, 1, 120);
> + if (rc)
> + goto i2c_failed;
> +
> + if (gpu0_present) {
> + if (state & (1 << 0)) {
> + prlog(PR_DEBUG, "PLAT: Chip %d GPU#0 is OpenCAPI\n",
> + chip->id);
> + /*
> + * On witherspoon, bricks 2 and 3 are connected to
> + * the lanes matching links 1 and 0 in OpenCAPI mode.
> + */
> + dev = find_link_index(npu, 0);
> + if (dev) {
> + dev->type = NPU2_DEV_TYPE_OPENCAPI;
> + dev->brick_index = 3;
> + }
> +
> + dev = find_link_index(npu, 1);
> + if (dev) {
> + /* dev->type = NPU2_DEV_TYPE_OPENCAPI; */
> + /* We current don't support using the second link */
> + dev->type = NPU2_DEV_TYPE_UNKNOWN;
> + dev->brick_index = 2;
> + }
> + } else {
> + prlog(PR_DEBUG, "PLAT: Chip %d GPU#0 is NVLink\n",
> + chip->id);
> + dev = find_link_index(npu, 0);
> + if (dev)
> + dev->type = NPU2_DEV_TYPE_NVLINK;
> + dev = find_link_index(npu, 1);
> + if (dev)
> + dev->type = NPU2_DEV_TYPE_NVLINK;
> + dev = find_link_index(npu, 2);
> + if (dev)
> + dev->type = NPU2_DEV_TYPE_NVLINK;
> + }
> + }
> +
> + if (gpu1_present) {
> + if (state & (1 << 1)) {
> + prlog(PR_DEBUG, "PLAT: Chip %d GPU#1 is OpenCAPI\n",
> + chip->id);
> + dev = find_link_index(npu, 4);
> + if (dev)
> + dev->type = NPU2_DEV_TYPE_OPENCAPI;
> + dev = find_link_index(npu, 5);
> + if (dev)
> + /* dev->type = NPU2_DEV_TYPE_OPENCAPI; */
> + /* We current don't support using the second link */
> + dev->type = NPU2_DEV_TYPE_UNKNOWN;
> + } else {
> + prlog(PR_DEBUG, "PLAT: Chip %d GPU#1 is NVLink\n",
> + chip->id);
> + dev = find_link_index(npu, 3);
> + if (dev)
> + dev->type = NPU2_DEV_TYPE_NVLINK;
> + dev = find_link_index(npu, 4);
> + if (dev)
> + dev->type = NPU2_DEV_TYPE_NVLINK;
> + dev = find_link_index(npu, 5);
> + if (dev)
> + dev->type = NPU2_DEV_TYPE_NVLINK;
> + }
> + }
Do we need some sort of set_link_type() helper function?
> + return;
> +
> +i2c_failed:
> + prlog(PR_ERR, "PLAT: NPU device type detection failed, rc=%d\n", rc);
> + return;
> +}
> +
> +const struct platform_ocapi witherspoon_ocapi = {
> + .i2c_engine = 1,
> + .i2c_port = 4,
> + .odl_phy_swap = false,
> + .i2c_reset_addr = 0x20,
> + .i2c_reset_brick2 = 1 << 0,
> + .i2c_reset_brick3 = 1 << 0,
> + .i2c_reset_brick4 = 1 << 1,
> + .i2c_reset_brick5 = 1 << 1,
A comment explaining why it's not as wrong as it looks at first could be
useful :-) It's in the commit message, but will be lost to whoever reads
this.
Overall the full series look pretty good to me!
Fred
> + .i2c_presence_addr = 0x20,
> + /* unused, we do this in custom presence detect */
> + .i2c_presence_brick2 = 0,
> + .i2c_presence_brick3 = 0,
> + .i2c_presence_brick4 = 0,
> + .i2c_presence_brick5 = 0,
> +};
> +
> /* The only difference between these is the PCI slot handling */
>
> DECLARE_PLATFORM(witherspoon) = {
> @@ -179,5 +388,6 @@ DECLARE_PLATFORM(witherspoon) = {
> .terminate = ipmi_terminate,
>
> .pci_get_slot_info = dt_slot_get_slot_info,
> + .ocapi = &witherspoon_ocapi,
> .npu2_device_detect = witherspoon_npu2_device_detect,
> };
>
More information about the Skiboot
mailing list