Skip to content

Commit

Permalink
Merge tag 'misc-habanalabs-next-2019-04-19' of git://people.freedeskt…
Browse files Browse the repository at this point in the history
…op.org/~gabbayo/linux into char-misc-next

Oded writes:

This tag contains many changes for kernel 5.2.

The major changes are:
- Add a new IOCTL for debug, profiling and trace operations on the device.
  This will allow the user to perform profiling and debugging of the
  deep learning topologies that are executing on the ASIC.

- Add a shadow table for the ASIC's MMU page tables to avoid doing page
  table walks on the device's DRAM during map/unmap operations.

- re-factor of ASIC-dependent code to be common code for all ASICs

In addition, there are many small fixes and changes. The notable ones are:
- Allow accessing the DRAM using virtual address through the debugFS
  interface. Until now, only physical addresses were valid, but that is
  useless for debugging when working with MMU.

- Allow the user to modify the TPC clock relaxation value to better
  control TPC power consumption during topology execution.

- Allow the user to inquire about the device's status
  (operational/Malfunction/in-reset) in the INFO IOCTL.

- Improvements to the device's removal function, to prevent crash in case
  of force removal by the OS.

- Prevent PTE read/write during hard-reset. This will improve stability of
  the device during hard-reset.

* tag 'misc-habanalabs-next-2019-04-19' of git://people.freedesktop.org/~gabbayo/linux: (31 commits)
  habanalabs: prevent device PTE read/write during hard-reset
  habanalabs: improve IOCTLs behavior when disabled or reset
  habanalabs: all FD must be closed before removing device
  habanalabs: split mmu/no-mmu code paths in memory ioctl
  habanalabs: ASIC_AUTO_DETECT enum value is redundant
  habanalabs: refactoring in goya.c
  uapi/habanalabs: fix some comments in uapi file
  habanalabs: add goya implementation for debug configuration
  habanalabs: add new IOCTL for debug, tracing and profiling
  habanalabs: remove extra semicolon
  habanalabs: prevent CPU soft lockup on Palladium
  habanalabs: remove trailing blank line from EOF
  habanalabs: improve error messages
  habanalabs: add device status option to INFO IOCTL
  habanalabs: allow user to modify TPC clock relaxation value
  habanalabs: set new golden value to tpc clock relaxation
  habanalabs: never fail hard reset of device
  habanalabs: keep track of the device's dma mask
  habanalabs: add MMU shadow mapping
  habanalabs: Allow accessing DRAM virtual addresses via debugfs
  ...
  • Loading branch information
Greg Kroah-Hartman committed Apr 19, 2019
2 parents d358b17 + 9f201ab commit cef62a6
Show file tree
Hide file tree
Showing 120 changed files with 3,118 additions and 1,250 deletions.
2 changes: 1 addition & 1 deletion drivers/misc/habanalabs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ obj-m := habanalabs.o

habanalabs-y := habanalabs_drv.o device.o context.o asid.o habanalabs_ioctl.o \
command_buffer.o hw_queue.o irq.o sysfs.o hwmon.o memory.o \
command_submission.o mmu.o
command_submission.o mmu.o firmware_if.o pci.o

habanalabs-$(CONFIG_DEBUG_FS) += debugfs.o

Expand Down
7 changes: 7 additions & 0 deletions drivers/misc/habanalabs/command_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,13 @@ int hl_cb_ioctl(struct hl_fpriv *hpriv, void *data)
u64 handle;
int rc;

if (hl_device_disabled_or_in_reset(hdev)) {
dev_warn_ratelimited(hdev->dev,
"Device is %s. Can't execute CB IOCTL\n",
atomic_read(&hdev->in_reset) ? "in_reset" : "disabled");
return -EBUSY;
}

