finalisers for SPI; clean up sdcardio; reset all pins after finalisers; avoid USB SD races #10699
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is a multi-part fix for race conditions occurring on VM shutdown when an SD card mounted in user code is exposed via USB MSC. There can be filesystem operations initiated by the host that are in process when
code.pyends., which cause crashes or USB disconnects. In the process of debugging this, I found several other things to clean up and add.SPI resetting when VM shuts down
Previously, many ports had
spi_reset()orreset_spi()routines that reset all SPI buses that were not persistent when the VM shut down. If there were host-initiated USB MSC operations (usually just reads) on a user-mounted filesystem, these forced resets would interfere with those USB MSC operations, or vice versa. For instance, on Espressif, the forced resets would fail if an SPI operation was in progress.busio.SPI()to have a finaliser. This obviates the need for a global SPI reset.reset_spi()andspi_reset(). Thecommon_hal_busio_spi_deinit()routines take care of all SPI resetting necessary when the finalisers are run.common_hal_busio_spi_mark_deinit()routines to allbusio.SPIimplementations, and call them as appropriate in the variousSPI.cfiles.common_hal_busio_spi_mark_deinit()inshared-module/displayio/__init__.cwhen aFourWirebus is copied. This mimics what was already done fordisplayioI2C bus copies, whenbusio.I2C()was changed to use a finaliser.Don't reset pins before finalisers run
reset_port()is called inmain.cbefore finalisers are run. On all ports,reset_port()would callreset_all_pins(). However, this meant that SPI pins would get reset while SD card operations might still be in progress, allowing the kind of race conditions described above.reset_all_pins()out of the port-specificreset_port()routines, and instead call it inmain.cafterstop_mp(), and so therefore after the finalisers run. All ports providereset_all_pins(), so it does not need to be called individually in each port. I was initially thinking about add areset_port_after_finalisers()routine for each port that calledreset_all_pins(), but this was not necessary.sdcardioimprovementscmd_nodata, which wasboolbut should have beenint.-MP_EIOinstead of-EIOseveral places. The value is the same.persistent_mountflag tosdcardio_sdcard_construct()to distinguish user-mounted SD cards from automounted SD card mounts that persist across VM's. This flag is used to implement the next item.lock_and_configure()inSDCard.c. Once it has been acquired, check whether the VM is still running and whether the mount is persistent before proceeding. If the mount is not persistent and the VM is no longer running, give up the lock.supervisor/shared/usb/usb_msc_flash.cfixesCIRCUITPY_SDCARD_USBinstead ofCIRCUITPY_SDCARDIO.#ifdef SDCARD_LUNinstead ofCIRCUITPY_SDCARD_USB.get_vfs()will now check if the LUN passed in is for a user-mounted SD card but the VM is no longer running, and will return NULL. This prevents USB MSC operations that are attempted to be initiated after the VM starts to shut down. However, there are still races that can happen and the other checks above avoid those races.Other
bool vm_is_running()routine, which istruewhen the VM has finished starting up and is set tofalsewhen it starts to shut down. This supports the "VM is running" checks mentioned above. The flag is set and cleared inmain.c.This is a draft to start with because I need to test the non-Espressif ports for SPI issues, especially with SD cards, and I can use the PR builds for that testing.