Commit 4a0ce776 authored by Tomer Tayar's avatar Tomer Tayar Committed by Oded Gabbay
Browse files

habanalabs: Allow accessing host mapped addresses via debugfs



Allows using the addr/data32 debugfs nodes to access a device VA of a
host mapped memory when the IOMMU is disabled.

Due to the possible large amount of a user host mapped memory, the
driver doesn't maintain a database with the host addresses per device VA.
When the IOMMU is disabled, this missing info is being overcome by
simply using phys_to_virt(). However, this is not useful when the IOMMU
is enabled, and thus the enforced limitation.

Signed-off-by: default avatarTomer Tayar <ttayar@habana.ai>
Reviewed-by: default avatarOded Gabbay <oded.gabbay@gmail.com>
Signed-off-by: default avatarOded Gabbay <oded.gabbay@gmail.com>
parent 747bf88c
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -3,7 +3,10 @@ Date: Jan 2019
KernelVersion:  5.1
Contact:        oded.gabbay@gmail.com
Description:    Sets the device address to be used for read or write through
                PCI bar. The acceptable value is a string that starts with "0x"
                PCI bar, or the device VA of a host mapped memory to be read or
                written directly from the host. The latter option is allowed
                only when the IOMMU is disabled.
                The acceptable value is a string that starts with "0x"

What:           /sys/kernel/debug/habanalabs/hl<n>/command_buffers
Date:           Jan 2019
@@ -33,10 +36,12 @@ Contact: oded.gabbay@gmail.com
Description:    Allows the root user to read or write directly through the
                device's PCI bar. Writing to this file generates a write
                transaction while reading from the file generates a read
                transcation. This custom interface is needed (instead of using
                transaction. This custom interface is needed (instead of using
                the generic Linux user-space PCI mapping) because the DDR bar
                is very small compared to the DDR memory and only the driver can
                move the bar before and after the transaction
                move the bar before and after the transaction.
                If the IOMMU is disabled, it also allows the root user to read
                or write from the host a device VA of a host mapped memory

What:           /sys/kernel/debug/habanalabs/hl<n>/device
Date:           Jan 2019
+23 −12
Original line number Diff line number Diff line
@@ -500,6 +500,25 @@ err:
	return -EINVAL;
}

static bool hl_is_device_va(struct hl_device *hdev, u64 addr)
{
	struct asic_fixed_properties *prop = &hdev->asic_prop;

	if (!hdev->mmu_enable)
		goto out;

	if (hdev->dram_supports_virtual_memory &&
			addr >= prop->va_space_dram_start_address &&
			addr < prop->va_space_dram_end_address)
		return true;

	if (addr >= prop->va_space_host_start_address &&
			addr < prop->va_space_host_end_address)
		return true;
out:
	return false;
}

static int device_va_to_pa(struct hl_device *hdev, u64 virt_addr,
				u64 *phys_addr)
{
@@ -573,7 +592,6 @@ static ssize_t hl_data_read32(struct file *f, char __user *buf,
{
	struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
	struct hl_device *hdev = entry->hdev;
	struct asic_fixed_properties *prop = &hdev->asic_prop;
	char tmp_buf[32];
	u64 addr = entry->addr;
	u32 val;
@@ -582,11 +600,8 @@ static ssize_t hl_data_read32(struct file *f, char __user *buf,
	if (*ppos)
		return 0;

	if (addr >= prop->va_space_dram_start_address &&
			addr < prop->va_space_dram_end_address &&
			hdev->mmu_enable &&
			hdev->dram_supports_virtual_memory) {
		rc = device_va_to_pa(hdev, entry->addr, &addr);
	if (hl_is_device_va(hdev, addr)) {
		rc = device_va_to_pa(hdev, addr, &addr);
		if (rc)
			return rc;
	}
@@ -607,7 +622,6 @@ static ssize_t hl_data_write32(struct file *f, const char __user *buf,
{
	struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
	struct hl_device *hdev = entry->hdev;
	struct asic_fixed_properties *prop = &hdev->asic_prop;
	u64 addr = entry->addr;
	u32 value;
	ssize_t rc;
@@ -616,11 +630,8 @@ static ssize_t hl_data_write32(struct file *f, const char __user *buf,
	if (rc)
		return rc;

	if (addr >= prop->va_space_dram_start_address &&
			addr < prop->va_space_dram_end_address &&
			hdev->mmu_enable &&
			hdev->dram_supports_virtual_memory) {
		rc = device_va_to_pa(hdev, entry->addr, &addr);
	if (hl_is_device_va(hdev, addr)) {
		rc = device_va_to_pa(hdev, addr, &addr);
		if (rc)
			return rc;
	}
+15 −4
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/genalloc.h>
#include <linux/hwmon.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/iommu.h>

/*
 * GOYA security scheme:
@@ -3941,10 +3942,11 @@ static void goya_clear_sm_regs(struct hl_device *hdev)
}

/*
 * goya_debugfs_read32 - read a 32bit value from a given device address
 * goya_debugfs_read32 - read a 32bit value from a given device or a host mapped
 *                       address.
 *
 * @hdev:	pointer to hl_device structure
 * @addr:	address in device
 * @addr:	device or host mapped address
 * @val:	returned value
 *
 * In case of DDR address that is not mapped into the default aperture that
@@ -3985,6 +3987,10 @@ static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val)
		}
		if (ddr_bar_addr == U64_MAX)
			rc = -EIO;

	} else if (addr >= HOST_PHYS_BASE && !iommu_present(&pci_bus_type)) {
		*val = *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE);

	} else {
		rc = -EFAULT;
	}
@@ -3993,10 +3999,11 @@ static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val)
}

/*
 * goya_debugfs_write32 - write a 32bit value to a given device address
 * goya_debugfs_write32 - write a 32bit value to a given device or a host mapped
 *                        address.
 *
 * @hdev:	pointer to hl_device structure
 * @addr:	address in device
 * @addr:	device or host mapped address
 * @val:	returned value
 *
 * In case of DDR address that is not mapped into the default aperture that
@@ -4037,6 +4044,10 @@ static int goya_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val)
		}
		if (ddr_bar_addr == U64_MAX)
			rc = -EIO;

	} else if (addr >= HOST_PHYS_BASE && !iommu_present(&pci_bus_type)) {
		*(u32 *) phys_to_virt(addr - HOST_PHYS_BASE) = val;

	} else {
		rc = -EFAULT;
	}