Hi Andres, > Subject: Re: [PATCH v3 4/6] hw/gpio/aspeed: Fix clear incorrect interrupt > status > for GPIO index mode > > On Thu, 2024-09-26 at 15:45 +0800, Jamin Lin wrote: > > The interrupt status field is W1C, where a set bit on read indicates > > an interrupt is pending. If the bit extracted from data is set it > > should clear the corresponding bit in group_value. However, if the > > extracted bit is clear then the value of the corresponding bit in > > group_value should be unchanged. > > > > SHARED_FIELD_EX32() extracts the interrupt status bit from the write > > (data). group_value is set to the set's interrupt status, which means > > I think you should s/group_value/reg_value/ here as that's what's used in the > removed code below. > > Though maybe Cédric can fix it up for you when he applies it if another > revision isn't otherwise necessary. > Thanks for review and suggestion. I will update them and add GPIO test case in V4 patch.
Jamin > > that for any pin with an interrupt pending, the corresponding bit is > > set. The deposit32() call updates the bit at pin_idx in the group, > > using the value extracted from the write (data). > > > > The result is that if multiple interrupt status bits were pending and > > the write was acknowledging specific one bit, then the all interrupt > > status bits will be cleared. > > However, it is index mode and should only clear the corresponding bit. > > > > For example, say we have an interrupt pending for GPIOA0, where the > > following statements are true: > > > > set->int_status == 0b01 > > s->pending == 1 > > > > Before it is acknowledged, an interrupt becomes pending for GPIOA1: > > > > set->int_status == 0b11 > > s->pending == 2 > > > > A write is issued to acknowledge the interrupt for GPIOA0. This causes > > the following sequence: > > > > reg_value == 0b11 > > pending == 2 > > s->pending == 0 > > set->int_status == 0b00 > > > > It should only clear bit 0 in index mode and the correct result should > > be as following. > > > > set->int_status == 0b11 > > s->pending == 2 > > > > pending == 1 > > s->pending == 1 > > set->int_status == 0b10 > > > > Maybe this is a bit forward, but: > > Suggested-by: Andrew Jeffery <and...@codeconstruct.com.au> > Reviewed-by: Andrew Jeffery <and...@codeconstruct.com.au> > > > Signed-off-by: Jamin Lin <jamin_...@aspeedtech.com> > > --- > > hw/gpio/aspeed_gpio.c | 27 +++++++++++++++++---------- > > 1 file changed, 17 insertions(+), 10 deletions(-) > > > > diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index > > 8725606aec..16c18ea2f7 100644 > > --- a/hw/gpio/aspeed_gpio.c > > +++ b/hw/gpio/aspeed_gpio.c > > @@ -641,7 +641,7 @@ static void aspeed_gpio_write_index_mode(void > *opaque, hwaddr offset, > > uint32_t pin_idx = reg_idx_number % ASPEED_GPIOS_PER_SET; > > uint32_t group_idx = pin_idx / GPIOS_PER_GROUP; > > uint32_t reg_value = 0; > > - uint32_t cleared; > > + uint32_t pending = 0; > > > > set = &s->sets[set_idx]; > > props = &agc->props[set_idx]; > > @@ -703,16 +703,23 @@ static void aspeed_gpio_write_index_mode(void > *opaque, hwaddr offset, > > FIELD_EX32(data, GPIO_INDEX_REG, > INT_SENS_2)); > > set->int_sens_2 = update_value_control_source(set, > set->int_sens_2, > > > reg_value); > > - /* set interrupt status */ > > - reg_value = set->int_status; > > - reg_value = deposit32(reg_value, pin_idx, 1, > > - FIELD_EX32(data, GPIO_INDEX_REG, > INT_STATUS)); > > - cleared = ctpop32(reg_value & set->int_status); > > - if (s->pending && cleared) { > > - assert(s->pending >= cleared); > > - s->pending -= cleared; > > + /* interrupt status */ > > + if (FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS)) { > > + /* pending is either 1 or 0 for a 1-bit field */ > > + pending = extract32(set->int_status, pin_idx, 1); > > + > > + assert(s->pending >= pending); > > + > > + /* No change to s->pending if pending is 0 */ > > + s->pending -= pending; > > + > > + /* > > + * The write acknowledged the interrupt regardless of > whether it > > + * was pending or not. The post-condition is that it mustn't > be > > + * pending. Unconditionally clear the status bit. > > + */ > > + set->int_status = deposit32(set->int_status, pin_idx, 1, > > + 0); > > } > > - set->int_status &= ~reg_value; > > break; > > case gpio_reg_idx_debounce: > > reg_value = set->debounce_1;