User Interface¶
This page outlines the low-level mechanisms via which the AMI kernel driver exposes functionality to userspace code.
Refer to AVED Management Interface userguide (ami_tool) for details of how to use ami_tool (the command line interface tool).
Character Device Files¶
Each compatible PCI device gets its own character device file under /dev/amiX where ‘X’ may be an arbitrary number. There is one special device file at /dev/ami0 which is a global file created only once during driver initialisation. Currently, usage of this file is not supported and may be removed in the future.
Example cdev tree:
. /dev/
├── ami0
├── ami1
├── ami2
├── ami3
├── ami4
SYSFS¶
See sysfs - _The_ filesystem for exporting kernel objects — The Linux Kernel documentation
Where possible, device attributes are exposed via the sysfs subsystem. This is an easy-to-use mechanism that maps driver attributes to objects which look and behave like standard Linux files. These can be opened, read, and (depending on permissions) written to.
When a user reads or writes to a sysfs node, a callback is triggered in the driver code. A sysfs tree is created automatically for each PCI device with some standard attributes. This is located at a path that looks like /sys/devices/pci0000:c0/0000:c0:01.1/0000:c1:00.0.
The domain (0000) and device (c1:00.0) may be different depending on your setup. Note that the sysfs tree may also be accessed at /sys/class/hwmon/hwmonX/device or /sys/bus/pci/devices/0000:c1:00.0; this may be more useful, especially if you refer to the ami_tool overview command.
Example sysfs tree (standard PCI attributes have been stripped):
. /sys/class/hwmon/hwmon3/device
├── logic_uuid
├── hwmon
│ └── hwmon3
│ ├── curr1_average
│ ├── curr1_input
│ ├── curr1_label
│ ├── curr1_max
│ ├── curr1_status
│ ├── curr2_average
│ ├── curr2_input
│ ├── curr2_label
│ ├── curr2_max
│ ├── curr2_status
│ ├── curr3_average
│ ├── curr3_input
│ ├── curr3_label
│ ├── curr3_max
│ ├── curr3_status
│ ├── device -> ../../../0000:c1:00.0
│ ├── in0_average
│ ├── in0_input
│ ├── in0_label
│ ├── in0_max
│ ├── in0_status
│ ├── in1_average
│ ├── in1_input
│ ├── in1_label
│ ├── in1_max
│ ├── in1_status
│ ├── in2_average
│ ├── in2_input
│ ├── in2_label
│ ├── in2_max
│ ├── in2_status
│ ├── name
│ ├── power
│ │ ├── async
│ │ ├── autosuspend_delay_ms
│ │ ├── control
│ │ ├── runtime_active_kids
│ │ ├── runtime_active_time
│ │ ├── runtime_enabled
│ │ ├── runtime_status
│ │ ├── runtime_suspended_time
│ │ └── runtime_usage
│ ├── power1_average
│ ├── power1_input
│ ├── power1_label
│ ├── power1_max
│ ├── power1_status
│ ├── subsystem -> ../../../../../../class/hwmon
│ ├── temp1_input
│ ├── temp1_label
│ ├── temp1_max
│ ├── temp1_status
│ ├── temp2_input
│ ├── temp2_label
│ ├── temp2_max
│ ├── temp2_status
│ ├── temp3_input
│ ├── temp3_label
│ ├── temp3_max
│ ├── temp3_status
│ ├── uevent
│ └── update_interval
Driver Attributes¶
Typically, SYSFS is used to expose device attributes, however, the driver itself may also expose some of its own global attributes. These can be located at /sys/bus/pci/drivers/ami. Currently, the following attributes are supported:
devices - when read, returns a map of all PCI devices registered with the driver in the format “<BDF> <cdev_num> <hwmon_num>”. This map can be used to determine where to look for the device you are interested in. For example, the map “c1:00.0 3 4” means that the device with BDF c1:00.0 has a character device file at /dev/ami3 and a hwmon tree at /sys/class/hwmon/hwmon4. A hwmon number value of -1 means that the device does not support the functionality. All devices will have a vaild character device, however. The first line read from the ‘devices’ file is a number representing the total number of devices attached to the driver.
version - when read, returns the current driver version in the format “MAJOR.MINOR.PATCH +COMMITS *STATUS”.
HWMON¶
See The Linux Hardware Monitoring kernel API — The Linux Kernel documentation
HWMON builds on the sysfs subsystem to provide sensor monitoring. This creates an attribute tree at /sys/class/hwmon/hwmonX.
For an example of the HWMON interface see the section above. For all intents and purposes, hwmon behaves exactly the same as sysfs.
IOCTL¶
IOCTL provides a way to perform arbitrary actions on character device files. An IOCTL is uniquely defined by a magic number and is executed with the ioctl() call. Each IOCTL can be thought of as a unique (and undocumented) system call which can take any arbitrary argument and copy memory between kernel/user space.
These are used sparingly and only when no other solution exists. The below table defines the IOCTL calls supported by the AMI driver.
#define AMI_IOC_MAGIC ‘a’
IOCTL | Definition | Input | Output | Requires Elevated Permissions | Superuser Only | Required Device State |
---|---|---|---|---|---|---|
AMI_IOC_DOWNLOAD_PDI | _IOW(AMI_IOC_MAGIC, 0, struct ami_ioc_data_payload*) | struct ami_ioc_data_payload* populated with the PDI image data | N/A | Yes | No | READY, MISSING_INFO, or COMPAT |
AMI_IOC_READ_BAR | _IOWR(AMI_IOC_MAGIC, 1, struct ami_ioc_bar_data*) | struct ami_ioc_bar_data* with attributes appropriately set | Data will be copied to buffer at the given address | Yes | No | Any state except INIT and SHUTDOWN |
AMI_IOC_WRITE_BAR | _IOW(AMI_IOC_MAGIC, 2, struct ami_ioc_bar_data*) | struct ami_ioc_bar_data* with attributes appropriately set - buffer at given address must be populated with data to write | N/A | Yes | No | Any state except INIT and SHUTDOWN |
AMI_IOC_GET_SENSOR_VALUE | _IOWR(AMI_IOC_MAGIC, 3, struct ami_ioc_sensor_value*) | struct ami_ioc_sensor_value* with "hwmon_channel" and "sensor_type" set appropriately | "val", "status", and "fresh" attributes of the given struct will be populated | No | No | READY or MISSING_INFO |
AMI_IOC_DEVICE_BOOT | _IOW(AMI_IOC_MAGIC, 4, struct ami_ioc_data_payload*) | struct ami_ioc_data_payload* with "partition" field set | N/A | Yes | No | READY, MISSING_INFO, or COMPAT |
AMI_IOC_COPY_PARTITION | _IOW(AMI_IOC_MAGIC, 5, struct ami_ioc_data_payload*) | struct ami_ioc_data_payload* with "src" and "dest" fields set | N/A | Yes | No | READY or MISSING_INFO |
AMI_IOC_SET_SENSOR_REFRESH | _IOW(AMI_IOC_MAGIC, 6, uint16_t) | new sensor refresh specified | N/A | No | No | READY or MISSING_INFO |
AMI_IOC_GET_FPT_HDR | _IOR(AMI_IOC_MAGIC, 7, struct ami_ioc_fpt_hdr_value*) | struct ami_ioc_fpt_hdr_value* | Provided struct is populated | No | No | READY or MISSING_INFO |
AMI_IOC_GET_FPT_PARTITION | _IOWR(AMI_IOC_MAGIC, 8, struct ami_ioc_fpt_partition_value*) | struct ami_ioc_fpt_partition_value* with "partition" field set | Remaining fields in provided struct are populated | No | No | READY or MISSING_INFO |
AMI_IOC_READ_EEPROM | _IOWR(AMI_IOC_MAGIC, 9, struct ami_ioc_eeprom_payload*) | struct ami_ioc_eeprom_data* with "len", "addr", and "offset" fields set | Data read from EEPROM | No | No | READY or MISSING_INFO |
AMI_IOC_WRITE_EEPROM | _IOW(AMI_IOC_MAGIC, 10, struct ami_ioc_eeprom_payload*) | struct ami_ioc_eeprom_data* with "len", "addr", and "offset" fields set | N/A | No | No | READY or MISSING_INFO |
AMI_IOC_APP_SETUP | _IOW(AMI_IOC_MAGIC, 11, enum ami_ioc_app_setup) | enum ami_ioc_app_setup | N/A | No | No | Any state except INIT and SHUTDOWN |
AMI_IOC_READ_MODULE | _IOW(AMI_IOC_MAGIC, 12, struct ami_ioc_module_payload*) | struct ami_ioc_module_payload* with all fields set | Data read from module | No | No | READY or MISSING_INFO |
AMI_IOC_WRITE_MODULE | _IOW(AMI_IOC_MAGIC, 13, struct ami_ioc_module_payload*) | struct ami_ioc_module_payload* with all fields set | N/A | No | No | READY or MISSING_INFO |
AMI_IOC_DEBUG_VERBOSITY | _IOW(AMI_IOC_MAGIC, 14, uint8_t) | The debug level to set | N/A | No | No | READY or MISSING_INFO |
Page Revision: v. 20