Received: by 2002:ac0:a5a6:0:0:0:0:0 with SMTP id m35-v6csp56339imm; Wed, 29 Aug 2018 13:50:37 -0700 (PDT) X-Google-Smtp-Source: ANB0VdZiR0PaNIUDBGGk9cBURgVLEzlc2Vz05ayjsCXtMzAqm4n0GPKxOJW4a1675+zAVB6tCnT3 X-Received: by 2002:a62:89d8:: with SMTP id n85-v6mr7447911pfk.83.1535575837198; Wed, 29 Aug 2018 13:50:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1535575837; cv=none; d=google.com; s=arc-20160816; b=hNIMNlBnppKFSyWMPAQ2VyjJiQw3sdlmC44OHCDI4yoFsIl9WqufAcCsQVkuKwDP4H VCw0rX9guWYIMcxSOaCUEcZ8iC0whZz/KNcViwZj7+sdxkCm0VOQeFcSoGGs+sj3e7L8 50ozIGofVkawyI40n1bXARU9Ds/Gw6X56t81EXyIBaKM33b3bJo7nSFgShMG+bd2ZpHW pV/QypeXnlmKfqFZwVrX2Yx3xyonZBA6zgG8Q8kFIKU7FCC2JHdiwnauuK6xJSiCGQc1 YvIeOK3rjw4eKyhZKo4/87Czr0H3wfgO2u24j5vdhIRPeAHRhu9Z2RrQ05FuE5URfPBa k8VQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=uh7mqvxXnjaw9WCsqO1jdthyZWLvGWRFnitWjcEgjoA=; b=OFewnhvCjprlFEXoGcyQy9TG8IUkzjrqMi3nT38NEWGU5JXRVAuoBbKLNyBE2hQts/ vFf29BciM5JkCiGH1TCAV7tW+fbA6dVVBZ+20MPu2KlTWqkWqqRpewo+WI+Qd2uaMJlj OGnde830nV69MydiAGHTiya3oT7a/gIp2M1k112U34Z118Qh5orLEJtXFLdSJhQh9z/C ez23iEm0+uGeZMIIFsuA0E03YRCYiKlVPsCeTXOZbH9MtTU72/bVrEcjZHMfYo6BzWLY 0Jdngu/8V9qz683TytxWNRsW8miYuDA54hkfAV5CoqC9MMiX6knxTxagzCOoIqPlq3tL dyIA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=t1NYkqq8; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id o126-v6si4649144pfb.20.2018.08.29.13.50.22; Wed, 29 Aug 2018 13:50:37 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=t1NYkqq8; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728980AbeH3ArU (ORCPT + 99 others); Wed, 29 Aug 2018 20:47:20 -0400 Received: from mail-lj1-f195.google.com ([209.85.208.195]:43131 "EHLO mail-lj1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727743AbeH3ArK (ORCPT ); Wed, 29 Aug 2018 20:47:10 -0400 Received: by mail-lj1-f195.google.com with SMTP id m84-v6so5463231lje.10; Wed, 29 Aug 2018 13:48:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=uh7mqvxXnjaw9WCsqO1jdthyZWLvGWRFnitWjcEgjoA=; b=t1NYkqq8D1p/fFdzor6udqB5Rz4nheEGLsJJWiwJxk+CgcPOECdgSUQP8RAB+nfLbW OJESYreUdskaJSnmUBj2JSwivjmzA3Jak2DY/ruGWgmNIn/8E0tHaEQyOLYK8bsF1yBN ZF8S0ii4vGu3+Yt8PKMTB3ACD1agHXyg87ibMd/VIa3VszATYJ7gYVkpfILzY8s6OZ81 Of4SSHvLfzP0vLuYzvpl3UqOmHu7oQG2VaZJnIp6bWWhi5My57cpBKCK6LJZAJkxDAR8 A5v/h2GNnogOgJ7th91vn4ICJHfz5QqmDIRFdce+TeBcakWRkaKxHpzieAIVUCzyfe8U goDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=uh7mqvxXnjaw9WCsqO1jdthyZWLvGWRFnitWjcEgjoA=; b=jy7KtD16A0WBre8XMDF+bXqH+o6KEc08RqOEJrw6OC8Sqzhlpthyaf1iOwqoyHt2Ja tL6AglRMQyq1tagEFhDTKkloA7onDMCPqJAKOcja7/qkx6jyK/fERutUHmUsflaJ2eXq fW1zqedxLyd7gcXPGoo7t50fSFWo6Ua19jy6llj4B0mqsymOZLVrMGE4L6Hs3sVoIk6f 29uVnT+OQI/QYPxL4Fmq0ryUfrQE3MMUowwUh1l1OfItzA2t97l64WWUdtj7+pLVGC+2 xDKH/Ws/Ksh9LjOmR5dtmhNT+wTzMjr7yosGKDxZyV59rXZzVYXI+efNeywnZge/AOCi SaNA== X-Gm-Message-State: APzg51D6M0Ew/HUihtzR4JeZ9SY3WpOv99niW/xWX28m9p2I9TGnIZeF jhj8gRYJX1xovpynGLcbMkw= X-Received: by 2002:a2e:954e:: with SMTP id t14-v6mr5233219ljh.68.1535575710581; Wed, 29 Aug 2018 13:48:30 -0700 (PDT) Received: from z50.lan (93-181-165-181.internetia.net.pl. [93.181.165.181]) by smtp.gmail.com with ESMTPSA id f66-v6sm947619lji.23.2018.08.29.13.48.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 29 Aug 2018 13:48:29 -0700 (PDT) From: Janusz Krzysztofik To: Linus Walleij Cc: Jonathan Corbet , Miguel Ojeda Sandonis , Peter Korsgaard , Peter Rosin , Ulf Hansson , Andrew Lunn , Florian Fainelli , "David S. Miller" , Dominik Brodowski , Greg Kroah-Hartman , Kishon Vijay Abraham I , Lars-Peter Clausen , Michael Hennerich , Jonathan Cameron , Hartmut Knaack , Peter Meerwald-Stadler , Jiri Slaby , Willy Tarreau , Geert Uytterhoeven , linux-doc@vger.kernel.org, linux-i2c@vger.kernel.org, linux-mmc@vger.kernel.org, netdev@vger.kernel.org, linux-iio@vger.kernel.org, devel@driverdev.osuosl.org, linux-serial@vger.kernel.org, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Janusz Krzysztofik Subject: [PATCH v5 4/4] gpiolib: Implement fast processing path in get/set array Date: Wed, 29 Aug 2018 22:49:00 +0200 Message-Id: <20180829204900.19390-5-jmkrzyszt@gmail.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180829204900.19390-1-jmkrzyszt@gmail.com> References: <20180820234341.5271-1-jmkrzyszt@gmail.com> <20180829204900.19390-1-jmkrzyszt@gmail.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Certain GPIO descriptor arrays returned by gpio_get_array() may contain information on direct mapping of array members to pins of a single GPIO chip in hardware order. In such cases, bitmaps of values can be passed directly from/to the chip's .get/set_multiple() callbacks without wasting time on iterations. Add respective code to gpiod_get/set_array_bitmap_complex() functions. Pins not applicable for fast path are processed as before, skipping over the 'fast' ones. Cc: Jonathan Corbet Signed-off-by: Janusz Krzysztofik --- Documentation/driver-api/gpio/board.rst | 15 ++++++ Documentation/driver-api/gpio/consumer.rst | 8 +++ drivers/gpio/gpiolib.c | 87 ++++++++++++++++++++++++++++-- 3 files changed, 105 insertions(+), 5 deletions(-) diff --git a/Documentation/driver-api/gpio/board.rst b/Documentation/driver-api/gpio/board.rst index 2c112553df84..c66821e033c2 100644 --- a/Documentation/driver-api/gpio/board.rst +++ b/Documentation/driver-api/gpio/board.rst @@ -193,3 +193,18 @@ And the table can be added to the board code as follows:: The line will be hogged as soon as the gpiochip is created or - in case the chip was created earlier - when the hog table is registered. + +Arrays of pins +-------------- +In addition to requesting pins belonging to a function one by one, a device may +also request an array of pins assigned to the function. The way those pins are +mapped to the device determines if the array qualifies for fast bitmap +processing. If yes, a bitmap is passed over get/set array functions directly +between a caller and a respective .get/set_multiple() callback of a GPIO chip. + +In order to qualify for fast bitmap processing, the pin mapping must meet the +following requirements: +- it must belong to the same chip as other 'fast' pins of the function, +- its index within the function must match its hardware number within the chip. + +Open drain and open source pins are excluded from fast bitmap output processing. diff --git a/Documentation/driver-api/gpio/consumer.rst b/Documentation/driver-api/gpio/consumer.rst index 0afd95a12b10..cf992e5ab976 100644 --- a/Documentation/driver-api/gpio/consumer.rst +++ b/Documentation/driver-api/gpio/consumer.rst @@ -388,6 +388,14 @@ array_info should be set to NULL. Note that for optimal performance GPIOs belonging to the same chip should be contiguous within the array of descriptors. +Still better performance may be achieved if array indexes of the descriptors +match hardware pin numbers of a single chip. If an array passed to a get/set +array function matches the one obtained from gpiod_get_array() and array_info +associated with the array is also passed, the function may take a fast bitmap +processing path, passing the value_bitmap argument directly to the respective +.get/set_multiple() callback of the chip. That allows for utilization of GPIO +banks as data I/O ports without much loss of performance. + The return value of gpiod_get_array_value() and its variants is 0 on success or negative on error. Note the difference to gpiod_get_value(), which returns 0 or 1 on success to convey the GPIO value. With the array functions, the GPIO diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 4d26cdbdb7cf..b799a89c4c17 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2787,7 +2787,36 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, struct gpio_array *array_info, unsigned long *value_bitmap) { - int i = 0; + int err, i = 0; + + /* + * Validate array_info against desc_array and its size. + * It should immediately follow desc_array if both + * have been obtained from the same gpiod_get_array() call. + */ + if (array_info && array_info->desc == desc_array && + array_size <= array_info->size && + (void *)array_info == desc_array + array_info->size) { + if (!can_sleep) + WARN_ON(array_info->chip->can_sleep); + + err = gpio_chip_get_multiple(array_info->chip, + array_info->get_mask, + value_bitmap); + if (err) + return err; + + if (!raw && !bitmap_empty(array_info->invert_mask, array_size)) + bitmap_xor(value_bitmap, value_bitmap, + array_info->invert_mask, array_size); + + if (bitmap_full(array_info->get_mask, array_size)) + return 0; + + i = find_first_zero_bit(array_info->get_mask, array_size); + } else { + array_info = NULL; + } while (i < array_size) { struct gpio_chip *chip = desc_array[i]->gdev->chip; @@ -2818,7 +2847,12 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, int hwgpio = gpio_chip_hwgpio(desc); __set_bit(hwgpio, mask); - i++; + + if (array_info) + find_next_zero_bit(array_info->get_mask, + array_size, i); + else + i++; } while ((i < array_size) && (desc_array[i]->gdev->chip == chip)); @@ -2829,7 +2863,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, return ret; } - for (j = first; j < i; j++) { + for (j = first; j < i; ) { const struct gpio_desc *desc = desc_array[j]; int hwgpio = gpio_chip_hwgpio(desc); int value = test_bit(hwgpio, bits); @@ -2838,6 +2872,11 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, value = !value; __assign_bit(j, value_bitmap, value); trace_gpio_value(desc_to_gpio(desc), 1, value); + + if (array_info) + find_next_zero_bit(array_info->get_mask, i, j); + else + j++; } if (mask != fastpath) @@ -3039,6 +3078,32 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, { int i = 0; + /* + * Validate array_info against desc_array and its size. + * It should immediately follow desc_array if both + * have been obtained from the same gpiod_get_array() call. + */ + if (array_info && array_info->desc == desc_array && + array_size <= array_info->size && + (void *)array_info == desc_array + array_info->size) { + if (!can_sleep) + WARN_ON(array_info->chip->can_sleep); + + if (!raw && !bitmap_empty(array_info->invert_mask, array_size)) + bitmap_xor(value_bitmap, value_bitmap, + array_info->invert_mask, array_size); + + gpio_chip_set_multiple(array_info->chip, array_info->set_mask, + value_bitmap); + + if (bitmap_full(array_info->set_mask, array_size)) + return 0; + + i = find_first_zero_bit(array_info->set_mask, array_size); + } else { + array_info = NULL; + } + while (i < array_size) { struct gpio_chip *chip = desc_array[i]->gdev->chip; unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)]; @@ -3066,7 +3131,14 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, int hwgpio = gpio_chip_hwgpio(desc); int value = test_bit(i, value_bitmap); - if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + /* + * Pins applicable for fast input but not for + * fast output processing may have been already + * inverted inside the fast path, skip them. + */ + if (!raw && !(array_info && + test_bit(i, array_info->invert_mask)) && + test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; trace_gpio_value(desc_to_gpio(desc), 0, value); /* @@ -3085,7 +3157,12 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, __clear_bit(hwgpio, bits); count++; } - i++; + + if (array_info) + find_next_zero_bit(array_info->set_mask, + array_size, i); + else + i++; } while ((i < array_size) && (desc_array[i]->gdev->chip == chip)); /* push collected bits to outputs */ -- 2.16.4