From patchwork Tue Aug 16 15:18:23 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 9284153 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 02C19600CB for ; Tue, 16 Aug 2016 15:19:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EEF5928C2E for ; Tue, 16 Aug 2016 15:19:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E35A228C66; Tue, 16 Aug 2016 15:19:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2CE6728C2E for ; Tue, 16 Aug 2016 15:19:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932328AbcHPPTC (ORCPT ); Tue, 16 Aug 2016 11:19:02 -0400 Received: from mail-wm0-f54.google.com ([74.125.82.54]:38635 "EHLO mail-wm0-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753626AbcHPPS4 (ORCPT ); Tue, 16 Aug 2016 11:18:56 -0400 Received: by mail-wm0-f54.google.com with SMTP id o80so175142368wme.1 for ; Tue, 16 Aug 2016 08:18:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netronome-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=bRRqM5nHj5mgHPT5/am+00straHvoDqDAgX7qp4HYYA=; b=eeu0cUtdwkF+pWqnQD+QBtZtcDSlKnu+dDoRcnE3QTQ3dXexrD96WuWHkW+P0U1zje wRSgzXozaFOnJ6lHaPoBlS66EfW/6TiWzrrYPqrcvT8dzeSM+PUMidYzUVoit8wgVws6 jiXUOkwrqGDROSswyd3ZIZYpXvFTTr7Q+ZL4JYZXBe9OlQJZx/J3jb+tAFm0+/ANeF16 4KiiM5VjbpEpggHlWo82POfptWhBoypNuGiyXjsVls1A6ASRqupLH3J6CySWcWYxie6B EcwBmTjSJBLsqUBzSg0J6N+g3EaIHKWtqU36x8kyKbpbRnaXr3cTN/gAYG86x9AGm65m 4xbQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=bRRqM5nHj5mgHPT5/am+00straHvoDqDAgX7qp4HYYA=; b=HNg0tcCaMWmaGGcotBs6YtZjCtZO10zedZuz3xuUT7D1rqfZK5Ao5v51k1NxjU+yde Y+MzZfc+ADO2Shdnl/Dh8T4YsZh3SHK+HpMTsSvjErpPqEJ0Dyo6BOlD8wZbGJTNqkOU CjfftCBTXowdmzk4tR+mya/SjuaHMDHi81iof14j0uOCF8zdtUHjdd18SWQq7diGl2xe vMyfMl92A3ppPYUU8Deo2H7j24psdg+nJmpUhPJiRqY4XBiJn6dGgfLlV60Wy4MrJoFO NODDziy5XBKUaCXLZlqjR8oRCwSBj/rEGrYNTSlYxdVvzpOlZ7GwmnK7zB0Z8WJxZrE7 fwyw== X-Gm-Message-State: AEkoousG/FNRWmd1+LOZnQY8mXD5E9CRYlYTAM2ritIN8NNdUd76EwJqO4Wy1kLJfDN6xop7 X-Received: by 10.28.23.141 with SMTP id 135mr23368829wmx.100.1471360734786; Tue, 16 Aug 2016 08:18:54 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com (host-79-78-33-110.static.as9105.net. [79.78.33.110]) by smtp.gmail.com with ESMTPSA id cw7sm27199191wjb.38.2016.08.16.08.18.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 16 Aug 2016 08:18:53 -0700 (PDT) From: Jakub Kicinski To: torvalds@linux-foundation.org, akpm@linux-foundation.org, gregkh@linuxfoundation.org, davem@davemloft.net, kvalo@codeaurora.org Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org, dinan.gunawardena@netronome.com, Jakub Kicinski Subject: [PATCHv6 1/2] add basic register-field manipulation macros Date: Tue, 16 Aug 2016 16:18:23 +0100 Message-Id: <1471360704-10507-2-git-send-email-jakub.kicinski@netronome.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1471360704-10507-1-git-send-email-jakub.kicinski@netronome.com> References: <1471360704-10507-1-git-send-email-jakub.kicinski@netronome.com> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Common approach to accessing register fields is to define structures or sets of macros containing mask and shift pair. Operations on the register are then performed as follows: field = (reg >> shift) & mask; reg &= ~(mask << shift); reg |= (field & mask) << shift; Defining shift and mask separately is tedious. Ivo van Doorn came up with an idea of computing them at compilation time based on a single shifted mask (later refined by Felix) which can be used like this: #define REG_FIELD 0x000ff000 field = FIELD_GET(REG_FIELD, reg); reg &= ~REG_FIELD; reg |= FIELD_PUT(REG_FIELD, field); FIELD_{GET,PUT} macros take care of finding out what the appropriate shift is based on compilation time ffs operation. GENMASK can be used to define registers (which is usually less error-prone and easier to match with datasheets). This approach is the most convenient I've seen so to limit code multiplication let's move the macros to a global header file. Attempts to use static inlines instead of macros failed due to false positive triggering of BUILD_BUG_ON()s, especially with GCC < 6.0. Signed-off-by: Jakub Kicinski Reviewed-by: Dinan Gunawardena --- include/linux/bitfield.h | 109 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/bug.h | 3 ++ 2 files changed, 112 insertions(+) create mode 100644 include/linux/bitfield.h diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h new file mode 100644 index 000000000000..ff9fd0af2ac7 --- /dev/null +++ b/include/linux/bitfield.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 Felix Fietkau + * Copyright (C) 2004 - 2009 Ivo van Doorn + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _LINUX_BITFIELD_H +#define _LINUX_BITFIELD_H + +#include +#include + +#define _bf_shf(x) (__builtin_ffsll(x) - 1) + +#define _BF_FIELD_CHECK(_mask, _val) \ + ({ \ + BUILD_BUG_ON(!(_mask)); \ + BUILD_BUG_ON(__builtin_constant_p(_val) ? \ + ~((_mask) >> _bf_shf(_mask)) & (_val) : \ + 0); \ + __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \ + (1ULL << _bf_shf(_mask))); \ + }) + +/* + * Bitfield access macros + * + * This file contains macros which take as input shifted mask + * from which they extract the base mask and shift amount at + * compilation time. There are two separate sets of the macros + * one for 32bit registers and one for 64bit ones. + * + * Fields can be defined using GENMASK (which is usually + * less error-prone and easier to match with datasheets). + * + * FIELD_{GET,PUT} macros are designed to be used with masks which + * are compilation time constants. + * + * Example: + * + * #define REG_FIELD_A GENMASK(6, 0) + * #define REG_FIELD_B BIT(7) + * #define REG_FIELD_C GENMASK(15, 8) + * #define REG_FIELD_D GENMASK(31, 16) + * + * Get: + * a = FIELD_GET(REG_FIELD_A, reg); + * b = FIELD_GET(REG_FIELD_B, reg); + * + * Set: + * reg = FIELD_PUT(REG_FIELD_A, 1) | + * FIELD_PUT(REG_FIELD_B, 0) | + * FIELD_PUT(REG_FIELD_C, c) | + * FIELD_PUT(REG_FIELD_D, 0x40); + * + * Modify: + * reg &= ~REG_FIELD_C; + * reg |= FIELD_PUT(REG_FIELD_C, c); + */ + +/** + * FIELD_PUT() - construct a bitfield element + * @_mask: shifted mask defining the field's length and position + * @_val: value to put in the field + * + * FIELD_PUT() masks and shifts up the value. The result should + * be combined with other fields of the bitfield using logical OR. + */ +#define FIELD_PUT(_mask, _val) \ + ({ \ + _BF_FIELD_CHECK(_mask, _val); \ + ((u32)(_val) << _bf_shf(_mask)) & (_mask); \ + }) + +/** + * FIELD_GET() - extract a bitfield element + * @_mask: shifted mask defining the field's length and position + * @_val: 32bit value of entire bitfield + * + * FIELD_GET() extracts the field specified by @_mask from the + * bitfield passed in as @_val. + */ +#define FIELD_GET(_mask, _val) \ + ({ \ + _BF_FIELD_CHECK(_mask, 0); \ + (u32)(((_val) & (_mask)) >> _bf_shf(_mask)); \ + }) + +#define FIELD_PUT64(_mask, _val) \ + ({ \ + _BF_FIELD_CHECK(_mask, _val); \ + ((u64)(_val) << _bf_shf(_mask)) & (_mask); \ + }) + +#define FIELD_GET64(_mask, _val) \ + ({ \ + _BF_FIELD_CHECK(_mask, 0); \ + (u64)(((_val) & (_mask)) >> _bf_shf(_mask)); \ + }) + +#endif diff --git a/include/linux/bug.h b/include/linux/bug.h index e51b0709e78d..bba5bdae1681 100644 --- a/include/linux/bug.h +++ b/include/linux/bug.h @@ -13,6 +13,7 @@ enum bug_trap_type { struct pt_regs; #ifdef __CHECKER__ +#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) (0) #define BUILD_BUG_ON_NOT_POWER_OF_2(n) (0) #define BUILD_BUG_ON_ZERO(e) (0) #define BUILD_BUG_ON_NULL(e) ((void*)0) @@ -24,6 +25,8 @@ struct pt_regs; #else /* __CHECKER__ */ /* Force a compilation error if a constant expression is not a power of 2 */ +#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) \ + BUILD_BUG_ON(((n) & ((n) - 1)) != 0) #define BUILD_BUG_ON_NOT_POWER_OF_2(n) \ BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))