Skip to content

Commit eeb38d0

Browse files
ksinyukKobyElbaz
authored andcommitted
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 <[email protected]> Reviewed-by: Farah Kassabri <[email protected]> Reviewed-by: Koby Elbaz <[email protected]> Signed-off-by: Koby Elbaz <[email protected]>
1 parent 8cbacc9 commit eeb38d0

File tree

2 files changed

+214
-0
lines changed

2 files changed

+214
-0
lines changed

drivers/accel/habanalabs/common/debugfs.c

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
#include "habanalabs.h"
9+
#include "hldio.h"
910
#include "../include/hw_ip/mmu/mmu_general.h"
1011

1112
#include <linux/pci.h>
@@ -602,6 +603,198 @@ static int engines_show(struct seq_file *s, void *data)
602603
return 0;
603604
}
604605

606+
#ifdef CONFIG_HL_HLDIO
607+
/* DIO debugfs functions following the standard pattern */
608+
static int dio_ssd2hl_show(struct seq_file *s, void *data)
609+
{
610+
struct hl_debugfs_entry *entry = s->private;
611+
struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
612+
struct hl_device *hdev = dev_entry->hdev;
613+
614+
if (!hdev->asic_prop.supports_nvme) {
615+
seq_puts(s, "NVMe Direct I/O not supported\\n");
616+
return 0;
617+
}
618+
619+
seq_puts(s, "Usage: echo \"fd=N va=0xADDR off=N len=N\" > dio_ssd2hl\n");
620+
seq_printf(s, "Last transfer: %zu bytes\\n", dev_entry->dio_stats.last_len_read);
621+
seq_puts(s, "Note: All parameters must be page-aligned (4KB)\\n");
622+
623+
return 0;
624+
}
625+
626+
static ssize_t dio_ssd2hl_write(struct file *file, const char __user *buf,
627+
size_t count, loff_t *f_pos)
628+
{
629+
struct seq_file *s = file->private_data;
630+
struct hl_debugfs_entry *entry = s->private;
631+
struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
632+
struct hl_device *hdev = dev_entry->hdev;
633+
struct hl_ctx *ctx = hdev->kernel_ctx;
634+
char kbuf[128];
635+
u64 device_va = 0, off_bytes = 0, len_bytes = 0;
636+
u32 fd = 0;
637+
size_t len_read = 0;
638+
int rc, parsed;
639+
640+
if (!hdev->asic_prop.supports_nvme)
641+
return -EOPNOTSUPP;
642+
643+
if (count >= sizeof(kbuf))
644+
return -EINVAL;
645+
646+
if (copy_from_user(kbuf, buf, count))
647+
return -EFAULT;
648+
649+
kbuf[count] = 0;
650+
651+
/* Parse: fd=N va=0xADDR off=N len=N */
652+
parsed = sscanf(kbuf, "fd=%u va=0x%llx off=%llu len=%llu",
653+
&fd, &device_va, &off_bytes, &len_bytes);
654+
if (parsed != 4) {
655+
dev_err(hdev->dev, "Invalid format. Expected: fd=N va=0xADDR off=N len=N\\n");
656+
return -EINVAL;
657+
}
658+
659+
/* Validate file descriptor */
660+
if (fd == 0) {
661+
dev_err(hdev->dev, "Invalid file descriptor: %u\\n", fd);
662+
return -EINVAL;
663+
}
664+
665+
/* Validate alignment requirements */
666+
if (!IS_ALIGNED(device_va, PAGE_SIZE) ||
667+
!IS_ALIGNED(off_bytes, PAGE_SIZE) ||
668+
!IS_ALIGNED(len_bytes, PAGE_SIZE)) {
669+
dev_err(hdev->dev,
670+
"All parameters must be page-aligned (4KB)\\n");
671+
return -EINVAL;
672+
}
673+
674+
/* Validate transfer size */
675+
if (len_bytes == 0 || len_bytes > SZ_1G) {
676+
dev_err(hdev->dev, "Invalid length: %llu (max 1GB)\\n",
677+
len_bytes);
678+
return -EINVAL;
679+
}
680+
681+
dev_dbg(hdev->dev, "DIO SSD2HL: fd=%u va=0x%llx off=%llu len=%llu\\n",
682+
fd, device_va, off_bytes, len_bytes);
683+
684+
rc = hl_dio_ssd2hl(hdev, ctx, fd, device_va, off_bytes, len_bytes, &len_read);
685+
if (rc < 0) {
686+
dev_entry->dio_stats.failed_ops++;
687+
dev_err(hdev->dev, "SSD2HL operation failed: %d\\n", rc);
688+
return rc;
689+
}
690+
691+
/* Update statistics */
692+
dev_entry->dio_stats.total_ops++;
693+
dev_entry->dio_stats.successful_ops++;
694+
dev_entry->dio_stats.bytes_transferred += len_read;
695+
dev_entry->dio_stats.last_len_read = len_read;
696+
697+
dev_dbg(hdev->dev, "DIO SSD2HL completed: %zu bytes transferred\\n", len_read);
698+
699+
return count;
700+
}
701+
702+
static int dio_hl2ssd_show(struct seq_file *s, void *data)
703+
{
704+
seq_puts(s, "HL2SSD (device-to-SSD) transfers not implemented\\n");
705+
return 0;
706+
}
707+
708+
static ssize_t dio_hl2ssd_write(struct file *file, const char __user *buf,
709+
size_t count, loff_t *f_pos)
710+
{
711+
struct seq_file *s = file->private_data;
712+
struct hl_debugfs_entry *entry = s->private;
713+
struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
714+
struct hl_device *hdev = dev_entry->hdev;
715+
716+
if (!hdev->asic_prop.supports_nvme)
717+
return -EOPNOTSUPP;
718+
719+
dev_dbg(hdev->dev, "HL2SSD operation not implemented\\n");
720+
return -EOPNOTSUPP;
721+
}
722+
723+
static int dio_stats_show(struct seq_file *s, void *data)
724+
{
725+
struct hl_debugfs_entry *entry = s->private;
726+
struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
727+
struct hl_device *hdev = dev_entry->hdev;
728+
struct hl_dio_stats *stats = &dev_entry->dio_stats;
729+
u64 avg_bytes_per_op = 0, success_rate = 0;
730+
731+
if (!hdev->asic_prop.supports_nvme) {
732+
seq_puts(s, "NVMe Direct I/O not supported\\n");
733+
return 0;
734+
}
735+
736+
if (stats->successful_ops > 0)
737+
avg_bytes_per_op = stats->bytes_transferred / stats->successful_ops;
738+
739+
if (stats->total_ops > 0)
740+
success_rate = (stats->successful_ops * 100) / stats->total_ops;
741+
742+
seq_puts(s, "=== Habanalabs Direct I/O Statistics ===\\n");
743+
seq_printf(s, "Total operations: %llu\\n", stats->total_ops);
744+
seq_printf(s, "Successful ops: %llu\\n", stats->successful_ops);
745+
seq_printf(s, "Failed ops: %llu\\n", stats->failed_ops);
746+
seq_printf(s, "Success rate: %llu%%\\n", success_rate);
747+
seq_printf(s, "Total bytes: %llu\\n", stats->bytes_transferred);
748+
seq_printf(s, "Avg bytes per op: %llu\\n", avg_bytes_per_op);
749+
seq_printf(s, "Last transfer: %zu bytes\\n", stats->last_len_read);
750+
751+
return 0;
752+
}
753+
754+
static int dio_reset_show(struct seq_file *s, void *data)
755+
{
756+
seq_puts(s, "Write '1' to reset DIO statistics\\n");
757+
return 0;
758+
}
759+
760+
static ssize_t dio_reset_write(struct file *file, const char __user *buf,
761+
size_t count, loff_t *f_pos)
762+
{
763+
struct seq_file *s = file->private_data;
764+
struct hl_debugfs_entry *entry = s->private;
765+
struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
766+
struct hl_device *hdev = dev_entry->hdev;
767+
char kbuf[8];
768+
unsigned long val;
769+
int rc;
770+
771+
if (!hdev->asic_prop.supports_nvme)
772+
return -EOPNOTSUPP;
773+
774+
if (count >= sizeof(kbuf))
775+
return -EINVAL;
776+
777+
if (copy_from_user(kbuf, buf, count))
778+
return -EFAULT;
779+
780+
kbuf[count] = 0;
781+
782+
rc = kstrtoul(kbuf, 0, &val);
783+
if (rc)
784+
return rc;
785+
786+
if (val == 1) {
787+
memset(&dev_entry->dio_stats, 0, sizeof(dev_entry->dio_stats));
788+
dev_dbg(hdev->dev, "DIO statistics reset\\n");
789+
} else {
790+
dev_err(hdev->dev, "Write '1' to reset statistics\\n");
791+
return -EINVAL;
792+
}
793+
794+
return count;
795+
}
796+
#endif
797+
605798
static ssize_t hl_memory_scrub(struct file *f, const char __user *buf,
606799
size_t count, loff_t *ppos)
607800
{
@@ -1633,6 +1826,13 @@ static const struct hl_info_list hl_debugfs_list[] = {
16331826
{"mmu", mmu_show, mmu_asid_va_write},
16341827
{"mmu_error", mmu_ack_error, mmu_ack_error_value_write},
16351828
{"engines", engines_show, NULL},
1829+
#ifdef CONFIG_HL_HLDIO
1830+
/* DIO entries - only created if NVMe is supported */
1831+
{"dio_ssd2hl", dio_ssd2hl_show, dio_ssd2hl_write},
1832+
{"dio_stats", dio_stats_show, NULL},
1833+
{"dio_reset", dio_reset_show, dio_reset_write},
1834+
{"dio_hl2ssd", dio_hl2ssd_show, dio_hl2ssd_write},
1835+
#endif
16361836
};
16371837

16381838
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
18312031
&hdev->asic_prop.server_type);
18322032

