mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-16 10:16:53 -05:00
accel/habanalabs: add debugfs interface for HLDIO testing
Add debugfs files for NVMe Direct I/O (HLDIO) functionality.
This interface allows userspace access to direct SSD ↔ device transfers
through debugfs nodes.
Four debugfs files are created under /sys/kernel/debug/habanalabs/hlN/:
- dio_ssd2hl : trigger SSD-to-device transfers
- dio_hl2ssd : trigger device-to-SSD transfers
(placeholder, not yet implemented)
- dio_stats : show transfer statistics
- dio_reset : reset statistics counters
Usage examples:
# Perform SSD → device transfer
echo "fd=3 va=0x10000 off=0 len=4096" > \
/sys/kernel/debug/habanalabs/hl0/dio_ssd2hl
# View statistics
cat /sys/kernel/debug/habanalabs/hl0/dio_stats
# Reset counters
echo 1 > /sys/kernel/debug/habanalabs/hl0/dio_reset
This interface provides access to HLDIO functionality for validation
and diagnostics.
Signed-off-by: Konstantin Sinyuk <konstantin.sinyuk@intel.com>
Reviewed-by: Farah Kassabri <farah.kassabri@intel.com>
Reviewed-by: Koby Elbaz <koby.elbaz@intel.com>
Signed-off-by: Koby Elbaz <koby.elbaz@intel.com>
This commit is contained in:
committed by
Koby Elbaz
parent
8cbacc9a27
commit
eeb38d0e91
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "habanalabs.h"
|
||||
#include "hldio.h"
|
||||
#include "../include/hw_ip/mmu/mmu_general.h"
|
||||
|
||||
#include <linux/pci.h>
|
||||
@@ -602,6 +603,198 @@ static int engines_show(struct seq_file *s, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HL_HLDIO
|
||||
/* DIO debugfs functions following the standard pattern */
|
||||
static int dio_ssd2hl_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct hl_debugfs_entry *entry = s->private;
|
||||
struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
|
||||
struct hl_device *hdev = dev_entry->hdev;
|
||||
|
||||
if (!hdev->asic_prop.supports_nvme) {
|
||||
seq_puts(s, "NVMe Direct I/O not supported\\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seq_puts(s, "Usage: echo \"fd=N va=0xADDR off=N len=N\" > dio_ssd2hl\n");
|
||||
seq_printf(s, "Last transfer: %zu bytes\\n", dev_entry->dio_stats.last_len_read);
|
||||
seq_puts(s, "Note: All parameters must be page-aligned (4KB)\\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t dio_ssd2hl_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *f_pos)
|
||||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct hl_debugfs_entry *entry = s->private;
|
||||
struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
|
||||
struct hl_device *hdev = dev_entry->hdev;
|
||||
struct hl_ctx *ctx = hdev->kernel_ctx;
|
||||
char kbuf[128];
|
||||
u64 device_va = 0, off_bytes = 0, len_bytes = 0;
|
||||
u32 fd = 0;
|
||||
size_t len_read = 0;
|
||||
int rc, parsed;
|
||||
|
||||
if (!hdev->asic_prop.supports_nvme)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (count >= sizeof(kbuf))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(kbuf, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
kbuf[count] = 0;
|
||||
|
||||
/* Parse: fd=N va=0xADDR off=N len=N */
|
||||
parsed = sscanf(kbuf, "fd=%u va=0x%llx off=%llu len=%llu",
|
||||
&fd, &device_va, &off_bytes, &len_bytes);
|
||||
if (parsed != 4) {
|
||||
dev_err(hdev->dev, "Invalid format. Expected: fd=N va=0xADDR off=N len=N\\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Validate file descriptor */
|
||||
if (fd == 0) {
|
||||
dev_err(hdev->dev, "Invalid file descriptor: %u\\n", fd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Validate alignment requirements */
|
||||
if (!IS_ALIGNED(device_va, PAGE_SIZE) ||
|
||||
!IS_ALIGNED(off_bytes, PAGE_SIZE) ||
|
||||
!IS_ALIGNED(len_bytes, PAGE_SIZE)) {
|
||||
dev_err(hdev->dev,
|
||||
"All parameters must be page-aligned (4KB)\\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Validate transfer size */
|
||||
if (len_bytes == 0 || len_bytes > SZ_1G) {
|
||||
dev_err(hdev->dev, "Invalid length: %llu (max 1GB)\\n",
|
||||
len_bytes);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(hdev->dev, "DIO SSD2HL: fd=%u va=0x%llx off=%llu len=%llu\\n",
|
||||
fd, device_va, off_bytes, len_bytes);
|
||||
|
||||
rc = hl_dio_ssd2hl(hdev, ctx, fd, device_va, off_bytes, len_bytes, &len_read);
|
||||
if (rc < 0) {
|
||||
dev_entry->dio_stats.failed_ops++;
|
||||
dev_err(hdev->dev, "SSD2HL operation failed: %d\\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Update statistics */
|
||||
dev_entry->dio_stats.total_ops++;
|
||||
dev_entry->dio_stats.successful_ops++;
|
||||
dev_entry->dio_stats.bytes_transferred += len_read;
|
||||
dev_entry->dio_stats.last_len_read = len_read;
|
||||
|
||||
dev_dbg(hdev->dev, "DIO SSD2HL completed: %zu bytes transferred\\n", len_read);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int dio_hl2ssd_show(struct seq_file *s, void *data)
|
||||
{
|
||||
seq_puts(s, "HL2SSD (device-to-SSD) transfers not implemented\\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t dio_hl2ssd_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *f_pos)
|
||||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct hl_debugfs_entry *entry = s->private;
|
||||
struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
|
||||
struct hl_device *hdev = dev_entry->hdev;
|
||||
|
||||
if (!hdev->asic_prop.supports_nvme)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
dev_dbg(hdev->dev, "HL2SSD operation not implemented\\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int dio_stats_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct hl_debugfs_entry *entry = s->private;
|
||||
struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
|
||||
struct hl_device *hdev = dev_entry->hdev;
|
||||
struct hl_dio_stats *stats = &dev_entry->dio_stats;
|
||||
u64 avg_bytes_per_op = 0, success_rate = 0;
|
||||
|
||||
if (!hdev->asic_prop.supports_nvme) {
|
||||
seq_puts(s, "NVMe Direct I/O not supported\\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stats->successful_ops > 0)
|
||||
avg_bytes_per_op = stats->bytes_transferred / stats->successful_ops;
|
||||
|
||||
if (stats->total_ops > 0)
|
||||
success_rate = (stats->successful_ops * 100) / stats->total_ops;
|
||||
|
||||
seq_puts(s, "=== Habanalabs Direct I/O Statistics ===\\n");
|
||||
seq_printf(s, "Total operations: %llu\\n", stats->total_ops);
|
||||
seq_printf(s, "Successful ops: %llu\\n", stats->successful_ops);
|
||||
seq_printf(s, "Failed ops: %llu\\n", stats->failed_ops);
|
||||
seq_printf(s, "Success rate: %llu%%\\n", success_rate);
|
||||
seq_printf(s, "Total bytes: %llu\\n", stats->bytes_transferred);
|
||||
seq_printf(s, "Avg bytes per op: %llu\\n", avg_bytes_per_op);
|
||||
seq_printf(s, "Last transfer: %zu bytes\\n", stats->last_len_read);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dio_reset_show(struct seq_file *s, void *data)
|
||||
{
|
||||
seq_puts(s, "Write '1' to reset DIO statistics\\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t dio_reset_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *f_pos)
|
||||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct hl_debugfs_entry *entry = s->private;
|
||||
struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
|
||||
struct hl_device *hdev = dev_entry->hdev;
|
||||
char kbuf[8];
|
||||
unsigned long val;
|
||||
int rc;
|
||||
|
||||
if (!hdev->asic_prop.supports_nvme)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (count >= sizeof(kbuf))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(kbuf, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
kbuf[count] = 0;
|
||||
|
||||
rc = kstrtoul(kbuf, 0, &val);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (val == 1) {
|
||||
memset(&dev_entry->dio_stats, 0, sizeof(dev_entry->dio_stats));
|
||||
dev_dbg(hdev->dev, "DIO statistics reset\\n");
|
||||
} else {
|
||||
dev_err(hdev->dev, "Write '1' to reset statistics\\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ssize_t hl_memory_scrub(struct file *f, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
@@ -1633,6 +1826,13 @@ static const struct hl_info_list hl_debugfs_list[] = {
|
||||
{"mmu", mmu_show, mmu_asid_va_write},
|
||||
{"mmu_error", mmu_ack_error, mmu_ack_error_value_write},
|
||||
{"engines", engines_show, NULL},
|
||||
#ifdef CONFIG_HL_HLDIO
|
||||
/* DIO entries - only created if NVMe is supported */
|
||||
{"dio_ssd2hl", dio_ssd2hl_show, dio_ssd2hl_write},
|
||||
{"dio_stats", dio_stats_show, NULL},
|
||||
{"dio_reset", dio_reset_show, dio_reset_write},
|
||||
{"dio_hl2ssd", dio_hl2ssd_show, dio_hl2ssd_write},
|
||||
#endif
|
||||
};
|
||||
|
||||
static int hl_debugfs_open(struct inode *inode, struct file *file)
|
||||
@@ -1831,6 +2031,11 @@ static void add_files_to_device(struct hl_device *hdev, struct hl_dbg_device_ent
|
||||
&hdev->asic_prop.server_type);
|
||||
|
||||
for (i = 0, entry = dev_entry->entry_arr ; i < count ; i++, entry++) {
|
||||
/* Skip DIO entries if NVMe is not supported */
|
||||
if (strncmp(hl_debugfs_list[i].name, "dio_", 4) == 0 &&
|
||||
!hdev->asic_prop.supports_nvme)
|
||||
continue;
|
||||
|
||||
debugfs_create_file(hl_debugfs_list[i].name,
|
||||
0644,
|
||||
root,
|
||||
@@ -1873,6 +2078,11 @@ int hl_debugfs_device_init(struct hl_device *hdev)
|
||||
spin_lock_init(&hdev->debugfs_cfg_accesses.lock);
|
||||
hdev->debugfs_cfg_accesses.head = 0; /* already zero by alloc but explicit init is fine */
|
||||
|
||||
#ifdef CONFIG_HL_HLDIO
|
||||
/* Initialize DIO statistics */
|
||||
memset(&dev_entry->dio_stats, 0, sizeof(dev_entry->dio_stats));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -2410,6 +2410,7 @@ struct hl_debugfs_entry {
|
||||
* @i2c_addr: generic u8 debugfs file for address value to use in i2c_data_read.
|
||||
* @i2c_reg: generic u8 debugfs file for register value to use in i2c_data_read.
|
||||
* @i2c_len: generic u8 debugfs file for length value to use in i2c_data_read.
|
||||
* @dio_stats: Direct I/O statistics
|
||||
*/
|
||||
struct hl_dbg_device_entry {
|
||||
struct dentry *root;
|
||||
@@ -2441,6 +2442,9 @@ struct hl_dbg_device_entry {
|
||||
u8 i2c_addr;
|
||||
u8 i2c_reg;
|
||||
u8 i2c_len;
|
||||
#ifdef CONFIG_HL_HLDIO
|
||||
struct hl_dio_stats dio_stats;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user