From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3DB896EB41; Tue, 23 Jan 2024 02:03:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1705975404; cv=none; b=WlVpJNRc5Vyq8VyWVMMhW7jei/6GQLIvFwDwHmpkJNpIA5NwivfBRQsg9piDmuiyOWb6WVzSXVXggPIEnJsrieesoAFEyG445sjx2QW0KmQOJRxkxB7V5BeIYixvq44a2TXqQXTOw3eb7Be5AGMSt5Oc89gf+pnTLCiXa+An2QQ= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1705975404; c=relaxed/simple; bh=BMaMw01DWZUVZ/SOX5TpFz3rze+Je8ppY9WYJBDYQAc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=R74DhiLCF+8lei/NkfU6auJRfCpWQz9vr/3F1XEO4tWt/iqRwAdpiaEHnfvUjvHHwRiT6xup8ozmGH4rT6NhcL+ZHoJ4t2DUHO8BLnY5W0x73ftGwbwijm8z93ergORvLwhTvVHXFO+7aA3JZcfCB1DM7QOHhk9hzVPXI5dfi9I= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=wHA7uove; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="wHA7uove" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 037F2C43390; Tue, 23 Jan 2024 02:03:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1705975404; bh=BMaMw01DWZUVZ/SOX5TpFz3rze+Je8ppY9WYJBDYQAc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wHA7uove1sz7vN4NljRsC2RKsJpZHdbtPIEkIWou39HUoJXyqc+XrM3Me0xiZrwMN KKFIxLlIhCk41sl4ENAhjraj2suZBgE8AevO86U54rBzo3MXd4zAXSur5CRAdtXz1i ldiJRHDfYzt9cV3hWZaB9I96cxgof77xcdXs1VCU= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Bartosz Golaszewski , Linus Walleij , Sasha Levin Subject: [PATCH 6.6 328/583] gpiolib: provide gpio_device_find() Date: Mon, 22 Jan 2024 15:56:19 -0800 Message-ID: <20240122235822.085816226@linuxfoundation.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240122235812.238724226@linuxfoundation.org> References: <20240122235812.238724226@linuxfoundation.org> User-Agent: quilt/0.67 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.6-stable review patch. If anyone has any objections, please let me know. ------------------ From: Bartosz Golaszewski [ Upstream commit cfe102f63308c8c8e01199a682868a64b83f653e ] gpiochip_find() is wrong and its kernel doc is misleading as the function doesn't return a reference to the gpio_chip but just a raw pointer. The chip itself is not guaranteed to stay alive, in fact it can be deleted at any point. Also: other than GPIO drivers themselves, nobody else has any business accessing gpio_chip structs. Provide a new gpio_device_find() function that returns a real reference to the opaque gpio_device structure that is guaranteed to stay alive for as long as there are active users of it. Signed-off-by: Bartosz Golaszewski Reviewed-by: Linus Walleij Stable-dep-of: 48e1b4d369cf ("gpiolib: remove the GPIO device from the list when it's unregistered") Signed-off-by: Sasha Levin --- drivers/gpio/gpiolib.c | 71 +++++++++++++++++++++++++++---------- include/linux/gpio/driver.h | 3 ++ 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c2b40d7138fa..71492d213ef4 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1014,16 +1014,10 @@ void gpiochip_remove(struct gpio_chip *gc) } EXPORT_SYMBOL_GPL(gpiochip_remove); -/** - * gpiochip_find() - iterator for locating a specific gpio_chip - * @data: data to pass to match function - * @match: Callback function to check gpio_chip +/* + * FIXME: This will be removed soon. * - * Similar to bus_find_device. It returns a reference to a gpio_chip as - * determined by a user supplied @match callback. The callback should return - * 0 if the device doesn't match and non-zero if it does. If the callback is - * non-zero, this function will return to the caller and not iterate over any - * more gpio_chips. + * This function is depracated, don't use. */ struct gpio_chip *gpiochip_find(void *data, int (*match)(struct gpio_chip *gc, @@ -1031,21 +1025,62 @@ struct gpio_chip *gpiochip_find(void *data, { struct gpio_device *gdev; struct gpio_chip *gc = NULL; - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - list_for_each_entry(gdev, &gpio_devices, list) - if (gdev->chip && match(gdev->chip, data)) { - gc = gdev->chip; - break; - } - spin_unlock_irqrestore(&gpio_lock, flags); + gdev = gpio_device_find(data, match); + if (gdev) { + gc = gdev->chip; + gpio_device_put(gdev); + } return gc; } EXPORT_SYMBOL_GPL(gpiochip_find); +/** + * gpio_device_find() - find a specific GPIO device + * @data: data to pass to match function + * @match: Callback function to check gpio_chip + * + * Returns: + * New reference to struct gpio_device. + * + * Similar to bus_find_device(). It returns a reference to a gpio_device as + * determined by a user supplied @match callback. The callback should return + * 0 if the device doesn't match and non-zero if it does. If the callback + * returns non-zero, this function will return to the caller and not iterate + * over any more gpio_devices. + * + * The callback takes the GPIO chip structure as argument. During the execution + * of the callback function the chip is protected from being freed. TODO: This + * actually has yet to be implemented. + * + * If the function returns non-NULL, the returned reference must be freed by + * the caller using gpio_device_put(). + */ +struct gpio_device *gpio_device_find(void *data, + int (*match)(struct gpio_chip *gc, + void *data)) +{ + struct gpio_device *gdev; + + /* + * Not yet but in the future the spinlock below will become a mutex. + * Annotate this function before anyone tries to use it in interrupt + * context like it happened with gpiochip_find(). + */ + might_sleep(); + + guard(spinlock_irqsave)(&gpio_lock); + + list_for_each_entry(gdev, &gpio_devices, list) { + if (gdev->chip && match(gdev->chip, data)) + return gpio_device_get(gdev); + } + + return NULL; +} +EXPORT_SYMBOL_GPL(gpio_device_find); + static int gpiochip_match_name(struct gpio_chip *gc, void *data) { const char *name = data; diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 64c214317a83..d6e38a500833 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -607,6 +607,9 @@ extern int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip extern struct gpio_chip *gpiochip_find(void *data, int (*match)(struct gpio_chip *gc, void *data)); +struct gpio_device *gpio_device_find(void *data, + int (*match)(struct gpio_chip *gc, void *data)); + struct gpio_device *gpio_device_get(struct gpio_device *gdev); void gpio_device_put(struct gpio_device *gdev); -- 2.43.0