From patchwork Tue Jan 17 16:28:37 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sergei Trofimov X-Patchwork-Id: 91691 Delivered-To: patch@linaro.org Received: by 10.140.20.99 with SMTP id 90csp574302qgi; Tue, 17 Jan 2017 08:29:40 -0800 (PST) X-Received: by 10.237.37.50 with SMTP id v47mr32914497qtc.126.1484670580692; Tue, 17 Jan 2017 08:29:40 -0800 (PST) Return-Path: Received: from lists.linaro.org (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTP id j22si16937564qtj.123.2017.01.17.08.29.40; Tue, 17 Jan 2017 08:29:40 -0800 (PST) Received-SPF: pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) client-ip=54.225.227.206; Authentication-Results: mx.google.com; spf=pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) smtp.mailfrom=lng-odp-bounces@lists.linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id 47D3A60ED5; Tue, 17 Jan 2017 16:29:40 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on ip-10-142-244-252 X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAD_ENC_HEADER,BAYES_00, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, URIBL_BLOCKED autolearn=disabled version=3.4.0 Received: from [127.0.0.1] (localhost [127.0.0.1]) by lists.linaro.org (Postfix) with ESMTP id 48B5060951; Tue, 17 Jan 2017 16:29:02 +0000 (UTC) X-Original-To: lng-odp@lists.linaro.org Delivered-To: lng-odp@lists.linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id A844660955; Tue, 17 Jan 2017 16:28:54 +0000 (UTC) Received: from EUR01-HE1-obe.outbound.protection.outlook.com (mail-he1eur01on0069.outbound.protection.outlook.com [104.47.0.69]) by lists.linaro.org (Postfix) with ESMTPS id 27FAA60641 for ; Tue, 17 Jan 2017 16:28:52 +0000 (UTC) Received: from e109786-lin.cambridge.arm.com (217.140.96.140) by AM5PR0801MB1746.eurprd08.prod.outlook.com (10.169.247.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.845.12; Tue, 17 Jan 2017 16:28:50 +0000 From: Sergei Trofimov To: Date: Tue, 17 Jan 2017 16:28:37 +0000 Message-ID: <1484670521-28503-2-git-send-email-sergei.trofimov@arm.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1484670521-28503-1-git-send-email-sergei.trofimov@arm.com> References: <1484670521-28503-1-git-send-email-sergei.trofimov@arm.com> MIME-Version: 1.0 X-Originating-IP: [217.140.96.140] X-ClientProxiedBy: DB6PR0301CA0004.eurprd03.prod.outlook.com (10.168.49.14) To AM5PR0801MB1746.eurprd08.prod.outlook.com (10.169.247.12) X-MS-Office365-Filtering-Correlation-Id: d55d6023-8017-4925-381f-08d43ef5eb99 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001); SRVR:AM5PR0801MB1746; X-Microsoft-Exchange-Diagnostics: 1; AM5PR0801MB1746; 3:nong69LN6LRYpHroVskbSO3YbhoMc9irO6IoTe0u3WZgPnB87pwZqCtc36a4O2GbXtrmJWnMVN4Zs/JJ2yhJIh/zlsSXBP7dljk12/eqNk9GPvls0lrino+n7TW4JEA4tVYTNYv3ectr7MZM6fnqiW6NCKw6b+h9VMjQwMMndk+AyikQIp/RIr/Pq4K9DEqWuTshmL6unZkldDXMjy7Hbwfdt6gfL4amULIA7M5j4QGXpkPaHPrFNWyZzj0sbp0IBD47uSiwjSCVJaL2Kat8sA== X-Microsoft-Exchange-Diagnostics: 1; AM5PR0801MB1746; 25:oFF4VsODg9VHh3Q+fe6IKYRLcBzQR4HzOx/ed3Z/QnoZKrbuUE4F9vmL+mQxhYdv2QXHQfvq+n3obDDx0IYMuTL8qOqLHMCn8LlFXrYOvsCFN6swzPynqjJtbJrtYU+oYRi4U3d/be30sFeLp4y8St5nL12IgY1zurwlqa2R2WIm9uM2usdEXFUFZ5xTDC3k9g4N/wNX28F2wT9pJkYNEIPFubOynDukg4XnVIsYyFNjQ03pZ/PmUlgYzvplfb1sR+3eMn9cWstz/icevj+N+TvvOtpDoJ6tQX1vECHA19UiZiVaOwRF96sZTsPhqp6nGQeJ/dSO71FymxKVA4WqTn/sHlnFBv7I0wQvtRoqUeHayShsjgV0gDFyL9agwCLLzXnk4AnbYsGV1tn4+x1c/UxN+5QlqL1Wweiq0k0oHoeXaHxvpWJyYT1U6Xyzt6u1VL8odh724Q+irlkYiZPuSCQDFTy3K7VfSaJQpKfl1JDbnlKUhyZRIAu2c2zu+102LKyVmeQoEOQC/6rBaIeHTh6hxgbNKpdnkKY7J99RdrTuL8mKzES5u3VtJ462MyLHXtbtzHTtfWUhWoAgmwiPzfM3VfFaIAsbthhA5BMZRCj3kHFzWU6DS5nU4XWumL5GoeDG63Kq+mx5a6uWL+gjsn3yEK8JbEraInO1FV2D2ZXyTBKpUk1FnxQDdDIuFQogdOQF5BloouziKRxXvisYU0+gYDWtfleTAkKbN5Wc7WDcTbm1qWapAURUkzOgbXY45QrcNDefveK/B/EoPp9SLw== X-Microsoft-Exchange-Diagnostics: 1; AM5PR0801MB1746; 31:TJLP7Slgv0shUs5EjriiIwvDkT2cnnO2n9GbIWf3k29CrlrVvVUjf1XNrN7PIKWXj/H7KKXyFrfmerRH7Zv8k6bKBZJBHtZDjr71wvn3DYkpWbBUZhAP5MdX0tz7x1GVYKZrcufOPCLxmBpYR3YGwAT5g84BixCTzoDQbh1b22x1ydBCTp9TAIngfuHEeaG6dahzEDU4o8HORB02RFjBbynbnACGdjYSG2xFMJJ/hMUc4x7SjMAYguEO2kCHDvDEQmxGnBX7JMmL8cndbNGFGQ==; 20:NFMYPsutTzPnnvYHXKI7mq9WG0YemGSBaDCEBMgeTNOUPCjeNnmKG/VraDzjQjdLYJZ9aJaicy6txcTZLE+N+XS1nJBiKudnAvE/Kn0aJQDYIDD+UZvVyTr45HrTJyI1Z027WeU6rHBoSf1OqBYlcR4Bewjfg9S7/aCYpXk+WrY= NoDisclaimer: True X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(180628864354917); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040375)(601004)(2401047)(5005006)(8121501046)(10201501046)(3002001)(6055026)(6041248)(20161123555025)(20161123560025)(20161123564025)(20161123562025)(6072148); SRVR:AM5PR0801MB1746; BCL:0; PCL:0; RULEID:; SRVR:AM5PR0801MB1746; X-Microsoft-Exchange-Diagnostics: 1; AM5PR0801MB1746; 4:W6+Y7mqA1pWFPFI54QSkYSWrOIMK2sixjqjOjJVtnRTLHTybVpHkJGbVWoZV0RVl2H6pKFx+T3SpBB9YiIN+jQmUo7PYecgKxG0muv5mln4msEvqRMh3b9gRsXnpaIATROGRTJUOgXVk0PNHCFoSq3ldImJNmM3CIx5gnBSluvK6v+T0zz46YZHVDpjnOdJXJcUA0LsTS3UVuvXiPycAcXQOOT1yRc9yLFRsZoPwTTTQnOQkRllwrBakcH2/jEe5Rf+3PP7GK+gGaXKL/jisQ5OTMTvYPxryhUbjKcXjdued3D6E51ckZ7ZRh1igDuyLuMfZ2afb6pxG6dzal7izF+Nj7K6MQWLD4v0VrodIR4Y+X9dZegpMcgp5SJYk0j4m+4C16q3CL9R4p3uL1jmUapI503F/U+rmEQQ+nk4a1yUC/ytg5mWUHCiXhPdeBBRyUV6ZYXqs06a4x7Z9MN634pNAnJXMaMWq1waqPI4LPn547olsZJGgO+jXnWiF2B/8Ji3qoJcuaN3D1fquNNynXlLKec+xDSQl46YD1cmUF8STfq4doAa+8C/Npvkh1i3adXY8P7slXVLbxZxonEBCZr0gUQUvdCKoXcO+zzWSNPVLJUBR4JyF0Z0D+jv/S7+uiyJlZS6Mr2HVadzOIAycuQ== X-Forefront-PRVS: 01901B3451 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(4630300001)(6009001)(7916002)(39450400003)(39840400002)(39410400002)(39860400002)(39850400002)(199003)(189002)(6666003)(81166006)(8676002)(50226002)(81156014)(305945005)(450100001)(7736002)(38730400001)(2950100002)(6116002)(97736004)(92566002)(6916009)(47776003)(2906002)(3846002)(54906002)(33646002)(66066001)(48376002)(50466002)(50986999)(189998001)(4326007)(76176999)(25786008)(36756003)(6486002)(110136003)(106356001)(105586002)(5660300001)(101416001)(68736007)(42186005)(2351001)(86362001)(5003940100001)(217873001); DIR:OUT; SFP:1101; SCL:1; SRVR:AM5PR0801MB1746; H:e109786-lin.cambridge.arm.com; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: arm.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; AM5PR0801MB1746; 23:+8gaI3cUiXL9PmpXVSR5yQBwFSE1QaiYKkqvtJ9?= IMmxp66N2tnpoCis4QdrnRRFizmTFE5LUI3o1OSFJmKGEfTdWsAO+jz05aryj8oIc6MqhO6veWoDbebLdpjwAnA/cJZZUdYbVpAvUTgHmMAnB00nXIWtoGc9lherZl86x+2doV3AUXux6Z8iCCf9WrNFoIUhU+l4dnjvztqppxd7zjV9jKynJ44T0HrGOHXqbnoTUQ5B0Fgx9uM3q4LBATmfYC8ZLMZkrJbV2RT7TAeHsbDFxJpEYyDaZHOJjEb4xAZZXNQJMW5H3rAt+6emVzjRctIvQSyWTswhJIrlYk9ddQYLPCVtPrnHvy7l2Dp0YGlSF9ifByNKvTdeBRCqMlQMB2AS1r4bwY57MyrdsMGj/aIsR3YXG+7Fi/D2kOdj3SsfVUnYwhNYjj1nAuX9QwsBMLI+wFhM7CS9jsbq3F5vjAi6lX6mxV0pCeWM9KkyT7xl03JVjo8ta+nUnzprNhSUdeHh0MWJqtonXZZnPkRPTmYKjscKOlsVEe/7W54IpKq6udCV5TPKz1oxNusB0q2f21klJY8zcSk/lltQwXM9rt9EQhlJevpe/ejLEHdvGyTPe/j76jKf5PE8VN8KJlxSEFkEs8RE7kx1q9TrgR6UPh3Q5Qikdxd5PHuovk6eNt07muNmFA+PemL8dY17FodAqOi9vxeo0w4zULUU7RLJUBfBmxLAwsdV1z3bsF76s5wcpmh+J0dQgvXRkNU02937T0/DVyh1PGxYbikJ+Am5D0S8+RaaLp6j7z2bT215FTxN/+0rINSsFqIStu8NOr7sV90vMzJ8lRnrA6psP0GaPlLvkS9fZt3b2x3Gaem8nAcV3QxCqkSu7KxgUhO7Lfz42Uwf2bvwCcXmOMjVRf6LVuF43YsvdP7lPgejEZMYwtOLBTXDXomhinc6vHWxQ4utyBACmVfTO9yYSErwOWy9RYPhab75zlSPBxfYK4njYUXjHO6rjWboXS+sAFPvhMl1mLluRtp/tnwOodxN46InYRCGdVj52E2iOeDHaTn3xLOMNjpiA5Su3ilhRuqqKUXX2amw4gX0ktYFuiZdXii97WkbBMv1VuMrWlaBIeH4kbZKVmGylGqSVNROY4/Rz5r3iM6sdjMTiyhMHbvATqGs5K44NLygFRQ638Pp4bk9sUFs2S0ajcJrreTpcAb7Noud+3nWsol/+H5XFR8Lw+sExew== X-Microsoft-Exchange-Diagnostics: 1; AM5PR0801MB1746; 6:seLHcTQQOqzpUS63a4os4URQq1AVsTlrIo8R7dCM9CH0ipM/TR7J2QPw8l1uaAcB3WZzbHO2wnxlgHiLmOG8Tz5lDYm0Dx6x9YDaOPEQU4LwniSn9aFg0zr8HNvpDvplWHHO6Fa0M7Mb+QET73JyGLNnLS1ZbkiFExESbds0w6vs2dv3aNzMu3W5kYxMTRfeBjzErZ5DPTgYpS9l2LqXHedJs89h5x+sNLxuZn6TcnBkIycwvpYZA4H3mhXOsfv0IEOO/HcXwX+/AF91Rmsn4/lynK8dTyFy53muA+c/uygtyMuj7GG3t3QClg3ivvq5wnLlz4LFl5cda4zSKUS5tCmN+qUt7q0tbpj6e7JBUbKepZC8NODDb9fhMgP+PnYmXmir44m35TIDNJq+vz+GJFXtvzskebbbrASMPQzhjz3sSI+HxkJZ3BMhZpBef1rM/HN+nOh3AnDGHprKotDZSg==; 5:ucnO6wvuRDL9ZKGSeNuapWdVi45Wi5eUAtVbjnkWvVzGCV6arXYSdkP7D6PsxuDzbQCM0iGtALq2sbhedD2NxxllV+ckCjZ9ICX1a2VkgRbNKatRxRDY6Dm5Zw/4wL7+kj7gxCCrrP4MHaW+hRnjMg==; 24:QyP6FNJPscZDuc46d2CY03VHmgxsYzpd67+7ZHUBsBjUuuhfwl76syGLd+im2Jkp/xWGIRLWW6c0lc8eEfHgy9WiSwb88Q7rQ3wviBBSRyk= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; AM5PR0801MB1746; 7:M0O3JaSA6HAfwVfNBvxeTpYN3XLdF2k9urlrum32mBuLoymrVwxypUWmlbvqf6X6/ffsBqd5uUl41GQQtbW5Tt/qmxu1HfyhWvXjNzjqGSxZ+n8ssr4X+DQ4mqDuZjPIj2MXgNapNdYg9jtisLhWiqxRRe/AMmaAEXBhBWeYX2Ofvc+UYwRlA042X9/M/TF10MZ4f94bvs5gUuNubLR31n2C40BxNpTXfuS+He96gxrckpI7drwYLFESNOBIOix6tF5rk59WNUajdRGcF9Lva4Mxix4lzAFKlW+mfTQefAZzrdvKqwNYnfj+hlzdPecsNk+ddMW0fPaqnj1GipOvqU0j382BP/wDWcx04NsokehNOVw3gJ3LSpgewLESD8H7ttWAX3VNAd/tT3AI7zdNTqQHmqXLuPbyXUEEShRkdp4JcQMsHQFllSpYYzjhmUlAmfJT5jhlB1u/XAajwD8xmw== X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 Jan 2017 16:28:50.4157 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM5PR0801MB1746 Cc: nd@arm.com Subject: [lng-odp] [API-NEXT PATCH 1/5] power: added API for managing CPU DVFS X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: "The OpenDataPlane \(ODP\) List" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: lng-odp-bounces@lists.linaro.org Sender: "lng-odp" Added APIs for quiering available CPU power/frequency domains and setting their frequencies. Current implementation assumes that Linux is using userspace cpufreq governor. Signed-off-by: Sergei Trofimov --- include/odp/api/spec/power.h | 116 ++++++++++ include/odp_api.h | 1 + platform/Makefile.inc | 1 + platform/linux-generic/Makefile.am | 2 + platform/linux-generic/include/odp/api/power.h | 1 + platform/linux-generic/odp_power.c | 294 +++++++++++++++++++++++++ 6 files changed, 415 insertions(+) create mode 100644 include/odp/api/spec/power.h create mode 100644 platform/linux-generic/include/odp/api/power.h create mode 100644 platform/linux-generic/odp_power.c -- 1.9.1 diff --git a/include/odp/api/spec/power.h b/include/odp/api/spec/power.h new file mode 100644 index 0000000..26dd64e --- /dev/null +++ b/include/odp/api/spec/power.h @@ -0,0 +1,116 @@ +/* Copyright (c) 2016, ARM Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +/** + * @file + * + * CPU power management + */ + +#ifndef ODP_POWER_H +#define ODP_POWER_H + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * CPU power domain description. + * + */ +typedef struct odp_power_domain_s{ + /** Number of possible performance levels in the domain. */ + int num_perf_levels; + /** Valid performance levels for the domain. Higher numeric values + * represent more performance. The units for performance levels are + * platform-specific. */ + int *perf_levels; + /** CPUs in this power domain */ + odp_cpumask_t cpus; +} odp_power_domain_t; + + +/** + * Information about the discovered power domains. + * + */ +typedef struct odp_power_domain_info_s { + /** Number of discovered power domains */ + int num_domains; + /** Discovered power domains */ + odp_power_domain_t *domains; +} odp_power_domain_info_t; + +/** + * Populate power domains info for this platform. + * + * Discover power domains available on the platform and populate the + * domain info object with them. + * + * + * @param info power domains info to be initialized + * + * @return zero on success or negative error value on error + * + */ +int odp_power_domain_info_populate(odp_power_domain_info_t *info); + +/** + * Destroy a previously init'd info struct, releasing associated resources. + * + * + * @param info power domains info to be terminated + * + */ +void odp_power_domain_info_destroy(odp_power_domain_info_t *info); + +/** + * Return the power domain associated with the specified cpu + * + * @param info contains information about power domains + * @param cpu CPU whose power domain will be returned + * + * @return a pointer to the power domain or NULL on error + * + */ +odp_power_domain_t *odp_power_domain_for_cpu(odp_power_domain_info_t *info, int cpu); + +/** + * Set performance level of the specified domain + * + * @param domain domain for which frequency will be set + * @param level the performance level to set + * + * @return zero on success or negative error value on error + * + */ +int odp_power_domain_set_perf_level(odp_power_domain_t *domain, int level); + + +/** + * Return the current performance level of the specified domain + * + * @param domain domain for which performance level will be set + * + * @return performance level + * + */ +uint64_t odp_power_domain_get_perf_level(odp_power_domain_t *domain); + +#ifdef __cplusplus +} +#endif + +#include +#endif // ODP_POWER_H diff --git a/include/odp_api.h b/include/odp_api.h index 73e5309..983e44f 100644 --- a/include/odp_api.h +++ b/include/odp_api.h @@ -58,6 +58,7 @@ extern "C" { #include #include #include +#include #ifdef __cplusplus } diff --git a/platform/Makefile.inc b/platform/Makefile.inc index aefbf9a..8427117 100644 --- a/platform/Makefile.inc +++ b/platform/Makefile.inc @@ -40,6 +40,7 @@ odpapispecinclude_HEADERS = \ $(top_srcdir)/include/odp/api/spec/packet_io.h \ $(top_srcdir)/include/odp/api/spec/packet_io_stats.h \ $(top_srcdir)/include/odp/api/spec/pool.h \ + $(top_srcdir)/include/odp/api/spec/power.h \ $(top_srcdir)/include/odp/api/spec/queue.h \ $(top_srcdir)/include/odp/api/spec/random.h \ $(top_srcdir)/include/odp/api/spec/rwlock.h \ diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index 6bbe775..738c582 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -43,6 +43,7 @@ odpapiinclude_HEADERS = \ $(srcdir)/include/odp/api/packet_io.h \ $(srcdir)/include/odp/api/packet_io_stats.h \ $(srcdir)/include/odp/api/pool.h \ + $(srcdir)/include/odp/api/power.h \ $(srcdir)/include/odp/api/queue.h \ $(srcdir)/include/odp/api/random.h \ $(srcdir)/include/odp/api/rwlock.h \ @@ -205,6 +206,7 @@ __LIB__libodp_linux_la_SOURCES = \ pktio/ring.c \ odp_pkt_queue.c \ odp_pool.c \ + odp_power.c \ odp_queue.c \ odp_rwlock.c \ odp_rwlock_recursive.c \ diff --git a/platform/linux-generic/include/odp/api/power.h b/platform/linux-generic/include/odp/api/power.h new file mode 100644 index 0000000..f012bf5 --- /dev/null +++ b/platform/linux-generic/include/odp/api/power.h @@ -0,0 +1 @@ +#include diff --git a/platform/linux-generic/odp_power.c b/platform/linux-generic/odp_power.c new file mode 100644 index 0000000..df41655 --- /dev/null +++ b/platform/linux-generic/odp_power.c @@ -0,0 +1,294 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PATH 255 +#define MAX_LINE MAX_PATH +#define MAX_PERF_LEVEL INT_MAX +#define MIN_PERF_LEVEL 0 + +typedef enum { + INT, + /*UINT,*/ + /*DOUBLE,*/ + POINTER +} ll_entry_type_t; + +struct ll_entry_s; +typedef struct ll_entry_s { + struct ll_entry_s *next; + union { + int64_t i64; + uint64_t u64; + double d; + void *p; + } value; + ll_entry_type_t type; +} ll_entry_t; + +typedef struct { + int num; + ll_entry_t *head; + ll_entry_t **ptail; +} llist_t; + +#define DEFINE_LLIST_ADD(NAME, TYPE, VALNAME, TYPE_ENUM) \ + static int llist_add_##NAME(llist_t *list, TYPE val);\ + static int llist_add_##NAME(llist_t *list, TYPE val) {\ + ll_entry_t *new = malloc(sizeof(ll_entry_t));\ + if (new == NULL)\ + return ENOMEM;\ + new->next = NULL;\ + new->type = TYPE_ENUM;\ + new->value.VALNAME = val;\ + *(list->ptail) = new;\ + list->ptail = &(new->next);\ + list->num++;\ + return 0;\ + } + +DEFINE_LLIST_ADD(int,int64_t,i64,INT); +DEFINE_LLIST_ADD(ptr,void *,p,POINTER); +/*DEFINE_LLIST_ADD(uint,uint64_t,u64,UINT);*/ +/*DEFINE_LLIST_ADD(double,double,d,DOUBLE);*/ + +static void llist_init(llist_t *list) { + list->num = 0; + list->head = NULL; + list->ptail = &list->head; +} + +static void llist_fini(llist_t *list) { + ll_entry_t *current, *next; + next = list->head; + while (next != NULL) { + current = next; + next = next->next; + free(current); + } + list->num = 0; +} + +static int read_int_list(char *path, int **list, int *num); +static int int_cmp(const void *val1, const void *val2); +static void get_related_cpus(int cpu_id, int **related_cpus, int *num); +static inline int check_in_array(int *arr, int size, int item); +static void get_available_cpu_frequencies(int cpu_id, int **freqs, int *num); + +int odp_power_domain_info_populate(odp_power_domain_info_t *info) { + int num_cpus = sysconf(_SC_NPROCESSORS_CONF); + + info->num_domains = 0; + + llist_t dom_list; + llist_init(&dom_list); + odp_cpumask_t processed; + odp_cpumask_zero(&processed); + int i; + for(i = 0; i < num_cpus; i++) { + + if (odp_cpumask_isset(&processed, (1ULL << i))) { + continue; + } + + odp_power_domain_t *dom = malloc(sizeof(odp_power_domain_t)); + if (dom == NULL) + goto return_nomem; + odp_cpumask_zero(&dom->cpus); + + int *related; + int num; + get_related_cpus(i, &related, &num); + get_available_cpu_frequencies(i, &(dom->perf_levels), &(dom->num_perf_levels)); + qsort(dom->perf_levels, dom->num_perf_levels, sizeof(int), int_cmp); + + int j; + for (j = 0; j < num; j++) { + + odp_cpumask_set(&dom->cpus, related[j]); + odp_cpumask_set(&processed, related[j]); + } + + llist_add_ptr(&dom_list, (void *)dom); + } + + info->domains = malloc(sizeof(odp_power_domain_t) * dom_list.num); + if (info->domains == NULL) + goto return_nomem; + + ll_entry_t *dom_entry = dom_list.head; + for (i = 0; i < dom_list.num; i++) { + memcpy(&(info->domains[i]), dom_entry->value.p, sizeof(odp_power_domain_t)); + free(dom_entry->value.p); + dom_entry = dom_entry->next; + } + info->num_domains = dom_list.num; + llist_fini(&dom_list); + + return 0; + +return_nomem: + dom_entry = dom_list.head; + for (i = 0; i < dom_list.num; i++) { + free(dom_entry->value.p); + dom_entry = dom_entry->next; + } + llist_fini(&dom_list); + return -ENOMEM; +} + +void odp_power_domain_info_destroy(odp_power_domain_info_t *info) +{ + int i; + for (i = 0; i < info->num_domains; i++) { + free(info->domains[i].perf_levels); + } + free(info->domains); +} + +odp_power_domain_t *odp_power_domain_for_cpu(odp_power_domain_info_t *info, int cpu) { + int i; + for (i = 0; i < info->num_domains; i++) { + odp_power_domain_t *dom = &info->domains[i]; + if (odp_cpumask_isset(&dom->cpus, cpu)) + return dom; + } + + return NULL; +} + +int odp_power_domain_set_perf_level(odp_power_domain_t *domain, int level) { + if (level == MAX_PERF_LEVEL) { + level = domain->perf_levels[domain->num_perf_levels - 1]; + } + if (level == MIN_PERF_LEVEL) { + level = domain->perf_levels[0]; + } + if (!check_in_array(domain->perf_levels, domain->num_perf_levels, level)) { + return -EINVAL; + } + + // Note: this assumes that the current governor is userspace + char path[MAX_PATH]; + int cpu = odp_cpumask_first(&domain->cpus); + snprintf(path, MAX_PATH, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_setspeed", cpu); + + FILE *f = fopen(path, "w"); + if (f == NULL) { + return errno; + } + + int err = fprintf(f, "%d", level); + if (err < 0) { + fclose(f); + return err; + } + + err = fclose(f); + return err; + +} + +uint64_t odp_power_domain_get_perf_level(odp_power_domain_t *domain) { + char path[MAX_PATH]; + int cpu = odp_cpumask_first(&domain->cpus); + snprintf(path, MAX_PATH, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", cpu); + + FILE *f = fopen(path, "r"); + if (f == NULL) { + return errno; + } + + char buffer[MAX_PATH]; + char *ret = fgets(buffer, MAX_PATH, f); + fclose(f); + if (ret == NULL) + return 0; + + return atoi(buffer); +} + +static int read_int_list(char *path, int **list, int *num) { + FILE *f = fopen(path, "r"); + char line[MAX_PATH]; + + char *ret = fgets(line, MAX_PATH, f); + fclose(f); + if (ret == NULL) + return -EIO; + + llist_t llist; + llist_init(&llist); + + *num = 0; + char *part = strtok(line, " "); + while(part != NULL) { + if (part[0] == '\n') + break; + llist_add_int(&llist, atoi(part)); + part = strtok(NULL, " "); + } + + *list = malloc(sizeof(int) * llist.num); + if (*list == NULL) { + llist_fini(&llist); + return -ENOMEM; + } + + int i = 0; + ll_entry_t *entry = llist.head; + while (entry != NULL) { + (*list)[i++] = entry->value.i64; + entry = entry->next; + } + *num = llist.num; + + llist_fini(&llist); + + return 0; +} + +static int int_cmp(const void *val1, const void *val2) { + int one = *((const int *)val1); + int two = *((const int *)val2); + + if (one > two) + return 1; + if (one < two) + return -1; + return 0; +} + +static inline int check_in_array(int *arr, int size, int item) { + int i; + for (i = 0; i < size; i++) { + if (arr[i] == item) + return 1; + } + + return 0; +} + +static void get_related_cpus(int cpu_id, int **related_cpus, int *num) { + char path[MAX_PATH]; + snprintf(path, MAX_PATH, "/sys/devices/system/cpu/cpu%d/cpufreq/affected_cpus", cpu_id); + int ret = read_int_list(path, related_cpus, num); + if (ret) + fprintf(stderr, "ERROR: could not read affected_cpus for CPU %d\n", cpu_id); +} + +static void get_available_cpu_frequencies(int cpu_id, int **freqs, int *num) { + char path[MAX_PATH]; + snprintf(path, MAX_PATH, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_available_frequencies", cpu_id); + int ret = read_int_list(path, freqs, num); + if (ret) + fprintf(stderr, "ERROR: could not read avaliable frequencies for CPU %d\n", cpu_id); +} +