switch (args->in.op) {
case HL_CB_OP_CREATE:
rc = hl_cb_create(hdev, &hpriv->cb_mgr, args->in.cb_size,
Expand Down
5 changes: 3 additions & 2 deletions drivers/misc/habanalabs/command_submission.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,8 @@ static void cs_timedout(struct work_struct *work)
ctx_asid = cs->ctx->asid;

/* TODO: add information about last signaled seq and last emitted seq */
dev_err(hdev->dev, "CS %d.%llu got stuck!\n", ctx_asid, cs->sequence);
dev_err(hdev->dev, "User %d command submission %llu got stuck!\n",
ctx_asid, cs->sequence);

cs_put(cs);

Expand Down Expand Up @@ -604,7 +605,7 @@ int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data)
bool need_soft_reset = false;

if (hl_device_disabled_or_in_reset(hdev)) {
dev_warn(hdev->dev,
dev_warn_ratelimited(hdev->dev,
"Device is %s. Can't submit new CS\n",
atomic_read(&hdev->in_reset) ? "in_reset" : "disabled");
rc = -EBUSY;
Expand Down
96 changes: 91 additions & 5 deletions drivers/misc/habanalabs/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -505,22 +505,97 @@ static ssize_t mmu_write(struct file *file, const char __user *buf,
return -EINVAL;
}

static int device_va_to_pa(struct hl_device *hdev, u64 virt_addr,
u64 *phys_addr)
{
struct hl_ctx *ctx = hdev->user_ctx;
u64 hop_addr, hop_pte_addr, hop_pte;
int rc = 0;

if (!ctx) {
dev_err(hdev->dev, "no ctx available\n");
return -EINVAL;
}

mutex_lock(&ctx->mmu_lock);

/* hop 0 */
hop_addr = get_hop0_addr(ctx);
hop_pte_addr = get_hop0_pte_addr(ctx, hop_addr, virt_addr);
hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);

/* hop 1 */
hop_addr = get_next_hop_addr(hop_pte);
if (hop_addr == ULLONG_MAX)
goto not_mapped;
hop_pte_addr = get_hop1_pte_addr(ctx, hop_addr, virt_addr);
hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);

/* hop 2 */
hop_addr = get_next_hop_addr(hop_pte);
if (hop_addr == ULLONG_MAX)
goto not_mapped;
hop_pte_addr = get_hop2_pte_addr(ctx, hop_addr, virt_addr);
hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);

/* hop 3 */
hop_addr = get_next_hop_addr(hop_pte);
if (hop_addr == ULLONG_MAX)
goto not_mapped;
hop_pte_addr = get_hop3_pte_addr(ctx, hop_addr, virt_addr);
hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);

if (!(hop_pte & LAST_MASK)) {
/* hop 4 */
hop_addr = get_next_hop_addr(hop_pte);
if (hop_addr == ULLONG_MAX)
goto not_mapped;
hop_pte_addr = get_hop4_pte_addr(ctx, hop_addr, virt_addr);
hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);
}

if (!(hop_pte & PAGE_PRESENT_MASK))
goto not_mapped;

*phys_addr = (hop_pte & PTE_PHYS_ADDR_MASK) | (virt_addr & OFFSET_MASK);

goto out;

not_mapped:
dev_err(hdev->dev, "virt addr 0x%llx is not mapped to phys addr\n",
virt_addr);
rc = -EINVAL;
out:
mutex_unlock(&ctx->mmu_lock);
return rc;
}

static ssize_t hl_data_read32(struct file *f, char __user *buf,
size_t count, loff_t *ppos)
{
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;
ssize_t rc;

if (*ppos)
return 0;

rc = hdev->asic_funcs->debugfs_read32(hdev, entry->addr, &val);
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 (rc)
return rc;
}

rc = hdev->asic_funcs->debugfs_read32(hdev, addr, &val);
if (rc) {
dev_err(hdev->dev, "Failed to read from 0x%010llx\n",
entry->addr);
dev_err(hdev->dev, "Failed to read from 0x%010llx\n", addr);
return rc;
}

Expand All @@ -536,17 +611,28 @@ 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;

rc = kstrtouint_from_user(buf, count, 16, &value);
if (rc)
return rc;

rc = hdev->asic_funcs->debugfs_write32(hdev, entry->addr, value);
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 (rc)
return rc;
}

rc = hdev->asic_funcs->debugfs_write32(hdev, addr, value);
if (rc) {
dev_err(hdev->dev, "Failed to write 0x%08x to 0x%010llx\n",
value, entry->addr);
value, addr);
return rc;
}

Expand Down
77 changes: 57 additions & 20 deletions drivers/misc/habanalabs/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <linux/pci.h>
#include <linux/sched/signal.h>
#include <linux/hwmon.h>
#include <uapi/misc/habanalabs.h>

#define HL_PLDM_PENDING_RESET_PER_SEC (HL_PENDING_RESET_PER_SEC * 10)

Expand All @@ -21,6 +22,20 @@ bool hl_device_disabled_or_in_reset(struct hl_device *hdev)
return false;
}

enum hl_device_status hl_device_status(struct hl_device *hdev)
{
enum hl_device_status status;

if (hdev->disabled)
status = HL_DEVICE_STATUS_MALFUNCTION;
else if (atomic_read(&hdev->in_reset))
status = HL_DEVICE_STATUS_IN_RESET;
else
status = HL_DEVICE_STATUS_OPERATIONAL;

return status;
};

static void hpriv_release(struct kref *ref)
{
struct hl_fpriv *hpriv;
Expand Down Expand Up @@ -498,11 +513,8 @@ int hl_device_resume(struct hl_device *hdev)
return rc;
}

