From patchwork Thu Aug 20 05:21:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Roese X-Patchwork-Id: 1348164 X-Patchwork-Delegate: daniel.schwierzeck@googlemail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=denx.de header.i=@denx.de header.a=rsa-sha256 header.s=phobos-20191101 header.b=JNn8Czml; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BXChL1ZKqz9sR4 for ; Thu, 20 Aug 2020 15:22:26 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 5D93682294; Thu, 20 Aug 2020 07:22:16 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=denx.de; s=phobos-20191101; t=1597900936; bh=GQW/DRDQ2MAU45E1/lYzyREytpU+kS/dWLiVdZ0gXQs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=JNn8CzmltocQk347ZZ6noQb/C6uuN/6DWs/FN/GD3iff+lyKMDh+dov+CA1YKDQ7g XuN0nZiPvfwD5RHmuSDavnJW3BS5ndKrba8Y7eGhSTVkbcSDVs2djVrAkVvbmJfVU2 LHMLT0Qllc7CDOf5Rr5w4Ydg6Rox0UZcEXL3W38drZC6Wdj2RpNo9py+cmT8rEz1rK Nbg0+4rV3r3Me5w5T1MtZulnAGhL7AylXlOa4qsAk18O1xbLk+y5pDxo8yDF3bEqp6 tT9oas6VO65sjBVQmHmUd73zD4D3YZVEE/kryc3yPENA3n++41dZUehrP5N4A9yX3I NbR8ch9W6H8pQ== Received: by phobos.denx.de (Postfix, from userid 109) id D2CC282262; Thu, 20 Aug 2020 07:22:12 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,KHOP_HELO_FCRDNS, SPF_HELO_NONE,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from mx2.mailbox.org (mx2a.mailbox.org [IPv6:2001:67c:2050:104:0:2:25:2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 843C581B45 for ; Thu, 20 Aug 2020 07:22:10 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=none smtp.mailfrom=sr@denx.de Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:105:465:1:1:0]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by mx2.mailbox.org (Postfix) with ESMTPS id 4F558A1751; Thu, 20 Aug 2020 07:22:10 +0200 (CEST) Received: from smtp1.mailbox.org ([80.241.60.240]) by spamfilter06.heinlein-hosting.de (spamfilter06.heinlein-hosting.de [80.241.56.125]) (amavisd-new, port 10030) with ESMTP id glxHX-Viz_tf; Thu, 20 Aug 2020 07:22:07 +0200 (CEST) From: Stefan Roese To: u-boot@lists.denx.de Cc: daniel.schwierzeck@gmail.com, cchavva@marvell.com, awilliams@marvell.com Subject: [PATCH v1 01/10] mips: octeon: octeon-model.h: Enable inclusion from assembler files Date: Thu, 20 Aug 2020 07:21:55 +0200 Message-Id: <20200820052204.2794174-2-sr@denx.de> In-Reply-To: <20200820052204.2794174-1-sr@denx.de> References: <20200820052204.2794174-1-sr@denx.de> MIME-Version: 1.0 X-MBO-SPAM-Probability: * X-Rspamd-Score: 0.74 / 15.00 / 15.00 X-Rspamd-Queue-Id: 2C71E37F X-Rspamd-UID: 61904c X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean Add the #ifdef __ASSEMBLY__ checks to enable inclusion of this header from assembler files. Signed-off-by: Stefan Roese --- arch/mips/mach-octeon/include/mach/octeon-model.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/mach-octeon/include/mach/octeon-model.h b/arch/mips/mach-octeon/include/mach/octeon-model.h index 209e813a2f..c842f894bf 100644 --- a/arch/mips/mach-octeon/include/mach/octeon-model.h +++ b/arch/mips/mach-octeon/include/mach/octeon-model.h @@ -266,6 +266,8 @@ ))); \ }) +#ifndef __ASSEMBLY__ + #ifndef OCTEON_IS_MODEL static inline int __octeon_is_model_runtime_internal__(u32 model) @@ -314,4 +316,6 @@ static inline u32 cvmx_get_octeon_family(void) return (read_c0_prid() & OCTEON_FAMILY_MASK); } +#endif /* __ASSEMBLY__ */ + #endif /* __OCTEON_MODEL_H__ */ From patchwork Thu Aug 20 05:21:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Roese X-Patchwork-Id: 1348166 X-Patchwork-Delegate: daniel.schwierzeck@googlemail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=denx.de header.i=@denx.de header.a=rsa-sha256 header.s=phobos-20191101 header.b=h5I9R+a4; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BXChn493lz9sR4 for ; Thu, 20 Aug 2020 15:22:49 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id E46FC82259; Thu, 20 Aug 2020 07:22:21 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=denx.de; s=phobos-20191101; t=1597900942; bh=oManEZlBh+y7b5rKJbUaSERsqf+jxgrAg5jwVeK3CvA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=h5I9R+a4LLloIbl0rJOJGkhEurJCGToOwOj+Uu9URdU4NEpd7DzQ/8FmqyCdvFjB8 mlLyfMdXDQIxDB9rN8aFiN8QZxjJaUm3FvhOR8tvNdXtXkPM+R42WcDMWV+cvrwXJh /9B/0LzkHYTvEGQwN20ikTb/WreSDITO4SrOJH5iPXtxXjYDjwOFusfjTEPkTcXKCp FGb568MpeqJHX+ZFlzD1MI4FjI0wIOcd3x3L8PiPONyP0o1UIj1CvvZ0K1NEJ0HRHN 11fCo7RD9d28mKRAuDZZFrFETyXolVHyo4a9oCk0Sww5M2C3IQzzQxDsWy3+02xRj5 e31k63MmD6YBw== Received: by phobos.denx.de (Postfix, from userid 109) id B212182272; Thu, 20 Aug 2020 07:22:15 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mx2.mailbox.org (mx2.mailbox.org [80.241.60.215]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 1742482249 for ; Thu, 20 Aug 2020 07:22:11 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=none smtp.mailfrom=sr@denx.de Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:105:465:1:1:0]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by mx2.mailbox.org (Postfix) with ESMTPS id CF9C5A1427; Thu, 20 Aug 2020 07:22:10 +0200 (CEST) Received: from smtp1.mailbox.org ([80.241.60.240]) by spamfilter05.heinlein-hosting.de (spamfilter05.heinlein-hosting.de [80.241.56.123]) (amavisd-new, port 10030) with ESMTP id UFg93LMknWwy; Thu, 20 Aug 2020 07:22:07 +0200 (CEST) From: Stefan Roese To: u-boot@lists.denx.de Cc: daniel.schwierzeck@gmail.com, cchavva@marvell.com, awilliams@marvell.com Subject: [PATCH v1 02/10] mips: octeon: lowlevel_init.S: Add NMI handling code for SMP Linux booting Date: Thu, 20 Aug 2020 07:21:56 +0200 Message-Id: <20200820052204.2794174-3-sr@denx.de> In-Reply-To: <20200820052204.2794174-1-sr@denx.de> References: <20200820052204.2794174-1-sr@denx.de> MIME-Version: 1.0 X-MBO-SPAM-Probability: * X-Rspamd-Score: 0.74 / 15.00 / 15.00 X-Rspamd-Queue-Id: B7ADE5FE X-Rspamd-UID: 92a9fd X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean This patch adds the necessary lowlevel init code, to enable SMP Linux booting. This code will be used with the platform specific Octeon Linux boot command "bootoctlinux", which starts a configurable number of cores into Linux. Additionally some erratas and lowlevel register initializations are copied from the original Cavium / Marvell U-Boot source code, enabling booting into the Linux kernel. Signed-off-by: Stefan Roese --- arch/mips/mach-octeon/lowlevel_init.S | 76 +++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/arch/mips/mach-octeon/lowlevel_init.S b/arch/mips/mach-octeon/lowlevel_init.S index fa87cb4e34..56d1d2261e 100644 --- a/arch/mips/mach-octeon/lowlevel_init.S +++ b/arch/mips/mach-octeon/lowlevel_init.S @@ -10,10 +10,36 @@ #include #include #include +#include + +#define COP0_CVMCTL_REG $9,7 /* Cavium control */ +#define COP0_CVMMEMCTL_REG $11,7 /* Cavium memory control */ +#define COP0_PROC_ID_REG $15,0 .set noreorder LEAF(lowlevel_init) + + /* Set LMEMSZ in CVMMEMCTL register */ + dmfc0 a0, COP0_CVMMEMCTL_REG + dins a0, zero, 0, 9 + mfc0 a4, COP0_PROC_ID_REG + li a5, OCTEON_CN63XX_PASS1_0 /* Octeon cn63xx pass1 chip id */ + bgt a5, a4, 2f + ori a0, 0x104 /* setup 4 lines of scratch */ + ori a6, a5, 8 /* Octeon cn63xx pass2 chip id */ + bge a4, a6, 2f + nop + li a6, 4 + ins a0, a6, 11, 4 /* Set WBTHRESH=4 as per Core-14752 errata */ +2: + dmtc0 a0, COP0_CVMMEMCTL_REG + + /* Set REPUN bit in CVMCTL register */ + dmfc0 a0, COP0_CVMCTL_REG + ori a0, 1<<14 /* enable fixup of unaligned mem access */ + dmtc0 a0, COP0_CVMCTL_REG + jr ra nop END(lowlevel_init) @@ -67,3 +93,53 @@ __dummy: nop END(mips_mach_early_init) + +LEAF(nmi_bootvector) + + /* + * From Marvell original bootvector setup + */ + mfc0 k0, CP0_STATUS + /* Enable 64-bit addressing, set ERL (should already be set) */ + ori k0, 0x84 + mtc0 k0, CP0_STATUS + /* Core-14345, clear L1 Dcache virtual tags if the core hit an NMI */ + cache 17, 0($0) + + /* + * Needed for Linux kernel booting, otherwise it hangs while + * zero'ing all of CVMSEG + */ + dmfc0 a0, COP0_CVMMEMCTL_REG + dins a0, zero, 0, 9 + ori a0, 0x104 /* setup 4 lines of scratch */ + dmtc0 a0, COP0_CVMMEMCTL_REG + + /* + * Load parameters and entry point + */ + PTR_LA t9, nmi_handler_para + sync + + ld s0, 0x00(t9) + ld a0, 0x08(t9) + ld a1, 0x10(t9) + ld a2, 0x18(t9) + ld a3, 0x20(t9) + + /* Finally jump to entry point (start kernel etc) */ + j s0 + nop + + END(nmi_bootvector) + + /* + * Add here some space for the NMI parameters (entry point and args) + */ + .globl nmi_handler_para +nmi_handler_para: + .dword 0 // entry-point + .dword 0 // arg0 + .dword 0 // arg1 + .dword 0 // arg2 + .dword 0 // arg3 From patchwork Thu Aug 20 05:21:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Roese X-Patchwork-Id: 1348167 X-Patchwork-Delegate: daniel.schwierzeck@googlemail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=denx.de header.i=@denx.de header.a=rsa-sha256 header.s=phobos-20191101 header.b=Vw77AuKv; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BXCj240WLz9sR4 for ; Thu, 20 Aug 2020 15:23:02 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 027ED8228A; Thu, 20 Aug 2020 07:22:23 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=denx.de; s=phobos-20191101; t=1597900943; bh=AKd5yBbRC+4Aklbt3igxypdQdY3/hPXyQu3Oq0NqLKE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=Vw77AuKvGf47+q4yHycjqaEiTTvRwipSwaNJjb5DhK28lL2f9sgIN9YVRfGF90jmP 1rmqUnwyvkGj4epVicdAUvS9ktIpzynYcekjIBuVeJpcsqLrBSHFhKTFmT/oyNr9I+ 8fPJ3RL6JrEtVi5njoRkkLZvHanx6AO8Tr9+0nOJr4UFXXxDXoKKLuBFAF8P48v+K+ M1am5ZHVZxaGPrXRponTD2l9N6MVElEd26vCyTfe0MX7K4Q8BWMo9lxiqxufpRa9+S 2uyYedw6u3669V4pFsksQiUhsChx9h+zvK2Ab5naf5E1Q7lmYn07IHHtvMXr0AEv+t jRkOp5kID/dSQ== Received: by phobos.denx.de (Postfix, from userid 109) id 3758782272; Thu, 20 Aug 2020 07:22:16 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,KHOP_HELO_FCRDNS, SPF_HELO_NONE,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from mx2.mailbox.org (mx2a.mailbox.org [IPv6:2001:67c:2050:104:0:2:25:2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 72FE582258 for ; Thu, 20 Aug 2020 07:22:11 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=none smtp.mailfrom=sr@denx.de Received: from smtp1.mailbox.org (smtp1.mailbox.org [80.241.60.240]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by mx2.mailbox.org (Postfix) with ESMTPS id 47F64A13D0; Thu, 20 Aug 2020 07:22:11 +0200 (CEST) Received: from smtp1.mailbox.org ([80.241.60.240]) by spamfilter03.heinlein-hosting.de (spamfilter03.heinlein-hosting.de [80.241.56.117]) (amavisd-new, port 10030) with ESMTP id uUxb5iWpm4tX; Thu, 20 Aug 2020 07:22:07 +0200 (CEST) From: Stefan Roese To: u-boot@lists.denx.de Cc: daniel.schwierzeck@gmail.com, cchavva@marvell.com, awilliams@marvell.com Subject: [PATCH v1 03/10] mips: octeon: Add header cvmx-regs.h Date: Thu, 20 Aug 2020 07:21:57 +0200 Message-Id: <20200820052204.2794174-4-sr@denx.de> In-Reply-To: <20200820052204.2794174-1-sr@denx.de> References: <20200820052204.2794174-1-sr@denx.de> MIME-Version: 1.0 X-MBO-SPAM-Probability: X-Rspamd-Score: -0.28 / 15.00 / 15.00 X-Rspamd-Queue-Id: 285AA6CF X-Rspamd-UID: 54c1d9 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean From: Aaron Williams This header includes common register defines and accessor functions. Signed-off-by: Aaron Williams Signed-off-by: Stefan Roese --- .../mips/mach-octeon/include/mach/cvmx-regs.h | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-regs.h diff --git a/arch/mips/mach-octeon/include/mach/cvmx-regs.h b/arch/mips/mach-octeon/include/mach/cvmx-regs.h new file mode 100644 index 0000000000..b84fc9fd57 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-regs.h @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2020 Stefan Roese + */ + +#ifndef __CVMX_REGS_H__ +#define __CVMX_REGS_H__ + +#include +#include +#include + +/* General defines */ +#define CVMX_MAX_CORES 48 +/* Maximum # of bits to define core in node */ +#define CVMX_NODE_NO_SHIFT 7 +#define CVMX_NODE_BITS 2 /* Number of bits to define a node */ +#define CVMX_MAX_NODES (1 << CVMX_NODE_BITS) +#define CVMX_NODE_MASK (CVMX_MAX_NODES - 1) +#define CVMX_NODE_IO_SHIFT 36 +#define CVMX_NODE_MEM_SHIFT 40 +#define CVMX_NODE_IO_MASK ((u64)CVMX_NODE_MASK << CVMX_NODE_IO_SHIFT) + +#define CVMX_MIPS_MAX_CORE_BITS 10 /* Maximum # of bits to define cores */ +#define CVMX_MIPS_MAX_CORES (1 << CVMX_MIPS_MAX_CORE_BITS) + +#define MAX_CORE_TADS 8 + +#define CAST_ULL(v) ((unsigned long long)(v)) +#define CASTPTR(type, v) ((type *)(long)(v)) + +/* Regs */ +#define CVMX_CIU_PP_RST 0x0001010000000100ULL +#define CVMX_CIU3_NMI 0x0001010000000160ULL +#define CVMX_CIU_FUSE 0x00010100000001a0ULL +#define CVMX_CIU_NMI 0x0001070000000718ULL + +#define CVMX_MIO_BOOT_LOC_CFGX(x) (0x0001180000000080ULL + ((x) & 1) * 8) +#define MIO_BOOT_LOC_CFG_BASE GENMASK_ULL(27, 3) +#define MIO_BOOT_LOC_CFG_EN BIT_ULL(31) + +#define CVMX_MIO_BOOT_LOC_ADR 0x0001180000000090ULL +#define MIO_BOOT_LOC_ADR_ADR GENMASK_ULL(7, 3) + +#define CVMX_MIO_BOOT_LOC_DAT 0x0001180000000098ULL + +#define CVMX_MIO_FUS_DAT2 0x0001180000001410ULL +#define MIO_FUS_DAT2_NOCRYPTO BIT_ULL(26) +#define MIO_FUS_DAT2_NOMUL BIT_ULL(27) +#define MIO_FUS_DAT2_DORM_CRYPTO BIT_ULL(34) + +#define CVMX_MIO_FUS_RCMD 0x0001180000001500ULL +#define MIO_FUS_RCMD_ADDR GENMASK_ULL(7, 0) +#define MIO_FUS_RCMD_PEND BIT_ULL(12) +#define MIO_FUS_RCMD_DAT GENMASK_ULL(23, 16) + +#define CVMX_RNM_CTL_STATUS 0x0001180040000000ULL +#define RNM_CTL_STATUS_EER_VAL BIT_ULL(9) + +/* turn the variable name into a string */ +#define CVMX_TMP_STR(x) CVMX_TMP_STR2(x) +#define CVMX_TMP_STR2(x) #x + +#define CVMX_RDHWRNV(result, regstr) \ + asm volatile ("rdhwr %[rt],$" CVMX_TMP_STR(regstr) : [rt] "=d" (result)) + +#define CVMX_SYNCW \ + asm volatile ("syncw\nsyncw\n" : : : "memory") + +/* ToDo: Currently only node = 0 supported */ +static inline u64 csr_rd_node(int node, u64 addr) +{ + void __iomem *base; + + base = ioremap_nocache(addr, 0x100); + return ioread64(base); +} + +static inline u64 csr_rd(u64 addr) +{ + return csr_rd_node(0, addr); +} + +static inline void csr_wr_node(int node, u64 addr, u64 val) +{ + void __iomem *base; + + base = ioremap_nocache(addr, 0x100); + iowrite64(val, base); +} + +static inline void csr_wr(u64 addr, u64 val) +{ + csr_wr_node(0, addr, val); +} + +/* + * We need to use the volatile access here, otherwise the IO accessor + * functions might swap the bytes + */ +static inline u64 cvmx_read64_uint64(u64 addr) +{ + return *(volatile u64 *)addr; +} + +static inline void cvmx_write64_uint64(u64 addr, u64 val) +{ + *(volatile u64 *)addr = val; +} + +static inline u32 cvmx_read64_uint32(u64 addr) +{ + return *(volatile u32 *)addr; +} + +static inline void cvmx_write64_uint32(u64 addr, u32 val) +{ + *(volatile u32 *)addr = val; +} + +static inline void *cvmx_phys_to_ptr(u64 addr) +{ + return (void *)CKSEG0ADDR(addr); +} + +static inline u64 cvmx_ptr_to_phys(void *ptr) +{ + return virt_to_phys(ptr); +} + +/** + * Number of the Core on which the program is currently running. + * + * @return core number + */ +static inline unsigned int cvmx_get_core_num(void) +{ + unsigned int core_num; + + CVMX_RDHWRNV(core_num, 0); + return core_num; +} + +#endif /* __CVMX_REGS_H__ */ From patchwork Thu Aug 20 05:21:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Roese X-Patchwork-Id: 1348169 X-Patchwork-Delegate: daniel.schwierzeck@googlemail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=denx.de header.i=@denx.de header.a=rsa-sha256 header.s=phobos-20191101 header.b=mfoOjP1q; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BXCjV3w7lz9sR4 for ; Thu, 20 Aug 2020 15:23:26 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id E2E70822AA; Thu, 20 Aug 2020 07:22:28 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=denx.de; s=phobos-20191101; t=1597900949; bh=81EKYhfgm4ade4YlmSvwK+S89KXWr8545Fa9wU1Vegw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=mfoOjP1qRfmW1sBLga7+iv5eVuBH7NnzqfuGV7I+nHYkLzBzWtbBFEBKQPRoGdMD3 dRyfGdyNjCpn1YWz9+bqDV1hm7zF0QevQfR+NEeybRWEAKB5fcpNieHPDeVMnG+dEI law/ZOleGQx66ER6++/B6Vd3X3DnhXgk/qZe/QYvgF8D6WQegMiFfmHyXxDAYNTzS1 Awx0/yzQlPuUJNSjZVMCnufJRTKjkPi6G4A9cs7WCratry6jl00gLAZtxN84hB1ENg PoXQ8A1ysej69Xj6CdvbGklBvfffmla9tYROIojUMC+B+RUtVuqEuz0B1HqtcIjM5O sf6R2nOcszk6Q== Received: by phobos.denx.de (Postfix, from userid 109) id BCF9F8226F; Thu, 20 Aug 2020 07:22:16 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,KHOP_HELO_FCRDNS, SPF_HELO_NONE,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from mx2.mailbox.org (mx2a.mailbox.org [IPv6:2001:67c:2050:104:0:2:25:2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id EBF1A8225B for ; Thu, 20 Aug 2020 07:22:11 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=none smtp.mailfrom=sr@denx.de Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:105:465:1:1:0]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by mx2.mailbox.org (Postfix) with ESMTPS id B12F2A18F2; Thu, 20 Aug 2020 07:22:11 +0200 (CEST) Received: from smtp1.mailbox.org ([80.241.60.240]) by hefe.heinlein-support.de (hefe.heinlein-support.de [91.198.250.172]) (amavisd-new, port 10030) with ESMTP id VKhH_hnbcRAV; Thu, 20 Aug 2020 07:22:07 +0200 (CEST) From: Stefan Roese To: u-boot@lists.denx.de Cc: daniel.schwierzeck@gmail.com, cchavva@marvell.com, awilliams@marvell.com Subject: [PATCH v1 04/10] mips: octeon: Add header octeon-feature.h Date: Thu, 20 Aug 2020 07:21:58 +0200 Message-Id: <20200820052204.2794174-5-sr@denx.de> In-Reply-To: <20200820052204.2794174-1-sr@denx.de> References: <20200820052204.2794174-1-sr@denx.de> MIME-Version: 1.0 X-MBO-SPAM-Probability: X-Rspamd-Score: -0.28 / 15.00 / 15.00 X-Rspamd-Queue-Id: 908C91311 X-Rspamd-UID: 2756f0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean From: Aaron Williams This header includes the Octeon feature detection used in many Octeon drivers. Signed-off-by: Aaron Williams Signed-off-by: Stefan Roese --- .../mach-octeon/include/mach/octeon-feature.h | 442 ++++++++++++++++++ 1 file changed, 442 insertions(+) create mode 100644 arch/mips/mach-octeon/include/mach/octeon-feature.h diff --git a/arch/mips/mach-octeon/include/mach/octeon-feature.h b/arch/mips/mach-octeon/include/mach/octeon-feature.h new file mode 100644 index 0000000000..1202716ba5 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/octeon-feature.h @@ -0,0 +1,442 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#ifndef __OCTEON_FEATURE_H__ +#define __OCTEON_FEATURE_H__ + +/* + * Octeon models are declared after the macros in octeon-model.h with the + * suffix _FEATURE. The individual features are declared with the + * _FEATURE_ infix. + */ +enum octeon_feature { + /* + * Checks on the critical path are moved to the top (8 positions) + * so that the compiler generates one less insn than for the rest + * of the checks. + */ + OCTEON_FEATURE_PKND, /* CN68XX uses port kinds for packet interface */ + /* CN68XX has different fields in word0 - word2 */ + OCTEON_FEATURE_CN68XX_WQE, + + /* + * Features + */ + /* + * Octeon models in the CN5XXX family and higher support atomic + * add instructions to memory (saa/saad) + */ + OCTEON_FEATURE_SAAD, + /* Does this Octeon support the ZIP offload engine? */ + OCTEON_FEATURE_ZIP, + /* Does this Octeon support crypto acceleration using COP2? */ + OCTEON_FEATURE_CRYPTO, + /* Can crypto be enabled by calling cvmx_crypto_dormant_enable()? */ + OCTEON_FEATURE_DORM_CRYPTO, + OCTEON_FEATURE_PCIE, /* Does this Octeon support PCI express? */ + OCTEON_FEATURE_SRIO, /* Does this Octeon support SRIO */ + OCTEON_FEATURE_ILK, /* Does this Octeon support Interlaken */ + /* + * Some Octeon models support internal memory for storing + * cryptographic keys + */ + OCTEON_FEATURE_KEY_MEMORY, + /* Octeon has a LED controller for banks of external LEDs */ + OCTEON_FEATURE_LED_CONTROLLER, + OCTEON_FEATURE_TRA, /* Octeon has a trace buffer */ + OCTEON_FEATURE_MGMT_PORT, /* Octeon has a management port */ + OCTEON_FEATURE_RAID, /* Octeon has a raid unit */ + OCTEON_FEATURE_USB, /* Octeon has a builtin USB */ + /* Octeon IPD can run without using work queue entries */ + OCTEON_FEATURE_NO_WPTR, + OCTEON_FEATURE_DFA, /* Octeon has DFA state machines */ + /* + * Octeon MDIO block supports clause 45 transactions for + * 10 Gig support + */ + OCTEON_FEATURE_MDIO_CLAUSE_45, + /* + * CN52XX and CN56XX used a block named NPEI for PCIe access. + * Newer chips replaced this with SLI+DPI + */ + OCTEON_FEATURE_NPEI, + OCTEON_FEATURE_HFA, /* Octeon has DFA/HFA */ + OCTEON_FEATURE_DFM, /* Octeon has DFM */ + OCTEON_FEATURE_CIU2, /* Octeon has CIU2 */ + /* Octeon has DMA Instruction Completion Interrupt mode */ + OCTEON_FEATURE_DICI_MODE, + /* Octeon has Bit Select Extractor schedulor */ + OCTEON_FEATURE_BIT_EXTRACTOR, + OCTEON_FEATURE_NAND, /* Octeon has NAND */ + OCTEON_FEATURE_MMC, /* Octeon has built-in MMC support */ + OCTEON_FEATURE_ROM, /* Octeon has built-in ROM support */ + OCTEON_FEATURE_AUTHENTIK, /* Octeon has Authentik ROM support */ + OCTEON_FEATURE_MULTICAST_TIMER, /* Octeon has multi_cast timer */ + OCTEON_FEATURE_MULTINODE, /* Octeon has node support */ + OCTEON_FEATURE_CIU3, /* Octeon has CIU3 */ + OCTEON_FEATURE_FPA3, /* Octeon has FPA first seen on 78XX */ + /* CN78XX has different fields in word0 - word2 */ + OCTEON_FEATURE_CN78XX_WQE, + OCTEON_FEATURE_PKO3, /* Octeon has enhanced PKO block */ + OCTEON_FEATURE_SPI, /* Octeon supports SPI interfaces */ + OCTEON_FEATURE_ZIP3, /* Octeon has zip first seen on 78XX */ + OCTEON_FEATURE_BCH, /* Octeon supports BCH ECC */ + OCTEON_FEATURE_PKI, /* Octeon has PKI block */ + OCTEON_FEATURE_OCLA, /* Octeon has OCLA */ + OCTEON_FEATURE_FAU, /* Octeon has FAU */ + OCTEON_FEATURE_BGX, /* Octeon has BGX */ + OCTEON_FEATURE_BGX_MIX, /* On of the BGX is used for MIX */ + OCTEON_FEATURE_HNA, /* Octeon has HNA */ + OCTEON_FEATURE_BGX_XCV, /* Octeon has BGX XCV RGMII support */ + OCTEON_FEATURE_TSO, /* Octeon has tcp segmentation offload */ + OCTEON_FEATURE_TDM, /* Octeon has PCM/TDM support */ + OCTEON_FEATURE_PTP, /* Octeon has PTP support */ + OCTEON_MAX_FEATURE +}; + +static inline int octeon_has_feature_OCTEON_FEATURE_SAAD(void) +{ + return true; +} + +static inline int octeon_has_feature_OCTEON_FEATURE_ZIP(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CNF71XX) || + OCTEON_IS_MODEL(OCTEON_CN70XX) || OCTEON_IS_MODEL(OCTEON_CNF75XX)) + return 0; + else + return !cvmx_fuse_read(121); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_ZIP3(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN78XX) || + OCTEON_IS_MODEL(OCTEON_CN73XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_BCH(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN70XX) || + OCTEON_IS_MODEL(OCTEON_CNF75XX) || + OCTEON_IS_MODEL(OCTEON_CN73XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_CRYPTO(void) +{ + /* OCTEON II and later */ + u64 val; + + val = csr_rd(CVMX_MIO_FUS_DAT2); + if (val & MIO_FUS_DAT2_NOCRYPTO || val & MIO_FUS_DAT2_NOMUL) + return 0; + else if (!(val & MIO_FUS_DAT2_DORM_CRYPTO)) + return 1; + + val = csr_rd(CVMX_RNM_CTL_STATUS); + return val & RNM_CTL_STATUS_EER_VAL; +} + +static inline int octeon_has_feature_OCTEON_FEATURE_DORM_CRYPTO(void) +{ + /* OCTEON II and later */ + u64 val; + + val = csr_rd(CVMX_MIO_FUS_DAT2); + return !(val & MIO_FUS_DAT2_NOCRYPTO) && !(val & MIO_FUS_DAT2_NOMUL) && + (val & MIO_FUS_DAT2_DORM_CRYPTO); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_PCIE(void) +{ + /* OCTEON II and later have PCIe */ + return true; +} + +static inline int octeon_has_feature_OCTEON_FEATURE_SRIO(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) { + if (cvmx_fuse_read(1601) == 0) + return 0; + else + return 1; + } else { + return (OCTEON_IS_MODEL(OCTEON_CN63XX) || + OCTEON_IS_MODEL(OCTEON_CN66XX)); + } +} + +static inline int octeon_has_feature_OCTEON_FEATURE_ILK(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN68XX) || + OCTEON_IS_MODEL(OCTEON_CN78XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_KEY_MEMORY(void) +{ + /* OCTEON II or later */ + return true; +} + +static inline int octeon_has_feature_OCTEON_FEATURE_LED_CONTROLLER(void) +{ + return false; +} + +static inline int octeon_has_feature_OCTEON_FEATURE_TRA(void) +{ + return !OCTEON_IS_OCTEON3(); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_MGMT_PORT(void) +{ + /* OCTEON II or later */ + return true; +} + +static inline int octeon_has_feature_OCTEON_FEATURE_RAID(void) +{ + return !OCTEON_IS_MODEL(OCTEON_CNF75XX); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_USB(void) +{ + return true; +} + +static inline int octeon_has_feature_OCTEON_FEATURE_NO_WPTR(void) +{ + return true; +} + +static inline int octeon_has_feature_OCTEON_FEATURE_DFA(void) +{ + return 0; +} + +static inline int octeon_has_feature_OCTEON_FEATURE_HFA(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) + return 0; + else + return !cvmx_fuse_read(90); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_HNA(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CN78XX) || OCTEON_IS_MODEL(OCTEON_CN73XX)) + return !cvmx_fuse_read(134); + else + return 0; +} + +static inline int octeon_has_feature_OCTEON_FEATURE_DFM(void) +{ + if (!(OCTEON_IS_MODEL(OCTEON_CN63XX) || OCTEON_IS_MODEL(OCTEON_CN66XX))) + return 0; + else + return !cvmx_fuse_read(90); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_MDIO_CLAUSE_45(void) +{ + return true; +} + +static inline int octeon_has_feature_OCTEON_FEATURE_NPEI(void) +{ + return false; +} + +static inline int octeon_has_feature_OCTEON_FEATURE_PKND(void) +{ + return OCTEON_IS_MODEL(OCTEON_CN68XX) || + OCTEON_IS_MODEL(OCTEON_CNF75XX) || + OCTEON_IS_MODEL(OCTEON_CN73XX) || + OCTEON_IS_MODEL(OCTEON_CN78XX); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_CN68XX_WQE(void) +{ + return OCTEON_IS_MODEL(OCTEON_CN68XX); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_CIU2(void) +{ + return OCTEON_IS_MODEL(OCTEON_CN68XX); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_CIU3(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN78XX) || + OCTEON_IS_MODEL(OCTEON_CNF75XX) || + OCTEON_IS_MODEL(OCTEON_CN73XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_FPA3(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN78XX) || + OCTEON_IS_MODEL(OCTEON_CNF75XX) || + OCTEON_IS_MODEL(OCTEON_CN73XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_NAND(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN63XX) || + OCTEON_IS_MODEL(OCTEON_CN66XX) || + OCTEON_IS_MODEL(OCTEON_CN68XX) || + OCTEON_IS_MODEL(OCTEON_CN73XX) || + OCTEON_IS_MODEL(OCTEON_CNF75XX) || + OCTEON_IS_MODEL(OCTEON_CN70XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_DICI_MODE(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS2_X) || + OCTEON_IS_MODEL(OCTEON_CN61XX) || + OCTEON_IS_MODEL(OCTEON_CNF71XX) || + OCTEON_IS_MODEL(OCTEON_CN70XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_BIT_EXTRACTOR(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS2_X) || + OCTEON_IS_MODEL(OCTEON_CN61XX) || + OCTEON_IS_MODEL(OCTEON_CNF71XX) || + OCTEON_IS_MODEL(OCTEON_CN70XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_MMC(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN61XX) || + OCTEON_IS_MODEL(OCTEON_CNF71XX) || OCTEON_IS_OCTEON3()); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_ROM(void) +{ + return OCTEON_IS_MODEL(OCTEON_CN66XX) || + OCTEON_IS_MODEL(OCTEON_CN61XX) || + OCTEON_IS_MODEL(OCTEON_CNF71XX); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_AUTHENTIK(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CN66XX) || + OCTEON_IS_MODEL(OCTEON_CN61XX) || + OCTEON_IS_MODEL(OCTEON_CNF71XX) || + OCTEON_IS_MODEL(OCTEON_CN70XX)) { + u64 val; + + val = csr_rd(CVMX_MIO_FUS_DAT2); + return (val & MIO_FUS_DAT2_NOCRYPTO) && + (val & MIO_FUS_DAT2_DORM_CRYPTO); + } + + return 0; +} + +static inline int octeon_has_feature_OCTEON_FEATURE_MULTICAST_TIMER(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_2) || + OCTEON_IS_MODEL(OCTEON_CN61XX) || + OCTEON_IS_MODEL(OCTEON_CNF71XX) || + OCTEON_IS_MODEL(OCTEON_CN70XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_MULTINODE(void) +{ + return (!OCTEON_IS_MODEL(OCTEON_CN76XX) && + OCTEON_IS_MODEL(OCTEON_CN78XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_CN78XX_WQE(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN78XX) || + OCTEON_IS_MODEL(OCTEON_CNF75XX) || + OCTEON_IS_MODEL(OCTEON_CN73XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_SPI(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN66XX) || + OCTEON_IS_MODEL(OCTEON_CN61XX) || + OCTEON_IS_MODEL(OCTEON_CNF71XX) || OCTEON_IS_OCTEON3()); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_PKI(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN78XX) || + OCTEON_IS_MODEL(OCTEON_CNF75XX) || + OCTEON_IS_MODEL(OCTEON_CN73XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_PKO3(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN78XX) || + OCTEON_IS_MODEL(OCTEON_CNF75XX) || + OCTEON_IS_MODEL(OCTEON_CN73XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_OCLA(void) +{ + return OCTEON_IS_OCTEON3(); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_FAU(void) +{ + return (!OCTEON_IS_MODEL(OCTEON_CN78XX) && + !OCTEON_IS_MODEL(OCTEON_CNF75XX) && + !OCTEON_IS_MODEL(OCTEON_CN73XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_BGX(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN78XX) || + OCTEON_IS_MODEL(OCTEON_CNF75XX) || + OCTEON_IS_MODEL(OCTEON_CN73XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_BGX_MIX(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN78XX) || + OCTEON_IS_MODEL(OCTEON_CNF75XX) || + OCTEON_IS_MODEL(OCTEON_CN73XX)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_BGX_XCV(void) +{ + return OCTEON_IS_MODEL(OCTEON_CN73XX); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_TSO(void) +{ + return (OCTEON_IS_MODEL(OCTEON_CN73XX) || + OCTEON_IS_MODEL(OCTEON_CNF75XX) || + OCTEON_IS_MODEL(OCTEON_CN78XX_PASS2_X)); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_TDM(void) +{ + return OCTEON_IS_MODEL(OCTEON_CN61XX) || + OCTEON_IS_MODEL(OCTEON_CNF71XX) || + OCTEON_IS_MODEL(OCTEON_CN70XX); +} + +static inline int octeon_has_feature_OCTEON_FEATURE_PTP(void) +{ + return OCTEON_IS_MODEL(OCTEON_CN6XXX) || + OCTEON_IS_MODEL(OCTEON_CNF7XXX) || + OCTEON_IS_MODEL(OCTEON_CN73XX) || + OCTEON_IS_MODEL(OCTEON_CNF75XX) || + OCTEON_IS_MODEL(OCTEON_CN78XX_PASS2_X); +} + +/* + * Answer ``Is the bit for feature set in the bitmap?'' + * @param feature + * @return 1 when the feature is present and 0 otherwise, -1 in case of error. + */ +#define octeon_has_feature(feature_x) octeon_has_feature_##feature_x() + +#endif /* __OCTEON_FEATURE_H__ */ From patchwork Thu Aug 20 05:21:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Roese X-Patchwork-Id: 1348165 X-Patchwork-Delegate: daniel.schwierzeck@googlemail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=denx.de header.i=@denx.de header.a=rsa-sha256 header.s=phobos-20191101 header.b=hjcgqu1V; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BXChY4VTxz9sR4 for ; Thu, 20 Aug 2020 15:22:37 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 87ED982261; Thu, 20 Aug 2020 07:22:17 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=denx.de; s=phobos-20191101; t=1597900937; bh=iItZmZlWr+aFu0Lx5YwjB00ElisCM3XKO0AmLgjPFTQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=hjcgqu1VAOMwbOX5sSpYLWp5dVl4QeSxi8F0TlODSAzQhncwVr0pOTZHFh59PSU+F JEEeIxrFKqRr1TI83wnnGz5LzdbtYO1/TV8a7nZj+428ALc3LjpVelVAye2rTQi5Bl K9/o99aDtup44WGZF6LhxRf5mtzk6uKifZu1mRIRgOH8msfOYzbwCv5kgGJ1itew+H 3bOO9GgGrvi5Xu7pc2jLQMctSZliz5XloZ9qSORt90JVFw7TxUVGBWczrm8/j8atb6 hVS1an3MndeecsshVEbYT0HJNVIeu5oNznbWZP+E+rqw+FkNIs+I1KWIUCEPiEZdRq vDnXGd3zUbAWA== Received: by phobos.denx.de (Postfix, from userid 109) id 520A88225E; Thu, 20 Aug 2020 07:22:13 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,KHOP_HELO_FCRDNS, SPF_HELO_NONE,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from mx2.mailbox.org (mx2a.mailbox.org [IPv6:2001:67c:2050:104:0:2:25:2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id BF28C81B79 for ; Thu, 20 Aug 2020 07:22:10 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=none smtp.mailfrom=sr@denx.de Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:105:465:1:1:0]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by mx2.mailbox.org (Postfix) with ESMTPS id 8E7B6A17C3; Thu, 20 Aug 2020 07:22:10 +0200 (CEST) Received: from smtp1.mailbox.org ([80.241.60.240]) by spamfilter02.heinlein-hosting.de (spamfilter02.heinlein-hosting.de [80.241.56.116]) (amavisd-new, port 10030) with ESMTP id X-Qml2bQbxRs; Thu, 20 Aug 2020 07:22:07 +0200 (CEST) From: Stefan Roese To: u-boot@lists.denx.de Cc: daniel.schwierzeck@gmail.com, cchavva@marvell.com, awilliams@marvell.com Subject: [PATCH v1 05/10] mips: octeon: Add header cvmx-fuse.h Date: Thu, 20 Aug 2020 07:21:59 +0200 Message-Id: <20200820052204.2794174-6-sr@denx.de> In-Reply-To: <20200820052204.2794174-1-sr@denx.de> References: <20200820052204.2794174-1-sr@denx.de> MIME-Version: 1.0 X-MBO-SPAM-Probability: X-Rspamd-Score: -0.28 / 15.00 / 15.00 X-Rspamd-Queue-Id: 79DB23CD X-Rspamd-UID: 67921b X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean From: Aaron Williams Add header to handle Octeon fuse access. Signed-off-by: Aaron Williams Signed-off-by: Stefan Roese --- .../mips/mach-octeon/include/mach/cvmx-fuse.h | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-fuse.h diff --git a/arch/mips/mach-octeon/include/mach/cvmx-fuse.h b/arch/mips/mach-octeon/include/mach/cvmx-fuse.h new file mode 100644 index 0000000000..a06a1326cb --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-fuse.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#ifndef __CVMX_FUSE_H__ +#define __CVMX_FUSE_H__ + +/** + * Read a byte of fuse data + * @param node node to read from + * @param byte_addr address to read + * + * @return fuse value: 0 or 1 + */ +static inline u8 cvmx_fuse_read_byte_node(u8 node, int byte_addr) +{ + u64 val; + + val = FIELD_PREP(MIO_FUS_RCMD_ADDR, byte_addr) | MIO_FUS_RCMD_PEND; + csr_wr_node(node, CVMX_MIO_FUS_RCMD, val); + + do { + val = csr_rd_node(node, CVMX_MIO_FUS_RCMD); + } while (val & MIO_FUS_RCMD_PEND); + + return FIELD_GET(MIO_FUS_RCMD_DAT, val); +} + +/** + * Read a byte of fuse data + * @param byte_addr address to read + * + * @return fuse value: 0 or 1 + */ +static inline u8 cvmx_fuse_read_byte(int byte_addr) +{ + return cvmx_fuse_read_byte_node(0, byte_addr); +} + +/** + * Read a single fuse bit + * + * @param node Node number + * @param fuse Fuse number (0-1024) + * + * @return fuse value: 0 or 1 + */ +static inline int cvmx_fuse_read_node(u8 node, int fuse) +{ + return (cvmx_fuse_read_byte_node(node, fuse >> 3) >> (fuse & 0x7)) & 1; +} + +/** + * Read a single fuse bit + * + * @param fuse Fuse number (0-1024) + * + * @return fuse value: 0 or 1 + */ +static inline int cvmx_fuse_read(int fuse) +{ + return cvmx_fuse_read_node(0, fuse); +} + +static inline int cvmx_octeon_fuse_locked(void) +{ + return cvmx_fuse_read(123); +} + +#endif /* __CVMX_FUSE_H__ */ From patchwork Thu Aug 20 05:22:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Roese X-Patchwork-Id: 1348168 X-Patchwork-Delegate: daniel.schwierzeck@googlemail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=denx.de header.i=@denx.de header.a=rsa-sha256 header.s=phobos-20191101 header.b=mJLlzPjN; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BXCjF60c8z9sR4 for ; Thu, 20 Aug 2020 15:23:13 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id B7C0B8229C; Thu, 20 Aug 2020 07:22:24 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=denx.de; s=phobos-20191101; t=1597900944; bh=uabmIDFlHdjq9g2OxKZKujEAW8qwB32QtCcPl1q6UqU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=mJLlzPjN0PbeOXyyVOa2jRfzbE7feXnhMbBl2Ky1gDpRZQl2yclb7hRi+Ya4wFuAA 1MyCYBS3Mo6RUDpKJS1X9uOzeeepdxS4W0kzeBAQwxEvhEnELOL58onArR4W7Jv20A vH+4BkVyaH0UX/25CofnFiS9+7Suh/LA49Fd9j0d4huv9w48t3YiaVIiSVw0UK42Vd tojrR0a4u3nnY3ttdkz0IAueNT0BdF4yBhA7pF2Y8iU9G2IFnvwPX30AyVPm8RVtEn Jk4KjDfDvDDLetRHakFQSpJA1WauHb3PL156Ht+mpfCCa6c2CM9vOxz6KdveO0ZKnf 4HOIDkFfKvZ9g== Received: by phobos.denx.de (Postfix, from userid 109) id 9AD1F8225E; Thu, 20 Aug 2020 07:22:16 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,KHOP_HELO_FCRDNS, SPF_HELO_NONE,UPPERCASE_50_75,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from mx2.mailbox.org (mx2a.mailbox.org [IPv6:2001:67c:2050:104:0:2:25:2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id C786782259 for ; Thu, 20 Aug 2020 07:22:11 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=none smtp.mailfrom=sr@denx.de Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:105:465:1:1:0]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by mx2.mailbox.org (Postfix) with ESMTPS id 8EFAFA1883; Thu, 20 Aug 2020 07:22:11 +0200 (CEST) Received: from smtp1.mailbox.org ([80.241.60.240]) by spamfilter03.heinlein-hosting.de (spamfilter03.heinlein-hosting.de [80.241.56.117]) (amavisd-new, port 10030) with ESMTP id TL8x8sfjFd0N; Thu, 20 Aug 2020 07:22:07 +0200 (CEST) From: Stefan Roese To: u-boot@lists.denx.de Cc: daniel.schwierzeck@gmail.com, cchavva@marvell.com, awilliams@marvell.com Subject: [PATCH v1 06/10] mips: octeon: Add header cvmx-bootinfo.h Date: Thu, 20 Aug 2020 07:22:00 +0200 Message-Id: <20200820052204.2794174-7-sr@denx.de> In-Reply-To: <20200820052204.2794174-1-sr@denx.de> References: <20200820052204.2794174-1-sr@denx.de> MIME-Version: 1.0 X-MBO-SPAM-Probability: X-Rspamd-Score: -0.28 / 15.00 / 15.00 X-Rspamd-Queue-Id: 77E0612BB X-Rspamd-UID: 21f4cb X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean From: Aaron Williams Add header to handle bootinfo support, needed for Octeon Linux kernel booting. Signed-off-by: Aaron Williams Signed-off-by: Stefan Roese --- .../mach-octeon/include/mach/cvmx-bootinfo.h | 350 ++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-bootinfo.h diff --git a/arch/mips/mach-octeon/include/mach/cvmx-bootinfo.h b/arch/mips/mach-octeon/include/mach/cvmx-bootinfo.h new file mode 100644 index 0000000000..337987178f --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-bootinfo.h @@ -0,0 +1,350 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +/* + * Header file containing the ABI with the bootloader. + */ + +#ifndef __CVMX_BOOTINFO_H__ +#define __CVMX_BOOTINFO_H__ + +#include "cvmx-coremask.h" + +/* + * Current major and minor versions of the CVMX bootinfo block that is + * passed from the bootloader to the application. This is versioned + * so that applications can properly handle multiple bootloader + * versions. + */ +#define CVMX_BOOTINFO_MAJ_VER 1 +#define CVMX_BOOTINFO_MIN_VER 4 + +#if (CVMX_BOOTINFO_MAJ_VER == 1) +#define CVMX_BOOTINFO_OCTEON_SERIAL_LEN 20 +/* + * This structure is populated by the bootloader. For binary + * compatibility the only changes that should be made are + * adding members to the end of the structure, and the minor + * version should be incremented at that time. + * If an incompatible change is made, the major version + * must be incremented, and the minor version should be reset + * to 0. + */ +struct cvmx_bootinfo { + u32 major_version; + u32 minor_version; + + u64 stack_top; + u64 heap_base; + u64 heap_end; + u64 desc_vaddr; + + u32 exception_base_addr; + u32 stack_size; + u32 flags; + u32 core_mask; + /* DRAM size in megabytes */ + u32 dram_size; + /* physical address of free memory descriptor block*/ + u32 phy_mem_desc_addr; + /* used to pass flags from app to debugger */ + u32 debugger_flags_base_addr; + + /* CPU clock speed, in hz */ + u32 eclock_hz; + + /* DRAM clock speed, in hz */ + u32 dclock_hz; + + u32 reserved0; + u16 board_type; + u8 board_rev_major; + u8 board_rev_minor; + u16 reserved1; + u8 reserved2; + u8 reserved3; + char board_serial_number[CVMX_BOOTINFO_OCTEON_SERIAL_LEN]; + u8 mac_addr_base[6]; + u8 mac_addr_count; +#if (CVMX_BOOTINFO_MIN_VER >= 1) + /* + * Several boards support compact flash on the Octeon boot + * bus. The CF memory spaces may be mapped to different + * addresses on different boards. These are the physical + * addresses, so care must be taken to use the correct + * XKPHYS/KSEG0 addressing depending on the application's + * ABI. These values will be 0 if CF is not present. + */ + u64 compact_flash_common_base_addr; + u64 compact_flash_attribute_base_addr; + /* + * Base address of the LED display (as on EBT3000 board) + * This will be 0 if LED display not present. + */ + u64 led_display_base_addr; +#endif +#if (CVMX_BOOTINFO_MIN_VER >= 2) + /* DFA reference clock in hz (if applicable)*/ + u32 dfa_ref_clock_hz; + + /* + * flags indicating various configuration options. These + * flags supercede the 'flags' variable and should be used + * instead if available. + */ + u32 config_flags; +#endif +#if (CVMX_BOOTINFO_MIN_VER >= 3) + /* + * Address of the OF Flattened Device Tree structure + * describing the board. + */ + u64 fdt_addr; +#endif +#if (CVMX_BOOTINFO_MIN_VER >= 4) + /* + * Coremask used for processors with more than 32 cores + * or with OCI. This replaces core_mask. + */ + struct cvmx_coremask ext_core_mask; +#endif +}; + +#define CVMX_BOOTINFO_CFG_FLAG_PCI_HOST (1ull << 0) +#define CVMX_BOOTINFO_CFG_FLAG_PCI_TARGET (1ull << 1) +#define CVMX_BOOTINFO_CFG_FLAG_DEBUG (1ull << 2) +#define CVMX_BOOTINFO_CFG_FLAG_NO_MAGIC (1ull << 3) +/* + * This flag is set if the TLB mappings are not contained in the + * 0x10000000 - 0x20000000 boot bus region. + */ +#define CVMX_BOOTINFO_CFG_FLAG_OVERSIZE_TLB_MAPPING (1ull << 4) +#define CVMX_BOOTINFO_CFG_FLAG_BREAK (1ull << 5) + +#endif /* (CVMX_BOOTINFO_MAJ_VER == 1) */ + +/* Type defines for board and chip types */ +enum cvmx_board_types_enum { + CVMX_BOARD_TYPE_NULL = 0, + CVMX_BOARD_TYPE_SIM = 1, + CVMX_BOARD_TYPE_EBT3000 = 2, + CVMX_BOARD_TYPE_KODAMA = 3, + CVMX_BOARD_TYPE_NIAGARA = 4, + CVMX_BOARD_TYPE_NAC38 = 5, /* formerly NAO38 */ + CVMX_BOARD_TYPE_THUNDER = 6, + CVMX_BOARD_TYPE_TRANTOR = 7, + CVMX_BOARD_TYPE_EBH3000 = 8, + CVMX_BOARD_TYPE_EBH3100 = 9, + CVMX_BOARD_TYPE_HIKARI = 10, + CVMX_BOARD_TYPE_CN3010_EVB_HS5 = 11, + CVMX_BOARD_TYPE_CN3005_EVB_HS5 = 12, + CVMX_BOARD_TYPE_KBP = 13, + /* Deprecated, CVMX_BOARD_TYPE_CN3010_EVB_HS5 supports the CN3020 */ + CVMX_BOARD_TYPE_CN3020_EVB_HS5 = 14, + CVMX_BOARD_TYPE_EBT5800 = 15, + CVMX_BOARD_TYPE_NICPRO2 = 16, + CVMX_BOARD_TYPE_EBH5600 = 17, + CVMX_BOARD_TYPE_EBH5601 = 18, + CVMX_BOARD_TYPE_EBH5200 = 19, + CVMX_BOARD_TYPE_BBGW_REF = 20, + CVMX_BOARD_TYPE_NIC_XLE_4G = 21, + CVMX_BOARD_TYPE_EBT5600 = 22, + CVMX_BOARD_TYPE_EBH5201 = 23, + CVMX_BOARD_TYPE_EBT5200 = 24, + CVMX_BOARD_TYPE_CB5600 = 25, + CVMX_BOARD_TYPE_CB5601 = 26, + CVMX_BOARD_TYPE_CB5200 = 27, + /* Special 'generic' board type, supports many boards */ + CVMX_BOARD_TYPE_GENERIC = 28, + CVMX_BOARD_TYPE_EBH5610 = 29, + CVMX_BOARD_TYPE_LANAI2_A = 30, + CVMX_BOARD_TYPE_LANAI2_U = 31, + CVMX_BOARD_TYPE_EBB5600 = 32, + CVMX_BOARD_TYPE_EBB6300 = 33, + CVMX_BOARD_TYPE_NIC_XLE_10G = 34, + CVMX_BOARD_TYPE_LANAI2_G = 35, + CVMX_BOARD_TYPE_EBT5810 = 36, + CVMX_BOARD_TYPE_NIC10E = 37, + CVMX_BOARD_TYPE_EP6300C = 38, + CVMX_BOARD_TYPE_EBB6800 = 39, + CVMX_BOARD_TYPE_NIC4E = 40, + CVMX_BOARD_TYPE_NIC2E = 41, + CVMX_BOARD_TYPE_EBB6600 = 42, + CVMX_BOARD_TYPE_REDWING = 43, + CVMX_BOARD_TYPE_NIC68_4 = 44, + CVMX_BOARD_TYPE_NIC10E_66 = 45, + CVMX_BOARD_TYPE_MAX, + + /* + * The range from CVMX_BOARD_TYPE_MAX to + * CVMX_BOARD_TYPE_CUST_DEFINED_MIN is reserved for future + * SDK use. + */ + + /* + * Set aside a range for customer boards. These numbers are managed + * by Cavium. + */ + CVMX_BOARD_TYPE_CUST_DEFINED_MIN = 10000, + CVMX_BOARD_TYPE_CUST_WSX16 = 10001, + CVMX_BOARD_TYPE_CUST_NS0216 = 10002, + CVMX_BOARD_TYPE_CUST_NB5 = 10003, + CVMX_BOARD_TYPE_CUST_WMR500 = 10004, + CVMX_BOARD_TYPE_CUST_ITB101 = 10005, + CVMX_BOARD_TYPE_CUST_NTE102 = 10006, + CVMX_BOARD_TYPE_CUST_AGS103 = 10007, + CVMX_BOARD_TYPE_CUST_GST104 = 10008, + CVMX_BOARD_TYPE_CUST_GCT105 = 10009, + CVMX_BOARD_TYPE_CUST_AGS106 = 10010, + CVMX_BOARD_TYPE_CUST_SGM107 = 10011, + CVMX_BOARD_TYPE_CUST_GCT108 = 10012, + CVMX_BOARD_TYPE_CUST_AGS109 = 10013, + CVMX_BOARD_TYPE_CUST_GCT110 = 10014, + CVMX_BOARD_TYPE_CUST_L2_AIR_SENDER = 10015, + CVMX_BOARD_TYPE_CUST_L2_AIR_RECEIVER = 10016, + CVMX_BOARD_TYPE_CUST_L2_ACCTON2_TX = 10017, + CVMX_BOARD_TYPE_CUST_L2_ACCTON2_RX = 10018, + CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_TX = 10019, + CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_RX = 10020, + CVMX_BOARD_TYPE_CUST_L2_ZINWELL = 10021, + CVMX_BOARD_TYPE_CUST_DEFINED_MAX = 20000, + + /* + * Set aside a range for customer private use. The SDK won't + * use any numbers in this range. + */ + CVMX_BOARD_TYPE_CUST_PRIVATE_MIN = 20001, + CVMX_BOARD_TYPE_UBNT_E100 = 20002, + CVMX_BOARD_TYPE_CUST_DSR1000N = 20006, + CVMX_BOARD_TYPE_KONTRON_S1901 = 21901, + CVMX_BOARD_TYPE_CUST_PRIVATE_MAX = 30000, + + /* The remaining range is reserved for future use. */ +}; + +enum cvmx_chip_types_enum { + CVMX_CHIP_TYPE_NULL = 0, + CVMX_CHIP_SIM_TYPE_DEPRECATED = 1, + CVMX_CHIP_TYPE_OCTEON_SAMPLE = 2, + CVMX_CHIP_TYPE_MAX, +}; + +/* + * Compatibility alias for NAC38 name change, planned to be removed + * from SDK 1.7 + */ +#define CVMX_BOARD_TYPE_NAO38 CVMX_BOARD_TYPE_NAC38 + +/* Functions to return string based on type */ +#define ENUM_BRD_TYPE_CASE(x) \ + case x: \ + return(#x + 16) /* Skip CVMX_BOARD_TYPE_ */ + +static inline const char *cvmx_board_type_to_string(enum + cvmx_board_types_enum type) +{ + switch (type) { + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NULL); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_SIM); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT3000); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KODAMA); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIAGARA); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NAC38); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_THUNDER); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_TRANTOR); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH3000); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH3100); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_HIKARI); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CN3010_EVB_HS5); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CN3005_EVB_HS5); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KBP); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CN3020_EVB_HS5); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5800); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NICPRO2); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5600); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5601); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5200); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_BBGW_REF); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC_XLE_4G); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5600); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5201); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5200); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CB5600); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CB5601); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CB5200); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_GENERIC); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5610); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_A); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_U); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB5600); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6300); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC_XLE_10G); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_G); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5810); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC10E); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EP6300C); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6800); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC4E); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC2E); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6600); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_REDWING); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC68_4); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC10E_66); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_MAX); + + /* Customer boards listed here */ + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MIN); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_WSX16); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NS0216); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NB5); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_WMR500); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_ITB101); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NTE102); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS103); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GST104); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT105); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS106); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_SGM107); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT108); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS109); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT110); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_AIR_SENDER); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_AIR_RECEIVER); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ACCTON2_TX); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ACCTON2_RX); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_TX); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_RX); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ZINWELL); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MAX); + + /* Customer private range */ + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MIN); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E100); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DSR1000N); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KONTRON_S1901); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX); + } + + return NULL; +} + +#define ENUM_CHIP_TYPE_CASE(x) \ + case x: \ + return(#x + 15) /* Skip CVMX_CHIP_TYPE */ + +static inline const char *cvmx_chip_type_to_string(enum + cvmx_chip_types_enum type) +{ + switch (type) { + ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_NULL); + ENUM_CHIP_TYPE_CASE(CVMX_CHIP_SIM_TYPE_DEPRECATED); + ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_OCTEON_SAMPLE); + ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_MAX); + } + + return "Unsupported Chip"; +} + +#endif /* __CVMX_BOOTINFO_H__ */ From patchwork Thu Aug 20 05:22:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Roese X-Patchwork-Id: 1348170 X-Patchwork-Delegate: daniel.schwierzeck@googlemail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=denx.de header.i=@denx.de header.a=rsa-sha256 header.s=phobos-20191101 header.b=uEWBccLZ; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BXCjk6qrwz9sR4 for ; Thu, 20 Aug 2020 15:23:38 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 49CE9822A7; Thu, 20 Aug 2020 07:22:30 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=denx.de; s=phobos-20191101; t=1597900950; bh=wZpQS9POFwVQhKPuDiVzSymMGj0zd03HJ8gR+W41QCw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=uEWBccLZGG6P++7VHqyZ6ItCWEHwtI+JGkjBL1XlBFX5Wr4eK0NgK399afnufg2TX YmjOUf6arztvflWZIgqJcefeudx1OeRl0nPisFMfNlZfKPRPMRP3sOlm55a0WH0t0W riSXiSFB/ijN/dO9yvL6sa6MwVQ3/nbGXFSB0Qt/eeWY2VmJn+ILRxUqx6wzDy4r1f Y074krWgp8rB4uOJC74lMPRvfkwqY4pzMhLqkKqx8u5RyvBkbb6rkdGkaoUeIttbUy TcR+gsxYdWftaPi76AmEPHC83dwbp1sZgFXoUSeUPlXCsyCrwFWXexoWdWIK3rKyyr hXeCz3z9StQiw== Received: by phobos.denx.de (Postfix, from userid 109) id 7729F82272; Thu, 20 Aug 2020 07:22:17 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mx2.mailbox.org (mx2.mailbox.org [80.241.60.215]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 9F91F82261 for ; Thu, 20 Aug 2020 07:22:12 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=none smtp.mailfrom=sr@denx.de Received: from smtp1.mailbox.org (smtp1.mailbox.org [80.241.60.240]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by mx2.mailbox.org (Postfix) with ESMTPS id 6FB90A15ED; Thu, 20 Aug 2020 07:22:12 +0200 (CEST) Received: from smtp1.mailbox.org ([80.241.60.240]) by hefe.heinlein-support.de (hefe.heinlein-support.de [91.198.250.172]) (amavisd-new, port 10030) with ESMTP id wKVN5rjwEtL2; Thu, 20 Aug 2020 07:22:07 +0200 (CEST) From: Stefan Roese To: u-boot@lists.denx.de Cc: daniel.schwierzeck@gmail.com, cchavva@marvell.com, awilliams@marvell.com Subject: [PATCH v1 07/10] mips: octeon: Add coremask support Date: Thu, 20 Aug 2020 07:22:01 +0200 Message-Id: <20200820052204.2794174-8-sr@denx.de> In-Reply-To: <20200820052204.2794174-1-sr@denx.de> References: <20200820052204.2794174-1-sr@denx.de> MIME-Version: 1.0 X-MBO-SPAM-Probability: X-Rspamd-Score: -0.28 / 15.00 / 15.00 X-Rspamd-Queue-Id: 53C3F66D X-Rspamd-UID: daccf1 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean From: Aaron Williams This patch adds the coremask handling functions. Signed-off-by: Aaron Williams Signed-off-by: Stefan Roese --- arch/mips/mach-octeon/Makefile | 1 + arch/mips/mach-octeon/cvmx-coremask.c | 366 +++++++++ .../mach-octeon/include/mach/cvmx-coremask.h | 752 ++++++++++++++++++ 3 files changed, 1119 insertions(+) create mode 100644 arch/mips/mach-octeon/cvmx-coremask.c create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-coremask.h diff --git a/arch/mips/mach-octeon/Makefile b/arch/mips/mach-octeon/Makefile index 2e37ca572c..5155f89a1e 100644 --- a/arch/mips/mach-octeon/Makefile +++ b/arch/mips/mach-octeon/Makefile @@ -8,3 +8,4 @@ obj-y += cache.o obj-y += clock.o obj-y += cpu.o obj-y += dram.o +obj-y += cvmx-coremask.o diff --git a/arch/mips/mach-octeon/cvmx-coremask.c b/arch/mips/mach-octeon/cvmx-coremask.c new file mode 100644 index 0000000000..cff8c08b97 --- /dev/null +++ b/arch/mips/mach-octeon/cvmx-coremask.c @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018-2020 Marvell International Ltd. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +struct cvmx_coremask *get_coremask_override(struct cvmx_coremask *pcm) +{ + struct cvmx_coremask pcm_override = CVMX_COREMASK_MAX; + char *cptr; + + /* The old code sets the number of cores to be to 16 in this case. */ + cvmx_coremask_set_cores(pcm, 0, 16); + + if (OCTEON_IS_OCTEON2() || OCTEON_IS_OCTEON3()) + cvmx_coremask_copy(pcm, &pcm_override); + + cptr = env_get("coremask_override"); + if (cptr) { + if (cvmx_coremask_str2bmp(pcm, cptr) < 0) + return NULL; + } + + return pcm; +} + +/* Validate the coremask that is passed to a boot* function. */ +int validate_coremask(struct cvmx_coremask *pcm) +{ + struct cvmx_coremask coremask_override; + struct cvmx_coremask fuse_coremask; + + if (!get_coremask_override(&coremask_override)) + return -1; + + octeon_get_available_coremask(&fuse_coremask); + + if (!cvmx_coremask_is_subset(&fuse_coremask, pcm)) { + puts("ERROR: Can't boot cores that don't exist!\n"); + puts("Available coremask:\n"); + cvmx_coremask_print(&fuse_coremask); + return -1; + } + + if (!cvmx_coremask_is_subset(&coremask_override, pcm)) { + struct cvmx_coremask print_cm; + + puts("Notice: coremask changed from:\n"); + cvmx_coremask_print(pcm); + puts("based on coremask_override of:\n"); + cvmx_coremask_print(&coremask_override); + cvmx_coremask_and(&print_cm, pcm, &coremask_override); + puts("to:\n"); + cvmx_coremask_print(&print_cm); + } + + return 0; +} + +/** + * In CIU_FUSE for the 78XX, odd and even cores are separated out. + * For example, a CIU_FUSE value of 0xfffffefffffe indicates that bits 0 and 1 + * are set. + * This function converts the bit number in the CIU_FUSE register to a + * physical core number. + */ +static int convert_ciu_fuse_to_physical_core(int core, int max_cores) +{ + if (!octeon_has_feature(OCTEON_FEATURE_CIU3)) + return core; + else if (!OCTEON_IS_MODEL(OCTEON_CN78XX)) + return core; + else if (core < (max_cores / 2)) + return core * 2; + else + return ((core - (max_cores / 2)) * 2) + 1; +} + +/** + * Get the total number of fuses blown as well as the number blown per tad. + * + * @param coremask fuse coremask + * @param[out] tad_blown_count number of cores blown for each tad + * @param num_tads number of tads + * @param max_cores maximum number of cores + * + * @return void + */ +void fill_tad_corecount(u64 coremask, int tad_blown_count[], int num_tads, + int max_cores) +{ + int core, physical_core; + + for (core = 0; core < max_cores; core++) { + if (!(coremask & (1ULL << core))) { + int tad; + + physical_core = + convert_ciu_fuse_to_physical_core(core, + max_cores); + tad = physical_core % num_tads; + tad_blown_count[tad]++; + } + } +} + +u64 get_core_pattern(int num_tads, int max_cores) +{ + u64 pattern = 1ULL; + int cnt; + + for (cnt = 1; cnt < (max_cores / num_tads); cnt++) + pattern |= pattern << num_tads; + + return pattern; +} + +/** + * For CN78XX and CN68XX this function returns the logical coremask from the + * CIU_FUSE register value. For other models there is no difference. + * + * @param ciu_fuse_value fuse value from CIU_FUSE register + * @return logical coremask of CIU_FUSE value. + */ +u64 get_logical_coremask(u64 ciu_fuse_value) +{ + int tad_blown_count[MAX_CORE_TADS] = {0}; + int tad; + u64 logical_coremask = 0; + u64 tad_mask, pattern; + int num_tads, max_cores; + + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) { + num_tads = 8; + max_cores = 48; + } else if (OCTEON_IS_MODEL(OCTEON_CN73XX) || + OCTEON_IS_MODEL(OCTEON_CNF75XX)) { + num_tads = 4; + max_cores = 16; + } else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + num_tads = 4; + max_cores = 32; + } else { + /* Most Octeon devices don't need any mapping. */ + return ciu_fuse_value; + } + + pattern = get_core_pattern(num_tads, max_cores); + fill_tad_corecount(ciu_fuse_value, tad_blown_count, + num_tads, max_cores); + + for (tad = 0; tad < num_tads; tad++) { + tad_mask = pattern << tad; + logical_coremask |= tad_mask >> (tad_blown_count[tad] * num_tads); + } + return logical_coremask; +} + +/** + * Returns the available coremask either from env or fuses. + * If the fuses are blown and locked, they are the definitive coremask. + * + * @param pcm pointer to coremask to fill in + * @return pointer to coremask + */ +struct cvmx_coremask *octeon_get_available_coremask(struct cvmx_coremask *pcm) +{ + u8 node_mask = 0x01; /* ToDo: Currently only one node is supported */ + u64 ciu_fuse; + u64 cores; + + cvmx_coremask_clear_all(pcm); + + if (octeon_has_feature(OCTEON_FEATURE_CIU3)) { + int node; + + cvmx_coremask_for_each_node(node, node_mask) { + ciu_fuse = (csr_rd(CVMX_CIU_FUSE) & + 0x0000FFFFFFFFFFFFULL); + + ciu_fuse = get_logical_coremask(ciu_fuse); + cvmx_coremask_set64_node(pcm, node, ciu_fuse); + } + + return pcm; + } + + ciu_fuse = (csr_rd(CVMX_CIU_FUSE) & 0x0000FFFFFFFFFFFFULL); + ciu_fuse = get_logical_coremask(ciu_fuse); + + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + cvmx_coremask_set64(pcm, ciu_fuse); + + /* Get number of cores from fuse register, convert to coremask */ + cores = __builtin_popcountll(ciu_fuse); + + cvmx_coremask_set_cores(pcm, 0, cores); + + return pcm; +} + +int cvmx_coremask_str2bmp(struct cvmx_coremask *pcm, char *hexstr) +{ + int i, j; + int l; /* length of the hexstr in characters */ + int lb; /* number of bits taken by hexstr */ + int hldr_offset;/* holder's offset within the coremask */ + int hldr_xsz; /* holder's size in the number of hex digits */ + u64 h; + char c; + +#define MINUS_ONE (hexstr[0] == '-' && hexstr[1] == '1' && hexstr[2] == 0) + if (MINUS_ONE) { + cvmx_coremask_set_all(pcm); + return 0; + } + + /* Skip '0x' from hexstr */ + if (hexstr[0] == '0' && (hexstr[1] == 'x' || hexstr[1] == 'X')) + hexstr += 2; + + if (!strlen(hexstr)) { + printf("%s: Error: hex string is empty\n", __func__); + return -2; + } + + /* Trim leading zeros */ + while (*hexstr == '0') + hexstr++; + + cvmx_coremask_clear_all(pcm); + l = strlen(hexstr); + + /* If length is 0 then the hex string must be all zeros */ + if (l == 0) + return 0; + + for (i = 0; i < l; i++) { + if (isxdigit((int)hexstr[i]) == 0) { + printf("%s: Non-hex digit within hexstr\n", __func__); + return -2; + } + } + + lb = (l - 1) * 4; + if (hexstr[0] > '7') + lb += 4; + else if (hexstr[0] > '3') + lb += 3; + else if (hexstr[0] > '1') + lb += 2; + else + lb += 1; + if (lb > CVMX_MIPS_MAX_CORES) { + printf("%s: hexstr (%s) is too long\n", __func__, hexstr); + return -1; + } + + hldr_offset = 0; + hldr_xsz = 2 * sizeof(u64); + for (i = l; i > 0; i -= hldr_xsz) { + c = hexstr[i]; + hexstr[i] = 0; + j = i - hldr_xsz; + if (j < 0) + j = 0; + h = simple_strtoull(&hexstr[j], NULL, 16); + if (errno == EINVAL) { + printf("%s: strtou returns w/ EINVAL\n", __func__); + return -2; + } + pcm->coremask_bitmap[hldr_offset] = h; + hexstr[i] = c; + hldr_offset++; + } + + return 0; +} + +void cvmx_coremask_print(const struct cvmx_coremask *pcm) +{ + int i, j; + int start; + int found = 0; + + /* + * Print one node per line. Since the bitmap is stored LSB to MSB + * we reverse the order when printing. + */ + if (!octeon_has_feature(OCTEON_FEATURE_MULTINODE)) { + start = 0; + for (j = CVMX_COREMASK_MAX_CORES_PER_NODE - + CVMX_COREMASK_HLDRSZ; + j >= 0; j -= CVMX_COREMASK_HLDRSZ) { + if (pcm->coremask_bitmap[j / CVMX_COREMASK_HLDRSZ] != 0) + start = 1; + if (start) { + printf(" 0x%llx", + (u64)pcm->coremask_bitmap[j / + CVMX_COREMASK_HLDRSZ]); + } + } + + if (start) + found = 1; + + /* + * If the coremask is empty print so it is not + * confusing + */ + if (!found) + printf(""); + printf("\n"); + + return; + } + + for (i = 0; i < CVMX_MAX_USED_CORES_BMP; + i += CVMX_COREMASK_MAX_CORES_PER_NODE) { + printf("%s node %d:", i > 0 ? "\n" : "", + cvmx_coremask_core_to_node(i)); + start = 0; + + for (j = i + CVMX_COREMASK_MAX_CORES_PER_NODE - + CVMX_COREMASK_HLDRSZ; + j >= i; + j -= CVMX_COREMASK_HLDRSZ) { + /* Don't start printing until we get a non-zero word. */ + if (pcm->coremask_bitmap[j / CVMX_COREMASK_HLDRSZ] != 0) + start = 1; + + if (start) { + printf(" 0x%llx", (u64)pcm->coremask_bitmap[j / + CVMX_COREMASK_HLDRSZ]); + } + } + + if (start) + found = 1; + } + + i /= CVMX_COREMASK_HLDRSZ; + for (; i < CVMX_COREMASK_BMPSZ; i++) { + if (pcm->coremask_bitmap[i]) { + printf(" EXTRA GARBAGE[%i]: %016llx\n", i, + (u64)pcm->coremask_bitmap[i]); + } + } + + /* If the coremask is empty print so it is not confusing */ + if (!found) + printf(""); + + printf("\n"); +} diff --git a/arch/mips/mach-octeon/include/mach/cvmx-coremask.h b/arch/mips/mach-octeon/include/mach/cvmx-coremask.h new file mode 100644 index 0000000000..c34ff46d3a --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-coremask.h @@ -0,0 +1,752 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +/** + * Module to support operations on bitmap of cores. Coremask can be used to + * select a specific core, a group of cores, or all available cores, for + * initialization and differentiation of roles within a single shared binary + * executable image. + * + * The core numbers used in this file are the same value as what is found in + * the COP0_EBASE register and the rdhwr 0 instruction. + * + * For the CN78XX and other multi-node environments the core numbers are not + * contiguous. The core numbers for the CN78XX are as follows: + * + * Node 0: Cores 0 - 47 + * Node 1: Cores 128 - 175 + * Node 2: Cores 256 - 303 + * Node 3: Cores 384 - 431 + * + * The coremask environment generally tries to be node agnostic in order to + * provide future compatibility if more cores are added to future processors + * or more nodes are supported. + */ + +#ifndef __CVMX_COREMASK_H__ +#define __CVMX_COREMASK_H__ + +#include "cvmx-regs.h" + +/* bits per holder */ +#define CVMX_COREMASK_HLDRSZ ((int)(sizeof(u64) * 8)) + +/** Maximum allowed cores per node */ +#define CVMX_COREMASK_MAX_CORES_PER_NODE (1 << CVMX_NODE_NO_SHIFT) + +/** Maximum number of bits actually used in the coremask */ +#define CVMX_MAX_USED_CORES_BMP (1 << (CVMX_NODE_NO_SHIFT + CVMX_NODE_BITS)) + +/* the number of valid bits in and the mask of the most significant holder */ +#define CVMX_COREMASK_MSHLDR_NBITS \ + (CVMX_MIPS_MAX_CORES % CVMX_COREMASK_HLDRSZ) + +#define CVMX_COREMASK_MSHLDR_MASK \ + ((CVMX_COREMASK_MSHLDR_NBITS) ? \ + (((u64)1 << CVMX_COREMASK_MSHLDR_NBITS) - 1) : \ + ((u64)-1)) + +/* cvmx_coremask size in u64 */ +#define CVMX_COREMASK_BMPSZ \ + ((int)(CVMX_MIPS_MAX_CORES / CVMX_COREMASK_HLDRSZ + \ + (CVMX_COREMASK_MSHLDR_NBITS != 0))) + +#define CVMX_COREMASK_USED_BMPSZ \ + (CVMX_MAX_USED_CORES_BMP / CVMX_COREMASK_HLDRSZ) + +#define CVMX_COREMASK_BMP_NODE_CORE_IDX(node, core) \ + ((((node) << CVMX_NODE_NO_SHIFT) + (core)) / CVMX_COREMASK_HLDRSZ) +/** + * Maximum available coremask. + */ +#define CVMX_COREMASK_MAX \ + { { \ + 0x0000FFFFFFFFFFFF, 0, \ + 0x0000FFFFFFFFFFFF, 0, \ + 0x0000FFFFFFFFFFFF, 0, \ + 0x0000FFFFFFFFFFFF, 0, \ + 0, 0, \ + 0, 0, \ + 0, 0, \ + 0, 0} } + +/** + * Empty coremask + */ +#define CVMX_COREMASK_EMPTY \ + { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } + +struct cvmx_coremask { + u64 coremask_bitmap[CVMX_COREMASK_BMPSZ]; +}; + +/** + * Macro to iterate through all available cores in a coremask + * + * @param core - core variable to use to iterate + * @param pcm - pointer to core mask + * + * Use this like a for statement + */ +#define cvmx_coremask_for_each_core(core, pcm) \ + for ((core) = -1; \ + (core) = cvmx_coremask_next_core((core), pcm), \ + (core) >= 0;) + +/** + * Given a node and node mask, return the next available node. + * + * @param node starting node number + * @param node_mask node mask to use to find the next node + * + * @return next node number or -1 if no more nodes are available + */ +static inline int cvmx_coremask_next_node(int node, u8 node_mask) +{ + int next_offset; + + next_offset = __builtin_ffs(node_mask >> (node + 1)); + if (next_offset == 0) + return -1; + else + return node + next_offset; +} + +/** + * Iterate through all nodes in a node mask + * + * @param node node iterator variable + * @param node_mask mask to use for iterating + * + * Use this like a for statement + */ +#define cvmx_coremask_for_each_node(node, node_mask) \ + for ((node) = __builtin_ffs(node_mask) - 1; \ + (node) >= 0 && (node) < CVMX_MAX_NODES; \ + (node) = cvmx_coremask_next_node(node, node_mask)) + +/** + * Is ``core'' set in the coremask? + * + * @param pcm is the pointer to the coremask. + * @param core + * @return 1 if core is set and 0 if not. + */ +static inline int cvmx_coremask_is_core_set(const struct cvmx_coremask *pcm, + int core) +{ + int n, i; + + n = core % CVMX_COREMASK_HLDRSZ; + i = core / CVMX_COREMASK_HLDRSZ; + + return (pcm->coremask_bitmap[i] & ((u64)1 << n)) != 0; +} + +/** + * Is ``current core'' set in the coremask? + * + * @param pcm is the pointer to the coremask. + * @return 1 if core is set and 0 if not. + */ +static inline int cvmx_coremask_is_self_set(const struct cvmx_coremask *pcm) +{ + return cvmx_coremask_is_core_set(pcm, (int)cvmx_get_core_num()); +} + +/** + * Is coremask empty? + * @param pcm is the pointer to the coremask. + * @return 1 if *pcm is empty (all zeros), 0 if not empty. + */ +static inline int cvmx_coremask_is_empty(const struct cvmx_coremask *pcm) +{ + int i; + + for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++) + if (pcm->coremask_bitmap[i] != 0) + return 0; + + return 1; +} + +/** + * Set ``core'' in the coremask. + * + * @param pcm is the pointer to the coremask. + * @param core + * @return 0. + */ +static inline int cvmx_coremask_set_core(struct cvmx_coremask *pcm, int core) +{ + int n, i; + + n = core % CVMX_COREMASK_HLDRSZ; + i = core / CVMX_COREMASK_HLDRSZ; + pcm->coremask_bitmap[i] |= ((u64)1 << n); + + return 0; +} + +/** + * Set ``current core'' in the coremask. + * + * @param pcm is the pointer to the coremask. + * @return 0. + */ +static inline int cvmx_coremask_set_self(struct cvmx_coremask *pcm) +{ + return cvmx_coremask_set_core(pcm, (int)cvmx_get_core_num()); +} + +/** + * Clear ``core'' from the coremask. + * + * @param pcm is the pointer to the coremask. + * @param core + * @return 0. + */ +static inline int cvmx_coremask_clear_core(struct cvmx_coremask *pcm, int core) +{ + int n, i; + + n = core % CVMX_COREMASK_HLDRSZ; + i = core / CVMX_COREMASK_HLDRSZ; + pcm->coremask_bitmap[i] &= ~((u64)1 << n); + + return 0; +} + +/** + * Clear ``current core'' from the coremask. + * + * @param pcm is the pointer to the coremask. + * @return 0. + */ +static inline int cvmx_coremask_clear_self(struct cvmx_coremask *pcm) +{ + return cvmx_coremask_clear_core(pcm, cvmx_get_core_num()); +} + +/** + * Toggle ``core'' in the coremask. + * + * @param pcm is the pointer to the coremask. + * @param core + * @return 0. + */ +static inline int cvmx_coremask_toggle_core(struct cvmx_coremask *pcm, int core) +{ + int n, i; + + n = core % CVMX_COREMASK_HLDRSZ; + i = core / CVMX_COREMASK_HLDRSZ; + pcm->coremask_bitmap[i] ^= ((u64)1 << n); + + return 0; +} + +/** + * Toggle ``current core'' in the coremask. + * + * @param pcm is the pointer to the coremask. + * @return 0. + */ +static inline int cvmx_coremask_toggle_self(struct cvmx_coremask *pcm) +{ + return cvmx_coremask_toggle_core(pcm, cvmx_get_core_num()); +} + +/** + * Set the lower 64-bit of the coremask. + * @param pcm pointer to coremask + * @param coremask_64 64-bit coremask to apply to the first node (0) + */ +static inline void cvmx_coremask_set64(struct cvmx_coremask *pcm, + u64 coremask_64) +{ + pcm->coremask_bitmap[0] = coremask_64; +} + +/** + * Set the 64-bit of the coremask for a particular node. + * @param pcm pointer to coremask + * @param node node to set + * @param coremask_64 64-bit coremask to apply to the specified node + */ +static inline void cvmx_coremask_set64_node(struct cvmx_coremask *pcm, + u8 node, + u64 coremask_64) +{ + pcm->coremask_bitmap[CVMX_COREMASK_BMP_NODE_CORE_IDX(node, 0)] = + coremask_64; +} + +/** + * Gets the lower 64-bits of the coremask + * + * @param[in] pcm - pointer to coremask + * @return 64-bit coremask for the first node + */ +static inline u64 cvmx_coremask_get64(const struct cvmx_coremask *pcm) +{ + return pcm->coremask_bitmap[0]; +} + +/** + * Gets the lower 64-bits of the coremask for the specified node + * + * @param[in] pcm - pointer to coremask + * @param node - node to get coremask for + * @return 64-bit coremask for the first node + */ +static inline u64 cvmx_coremask_get64_node(const struct cvmx_coremask *pcm, + u8 node) +{ + return pcm->coremask_bitmap[CVMX_COREMASK_BMP_NODE_CORE_IDX(node, 0)]; +} + +/** + * Gets the lower 32-bits of the coremask for compatibility + * + * @param[in] pcm - pointer to coremask + * @return 32-bit coremask for the first node + * @deprecated This function is to maintain compatibility with older + * SDK applications and may disappear at some point. + * This function is not compatible with the CN78XX or any other + * Octeon device with more than 32 cores. + */ +static inline u32 cvmx_coremask_get32(const struct cvmx_coremask *pcm) +{ + return pcm->coremask_bitmap[0] & 0xffffffff; +} + +/* + * cvmx_coremask_cmp() returns an integer less than, equal to, or + * greater than zero if *pcm1 is found, respectively, to be less than, + * to match, or be greater than *pcm2. + */ +static inline int cvmx_coremask_cmp(const struct cvmx_coremask *pcm1, + const struct cvmx_coremask *pcm2) +{ + int i; + + /* Start from highest node for arithemtically correct result */ + for (i = CVMX_COREMASK_USED_BMPSZ - 1; i >= 0; i--) + if (pcm1->coremask_bitmap[i] != pcm2->coremask_bitmap[i]) { + return (pcm1->coremask_bitmap[i] > + pcm2->coremask_bitmap[i]) ? 1 : -1; + } + + return 0; +} + +/* + * cvmx_coremask_OPx(pcm1, pcm2[, pcm3]), where OPx can be + * - and + * - or + * - xor + * - not + * ... + * For binary operators, pcm3 <-- pcm1 OPX pcm2. + * For unaries, pcm2 <-- OPx pcm1. + */ +#define CVMX_COREMASK_BINARY_DEFUN(binary_op, op) \ + static inline int cvmx_coremask_##binary_op( \ + struct cvmx_coremask *pcm1, \ + const struct cvmx_coremask *pcm2, \ + const struct cvmx_coremask *pcm3) \ + { \ + int i; \ + \ + for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++) \ + pcm1->coremask_bitmap[i] = \ + pcm2->coremask_bitmap[i] \ + op \ + pcm3->coremask_bitmap[i]; \ + \ + return 0; \ + } + +#define CVMX_COREMASK_UNARY_DEFUN(unary_op, op) \ + static inline int cvmx_coremask_##unary_op( \ + struct cvmx_coremask *pcm1, \ + const struct cvmx_coremask *pcm2) \ + { \ + int i; \ + \ + for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++) \ + pcm1->coremask_bitmap[i] = \ + op \ + pcm2->coremask_bitmap[i]; \ + \ + return 0; \ + } + +/* cvmx_coremask_and(pcm1, pcm2, pcm3): pcm1 = pmc2 & pmc3 */ +CVMX_COREMASK_BINARY_DEFUN(and, &) +/* cvmx_coremask_or(pcm1, pcm2, pcm3): pcm1 = pmc2 | pmc3 */ +CVMX_COREMASK_BINARY_DEFUN(or, |) +/* cvmx_coremask_xor(pcm1, pcm2, pcm3): pcm1 = pmc2 ^ pmc3 */ +CVMX_COREMASK_BINARY_DEFUN(xor, ^) +/* cvmx_coremask_maskoff(pcm1, pcm2, pcm3): pcm1 = pmc2 & ~pmc3 */ +CVMX_COREMASK_BINARY_DEFUN(maskoff, & ~) +/* cvmx_coremask_not(pcm1, pcm2): pcm1 = ~pcm2 */ +CVMX_COREMASK_UNARY_DEFUN(not, ~) +/* cvmx_coremask_fill(pcm1, pcm2): pcm1 = -1 */ +CVMX_COREMASK_UNARY_DEFUN(fill, -1 |) +/* cvmx_coremask_clear(pcm1, pcm2): pcm1 = 0 */ +CVMX_COREMASK_UNARY_DEFUN(clear, 0 &) +/* cvmx_coremask_dup(pcm1, pcm2): pcm1 = pcm2 */ +CVMX_COREMASK_UNARY_DEFUN(dup, +) + +/* + * Macros using the unary functions defined w/ + * CVMX_COREMASK_UNARY_DEFUN + * - set *pcm to its complement + * - set all bits in *pcm to 0 + * - set all (valid) bits in *pcm to 1 + */ +#define cvmx_coremask_complement(pcm) cvmx_coremask_not(pcm, pcm) +/* On clear, even clear the unused bits */ +#define cvmx_coremask_clear_all(pcm) \ + *(pcm) = (struct cvmx_coremask)CVMX_COREMASK_EMPTY +#define cvmx_coremask_set_all(pcm) cvmx_coremask_fill(pcm, NULL) + +/* + * convert a string of hex digits to struct cvmx_coremask + * + * @param pcm + * @param hexstr can be + * - "[1-9A-Fa-f][0-9A-Fa-f]*", or + * - "-1" to set the bits for all the cores. + * return + * 0 for success, + * -1 for string too long (i.e., hexstr takes more bits than + * CVMX_MIPS_MAX_CORES), + * -2 for conversion problems from hex string to an unsigned + * long long, e.g., non-hex char in hexstr, and + * -3 for hexstr starting with '0'. + * NOTE: + * This function clears the bitmask in *pcm before the conversion. + */ +int cvmx_coremask_str2bmp(struct cvmx_coremask *pcm, char *hexstr); + +/* + * convert a struct cvmx_coremask to a string of hex digits + * + * @param pcm + * @param hexstr is "[1-9A-Fa-f][0-9A-Fa-f]*" + * + * return 0. + */ +int cvmx_coremask_bmp2str(const struct cvmx_coremask *pcm, char *hexstr); + +/* + * Returns the index of the lowest bit in a coremask holder. + */ +static inline int cvmx_coremask_lowest_bit(u64 h) +{ + return __builtin_ctzll(h); +} + +/* + * Returns the 0-based index of the highest bit in a coremask holder. + */ +static inline int cvmx_coremask_highest_bit(u64 h) +{ + return (64 - __builtin_clzll(h) - 1); +} + +/** + * Returns the last core within the coremask and -1 when the coremask + * is empty. + * + * @param[in] pcm - pointer to coremask + * @returns last core set in the coremask or -1 if all clear + * + */ +static inline int cvmx_coremask_get_last_core(const struct cvmx_coremask *pcm) +{ + int i; + int found = -1; + + for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++) { + if (pcm->coremask_bitmap[i]) + found = i; + } + + if (found == -1) + return -1; + + return found * CVMX_COREMASK_HLDRSZ + + cvmx_coremask_highest_bit(pcm->coremask_bitmap[found]); +} + +/** + * Returns the first core within the coremask and -1 when the coremask + * is empty. + * + * @param[in] pcm - pointer to coremask + * @returns first core set in the coremask or -1 if all clear + * + */ +static inline int cvmx_coremask_get_first_core(const struct cvmx_coremask *pcm) +{ + int i; + + for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++) + if (pcm->coremask_bitmap[i]) + break; + + if (i == CVMX_COREMASK_USED_BMPSZ) + return -1; + + return i * CVMX_COREMASK_HLDRSZ + + cvmx_coremask_lowest_bit(pcm->coremask_bitmap[i]); +} + +/** + * Given a core and coremask, return the next available core in the coremask + * or -1 if none are available. + * + * @param core - starting core to check (can be -1 for core 0) + * @param pcm - pointer to coremask to check for the next core. + * + * @return next core following the core parameter or -1 if no more cores. + */ +static inline int cvmx_coremask_next_core(int core, + const struct cvmx_coremask *pcm) +{ + int n, i; + + core++; + n = core % CVMX_COREMASK_HLDRSZ; + i = core / CVMX_COREMASK_HLDRSZ; + + if (pcm->coremask_bitmap[i] != 0) { + for (; n < CVMX_COREMASK_HLDRSZ; n++) + if (pcm->coremask_bitmap[i] & (1ULL << n)) + return ((i * CVMX_COREMASK_HLDRSZ) + n); + } + + for (i = i + 1; i < CVMX_COREMASK_USED_BMPSZ; i++) { + if (pcm->coremask_bitmap[i] != 0) + return (i * CVMX_COREMASK_HLDRSZ) + + cvmx_coremask_lowest_bit(pcm->coremask_bitmap[i]); + } + return -1; +} + +/** + * Compute coremask for count cores starting with start_core. + * Note that the coremask for multi-node processors may have + * gaps. + * + * @param[out] pcm pointer to core mask data structure + * @param start_core starting code number + * @param count number of cores + * + */ +static inline void cvmx_coremask_set_cores(struct cvmx_coremask *pcm, + unsigned int start_core, + unsigned int count) +{ + int node; + int core; /** Current core in node */ + int cores_in_node; + int i; + + assert(CVMX_MAX_CORES < CVMX_COREMASK_HLDRSZ); + node = start_core >> CVMX_NODE_NO_SHIFT; + core = start_core & ((1 << CVMX_NODE_NO_SHIFT) - 1); + assert(core < CVMX_MAX_CORES); + + cvmx_coremask_clear_all(pcm); + while (count > 0) { + if (count + core > CVMX_MAX_CORES) + cores_in_node = CVMX_MAX_CORES - core; + else + cores_in_node = count; + + i = CVMX_COREMASK_BMP_NODE_CORE_IDX(node, core); + pcm->coremask_bitmap[i] = ((1ULL << cores_in_node) - 1) << core; + count -= cores_in_node; + core = 0; + node++; + } +} + +/** + * Makes a copy of a coremask + * + * @param[out] dest - pointer to destination coremask + * @param[in] src - pointer to source coremask + */ +static inline void cvmx_coremask_copy(struct cvmx_coremask *dest, + const struct cvmx_coremask *src) +{ + memcpy(dest, src, sizeof(*dest)); +} + +/** + * Test to see if the specified core is first core in coremask. + * + * @param[in] pcm pointer to the coremask to test against + * @param[in] core core to check + * + * @return 1 if the core is first core in the coremask, 0 otherwise + * + */ +static inline int cvmx_coremask_is_core_first_core(const struct cvmx_coremask *pcm, + unsigned int core) +{ + int n, i; + + n = core / CVMX_COREMASK_HLDRSZ; + + for (i = 0; i < n; i++) + if (pcm->coremask_bitmap[i] != 0) + return 0; + + /* From now on we only care about the core number within an entry */ + core &= (CVMX_COREMASK_HLDRSZ - 1); + if (__builtin_ffsll(pcm->coremask_bitmap[n]) < (core + 1)) + return 0; + + return (__builtin_ffsll(pcm->coremask_bitmap[n]) == core + 1); +} + +/* + * NOTE: + * cvmx_coremask_is_first_core() was retired due to improper usage. + * For inquiring about the current core being the initializing + * core for an application, use cvmx_is_init_core(). + * For simply inquring if the current core is numerically + * lowest in a given mask, use : + * cvmx_coremask_is_core_first_core( pcm, dvmx_get_core_num()) + */ + +/** + * Returns the number of 1 bits set in a coremask + * + * @param[in] pcm - pointer to core mask + * + * @return number of bits set in the coremask + */ +static inline int cvmx_coremask_get_core_count(const struct cvmx_coremask *pcm) +{ + int i; + int count = 0; + + for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++) + count += __builtin_popcountll(pcm->coremask_bitmap[i]); + + return count; +} + +/** + * For multi-node systems, return the node a core belongs to. + * + * @param core - core number (0-1023) + * + * @return node number core belongs to + */ +static inline int cvmx_coremask_core_to_node(int core) +{ + return (core >> CVMX_NODE_NO_SHIFT) & CVMX_NODE_MASK; +} + +/** + * Given a core number on a multi-node system, return the core number for a + * particular node. + * + * @param core - global core number + * + * @returns core number local to the node. + */ +static inline int cvmx_coremask_core_on_node(int core) +{ + return (core & ((1 << CVMX_NODE_NO_SHIFT) - 1)); +} + +/** + * Returns if one coremask is a subset of another coremask + * + * @param main - main coremask to test + * @param subset - subset coremask to test + * + * @return 0 if the subset contains cores not in the main coremask or 1 if + * the subset is fully contained in the main coremask. + */ +static inline int cvmx_coremask_is_subset(const struct cvmx_coremask *main, + const struct cvmx_coremask *subset) +{ + int i; + + for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++) + if ((main->coremask_bitmap[i] & subset->coremask_bitmap[i]) != + subset->coremask_bitmap[i]) + return 0; + return 1; +} + +/** + * Returns if one coremask intersects another coremask + * + * @param c1 - main coremask to test + * @param c2 - subset coremask to test + * + * @return 1 if coremask c1 intersects coremask c2, 0 if they are exclusive + */ +static inline int cvmx_coremask_intersects(const struct cvmx_coremask *c1, + const struct cvmx_coremask *c2) +{ + int i; + + for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++) + if ((c1->coremask_bitmap[i] & c2->coremask_bitmap[i]) != 0) + return 1; + return 0; +} + +/** + * Masks a single node of a coremask + * + * @param pcm - coremask to mask [inout] + * @param node - node number to mask against + */ +static inline void cvmx_coremask_mask_node(struct cvmx_coremask *pcm, int node) +{ + int i; + + for (i = 0; i < CVMX_COREMASK_BMP_NODE_CORE_IDX(node, 0); i++) + pcm->coremask_bitmap[i] = 0; + + for (i = CVMX_COREMASK_BMP_NODE_CORE_IDX(node + 1, 0); + i < CVMX_COREMASK_USED_BMPSZ; i++) + pcm->coremask_bitmap[i] = 0; +} + +/** + * Prints out a coremask in the form of node X: 0x... 0x... + * + * @param[in] pcm - pointer to core mask + * + * @return nothing + */ +void cvmx_coremask_print(const struct cvmx_coremask *pcm); + +static inline void cvmx_coremask_dprint(const struct cvmx_coremask *pcm) +{ + if (IS_ENABLED(DEBUG)) + cvmx_coremask_print(pcm); +} + +struct cvmx_coremask *octeon_get_available_coremask(struct cvmx_coremask *pcm); + +int validate_coremask(struct cvmx_coremask *pcm); + +#endif /* __CVMX_COREMASK_H__ */ From patchwork Thu Aug 20 05:22:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Roese X-Patchwork-Id: 1348173 X-Patchwork-Delegate: daniel.schwierzeck@googlemail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=denx.de header.i=@denx.de header.a=rsa-sha256 header.s=phobos-20191101 header.b=Fe/jpdCn; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BXCkN693Zz9sR4 for ; Thu, 20 Aug 2020 15:24:12 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 7B2C2822C7; Thu, 20 Aug 2020 07:22:33 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=denx.de; s=phobos-20191101; t=1597900953; bh=qGyDiRjrZxH1L/zIUwhG/JWs1wy2nA0qmDs0eIVG9lM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=Fe/jpdCnE+qO2LAjdrM90RvYUBjKDv4Jv1RfOS30qv+ugvFQj8TaPCkn+8C/AGA2j Wk8Qs0YMDuED+nGRThQNv/jPBCOUIx2xB+Ia4Vh+ewN5pC9FEzTtO25jLK68Lqsx5+ g+vJ1PDJj+jxd42i7+q3gybIn3ZLErzxqmPWjR2ulJN6IghR+eyHjVbBFiieUl3YoR v80OHmG2s2WWZ6tmQuOB5d4NowDD045aGSZjdCS/rW/Aa6e6OthccqV2aFXD9xYkNm OB+peMGY9u0UxHkbujsSZoL/ZHk+v+K/wMdM7eXAQZ/dRfkwOW5wJmiRaZTsaJnEWF fqbhUWATdT+kw== Received: by phobos.denx.de (Postfix, from userid 109) id 68BD282258; Thu, 20 Aug 2020 07:22:23 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,KHOP_HELO_FCRDNS, SPF_HELO_NONE,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from mx2.mailbox.org (mx2a.mailbox.org [IPv6:2001:67c:2050:104:0:2:25:2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 46EC982258 for ; Thu, 20 Aug 2020 07:22:16 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=none smtp.mailfrom=sr@denx.de Received: from smtp1.mailbox.org (smtp1.mailbox.org [80.241.60.240]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by mx2.mailbox.org (Postfix) with ESMTPS id 1992CA15ED; Thu, 20 Aug 2020 07:22:16 +0200 (CEST) Received: from smtp1.mailbox.org ([80.241.60.240]) by gerste.heinlein-support.de (gerste.heinlein-support.de [91.198.250.173]) (amavisd-new, port 10030) with ESMTP id g_2qPvqbvYQj; Thu, 20 Aug 2020 07:22:10 +0200 (CEST) From: Stefan Roese To: u-boot@lists.denx.de Cc: daniel.schwierzeck@gmail.com, cchavva@marvell.com, awilliams@marvell.com Subject: [PATCH v1 08/10] mips: octeon: Add bootmem support Date: Thu, 20 Aug 2020 07:22:02 +0200 Message-Id: <20200820052204.2794174-9-sr@denx.de> In-Reply-To: <20200820052204.2794174-1-sr@denx.de> References: <20200820052204.2794174-1-sr@denx.de> MIME-Version: 1.0 X-MBO-SPAM-Probability: X-Rspamd-Score: -0.28 / 15.00 / 15.00 X-Rspamd-Queue-Id: 01A1C271 X-Rspamd-UID: 2e09b5 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean From: Aaron Williams This is needed for Linux booting, as the memory infos need to be passed in this bootmem format to the Linux kernel. Signed-off-by: Aaron Williams Signed-off-by: Stefan Roese --- arch/mips/mach-octeon/Makefile | 1 + arch/mips/mach-octeon/cvmx-bootmem.c | 1460 +++++++++++++++++ .../mach-octeon/include/mach/cvmx-bootmem.h | 533 ++++++ 3 files changed, 1994 insertions(+) create mode 100644 arch/mips/mach-octeon/cvmx-bootmem.c create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-bootmem.h diff --git a/arch/mips/mach-octeon/Makefile b/arch/mips/mach-octeon/Makefile index 5155f89a1e..e96f0deb1b 100644 --- a/arch/mips/mach-octeon/Makefile +++ b/arch/mips/mach-octeon/Makefile @@ -9,3 +9,4 @@ obj-y += clock.o obj-y += cpu.o obj-y += dram.o obj-y += cvmx-coremask.o +obj-y += cvmx-bootmem.o diff --git a/arch/mips/mach-octeon/cvmx-bootmem.c b/arch/mips/mach-octeon/cvmx-bootmem.c new file mode 100644 index 0000000000..80bb7ac6c8 --- /dev/null +++ b/arch/mips/mach-octeon/cvmx-bootmem.c @@ -0,0 +1,1460 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018-2020 Marvell International Ltd. + */ + +/* + * Simple allocate only memory allocator. Used to allocate memory at + * application start time. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define CVMX_MIPS32_SPACE_KSEG0 1L +#define CVMX_MIPS_SPACE_XKPHYS 2LL + +#define CVMX_ADD_SEG(seg, add) ((((u64)(seg)) << 62) | (add)) +#define CVMX_ADD_SEG32(seg, add) (((u32)(seg) << 31) | (u32)(add)) + +/** + * This is the physical location of a struct cvmx_bootmem_desc + * structure in Octeon's memory. Note that dues to addressing + * limits or runtime environment it might not be possible to + * create a C pointer to this structure. + */ +static u64 cvmx_bootmem_desc_addr; + +/** + * This macro returns the size of a member of a structure. + * Logically it is the same as "sizeof(s::field)" in C++, but + * C lacks the "::" operator. + */ +#define SIZEOF_FIELD(s, field) sizeof(((s *)NULL)->field) + +/** + * This macro returns a member of the struct cvmx_bootmem_desc + * structure. These members can't be directly addressed as + * they might be in memory not directly reachable. In the case + * where bootmem is compiled with LINUX_HOST, the structure + * itself might be located on a remote Octeon. The argument + * "field" is the member name of the struct cvmx_bootmem_desc to read. + * Regardless of the type of the field, the return type is always + * a u64. + */ +#define CVMX_BOOTMEM_DESC_GET_FIELD(field) \ + __cvmx_bootmem_desc_get(cvmx_bootmem_desc_addr, \ + offsetof(struct cvmx_bootmem_desc, field), \ + SIZEOF_FIELD(struct cvmx_bootmem_desc, field)) + +/** + * This macro writes a member of the struct cvmx_bootmem_desc + * structure. These members can't be directly addressed as + * they might be in memory not directly reachable. In the case + * where bootmem is compiled with LINUX_HOST, the structure + * itself might be located on a remote Octeon. The argument + * "field" is the member name of the struct cvmx_bootmem_desc to write. + */ +#define CVMX_BOOTMEM_DESC_SET_FIELD(field, value) \ + __cvmx_bootmem_desc_set(cvmx_bootmem_desc_addr, \ + offsetof(struct cvmx_bootmem_desc, field), \ + SIZEOF_FIELD(struct cvmx_bootmem_desc, field), \ + value) + +/** + * This macro returns a member of the + * struct cvmx_bootmem_named_block_desc structure. These members can't + * be directly addressed as they might be in memory not directly + * reachable. In the case where bootmem is compiled with + * LINUX_HOST, the structure itself might be located on a remote + * Octeon. The argument "field" is the member name of the + * struct cvmx_bootmem_named_block_desc to read. Regardless of the type + * of the field, the return type is always a u64. The "addr" + * parameter is the physical address of the structure. + */ +#define CVMX_BOOTMEM_NAMED_GET_FIELD(addr, field) \ + __cvmx_bootmem_desc_get(addr, \ + offsetof(struct cvmx_bootmem_named_block_desc, field), \ + SIZEOF_FIELD(struct cvmx_bootmem_named_block_desc, field)) + +/** + * This macro writes a member of the struct cvmx_bootmem_named_block_desc + * structure. These members can't be directly addressed as + * they might be in memory not directly reachable. In the case + * where bootmem is compiled with LINUX_HOST, the structure + * itself might be located on a remote Octeon. The argument + * "field" is the member name of the + * struct cvmx_bootmem_named_block_desc to write. The "addr" parameter + * is the physical address of the structure. + */ +#define CVMX_BOOTMEM_NAMED_SET_FIELD(addr, field, value) \ + __cvmx_bootmem_desc_set(addr, \ + offsetof(struct cvmx_bootmem_named_block_desc, field), \ + SIZEOF_FIELD(struct cvmx_bootmem_named_block_desc, field), \ + value) + +/** + * This function is the implementation of the get macros defined + * for individual structure members. The argument are generated + * by the macros inorder to read only the needed memory. + * + * @param base 64bit physical address of the complete structure + * @param offset Offset from the beginning of the structure to the member being + * accessed. + * @param size Size of the structure member. + * + * @return Value of the structure member promoted into a u64. + */ +static inline u64 __cvmx_bootmem_desc_get(u64 base, int offset, + int size) +{ + base = (1ull << 63) | (base + offset); + switch (size) { + case 4: + return cvmx_read64_uint32(base); + case 8: + return cvmx_read64_uint64(base); + default: + return 0; + } +} + +/** + * This function is the implementation of the set macros defined + * for individual structure members. The argument are generated + * by the macros in order to write only the needed memory. + * + * @param base 64bit physical address of the complete structure + * @param offset Offset from the beginning of the structure to the member being + * accessed. + * @param size Size of the structure member. + * @param value Value to write into the structure + */ +static inline void __cvmx_bootmem_desc_set(u64 base, int offset, int size, + u64 value) +{ + base = (1ull << 63) | (base + offset); + switch (size) { + case 4: + cvmx_write64_uint32(base, value); + break; + case 8: + cvmx_write64_uint64(base, value); + break; + default: + break; + } +} + +/** + * This function returns the address of the bootmem descriptor lock. + * + * @return 64-bit address in KSEG0 of the bootmem descriptor block + */ +static inline u64 __cvmx_bootmem_get_lock_addr(void) +{ + return (1ull << 63) | + (cvmx_bootmem_desc_addr + offsetof(struct cvmx_bootmem_desc, lock)); +} + +/** + * This function retrieves the string name of a named block. It is + * more complicated than a simple memcpy() since the named block + * descriptor may not be directly accessible. + * + * @param addr Physical address of the named block descriptor + * @param str String to receive the named block string name + * @param len Length of the string buffer, which must match the length + * stored in the bootmem descriptor. + */ +static void CVMX_BOOTMEM_NAMED_GET_NAME(u64 addr, char *str, int len) +{ + int l = len; + char *ptr = str; + + addr |= (1ull << 63); + addr += offsetof(struct cvmx_bootmem_named_block_desc, name); + while (l) { + /* + * With big-endian in memory byte order, this gives uniform + * results for the CPU in either big or Little endian mode. + */ + u64 blob = cvmx_read64_uint64(addr); + int sa = 56; + + addr += sizeof(u64); + while (l && sa >= 0) { + *ptr++ = (char)(blob >> sa); + l--; + sa -= 8; + } + } + str[len] = 0; +} + +/** + * This function stores the string name of a named block. It is + * more complicated than a simple memcpy() since the named block + * descriptor may not be directly accessible. + * + * @param addr Physical address of the named block descriptor + * @param str String to store into the named block string name + * @param len Length of the string buffer, which must match the length + * stored in the bootmem descriptor. + */ +void CVMX_BOOTMEM_NAMED_SET_NAME(u64 addr, const char *str, int len) +{ + int l = len; + + addr |= (1ull << 63); + addr += offsetof(struct cvmx_bootmem_named_block_desc, name); + + while (l) { + /* + * With big-endian in memory byte order, this gives uniform + * results for the CPU in either big or Little endian mode. + */ + u64 blob = 0; + int sa = 56; + + while (l && sa >= 0) { + u64 c = (u8)(*str++); + + l--; + if (l == 0) + c = 0; + blob |= c << sa; + sa -= 8; + } + cvmx_write64_uint64(addr, blob); + addr += sizeof(u64); + } +} + +/* See header file for descriptions of functions */ + +/* + * Wrapper functions are provided for reading/writing the size and next block + * values as these may not be directly addressible (in 32 bit applications, for + * instance.) + * + * Offsets of data elements in bootmem list, must match + * struct cvmx_bootmem_block_header + */ +#define NEXT_OFFSET 0 +#define SIZE_OFFSET 8 + +static void cvmx_bootmem_phy_set_size(u64 addr, u64 size) +{ + cvmx_write64_uint64((addr + SIZE_OFFSET) | (1ull << 63), size); +} + +static void cvmx_bootmem_phy_set_next(u64 addr, u64 next) +{ + cvmx_write64_uint64((addr + NEXT_OFFSET) | (1ull << 63), next); +} + +static u64 cvmx_bootmem_phy_get_size(u64 addr) +{ + return cvmx_read64_uint64((addr + SIZE_OFFSET) | (1ull << 63)); +} + +static u64 cvmx_bootmem_phy_get_next(u64 addr) +{ + return cvmx_read64_uint64((addr + NEXT_OFFSET) | (1ull << 63)); +} + +/** + * Check the version information on the bootmem descriptor + * + * @param exact_match + * Exact major version to check against. A zero means + * check that the version supports named blocks. + * + * @return Zero if the version is correct. Negative if the version is + * incorrect. Failures also cause a message to be displayed. + */ +static int __cvmx_bootmem_check_version(int exact_match) +{ + int major_version; + + major_version = CVMX_BOOTMEM_DESC_GET_FIELD(major_version); + if (major_version > 3 || + (exact_match && major_version) != exact_match) { + debug("ERROR: Incompatible bootmem descriptor version: %d.%d at addr: 0x%llx\n", + major_version, + (int)CVMX_BOOTMEM_DESC_GET_FIELD(minor_version), + CAST_ULL(cvmx_bootmem_desc_addr)); + return -1; + } else { + return 0; + } +} + +/** + * Get the low level bootmem descriptor lock. If no locking + * is specified in the flags, then nothing is done. + * + * @param flags CVMX_BOOTMEM_FLAG_NO_LOCKING means this functions should do + * nothing. This is used to support nested bootmem calls. + */ +static inline void __cvmx_bootmem_lock(u32 flags) +{ + if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) { + /* + * Unfortunately we can't use the normal cvmx-spinlock code as + * the memory for the bootmem descriptor may be not accessible + * by a C pointer. We use a 64bit XKPHYS address to access the + * memory directly + */ + u64 lock_addr = (1ull << 63) | + (cvmx_bootmem_desc_addr + offsetof(struct cvmx_bootmem_desc, + lock)); + unsigned int tmp; + + __asm__ __volatile__(".set noreorder\n" + "1: ll %[tmp], 0(%[addr])\n" + " bnez %[tmp], 1b\n" + " li %[tmp], 1\n" + " sc %[tmp], 0(%[addr])\n" + " beqz %[tmp], 1b\n" + " nop\n" + ".set reorder\n" + : [tmp] "=&r"(tmp) + : [addr] "r"(lock_addr) + : "memory"); + } +} + +/** + * Release the low level bootmem descriptor lock. If no locking + * is specified in the flags, then nothing is done. + * + * @param flags CVMX_BOOTMEM_FLAG_NO_LOCKING means this functions should do + * nothing. This is used to support nested bootmem calls. + */ +static inline void __cvmx_bootmem_unlock(u32 flags) +{ + if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) { + /* + * Unfortunately we can't use the normal cvmx-spinlock code as + * the memory for the bootmem descriptor may be not accessible + * by a C pointer. We use a 64bit XKPHYS address to access the + * memory directly + */ + u64 lock_addr = __cvmx_bootmem_get_lock_addr(); + + CVMX_SYNCW; + __asm__ __volatile__("sw $0, 0(%[addr])\n" + : : [addr] "r"(lock_addr) + : "memory"); + CVMX_SYNCW; + } +} + +/* + * Some of the cvmx-bootmem functions dealing with C pointers are not + * supported when we are compiling for CVMX_BUILD_FOR_LINUX_HOST. This + * ifndef removes these functions when they aren't needed. + * + * This functions takes an address range and adjusts it as necessary + * to match the ABI that is currently being used. This is required to + * ensure that bootmem_alloc* functions only return valid pointers for + * 32 bit ABIs + */ +static int __cvmx_validate_mem_range(u64 *min_addr_ptr, + u64 *max_addr_ptr) +{ + u64 max_phys = (1ull << 29) - 0x10; /* KSEG0 */ + + *min_addr_ptr = min_t(u64, max_t(u64, *min_addr_ptr, 0x0), max_phys); + if (!*max_addr_ptr) { + *max_addr_ptr = max_phys; + } else { + *max_addr_ptr = max_t(u64, min_t(u64, *max_addr_ptr, + max_phys), 0x0); + } + + return 0; +} + +u64 cvmx_bootmem_phy_alloc_range(u64 size, u64 alignment, + u64 min_addr, u64 max_addr) +{ + s64 address; + + __cvmx_validate_mem_range(&min_addr, &max_addr); + address = cvmx_bootmem_phy_alloc(size, min_addr, max_addr, + alignment, 0); + if (address > 0) + return address; + else + return 0; +} + +void *cvmx_bootmem_alloc_range(u64 size, u64 alignment, + u64 min_addr, u64 max_addr) +{ + s64 address; + + __cvmx_validate_mem_range(&min_addr, &max_addr); + address = cvmx_bootmem_phy_alloc(size, min_addr, max_addr, + alignment, 0); + + if (address > 0) + return cvmx_phys_to_ptr(address); + else + return NULL; +} + +void *cvmx_bootmem_alloc_address(u64 size, u64 address, + u64 alignment) +{ + return cvmx_bootmem_alloc_range(size, alignment, address, + address + size); +} + +void *cvmx_bootmem_alloc_node(u64 node, u64 size, u64 alignment) +{ + return cvmx_bootmem_alloc_range(size, alignment, + node << CVMX_NODE_MEM_SHIFT, + ((node + 1) << CVMX_NODE_MEM_SHIFT) - 1); +} + +void *cvmx_bootmem_alloc(u64 size, u64 alignment) +{ + return cvmx_bootmem_alloc_range(size, alignment, 0, 0); +} + +void *cvmx_bootmem_alloc_named_range_once(u64 size, u64 min_addr, + u64 max_addr, u64 align, + const char *name, + void (*init)(void *)) +{ + u64 named_block_desc_addr; + void *ptr; + s64 addr; + + __cvmx_bootmem_lock(0); + + __cvmx_validate_mem_range(&min_addr, &max_addr); + named_block_desc_addr = + cvmx_bootmem_phy_named_block_find(name, + CVMX_BOOTMEM_FLAG_NO_LOCKING); + + if (named_block_desc_addr) { + addr = CVMX_BOOTMEM_NAMED_GET_FIELD(named_block_desc_addr, + base_addr); + __cvmx_bootmem_unlock(0); + return cvmx_phys_to_ptr(addr); + } + + addr = cvmx_bootmem_phy_named_block_alloc(size, min_addr, max_addr, + align, name, + CVMX_BOOTMEM_FLAG_NO_LOCKING); + + if (addr < 0) { + __cvmx_bootmem_unlock(0); + return NULL; + } + ptr = cvmx_phys_to_ptr(addr); + + if (init) + init(ptr); + else + memset(ptr, 0, size); + + __cvmx_bootmem_unlock(0); + return ptr; +} + +void *cvmx_bootmem_alloc_named_range_flags(u64 size, u64 min_addr, + u64 max_addr, u64 align, + const char *name, u32 flags) +{ + s64 addr; + + __cvmx_validate_mem_range(&min_addr, &max_addr); + addr = cvmx_bootmem_phy_named_block_alloc(size, min_addr, max_addr, + align, name, flags); + if (addr >= 0) + return cvmx_phys_to_ptr(addr); + else + return NULL; +} + +void *cvmx_bootmem_alloc_named_range(u64 size, u64 min_addr, + u64 max_addr, u64 align, + const char *name) +{ + return cvmx_bootmem_alloc_named_range_flags(size, min_addr, max_addr, + align, name, 0); +} + +void *cvmx_bootmem_alloc_named_address(u64 size, u64 address, + const char *name) +{ + return cvmx_bootmem_alloc_named_range(size, address, address + size, + 0, name); +} + +void *cvmx_bootmem_alloc_named(u64 size, u64 alignment, + const char *name) +{ + return cvmx_bootmem_alloc_named_range(size, 0, 0, alignment, name); +} + +void *cvmx_bootmem_alloc_named_flags(u64 size, u64 alignment, + const char *name, u32 flags) +{ + return cvmx_bootmem_alloc_named_range_flags(size, 0, 0, alignment, + name, flags); +} + +int cvmx_bootmem_free_named(const char *name) +{ + return cvmx_bootmem_phy_named_block_free(name, 0); +} + +/** + * Find a named block with flags + * + * @param name is the block name + * @param flags indicates the need to use locking during search + * @return pointer to named block descriptor + * + * Note: this function returns a pointer to a static structure, + * and is therefore not re-entrant. + * Making this function re-entrant will break backward compatibility. + */ +const struct cvmx_bootmem_named_block_desc * +__cvmx_bootmem_find_named_block_flags(const char *name, u32 flags) +{ + static struct cvmx_bootmem_named_block_desc desc; + u64 named_addr = cvmx_bootmem_phy_named_block_find(name, flags); + + if (named_addr) { + desc.base_addr = CVMX_BOOTMEM_NAMED_GET_FIELD(named_addr, + base_addr); + desc.size = CVMX_BOOTMEM_NAMED_GET_FIELD(named_addr, size); + strncpy(desc.name, name, sizeof(desc.name)); + desc.name[sizeof(desc.name) - 1] = 0; + return &desc; + } else { + return NULL; + } +} + +const struct cvmx_bootmem_named_block_desc * +cvmx_bootmem_find_named_block(const char *name) +{ + return __cvmx_bootmem_find_named_block_flags(name, 0); +} + +void cvmx_bootmem_print_named(void) +{ + cvmx_bootmem_phy_named_block_print(); +} + +int cvmx_bootmem_init(u64 mem_desc_addr) +{ + if (!cvmx_bootmem_desc_addr) + cvmx_bootmem_desc_addr = mem_desc_addr; + + return 0; +} + +u64 cvmx_bootmem_available_mem(u64 min_block_size) +{ + return cvmx_bootmem_phy_available_mem(min_block_size); +} + +/* + * The cvmx_bootmem_phy* functions below return 64 bit physical + * addresses, and expose more features that the cvmx_bootmem_functions + * above. These are required for full memory space access in 32 bit + * applications, as well as for using some advance features. Most + * applications should not need to use these. + */ + +s64 cvmx_bootmem_phy_alloc(u64 req_size, u64 address_min, + u64 address_max, u64 alignment, + u32 flags) +{ + u64 head_addr, ent_addr, ent_size; + u64 target_ent_addr = 0, target_prev_addr = 0; + u64 target_size = ~0ull; + u64 free_start, free_end; + u64 next_addr, prev_addr = 0; + u64 new_ent_addr = 0, new_ent_size; + u64 desired_min_addr, usable_max; + u64 align, align_mask; + + debug("%s: req_size: 0x%llx, min_addr: 0x%llx, max_addr: 0x%llx, align: 0x%llx\n", + __func__, CAST_ULL(req_size), CAST_ULL(address_min), + CAST_ULL(address_max), CAST_ULL(alignment)); + + if (__cvmx_bootmem_check_version(0)) + return -1; + + /* + * Do a variety of checks to validate the arguments. The + * allocator code will later assume that these checks have + * been made. We validate that the requested constraints are + * not self-contradictory before we look through the list of + * available memory + */ + + /* 0 is not a valid req_size for this allocator */ + if (!req_size) + return -1; + + /* Round req_size up to multiple of minimum alignment bytes */ + req_size = (req_size + (CVMX_BOOTMEM_ALIGNMENT_SIZE - 1)) & + ~(CVMX_BOOTMEM_ALIGNMENT_SIZE - 1); + + /* Make sure alignment is power of 2, and at least the minimum */ + for (align = CVMX_BOOTMEM_ALIGNMENT_SIZE; + align < (1ull << 48); + align <<= 1) { + if (align >= alignment) + break; + } + + align_mask = ~(align - 1); + + /* + * Adjust address minimum based on requested alignment (round + * up to meet alignment). Do this here so we can reject + * impossible requests up front. (NOP for address_min == 0) + */ + address_min = (address_min + (align - 1)) & align_mask; + + /* + * Convert !0 address_min and 0 address_max to special case of + * range that specifies an exact memory block to allocate. Do + * this before other checks and adjustments so that this + * tranformation will be validated + */ + if (address_min && !address_max) + address_max = address_min + req_size; + else if (!address_min && !address_max) + address_max = ~0ull; /* If no limits given, use max */ + + /* + * Reject inconsistent args. We have adjusted these, so this + * may fail due to our internal changes even if this check + * would pass for the values the user supplied. + */ + if (req_size > address_max - address_min) + return -1; + + __cvmx_bootmem_lock(flags); + + /* Walk through the list entries to find the right fit */ + head_addr = CVMX_BOOTMEM_DESC_GET_FIELD(head_addr); + + for (ent_addr = head_addr; + ent_addr != 0ULL && ent_addr < address_max; + prev_addr = ent_addr, + ent_addr = cvmx_bootmem_phy_get_next(ent_addr)) { + /* Raw free block size */ + ent_size = cvmx_bootmem_phy_get_size(ent_addr); + next_addr = cvmx_bootmem_phy_get_next(ent_addr); + + /* Validate the free list ascending order */ + if (ent_size < CVMX_BOOTMEM_ALIGNMENT_SIZE || + (next_addr && ent_addr > next_addr)) { + debug("ERROR: %s: bad free list ent: %#llx, next: %#llx\n", + __func__, CAST_ULL(ent_addr), + CAST_ULL(next_addr)); + goto error_out; + } + + /* adjust free block edges for alignment */ + free_start = (ent_addr + align - 1) & align_mask; + free_end = (ent_addr + ent_size) & align_mask; + + /* check that free block is large enough */ + if ((free_start + req_size) > free_end) + continue; + + /* check that desired start is within the free block */ + if (free_end < address_min || free_start > address_max) + continue; + if ((free_end - address_min) < req_size) + continue; + if ((address_max - free_start) < req_size) + continue; + + /* Found usebale free block */ + target_ent_addr = ent_addr; + target_prev_addr = prev_addr; + target_size = ent_size; + + /* Continue looking for highest/best block that fits */ + } + + /* Bail if the search has resulted in no eligible free blocks */ + if (target_ent_addr == 0) { + debug("%s: eligible free block not found\n", __func__); + goto error_out; + } + + /* Found the free block to allocate from */ + ent_addr = target_ent_addr; + prev_addr = target_prev_addr; + ent_size = target_size; + + debug("%s: using free block at %#010llx size %#llx\n", + __func__, CAST_ULL(ent_addr), CAST_ULL(ent_size)); + + /* Always allocate from the end of a free block */ + usable_max = min_t(u64, address_max, ent_addr + ent_size); + desired_min_addr = usable_max - req_size; + desired_min_addr &= align_mask; + + /* Split current free block into up to 3 free blocks */ + + /* Check for head room */ + if (desired_min_addr > ent_addr) { + /* Create a new free block at the allocation address */ + new_ent_addr = desired_min_addr; + new_ent_size = ent_size - (desired_min_addr - ent_addr); + + cvmx_bootmem_phy_set_next(new_ent_addr, + cvmx_bootmem_phy_get_next(ent_addr)); + cvmx_bootmem_phy_set_size(new_ent_addr, new_ent_size); + + /* Split out head room into a new free block */ + ent_size -= new_ent_size; + cvmx_bootmem_phy_set_next(ent_addr, new_ent_addr); + cvmx_bootmem_phy_set_size(ent_addr, ent_size); + + debug("%s: splitting head, addr %#llx size %#llx\n", + __func__, CAST_ULL(ent_addr), CAST_ULL(ent_size)); + + /* Make the allocation target the current free block */ + prev_addr = ent_addr; + ent_addr = new_ent_addr; + ent_size = new_ent_size; + } + + /* Check for tail room */ + if ((desired_min_addr + req_size) < (ent_addr + ent_size)) { + new_ent_addr = ent_addr + req_size; + new_ent_size = ent_size - req_size; + + /* Create a new free block from tail room */ + cvmx_bootmem_phy_set_next(new_ent_addr, + cvmx_bootmem_phy_get_next(ent_addr)); + cvmx_bootmem_phy_set_size(new_ent_addr, new_ent_size); + + debug("%s: splitting tail, addr %#llx size %#llx\n", + __func__, CAST_ULL(new_ent_addr), CAST_ULL(new_ent_size)); + + /* Adjust the current block to exclude tail room */ + ent_size = ent_size - new_ent_size; + cvmx_bootmem_phy_set_next(ent_addr, new_ent_addr); + cvmx_bootmem_phy_set_size(ent_addr, ent_size); + } + + /* The current free block IS the allocation target */ + if (desired_min_addr != ent_addr || ent_size != req_size) + debug("ERROR: %s: internal error - addr %#llx %#llx size %#llx %#llx\n", + __func__, CAST_ULL(desired_min_addr), CAST_ULL(ent_addr), + CAST_ULL(ent_size), CAST_ULL(req_size)); + + /* Remove the current free block from list */ + if (prev_addr) { + cvmx_bootmem_phy_set_next(prev_addr, + cvmx_bootmem_phy_get_next(ent_addr)); + } else { + /* head of list being returned, so update head ptr */ + CVMX_BOOTMEM_DESC_SET_FIELD(head_addr, + cvmx_bootmem_phy_get_next(ent_addr)); + } + + __cvmx_bootmem_unlock(flags); + debug("%s: allocated size: %#llx, at addr: %#010llx\n", + __func__, + CAST_ULL(req_size), + CAST_ULL(desired_min_addr)); + + return desired_min_addr; + +error_out: + /* Requested memory not found or argument error */ + __cvmx_bootmem_unlock(flags); + return -1; +} + +int __cvmx_bootmem_phy_free(u64 phy_addr, u64 size, u32 flags) +{ + u64 cur_addr; + u64 prev_addr = 0; /* zero is invalid */ + int retval = 0; + + debug("%s addr: %#llx, size: %#llx\n", __func__, + CAST_ULL(phy_addr), CAST_ULL(size)); + + if (__cvmx_bootmem_check_version(0)) + return 0; + + /* 0 is not a valid size for this allocator */ + if (!size || !phy_addr) + return 0; + + /* Round size up to mult of minimum alignment bytes */ + size = (size + (CVMX_BOOTMEM_ALIGNMENT_SIZE - 1)) & + ~(CVMX_BOOTMEM_ALIGNMENT_SIZE - 1); + + __cvmx_bootmem_lock(flags); + cur_addr = CVMX_BOOTMEM_DESC_GET_FIELD(head_addr); + if (cur_addr == 0 || phy_addr < cur_addr) { + /* add at front of list - special case with changing head ptr */ + if (cur_addr && phy_addr + size > cur_addr) + goto bootmem_free_done; /* error, overlapping section */ + else if (phy_addr + size == cur_addr) { + /* Add to front of existing first block */ + cvmx_bootmem_phy_set_next(phy_addr, + cvmx_bootmem_phy_get_next(cur_addr)); + cvmx_bootmem_phy_set_size(phy_addr, + cvmx_bootmem_phy_get_size(cur_addr) + size); + CVMX_BOOTMEM_DESC_SET_FIELD(head_addr, phy_addr); + + } else { + /* New block before first block */ + /* OK if cur_addr is 0 */ + cvmx_bootmem_phy_set_next(phy_addr, cur_addr); + cvmx_bootmem_phy_set_size(phy_addr, size); + CVMX_BOOTMEM_DESC_SET_FIELD(head_addr, phy_addr); + } + retval = 1; + goto bootmem_free_done; + } + + /* Find place in list to add block */ + while (cur_addr && phy_addr > cur_addr) { + prev_addr = cur_addr; + cur_addr = cvmx_bootmem_phy_get_next(cur_addr); + } + + if (!cur_addr) { + /* + * We have reached the end of the list, add on to end, checking + * to see if we need to combine with last block + */ + if (prev_addr + cvmx_bootmem_phy_get_size(prev_addr) == phy_addr) { + cvmx_bootmem_phy_set_size(prev_addr, + cvmx_bootmem_phy_get_size(prev_addr) + size); + } else { + cvmx_bootmem_phy_set_next(prev_addr, phy_addr); + cvmx_bootmem_phy_set_size(phy_addr, size); + cvmx_bootmem_phy_set_next(phy_addr, 0); + } + retval = 1; + goto bootmem_free_done; + } else { + /* + * insert between prev and cur nodes, checking for merge with + * either/both + */ + if (prev_addr + cvmx_bootmem_phy_get_size(prev_addr) == phy_addr) { + /* Merge with previous */ + cvmx_bootmem_phy_set_size(prev_addr, + cvmx_bootmem_phy_get_size(prev_addr) + size); + if (phy_addr + size == cur_addr) { + /* Also merge with current */ + cvmx_bootmem_phy_set_size(prev_addr, + cvmx_bootmem_phy_get_size(cur_addr) + + cvmx_bootmem_phy_get_size(prev_addr)); + cvmx_bootmem_phy_set_next(prev_addr, + cvmx_bootmem_phy_get_next(cur_addr)); + } + retval = 1; + goto bootmem_free_done; + } else if (phy_addr + size == cur_addr) { + /* Merge with current */ + cvmx_bootmem_phy_set_size(phy_addr, + cvmx_bootmem_phy_get_size(cur_addr) + size); + cvmx_bootmem_phy_set_next(phy_addr, + cvmx_bootmem_phy_get_next(cur_addr)); + cvmx_bootmem_phy_set_next(prev_addr, phy_addr); + retval = 1; + goto bootmem_free_done; + } + + /* It is a standalone block, add in between prev and cur */ + cvmx_bootmem_phy_set_size(phy_addr, size); + cvmx_bootmem_phy_set_next(phy_addr, cur_addr); + cvmx_bootmem_phy_set_next(prev_addr, phy_addr); + } + retval = 1; + +bootmem_free_done: + __cvmx_bootmem_unlock(flags); + return retval; +} + +void cvmx_bootmem_phy_list_print(void) +{ + u64 addr; + + addr = CVMX_BOOTMEM_DESC_GET_FIELD(head_addr); + printf("\n\n\nPrinting bootmem block list, descriptor: 0x%llx, head is 0x%llx\n", + CAST_ULL(cvmx_bootmem_desc_addr), CAST_ULL(addr)); + printf("Descriptor version: %d.%d\n", + (int)CVMX_BOOTMEM_DESC_GET_FIELD(major_version), + (int)CVMX_BOOTMEM_DESC_GET_FIELD(minor_version)); + if (CVMX_BOOTMEM_DESC_GET_FIELD(major_version) > 3) + debug("Warning: Bootmem descriptor version is newer than expected\n"); + + if (!addr) + printf("mem list is empty!\n"); + + while (addr) { + printf("Block address: 0x%08llx, size: 0x%08llx, next: 0x%08llx\n", CAST_ULL(addr), + CAST_ULL(cvmx_bootmem_phy_get_size(addr)), + CAST_ULL(cvmx_bootmem_phy_get_next(addr))); + addr = cvmx_bootmem_phy_get_next(addr); + } + printf("\n\n"); +} + +u64 cvmx_bootmem_phy_available_mem(u64 min_block_size) +{ + u64 addr; + + u64 available_mem = 0; + + __cvmx_bootmem_lock(0); + addr = CVMX_BOOTMEM_DESC_GET_FIELD(head_addr); + while (addr) { + if (cvmx_bootmem_phy_get_size(addr) >= min_block_size) + available_mem += cvmx_bootmem_phy_get_size(addr); + addr = cvmx_bootmem_phy_get_next(addr); + } + __cvmx_bootmem_unlock(0); + return available_mem; +} + +u64 cvmx_bootmem_phy_named_block_find(const char *name, u32 flags) +{ + u64 result = 0; + + debug("%s: %s\n", __func__, name); + + __cvmx_bootmem_lock(flags); + if (!__cvmx_bootmem_check_version(3)) { + int i; + u64 named_block_array_addr = + CVMX_BOOTMEM_DESC_GET_FIELD(named_block_array_addr); + int num_blocks = + CVMX_BOOTMEM_DESC_GET_FIELD(named_block_num_blocks); + int name_length = + CVMX_BOOTMEM_DESC_GET_FIELD(named_block_name_len); + u64 named_addr = named_block_array_addr; + + for (i = 0; i < num_blocks; i++) { + u64 named_size = + CVMX_BOOTMEM_NAMED_GET_FIELD(named_addr, size); + if (name && named_size) { + char name_tmp[name_length + 1]; + + CVMX_BOOTMEM_NAMED_GET_NAME(named_addr, + name_tmp, + name_length); + if (!strncmp(name, name_tmp, name_length)) { + result = named_addr; + break; + } + } else if (!name && !named_size) { + result = named_addr; + break; + } + + named_addr += + sizeof(struct cvmx_bootmem_named_block_desc); + } + } + __cvmx_bootmem_unlock(flags); + return result; +} + +int cvmx_bootmem_phy_named_block_free(const char *name, u32 flags) +{ + u64 named_block_addr; + + if (__cvmx_bootmem_check_version(3)) + return 0; + + debug("%s: %s\n", __func__, name); + + /* + * Take lock here, as name lookup/block free/name free need to be + * atomic + */ + __cvmx_bootmem_lock(flags); + + named_block_addr = cvmx_bootmem_phy_named_block_find(name, + CVMX_BOOTMEM_FLAG_NO_LOCKING); + if (named_block_addr) { + u64 named_addr = + CVMX_BOOTMEM_NAMED_GET_FIELD(named_block_addr, + base_addr); + u64 named_size = + CVMX_BOOTMEM_NAMED_GET_FIELD(named_block_addr, size); + + debug("%s: %s, base: 0x%llx, size: 0x%llx\n", + __func__, name, CAST_ULL(named_addr), + CAST_ULL(named_size)); + + __cvmx_bootmem_phy_free(named_addr, named_size, + CVMX_BOOTMEM_FLAG_NO_LOCKING); + + /* Set size to zero to indicate block not used. */ + CVMX_BOOTMEM_NAMED_SET_FIELD(named_block_addr, size, 0); + } + + __cvmx_bootmem_unlock(flags); + return !!named_block_addr; /* 0 on failure, 1 on success */ +} + +s64 cvmx_bootmem_phy_named_block_alloc(u64 size, u64 min_addr, + u64 max_addr, + u64 alignment, const char *name, + u32 flags) +{ + s64 addr_allocated; + u64 named_block_desc_addr; + + debug("%s: size: 0x%llx, min: 0x%llx, max: 0x%llx, align: 0x%llx, name: %s\n", + __func__, CAST_ULL(size), CAST_ULL(min_addr), CAST_ULL(max_addr), + CAST_ULL(alignment), name); + + if (__cvmx_bootmem_check_version(3)) + return -1; + + /* + * Take lock here, as name lookup/block alloc/name add need to be + * atomic + */ + __cvmx_bootmem_lock(flags); + + named_block_desc_addr = + cvmx_bootmem_phy_named_block_find(name, flags | + CVMX_BOOTMEM_FLAG_NO_LOCKING); + if (named_block_desc_addr) { + __cvmx_bootmem_unlock(flags); + return -1; + } + + /* Get pointer to first available named block descriptor */ + named_block_desc_addr = + cvmx_bootmem_phy_named_block_find(NULL, flags | + CVMX_BOOTMEM_FLAG_NO_LOCKING); + if (!named_block_desc_addr) { + __cvmx_bootmem_unlock(flags); + return -1; + } + + /* + * Round size up to mult of minimum alignment bytes + * We need the actual size allocated to allow for blocks to be + * coallesced when they are freed. The alloc routine does the + * same rounding up on all allocations. + */ + size = (size + (CVMX_BOOTMEM_ALIGNMENT_SIZE - 1)) & + ~(CVMX_BOOTMEM_ALIGNMENT_SIZE - 1); + + addr_allocated = cvmx_bootmem_phy_alloc(size, min_addr, max_addr, + alignment, + flags | CVMX_BOOTMEM_FLAG_NO_LOCKING); + if (addr_allocated >= 0) { + CVMX_BOOTMEM_NAMED_SET_FIELD(named_block_desc_addr, base_addr, + addr_allocated); + CVMX_BOOTMEM_NAMED_SET_FIELD(named_block_desc_addr, size, size); + CVMX_BOOTMEM_NAMED_SET_NAME(named_block_desc_addr, name, + CVMX_BOOTMEM_DESC_GET_FIELD(named_block_name_len)); + } + + __cvmx_bootmem_unlock(flags); + return addr_allocated; +} + +void cvmx_bootmem_phy_named_block_print(void) +{ + int i; + int printed = 0; + + u64 named_block_array_addr = + CVMX_BOOTMEM_DESC_GET_FIELD(named_block_array_addr); + int num_blocks = CVMX_BOOTMEM_DESC_GET_FIELD(named_block_num_blocks); + int name_length = CVMX_BOOTMEM_DESC_GET_FIELD(named_block_name_len); + u64 named_block_addr = named_block_array_addr; + + debug("%s: desc addr: 0x%llx\n", + __func__, CAST_ULL(cvmx_bootmem_desc_addr)); + + if (__cvmx_bootmem_check_version(3)) + return; + + printf("List of currently allocated named bootmem blocks:\n"); + for (i = 0; i < num_blocks; i++) { + u64 named_size = + CVMX_BOOTMEM_NAMED_GET_FIELD(named_block_addr, size); + if (named_size) { + char name_tmp[name_length + 1]; + u64 named_addr = + CVMX_BOOTMEM_NAMED_GET_FIELD(named_block_addr, + base_addr); + CVMX_BOOTMEM_NAMED_GET_NAME(named_block_addr, name_tmp, + name_length); + printed++; + printf("Name: %s, address: 0x%08llx, size: 0x%08llx, index: %d\n", name_tmp, + CAST_ULL(named_addr), + CAST_ULL(named_size), i); + } + named_block_addr += + sizeof(struct cvmx_bootmem_named_block_desc); + } + + if (!printed) + printf("No named bootmem blocks exist.\n"); +} + +s64 cvmx_bootmem_phy_mem_list_init(u64 mem_size, + u32 low_reserved_bytes, + struct cvmx_bootmem_desc *desc_buffer) +{ + u64 cur_block_addr; + s64 addr; + int i; + + debug("%s (arg desc ptr: %p, cvmx_bootmem_desc: 0x%llx)\n", + __func__, desc_buffer, CAST_ULL(cvmx_bootmem_desc_addr)); + + /* + * Descriptor buffer needs to be in 32 bit addressable space to be + * compatible with 32 bit applications + */ + if (!desc_buffer) { + debug("ERROR: no memory for cvmx_bootmem descriptor provided\n"); + return 0; + } + + if (mem_size > OCTEON_MAX_PHY_MEM_SIZE) { + mem_size = OCTEON_MAX_PHY_MEM_SIZE; + debug("ERROR: requested memory size too large, truncating to maximum size\n"); + } + + if (cvmx_bootmem_desc_addr) + return 1; + + /* Initialize cvmx pointer to descriptor */ + cvmx_bootmem_init(cvmx_ptr_to_phys(desc_buffer)); + + /* Fill the bootmem descriptor */ + CVMX_BOOTMEM_DESC_SET_FIELD(lock, 0); + CVMX_BOOTMEM_DESC_SET_FIELD(flags, 0); + CVMX_BOOTMEM_DESC_SET_FIELD(head_addr, 0); + CVMX_BOOTMEM_DESC_SET_FIELD(major_version, CVMX_BOOTMEM_DESC_MAJ_VER); + CVMX_BOOTMEM_DESC_SET_FIELD(minor_version, CVMX_BOOTMEM_DESC_MIN_VER); + CVMX_BOOTMEM_DESC_SET_FIELD(app_data_addr, 0); + CVMX_BOOTMEM_DESC_SET_FIELD(app_data_size, 0); + + /* + * Set up global pointer to start of list, exclude low 64k for exception + * vectors, space for global descriptor + */ + cur_block_addr = (OCTEON_DDR0_BASE + low_reserved_bytes); + + if (mem_size <= OCTEON_DDR0_SIZE) { + __cvmx_bootmem_phy_free(cur_block_addr, + mem_size - low_reserved_bytes, 0); + goto frees_done; + } + + __cvmx_bootmem_phy_free(cur_block_addr, + OCTEON_DDR0_SIZE - low_reserved_bytes, 0); + + mem_size -= OCTEON_DDR0_SIZE; + + /* Add DDR2 block next if present */ + if (mem_size > OCTEON_DDR1_SIZE) { + __cvmx_bootmem_phy_free(OCTEON_DDR1_BASE, OCTEON_DDR1_SIZE, 0); + __cvmx_bootmem_phy_free(OCTEON_DDR2_BASE, + mem_size - OCTEON_DDR1_SIZE, 0); + } else { + __cvmx_bootmem_phy_free(OCTEON_DDR1_BASE, mem_size, 0); + } +frees_done: + + /* Initialize the named block structure */ + CVMX_BOOTMEM_DESC_SET_FIELD(named_block_name_len, CVMX_BOOTMEM_NAME_LEN); + CVMX_BOOTMEM_DESC_SET_FIELD(named_block_num_blocks, + CVMX_BOOTMEM_NUM_NAMED_BLOCKS); + CVMX_BOOTMEM_DESC_SET_FIELD(named_block_array_addr, 0); + + /* Allocate this near the top of the low 256 MBytes of memory */ + addr = cvmx_bootmem_phy_alloc(CVMX_BOOTMEM_NUM_NAMED_BLOCKS * + sizeof(struct cvmx_bootmem_named_block_desc), + 0, 0x10000000, 0, + CVMX_BOOTMEM_FLAG_END_ALLOC); + if (addr >= 0) + CVMX_BOOTMEM_DESC_SET_FIELD(named_block_array_addr, addr); + + debug("%s: named_block_array_addr: 0x%llx)\n", + __func__, CAST_ULL(addr)); + + if (addr < 0) { + debug("FATAL ERROR: unable to allocate memory for bootmem descriptor!\n"); + return 0; + } + + for (i = 0; i < CVMX_BOOTMEM_NUM_NAMED_BLOCKS; i++) { + CVMX_BOOTMEM_NAMED_SET_FIELD(addr, base_addr, 0); + CVMX_BOOTMEM_NAMED_SET_FIELD(addr, size, 0); + addr += sizeof(struct cvmx_bootmem_named_block_desc); + } + + return 1; +} + +s64 cvmx_bootmem_phy_mem_list_init_multi(u8 node_mask, + u32 mem_sizes[], + u32 low_reserved_bytes, + struct cvmx_bootmem_desc *desc_buffer) +{ + u64 cur_block_addr; + u64 mem_size; + s64 addr; + int i; + int node; + u64 node_base; /* Make u64 to reduce type casting */ + + mem_sizes[0] = gd->ram_size / (1024 * 1024); + + debug("cvmx_bootmem_phy_mem_list_init (arg desc ptr: %p, cvmx_bootmem_desc: 0x%llx)\n", + desc_buffer, CAST_ULL(cvmx_bootmem_desc_addr)); + + /* + * Descriptor buffer needs to be in 32 bit addressable space to be + * compatible with 32 bit applications + */ + if (!desc_buffer) { + debug("ERROR: no memory for cvmx_bootmem descriptor provided\n"); + return 0; + } + + cvmx_coremask_for_each_node(node, node_mask) { + if ((mem_sizes[node] * 1024 * 1024) > OCTEON_MAX_PHY_MEM_SIZE) { + mem_sizes[node] = OCTEON_MAX_PHY_MEM_SIZE / + (1024 * 1024); + debug("ERROR node#%lld: requested memory size too large, truncating to maximum size\n", + CAST_ULL(node)); + } + } + + if (cvmx_bootmem_desc_addr) + return 1; + + /* Initialize cvmx pointer to descriptor */ + cvmx_bootmem_init(cvmx_ptr_to_phys(desc_buffer)); + + /* Fill the bootmem descriptor */ + CVMX_BOOTMEM_DESC_SET_FIELD(lock, 0); + CVMX_BOOTMEM_DESC_SET_FIELD(flags, 0); + CVMX_BOOTMEM_DESC_SET_FIELD(head_addr, 0); + CVMX_BOOTMEM_DESC_SET_FIELD(major_version, CVMX_BOOTMEM_DESC_MAJ_VER); + CVMX_BOOTMEM_DESC_SET_FIELD(minor_version, CVMX_BOOTMEM_DESC_MIN_VER); + CVMX_BOOTMEM_DESC_SET_FIELD(app_data_addr, 0); + CVMX_BOOTMEM_DESC_SET_FIELD(app_data_size, 0); + + cvmx_coremask_for_each_node(node, node_mask) { + if (node != 0) /* do not reserve memory on remote nodes */ + low_reserved_bytes = 0; + + mem_size = (u64)mem_sizes[node] * (1024 * 1024); /* MBytes */ + + /* + * Set up global pointer to start of list, exclude low 64k + * for exception vectors, space for global descriptor + */ + + node_base = (u64)node << CVMX_NODE_MEM_SHIFT; + cur_block_addr = (OCTEON_DDR0_BASE + low_reserved_bytes) | + node_base; + + if (mem_size <= OCTEON_DDR0_SIZE) { + __cvmx_bootmem_phy_free(cur_block_addr, + mem_size - low_reserved_bytes, + 0); + continue; + } + + __cvmx_bootmem_phy_free(cur_block_addr, + OCTEON_DDR0_SIZE - low_reserved_bytes, + 0); + + mem_size -= OCTEON_DDR0_SIZE; + + /* Add DDR2 block next if present */ + if (mem_size > OCTEON_DDR1_SIZE) { + __cvmx_bootmem_phy_free(OCTEON_DDR1_BASE | + node_base, + OCTEON_DDR1_SIZE, 0); + __cvmx_bootmem_phy_free(OCTEON_DDR2_BASE | + node_base, + mem_size - OCTEON_DDR1_SIZE, 0); + } else { + __cvmx_bootmem_phy_free(OCTEON_DDR1_BASE | + node_base, + mem_size, 0); + } + } + + debug("%s: Initialize the named block\n", __func__); + + /* Initialize the named block structure */ + CVMX_BOOTMEM_DESC_SET_FIELD(named_block_name_len, CVMX_BOOTMEM_NAME_LEN); + CVMX_BOOTMEM_DESC_SET_FIELD(named_block_num_blocks, + CVMX_BOOTMEM_NUM_NAMED_BLOCKS); + CVMX_BOOTMEM_DESC_SET_FIELD(named_block_array_addr, 0); + + /* Allocate this near the top of the low 256 MBytes of memory */ + addr = cvmx_bootmem_phy_alloc(CVMX_BOOTMEM_NUM_NAMED_BLOCKS * + sizeof(struct cvmx_bootmem_named_block_desc), + 0, 0x10000000, 0, + CVMX_BOOTMEM_FLAG_END_ALLOC); + if (addr >= 0) + CVMX_BOOTMEM_DESC_SET_FIELD(named_block_array_addr, addr); + + debug("cvmx_bootmem_phy_mem_list_init: named_block_array_addr: 0x%llx)\n", + CAST_ULL(addr)); + + if (addr < 0) { + debug("FATAL ERROR: unable to allocate memory for bootmem descriptor!\n"); + return 0; + } + + for (i = 0; i < CVMX_BOOTMEM_NUM_NAMED_BLOCKS; i++) { + CVMX_BOOTMEM_NAMED_SET_FIELD(addr, base_addr, 0); + CVMX_BOOTMEM_NAMED_SET_FIELD(addr, size, 0); + addr += sizeof(struct cvmx_bootmem_named_block_desc); + } + + // test-only: DEBUG ifdef??? + cvmx_bootmem_phy_list_print(); + + return 1; +} + +int cvmx_bootmem_reserve_memory(u64 start_addr, u64 size, + const char *name, u32 flags) +{ + u64 addr; + int rc = 1; + static unsigned int block_num; + char block_name[CVMX_BOOTMEM_NAME_LEN]; + + debug("%s: start %#llx, size: %#llx, name: %s, flags:%#x)\n", + __func__, CAST_ULL(start_addr), CAST_ULL(size), name, flags); + + if (__cvmx_bootmem_check_version(3)) + return 0; + + addr = CVMX_BOOTMEM_DESC_GET_FIELD(head_addr); + if (!addr) + return 0; + + if (!name) + name = "__cvmx_bootmem_reserved"; + + while (addr && rc) { + u64 block_size = cvmx_bootmem_phy_get_size(addr); + u64 reserve_size = 0; + + if (addr >= start_addr && addr < start_addr + size) { + reserve_size = size - (addr - start_addr); + if (block_size < reserve_size) + reserve_size = block_size; + } else if (start_addr > addr && + start_addr < (addr + block_size)) { + reserve_size = block_size - (start_addr - addr); + } + + if (reserve_size) { + snprintf(block_name, sizeof(block_name), + "%.32s_%012llx_%u", + name, (unsigned long long)start_addr, + (unsigned int)block_num); + + debug("%s: Reserving 0x%llx bytes at address 0x%llx with name %s\n", + __func__, CAST_ULL(reserve_size), + CAST_ULL(addr), block_name); + + if (cvmx_bootmem_phy_named_block_alloc(reserve_size, + addr, 0, 0, + block_name, + flags) == -1) { + debug("%s: Failed to reserve 0x%llx bytes at address 0x%llx\n", + __func__, CAST_ULL(reserve_size), + (unsigned long long)addr); + rc = 0; + break; + } + + debug("%s: Reserved 0x%llx bytes at address 0x%llx with name %s\n", + __func__, CAST_ULL(reserve_size), + CAST_ULL(addr), block_name); + } + + addr = cvmx_bootmem_phy_get_next(addr); + block_num++; + } + + return rc; +} + +void cvmx_bootmem_lock(void) +{ + __cvmx_bootmem_lock(0); +} + +void cvmx_bootmem_unlock(void) +{ + __cvmx_bootmem_unlock(0); +} + +void *__cvmx_phys_addr_to_ptr(u64 phys, int size) +{ + void *tmp; + + if (sizeof(void *) == 8) { + tmp = CASTPTR(void, CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, phys)); + } else { + u32 phy32 = (u32)(phys & 0x7fffffffULL); + + tmp = CASTPTR(void, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, + phy32)); + } + + return tmp; +} + +void *__cvmx_bootmem_internal_get_desc_ptr(void) +{ + return cvmx_phys_to_ptr(cvmx_bootmem_desc_addr); +} diff --git a/arch/mips/mach-octeon/include/mach/cvmx-bootmem.h b/arch/mips/mach-octeon/include/mach/cvmx-bootmem.h new file mode 100644 index 0000000000..d60668c9ad --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-bootmem.h @@ -0,0 +1,533 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +/** + * @file + * Simple allocate only memory allocator. Used to allocate memory at application + * start time. + */ + +#ifndef __CVMX_BOOTMEM_H__ +#define __CVMX_BOOTMEM_H__ + +/* Must be multiple of 8, changing breaks ABI */ +#define CVMX_BOOTMEM_NAME_LEN 128 +/* Can change without breaking ABI */ +#define CVMX_BOOTMEM_NUM_NAMED_BLOCKS 64 +/* minimum alignment of bootmem alloced blocks */ +#define CVMX_BOOTMEM_ALIGNMENT_SIZE (16ull) + +/* Flags for cvmx_bootmem_phy_mem* functions */ +/* Allocate from end of block instead of beginning */ +#define CVMX_BOOTMEM_FLAG_END_ALLOC (1 << 0) +#define CVMX_BOOTMEM_FLAG_NO_LOCKING (1 << 1) /* Don't do any locking. */ + +/* Real physical addresses of memory regions */ +#define OCTEON_DDR0_BASE (0x0ULL) +#define OCTEON_DDR0_SIZE (0x010000000ULL) +#define OCTEON_DDR1_BASE ((OCTEON_IS_OCTEON2() || OCTEON_IS_OCTEON3()) \ + ? 0x20000000ULL : 0x410000000ULL) +#define OCTEON_DDR1_SIZE (0x010000000ULL) +#define OCTEON_DDR2_BASE ((OCTEON_IS_OCTEON2() || OCTEON_IS_OCTEON3()) \ + ? 0x30000000ULL : 0x20000000ULL) +#define OCTEON_DDR2_SIZE ((OCTEON_IS_OCTEON2() || OCTEON_IS_OCTEON3()) \ + ? 0x7d0000000ULL : 0x3e0000000ULL) +#define OCTEON_MAX_PHY_MEM_SIZE ((OCTEON_IS_MODEL(OCTEON_CN68XX)) \ + ? 128 * 1024 * 1024 * 1024ULL \ + : (OCTEON_IS_OCTEON2()) \ + ? 32 * 1024 * 1024 * 1024ull \ + : (OCTEON_IS_OCTEON3()) \ + ? 512 * 1024 * 1024 * 1024ULL \ + : 16 * 1024 * 1024 * 1024ULL) + +/* + * First bytes of each free physical block of memory contain this structure, + * which is used to maintain the free memory list. Since the bootloader is + * only 32 bits, there is a union providing 64 and 32 bit versions. The + * application init code converts addresses to 64 bit addresses before the + * application starts. + */ +struct cvmx_bootmem_block_header { + /* Note: these are referenced from assembly routines in the bootloader, + * so this structure should not be changed without changing those + * routines as well. + */ + u64 next_block_addr; + u64 size; + +}; + +/* + * Structure for named memory blocks + * Number of descriptors + * available can be changed without affecting compatibility, + * but name length changes require a bump in the bootmem + * descriptor version + * Note: This structure must be naturally 64 bit aligned, as a single + * memory image will be used by both 32 and 64 bit programs. + */ +struct cvmx_bootmem_named_block_desc { + u64 base_addr; /* Base address of named block */ + /* + * Size actually allocated for named block (may differ from requested) + */ + u64 size; + char name[CVMX_BOOTMEM_NAME_LEN]; /* name of named block */ +}; + +/* Current descriptor versions */ +/* CVMX bootmem descriptor major version */ +#define CVMX_BOOTMEM_DESC_MAJ_VER 3 +/* CVMX bootmem descriptor minor version */ +#define CVMX_BOOTMEM_DESC_MIN_VER 0 + +/* + * First three members of cvmx_bootmem_desc_t are left in original + * positions for backwards compatibility. + */ +struct cvmx_bootmem_desc { + /* Linux compatible proxy for __BIG_ENDIAN */ + u32 lock; /* spinlock to control access to list */ + u32 flags; /* flags for indicating various conditions */ + u64 head_addr; + + /* incremented changed when incompatible changes made */ + u32 major_version; + /* + * incremented changed when compatible changes made, reset to + * zero when major incremented + */ + u32 minor_version; + u64 app_data_addr; + u64 app_data_size; + + /* number of elements in named blocks array */ + u32 named_block_num_blocks; + /* length of name array in bootmem blocks */ + u32 named_block_name_len; + /* address of named memory block descriptors */ + u64 named_block_array_addr; +}; + +/** + * Initialize the boot alloc memory structures. This is + * normally called inside of cvmx_user_app_init() + * + * @param mem_desc_addr Address of the free memory list + * @return + */ +int cvmx_bootmem_init(u64 mem_desc_addr); + +/** + * Allocate a block of memory from the free list that was passed + * to the application by the bootloader. + * This is an allocate-only algorithm, so freeing memory is not possible. + * + * @param size Size in bytes of block to allocate + * @param alignment Alignment required - must be power of 2 + * + * @return pointer to block of memory, NULL on error + */ +void *cvmx_bootmem_alloc(u64 size, u64 alignment); + +/** + * Allocate a block of memory from the free list that was passed + * to the application by the bootloader from a specific node. + * This is an allocate-only algorithm, so freeing memory is not possible. + * + * @param node The node to allocate memory from + * @param size Size in bytes of block to allocate + * @param alignment Alignment required - must be power of 2 + * + * @return pointer to block of memory, NULL on error + */ +void *cvmx_bootmem_alloc_node(u64 node, u64 size, u64 alignment); + +/** + * Allocate a block of memory from the free list that was + * passed to the application by the bootloader at a specific + * address. This is an allocate-only algorithm, so + * freeing memory is not possible. Allocation will fail if + * memory cannot be allocated at the specified address. + * + * @param size Size in bytes of block to allocate + * @param address Physical address to allocate memory at. If this + * memory is not available, the allocation fails. + * @param alignment Alignment required - must be power of 2 + * @return pointer to block of memory, NULL on error + */ +void *cvmx_bootmem_alloc_address(u64 size, u64 address, + u64 alignment); + +/** + * Allocate a block of memory from the free list that was + * passed to the application by the bootloader within a specified + * address range. This is an allocate-only algorithm, so + * freeing memory is not possible. Allocation will fail if + * memory cannot be allocated in the requested range. + * + * @param size Size in bytes of block to allocate + * @param min_addr defines the minimum address of the range + * @param max_addr defines the maximum address of the range + * @param alignment Alignment required - must be power of 2 + * @return pointer to block of memory, NULL on error + */ +void *cvmx_bootmem_alloc_range(u64 size, u64 alignment, + u64 min_addr, u64 max_addr); + +/** + * Allocate a block of memory from the free list that was passed + * to the application by the bootloader, and assign it a name in the + * global named block table. (part of the cvmx_bootmem_descriptor_t structure) + * Named blocks can later be freed. + * + * @param size Size in bytes of block to allocate + * @param alignment Alignment required - must be power of 2 + * @param name name of block - must be less than CVMX_BOOTMEM_NAME_LEN bytes + * + * @return pointer to block of memory, NULL on error + */ +void *cvmx_bootmem_alloc_named(u64 size, u64 alignment, + const char *name); + +/** + * Allocate a block of memory from the free list that was passed + * to the application by the bootloader, and assign it a name in the + * global named block table. (part of the cvmx_bootmem_descriptor_t structure) + * Named blocks can later be freed. + * + * @param size Size in bytes of block to allocate + * @param alignment Alignment required - must be power of 2 + * @param name name of block - must be less than CVMX_BOOTMEM_NAME_LEN bytes + * @param flags Flags to control options for the allocation. + * + * @return pointer to block of memory, NULL on error + */ +void *cvmx_bootmem_alloc_named_flags(u64 size, u64 alignment, + const char *name, u32 flags); + +/** + * Allocate a block of memory from the free list that was passed + * to the application by the bootloader, and assign it a name in the + * global named block table. (part of the cvmx_bootmem_descriptor_t structure) + * Named blocks can later be freed. + * + * @param size Size in bytes of block to allocate + * @param address Physical address to allocate memory at. If this + * memory is not available, the allocation fails. + * @param name name of block - must be less than CVMX_BOOTMEM_NAME_LEN bytes + * + * @return pointer to block of memory, NULL on error + */ +void *cvmx_bootmem_alloc_named_address(u64 size, u64 address, + const char *name); + +/** + * Allocate a block of memory from a specific range of the free list + * that was passed to the application by the bootloader, and assign it + * a name in the global named block table. (part of the + * cvmx_bootmem_descriptor_t structure) Named blocks can later be + * freed. If request cannot be satisfied within the address range + * specified, NULL is returned + * + * @param size Size in bytes of block to allocate + * @param min_addr minimum address of range + * @param max_addr maximum address of range + * @param align Alignment of memory to be allocated. (must be a power of 2) + * @param name name of block - must be less than CVMX_BOOTMEM_NAME_LEN bytes + * + * @return pointer to block of memory, NULL on error + */ +void *cvmx_bootmem_alloc_named_range(u64 size, u64 min_addr, + u64 max_addr, u64 align, + const char *name); + +/** + * Allocate if needed a block of memory from a specific range of the + * free list that was passed to the application by the bootloader, and + * assign it a name in the global named block table. (part of the + * cvmx_bootmem_descriptor_t structure) Named blocks can later be + * freed. If the requested name block is already allocated, return + * the pointer to block of memory. If request cannot be satisfied + * within the address range specified, NULL is returned + * + * @param size Size in bytes of block to allocate + * @param min_addr minimum address of range + * @param max_addr maximum address of range + * @param align Alignment of memory to be allocated. (must be a power of 2) + * @param name name of block - must be less than CVMX_BOOTMEM_NAME_LEN bytes + * @param init Initialization function + * + * The initialization function is optional, if omitted the named block + * is initialized to all zeros when it is created, i.e. once. + * + * @return pointer to block of memory, NULL on error + */ +void *cvmx_bootmem_alloc_named_range_once(u64 size, + u64 min_addr, + u64 max_addr, + u64 align, + const char *name, + void (*init)(void *)); + +/** + * Allocate all free memory starting at the start address. This is used to + * prevent any free blocks from later being allocated within the reserved space. + * Note that any memory allocated with this function cannot be later freed. + * + * @param start_addr Starting address to reserve + * @param size Size in bytes to reserve starting at start_addr + * @param name Name to assign to reserved blocks + * @param flags Flags to use when reserving memory + * + * @return 0 on failure, + * !0 on success + */ +int cvmx_bootmem_reserve_memory(u64 start_addr, u64 size, + const char *name, u32 flags); + +/** + * Frees a previously allocated named bootmem block. + * + * @param name name of block to free + * + * @return 0 on failure, + * !0 on success + */ +int cvmx_bootmem_free_named(const char *name); + +/** + * Finds a named bootmem block by name. + * + * @param name name of block to free + * + * @return pointer to named block descriptor on success + * 0 on failure + */ +const struct cvmx_bootmem_named_block_desc * +cvmx_bootmem_find_named_block(const char *name); + +/** + * Returns the size of available memory in bytes, only + * counting blocks that are at least as big as the minimum block + * size. + * + * @param min_block_size + * Minimum block size to count in total. + * + * @return Number of bytes available for allocation that meet the + * block size requirement + */ +u64 cvmx_bootmem_available_mem(u64 min_block_size); + +/** + * Prints out the list of named blocks that have been allocated + * along with their addresses and sizes. + * This is primarily used for debugging purposes + */ +void cvmx_bootmem_print_named(void); + +/** + * Allocates a block of physical memory from the free list, at + * (optional) requested address and alignment. + * + * @param req_size size of region to allocate. All requests are + * rounded up to be a multiple CVMX_BOOTMEM_ALIGNMENT_SIZE bytes size + * + * @param address_min Minimum address that block can occupy. + * + * @param address_max Specifies the maximum address_min (inclusive) + * that the allocation can use. + * + * @param alignment Requested alignment of the block. If this + * alignment cannot be met, the allocation fails. + * This must be a power of 2. (Note: Alignment of + * CVMX_BOOTMEM_ALIGNMENT_SIZE bytes is required, and + * internally enforced. Requested alignments of less + * than CVMX_BOOTMEM_ALIGNMENT_SIZE are set to + * CVMX_BOOTMEM_ALIGNMENT_SIZE.) + * @param flags Flags to control options for the allocation. + * + * @return physical address of block allocated, or -1 on failure + */ +s64 cvmx_bootmem_phy_alloc(u64 req_size, u64 address_min, u64 address_max, + u64 alignment, u32 flags); + +/** + * Allocates a named block of physical memory from the free list, at + * (optional) requested address and alignment. + * + * @param size size of region to allocate. All requests are rounded + * up to be a multiple CVMX_BOOTMEM_ALIGNMENT_SIZE bytes size + * + * @param min_addr Minimum address that block can occupy. + * + * @param max_addr Specifies the maximum address_min (inclusive) that + * the allocation can use. + * + * @param alignment Requested alignment of the block. If this + * alignment cannot be met, the allocation fails. + * This must be a power of 2. (Note: Alignment of + * CVMX_BOOTMEM_ALIGNMENT_SIZE bytes is required, and + * internally enforced. Requested alignments of less + * than CVMX_BOOTMEM_ALIGNMENT_SIZE are set to + * CVMX_BOOTMEM_ALIGNMENT_SIZE.) + * + * @param name name to assign to named block + * + * @param flags Flags to control options for the allocation. + * + * @return physical address of block allocated, or -1 on failure + */ +s64 cvmx_bootmem_phy_named_block_alloc(u64 size, u64 min_addr, u64 max_addr, + u64 alignment, const char *name, + u32 flags); + +/** + * Finds a named memory block by name. + * Also used for finding an unused entry in the named block table. + * + * @param name Name of memory block to find. If NULL pointer given, + * then finds unused descriptor, if available. + * + * @param flags Flags to control options for the allocation. + * + * @return Physical address of the memory block descriptor, zero if not + * found. If zero returned when name parameter is NULL, then no + * memory block descriptors are available. + */ +u64 cvmx_bootmem_phy_named_block_find(const char *name, u32 flags); + +/** + * Returns the size of available memory in bytes, only + * counting blocks that are at least as big as the minimum block + * size. + * + * @param min_block_size + * Minimum block size to count in total. + * + * @return Number of bytes available for allocation that meet the + * block size requirement + */ +u64 cvmx_bootmem_phy_available_mem(u64 min_block_size); + +/** + * Frees a named block. + * + * @param name name of block to free + * @param flags flags for passing options + * + * @return 0 on failure + * 1 on success + */ +int cvmx_bootmem_phy_named_block_free(const char *name, u32 flags); + +/** + * Frees a block to the bootmem allocator list. This must + * be used with care, as the size provided must match the size + * of the block that was allocated, or the list will become + * corrupted. + * + * IMPORTANT: This is only intended to be used as part of named block + * frees and initial population of the free memory list. + * * + * + * @param phy_addr physical address of block + * @param size size of block in bytes. + * @param flags flags for passing options + * + * @return 1 on success, + * 0 on failure + */ +int __cvmx_bootmem_phy_free(u64 phy_addr, u64 size, u32 flags); + +/** + * Prints the list of currently allocated named blocks + * + */ +void cvmx_bootmem_phy_named_block_print(void); + +/** + * Prints the list of available memory. + * + */ +void cvmx_bootmem_phy_list_print(void); + +/** + * This function initializes the free memory list used by cvmx_bootmem. + * This must be called before any allocations can be done. + * + * @param mem_size Total memory available, in bytes + * + * @param low_reserved_bytes Number of bytes to reserve (leave out of + * free list) at address 0x0. + * + * @param desc_buffer Buffer for the bootmem descriptor. This must be + * a 32 bit addressable address. + * + * @return 1 on success + * 0 on failure + */ +s64 cvmx_bootmem_phy_mem_list_init(u64 mem_size, u32 low_reserved_bytes, + struct cvmx_bootmem_desc *desc_buffer); + +/** + * This function initializes the free memory list used by cvmx_bootmem. + * This must be called before any allocations can be done. + * + * @param nodemask Nodemask - one bit per node (bit0->node0, bit1->node1,...) + * + * @param mem_size[] Array of memory sizes in MBytes per node ([0]->node0,...) + * + * @param low_reserved_bytes Number of bytes to reserve (leave out of + * free list) at address 0x0. + * + * @param desc_buffer Buffer for the bootmem descriptor. This must be + * a 32 bit addressable address. + * + * @return 1 on success + * 0 on failure + */ +s64 cvmx_bootmem_phy_mem_list_init_multi(u8 nodemask, u32 mem_size[], + u32 low_reserved_bytes, + struct cvmx_bootmem_desc *desc_buffer); +/** + * Locks the bootmem allocator. This is useful in certain situations + * where multiple allocations must be made without being interrupted. + * This should be used with the CVMX_BOOTMEM_FLAG_NO_LOCKING flag. + * + */ +void cvmx_bootmem_lock(void); + +/** + * Unlocks the bootmem allocator. This is useful in certain situations + * where multiple allocations must be made without being interrupted. + * This should be used with the CVMX_BOOTMEM_FLAG_NO_LOCKING flag. + * + */ +void cvmx_bootmem_unlock(void); + +/** + * Internal use function to get the current descriptor pointer + */ +void *__cvmx_bootmem_internal_get_desc_ptr(void); + +/** + * Internal use. This is userd to get a pointer to a physical + * address. For linux n32 the physical address in mmaped to a virtual + * address and the virtual address is returned. For n64 the address + * is converted to an xkphys address and the xkhpys address is + * returned. + */ +void *__cvmx_phys_addr_to_ptr(u64 phys, int size); +const struct cvmx_bootmem_named_block_desc * +__cvmx_bootmem_find_named_block_flags(const char *name, u32 flags); +void *cvmx_bootmem_alloc_named_range_flags(u64 size, u64 min_addr, + u64 max_addr, u64 align, + const char *name, u32 flags); +u64 cvmx_bootmem_phy_alloc_range(u64 size, u64 alignment, + u64 min_addr, u64 max_addr); + +#endif /* __CVMX_BOOTMEM_H__ */ From patchwork Thu Aug 20 05:22:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Roese X-Patchwork-Id: 1348172 X-Patchwork-Delegate: daniel.schwierzeck@googlemail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=denx.de header.i=@denx.de header.a=rsa-sha256 header.s=phobos-20191101 header.b=lHUTs8fO; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BXCk93R95z9sR4 for ; Thu, 20 Aug 2020 15:24:01 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 55A7F822BF; Thu, 20 Aug 2020 07:22:32 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=denx.de; s=phobos-20191101; t=1597900952; bh=dgnIJfppnj5iIyLEzEGXzA3zyHnk5TBCKAJyntaFHrA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=lHUTs8fOkQzB3g3rlVvSCao+3x2jKkqKCBYJ5xQyIgzcdf4ATWXbRL7dAT2lL9pK8 Up0srACGxAGMNmAWV966TbB11XhBLylM2TooN9Wy7ZcoVUxcuY4CVT17ZOltIIqo7Q TA560uHtVX+OjC+sfDChb0gV7VKtkMk/EEeCQX4yX8DVDLgMZFQemgbQg5kcW+z2Vy 08pHNEomWKbGXJSwW2UhY/peZIoilMEgdK12WIpFShnwrS0Px1b5aBbBxRZrS0x2Nv Jx72nt8tDcZH3Rq2x52KYbnOdD1CPGDPE5BVqV+Xc8bKgmNDT+svS0qs2sfmnezRgO FGenO3Hidbh0w== Received: by phobos.denx.de (Postfix, from userid 109) id 9B2C08225B; Thu, 20 Aug 2020 07:22:20 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mx2.mailbox.org (mx2.mailbox.org [80.241.60.215]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 0F29681B79 for ; Thu, 20 Aug 2020 07:22:14 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=none smtp.mailfrom=sr@denx.de Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:105:465:1:1:0]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by mx2.mailbox.org (Postfix) with ESMTPS id D07B6A13D0; Thu, 20 Aug 2020 07:22:13 +0200 (CEST) Received: from smtp1.mailbox.org ([80.241.60.240]) by spamfilter06.heinlein-hosting.de (spamfilter06.heinlein-hosting.de [80.241.56.125]) (amavisd-new, port 10030) with ESMTP id ovHip_blXVPD; Thu, 20 Aug 2020 07:22:10 +0200 (CEST) From: Stefan Roese To: u-boot@lists.denx.de Cc: daniel.schwierzeck@gmail.com, cchavva@marvell.com, awilliams@marvell.com Subject: [PATCH v1 09/10] mips: octeon: Add bootoctlinux command Date: Thu, 20 Aug 2020 07:22:03 +0200 Message-Id: <20200820052204.2794174-10-sr@denx.de> In-Reply-To: <20200820052204.2794174-1-sr@denx.de> References: <20200820052204.2794174-1-sr@denx.de> MIME-Version: 1.0 X-MBO-SPAM-Probability: X-Rspamd-Score: -0.28 / 15.00 / 15.00 X-Rspamd-Queue-Id: ACF63679 X-Rspamd-UID: 81d459 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean From: Aaron Williams Octeon needs a platform specific cmd to boot the Linux kernel, as specific parameters need to be passed and special handling for the multiple cores (SMP) is needed. Co-developed-by: Stefan Roese Signed-off-by: Aaron Williams Signed-off-by: Stefan Roese --- arch/mips/mach-octeon/Makefile | 1 + arch/mips/mach-octeon/bootoctlinux.c | 661 ++++++++++++++++++ .../mach-octeon/include/mach/bootoct_cmd.h | 54 ++ 3 files changed, 716 insertions(+) create mode 100644 arch/mips/mach-octeon/bootoctlinux.c create mode 100644 arch/mips/mach-octeon/include/mach/bootoct_cmd.h diff --git a/arch/mips/mach-octeon/Makefile b/arch/mips/mach-octeon/Makefile index e96f0deb1b..3486aa9d8b 100644 --- a/arch/mips/mach-octeon/Makefile +++ b/arch/mips/mach-octeon/Makefile @@ -10,3 +10,4 @@ obj-y += cpu.o obj-y += dram.o obj-y += cvmx-coremask.o obj-y += cvmx-bootmem.o +obj-y += bootoctlinux.o diff --git a/arch/mips/mach-octeon/bootoctlinux.c b/arch/mips/mach-octeon/bootoctlinux.c new file mode 100644 index 0000000000..af69808ce8 --- /dev/null +++ b/arch/mips/mach-octeon/bootoctlinux.c @@ -0,0 +1,661 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Stefan Roese + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* ToDo: Revisit these settings */ +#define OCTEON_RESERVED_LOW_MEM_SIZE (512 * 1024) +#define OCTEON_RESERVED_LOW_BOOT_MEM_SIZE (1024 * 1024) +#define BOOTLOADER_BOOTMEM_DESC_SPACE (1024 * 1024) + +/* Default stack and heap sizes, in bytes */ +#define DEFAULT_STACK_SIZE (1 * 1024 * 1024) +#define DEFAULT_HEAP_SIZE (3 * 1024 * 1024) + +/** + * NOTE: This must duplicate octeon_boot_descriptor_t in the toolchain + * octeon-app-init.h file. + */ +enum { + /* If set, core should do app-wide init, only one core per app will have + * this flag set. + */ + BOOT_FLAG_INIT_CORE = 1, + OCTEON_BL_FLAG_DEBUG = 1 << 1, + OCTEON_BL_FLAG_NO_MAGIC = 1 << 2, + /* If set, use uart1 for console */ + OCTEON_BL_FLAG_CONSOLE_UART1 = 1 << 3, + OCTEON_BL_FLAG_CONSOLE_PCI = 1 << 4, /* If set, use PCI console */ + /* Call exit on break on serial port */ + OCTEON_BL_FLAG_BREAK = 1 << 5, + /* + * Be sure to update OCTEON_APP_INIT_H_VERSION when new fields are added + * and to conditionalize the new flag's usage based on the version. + */ +} octeon_boot_descriptor_flag; + +/** + * NOTE: This must duplicate octeon_boot_descriptor_t in the toolchain + * octeon-app-init.h file. + */ +#ifndef OCTEON_CURRENT_DESC_VERSION +# define OCTEON_CURRENT_DESC_VERSION 7 +#endif +/** + * NOTE: This must duplicate octeon_boot_descriptor_t in the toolchain + * octeon-app-init.h file. + */ +/* Version 7 changes: Change names of deprecated fields */ +#ifndef OCTEON_ARGV_MAX_ARGS +# define OCTEON_ARGV_MAX_ARGS 64 +#endif + +/** + * NOTE: This must duplicate octeon_boot_descriptor_t in the toolchain + * octeon-app-init.h file. + */ +#ifndef OCTEON_SERIAL_LEN +# define OCTEON_SERIAL_LEN 20 +#endif + +/** + * Bootloader structure used to pass info to Octeon executive startup code. + * NOTE: all fields are deprecated except for: + * * desc_version + * * desc_size, + * * heap_base + * * heap_end + * * eclock_hz + * * flags + * * argc + * * argv + * * cvmx_desc_vaddr + * * debugger_flags_base_addr + * + * All other fields have been moved to the cvmx_descriptor, and the new + * fields should be added there. They are left as placeholders in this + * structure for binary compatibility. + * + * NOTE: This structure must match what is in the toolchain octeon-app-init.h + * file. + */ +struct octeon_boot_descriptor { + /* Start of block referenced by assembly code - do not change! */ + u32 desc_version; + u32 desc_size; + u64 stack_top; + u64 heap_base; + u64 heap_end; + u64 deprecated17; + u64 deprecated16; + /* End of block referenced by assembly code - do not change! */ + u32 deprecated18; + u32 deprecated15; + u32 deprecated14; + u32 argc; /* argc for main() */ + u32 argv[OCTEON_ARGV_MAX_ARGS]; /* argv for main() */ + u32 flags; /* Flags for application */ + u32 core_mask; /* Coremask running this image */ + u32 dram_size; /* DEPRECATED, DRAM size in megabyes. Used up to SDK 1.8.1 */ + u32 phy_mem_desc_addr; + u32 debugger_flags_base_addr; /* used to pass flags from app to debugger. */ + u32 eclock_hz; /* CPU clock speed, in hz. */ + u32 deprecated10; + u32 deprecated9; + u16 deprecated8; + u8 deprecated7; + u8 deprecated6; + u16 deprecated5; + u8 deprecated4; + u8 deprecated3; + char deprecated2[OCTEON_SERIAL_LEN]; + u8 deprecated1[6]; + u8 deprecated0; + u64 cvmx_desc_vaddr; /* Address of cvmx descriptor */ +}; + +static struct octeon_boot_descriptor boot_desc[CVMX_MIPS_MAX_CORES]; +static struct cvmx_bootinfo cvmx_bootinfo_array[CVMX_MIPS_MAX_CORES]; + +/** + * Programs the boot bus moveable region + * @param base base address to place the boot bus moveable region + * (bits [31:7]) + * @param region_num Selects which region, 0 or 1 for node 0, + * 2 or 3 for node 1 + * @param enable Set true to enable, false to disable + * @param data Pointer to data to put in the region, up to + * 16 dwords. + * @param num_words Number of data dwords (up to 32) + * + * @return 0 for success, -1 on error + */ +static int octeon_set_moveable_region(u32 base, int region_num, + bool enable, const u64 *data, + unsigned int num_words) +{ + int node = region_num >> 1; + u64 val; + int i; + u8 node_mask = 0x01; /* ToDo: Currently only one node is supported */ + + debug("%s(0x%x, %d, %d, %p, %u)\n", __func__, base, region_num, enable, + data, num_words); + + if (num_words > 32) { + printf("%s: Too many words (%d) for region %d\n", __func__, + num_words, region_num); + return -1; + } + + if (base & 0x7f) { + printf("%s: Error: base address 0x%x must be 128 byte aligned\n", + __func__, base); + return -1; + } + + if (region_num > (node_mask > 1 ? 3 : 1)) { + printf("%s: Region number %d out of range\n", + __func__, region_num); + return -1; + } + + if (!data && num_words > 0) { + printf("%s: Error: NULL data\n", __func__); + return -1; + } + + region_num &= 1; + + val = MIO_BOOT_LOC_CFG_EN | + FIELD_PREP(MIO_BOOT_LOC_CFG_BASE, base >> 7); + debug("%s: Setting MIO_BOOT_LOC_CFG(%d) on node %d to 0x%llx\n", + __func__, region_num, node, val); + csr_wr(CVMX_MIO_BOOT_LOC_CFGX(region_num & 1), val); + + val = FIELD_PREP(MIO_BOOT_LOC_ADR_ADR, (region_num ? 0x80 : 0x00) >> 3); + debug("%s: Setting MIO_BOOT_LOC_ADR start to 0x%llx\n", __func__, val); + csr_wr(CVMX_MIO_BOOT_LOC_ADR, val); + + for (i = 0; i < num_words; i++) { + debug(" 0x%02llx: 0x%016llx\n", + csr_rd(CVMX_MIO_BOOT_LOC_ADR), data[i]); + csr_wr(CVMX_MIO_BOOT_LOC_DAT, data[i]); + } + + return 0; +} + +/** + * Parse comma separated numbers into an array + * + * @param[out] values values read for each node + * @param[in] str string to parse + * @param base 0 for auto, otherwise 8, 10 or 16 for the number base + * + * @return number of values read. + */ +static int octeon_parse_nodes(u64 values[CVMX_MAX_NODES], + const char *str, int base) +{ + int node = 0; + char *sep; + + do { + debug("Parsing node %d: \"%s\"\n", node, str); + values[node] = simple_strtoull(str, &sep, base); + debug(" node %d: 0x%llx\n", node, values[node]); + str = sep + 1; + } while (++node < CVMX_MAX_NODES && *sep == ','); + + debug("%s: returning %d\n", __func__, node); + return node; +} + +/** + * Parse command line arguments + * + * @param argc number of arguments + * @param[in] argv array of argument strings + * @param cmd command type + * @param[out] boot_args parsed values + * + * @return number of arguments parsed + */ +int octeon_parse_bootopts(int argc, char *const argv[], + enum octeon_boot_cmd_type cmd, + struct octeon_boot_args *boot_args) +{ + u64 node_values[CVMX_MAX_NODES]; + int arg, j; + int num_values; + int node; + u8 node_mask = 0x01; /* ToDo: Currently only one node is supported */ + + debug("%s(%d, %p, %d, %p)\n", __func__, argc, argv, cmd, boot_args); + memset(boot_args, 0, sizeof(*boot_args)); + boot_args->stack_size = DEFAULT_STACK_SIZE; + boot_args->heap_size = DEFAULT_HEAP_SIZE; + boot_args->node_mask = 0; + + for (arg = 0; arg < argc; arg++) { + debug(" argv[%d]: %s\n", arg, argv[arg]); + if (cmd == BOOTOCT && !strncmp(argv[arg], "stack=", 6)) { + boot_args->stack_size = simple_strtoul(argv[arg] + 6, + NULL, 0); + } else if (cmd == BOOTOCT && !strncmp(argv[arg], "heap=", 5)) { + boot_args->heap_size = simple_strtoul(argv[arg] + 5, + NULL, 0); + } else if (!strncmp(argv[arg], "debug", 5)) { + puts("setting debug flag!\n"); + boot_args->boot_flags |= OCTEON_BL_FLAG_DEBUG; + } else if (cmd == BOOTOCT && !strncmp(argv[arg], "break", 5)) { + puts("setting break flag!\n"); + boot_args->boot_flags |= OCTEON_BL_FLAG_BREAK; + } else if (!strncmp(argv[arg], "forceboot", 9)) { + boot_args->forceboot = true; + } else if (!strncmp(argv[arg], "nodemask=", 9)) { + boot_args->node_mask = simple_strtoul(argv[arg] + 9, + NULL, 16); + } else if (!strncmp(argv[arg], "numcores=", 9)) { + memset(node_values, 0, sizeof(node_values)); + num_values = octeon_parse_nodes(node_values, + argv[arg] + 9, 0); + for (j = 0; j < num_values; j++) + boot_args->num_cores[j] = node_values[j]; + boot_args->num_cores_set = true; + } else if (!strncmp(argv[arg], "skipcores=", 10)) { + memset(node_values, 0, sizeof(node_values)); + num_values = octeon_parse_nodes(node_values, + argv[arg] + 10, 0); + for (j = 0; j < num_values; j++) + boot_args->num_skipped[j] = node_values[j]; + boot_args->num_skipped_set = true; + } else if (!strncmp(argv[arg], "console_uart=", 13)) { + boot_args->console_uart = simple_strtoul(argv[arg] + 13, + NULL, 0); + if (boot_args->console_uart == 1) { + boot_args->boot_flags |= + OCTEON_BL_FLAG_CONSOLE_UART1; + } else if (!boot_args->console_uart) { + boot_args->boot_flags &= + ~OCTEON_BL_FLAG_CONSOLE_UART1; + } + } else if (!strncmp(argv[arg], "coremask=", 9)) { + memset(node_values, 0, sizeof(node_values)); + num_values = octeon_parse_nodes(node_values, + argv[arg] + 9, 16); + for (j = 0; j < num_values; j++) + cvmx_coremask_set64_node(&boot_args->coremask, + j, node_values[j]); + boot_args->coremask_set = true; + } else if (cmd == BOOTOCTLINUX && + !strncmp(argv[arg], "namedblock=", 11)) { + boot_args->named_block = argv[arg] + 11; + } else if (!strncmp(argv[arg], "endbootargs", 11)) { + boot_args->endbootargs = 1; + arg++; + if (argc >= arg && cmd != BOOTOCTLINUX) + boot_args->app_name = argv[arg]; + break; + } else { + debug(" Unknown argument \"%s\"\n", argv[arg]); + } + } + + if (boot_args->coremask_set && boot_args->num_cores_set) { + puts("Warning: both coremask and numcores are set, using coremask.\n"); + } else if (!boot_args->coremask_set && !boot_args->num_cores_set) { + cvmx_coremask_set_core(&boot_args->coremask, 0); + boot_args->coremask_set = true; + } else if ((!boot_args->coremask_set) && boot_args->num_cores_set) { + cvmx_coremask_for_each_node(node, node_mask) + cvmx_coremask_set64_node(&boot_args->coremask, node, + ((1ull << boot_args->num_cores[node]) - 1) << + boot_args->num_skipped[node]); + boot_args->coremask_set = true; + } + + /* Update the node mask based on the coremask or the number of cores */ + for (j = 0; j < CVMX_MAX_NODES; j++) { + if (cvmx_coremask_get64_node(&boot_args->coremask, j)) + boot_args->node_mask |= 1 << j; + } + + debug("%s: return %d\n", __func__, arg); + return arg; +} + +int do_bootoctlinux(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + typedef void __noreturn (*kernel_entry_t)(int, ulong, ulong, ulong); + kernel_entry_t kernel; + struct octeon_boot_args boot_args; + int arg_start = 1; + int arg_count; + u64 addr = 0; /* Address of the ELF image */ + int arg0; + u64 arg1; + u64 arg2; + u64 arg3; + int ret; + struct cvmx_coremask core_mask; + struct cvmx_coremask coremask_to_run; + struct cvmx_coremask avail_coremask; + int first_core; + int core; + struct ram_info ram; + struct udevice *dev; + const u64 *nmi_code; + int num_dwords; + u8 node_mask = 0x01; + int i; + + cvmx_coremask_clear_all(&core_mask); + cvmx_coremask_clear_all(&coremask_to_run); + + if (argc >= 2 && (isxdigit(argv[1][0]) && (isxdigit(argv[1][1]) || + argv[1][1] == 'x' || + argv[1][1] == 'X' || + argv[1][1] == '\0'))) { + addr = simple_strtoul(argv[1], NULL, 16); + if (!addr) + addr = CONFIG_SYS_LOAD_ADDR; + arg_start++; + } + if (addr == 0) + addr = CONFIG_SYS_LOAD_ADDR; + + debug("%s: arg start: %d\n", __func__, arg_start); + arg_count = octeon_parse_bootopts(argc - arg_start, argv + arg_start, + BOOTOCTLINUX, &boot_args); + + debug("%s:\n" + " named block: %s\n" + " node mask: 0x%x\n" + " stack size: 0x%x\n" + " heap size: 0x%x\n" + " boot flags: 0x%x\n" + " force boot: %s\n" + " coremask set: %s\n" + " num cores set: %s\n" + " num skipped set: %s\n" + " endbootargs: %s\n", + __func__, + boot_args.named_block ? boot_args.named_block : "none", + boot_args.node_mask, + boot_args.stack_size, + boot_args.heap_size, + boot_args.boot_flags, + boot_args.forceboot ? "true" : "false", + boot_args.coremask_set ? "true" : "false", + boot_args.num_cores_set ? "true" : "false", + boot_args.num_skipped_set ? "true" : "false", + boot_args.endbootargs ? "true" : "false"); + debug(" num cores: "); + for (i = 0; i < CVMX_MAX_NODES; i++) + debug("%s%d", i > 0 ? ", " : "", boot_args.num_cores[i]); + debug("\n num skipped: "); + for (i = 0; i < CVMX_MAX_NODES; i++) { + debug("%s%d", i > 0 ? ", " : "", boot_args.num_skipped[i]); + debug("\n coremask:\n"); + cvmx_coremask_dprint(&boot_args.coremask); + } + + if (boot_args.endbootargs) { + debug("endbootargs set, adjusting argc from %d to %d, arg_count: %d, arg_start: %d\n", + argc, argc - (arg_count + arg_start), arg_count, + arg_start); + argc -= (arg_count + arg_start); + argv += (arg_count + arg_start); + } + + /* + * numcores specification overrides a coremask on the same command line + */ + cvmx_coremask_copy(&core_mask, &boot_args.coremask); + + /* + * Remove cores from coremask based on environment variable stored in + * flash + */ + if (validate_coremask(&core_mask) != 0) { + puts("Invalid coremask.\n"); + return 1; + } else if (cvmx_coremask_is_empty(&core_mask)) { + puts("Coremask is empty after coremask_override mask. Nothing to do.\n"); + return 0; + } + + if (cvmx_coremask_intersects(&core_mask, &coremask_to_run)) { + puts("ERROR: Can't load code on core twice! Provided coremask:\n"); + cvmx_coremask_print(&core_mask); + puts("overlaps previously loaded coremask:\n"); + cvmx_coremask_print(&coremask_to_run); + return -1; + } + + debug("Setting up boot descriptor block with core mask:\n"); + cvmx_coremask_dprint(&core_mask); + + /* + * Add coremask to global mask of cores that have been set up and are + * runable + */ + cvmx_coremask_or(&coremask_to_run, &coremask_to_run, &core_mask); + + /* Get RAM size */ + ret = uclass_get_device(UCLASS_RAM, 0, &dev); + if (ret) { + debug("DRAM init failed: %d\n", ret); + return ret; + } + + ret = ram_get_info(dev, &ram); + if (ret) { + debug("Cannot get DRAM size: %d\n", ret); + return ret; + } + + /* + * Load kernel ELF image, or try binary if ELF is not detected. + * This way the much smaller vmlinux.bin can also be started but + * has to be loaded at the correct address (ep as parameter). + */ + if (!valid_elf_image(addr)) + printf("Booting binary image instead (vmlinux.bin)...\n"); + else + addr = load_elf_image_shdr(addr); + + /* Set kernel entry point */ + kernel = (kernel_entry_t)addr; + + /* Init bootmem list for Linux kernel booting */ + if (!cvmx_bootmem_phy_mem_list_init( + ram.size, OCTEON_RESERVED_LOW_MEM_SIZE, + (void *)CKSEG0ADDR(BOOTLOADER_BOOTMEM_DESC_SPACE))) { + printf("FATAL: Error initializing free memory list\n"); + return 0; + } + + first_core = cvmx_coremask_get_first_core(&coremask_to_run); + + cvmx_coremask_for_each_core(core, &coremask_to_run) { + debug("%s: Activating core %d\n", __func__, core); + + cvmx_bootinfo_array[core].core_mask = + cvmx_coremask_get32(&coremask_to_run); + cvmx_coremask_copy(&cvmx_bootinfo_array[core].ext_core_mask, + &coremask_to_run); + + if (core == first_core) + cvmx_bootinfo_array[core].flags |= BOOT_FLAG_INIT_CORE; + + cvmx_bootinfo_array[core].dram_size = ram.size / (1024 * 1024); + + cvmx_bootinfo_array[core].dclock_hz = gd->mem_clk * 1000000; + cvmx_bootinfo_array[core].eclock_hz = gd->cpu_clk; + + cvmx_bootinfo_array[core].led_display_base_addr = 0; + cvmx_bootinfo_array[core].phy_mem_desc_addr = + ((u32)(u64)__cvmx_bootmem_internal_get_desc_ptr()) & + 0x7ffffff; + + cvmx_bootinfo_array[core].major_version = CVMX_BOOTINFO_MAJ_VER; + cvmx_bootinfo_array[core].minor_version = CVMX_BOOTINFO_MIN_VER; + cvmx_bootinfo_array[core].fdt_addr = virt_to_phys(gd->fdt_blob); + + boot_desc[core].dram_size = gd->ram_size / (1024 * 1024); + boot_desc[core].cvmx_desc_vaddr = + virt_to_phys(&cvmx_bootinfo_array[core]); + + boot_desc[core].desc_version = OCTEON_CURRENT_DESC_VERSION; + boot_desc[core].desc_size = sizeof(boot_desc[0]); + + boot_desc[core].flags = cvmx_bootinfo_array[core].flags; + boot_desc[core].eclock_hz = cvmx_bootinfo_array[core].eclock_hz; + + boot_desc[core].argc = argc; + for (i = 0; i < argc; i++) + boot_desc[core].argv[i] = (u32)virt_to_phys(argv[i]); + } + + core = 0; + arg0 = argc; + arg1 = (u64)argv; + arg2 = 0x1; /* Core 0 sets init core for Linux */ + arg3 = XKPHYS | virt_to_phys(&boot_desc[core]); + + debug("## Transferring control to Linux (at address %p) ...\n", kernel); + + /* + * Flush cache before jumping to application. Let's flush the + * whole SDRAM area, since we don't know the size of the image + * that was loaded. + */ + flush_cache(gd->bd->bi_memstart, gd->ram_top - gd->bd->bi_memstart); + + /* Take all cores out of reset */ + csr_wr(CVMX_CIU_PP_RST, 0); + sync(); + + /* Wait a short while for the other cores... */ + mdelay(100); + + /* Install boot code into moveable bus for NMI (other cores) */ + nmi_code = (const u64 *)nmi_bootvector; + num_dwords = (((u64)&nmi_handler_para[0] - (u64)nmi_code) + 7) / 8; + + ret = octeon_set_moveable_region(0x1fc00000, 0, true, nmi_code, + num_dwords); + if (ret) { + printf("Error installing NMI handler for SMP core startup\n"); + return 0; + } + + /* Write NMI handler parameters for Linux kernel booting */ + nmi_handler_para[0] = (u64)kernel; + nmi_handler_para[1] = arg0; + nmi_handler_para[2] = arg1; + nmi_handler_para[3] = 0; /* Don't set init core for secondary cores */ + nmi_handler_para[4] = arg3; + sync(); + + /* Wait a short while for the other cores... */ + mdelay(100); + + /* + * Cores have already been taken out of reset to conserve power. + * We need to send a NMI to get the cores out of their wait loop + */ + octeon_get_available_coremask(&avail_coremask); + debug("Available coremask:\n"); + cvmx_coremask_dprint(&avail_coremask); + debug("Starting coremask:\n"); + cvmx_coremask_dprint(&coremask_to_run); + debug("Sending NMIs to other cores\n"); + if (octeon_has_feature(OCTEON_FEATURE_CIU3)) { + u64 avail_cm; + int node; + + cvmx_coremask_for_each_node(node, node_mask) { + avail_cm = cvmx_coremask_get64_node(&avail_coremask, + node); + + if (avail_cm != 0) { + debug("Sending NMI to node %d, coremask=0x%llx, CIU3_NMI=0x%llx\n", + node, avail_cm, + (node > 0 ? -1ull : -2ull) & avail_cm); + csr_wr(CVMX_CIU3_NMI, + (node > 0 ? -1ull : -2ull) & avail_cm); + } + } + } else { + csr_wr(CVMX_CIU_NMI, + -2ull & cvmx_coremask_get64(&avail_coremask)); + } + debug("Done sending NMIs\n"); + + /* Wait a short while for the other cores... */ + mdelay(100); + + /* + * pass address parameter as argv[0] (aka command name), + * and all remaining args + * a0 = argc + * a1 = argv (32 bit physical addresses, not pointers) + * a2 = init core + * a3 = boot descriptor address + * a4/t0 = entry point (only used by assembly stub) + */ + kernel(arg0, arg1, arg2, arg3); + + return 0; +} + +U_BOOT_CMD(bootoctlinux, 32, 0, do_bootoctlinux, + "Boot from a linux ELF image in memory", + "elf_address [coremask=mask_to_run | numcores=core_cnt_to_run] " + "[forceboot] [skipcores=core_cnt_to_skip] [namedblock=name] [endbootargs] [app_args ...]\n" + "elf_address - address of ELF image to load. If 0, default load address\n" + " is used.\n" + "coremask - mask of cores to run on. Anded with coremask_override\n" + " environment variable to ensure only working cores are used\n" + "numcores - number of cores to run on. Runs on specified number of cores,\n" + " taking into account the coremask_override.\n" + "skipcores - only meaningful with numcores. Skips this many cores\n" + " (starting from 0) when loading the numcores cores.\n" + " For example, setting skipcores to 1 will skip core 0\n" + " and load the application starting at the next available core.\n" + "forceboot - if set, boots application even if core 0 is not in mask\n" + "namedblock - specifies a named block to load the kernel\n" + "endbootargs - if set, bootloader does not process any further arguments and\n" + " only passes the arguments that follow to the kernel.\n" + " If not set, the kernel gets the entire commnad line as\n" + " arguments.\n" "\n"); diff --git a/arch/mips/mach-octeon/include/mach/bootoct_cmd.h b/arch/mips/mach-octeon/include/mach/bootoct_cmd.h new file mode 100644 index 0000000000..657698ba54 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/bootoct_cmd.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#ifndef __BOOTOCT_CMD_H__ +#define __BOOTOCT_CMD_H__ + +#include "cvmx-coremask.h" + +enum octeon_boot_cmd_type { + BOOTOCT, + BOOTOCTLINUX, + BOOTOCTELF +}; + +/** Structure to contain results of command line argument parsing */ +struct octeon_boot_args { + struct cvmx_coremask coremask; /** Parsed coremask */ + int num_cores[CVMX_MAX_NODES]; /** number of cores */ + int num_skipped[CVMX_MAX_NODES];/** number of skipped cores */ + const char *app_name; /** Application name */ + const char *named_block; /** Named block to load Linux into */ + u32 stack_size; /** stack size */ + u32 heap_size; /** heap size */ + u32 boot_flags; /** boot flags */ + int node_mask; /** Node mask to use */ + int console_uart; /** serial console number */ + bool forceboot; /** force booting if core 0 not set */ + bool coremask_set; /** set if coremask was set */ + bool num_cores_set; /** Set if num_cores was set */ + bool num_skipped_set; /** Set if num_skipped was set */ + /** Set if endbootargs parameter was passed. */ + bool endbootargs; +}; + +/** + * Parse command line arguments + * + * @param argc number of arguments + * @param[in] argv array of argument strings + * @param cmd command type + * @param[out] boot_args parsed values + * + * @return number of arguments parsed + */ +int octeon_parse_bootopts(int argc, char *const argv[], + enum octeon_boot_cmd_type cmd, + struct octeon_boot_args *boot_args); + +void nmi_bootvector(void); +extern u64 nmi_handler_para[]; + +#endif /* __BOOTOCT_CMD_H__ */ From patchwork Thu Aug 20 05:22:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Roese X-Patchwork-Id: 1348171 X-Patchwork-Delegate: daniel.schwierzeck@googlemail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=denx.de header.i=@denx.de header.a=rsa-sha256 header.s=phobos-20191101 header.b=eJB+kGVp; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BXCjy5V4Cz9sR4 for ; Thu, 20 Aug 2020 15:23:50 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 5CBF7822B3; Thu, 20 Aug 2020 07:22:31 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=denx.de; s=phobos-20191101; t=1597900951; bh=QldjG6abstNNMvkkOYq1h0JCMy5Ew3+lKlfU3NBqW+E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=eJB+kGVpfBMcRYdTytTl5mry1zHmsziNmhazH+57EfrWI+9mlZX2NwrhfBQjkVM8+ mAkkXLIpDduNH3XUQSv/EyMUBmA2hntcYTH0V2W2EUc4XEs1k/9XKwOTcxTBkc/QHr EAAxnRcTbqG33xtC1+Pr4p1Yf1Q8k9+9tlUr4dbLrnn/i+3jukEjF8TgkAO2MQTjpG DTJCcqljbcHmZaxgiJQXnhISGX1EPYqzrzoE2FDFFQb+AiAflzoe+XZgCVDE5egtHd rWMdnguivH81netlHh0XamfHAN1nRtfu3kwZet0yJ1bi2mGbGYNGl9ynygvUmgSSK/ vCRxQ+qm9s7kA== Received: by phobos.denx.de (Postfix, from userid 109) id 1DFF182292; Thu, 20 Aug 2020 07:22:18 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mx2.mailbox.org (mx2.mailbox.org [80.241.60.215]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 7118181B45 for ; Thu, 20 Aug 2020 07:22:13 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=denx.de Authentication-Results: phobos.denx.de; spf=none smtp.mailfrom=sr@denx.de Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:105:465:1:1:0]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by mx2.mailbox.org (Postfix) with ESMTPS id 3FBC0A13CD; Thu, 20 Aug 2020 07:22:13 +0200 (CEST) Received: from smtp1.mailbox.org ([80.241.60.240]) by spamfilter06.heinlein-hosting.de (spamfilter06.heinlein-hosting.de [80.241.56.125]) (amavisd-new, port 10030) with ESMTP id IGhL9CRdyH_T; Thu, 20 Aug 2020 07:22:10 +0200 (CEST) From: Stefan Roese To: u-boot@lists.denx.de Cc: daniel.schwierzeck@gmail.com, cchavva@marvell.com, awilliams@marvell.com Subject: [PATCH v1 10/10] mips: octeon: octeon_common.h: Increase CONFIG_SYS_BOOTM_LEN Date: Thu, 20 Aug 2020 07:22:04 +0200 Message-Id: <20200820052204.2794174-11-sr@denx.de> In-Reply-To: <20200820052204.2794174-1-sr@denx.de> References: <20200820052204.2794174-1-sr@denx.de> MIME-Version: 1.0 X-MBO-SPAM-Probability: * X-Rspamd-Score: 0.74 / 15.00 / 15.00 X-Rspamd-Queue-Id: 2CFF137F X-Rspamd-UID: 94df53 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean Increase CONFIG_SYS_BOOTM_LEN to 64MiB for Linux kernel booting. Signed-off-by: Stefan Roese --- include/configs/octeon_common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/configs/octeon_common.h b/include/configs/octeon_common.h index 541b81801e..109ef4064d 100644 --- a/include/configs/octeon_common.h +++ b/include/configs/octeon_common.h @@ -21,4 +21,6 @@ #define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + (1 << 20)) +#define CONFIG_SYS_BOOTM_LEN (64 << 20) /* 64M */ + #endif /* __OCTEON_COMMON_H__ */