[sw] Introduce a DIF for rv_timer#1501
Conversation
91614b6 to
5ae1934
Compare
alphan
left a comment
There was a problem hiding this comment.
Thanks for implementing this @mcy! Please see my comments below. IMHO, the way the word timer is used, or overused, in the spec is a little bit confusing. Here is my understanding:
- Each hart can have a timer.
- Each timer can have one or more comparators, i.e.,
mtimecmp. - Each timer, not comparator, can be enabled/disabled individually. (CTRL register)
- Within a timer, interrupts of individual comparators, i.e.,
mtimecmpcan be enabled/disabled.
Please let me know if I misunderstood anything.
0d4daf6 to
9a17829
Compare
silvestrst
left a comment
There was a problem hiding this comment.
@mcy looks pretty good, I only went through half of this change, and will try to do the rest at some point this week, or early next week.
|
@mcy I am not sure what exactly is happened, but I don't see In the latest change that I have reviewed, is github being difficult, or you have removed it? |
|
Regarding multiple harts: the specification of OpenTitan's implementation of the timer device is unclear on how multiple harts and multiple comparisons will be handled, especially with how they will be mapped. Right now, there's just one register offset for the sole comparison register. Also, I think that having to provide the hart separately for each call is a bad idea and makes for an unpleasant API. I think a better approach is to either have the hart be part of the device struct, or to have an "init_hart" function that converts an overall device struct (containing just an MMIO pointer) to a hart-specific struct that most, but not all, DIFs accept. |
c4e956f to
7d6f818
Compare
|
I've re-written the DIF from the ground up to address most of the comments. |
|
Is this PR ready to be merged? |
|
@sriyerg No. This PR has not been approved yet, and doesn't have unit tests. |
lenary
left a comment
There was a problem hiding this comment.
Garret and I did a Design Review of RV_Timer today. There are specific comments below.
In terms of things we would like to see added:
- We would like to see the
disable/restoreAPI that exists in the UART DIF for interrupts, to allow users to disable interrupts and then restore back to the original state before they disabled any. - We would like typedefs for
hart_idandcomp_idto typedefuint32_ttodif_rv_timer_hart_id_tanddif_rv_timer_comp_id_t. This promotes readability and understandability of the interface.
There was a problem hiding this comment.
This is good. We're happy to handle parameters in this way (dynamically, rather than with a _Static_assert), though we know other DIFs are not doing this yet.
There was a problem hiding this comment.
As with I2C, we're happy that this API allows software to tune the dif_rv_timer_tick_params_t as necessary if there are timing issues on a specific device, but that a programmer can use this function to get good defaults.
There was a problem hiding this comment.
Given an inability to disarm a timer (beyond disabling the interrupt, which this function doesn't do), we think this should be called dif_rv_timer_set_threshold, and the comment about using UINT64_MAX should be removed, as @alphan points out it is incorrect.
|
(Note: I'm still in the process of going through comments, so I've marked several as resolved, but I won't upload the updated patch until I'm all the way done.) |
|
Unit tests added. |
|
I was wondering whether it could be a good idea for @hudson-ayers to have a quick look at the |
hudson-ayers
left a comment
There was a problem hiding this comment.
I went through everything but the tests, and only have a few comments. If any of my comments are obviously ignorant of best practices/standards for DIFs, that is because I first read the "what is a DIF" section of the opentitan docs this morning, so feel free to ignore :)
From the perspective my limited experience using the mtimer in Tock, I think this interface seems very reasonable and that it should be easy to port the existing mtimer code to use this DIF.
There was a problem hiding this comment.
Do we really need comparators here? Looking at the layout in the tech spec, I would expect the values of RV_TIMER_INTR_{ENABLE0,STATE0,TEST0}_REG_OFFSET to include the address shift due to the number of comparators, wouldn't they?
There was a problem hiding this comment.
Yes, unfortunately. The register offsets in the .h file are correct for earlgrey, but not in general: they assume one hart and one comparator per. To be fully general, we need to know the number of comparators, since the IRQ registers are placed after the comparators. I've spoken to @eunchan about switching the order (IRQs, then compartors), but I don't know if that wound up being a thing we were doing or not.
There was a problem hiding this comment.
I see, but for an instance with two comparators, I would expect the registers of both of the comparators to be before the irq registers and the values of RV_TIMER_INTR_{ENABLE0,STATE0,TEST0}_REG_OFFSET to be shifted accordingly.
There was a problem hiding this comment.
We talked about this offline: It looks like the best solution would be to move irq registers before the comparator registers (since their number is configurable). Without this we don't think there is a great solution:
- Adding the offset for comparators here means that if this DIF library is compiled for an rv_timer with N comparators, it can be used for rv_timers with >= N comparators.
- Not adding the offset for comparators here means that if this DIF library is compiled for an rv_timer with N comparators, it can be used for rv_timers with 1..N comparators.
I will create an issue to see if we can move the irq registers before the comparator registers.
@mcy, if things stay the same I think it would be a good idea to add a check in init to avoid surprises.
There was a problem hiding this comment.
I realized that this can be written to be fully genericaly, so I've gone ahead and updated it as such. =)
There was a problem hiding this comment.
If you agree with my above comment, I don't think you need irq_reg_for_hart. reg_for_hart(..., RV_TIMER_INTR_STATE0_REG_OFFSET) should suffice. Applies to other usages with the appropriate RV_TIMER_*_REG_OFFSET offset.
lenary
left a comment
There was a problem hiding this comment.
I don't think there are major hurdles here - we can address any minor comments in follow-ups, which will be much easier to review.
There was a problem hiding this comment.
We know we need to revisit the "reset on init" issue, so keep this for the moment and we can decide for real later.
There was a problem hiding this comment.
Yup. I think this behavior is consistent with the code we have today, and it shouldn't be hard to change if we change our minds.
f4f9d79 to
34ed2c8
Compare
Signed-off-by: Miguel Young de la Sota <mcyoung@google.com>
| static ptrdiff_t irq_reg_for_hart(uint32_t hart_id, uint32_t comparators, | ||
| ptrdiff_t reg_offset) { | ||
| // Note that it is completely valid for this value to be negative: if this | ||
| // library is built for hardware with a large number of compartors, this value | ||
| // is necessarially negative when used with hardware with a small number of | ||
| // comparators. | ||
| ptrdiff_t extra_comparator_offset = | ||
| sizeof(uint64_t) * (comparators - kComparatorsInReggenHeader); | ||
| return reg_for_hart(hart_id, reg_offset) + extra_comparator_offset; | ||
| } |
There was a problem hiding this comment.
Yes, this should work. The comment for the config struct is clear, as long as its fields are set correctly for the rv_timer instance being used, this eliminates the need for recompilation.
|
See #2741 for comments deferred to followups. |
|
Ok, I think we have enough consensus to land this. Anyone think not? |
Includes a cleanup of rv_timer_test to actually not interrupt immediately.