18332033
for (i = 0, entry = dev_entry->entry_arr ; i < count ; i++, entry++) {
2034+
/* Skip DIO entries if NVMe is not supported */
2035+
if (strncmp(hl_debugfs_list[i].name, "dio_", 4) == 0 &&
2036+
!hdev->asic_prop.supports_nvme)
2037+
continue;
2038+
18342039
debugfs_create_file(hl_debugfs_list[i].name,
18352040
0644,
18362041
root,
@@ -1873,6 +2078,11 @@ int hl_debugfs_device_init(struct hl_device *hdev)
18732078
spin_lock_init(&hdev->debugfs_cfg_accesses.lock);
18742079
hdev->debugfs_cfg_accesses.head = 0; /* already zero by alloc but explicit init is fine */
18752080

2081+
#ifdef CONFIG_HL_HLDIO
2082+
/* Initialize DIO statistics */
2083+
memset(&dev_entry->dio_stats, 0, sizeof(dev_entry->dio_stats));
2084+
#endif
2085+
18762086
return 0;
18772087
}
18782088

drivers/accel/habanalabs/common/habanalabs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2410,6 +2410,7 @@ struct hl_debugfs_entry {
24102410
* @i2c_addr: generic u8 debugfs file for address value to use in i2c_data_read.
24112411
* @i2c_reg: generic u8 debugfs file for register value to use in i2c_data_read.
24122412
* @i2c_len: generic u8 debugfs file for length value to use in i2c_data_read.
2413+
* @dio_stats: Direct I/O statistics
24132414
*/
24142415
struct hl_dbg_device_entry {
24152416
struct dentry *root;
@@ -2441,6 +2442,9 @@ struct hl_dbg_device_entry {
24412442
u8 i2c_addr;
24422443
u8 i2c_reg;
24432444
u8 i2c_len;
2445+
#ifdef CONFIG_HL_HLDIO
2446+
struct hl_dio_stats dio_stats;
2447+
#endif
24442448
};
24452449

24462450
/**

0 commit comments

Comments
 (0)