diff options
author | Janusz Krzysztofik <jmkrzyszt@gmail.com> | 2018-09-05 17:50:08 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2018-09-13 05:17:23 -0400 |
commit | b17566a6b08be18ded5472a2e4bbc066593b3662 (patch) | |
tree | 855c1933616c99b7b7998be6e5e5a88dc490d5a4 /drivers/gpio | |
parent | 77588c14ac868caece82fddbfae7de03b2cec941 (diff) |
gpiolib: Implement fast processing path in get/set array
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 <corbet@lwn.net>
Signed-off-by: Janusz Krzysztofik <jmkrzyszt@gmail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpiolib.c | 87 |
1 files changed, 82 insertions, 5 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index cd7c1deed132..d7532aa6c0bc 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -2789,7 +2789,36 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, | |||
2789 | struct gpio_array *array_info, | 2789 | struct gpio_array *array_info, |
2790 | unsigned long *value_bitmap) | 2790 | unsigned long *value_bitmap) |
2791 | { | 2791 | { |
2792 | int i = 0; | 2792 | int err, i = 0; |
2793 | |||
2794 | /* | ||
2795 | * Validate array_info against desc_array and its size. | ||
2796 | * It should immediately follow desc_array if both | ||
2797 | * have been obtained from the same gpiod_get_array() call. | ||
2798 | */ | ||
2799 | if (array_info && array_info->desc == desc_array && | ||
2800 | array_size <= array_info->size && | ||
2801 | (void *)array_info == desc_array + array_info->size) { | ||
2802 | if (!can_sleep) | ||
2803 | WARN_ON(array_info->chip->can_sleep); | ||
2804 | |||
2805 | err = gpio_chip_get_multiple(array_info->chip, | ||
2806 | array_info->get_mask, | ||
2807 | value_bitmap); | ||
2808 | if (err) | ||
2809 | return err; | ||
2810 | |||
2811 | if (!raw && !bitmap_empty(array_info->invert_mask, array_size)) | ||
2812 | bitmap_xor(value_bitmap, value_bitmap, | ||
2813 | array_info->invert_mask, array_size); | ||
2814 | |||
2815 | if (bitmap_full(array_info->get_mask, array_size)) | ||
2816 | return 0; | ||
2817 | |||
2818 | i = find_first_zero_bit(array_info->get_mask, array_size); | ||
2819 | } else { | ||
2820 | array_info = NULL; | ||
2821 | } | ||
2793 | 2822 | ||
2794 | while (i < array_size) { | 2823 | while (i < array_size) { |
2795 | struct gpio_chip *chip = desc_array[i]->gdev->chip; | 2824 | struct gpio_chip *chip = desc_array[i]->gdev->chip; |
@@ -2820,7 +2849,12 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, | |||
2820 | int hwgpio = gpio_chip_hwgpio(desc); | 2849 | int hwgpio = gpio_chip_hwgpio(desc); |
2821 | 2850 | ||
2822 | __set_bit(hwgpio, mask); | 2851 | __set_bit(hwgpio, mask); |
2823 | i++; | 2852 | |
2853 | if (array_info) | ||
2854 | find_next_zero_bit(array_info->get_mask, | ||
2855 | array_size, i); | ||
2856 | else | ||
2857 | i++; | ||
2824 | } while ((i < array_size) && | 2858 | } while ((i < array_size) && |
2825 | (desc_array[i]->gdev->chip == chip)); | 2859 | (desc_array[i]->gdev->chip == chip)); |
2826 | 2860 | ||
@@ -2831,7 +2865,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, | |||
2831 | return ret; | 2865 | return ret; |
2832 | } | 2866 | } |
2833 | 2867 | ||
2834 | for (j = first; j < i; j++) { | 2868 | for (j = first; j < i; ) { |
2835 | const struct gpio_desc *desc = desc_array[j]; | 2869 | const struct gpio_desc *desc = desc_array[j]; |
2836 | int hwgpio = gpio_chip_hwgpio(desc); | 2870 | int hwgpio = gpio_chip_hwgpio(desc); |
2837 | int value = test_bit(hwgpio, bits); | 2871 | int value = test_bit(hwgpio, bits); |
@@ -2840,6 +2874,11 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, | |||
2840 | value = !value; | 2874 | value = !value; |
2841 | __assign_bit(j, value_bitmap, value); | 2875 | __assign_bit(j, value_bitmap, value); |
2842 | trace_gpio_value(desc_to_gpio(desc), 1, value); | 2876 | trace_gpio_value(desc_to_gpio(desc), 1, value); |
2877 | |||
2878 | if (array_info) | ||
2879 | find_next_zero_bit(array_info->get_mask, i, j); | ||
2880 | else | ||
2881 | j++; | ||
2843 | } | 2882 | } |
2844 | 2883 | ||
2845 | if (mask != fastpath) | 2884 | if (mask != fastpath) |
@@ -3043,6 +3082,32 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, | |||
3043 | { | 3082 | { |
3044 | int i = 0; | 3083 | int i = 0; |
3045 | 3084 | ||
3085 | /* | ||
3086 | * Validate array_info against desc_array and its size. | ||
3087 | * It should immediately follow desc_array if both | ||
3088 | * have been obtained from the same gpiod_get_array() call. | ||
3089 | */ | ||
3090 | if (array_info && array_info->desc == desc_array && | ||
3091 | array_size <= array_info->size && | ||
3092 | (void *)array_info == desc_array + array_info->size) { | ||
3093 | if (!can_sleep) | ||
3094 | WARN_ON(array_info->chip->can_sleep); | ||
3095 | |||
3096 | if (!raw && !bitmap_empty(array_info->invert_mask, array_size)) | ||
3097 | bitmap_xor(value_bitmap, value_bitmap, | ||
3098 | array_info->invert_mask, array_size); | ||
3099 | |||
3100 | gpio_chip_set_multiple(array_info->chip, array_info->set_mask, | ||
3101 | value_bitmap); | ||
3102 | |||
3103 | if (bitmap_full(array_info->set_mask, array_size)) | ||
3104 | return 0; | ||
3105 | |||
3106 | i = find_first_zero_bit(array_info->set_mask, array_size); | ||
3107 | } else { | ||
3108 | array_info = NULL; | ||
3109 | } | ||
3110 | |||
3046 | while (i < array_size) { | 3111 | while (i < array_size) { |
3047 | struct gpio_chip *chip = desc_array[i]->gdev->chip; | 3112 | struct gpio_chip *chip = desc_array[i]->gdev->chip; |
3048 | unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)]; | 3113 | unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)]; |
@@ -3070,7 +3135,14 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, | |||
3070 | int hwgpio = gpio_chip_hwgpio(desc); | 3135 | int hwgpio = gpio_chip_hwgpio(desc); |
3071 | int value = test_bit(i, value_bitmap); | 3136 | int value = test_bit(i, value_bitmap); |
3072 | 3137 | ||
3073 | if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags)) | 3138 | /* |
3139 | * Pins applicable for fast input but not for | ||
3140 | * fast output processing may have been already | ||
3141 | * inverted inside the fast path, skip them. | ||
3142 | */ | ||
3143 | if (!raw && !(array_info && | ||
3144 | test_bit(i, array_info->invert_mask)) && | ||
3145 | test_bit(FLAG_ACTIVE_LOW, &desc->flags)) | ||
3074 | value = !value; | 3146 | value = !value; |
3075 | trace_gpio_value(desc_to_gpio(desc), 0, value); | 3147 | trace_gpio_value(desc_to_gpio(desc), 0, value); |
3076 | /* | 3148 | /* |
@@ -3089,7 +3161,12 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, | |||
3089 | __clear_bit(hwgpio, bits); | 3161 | __clear_bit(hwgpio, bits); |
3090 | count++; | 3162 | count++; |
3091 | } | 3163 | } |
3092 | i++; | 3164 | |
3165 | if (array_info) | ||
3166 | find_next_zero_bit(array_info->set_mask, | ||
3167 | array_size, i); | ||
3168 | else | ||
3169 | i++; | ||
3093 | } while ((i < array_size) && | 3170 | } while ((i < array_size) && |
3094 | (desc_array[i]->gdev->chip == chip)); | 3171 | (desc_array[i]->gdev->chip == chip)); |
3095 | /* push collected bits to outputs */ | 3172 | /* push collected bits to outputs */ |