GIET-VM / HBA Driver
The hba_driver.c and hba_driver.h files define the HBA driver.
The vci_multi_ahci component is a multi-channels, block oriented, external mass storage controller respecting the AHCI standard. Each channel define an independant physical disk, but this driver supports only one channel, because the GIET-VM uses only one physical disk.
The Command List can contain up to 32 independant commands, posted by different user tasks. These independant transfers are handled by the HBA device, not necessarily in the same order as they have been written in the command list. The command list being a shared structure, the driver must use a lock to get a slot in the command list (except in boot mode when only one processor uses the HBA component). This slot is then allocated to the task until the command is completed.
This driver implements two operating mode:
- In synchronous mode, the calling task uses a polling strategy on the HBA_PXCI register to detect the command completion (busy waiting). It does not use interrupt. This mode is used by the boot code to load the map.bin file into memory (before MMU activation), or to load the .elf files (after MMU activation).
- In descheduling mode, the calling task is descheduled, and the calling task global index is saved in the _hba_gtid[32] array, indexed by the command index. The task must be reactivated when the command is completed. This mode is used, to handle the user system calls.
As several user tasks can concurrently register commands in the command list, and there is only one HBA interrupt per channel, this interrupt is not linked to a specific command. In descheduling mode, the HBA IRQ is a "global" IRQ that is statically routed to processor P[x_io,y_io,0]. The associated global HBA_ISR send a WAKUP WTI to all tasks that have a completed command. In order to know which commands expect completion, the HBA_ISR uses the _hba_active_cmd table which indicates currently active commands.
The SEG_IOC_BASE address must be defined in the hard_config.h file.
The addressable registers map is defined here.
Software data structures
The HBA component support split memory buffers (several physical buffers for one single command), but this driver supports only one single buffer commands, because a contiguous buffer in virtual space is also contiguous in physical space. This is a nice property of the the static memory allocation policy implemented by the GIET_VM.
There exist 32 command tables associated to the 32 commands in the command list, and each command table occupies only 32 bytes.
Command List
The command List is an array of 32 Command Descriptors. Each Command Descriptor occupies 16 bytes, and is aligned on a 16 bytes boundary.
typedef struct hba_cmd_desc_s // size = 16 bytes { unsigned char flag[2]; // W in bit 6 of flag[0] unsigned char prdtl[2]; // Number of buffers unsigned int prdbc; // Number of bytes actually transfered unsigned int ctba; // Command Table base address 32 LSB bits unsigned int ctbau; // Command Table base address 32 MSB bits } hba_cmd_desc_t;
Command Table
The GIET_VM define an array of 32 Command Tables. A Command Table contains one header, and one Buffer Descriptor. Each Command Table occupies 32 bytes, and is aligned on a 32 bytes boundary.
typedef struct hba_cmd_header_s // size = 16 bytes { unsigned int res0; // reserved unsigned char lba0; // LBA 7:0 unsigned char lba1; // LBA 15:8 unsigned char lba2; // LBA 23:16 unsigned char res1; // reserved unsigned char lba3; // LBA 31:24 unsigned char lba4; // LBA 39:32 unsigned char lba5; // LBA 47:40 unsigned char res2; // reserved unsigned int res3; // reserved } hba_cmd_header_t; typedef struct hba_cmd_buffer_s // size = 16 bytes { unsigned int dba; // Buffer base address 32 LSB bits unsigned int dbau; // Buffer base address 32 MSB bits unsigned int res0; // reserved unsigned int dbc; // Buffer byte count } hba_cmd_buffer_t; typedef struct hba_cmd_table_s // size = 32 bytes { hba_cmd_header_t header; // contains LBA hba_cmd_buffer_t buffer; // only one physical buffer } hba_cmd_table_t;
Access Functions
unsigned int _hba_init ( )
This function checks the block size and desactivates interrupts. It initializes the HBA hardware registers, the Command List and the allocator lock (except in boot mode). Return 0 for success, > 0 if error.
unsigned int _hba_access( unsigned int use_irq , unsigned int to_mem , unsigned int lba , unsigned long long paddr, unsigned int count )
This function gets a command index and then registers the command in both the command list and the command table. It updates the HBA_PXCI register and the hba_active_cmd in descheduling mode. At the end the command slot is released.
- use_irq: Boolean => request to use the descheduling mode if non zero
- to_mem : Boolean => to memory transfer if non zero
- lba : logic bloc address on device
- paddr : memory buffer physical base address
- count : number of blocs
Returns 0 if success, > 0 if error.
void _hba_isr( unsigned int irq_type , unsigned int irq_id , unsigned int channel )
This Interrupt Service routine is only used in the descheduling mode. After a reset of the HBA_PXIS register, it analyses the _hba_active_cmd table and the HBA_PXCI register. For all active and completed commands, it activates the task waiting completion of this command.
- irq_type : HWI / PTI / WTI
- irq-id : index returned by XCU
- channel : unused (only one HBA channel is supported).