static void hl_device_hard_reset_pending(struct work_struct *work)
static void device_kill_open_processes(struct hl_device *hdev)
{
struct hl_device_reset_work *device_reset_work =
container_of(work, struct hl_device_reset_work, reset_work);
struct hl_device *hdev = device_reset_work->hdev;
u16 pending_total, pending_cnt;
struct task_struct *task = NULL;

Expand Down Expand Up @@ -537,6 +549,12 @@ static void hl_device_hard_reset_pending(struct work_struct *work)
}
}

/* We killed the open users, but because the driver cleans up after the
* user contexts are closed (e.g. mmu mappings), we need to wait again
* to make sure the cleaning phase is finished before continuing with
* the reset
*/

pending_cnt = pending_total;

while ((atomic_read(&hdev->fd_open_cnt)) && (pending_cnt)) {
Expand All @@ -552,6 +570,16 @@ static void hl_device_hard_reset_pending(struct work_struct *work)

mutex_unlock(&hdev->fd_open_cnt_lock);

}

static void device_hard_reset_pending(struct work_struct *work)
{
struct hl_device_reset_work *device_reset_work =
container_of(work, struct hl_device_reset_work, reset_work);
struct hl_device *hdev = device_reset_work->hdev;

device_kill_open_processes(hdev);

hl_device_reset(hdev, true, true);

kfree(device_reset_work);
Expand Down Expand Up @@ -613,15 +641,15 @@ int hl_device_reset(struct hl_device *hdev, bool hard_reset,
if ((hard_reset) && (!from_hard_reset_thread)) {
struct hl_device_reset_work *device_reset_work;

hdev->hard_reset_pending = true;

if (!hdev->pdev) {
dev_err(hdev->dev,
"Reset action is NOT supported in simulator\n");
rc = -EINVAL;
goto out_err;
}

hdev->hard_reset_pending = true;

device_reset_work = kzalloc(sizeof(*device_reset_work),
GFP_ATOMIC);
if (!device_reset_work) {
Expand All @@ -635,7 +663,7 @@ int hl_device_reset(struct hl_device *hdev, bool hard_reset,
* from a dedicated work
*/
INIT_WORK(&device_reset_work->reset_work,
hl_device_hard_reset_pending);
device_hard_reset_pending);
device_reset_work->hdev = hdev;
schedule_work(&device_reset_work->reset_work);

Expand Down Expand Up @@ -663,17 +691,9 @@ int hl_device_reset(struct hl_device *hdev, bool hard_reset,
/* Go over all the queues, release all CS and their jobs */
hl_cs_rollback_all(hdev);

if (hard_reset) {
/* Release kernel context */
if (hl_ctx_put(hdev->kernel_ctx) != 1) {
dev_err(hdev->dev,
"kernel ctx is alive during hard reset\n");
rc = -EBUSY;
goto out_err;
}

/* Release kernel context */
if ((hard_reset) && (hl_ctx_put(hdev->kernel_ctx) == 1))
hdev->kernel_ctx = NULL;
}

/* Reset the H/W. It will be in idle state after this returns */
hdev->asic_funcs->hw_fini(hdev, hard_reset);
Expand All @@ -698,6 +718,14 @@ int hl_device_reset(struct hl_device *hdev, bool hard_reset,

if (hard_reset) {
hdev->device_cpu_disabled = false;
hdev->hard_reset_pending = false;

if (hdev->kernel_ctx) {
dev_crit(hdev->dev,
"kernel ctx was alive during hard reset, something is terribly wrong\n");
rc = -EBUSY;
goto out_err;
}

/* Allocate the kernel context */
hdev->kernel_ctx = kzalloc(sizeof(*hdev->kernel_ctx),
Expand Down Expand Up @@ -752,8 +780,6 @@ int hl_device_reset(struct hl_device *hdev, bool hard_reset,
}

hl_set_max_power(hdev, hdev->max_power);

hdev->hard_reset_pending = false;
} else {
rc = hdev->asic_funcs->soft_reset_late_init(hdev);
if (rc) {
Expand Down Expand Up @@ -1030,11 +1056,22 @@ void hl_device_fini(struct hl_device *hdev)
WARN(1, "Failed to remove device because reset function did not finish\n");
return;
}
};
}

/* Mark device as disabled */
hdev->disabled = true;

/*
* Flush anyone that is inside the critical section of enqueue
* jobs to the H/W
*/
hdev->asic_funcs->hw_queues_lock(hdev);
hdev->asic_funcs->hw_queues_unlock(hdev);

hdev->hard_reset_pending = true;

device_kill_open_processes(hdev);

hl_hwmon_fini(hdev);

device_late_fini(hdev);
Expand Down
Loading

0 comments on commit cef62a6

Please sign in to comment.