lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <67f40dec.170a0220.5cda5.994c@mx.google.com>
Date: Mon, 7 Apr 2025 19:39:54 +0200
From: Christian Marangi <ansuelsmth@...il.com>
To: Uwe Kleine-König <ukleinek@...nel.org>
Cc: linux-kernel@...r.kernel.org, linux-pwm@...r.kernel.org,
	Benjamin Larsson <benjamin.larsson@...exis.eu>,
	AngeloGioacchino Del Regno <angelogioacchino.delregno@...labora.com>,
	Lorenzo Bianconi <lorenzo@...nel.org>
Subject: Re: [RESEND PATCH v11] pwm: airoha: Add support for EN7581 SoC

On Thu, Apr 03, 2025 at 05:01:46PM +0200, Uwe Kleine-König wrote:
> Hello,
> 
> On Thu, Apr 03, 2025 at 12:50:27PM +0200, Christian Marangi wrote:
> > On Thu, Apr 03, 2025 at 11:58:48AM +0200, Uwe Kleine-König wrote:
> > > > +	if (hwpwm >= AIROHA_PWM_NUM_GPIO)
> > > > +		offset -= AIROHA_PWM_NUM_GPIO;
> > > > +
> > > > +	/* One FLASH_MAP register handles 8 pins */
> > > > +	*shift = do_div(offset, AIROHA_PWM_PINS_PER_FLASH_MAP);
> > > > +	*shift = AIROHA_PWM_REG_GPIO_FLASH_MAP_SHIFT(*shift);
> > > > +
> > > > +	if (offset < AIROHA_PWM_NUM_GPIO)
> > > > +		*addr = AIROHA_PWM_REG_GPIO_FLASH_MAP(offset);
> > > > +	else
> > > > +		*addr = AIROHA_PWM_REG_SIPO_FLASH_MAP(offset);
> > > 
> > > A single if would be a bit more straight forward. Something like:
> > > 
> > > 	static void airoha_pwm_get_flash_map_addr_and_shift(unsigned int hwpwm,
> > > 							    unsigned int *addr, unsigned int *shift)
> > > 	{
> > > 		u64 offset = hwpwm;
> > > 	
> > > 		if (hwpwm >= AIROHA_PWM_NUM_GPIO) {
> > > 			unsigned sipohwpwm = hwpwm - AIROHA_PWM_NUM_GPIO;
> > > 
> > > 			*shift = AIROHA_PWM_REG_GPIO_FLASH_MAP_SHIFT(sipohwpwm % AIROHA_PWM_PINS_PER_FLASH_MAP)
> > > 			*addr = AIROHA_PWM_REG_SIPO_FLASH_MAP(sipohwpwm);
> > > 		} else {
> > > 			*shift = AIROHA_PWM_REG_GPIO_FLASH_MAP_SHIFT(hwpwm % AIROHA_PWM_PINS_PER_FLASH_MAP)
> > > 			*addr = AIROHA_PWM_REG_GPIO_FLASH_MAP(hwpwm);
> > > 		}
> > > 	}
> > > 
> > 
> > I think you missed the do_div that do side effect on offset. Also that
> > needs to be / AIROHA_PWM_PINS_PER_FLASH_MAP.
> 
> Ack. Luckily you got the idea anyhow. This double effect of do_div() is
> easy to miss, so getting rid of them sounds sensible.
> 
> > > > +		if (duty_ns == bucket->duty_ns &&
> > > > +		    period_ns == bucket->period_ns)
> > > > +			return i;
> > > 
> > > If period_ns == 4010 and bucket->period_ns == 4000 you're not
> > > considering *bucket even though it has the right period setting.
> > > (period_ns is the requested period and not the expected period actually
> > > implemented by HW, right?)
> > > 
> > 
> > Doesn't that requires a different generator? The value we store in the
> > bucket is the requested period yes.
> 
> No it doesn't. If I understood right the possible periods are: 4ms, 8ms,
> ..., so a request to do 4.01ms will be mapped to 4ms which allows to
> share the generator.
> 
> > > > +				  AIROHA_PWM_GPIO_FLASH_EN << shift);
> > > > +		return;
> > > > +	}
> > > > +
> > > > +	regmap_update_bits(pc->regmap, addr,
> > > > +			   AIROHA_PWM_GPIO_FLASH_SET_ID << shift,
> > > > +			   FIELD_PREP(AIROHA_PWM_GPIO_FLASH_SET_ID, index) << shift);
> > > 
> > > Huh, I'd prefer:
> > > 
> > > 	regmap_update_bits(pc->regmap, addr,
> > > 			   AIROHA_PWM_GPIO_FLASH_SET_ID(hwpwm % 8)
> > > 			   FIELD_PREP(AIROHA_PWM_GPIO_FLASH_SET_ID(hwpwm % 8), index));
> > > 
> > > (That probably doesn't work out of the box because of the
> > > __builtin_constant_p check on mask, so you might need a local
> > > alternative to FIELD_PREP without that check.)
> > 
> > Honestly it's not worth to introduce custom FIELD_PREP for this. Yes the
> > problem is that FIELD_PREP requires constant mask so hwpwm % 8 is
> > problematic. An old implementation had stuff in define but resulted in
> > very ugly and confusing define and macro. The shift and FIELD_PREP
> > permits a much cleaner description in the define part at the cost of
> > that additional << shift needed.
> > 
> > Hope you can understand why I think it's better to keep it this way.
> 
> OK, I can live with that.
> 
> > > > +	bucket = airoha_pwm_consume_generator(pc, duty_ns, period_ns,
> > > > +					      hwpwm);
> > > > +	if (bucket < 0)
> > > > +		return -EBUSY;
> > > > +
> > > > +	/*
> > > > +	 * For SIPO reinit is always needed to trigger the shift register chip
> > > > +	 * and apply the new flash configuration.
> > > 
> > > I don't understand that sentence. What is the shift register chip? What
> > > is a flash configuration?
> > > 
> > 
> > The SoC can have attached a shift register chip to supports multiple LEDs.
> > The handling of this chip and comunication is done internally to the SoC
> > and it's exposed to register with these additional register.
> > 
> > When such channel are used with an assumed shift register, to apply the
> > new configuration in airoha_pwm_config_flash_map(), the shift register
> > chip needs to be reinit to actually refresh the chip internal register
> > with the new "flash configuration" (aka the values for
> > AIROHA_PWM_GPIO_FLASH_SET_ID)
> > 
> > Will add more comments to this to make it more clear.
> 
> Sounds good.
> 
> > > > +	state->enabled = FIELD_GET(AIROHA_PWM_GPIO_FLASH_EN, val >> shift);
> > > > +	if (!state->enabled)
> > > > +		return 0;
> > > > +
> > > > +	state->polarity = PWM_POLARITY_NORMAL;
> > > > +
> > > > +	bucket = FIELD_GET(AIROHA_PWM_GPIO_FLASH_SET_ID, val >> shift);
> > > > +	state->period = pc->buckets[bucket].period_ns;
> > > 
> > > Does .period_ns hold the requested or the actual period? You should
> > > return the latter.
> > 
> > Problem is that putting .period_ns here cause error in the PWM_DEBUG
> > validations. This is caused by the conversion error of the various / and
> > * done to convert tick to ns. Also on applying the configuration we
> > already do all the validation to make sure the request value is the
> > expected one.
> 
> Then there is a bug somewhere. I wouldn't completely rule out it's in
> the PWM_DEBUG logic, but my bet is on your driver then.
>  
> > For the initial values, there is airoha_pwm_fill_bucket that read the
> > current PWM values at boot and fill the buckets with the current values.
> > 
> > This is the compromise I found to handle both pre-configured bucket and
> > also handle the division errors in the ns - tick conversion.
> > 
> > Hope this is acceptable, do you have hint on better handling this?
> 
> I'd wait for the next iteration of your patch and then take a deeper
> look in the maths involved. It should be possible to make PWM_DEBUG
> happy and still report the actual configuration.
> 

Hi Uwe,

I just sent v12. While making more test I notice something interesting
where the duty was off-by-1 in get_state in the PWM_DEBUG scenario.

That caused the idemponent error, I found the cause so now get_state
actually return the real values instead of the local one in the bucket!

I address everything else, hope v12 is the one!

-- 
	Ansuel

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