diff mbox

[0/2,v5] pinctrl: qcom: add support for sparse GPIOs

Message ID 20171003220311.GU457@codeaurora.org (mailing list archive)
State New, archived
Headers show

Commit Message

Stephen Boyd Oct. 3, 2017, 10:03 p.m. UTC
On 09/22, Timur Tabi wrote:
> On 09/22/2017 08:29 AM, Linus Walleij wrote:
> >
> >What is your response to Stephen's comment:
> >
> >>[Stephen Boyd]
> >>Perhaps we can add another hook for our purposes here that
> >>tells gpiolib that the gpio is not usable and to skip it. The
> >>semantics would be clear, it's just about probing availability of
> >>this pin as a gpio and doesn't mux any pins.
> 
> >I think this kind of related to my response (after I realized it
> >was not just about IRQs):
> 
> We already have 95% of this.  We can already specify individual pin
> ranges, and the vast majority of the code recognizes the ranges.
> There is only one small loophole, and that's in gpiochip_add_data().
> The for-loop iterates over all GPIOs:
> 
> 	for (i = 0; i < chip->ngpio; i++) {
> 		struct gpio_desc *desc = &gdev->descs[i];
> 
> 		desc->gdev = gdev;
> 		/*
> 		 * REVISIT: most hardware initializes GPIOs as inputs
> 		 * (often with pullups enabled) so power usage is
> 		 * minimized. Linux code should set the gpio direction
> 		 * first thing; but until it does, and in case
> 		 * chip->get_direction is not set, we may expose the
> 		 * wrong direction in sysfs.
> 		 */
> 
> I believe the real problem is that this for-loop should be moved
> from gpiochip_add_data() into some other function that is called
> *after* the pin ranges are defined.  We can put it in
> gpiochip_add_pin_range(), maybe.
> 
> My patch covers the loophole by adding a check inside
> get_direction(). If we fix gpiochip_add_data(), I can remove that
> patch.
> 
> However, I think that change is risky and will require a lot of
> testing and review.
> 

I've run into this now on our mobile SoCs after I pull in commit
8e51533780ba ("pinctrl: qcom: add get_direction function").
Before that commit we never read each pin of the device. On our
mobile SoCs we have devicetree and it feels like having that
describe which pins are available and not available is
half-duplicating information we would already have via consumers
indicating which pins they care about. I don't see any value
beyond system wide debug in figuring out the default pin
configuration of a pin that doesn't have a consumer in Linux.

Could we remove the pin direction finding part here in
gpiochip_add_pin_range() and lazily resolve the pin direction
when a pin is requested? We would need a similar check in the msm
specific debugfs code where we skip pins that aren't requested.
This is basically a revert of commit 72d320006177 ("gpio: set up
initial state from .get_direction()").

ACPI can still describe only the pin ranges that they care about
exposing, but from the devicetree side it's been working well
enough to not touch pins that aren't used by anything in Linux.

---8<----

Comments

Timur Tabi Oct. 3, 2017, 10:12 p.m. UTC | #1
On 10/03/2017 05:03 PM, Stephen Boyd wrote:
> I've run into this now on our mobile SoCs after I pull in commit
> 8e51533780ba ("pinctrl: qcom: add get_direction function").
> Before that commit we never read each pin of the device. On our
> mobile SoCs we have devicetree and it feels like having that
> describe which pins are available and not available is
> half-duplicating information we would already have via consumers
> indicating which pins they care about. I don't see any value
> beyond system wide debug in figuring out the default pin
> configuration of a pin that doesn't have a consumer in Linux.

At the time I wrote that patch, the ACPI tables exposed all of the 
GPIOs, even the ones it didn't care about.  The new ACPI tables list 
only specific GPIOs, and so we no longer need to blindly read the 
direction of all GPIOs.

> Could we remove the pin direction finding part here in
> gpiochip_add_pin_range() and lazily resolve the pin direction
> when a pin is requested?

That makes a lot more sense.

> We would need a similar check in the msm
> specific debugfs code where we skip pins that aren't requested.

I have that in patch #1.

> This is basically a revert of commit 72d320006177 ("gpio: set up
> initial state from .get_direction()").

I would be in favor of either reverting that patch, or moving the code 
into gpiochip_add_pin_range().

> ACPI can still describe only the pin ranges that they care about
> exposing, but from the devicetree side it's been working well
> enough to not touch pins that aren't used by anything in Linux.

I do hate having to hack up the driver to support crappy ACPI 
definitions, but I'm stuck between a rock and a hard place.
Stephen Boyd Oct. 4, 2017, 9:50 p.m. UTC | #2
On 10/03, Timur Tabi wrote:
> On 10/03/2017 05:03 PM, Stephen Boyd wrote:
> >I've run into this now on our mobile SoCs after I pull in commit
> >8e51533780ba ("pinctrl: qcom: add get_direction function").
> >Before that commit we never read each pin of the device. On our
> >mobile SoCs we have devicetree and it feels like having that
> >describe which pins are available and not available is
> >half-duplicating information we would already have via consumers
> >indicating which pins they care about. I don't see any value
> >beyond system wide debug in figuring out the default pin
> >configuration of a pin that doesn't have a consumer in Linux.
> 
> At the time I wrote that patch, the ACPI tables exposed all of the
> GPIOs, even the ones it didn't care about.  The new ACPI tables list
> only specific GPIOs, and so we no longer need to blindly read the
> direction of all GPIOs.
> 

Do you avoid this problem on new ACPI tables because only pins
that are able to be read are exposed?

> 
> >This is basically a revert of commit 72d320006177 ("gpio: set up
> >initial state from .get_direction()").
> 
> I would be in favor of either reverting that patch, or moving the
> code into gpiochip_add_pin_range().

If it's in gpiochip_add_pin_range() would we still read the
hardware when creating the pin ranges? I don't want to have to
describe pin ranges of "valid" pins that won't cause the system
to blow up if we touch them, because those pins are never used by
Linux so reading them is not useful.
Timur Tabi Oct. 4, 2017, 10:41 p.m. UTC | #3
On 10/04/2017 04:50 PM, Stephen Boyd wrote:

>> At the time I wrote that patch, the ACPI tables exposed all of the
>> GPIOs, even the ones it didn't care about.  The new ACPI tables list
>> only specific GPIOs, and so we no longer need to blindly read the
>> direction of all GPIOs.
>>
> 
> Do you avoid this problem on new ACPI tables because only pins
> that are able to be read are exposed?

Yes.  A recent firmware update enabled the "XPU" block which is being 
programmed with a select subset of individual GPIOs.  On our silicon, 
each TLMM GPIO is in a separate 64k page, and so the XPU can block any 
individual GPIO.  Any attempt to touch those registers causes an XPU 
violation which takes the whole system down.

>>> This is basically a revert of commit 72d320006177 ("gpio: set up
>>> initial state from .get_direction()").
>>
>> I would be in favor of either reverting that patch, or moving the
>> code into gpiochip_add_pin_range().
> 
> If it's in gpiochip_add_pin_range() would we still read the
> hardware when creating the pin ranges?

I presume so.  The idea is that pinctrl-qdf2xxx/pinctrl-msm only submit 
pin ranges that are present in the ACPI tables.

 > I don't want to have to> describe pin ranges of "valid" pins that 
won't cause the system
> to blow up if we touch them, because those pins are never used by
> Linux so reading them is not useful.

Well, that's exactly what I'm trying to do with current patch set :-) 
It seems the most logical approach to me.  I don't understand the 
dislike for it.  What else are pin ranges for, other than to specify 
ranges of pins that can be accessed?

Another alternative was to enumerate all of the GPIOs starting from 0. 
So the first GPIO in ACPI would be gpio0, regardless of what gpio number 
it actually was.  E.g. GPIO 37 would appear as gpio0, GPIO 38 would 
appear as gpio1, and so on.  That also worked, but it meant that 
customers would need to figure out which GPIO that "gpio0" actually 
pointed to.  That was not acceptable, so I dropped it.

I'm at a loss on how else to do it.  I think a gpio_chip.available 
callback is far less elegant than define pin ranges.  There is no chance 
that unavailable GPIOs can be accessed because the physical addresses 
are not in the msm_pingroup array.  That is, groups[0].ctrl_reg == 0, 
not 0xFF02010000.
Stephen Boyd Oct. 5, 2017, 9:30 p.m. UTC | #4
On 10/04, Timur Tabi wrote:
> On 10/04/2017 04:50 PM, Stephen Boyd wrote:
> 
> Yes.  A recent firmware update enabled the "XPU" block which is
> being programmed with a select subset of individual GPIOs.  On our
> silicon, each TLMM GPIO is in a separate 64k page, and so the XPU
> can block any individual GPIO.  Any attempt to touch those registers
> causes an XPU violation which takes the whole system down.

Yes it's the same sort of design with the hardware I have too.

> 
> >
> >If it's in gpiochip_add_pin_range() would we still read the
> >hardware when creating the pin ranges?
> 
> I presume so.  The idea is that pinctrl-qdf2xxx/pinctrl-msm only
> submit pin ranges that are present in the ACPI tables.

Ok.

> 
> > I don't want to have to describe pin ranges of "valid" pins that
> > won't cause the system
> > to blow up if we touch them, because those pins are never used by
> > Linux so reading them is not useful.
> 
> Well, that's exactly what I'm trying to do with current patch set
> :-) It seems the most logical approach to me.  I don't understand
> the dislike for it.  What else are pin ranges for, other than to
> specify ranges of pins that can be accessed?

I have no idea. To describe non-contiguous pin ranges? Linus?

> 
> Another alternative was to enumerate all of the GPIOs starting from
> 0. So the first GPIO in ACPI would be gpio0, regardless of what gpio
> number it actually was.  E.g. GPIO 37 would appear as gpio0, GPIO 38
> would appear as gpio1, and so on.  That also worked, but it meant
> that customers would need to figure out which GPIO that "gpio0"
> actually pointed to.  That was not acceptable, so I dropped it.

Agreed.

> 
> I'm at a loss on how else to do it.  I think a gpio_chip.available
> callback is far less elegant than define pin ranges.  There is no
> chance that unavailable GPIOs can be accessed because the physical
> addresses are not in the msm_pingroup array.  That is,
> groups[0].ctrl_reg == 0, not 0xFF02010000.
> 

Yes, thinking more about it I don't want an available callback
either. It will add burden on DT platforms where we have to
describe per-firmware pin ranges just because gpiolib is reading
the direction of gpios we don't use.

Instead, I'd prefer we delay reading the direction until a
consumer requests the gpio, this way we don't touch the hardware
unless a consumer wants to. That seems simpler and doesn't
require anything special from the driver.

Don't get me wrong, I'm willing to describe with DT/ACPI which
pins are available if we have a need for it, but so far I don't
see the requirement and I'm a lazy person so I like avoiding more
work.

Does my patch fail on your platform for some reason? I can only
guess that somewhere we don't request the gpio before using it
and then you don't see the proper direction.
Linus Walleij Oct. 11, 2017, 7:51 a.m. UTC | #5
On Wed, Oct 4, 2017 at 12:03 AM, Stephen Boyd <sboyd@codeaurora.org> wrote:

> Could we remove the pin direction finding part here in
> gpiochip_add_pin_range() and lazily resolve the pin direction
> when a pin is requested? We would need a similar check in the msm
> specific debugfs code where we skip pins that aren't requested.
> This is basically a revert of commit 72d320006177 ("gpio: set up
> initial state from .get_direction()").

It seems reasonable for the gpiolib to be able to call this
function immediately after registering the new GPIO chip
with its vtable.

I think it is more up to the driver to numb the reply with
some dummy return value (i.e. input mode) or refactor the
callback so that it is acceptable for gpiolib to get an -EINVAL
or so from the driver (again it will assume input mode) if the
driver can't return the direction at this time.

Yours,
Linus Walleij
Stephen Boyd Oct. 12, 2017, 7:39 a.m. UTC | #6
On 10/11, Linus Walleij wrote:
> On Wed, Oct 4, 2017 at 12:03 AM, Stephen Boyd <sboyd@codeaurora.org> wrote:
> 
> > Could we remove the pin direction finding part here in
> > gpiochip_add_pin_range() and lazily resolve the pin direction
> > when a pin is requested? We would need a similar check in the msm
> > specific debugfs code where we skip pins that aren't requested.
> > This is basically a revert of commit 72d320006177 ("gpio: set up
> > initial state from .get_direction()").
> 
> It seems reasonable for the gpiolib to be able to call this
> function immediately after registering the new GPIO chip
> with its vtable.

I agree. I don't see the benefit though. Reading the direction
later would achieve the same effect and also work for ACPI qcom
platforms.

> 
> I think it is more up to the driver to numb the reply with
> some dummy return value (i.e. input mode) or refactor the
> callback so that it is acceptable for gpiolib to get an -EINVAL
> or so from the driver (again it will assume input mode) if the
> driver can't return the direction at this time.
> 

For qcom platforms the driver will never be able to return the
direction for these certain pins because reading the register is
not allowed by the firmware. Doing so will cause the device to
crash with a security violation.

If you don't want to delay reading the direction until request
time, we should have the DT msm pinctrl drivers leave the
get_direction() pointer as NULL. We don't need to read the
direction on DT platforms to make anything work.
Timur Tabi Oct. 13, 2017, 11:26 p.m. UTC | #7
On 10/03/2017 05:03 PM, Stephen Boyd wrote:
> I don't see any value
> beyond system wide debug in figuring out the default pin
> configuration of a pin that doesn't have a consumer in Linux.

I can agree with that.

> Could we remove the pin direction finding part here in
> gpiochip_add_pin_range() and lazily resolve the pin direction
> when a pin is requested? We would need a similar check in the msm
> specific debugfs code where we skip pins that aren't requested.
> This is basically a revert of commit 72d320006177 ("gpio: set up
> initial state from .get_direction()").
> 
> ACPI can still describe only the pin ranges that they care about
> exposing, but from the devicetree side it's been working well
> enough to not touch pins that aren't used by anything in Linux.
> 
> ---8<----
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index cd003b74512f..673028823bc5 100644
> --- a/drivers/gpio/gpiolib.c
> +++ b/drivers/gpio/gpiolib.c
> @@ -1210,16 +1210,7 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
>   		 * wrong direction in sysfs.
>   		 */
>   
> -		if (chip->get_direction) {
> -			/*
> -			 * If we have .get_direction, set up the initial
> -			 * direction flag from the hardware.
> -			 */
> -			int dir = chip->get_direction(chip, i);
> -
> -			if (!dir)
> -				set_bit(FLAG_IS_OUT, &desc->flags);
> -		} else if (!chip->direction_input) {
> +		if (!chip->direction_input) {
>   			/*
>   			 * If the chip lacks the .direction_input callback
>   			 * we logically assume all lines are outputs.
> diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
> index 273badd92561..4a0aeceb42f1 100644
> --- a/drivers/pinctrl/qcom/pinctrl-msm.c
> +++ b/drivers/pinctrl/qcom/pinctrl-msm.c
> @@ -24,7 +24,7 @@
>   #include <linux/pinctrl/pinconf.h>
>   #include <linux/pinctrl/pinconf-generic.h>
>   #include <linux/slab.h>
> -#include <linux/gpio.h>
> +#include <linux/gpio/driver.h>
>   #include <linux/interrupt.h>
>   #include <linux/spinlock.h>
>   #include <linux/reboot.h>
> @@ -494,6 +494,12 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
>   	};
>   
>   	g = &pctrl->soc->groups[offset];
> +
> +	if (!gpiochip_is_requested(chip, gpio)) {
> +		seq_printf(s, " %-8s:", g->name);
> +		return;
> +	}
> +
>   	ctl_reg = readl(pctrl->regs + g->ctl_reg);
>   
>   	is_out = !!(ctl_reg & BIT(g->oe_bit));

In order for this to work, I had to add this function from patch #1:

static int msm_gpio_request(struct gpio_chip *chip, unsigned int offset)
{
	struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
	const struct msm_pingroup *g = &pctrl->soc->groups[offset];

	if (!g->npins)
		return -ENODEV;

	return gpiochip_generic_request(chip, offset);
}

The problem with this is that none of the GPIOs are "requested", so it 
displays an output like this:

# cat /sys/kernel/debug/gpio
gpiochip0: GPIOs 0-149, parent: platform/QCOM8002:00, QCOM8002:00:
  (null)  :
  (null)  :
  (null)  :
[... truncated ]]
  (null)  :
  (null)  :
  (null)  :
  (null)  :
  gpio36  :
  gpio37  :
  gpio38  :
  gpio39  :
  (null)  :
  (null)  :

It can't differentiate between GPIOs that don't exist and GPIOs that 
haven't been requested.  Plus, the "(null)" entries are what I've been 
trying to avoid in the first place.

So overall, this patch seems okay, although it needs a little work. 
However, it doesn't address Bjorn's complaint that he doesn't want me to 
use pin ranges at all.
Linus Walleij Oct. 14, 2017, 10:43 p.m. UTC | #8
On Thu, Oct 12, 2017 at 9:39 AM, Stephen Boyd <sboyd@codeaurora.org> wrote:

> For qcom platforms the driver will never be able to return the
> direction for these certain pins because reading the register is
> not allowed by the firmware. Doing so will cause the device to
> crash with a security violation.

So I guess the driver needs to know what pin registers it can't
access so the user does not get a gun to shoot in the foot with.

If we augment gpiolib to just handle -EACCES or something
(-EIO?) from the driver .get_direction() callback for these lines,
things should be smooth?

Yours,
Linus Walleij
Thierry Reding Oct. 15, 2017, 8:18 p.m. UTC | #9
On Fri, Oct 13, 2017 at 06:26:23PM -0500, Timur Tabi wrote:
> On 10/03/2017 05:03 PM, Stephen Boyd wrote:
> > I don't see any value
> > beyond system wide debug in figuring out the default pin
> > configuration of a pin that doesn't have a consumer in Linux.
> 
> I can agree with that.
> 
> > Could we remove the pin direction finding part here in
> > gpiochip_add_pin_range() and lazily resolve the pin direction
> > when a pin is requested? We would need a similar check in the msm
> > specific debugfs code where we skip pins that aren't requested.
> > This is basically a revert of commit 72d320006177 ("gpio: set up
> > initial state from .get_direction()").
> > 
> > ACPI can still describe only the pin ranges that they care about
> > exposing, but from the devicetree side it's been working well
> > enough to not touch pins that aren't used by anything in Linux.
> > 
> > ---8<----
> > diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> > index cd003b74512f..673028823bc5 100644
> > --- a/drivers/gpio/gpiolib.c
> > +++ b/drivers/gpio/gpiolib.c
> > @@ -1210,16 +1210,7 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
> >   		 * wrong direction in sysfs.
> >   		 */
> > -		if (chip->get_direction) {
> > -			/*
> > -			 * If we have .get_direction, set up the initial
> > -			 * direction flag from the hardware.
> > -			 */
> > -			int dir = chip->get_direction(chip, i);
> > -
> > -			if (!dir)
> > -				set_bit(FLAG_IS_OUT, &desc->flags);
> > -		} else if (!chip->direction_input) {
> > +		if (!chip->direction_input) {
> >   			/*
> >   			 * If the chip lacks the .direction_input callback
> >   			 * we logically assume all lines are outputs.
> > diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
> > index 273badd92561..4a0aeceb42f1 100644
> > --- a/drivers/pinctrl/qcom/pinctrl-msm.c
> > +++ b/drivers/pinctrl/qcom/pinctrl-msm.c
> > @@ -24,7 +24,7 @@
> >   #include <linux/pinctrl/pinconf.h>
> >   #include <linux/pinctrl/pinconf-generic.h>
> >   #include <linux/slab.h>
> > -#include <linux/gpio.h>
> > +#include <linux/gpio/driver.h>
> >   #include <linux/interrupt.h>
> >   #include <linux/spinlock.h>
> >   #include <linux/reboot.h>
> > @@ -494,6 +494,12 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
> >   	};
> >   	g = &pctrl->soc->groups[offset];
> > +
> > +	if (!gpiochip_is_requested(chip, gpio)) {
> > +		seq_printf(s, " %-8s:", g->name);
> > +		return;
> > +	}
> > +
> >   	ctl_reg = readl(pctrl->regs + g->ctl_reg);
> >   	is_out = !!(ctl_reg & BIT(g->oe_bit));
> 
> In order for this to work, I had to add this function from patch #1:
> 
> static int msm_gpio_request(struct gpio_chip *chip, unsigned int offset)
> {
> 	struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
> 	const struct msm_pingroup *g = &pctrl->soc->groups[offset];
> 
> 	if (!g->npins)
> 		return -ENODEV;
> 
> 	return gpiochip_generic_request(chip, offset);
> }
> 
> The problem with this is that none of the GPIOs are "requested", so it
> displays an output like this:
> 
> # cat /sys/kernel/debug/gpio
> gpiochip0: GPIOs 0-149, parent: platform/QCOM8002:00, QCOM8002:00:
>  (null)  :
>  (null)  :
>  (null)  :
> [... truncated ]]
>  (null)  :
>  (null)  :
>  (null)  :
>  (null)  :
>  gpio36  :
>  gpio37  :
>  gpio38  :
>  gpio39  :
>  (null)  :
>  (null)  :
> 
> It can't differentiate between GPIOs that don't exist and GPIOs that haven't
> been requested.

This confuses me. Why would you even want to register pins that don't
exist? It sounds to me like you're lying to gpiolib and then try to work
around it trying to access the GPIOs that don't exist but which you told
it were there.

Why not just tell gpiolib about only the GPIOs that exist?

Thierry
Timur Tabi Oct. 15, 2017, 9:09 p.m. UTC | #10
On 10/15/17 3:18 PM, Thierry Reding wrote:
> This confuses me. Why would you even want to register pins that don't
> exist? It sounds to me like you're lying to gpiolib and then try to work
> around it trying to access the GPIOs that don't exist but which you told
> it were there.
> 
> Why not just tell gpiolib about only the GPIOs that exist?

Please look at my patches.  That's exactly what they do, but no one else 
likes that approach.
diff mbox

Patch

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index cd003b74512f..673028823bc5 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1210,16 +1210,7 @@  int gpiochip_add_data(struct gpio_chip *chip, void *data)
 		 * wrong direction in sysfs.
 		 */
 
-		if (chip->get_direction) {
-			/*
-			 * If we have .get_direction, set up the initial
-			 * direction flag from the hardware.
-			 */
-			int dir = chip->get_direction(chip, i);
-
-			if (!dir)
-				set_bit(FLAG_IS_OUT, &desc->flags);
-		} else if (!chip->direction_input) {
+		if (!chip->direction_input) {
 			/*
 			 * If the chip lacks the .direction_input callback
 			 * we logically assume all lines are outputs.
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 273badd92561..4a0aeceb42f1 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -24,7 +24,7 @@ 
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/slab.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/reboot.h>
@@ -494,6 +494,12 @@  static void msm_gpio_dbg_show_one(struct seq_file *s,
 	};
 
 	g = &pctrl->soc->groups[offset];
+
+	if (!gpiochip_is_requested(chip, gpio)) {
+		seq_printf(s, " %-8s:", g->name);
+		return;
+	}
+
 	ctl_reg = readl(pctrl->regs + g->ctl_reg);
 
 	is_out = !!(ctl_reg & BIT(g->oe_bit));