linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: "Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	stable@vger.kernel.org, YueHaibing <yuehaibing@huawei.com>,
	"Mika Westerberg" <mika.westerberg@linux.intel.com>,
	"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>,
	"Sven Van Asbroeck" <TheSven73@gmail.com>,
	"Clemens Gruber" <clemens.gruber@pqgruber.com>,
	"Thierry Reding" <thierry.reding@gmail.com>
Subject: [PATCH 5.5 27/65] pwm: pca9685: Fix PWM/GPIO inter-operation
Date: Mon, 20 Apr 2020 14:38:31 +0200	[thread overview]
Message-ID: <20200420121512.063188836@linuxfoundation.org> (raw)
In-Reply-To: <20200420121505.909671922@linuxfoundation.org>

From: Sven Van Asbroeck <TheSven73@gmail.com>

commit 9cc5f232a4b6a0ef6e9b57876d61b88f61bdd7c2 upstream.

This driver allows pwms to be requested as gpios via gpiolib. Obviously,
it should not be allowed to request a GPIO when its corresponding PWM is
already requested (and vice versa). So it requires some exclusion code.

Given that the PWMm and GPIO cores are not synchronized with respect to
each other, this exclusion code will also require proper
synchronization.

Such a mechanism was in place, but was inadvertently removed by Uwe's
clean-up in commit e926b12c611c ("pwm: Clear chip_data in pwm_put()").

Upon revisiting the synchronization mechanism, we found that
theoretically, it could allow two threads to successfully request
conflicting PWMs/GPIOs.

Replace with a bitmap which tracks PWMs in-use, plus a mutex. As long as
PWM and GPIO's respective request/free functions modify the in-use
bitmap while holding the mutex, proper synchronization will be
guaranteed.

Reported-by: YueHaibing <yuehaibing@huawei.com>
Fixes: e926b12c611c ("pwm: Clear chip_data in pwm_put()")
Cc: Mika Westerberg <mika.westerberg@linux.intel.com>
Cc: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Cc: YueHaibing <yuehaibing@huawei.com>
Link: https://lkml.org/lkml/2019/5/31/963
Signed-off-by: Sven Van Asbroeck <TheSven73@gmail.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
[cg: Tested on an i.MX6Q board with two NXP PCA9685 chips]
Tested-by: Clemens Gruber <clemens.gruber@pqgruber.com>
Reviewed-by: Sven Van Asbroeck <TheSven73@gmail.com> # cg's rebase
Link: https://lore.kernel.org/lkml/20200330160238.GD2817345@ulmo/
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

---
 drivers/pwm/pwm-pca9685.c |   85 +++++++++++++++++++++++++---------------------
 1 file changed, 48 insertions(+), 37 deletions(-)

--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/pm_runtime.h>
+#include <linux/bitmap.h>
 
 /*
  * Because the PCA9685 has only one prescaler per chip, changing the period of
@@ -74,6 +75,7 @@ struct pca9685 {
 #if IS_ENABLED(CONFIG_GPIOLIB)
 	struct mutex lock;
 	struct gpio_chip gpio;
+	DECLARE_BITMAP(pwms_inuse, PCA9685_MAXCHAN + 1);
 #endif
 };
 
@@ -83,51 +85,51 @@ static inline struct pca9685 *to_pca(str
 }
 
 #if IS_ENABLED(CONFIG_GPIOLIB)
-static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
+static bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, int pwm_idx)
 {
-	struct pca9685 *pca = gpiochip_get_data(gpio);
-	struct pwm_device *pwm;
+	bool is_inuse;
 
 	mutex_lock(&pca->lock);
-
-	pwm = &pca->chip.pwms[offset];
-
-	if (pwm->flags & (PWMF_REQUESTED | PWMF_EXPORTED)) {
-		mutex_unlock(&pca->lock);
-		return -EBUSY;
+	if (pwm_idx >= PCA9685_MAXCHAN) {
+		/*
+		 * "all LEDs" channel:
+		 * pretend already in use if any of the PWMs are requested
+		 */
+		if (!bitmap_empty(pca->pwms_inuse, PCA9685_MAXCHAN)) {
+			is_inuse = true;
+			goto out;
+		}
+	} else {
+		/*
+		 * regular channel:
+		 * pretend already in use if the "all LEDs" channel is requested
+		 */
+		if (test_bit(PCA9685_MAXCHAN, pca->pwms_inuse)) {
+			is_inuse = true;
+			goto out;
+		}
 	}
-
-	pwm_set_chip_data(pwm, (void *)1);
-
+	is_inuse = test_and_set_bit(pwm_idx, pca->pwms_inuse);
+out:
 	mutex_unlock(&pca->lock);
-	pm_runtime_get_sync(pca->chip.dev);
-	return 0;
+	return is_inuse;
 }
 
