-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
core: interrupts: add interrupt_release api for reset properties #6907
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've not fully dug into the implication of this feature. That said, here are some comments. Also, I wonder it interrupt_release()
would be a better label, rather than interrupt_reset()
.
core/include/kernel/interrupt.h
Outdated
* @itr_num Interrupt number to reset | ||
*/ | ||
static inline void interrupt_reset(struct itr_chip *chip, size_t itr_num) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert(chip->ops->reset)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
core/drivers/gic.c
Outdated
{ | ||
size_t idx = it / NUM_INTS_PER_REG; | ||
uint32_t mask = 1 << (it % NUM_INTS_PER_REG); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
must check that it >= GIC_SPI_BASE
For consistency, it think this function should also ensures the the interrupt was previously disabled. I think this means git_it_reset()
needs a return code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checked, if it < GIC_SPI_BASE, it will panic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API only reset the properties of interrupt, It is not necessary that interrupts have been disabled before. Functionally, the two are not coupled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure it's that simple (I'm happy to be proven wrong though). What if the interrupt is active?
core/drivers/gic.c
Outdated
@@ -996,6 +1024,26 @@ static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, | |||
gic_it_raise_sgi(gd, it, cpu_mask, ns); | |||
} | |||
|
|||
static void gic_it_reset(struct gic_data *gd, size_t it) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this whole function gic_it_reset()
seems supported only when CFG_ARM_GICV3
is enabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It also works when CFG_ARM_GICV3 is not enabled, The GIC version affects whether IGROUPMODR is configured.
core/include/kernel/interrupt.h
Outdated
/* | ||
* interrupt_reset() - Reset the property for an interrupt | ||
* @chip Interrupt controller | ||
* @itr_num Interrupt number to reset |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is supported only for SPIs, could you add this information in this inline description comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Replaced the label from interrupt_reset to interrupt_release. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this doesn't boil to changing the group assignment of the interrupt id. As long as the interrupt is disabled we could leave it to the previous owner to restore the other properties.
core/drivers/gic.c
Outdated
{ | ||
struct gic_data *gd = &gic_data; | ||
|
||
gd->pre_prio = calloc(gd->max_it + 1, sizeof(*gd->pre_prio)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will only be needed in very specific configurations, but like this, it will impact all configurations. How about keeping this information outside the GIC driver and letting interrupt_release()
take the needed parameters to restore the state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the gic_spi_get_prop API to get the interrupt properties, and the interrupt_release need to specify the interrupt attributes as parameters.
core/drivers/gic.c
Outdated
size_t idx = it / NUM_INTS_PER_REG; | ||
uint32_t mask = 1 << (it % NUM_INTS_PER_REG); | ||
|
||
/* Assigned to group0 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about group1 interrupts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API is used for change group0 or goup1 secure interrupts to group1 interrupts, so if group1 nonsecure interrupts call this API, it will be asserted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GICv3 Group 0 interrupts belong to EL3 so I'm not sure we should do anything with those.
Yes, it will change the group assignment of the interrupt id. |
core/drivers/gic.c
Outdated
size_t idx = it / NUM_INTS_PER_REG; | ||
uint32_t mask = 1 << (it % NUM_INTS_PER_REG); | ||
|
||
/* Assigned to group0 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GICv3 Group 0 interrupts belong to EL3 so I'm not sure we should do anything with those.
core/drivers/gic.c
Outdated
/* Assigned to group0 */ | ||
assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); | ||
|
||
gic_it_set_cpu_mask(gd, it, cpu_mask); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once the interrupt has been changed to non-secure, the normal can configure it to their liking. How about clearing cpu_mask
and setting prio
to 0xff
to avoid leaking information or unintended state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's OK to clear the cpu_mask, but is it possible to set the priority to the Linux kernel's default priority setting of 0xa0?And the current behavior of Kernel setting prio is undefined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, that makes sense.
core/include/kernel/interrupt.h
Outdated
* @prio Interrupt priority | ||
* @cpu_mask Mask of the CPUs targeted by the interrupt | ||
*/ | ||
static inline void interrupt_release(struct itr_chip *chip, size_t itr_num, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that you have already changed the name of this function once, but wouldn't interrupt_release_to_ns()
be more clear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I will use interrupt_release_to_ns instead of interrupt_release.
core/include/kernel/interrupt.h
Outdated
* @cpu_mask Mask of the CPUs targeted by the interrupt | ||
*/ | ||
static inline void interrupt_release(struct itr_chip *chip, size_t itr_num, | ||
uint8_t prio, uint8_t cpu_mask) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The normal world should be able to configure this itself.
core/drivers/gic.c
Outdated
@@ -858,6 +888,20 @@ void gic_dump_state(void) | |||
} | |||
} | |||
|
|||
void gic_spi_get_prop(size_t it, uint8_t *cpu_mask, uint8_t *prio) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this function needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to get property before requesting the IRQ so that it can be used later in the irq_release flow. I will remove this function if the cpu_mask is cleared and the priority set to default value.
core/drivers/gic.c
Outdated
{ | ||
size_t idx = it / NUM_INTS_PER_REG; | ||
uint32_t mask = 1 << (it % NUM_INTS_PER_REG); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure it's that simple (I'm happy to be proven wrong though). What if the interrupt is active?
core/include/kernel/interrupt.h
Outdated
@@ -72,6 +72,8 @@ struct itr_ops { | |||
void (*raise_pi)(struct itr_chip *chip, size_t it); | |||
void (*raise_sgi)(struct itr_chip *chip, size_t it, | |||
uint32_t cpu_mask); | |||
void (*release)(struct itr_chip *chip, size_t it, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
release() is doing other way of add(). so, would it be much clear if they are next to each other?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your comment, It's sorted them in descending order by the first letter
By the way, rebasing the patches on the latest should take care of the failing test case. |
Please use rebase instead of merge, we don't accept merges in pull requests. |
6d5dbeb
to
0e58e2d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With my comment addressed, please apply:
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
core/drivers/gic.c
Outdated
{ | ||
struct gic_data *gd = &gic_data; | ||
size_t idx = it / NUM_INTS_PER_REG; | ||
uint32_t mask = 1 << (it % NUM_INTS_PER_REG); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the BIT32()
macro instead. I know we're doing a bit of both in this file, but using BIT32()
is the preferred way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
core/drivers/gic.c
Outdated
|
||
assert(it < gd->max_it && it >= GIC_SPI_BASE); | ||
/* Assert it's already disabled */ | ||
assert(!gic_it_is_enabled(gd, it)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if an assertion is enough here. I would rather suggest to return an error code, what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most errors here either cause an assert or a panic. I don't see how this error is a special case.
What should a caller do on this error that he shouldn't have done already?
This is a static programming error, not a dynamic error like malloc() failing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
/* Clear pending status */ | ||
io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask); | ||
/* Assign it to NS Group1 */ | ||
io_setbits32(gd->gicd_base + GICD_IGROUPR(idx), mask); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this instruction and the one below should be protected by a lock.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, since we're writing to a value register, not a set or clear bits register.
This function is in contrast to void gic_init_donate_sgi_to_ns()
used post-boot when more than one core might be active in the secure world.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
core/include/drivers/gic.h
Outdated
@@ -56,4 +58,7 @@ void gic_init_per_cpu(void); | |||
|
|||
/* Print GIC state to console */ | |||
void gic_dump_state(void); | |||
|
|||
/* Release the property for a shared peripheral interrupt */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explicitly say that the interrupt is re-assigned to the non-secure interrupt group and its priority reset to GIC_SPI_PRI_NS_EL1
.
State also that the interrupt shall be disabled when this function is called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
of an interrupt This patch introduces gic_spi_release_to_ns API to release an interrupt to Non secure settings. This functionality is essential for scenarios where a specific interrupt needs to be dynamically set to either Group 1 Secure (G1S) or Group 1 Non-Secure (G1NS) at different times. Signed-off-by: Runyang Chen <runyang.chen@mediatek.com> Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
uint32_t mask = BIT32(it % NUM_INTS_PER_REG); | ||
|
||
if (it < gd->max_it && it >= GIC_SPI_BASE) | ||
return TEE_ERROR_OVERFLOW; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest TEE_ERROR_BAD_PARAMETERS
instead.
@@ -858,6 +860,36 @@ void gic_dump_state(void) | |||
} | |||
} | |||
|
|||
int gic_spi_release_to_ns(size_t it) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/int
/TEE_Result
/
This pull request has been marked as a stale pull request because it has been open (more than) 30 days with no activity. Remove the stale label or add a comment, otherwise this pull request will automatically be closed in 5 days. Note, that you can always re-open a closed issue at any time. |
@ChenRunyang, do you plan to update this P-R? |
This pull request has been marked as a stale pull request because it has been open (more than) 30 days with no activity. Remove the stale label or add a comment, otherwise this pull request will automatically be closed in 5 days. Note, that you can always re-open a closed issue at any time. |
Sorry for late, I've been on vacation recently, I will modify the patch according to your suggestions. |
This patch introduces a interrupt_release API to reset the properties of an interrupt to its previous settings. This functionality is essential for scenarios where a specific interrupt needs to be dynamically set to either Group 1 Secure (G1S) or Group 1 Non-Secure (G1NS) at different times.