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] [thread-next>] [day] [month] [year] [list]
Message-ID: <E4EE696368DDDB1E+aNaRl8upyNeld9zX@troy-wujie14pro-arch>
Date: Fri, 26 Sep 2025 21:13:59 +0800
From: Troy Mitchell <troy.mitchell@...ux.spacemit.com>
To: Yixun Lan <dlan@...too.org>,
	Troy Mitchell <troy.mitchell@...ux.spacemit.com>
Cc: Andi Shyti <andi.shyti@...nel.org>, Alex Elder <elder@...cstar.com>,
	Troy Mitchell <troymitchell988@...il.com>,
	linux-i2c@...r.kernel.org, linux-kernel@...r.kernel.org,
	linux-riscv@...ts.infradead.org, spacemit@...ts.linux.dev
Subject: Re: [PATCH v2 6/6] i2c: spacemit: introduce pio for k1

On Fri, Sep 26, 2025 at 07:10:55PM +0800, Yixun Lan wrote:
> Hi Troy,
Hi Yixun,
Thanks for your review.

I have a question regarding the patch series.
Since patches 1–5 have already been merged,
should I keep the current version number and just send this single patch ?

About reply, see below.
> 
> On 10:02 Thu 25 Sep     , Troy Mitchell wrote:
> > This patch introduces I2C PIO functionality for the Spacemit K1 SoC,
> > enabling the use of I2C with interrupts disabled.
> > 
> > Signed-off-by: Troy Mitchell <troy.mitchell@...ux.spacemit.com>
> > ---
> >  drivers/i2c/busses/i2c-k1.c | 164 +++++++++++++++++++++++++++++++++++++-------
> >  1 file changed, 140 insertions(+), 24 deletions(-)
> > 
> > diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c
> > index 6b918770e612e098b8ad17418f420d87c94df166..e403eb7d6f329f4fe5c5242f94cc21094dff105c 100644
> > --- a/drivers/i2c/busses/i2c-k1.c
> > +++ b/drivers/i2c/busses/i2c-k1.c
> > @@ -97,6 +97,9 @@
> >  
> >  #define SPACEMIT_BUS_RESET_CLK_CNT_MAX		9
> >  
> > +/* Constants */
> > +#define SPACEMIT_WAIT_TIMEOUT      1000 /* ms */
> > +
> >  enum spacemit_i2c_state {
> >  	SPACEMIT_STATE_IDLE,
> >  	SPACEMIT_STATE_START,
> > @@ -125,6 +128,7 @@ struct spacemit_i2c_dev {
> >  
> >  	enum spacemit_i2c_state state;
> >  	bool read;
> > +	bool is_pio;
> using_pio_mode or simply use_pio, but have to say..
> 
> I feel it's improper to have this flag here, since it's not a controller
> level feature, I understand it was introduced to support aotmic operation
> 
> Personally, I'd suggest to pass the flag in xfer(), then propagate down to
> whatever needed, so it limit to single transmission which more flexible
I agree. I'll move the flag to xfer().

> 
> >  	struct completion complete;
> >  	u32 status;
> >  };
> > @@ -206,9 +210,14 @@ static int spacemit_i2c_wait_bus_idle(struct spacemit_i2c_dev *i2c)
> >  	if (!(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)))
> >  		return 0;
> >  
> > -	ret = readl_poll_timeout(i2c->base + SPACEMIT_ISR,
> > -				 val, !(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)),
> > -				 1500, SPACEMIT_I2C_BUS_BUSY_TIMEOUT);
> > +	if (!i2c->is_pio)
> > +		ret = readl_poll_timeout(i2c->base + SPACEMIT_ISR,
> > +					 val, !(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)),
> > +					 1500, SPACEMIT_I2C_BUS_BUSY_TIMEOUT);
> > +	else
> > +		ret = readl_poll_timeout_atomic(i2c->base + SPACEMIT_ISR,
> > +						val, !(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)),
> > +						1500, SPACEMIT_I2C_BUS_BUSY_TIMEOUT);
> question, since you have already used state-machine to track the I2C process,
> can you not poke hardware ISR register in a scatter way?

>
> I'd rather see it handled
> more closely in a interrupt context or related?
> 
> btw, does some bits of the ISR register have read-then-clear feature?
> which may require special attention to handle..
I’m not reading the ISR state all over the place. It is only accessed in
spacemit_i2c_wait_bus_idle() and spacemit_i2c_check_bus_release().
The first one is used before a transfer starts, and the second one is used
after a transfer error. In these cases I don’t see a way to rely on the
irq_handler to get the information in time.

In addition, with PIO support, the ISR needs to be read inside
wait_pio_xfer(). This is required, otherwise we can’t know when to
proceed with RX/TX.