-static bool pca9685_pwm_is_gpio(struct pca9685 *pca, struct pwm_device *pwm)
+static void pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx)
 {
-	bool is_gpio = false;
-
 	mutex_lock(&pca->lock);
+	clear_bit(pwm_idx, pca->pwms_inuse);
+	mutex_unlock(&pca->lock);
+}
 
-	if (pwm->hwpwm >= PCA9685_MAXCHAN) {
-		unsigned int i;
-
-		/*
-		 * Check if any of the GPIOs are requested and in that case
-		 * prevent using the "all LEDs" channel.
-		 */
-		for (i = 0; i < pca->gpio.ngpio; i++)
-			if (gpiochip_is_requested(&pca->gpio, i)) {
-				is_gpio = true;
-				break;
-			}
-	} else if (pwm_get_chip_data(pwm)) {
-		is_gpio = true;
-	}
+static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
+{
+	struct pca9685 *pca = gpiochip_get_data(gpio);
 
-	mutex_unlock(&pca->lock);
-	return is_gpio;
+	if (pca9685_pwm_test_and_set_inuse(pca, offset))
+		return -EBUSY;
+	pm_runtime_get_sync(pca->chip.dev);
+	return 0;
 }
 
 static int pca9685_pwm_gpio_get(struct gpio_chip *gpio, unsigned int offset)
@@ -162,6 +164,7 @@ static void pca9685_pwm_gpio_free(struct
 
 	pca9685_pwm_gpio_set(gpio, offset, 0);
 	pm_runtime_put(pca->chip.dev);
+	pca9685_pwm_clear_inuse(pca, offset);
 }
 
 static int pca9685_pwm_gpio_get_direction(struct gpio_chip *chip,
@@ -213,12 +216,17 @@ static int pca9685_pwm_gpio_probe(struct
 	return devm_gpiochip_add_data(dev, &pca->gpio, pca);
 }
 #else
-static inline bool pca9685_pwm_is_gpio(struct pca9685 *pca,
-				       struct pwm_device *pwm)
+static inline bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca,
+						  int pwm_idx)
 {
 	return false;
 }
 
+static inline void
+pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx)
+{
+}
+
 static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
 {
 	return 0;
@@ -402,7 +410,7 @@ static int pca9685_pwm_request(struct pw
 {
 	struct pca9685 *pca = to_pca(chip);
 
-	if (pca9685_pwm_is_gpio(pca, pwm))
+	if (pca9685_pwm_test_and_set_inuse(pca, pwm->hwpwm))
 		return -EBUSY;
 	pm_runtime_get_sync(chip->dev);
 
@@ -411,8 +419,11 @@ static int pca9685_pwm_request(struct pw
 
 static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
+	struct pca9685 *pca = to_pca(chip);
+
 	pca9685_pwm_disable(chip, pwm);
 	pm_runtime_put(chip->dev);
+	pca9685_pwm_clear_inuse(pca, pwm->hwpwm);
 }
 
 static const struct pwm_ops pca9685_pwm_ops = {



  parent reply	other threads:[~2020-04-20 12:40 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-20 12:38 [PATCH 5.5 00/65] 5.5.19-rc1 review Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 01/65] amd-xgbe: Use __napi_schedule() in BH context Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 02/65] hsr: check protocol version in hsr_newlink() Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 03/65] l2tp: Allow management of tunnels and session in user namespace Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 04/65] net: dsa: mt7530: fix tagged frames pass-through in VLAN-unaware mode Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 05/65] net: ipv4: devinet: Fix crash when add/del multicast IP with autojoin Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 06/65] net: ipv6: do not consider routes via gateways for anycast address check Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 07/65] net: phy: micrel: use genphy_read_status for KSZ9131 Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 08/65] net: qrtr: send msgs from local of same id as broadcast Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 09/65] net: revert default NAPI poll timeout to 2 jiffies Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 10/65] net: tun: record RX queue in skb before do_xdp_generic() Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 11/65] net: dsa: mt7530: move mt7623 settings out off the mt7530 Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 12/65] net: ethernet: mediatek: " Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 13/65] net/mlx5: Fix frequent ioread PCI access during recovery Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 14/65] net/mlx5e: Add missing release firmware call Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 15/65] net/mlx5e: Fix nest_level for vlan pop action Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 16/65] net/mlx5e: Fix pfnum in devlink port attribute Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 17/65] net: icmp6: do not select saddr from iif when route has prefsrc set Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 18/65] net: mscc: ocelot: fix untagged packet drops when enslaving to vlan aware bridge Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 19/65] net: stmmac: dwmac-sunxi: Provide TX and RX fifo sizes Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 20/65] Revert "ACPI: EC: Do not clear boot_ec_is_ecdt in acpi_ec_add()" Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 21/65] ovl: fix value of i_ino for lower hardlink corner case Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 22/65] scsi: ufs: Fix ufshcd_hold() caused scheduling while atomic Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 23/65] platform/chrome: cros_ec_rpmsg: Fix race with host event Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 24/65] jbd2: improve comments about freeing data buffers whose page mapping is NULL Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 25/65] acpi/nfit: improve bounds checking for func Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 26/65] perf report: Fix no branch type statistics report issue Greg Kroah-Hartman
