That's what this class really is; in fact that's what the first line of
the comment says it is.
This commit does not rename the main files, since those will contain
other time-related classes in a little bit.
Add a helper initialize_interrupt_queue() helper to enable_irq instead
of doing it as part of its object construction as it can fail. This is
similar to how AHCI initializes its interrupt as well.
NVMe{Poll|Interrupt}Queue don't have a try_create() method. Add one to
keep it consistent with how we create objects. Also this commit is in
preparation to moving any initialization related code out of the
constructor.
Remove the hardcoded "AHCI Scattered DMA" for region name as it is a
part of a common API. Add region_name parameter to the try_create API
so that this API can be used by other drivers with the correct Memory
region name.
This removes the TODO from the try_create API to return ErrorOr. This
is also a preparation patch to move the init code in the constructor
that can fail to this try_create function.
This is in preparation for adding MSI(x) support to the NVMe device.
NVMeInterruptQueue needs access to the PCI device to deal with MSI(x)
interrupts. It is ok to pass the NVMeController as a reference to the
NVMeQueue as NVMeController is the one that owns the NVMeQueue.
This is very similar to how AHCIController passes its reference to its
interrupt handler.
Add an explicit QueueType enum which could be used to create a poll or
an interrupt queue. This is better than passing an Optional<irq>.
This refactoring is in preparation for adding MSIx support to NVMe.
This should not affect boot times on qemu, as that does not use
dynamic transfer delays in its adma code path.
On real hardware this could potentially double the data throughput,
decreasing load times.
Currently we do not use interrupts for the SD driver, yet we
had enabled the signaling of all of them.
Since we were never acknowledging them, we were getting spammed by
unnecessary interrupts, causing the system to slow down to a crawl.
This commit makes the system boot in less than 1 minute with PIO,
compared to the old 30+ minute boot.
To do this we also need to get rid of LockRefPtrs in the USB code as
well.
Most of the SysFS nodes are statically generated during boot and are not
mutated afterwards.
The same goes for general device code - once we generate the appropriate
SysFS nodes, we almost never mutate the node pointers afterwards, making
locking unnecessary.
This is done by 2 ways which both fit very well together:
- We stop use LockRefPtrs. We also don't allow expansion of the
m_channels member, by setting it to be a fixed Array of 2
IDEChannels.
- More error propagation through the code, in the construction point of
IDEChannel(s). This means that in the future we could technically do
something meaningful with OOM conditions when initializing an IDE
controller.
These were easy to pick-up as these pointers are assigned during the
construction point and are never changed afterwards.
This small change to these pointers will ensure that our code will not
accidentally assign these pointers with a new object which is always a
kind of bug we will want to prevent.
The current way we handle sync commands is very ugly and depends on lot
of preconditions. Now that we have an end_io handler for a request, we
can use WaitQueue to do sync commands more elegantly.
This does depend on block layer sending one request at a time but this
change is a step forward towards better IO handling.
There was a private variable named m_current_request which was used to
track a single request at a time. This guarantee is given by the block
layer where we wait on each IO. This design will break down in the
driver once the block layer removes that constraint.
Redesign the IO handling in a completely asynchronous way by maintaining
requests up to queue depth. NVMeIO struct is introduced to track an IO
submitted along with other information such whether the IO is still
being processed and an endio callback which will be called during the
end of a request.
A hashmap private variable is created which will key based on the
command id of a request with a value of NVMeIO. endio handler will come
in handy if we are doing a sync request and we want to wake up the wait
queue during the end.
This change also simplified the code by removing some special condition
in submit_sqe function, etc that were marked as FIXME for a long time.
Using sq_tail as cid makes an inherent assumption that we send only
one IO at a time. Use an atomic variable instead for command id of a
submission queue entry.
As sq_tail is not used as cid anymore, remove m_prev_sq_tail which used
to hold the last used sq_tail value.
There was only one permanent storage location for these: as a member
in the Mount class.
That member is never modified after Mount initialization, so we don't
need to worry about races there.
This reverts commit 187723776a.
This was reverted because it was needed until the aarch64 port
got an SD card driver
Co-authored-by: Ollrogge <nils-ollrogge@outlook.de>
Before, the mapping of our HBA region would be done in the constructor.
Since this can fail, I moved it into initialize().
Additionally, we now use the TypedMapping helper for mapping the HBA
instead of doing it manually. This actually uncovered a bug where we
would ignore any possible offset into the page we were mapping, which
caused us to miss the mapped registers entirely.
Use the same pattern for Ramdisk similar to other storage devices during
device initialization. This will propagate errors if the Ramdisk fails
to initialize.
Storage controllers are initialized during init and are never modified.
NonnullRefPtr can be safely used instead of the NonnullLockRefPtr. This
also fixes one of the UB issue that was there when using an NVMe device
because of NonnullLockRefPtr.
We can add proper locking when we need to modify the storage controllers
after init.
The LUN.target_id parameter points to a NVMe Namespace which starts from
1 and not 0. Fix the document to reflect the same while addressing a
nvme device in the boot parameters
There's no plan to support ATAPI in the foreseeable future. ATAPI is
considered mostly as an extension to pass SCSI commands over ATA-link
compatible channel (which could be a physical SATA or PATA).
ATAPI is mostly used for controlling optical drives which are considered
obsolete in 2023, and require an entire SCSI abstraction layer we don't
exhibit with bypassing ioctls for sending specific SCSI commands in many
control-flow sequences for actions being taken for such hardware.
Therefore, let's make it clear we don't support ATAPI (SCSI over ATA)
unless someone picks it up and proves otherwise that this can be done
cleanly and also in a relevant way to our project.
This class had slightly confusing semantics and the added weirdness
doesn't seem worth it just so we can say "." instead of "->" when
iterating over a vector of NNRPs.
This patch replaces NonnullRefPtrVector<T> with Vector<NNRP<T>>.
This reverts commit 4e0f85432a as the
ramdisk code is useful for the bring-up of the aarch64 port. Once the
kernel supports better ram-based filesystems, this code will be removed
again.
There are now 2 separate classes for almost the same object type:
- EnumerableDeviceIdentifier, which is used in the enumeration code for
all PCI host controller classes. This is allowed to be moved and
copied, as it doesn't support ref-counting.
- DeviceIdentifier, which inherits from EnumerableDeviceIdentifier. This
class uses ref-counting, and is not allowed to be copied. It has a
spinlock member in its structure to allow safely executing complicated
IO sequences on a PCI device and its space configuration.
There's a static method that allows a quick conversion from
EnumerableDeviceIdentifier to DeviceIdentifier while creating a
NonnullRefPtr out of it.
The reason for doing this is for the sake of integrity and reliablity of
the system in 2 places:
- Ensure that "complicated" tasks that rely on manipulating PCI device
registers are done in a safe manner. For example, determining a PCI
BAR space size requires multiple read and writes to the same register,
and if another CPU tries to do something else with our selected
register, then the result will be a catastrophe.
- Allow the PCI API to have a united form around a shared object which
actually holds much more data than the PCI::Address structure. This is
fundamental if we want to do certain types of optimizations, and be
able to support more features of the PCI bus in the foreseeable
future.
This patch already has several implications:
- All PCI::Device(s) hold a reference to a DeviceIdentifier structure
being given originally from the PCI::Access singleton. This means that
all instances of DeviceIdentifier structures are located in one place,
and all references are pointing to that location. This ensures that
locking the operation spinlock will take effect in all the appropriate
places.
- We no longer support adding PCI host controllers and then immediately
allow for enumerating it with a lambda function. It was found that
this method is extremely broken and too much complicated to work
reliably with the new paradigm being introduced in this patch. This
means that for Volume Management Devices (Intel VMD devices), we
simply first enumerate the PCI bus for such devices in the storage
code, and if we find a device, we attach it in the PCI::Access method
which will scan for devices behind that bridge and will add new
DeviceIdentifier(s) objects to its internal Vector. Afterwards, we
just continue as usual with scanning for actual storage controllers,
so we will find a corresponding NVMe controllers if there were any
behind that VMD bridge.
This header has always been fundamentally a Kernel API file. Move it
where it belongs. Include it directly in Kernel files, and make
Userland applications include it via sys/ioctl.h rather than directly.