-
Notifications
You must be signed in to change notification settings - Fork 13
ot_spi_device,ot_spi_host: Bugfix + Refactoring + Passthrough mode implementation
#255
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
base: ot-9.2.0
Are you sure you want to change the base?
ot_spi_device,ot_spi_host: Bugfix + Refactoring + Passthrough mode implementation
#255
Conversation
b7c3b04 to
2e2300b
Compare
2264c77 to
f1a68a2
Compare
hw/opentitan/ot_spi_device.c
Outdated
| bool loop; /* Keep reading the buffer if end is reached */ | ||
| bool watermark; /* Read watermark hit, used as flip-flop */ | ||
| bool new_cmd; /* New command has been pushed in current SPI transaction */ | ||
| bool cmd_addr_swap_en; /* Passthrough mode - address swap 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.
maybe group all the passthrough related value into a structure. (cmd....?)
This would also to clear the whole thing at once in ot_spi_device_passthrough_unmatched_command_params
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.
If not grouped in a structure no big deal but it seems these values are not reset yet.
f1a68a2 to
6e8f034
Compare
e8ef6d7 to
ad5c39c
Compare
ot_spi_device: Refactoring + Passthrough mode implementationot_spi_device,ot_spi_host: Refactoring + Passthrough mode implementation
ca61a08 to
28ffc3c
Compare
|
I have discovered that OT SPI Device is not the only device controlling this SPI bus, the bus is actually shared by OT SPI Host 0 in Earlgrey, and OT SPI Host is bypassed entirely when Passthrough mode is enabled. This seems to only be documented here. As such this PR has been reworked a bit. |
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.
quick review.
28ffc3c to
a49e9bf
Compare
a49e9bf to
3a643ee
Compare
ot_spi_device,ot_spi_host: Refactoring + Passthrough mode implementationot_spi_device,ot_spi_host: Bugfix + Refactoring + Passthrough mode implementation
3a643ee to
05aa2a7
Compare
05aa2a7 to
6fc1a21
Compare
|
Just missing some checks in OT SPI Host to inhibit its activity when Passthrough on SPI Device is enabled, which should be a very pathological situation. Otherwise ready for review and nits up to now. |
Depends on lowRISC/qemu#255 Signed-off-by: Alice Ziuziakowska <[email protected]>
Depends on lowRISC/qemu#255 Signed-off-by: Alice Ziuziakowska <[email protected]>
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.
There are two small features missing
- complete cleanup of passthrough variables from
reset_enter - add
LOG_GUEST_ERRORmessage when the SPI host is attempting to drive its /CS line or data lines whenpassthrough_enis enabled. I guess it could be implemented by trackingpassthrough_enwhenever it attempts to change its first /CS line.
hw/opentitan/ot_spi_host.c
Outdated
| { | ||
| /* Passthrough is not implemented if SPI Host has more than one CS line */ | ||
| if (s->num_cs != 1u) { | ||
| trace_ot_spi_host_passthrough_unimplemented(s->ot_id); |
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.
nit pick: I wonder if the name of the trace is not a bit confusing, as unimplemented is usually ... used to report something that is not -yet- implemented, whereas here it is the HW that does not support this feature.
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.
Should this be a LOG_GUEST_ERROR instead maybe? The software should know if there is more than one CS on the hardware it is running on.
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 guess it could be understood this way yes.
In this case, I think it would great to also add a boolean flag so that this error message is only emitted once (as we do for OT_UNIMP) so that the error log is not flooded with the same message for every attempt to transmit a byte or drive the /CS line.
a847e12 to
1ef99aa
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.
Thanks for all the work on this @ziuziakowska, it looks great to me and matches the HW implementation more closely now.
I agree with @rivos-eblot's remaining comments, but I'm happy to approve when those (and my new comments) are addressed.
As one final suggestion, it would also be great if you could rebase on #277 and then update the SPI device documentation to briefly note that passthrough is supported, and any known limitations (e.g. dummy cycles rounded up)?
1ef99aa to
07a9072
Compare
| static uint8_t ot_spi_host_downstream_transfer(OtSPIHostState *s, uint8_t tx) | ||
| { | ||
| if (!ot_spi_host_supports_passthrough(s)) { | ||
| qemu_log_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.
it would be useful to add a boolean value to only emit this error (passthrough triggerred) once per reset session, to avoid flooding the error stream (one per byte...)
The same boolean could be re-used with all siblings errors (/CS, EN)
It could be a bitmask of errors, as there are several ones to track
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 that on every byte might be a bit too aggressive guest error messaging, but I think once per-reset might be too far in the other direction (for this specific case I think it makes sense, but not in general). I could imagine complicated behaviour in software could cause some of these guest error conditions to be hit but not cause any meaningful issues, and later on in situations where it could be a problem the guest errors would be inhibited.
| if (!ot_spi_host_supports_passthrough(s) || !s->passthrough_en) { | ||
| rx = (uint8_t)ssi_transfer(s->ssi, tx); | ||
| } else { | ||
| qemu_log_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.
Another boolean for this error (host-triggered) would be nice.
| qemu_log_mask(LOG_GUEST_ERROR, | ||
| "%s: R/O register 0x%02" HWADDR_PRIx " (%s)\n", __func__, | ||
| addr, TPM_REG_NAME(reg)); | ||
| "%s: %s: R/O register 0x%02" HWADDR_PRIx " (%s)\n", |
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.
nit: I got tired on this syntax in other files, so I've started to use something more compact (less lines) and fully valid with OT:
"%s: %s: .. 0x%02x (%s)\n",
__func__, s->ot_id, (uint32_t)addr, TPM_REG_NAME(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 very sure about this in general, there are some devices where the offset of the register can be greater than 0x100, such as the flash controller, and in the SPI Device TPM implementation. I would rather leave this for a separate PR to do this across all the devices at once in a consistent 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.
I did not mean to use 0x02 in general which was already defined (i.e. there is no change) but to replace HWADDR_PRIx/hwaddr with x/(uint32_t)addr , since OT only uses 32-bit buses.
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.
Depending on the devices, we have 1, 2, 3 or 4 meaningful nibbles.
|
Note: you will need to update |
74110d6 to
939c7fe
Compare
Both EG and DJ use E/I SRAM now Signed-off-by: Alice Ziuziakowska <[email protected]>
Signed-off-by: Alice Ziuziakowska <[email protected]>
The bit-fields previously used here are just advisory/convention, the whole 22-bit field is RW and software maintained. This is also expected behaviour for spi_passthru_test. Signed-off-by: Alice Ziuziakowska <[email protected]>
The bytes are received over the wire and stored in the buffer most-significant byte first (big-endian), so the dummy byte is the last byte not the first. Signed-off-by: Alice Ziuziakowska <[email protected]>
Expected by spi_passthru_test, see: https://github.com/lowRISC/opentitan/blob/master/sw/host/tests/chip/spi_device/src/spi_passthru.rs#L70-L80 Signed-off-by: Alice Ziuziakowska <[email protected]>
…ALUE Name is more verbose but matches the usage better, as in `ot_spi_host` Signed-off-by: Alice Ziuziakowska <[email protected]>
This commit simplifies command slot definitions and the associated state and control flow. The HW CFG and the HW STA commands have been combined into just HW commands, as in flash mode they are handled in hardware by some way and should therefore share the same data path. For passthrough mode, a subset of these HW commands can be intercepted (all except for WREN and WRDI). As the matched command slot number determines whether the command is a SW or HW command, the `OtSpiFlashCommand` enum has been removed in favour of using `is_sw_command` to return the boolean. Command slot matching has been brought out into its own function, `match_command_slot`, which returns whether an opcode was matched in the command info registers. The decoded slot number is only valid if this returns true. Also a bug is fixed in `ot_spi_device_exec_command` where hardcoded opcodes for read commands were used instead of the opcodes in the associated command slot. Signed-off-by: Alice Ziuziakowska <[email protected]>
Signed-off-by: Alice Ziuziakowska <[email protected]>
... and removes `OtSpiDeviceAddrMode`. `ot_spi_device_get_command_address_size` now returns the size of the address field in the current command, using the value in `cmd_info` and the current 4B enable state. Signed-off-by: Alice Ziuziakowska <[email protected]>
Signed-off-by: Alice Ziuziakowska <[email protected]>
Signed-off-by: Alice Ziuziakowska <[email protected]>
This implements a passthrough enable and chip select IRQ and a method to interact with the downstream SPI bus, for use by upstream SPI Device. Signed-off-by: Alice Ziuziakowska <[email protected]>
This adds the corresponding out IRQs to OT SPI Device, as well as a property that contains the downstream OT SPI Host. Signed-off-by: Alice Ziuziakowska <[email protected]>
…IRQs Signed-off-by: Alice Ziuziakowska <[email protected]>
This commit implements the Passthrough mode on SPI Device. Passthrough mode allows the device to act as a proxy for a downstream flash device, optionally intercepting commands to send back its own values, filtering commands sent downstream, or transparently translating address and payload bytes. This also "implements" the Disabled mode, which discards all bytes sent to the device. Signed-off-by: Alice Ziuziakowska <[email protected]>
Signed-off-by: Alice Ziuziakowska <[email protected]>
939c7fe to
4d28dec
Compare
This PR implements the Passthrough mode for OT SPI Device and any required changes in OT SPI Host. Passthrough mode allows for external SPI transfers to be passed through to a downstream device, and optionally intercepted or modified by OT SPI Device.
In HW, OT SPI Device and OT SPI Host are linked by their SPI bus and a wire that represents whether the Device is in Passthrough mode. If Passthrough mode is enabled, the SPI Host is entirely bypassed and SPI Device has full control over the bus, which it uses to talk to the same downstream flash as SPI Host. See Documentation reference, RTL.
This passthrough mechanism is only implemented by OT SPI Host if it has one CS line: RTL
The structure of the PR is as follows:
ot_spi_devicefor the Passthrough implementation.ot_spi_host- two GPIOs are used to communicate Passthrough enabled and the Chip Select as driven by OT SPI Device, OT SPI Device and OT SPI Host are then linked together.ot_spi_device.I have tried to handle most corner-cases I can think of, but some conflicting configuration options might not behave as expected.
Unimplemented features:
Testing:
This implementation has been tested against
spi_passthru_test. See lowRISC/opentitan#28649 for the changes required in OpenTitan. To test manually the steps are:dd if=/dev/zero of=<flash> bs=1M count=32spi_passthru_test, with these additional flags:-global ot-earlgrey-board.spiflash0=w25q256 -drive if=mtd,file=<flash>,format=raw,bus=0