2020-04-20 12:38 ` Greg Kroah-Hartman [this message]
2020-04-20 12:38 ` [PATCH 5.5 28/65] net: stmmac: xgmac: Fix VLAN register handling Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 29/65] net/bpfilter: remove superfluous testing message Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 30/65] ext4: fix incorrect group count in ext4_fill_super error message Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 31/65] ext4: fix incorrect inodes per group in " Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 32/65] HID: lg-g15: Do not fail the probe when we fail to disable F# emulation Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 33/65] clk: at91: sam9x60: fix usb clock parents Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 34/65] clk: at91: usb: use proper usbs_mask Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 35/65] ARM: dts: imx7-colibri: fix muxing of usbc_det pin Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 36/65] arm64: dts: librem5-devkit: add a vbus supply to usb0 Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 37/65] usb: dwc3: gadget: Dont clear flags before transfer ended Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 38/65] ASoC: Intel: mrfld: fix incorrect check on p->sink Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 39/65] ASoC: Intel: mrfld: return error codes when an error occurs Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 40/65] ALSA: hda/realtek - Enable the headset mic on Asus FX505DT Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 41/65] ALSA: usb-audio: Filter error from connector kctl ops, too Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 42/65] ALSA: usb-audio: Dont override ignore_ctl_error value from the map Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 43/65] ALSA: usb-audio: Dont create jack controls for PCM terminals Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 44/65] ALSA: usb-audio: Check mapping at creating connector controls, too Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 45/65] arm64: vdso: dont free unallocated pages Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 46/65] keys: Fix proc_keys_next to increase position index Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 47/65] tracing: Fix the race between registering snapshot event trigger and triggering snapshot operation Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 48/65] btrfs: check commit root generation in should_ignore_root Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 49/65] nl80211: fix NL80211_ATTR_FTM_RESPONDER policy Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 50/65] mac80211: fix race in ieee80211_register_hw() Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 51/65] mac80211_hwsim: Use kstrndup() in place of kasprintf() Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 52/65] net/mlx5e: Encapsulate updating netdev queues into a function Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 53/65] net/mlx5e: Rename hw_modify to preactivate Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 54/65] net/mlx5e: Use preactivate hook to set the indirection table Greg Kroah-Hartman
2020-04-20 12:38 ` [PATCH 5.5 55/65] drm/amd/powerplay: force the trim of the mclk dpm_levels if OD is enabled Greg Kroah-Hartman
2020-04-20 12:39 ` [PATCH 5.5 56/65] drm/amdgpu: fix the hw hang during perform system reboot and reset Greg Kroah-Hartman
2020-04-20 12:39 ` [PATCH 5.5 57/65] i2c: designware: platdrv: Remove DPM_FLAG_SMART_SUSPEND flag on BYT and CHT Greg Kroah-Hartman
2020-04-20 12:39 ` [PATCH 5.5 58/65] drm/i915/perf: Do not clear pollin for small user read buffers Greg Kroah-Hartman
2020-04-20 12:39 ` [PATCH 5.5 59/65] ext4: do not zeroout extents beyond i_disksize Greg Kroah-Hartman
2020-04-20 12:39 ` [PATCH 5.5 60/65] irqchip/ti-sci-inta: Fix processing of masked irqs Greg Kroah-Hartman
2020-04-20 12:39 ` [PATCH 5.5 61/65] x86/resctrl: Preserve CDP enable over CPU hotplug Greg Kroah-Hartman
2020-04-20 12:39 ` [PATCH 5.5 62/65] x86/resctrl: Fix invalid attempt at removing the default resource group Greg Kroah-Hartman
2020-04-20 12:39 ` [PATCH 5.5 63/65] scsi: target: remove boilerplate code Greg Kroah-Hartman
2020-04-20 12:39 ` [PATCH 5.5 64/65] scsi: target: fix hang when multiple threads try to destroy the same iscsi session Greg Kroah-Hartman
2020-04-20 12:39 ` [PATCH 5.5 65/65] x86/microcode/AMD: Increase microcode PATCH_MAX_SIZE Greg Kroah-Hartman
2020-04-20 19:01 ` [PATCH 5.5 00/65] 5.5.19-rc1 review Naresh Kamboju
2020-04-20 19:53 ` Guenter Roeck
2020-04-21  9:55 ` Jon Hunter
2020-04-21 19:56 ` shuah

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200420121512.063188836@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=TheSven73@gmail.com \
    --cc=clemens.gruber@pqgruber.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mika.westerberg@linux.intel.com \
    --cc=stable@vger.kernel.org \
    --cc=thierry.reding@gmail.com \
    --cc=u.kleine-koenig@pengutronix.de \
    --cc=yuehaibing@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).