From owner-svn-src-all@freebsd.org Fri Nov 8 18:57:42 2019 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id A9C4F15BA24; Fri, 8 Nov 2019 18:57:42 +0000 (UTC) (envelope-from mmel@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 478qK241WQz3HBj; Fri, 8 Nov 2019 18:57:42 +0000 (UTC) (envelope-from mmel@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 52FD127FB; Fri, 8 Nov 2019 18:57:42 +0000 (UTC) (envelope-from mmel@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id xA8Ivg7i092150; Fri, 8 Nov 2019 18:57:42 GMT (envelope-from mmel@FreeBSD.org) Received: (from mmel@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id xA8Ivf2J092145; Fri, 8 Nov 2019 18:57:41 GMT (envelope-from mmel@FreeBSD.org) Message-Id: <201911081857.xA8Ivf2J092145@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mmel set sender to mmel@FreeBSD.org using -f From: Michal Meloun Date: Fri, 8 Nov 2019 18:57:41 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r354554 - in head/sys: conf dev/extres/clk X-SVN-Group: head X-SVN-Commit-Author: mmel X-SVN-Commit-Paths: in head/sys: conf dev/extres/clk X-SVN-Commit-Revision: 354554 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 08 Nov 2019 18:57:42 -0000 Author: mmel Date: Fri Nov 8 18:57:41 2019 New Revision: 354554 URL: https://svnweb.freebsd.org/changeset/base/354554 Log: Implement support for (soft)linked clocks. This kind of clock nodes represent temporary placeholder for clocks defined later in boot process. Also, these are necessary to break circular dependencies occasionally occurring in complex clock graphs. MFC after: 3 weeks Added: head/sys/dev/extres/clk/clk_link.c (contents, props changed) head/sys/dev/extres/clk/clk_link.h (contents, props changed) Modified: head/sys/conf/files head/sys/dev/extres/clk/clk.c head/sys/dev/extres/clk/clk.h Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Fri Nov 8 18:56:02 2019 (r354553) +++ head/sys/conf/files Fri Nov 8 18:57:41 2019 (r354554) @@ -1681,6 +1681,7 @@ dev/extres/clk/clk_bus.c optional ext_resources clk fd dev/extres/clk/clk_div.c optional ext_resources clk fdt dev/extres/clk/clk_fixed.c optional ext_resources clk fdt dev/extres/clk/clk_gate.c optional ext_resources clk fdt +dev/extres/clk/clk_link.c optional ext_resources clk fdt dev/extres/clk/clk_mux.c optional ext_resources clk fdt dev/extres/phy/phy.c optional ext_resources phy fdt dev/extres/phy/phydev_if.m optional ext_resources phy fdt Modified: head/sys/dev/extres/clk/clk.c ============================================================================== --- head/sys/dev/extres/clk/clk.c Fri Nov 8 18:56:02 2019 (r354553) +++ head/sys/dev/extres/clk/clk.c Fri Nov 8 18:57:41 2019 (r354554) @@ -189,6 +189,9 @@ enum clknode_sysctl_type { static int clknode_sysctl(SYSCTL_HANDLER_ARGS); static int clkdom_sysctl(SYSCTL_HANDLER_ARGS); +static void clknode_finish(void *dummy); +SYSINIT(clknode_finish, SI_SUB_LAST, SI_ORDER_ANY, clknode_finish, NULL); + /* * Default clock methods for base class. */ @@ -526,20 +529,71 @@ clknode_create(struct clkdom * clkdom, clknode_class_t { struct clknode *clknode; struct sysctl_oid *clknode_oid; + bool replaced; KASSERT(def->name != NULL, ("clock name is NULL")); KASSERT(def->name[0] != '\0', ("clock name is empty")); -#ifdef INVARIANTS + if (def->flags & CLK_NODE_LINKED) { + KASSERT(def->parent_cnt == 0, + ("Linked clock must not have parents")); + KASSERT(clknode_class->size== 0, + ("Linked clock cannot have own softc")); + } + + /* Process duplicated clocks */ CLK_TOPO_SLOCK(); - if (clknode_find_by_name(def->name) != NULL) - panic("Duplicated clock registration: %s\n", def->name); + clknode = clknode_find_by_name(def->name); CLK_TOPO_UNLOCK(); -#endif + if (clknode != NULL) { + if (!(clknode->flags & CLK_NODE_LINKED) && + def->flags & CLK_NODE_LINKED) { + /* + * New clock is linked and real already exists. + * Do nothing and return real node. It is in right + * domain, enqueued in right lists and fully initialized. + */ + return (clknode); + } else if (clknode->flags & CLK_NODE_LINKED && + !(def->flags & CLK_NODE_LINKED)) { + /* + * New clock is real but linked already exists. + * Remove old linked node from originating domain + * (real clock must be owned by another) and from + * global names link (it will be added back into it + * again in following clknode_register()). Then reuse + * original clknode structure and reinitialize it + * with new dat. By this, all lists containing this + * node remains valid, but the new node virtually + * replace the linked one. + */ + KASSERT(clkdom != clknode->clkdom, + ("linked clock must be from another " + "domain that real one")); + TAILQ_REMOVE(&clkdom->clknode_list, clknode, + clkdom_link); + TAILQ_REMOVE(&clknode_list, clknode, clklist_link); + replaced = true; + } else if (clknode->flags & CLK_NODE_LINKED && + def->flags & CLK_NODE_LINKED) { + /* + * Both clocks are linked. + * Return old one, so we hold only one copy od link. + */ + return (clknode); + } else { + /* Both clocks are real */ + panic("Duplicated clock registration: %s\n", def->name); + } + } else { + /* Create clknode object and initialize it. */ + clknode = malloc(sizeof(struct clknode), M_CLOCK, + M_WAITOK | M_ZERO); + sx_init(&clknode->lock, "Clocknode lock"); + TAILQ_INIT(&clknode->children); + replaced = false; + } - /* Create object and initialize it. */ - clknode = malloc(sizeof(struct clknode), M_CLOCK, M_WAITOK | M_ZERO); kobj_init((kobj_t)clknode, (kobj_class_t)clknode_class); - sx_init(&clknode->lock, "Clocknode lock"); /* Allocate softc if required. */ if (clknode_class->size > 0) { @@ -568,8 +622,10 @@ clknode_create(struct clkdom * clkdom, clknode_class_t clknode->parent_cnt = def->parent_cnt; clknode->parent = NULL; clknode->parent_idx = CLKNODE_IDX_NONE; - TAILQ_INIT(&clknode->children); + if (replaced) + return (clknode); + sysctl_ctx_init(&clknode->sysctl_ctx); clknode_oid = SYSCTL_ADD_NODE(&clknode->sysctl_ctx, SYSCTL_STATIC_CHILDREN(_hw_clock), @@ -617,6 +673,10 @@ clknode_register(struct clkdom * clkdom, struct clknod { int rv; + /* Skip already registered linked node */ + if (clknode->flags & CLK_NODE_REGISTERED) + return(clknode); + rv = CLKNODE_INIT(clknode, clknode_get_device(clknode)); if (rv != 0) { printf(" CLKNODE_INIT failed: %d\n", rv); @@ -624,10 +684,24 @@ clknode_register(struct clkdom * clkdom, struct clknod } TAILQ_INSERT_TAIL(&clkdom->clknode_list, clknode, clkdom_link); - + clknode->flags |= CLK_NODE_REGISTERED; return (clknode); } + +static void +clknode_finish(void *dummy) +{ + struct clknode *clknode; + + CLK_TOPO_SLOCK(); + TAILQ_FOREACH(clknode, &clknode_list, clklist_link) { + if (clknode->flags & CLK_NODE_LINKED) + printf("Unresolved linked clock found: %s\n", + clknode->name); + } + CLK_TOPO_UNLOCK(); +} /* * Clock providers interface. */ Modified: head/sys/dev/extres/clk/clk.h ============================================================================== --- head/sys/dev/extres/clk/clk.h Fri Nov 8 18:56:02 2019 (r354553) +++ head/sys/dev/extres/clk/clk.h Fri Nov 8 18:57:41 2019 (r354554) @@ -41,7 +41,9 @@ /* clknode flags. */ #define CLK_NODE_STATIC_STRINGS 0x00000001 /* Static name strings */ #define CLK_NODE_GLITCH_FREE 0x00000002 /* Freq can change w/o stop */ -#define CLK_NODE_CANNOT_STOP 0x00000004 /* Clock cannot be disabled */ +#define CLK_NODE_CANNOT_STOP 0x00000004 /* Cannot be disabled */ +#define CLK_NODE_LINKED 0x00000008 /* Is linked clock */ +#define CLK_NODE_REGISTERED 0x00000020 /* Is already registered */ /* Flags passed to clk_set_freq() and clknode_set_freq(). */ #define CLK_SET_ROUND(x) ((x) & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) Added: head/sys/dev/extres/clk/clk_link.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/extres/clk/clk_link.c Fri Nov 8 18:57:41 2019 (r354554) @@ -0,0 +1,122 @@ +/*- + * Copyright 2016 Michal Meloun + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +static int clknode_link_init(struct clknode *clk, device_t dev); +static int clknode_link_recalc(struct clknode *clk, uint64_t *freq); +static int clknode_link_set_freq(struct clknode *clk, uint64_t fin, + uint64_t *fout, int flags, int *stop); +static int clknode_link_set_mux(struct clknode *clk, int idx); +static int clknode_link_set_gate(struct clknode *clk, bool enable); + +static clknode_method_t clknode_link_methods[] = { + /* Device interface */ + CLKNODEMETHOD(clknode_init, clknode_link_init), + CLKNODEMETHOD(clknode_recalc_freq, clknode_link_recalc), + CLKNODEMETHOD(clknode_set_freq, clknode_link_set_freq), + CLKNODEMETHOD(clknode_set_gate, clknode_link_set_gate), + CLKNODEMETHOD(clknode_set_mux, clknode_link_set_mux), + CLKNODEMETHOD_END +}; +DEFINE_CLASS_1(clknode_link, clknode_link_class, clknode_link_methods, + 0, clknode_class); + +static int +clknode_link_init(struct clknode *clk, device_t dev) +{ + return(0); +} + +static int +clknode_link_recalc(struct clknode *clk, uint64_t *freq) +{ + + printf("%s: Attempt to use unresolved linked clock: %s\n", __func__, + clknode_get_name(clk)); + return (EBADF); +} + +static int +clknode_link_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout, + int flags, int *stop) +{ + + printf("%s: Attempt to use unresolved linked clock: %s\n", __func__, + clknode_get_name(clk)); + return (EBADF); +} + +static int +clknode_link_set_mux(struct clknode *clk, int idx) +{ + + printf("%s: Attempt to use unresolved linked clock: %s\n", __func__, + clknode_get_name(clk)); + return (EBADF); +} + +static int +clknode_link_set_gate(struct clknode *clk, bool enable) +{ + + printf("%s: Attempt to use unresolved linked clock: %s\n", __func__, + clknode_get_name(clk)); + return (EBADF); +} + +int +clknode_link_register(struct clkdom *clkdom, struct clk_link_def *clkdef) +{ + struct clknode *clk; + struct clknode_init_def tmp; + + tmp = clkdef->clkdef; + tmp.flags |= CLK_NODE_LINKED; + clk = clknode_create(clkdom, &clknode_link_class, &tmp); + if (clk == NULL) + return (1); + clknode_register(clkdom, clk); + return (0); +} Added: head/sys/dev/extres/clk/clk_link.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/extres/clk/clk_link.h Fri Nov 8 18:57:41 2019 (r354554) @@ -0,0 +1,47 @@ +/*- + * Copyright 2016 Michal Meloun + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_EXTRES_CLK_LINK_H_ +#define _DEV_EXTRES_CLK_LINK_H_ + +#include + +/* + * A linked clock is used as placeholder for not yet available clock. + * It will be replaced by equally named clock from other domain, created + * in future stage of system initialization. +*/ + +struct clk_link_def { + struct clknode_init_def clkdef; + +}; + +int clknode_link_register(struct clkdom *clkdom, struct clk_link_def *clkdef); + +#endif /*_DEV_EXTRES_CLK_LINK_H_*/