As you mentioned, some ISR bits are indeed read-to-clear. I’ve already
added handling for that in the irq_handler to avoid losing events.
> 
> >  	if (ret)
> >  		spacemit_i2c_reset(i2c);
> >  
> > @@ -226,7 +235,7 @@ static void spacemit_i2c_check_bus_release(struct spacemit_i2c_dev *i2c)
> >  
> >  static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
> >  {
> > -	u32 val;
> > +	u32 val = 0;
> >  
> >  	/*
> >  	 * Unmask interrupt bits for all xfer mode:
> > @@ -234,7 +243,8 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
> >  	 * For transaction complete signal, we use master stop
> >  	 * interrupt, so we don't need to unmask SPACEMIT_CR_TXDONEIE.
> >  	 */
> > -	val = SPACEMIT_CR_BEIE | SPACEMIT_CR_ALDIE;
> > +	if (!i2c->is_pio)
> ..
> > +		val = SPACEMIT_CR_BEIE | SPACEMIT_CR_ALDIE;
> >  
> >  	/*
> >  	 * Unmask interrupt bits for interrupt xfer mode:
> > @@ -244,7 +254,8 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
> >  	 * i2c_start function.
> >  	 * Otherwise, it will cause an erroneous empty interrupt before i2c_start.
> >  	 */
> > -	val |= SPACEMIT_CR_DRFIE;
> > +	if (!i2c->is_pio)
> ..
> > +		val |= SPACEMIT_CR_DRFIE;
> >  
> >  	if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ)
> >  		val |= SPACEMIT_CR_MODE_FAST;
> > @@ -256,7 +267,10 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
> >  	val |= SPACEMIT_CR_SCLE;
> >  
> >  	/* enable master stop detected */
> > -	val |= SPACEMIT_CR_MSDE | SPACEMIT_CR_MSDIE;
> > +	val |= SPACEMIT_CR_MSDE;
> > +
> > +	if (!i2c->is_pio)
> > +		val |= SPACEMIT_CR_MSDIE;
> can you converge all assignment under one if?
Yes, I'll fix it in the next version.

> >  
> >  	writel(val, i2c->base + SPACEMIT_ICR);
> >  
> > @@ -293,10 +307,54 @@ static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c)
> >  	/* send start pulse */
> >  	val = readl(i2c->base + SPACEMIT_ICR);
> >  	val &= ~SPACEMIT_CR_STOP;
> > -	val |= SPACEMIT_CR_START | SPACEMIT_CR_TB | SPACEMIT_CR_DTEIE;
> > +	val |= SPACEMIT_CR_START | SPACEMIT_CR_TB;
> > +
> > +	if (!i2c->is_pio)
> > +		val |= SPACEMIT_CR_DTEIE;
> > +
> >  	writel(val, i2c->base + SPACEMIT_ICR);
> >  }
> >  
> > +static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid);
> > +static int spacemit_i2c_wait_pio_xfer(struct spacemit_i2c_dev *i2c)
> > +{
> > +	u32 msec = jiffies_to_msecs(i2c->adapt.timeout);
> > +	ktime_t timeout = ktime_add_ms(ktime_get(), msec);
> > +	int ret;
> > +
> > +	while (i2c->unprocessed && ktime_compare(ktime_get(), timeout) < 0) {
> > +		udelay(10);
> > +		i2c->status = readl(i2c->base + SPACEMIT_ISR);
> > +
> > +		spacemit_i2c_clear_int_status(i2c, i2c->status);
> > +
> > +		if (!(i2c->status & SPACEMIT_SR_IRF) && !(i2c->status & SPACEMIT_SR_ITE))
> > +			continue;
> > +
> > +		spacemit_i2c_irq_handler(0, i2c);
> 
> can you refactor and construct a new function? that can be reused between
> irq() and pio() cases, it makes people confused..
It makes sense. I will.
> 
> > +
> > +		i2c->status = readl(i2c->base + SPACEMIT_ISR);
> > +
> > +		/*
[...]
> >  
> > -static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num)
> > +static inline int
> > +spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num, bool is_pio)
> s/spacemit_i2c_xfer/spacemit_i2c_xfer_common/
Great suggesstion!

> 
> s/is_pio/atomic/, I'd suggest to distinguish 'pio' vs 'atomic'
Uh, But I wanna keep the original name 'pio' to avoid confusion.
In the public doc, It is named PIO..

> 
> >  {
> >  	struct spacemit_i2c_dev *i2c = i2c_get_adapdata(adapt);
> >  	int ret;
> >  
> > +	i2c->is_pio = is_pio;
> so, check my previous comment, you use this member to cache the flag..
> 
> > +
[...]
> >  
> >  static const struct i2c_algorithm spacemit_i2c_algo = {
> > -	.xfer = spacemit_i2c_xfer,
> > +	.xfer = spacemit_i2c_int_xfer,
> > +	.xfer_atomic = spacemit_i2c_pio_xfer,
> I'd suggest to align with core function's prototype,
> s/spacemit_i2c_int_xfer/spacemit_i2c_xfer/
> s/spacemit_i2c_pio_xfer/spacemit_i2c_pio_xfer_atomic /
Thanks.
                - Troy
> 
> >  	.functionality = spacemit_i2c_func,
> >  };
> >  
> > 
> > -- 
> > 2.51.0
> > 
> 
> -- 
> Yixun Lan (dlan)
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