From patchwork Tue Aug 22 08:15:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver O'Halloran X-Patchwork-Id: 804332 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xc3kk1v3Sz9sNd for ; Tue, 22 Aug 2017 18:34:22 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="NsNf9iMW"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3xc3kk0q9fzDrJR for ; Tue, 22 Aug 2017 18:34:22 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="NsNf9iMW"; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from mail-pg0-x243.google.com (mail-pg0-x243.google.com [IPv6:2607:f8b0:400e:c05::243]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3xc3KY3WnqzDqTy for ; Tue, 22 Aug 2017 18:16:01 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="NsNf9iMW"; dkim-atps=neutral Received: by mail-pg0-x243.google.com with SMTP id y129so26801246pgy.3 for ; Tue, 22 Aug 2017 01:16:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=J9lM+7uWKxXIJ3zTroLER7AhSjA0s2dkntsQN4nXI34=; b=NsNf9iMWqK26CZz0cUIMLJlscyH1YcUQSWh93Qg2+3hkcKP+Ud+wmGr32g533SQb+W PeDw3UwQGWRXW7IFKNLR9Bx95Hxe6LPKcgd9klsqvXbn2AIHF/k1MV0IzwMvnE3sjct7 C8U/ub/k+eAAml5rI+fAYjv7lIxJJXlzM7e/iyZP78DSyiYcAKWcN5rgNAHOYuNOQPtF 9EHeTsqAhAVHr4FhvA14NTtBFSoq7AYAKy51UoeCcRmhDcPcjby8BGCf2/08VTHaDgYT 5QBfsHfJIvR42W5xKFTnMyW58vNLKv65I0zSBD4c3Em0B6VwGLRKF7dLH8VXfjsxvQwV KT3g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=J9lM+7uWKxXIJ3zTroLER7AhSjA0s2dkntsQN4nXI34=; b=gFOnj/hEzEUBciowxdiisYN9BdzvuSDzhImsc7yiMBoFxXfR4hEUrsDRWGkcl8/GcN ziuuukxsHereHiRKsKJA45rDYCFyosVoEkjBqKGDXxyFolCG7V/GTlfD2E6OJkQxhjii 0y55NUEccyj9AAA0/UXuzATkwD+IeDoZFuk302+BqD3K4LzRCCBz/n6QvnYKQl11dPbD T5iDH+04WIbB/Li/hczZOA8lFuNmSV6IuoMLmI9VLCDfkWZJqxv1Au/sbFWNefcO4qzK SuJzVGHRE6Hy6Y3vA6aorDmcy3Px1HFiHsTQe/NMJ1qs7WKq70+p6wdqIbLnPsyWwGFM 2dyw== X-Gm-Message-State: AHYfb5hAFAVrZAAaM/VkCG+tcEmGu8LuaMW8RhnV/o92/sLiPWTcM1Ab ftB+QEpunY13zWL9 X-Received: by 10.99.181.77 with SMTP id u13mr19086612pgo.262.1503389759218; Tue, 22 Aug 2017 01:15:59 -0700 (PDT) Received: from flat-canetoad.ozlabs.ibm.com ([122.99.82.10]) by smtp.gmail.com with ESMTPSA id a22sm24074476pfj.94.2017.08.22.01.15.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 Aug 2017 01:15:58 -0700 (PDT) From: Oliver O'Halloran To: skiboot@lists.ozlabs.org Date: Tue, 22 Aug 2017 18:15:42 +1000 Message-Id: <20170822081543.30506-2-oohall@gmail.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20170822081543.30506-1-oohall@gmail.com> References: <20170822081543.30506-1-oohall@gmail.com> Subject: [Skiboot] [PATCH 2/3] npu: Rework finding the paired PCI devices X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alistair@popple.id.au MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" The NVLink DT nodes and the PCI device node include a phandle to the PCIe slot node that contains the device. We can use that to identify which NVLink and PCIe devices are bound together. This patch reworks the npu-dev <-> gpu-dev binding logic so make use of the new device-tree based PCIe slot information and moves some common functionality out of npu.c and npu2.c into npu-common.c Signed-off-by: Oliver O'Halloran --- hw/Makefile.inc | 2 +- hw/npu-common.c | 123 ++++++++++++++++++++++++++++++++++++++ hw/npu.c | 158 ++++++++++++------------------------------------ hw/npu2.c | 182 ++++++++++++++++---------------------------------------- 4 files changed, 211 insertions(+), 254 deletions(-) create mode 100644 hw/npu-common.c diff --git a/hw/Makefile.inc b/hw/Makefile.inc index 40be37f5b4ef..2c86dc42f91d 100644 --- a/hw/Makefile.inc +++ b/hw/Makefile.inc @@ -7,7 +7,7 @@ HW_OBJS += p7ioc.o p7ioc-inits.o p7ioc-phb.o HW_OBJS += phb3.o sfc-ctrl.o fake-rtc.o bt.o p8-i2c.o prd.o HW_OBJS += dts.o lpc-rtc.o npu.o npu-hw-procedures.o xive.o phb4.o HW_OBJS += fake-nvram.o lpc-mbox.o npu2.o npu2-hw-procedures.o -HW_OBJS += phys-map.o sbe-p9.o capp.o occ-sensor.o +HW_OBJS += phys-map.o sbe-p9.o capp.o occ-sensor.o npu-common.o HW=hw/built-in.o # FIXME hack this for now diff --git a/hw/npu-common.c b/hw/npu-common.c new file mode 100644 index 000000000000..9418f39a9e1f --- /dev/null +++ b/hw/npu-common.c @@ -0,0 +1,123 @@ +/* Copyright 2017 IBM Corp. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct pci_device *npu_find_gpu_dev(struct pci_device *npu_pd) +{ + const char *npu_slot, *gpu_slot; + struct pci_device *pd; + struct phb *phb; + int tmp; + + /* + * We want to find the GPU device with a slot label that matches + * this NPU (virtual PCI) device. + */ + npu_slot = dt_prop_get(npu_pd->dn, "ibm,slot-label"); + if (!npu_slot) { + char *c = dt_get_path(npu_pd->dn); + + prerror("%s has no slot label\n", c); + free(c); + + return NULL; + } + + for_each_phb(phb) { + /* Don't match the device to itself */ + if (npu_pd->phb->opal_id == phb->opal_id) + continue; + + for_each_pci_dev(phb, pd, &tmp) { + /* skip non-nvidia devices */ + if ((pd->vdid & 0xffff) != 0x10de) + continue; + + gpu_slot = dt_prop_get(pd->dn, "ibm,slot-label"); + if (!gpu_slot) { + char *c = dt_get_path(pd->dn); + + prerror("%s has no slot label!\n", c); + free(c); + continue; + } + + if (streq(gpu_slot, npu_slot)) + return pd; + } + } + + return NULL; +} + +static struct lock pci_npu_phandle_lock = LOCK_UNLOCKED; + +/* + * Appends an NPU phandle to the given PCI device node's ibm,npu + * property. We need this since there can be (and usually is) multiple + * links per GPU. + */ +void npu_append_pci_phandle(struct dt_node *dn, u32 phandle) +{ + struct dt_property *pci_npu_phandle_prop; + uint32_t *npu_phandles; + size_t prop_len; + + /* + * Use a lock to make sure no one else has a reference to an + * ibm,npu property (this assumes this is the only function + * that holds a reference to it). + */ + lock(&pci_npu_phandle_lock); + + /* This function shouldn't be called unless ibm,npu exists */ + pci_npu_phandle_prop = (struct dt_property *) + dt_find_property(dn, "ibm,npu"); + + if (!pci_npu_phandle_prop) { + dt_add_property_cells(dn, "ibm,npu", phandle); + unlock(&pci_npu_phandle_lock); + return; + } + + /* Need to append to the properties */ + prop_len = pci_npu_phandle_prop->len; + prop_len += sizeof(*npu_phandles); + dt_resize_property(&pci_npu_phandle_prop, prop_len); + pci_npu_phandle_prop->len = prop_len; + + npu_phandles = (uint32_t *) pci_npu_phandle_prop->prop; + npu_phandles[prop_len/sizeof(*npu_phandles) - 1] = phandle; + + unlock(&pci_npu_phandle_lock); +} diff --git a/hw/npu.c b/hw/npu.c index b113800b9afd..ad44a56000a2 100644 --- a/hw/npu.c +++ b/hw/npu.c @@ -33,6 +33,8 @@ #include #include #include +#include + /* * Terminology: @@ -336,134 +338,48 @@ NPU_CFG_WRITE(8, u8); NPU_CFG_WRITE(16, u16); NPU_CFG_WRITE(32, u32); -static int __npu_dev_bind_pci_dev(struct phb *phb __unused, - struct pci_device *pd, - void *data) -{ - struct npu_dev *dev = data; - struct dt_node *pci_dt_node; - char *pcislot; - - /* Ignore non-nvidia PCI devices */ - if ((pd->vdid & 0xffff) != 0x10de) - return 0; - - /* Find the PCI device's slot location */ - for (pci_dt_node = pd->dn; - pci_dt_node && !dt_find_property(pci_dt_node, "ibm,slot-label"); - pci_dt_node = pci_dt_node->parent); - - if (!pci_dt_node) - return 0; - - pcislot = (char *)dt_prop_get(pci_dt_node, "ibm,slot-label"); - - prlog(PR_DEBUG, "NPU: comparing GPU %s and NPU %s\n", - pcislot, dev->slot_label); - - if (streq(pcislot, dev->slot_label)) - return 1; - - return 0; -} - -static void npu_dev_bind_pci_dev(struct npu_dev *dev) +/* + * Locate the real PCI device targeted by this NVlink by matching devices + * against slots. + */ +static void npu_phb_final_fixup(struct phb *phb) { - struct phb *phb; - uint32_t i; - - if (dev->pd) - return; - - for (i = 0; i < 64; i++) { - if (dev->npu->phb.opal_id == i) - continue; - - phb = pci_get_phb(i); - if (!phb) + struct npu *npu = phb_to_npu(phb); + struct pci_device *npu_pd, *pd; + const char *label; + int tmp; + + for_each_pci_dev(phb, npu_pd, &tmp) { + struct npu_dev *dev = bdfn_to_npu_dev(npu, npu_pd->bdfn); + uint32_t phandle; + + /* copy the slot info from the link@x to the pci node */ + label = dt_prop_get(dev->dt_node, "ibm,slot-label"); + dt_add_property_string(npu_pd->dn, "ibm,slot-label", label); + + phandle = dt_prop_get_u32_def(dev->dt_node, "ibm,pcie-slot", 0); + if (phandle) + dt_add_property_cells(npu_pd->dn, "ibm,pcie-slot", + phandle); + + pd = npu_find_gpu_dev(npu_pd); + if (!pd) { + prerror("%s: No PCI device for NPU device %04x:00:%02x.0 to bind to. If you expect a GPU to be there, this is a problem.\n", + __func__, dev->npu->phb.opal_id, dev->index); continue; - - dev->pd = pci_walk_dev(phb, NULL, __npu_dev_bind_pci_dev, dev); - if (dev->pd) { - dev->phb = phb; - /* Found the device, set the bit in config space */ - PCI_VIRT_CFG_INIT_RO(dev->pvd, VENDOR_CAP_START + - VENDOR_CAP_PCI_DEV_OFFSET, 1, 0x01); - return; } - } - - prlog(PR_INFO, "%s: No PCI device for NPU device %04x:00:%02x.0 to bind to. If you expect a GPU to be there, this is a problem.\n", - __func__, dev->npu->phb.opal_id, dev->index); -} - -static struct lock pci_npu_phandle_lock = LOCK_UNLOCKED; - -/* Appends an NPU phandle to the given PCI device node ibm,npu - * property */ -static void npu_append_pci_phandle(struct dt_node *dn, u32 phandle) -{ - uint32_t *npu_phandles; - struct dt_property *pci_npu_phandle_prop; - size_t prop_len; - - /* Use a lock to make sure no one else has a reference to an - * ibm,npu property (this assumes this is the only function - * that holds a reference to it). */ - lock(&pci_npu_phandle_lock); - - /* This function shouldn't be called unless ibm,npu exists */ - pci_npu_phandle_prop = (struct dt_property *) - dt_require_property(dn, "ibm,npu", -1); - - /* Need to append to the properties */ - prop_len = pci_npu_phandle_prop->len; - prop_len += sizeof(*npu_phandles); - dt_resize_property(&pci_npu_phandle_prop, prop_len); - pci_npu_phandle_prop->len = prop_len; - - npu_phandles = (uint32_t *) pci_npu_phandle_prop->prop; - npu_phandles[prop_len/sizeof(*npu_phandles) - 1] = phandle; - unlock(&pci_npu_phandle_lock); -} - -static int npu_dn_fixup(struct phb *phb, - struct pci_device *pd, - void *data __unused) -{ - struct npu *p = phb_to_npu(phb); - struct npu_dev *dev; - dev = bdfn_to_npu_dev(p, pd->bdfn); - assert(dev); + /* Now bind this nvlink to this GPU */ + dev->phb = pd->phb; + dev->pd = pd; - if (dev->phb || dev->pd) - return 0; + npu_append_pci_phandle(pd->dn, npu_pd->dn->phandle); + dt_add_property_cells(npu_pd->dn, "ibm,gpu", pd->dn->phandle); - /* NPU devices require a slot location to associate with GPUs */ - dev->slot_label = dt_prop_get(pd->dn, "ibm,slot-label"); - - /* Bind the emulated PCI device with the real one, which can't - * be done until the PCI devices are populated. Once the real - * PCI device is identified, we also need fix the device-tree - * for it - */ - npu_dev_bind_pci_dev(dev); - if (dev->phb && dev->pd && dev->pd->dn) { - if (dt_find_property(dev->pd->dn, "ibm,npu")) - npu_append_pci_phandle(dev->pd->dn, pd->dn->phandle); - else - dt_add_property_cells(dev->pd->dn, "ibm,npu", pd->dn->phandle); - - dt_add_property_cells(pd->dn, "ibm,gpu", dev->pd->dn->phandle); + /* Mark the link as in use in cfg space */ + PCI_VIRT_CFG_INIT_RO(dev->pvd, VENDOR_CAP_START + + VENDOR_CAP_PCI_DEV_OFFSET, 1, 0x01); } - - return 0; -} - -static void npu_phb_final_fixup(struct phb *phb) -{ - pci_walk_dev(phb, NULL, npu_dn_fixup, NULL); } static void npu_ioda_init(struct npu *p) diff --git a/hw/npu2.c b/hw/npu2.c index 74e332551085..9f83fd046c4c 100644 --- a/hw/npu2.c +++ b/hw/npu2.c @@ -36,6 +36,7 @@ #include #include #include +#include /* * NPU2 BAR layout definition. We have 3 stacks and each of them @@ -429,95 +430,6 @@ NPU2_CFG_WRITE(8, u8); NPU2_CFG_WRITE(16, u16); NPU2_CFG_WRITE(32, u32); -static int __npu2_dev_bind_pci_dev(struct phb *phb __unused, - struct pci_device *pd, - void *data) -{ - struct npu2_dev *dev = data; - struct dt_node *pci_dt_node; - char *pcislot; - - /* Ignore non-nvidia PCI devices */ - if ((pd->vdid & 0xffff) != 0x10de) - return 0; - - /* Find the PCI device's slot location */ - for (pci_dt_node = pd->dn; - pci_dt_node && !dt_find_property(pci_dt_node, "ibm,slot-label"); - pci_dt_node = pci_dt_node->parent); - - if (!pci_dt_node) - return 0; - - pcislot = (char *)dt_prop_get(pci_dt_node, "ibm,slot-label"); - - prlog(PR_DEBUG, "NPU: comparing GPU %s and NPU %s\n", - pcislot, dev->slot_label); - - if (streq(pcislot, dev->slot_label)) - return 1; - - return 0; -} - -static void npu2_dev_bind_pci_dev(struct npu2_dev *dev) -{ - struct phb *phb; - uint32_t i; - - if (dev->pd) - return; - - for (i = 0; i < 64; i++) { - if (dev->npu->phb.opal_id == i) - continue; - - phb = pci_get_phb(i); - if (!phb) - continue; - - dev->pd = pci_walk_dev(phb, NULL, __npu2_dev_bind_pci_dev, dev); - if (dev->pd) { - dev->phb = phb; - /* Found the device, set the bit in config space */ - npu2_set_link_flag(dev, NPU2_DEV_PCI_LINKED); - return; - } - } - - prlog(PR_INFO, "%s: No PCI device for NPU device %04x:00:%02x.0 to bind to. If you expect a GPU to be there, this is a problem.\n", - __func__, dev->npu->phb.opal_id, dev->index); -} - -static struct lock pci_npu_phandle_lock = LOCK_UNLOCKED; - -static void npu2_append_phandle(struct dt_node *dn, - u32 phandle) -{ - struct dt_property *prop; - uint32_t *npu_phandles; - size_t len; - - /* - * Use a lock to make sure no one else has a reference to an - * ibm,npu property (this assumes this is the only function - * that holds a reference to it) - */ - lock(&pci_npu_phandle_lock); - - /* This function shouldn't be called unless ibm,npu exists */ - prop = (struct dt_property *)dt_require_property(dn, "ibm,npu", -1); - - /* Need to append to the properties */ - len = prop->len + sizeof(*npu_phandles); - dt_resize_property(&prop, len); - prop->len = len; - - npu_phandles = (uint32_t *)prop->prop; - npu_phandles[len / sizeof(*npu_phandles) - 1] = phandle; - unlock(&pci_npu_phandle_lock); -} - static struct dt_node *npu2_create_memory_dn(uint64_t addr, uint64_t size) { struct dt_node *mem; @@ -667,57 +579,63 @@ static int npu2_assign_gmb(struct npu2_dev *ndev) return 0; } -static int npu2_dn_fixup(struct phb *phb, - struct pci_device *pd, - void *data __unused) +/* + * Locate the real PCI device targeted by this NVlink by matching devices + * against slots. + */ +static void npu2_phb_final_fixup(struct phb *phb) { - struct npu2 *p = phb_to_npu2(phb); - struct npu2_dev *dev; + struct npu2 *npu = phb_to_npu2(phb); + struct pci_device *npu_pd, *gpu; + uint32_t phandle; + int tmp; - dev = npu2_bdf_to_dev(p, pd->bdfn); - assert(dev); - if (dev->phb || dev->pd) - return 0; + /* + * For each "pci_virt_device" on the PHB we want to find the probed + * PCI device that matches it. + * + * XXX: Can we have virtual and real devices on a PHB at the same time? + * the virtual config space design seems to preclude it and there could + * be bus numbering conflicts. + * + * actual PCI device and add the node cross references. + */ - npu2_assign_gmb(dev); - npu2_dn_fixup_gmb(pd->dn, dev); - dt_add_property_cells(pd->dn, "ibm,nvlink", dev->dt_node->phandle); + for_each_pci_dev(phb, npu_pd, &tmp) { + struct npu2_dev *dev = npu2_bdf_to_dev(npu, npu_pd->bdfn); - /* NPU devices require a slot location to associate with GPUs */ - dev->slot_label = dt_prop_get_def(pd->dn, "ibm,slot-label", NULL); - if (!dev->slot_label) { - /** - * @fwts-label NPUNoPHBSlotLabel - * @fwts-advice No GPU/NPU slot information was found. - * NVLink2 functionality will not work. - */ - prlog(PR_ERR, "NPU: Cannot find GPU slot information\n"); - return 0; - } + assert(dev); + if (dev->phb || dev->pd) + continue; - /* - * Bind the emulated PCI device with the real one, which can't - * be done until the PCI devices are populated. Once the real - * PCI device is identified, we also need fix the device-tree - * for it - */ - npu2_dev_bind_pci_dev(dev); - if (dev->phb && dev->pd && dev->pd->dn) { - if (dt_find_property(dev->pd->dn, "ibm,npu")) - npu2_append_phandle(dev->pd->dn, pd->dn->phandle); - else - dt_add_property_cells(dev->pd->dn, "ibm,npu", pd->dn->phandle); + npu2_assign_gmb(dev); + npu2_dn_fixup_gmb(npu_pd->dn, dev); - dt_add_property_cells(pd->dn, "ibm,gpu", dev->pd->dn->phandle); - dev->gpu_bdfn = dev->pd->bdfn; - } + /* copy the pcie-slot from the link to the emulated pci */ + phandle = dt_prop_get_u32(dev->dt_node, "ibm,pcie-slot"); + dt_add_property_cells(npu_pd->dn, "ibm,pcie-slot", phandle); - return 0; -} + gpu = npu_find_gpu_dev(npu_pd); + if (!gpu) { + prerror("%s: No PCI device for NPU device %04x:00:%02x.0 to bind to. If you expect a GPU to be there, this is a problem.\n", + __func__, dev->npu->phb.opal_id, dev->index); + continue; + } -static void npu2_phb_final_fixup(struct phb *phb) -{ - pci_walk_dev(phb, NULL, npu2_dn_fixup, NULL); + /* Found the device, set the bit in config space */ + npu2_set_link_flag(dev, NPU2_DEV_PCI_LINKED); + + dt_add_property_cells(npu_pd->dn, "ibm,nvlink", + dev->dt_node->phandle); + + /* Now bind this nvlink to this GPU */ + dev->phb = gpu->phb; + dev->pd = gpu; + dev->gpu_bdfn = gpu->bdfn; + + npu_append_pci_phandle(gpu->dn, npu_pd->dn->phandle); + dt_add_property_cells(npu_pd->dn, "ibm,gpu", gpu->dn->phandle); + } } static void npu2_init_ioda_cache(struct npu2 *p)