Merge tag 'misc-habanalabs-fixes-2019-05-24' of git://people.freedesktop.org/~gabbayo/linux into char-misc-linus

Oded writes:

This tag contains the following fixes:

- Halt debug engines when user process closes the FD. We can't allow the
  device to issue transactions for a user which doesn't exists anymore.

- Fix various security holes in debugfs API.

- Add a new opcode to the DEBUG IOCTL API. The opcode is designed
  for setting the device into and out of debug mode. Although not a fix
  per-se, because this is a new IOCTL which is upstreamed in kernel 5.2, I
  think this is justified at this point because we won't be able to change
  the API later.

- Fix a bug where the code used an uninitialized mutex

* tag 'misc-habanalabs-fixes-2019-05-24' of git://people.freedesktop.org/~gabbayo/linux:
  habanalabs: Avoid using a non-initialized MMU cache mutex
  habanalabs: fix debugfs code
  uapi/habanalabs: add opcode for enable/disable device debug mode
  habanalabs: halt debug engines on user process close
This commit is contained in:
Greg Kroah-Hartman 2019-05-31 09:19:42 -07:00
commit 8aa75b72e3
9 changed files with 69 additions and 52 deletions

View file

@ -26,6 +26,12 @@ static void hl_ctx_fini(struct hl_ctx *ctx)
dma_fence_put(ctx->cs_pending[i]);
if (ctx->asid != HL_KERNEL_ASID_ID) {
/*
* The engines are stopped as there is no executing CS, but the
* Coresight might be still working by accessing addresses
* related to the stopped engines. Hence stop it explicitly.
*/
hdev->asic_funcs->halt_coresight(hdev);
hl_vm_ctx_fini(ctx);
hl_asid_free(hdev, ctx->asid);
}

View file

@ -459,41 +459,31 @@ static ssize_t mmu_write(struct file *file, const char __user *buf,
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[MMU_KBUF_SIZE], asid_kbuf[MMU_ASID_BUF_SIZE],
addr_kbuf[MMU_ADDR_BUF_SIZE];
char kbuf[MMU_KBUF_SIZE];
char *c;
ssize_t rc;
if (!hdev->mmu_enable)
return count;
memset(kbuf, 0, sizeof(kbuf));
memset(asid_kbuf, 0, sizeof(asid_kbuf));
memset(addr_kbuf, 0, sizeof(addr_kbuf));
if (count > sizeof(kbuf) - 1)
goto err;
if (copy_from_user(kbuf, buf, count))
goto err;
kbuf[MMU_KBUF_SIZE - 1] = 0;
kbuf[count] = 0;
c = strchr(kbuf, ' ');
if (!c)
goto err;
*c = '\0';
memcpy(asid_kbuf, kbuf, c - kbuf);
rc = kstrtouint(asid_kbuf, 10, &dev_entry->mmu_asid);
rc = kstrtouint(kbuf, 10, &dev_entry->mmu_asid);
if (rc)
goto err;
c = strstr(kbuf, " 0x");
if (!c)
if (strncmp(c+1, "0x", 2))
goto err;
c += 3;
memcpy(addr_kbuf, c, (kbuf + count) - c);
rc = kstrtoull(addr_kbuf, 16, &dev_entry->mmu_addr);
rc = kstrtoull(c+3, 16, &dev_entry->mmu_addr);
if (rc)
goto err;
@ -600,10 +590,8 @@ static ssize_t hl_data_read32(struct file *f, char __user *buf,
}
sprintf(tmp_buf, "0x%08x\n", val);
rc = simple_read_from_buffer(buf, strlen(tmp_buf) + 1, ppos, tmp_buf,
strlen(tmp_buf) + 1);
return rc;
return simple_read_from_buffer(buf, count, ppos, tmp_buf,
strlen(tmp_buf));
}
static ssize_t hl_data_write32(struct file *f, const char __user *buf,
@ -645,7 +633,6 @@ static ssize_t hl_get_power_state(struct file *f, char __user *buf,
struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
struct hl_device *hdev = entry->hdev;
char tmp_buf[200];
ssize_t rc;
int i;
if (*ppos)
@ -660,10 +647,8 @@ static ssize_t hl_get_power_state(struct file *f, char __user *buf,
sprintf(tmp_buf,
"current power state: %d\n1 - D0\n2 - D3hot\n3 - Unknown\n", i);
rc = simple_read_from_buffer(buf, strlen(tmp_buf) + 1, ppos, tmp_buf,
strlen(tmp_buf) + 1);
return rc;
return simple_read_from_buffer(buf, count, ppos, tmp_buf,
strlen(tmp_buf));
}
static ssize_t hl_set_power_state(struct file *f, const char __user *buf,
@ -716,8 +701,8 @@ static ssize_t hl_i2c_data_read(struct file *f, char __user *buf,
}
sprintf(tmp_buf, "0x%02x\n", val);
rc = simple_read_from_buffer(buf, strlen(tmp_buf) + 1, ppos, tmp_buf,
strlen(tmp_buf) + 1);
rc = simple_read_from_buffer(buf, count, ppos, tmp_buf,
strlen(tmp_buf));
return rc;
}
@ -806,18 +791,9 @@ static ssize_t hl_led2_write(struct file *f, const char __user *buf,
static ssize_t hl_device_read(struct file *f, char __user *buf,
size_t count, loff_t *ppos)
{
char tmp_buf[200];
ssize_t rc;
if (*ppos)
return 0;
sprintf(tmp_buf,
"Valid values: disable, enable, suspend, resume, cpu_timeout\n");
rc = simple_read_from_buffer(buf, strlen(tmp_buf) + 1, ppos, tmp_buf,
strlen(tmp_buf) + 1);
return rc;
static const char *help =
"Valid values: disable, enable, suspend, resume, cpu_timeout\n";
return simple_read_from_buffer(buf, count, ppos, help, strlen(help));
}
static ssize_t hl_device_write(struct file *f, const char __user *buf,
@ -825,7 +801,7 @@ static ssize_t hl_device_write(struct file *f, const char __user *buf,
{
struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
struct hl_device *hdev = entry->hdev;
char data[30];
char data[30] = {0};
/* don't allow partial writes */
if (*ppos != 0)

View file

@ -231,6 +231,7 @@ static int device_early_init(struct hl_device *hdev)
mutex_init(&hdev->fd_open_cnt_lock);
mutex_init(&hdev->send_cpu_message_lock);
mutex_init(&hdev->mmu_cache_lock);
INIT_LIST_HEAD(&hdev->hw_queues_mirror_list);
spin_lock_init(&hdev->hw_queues_mirror_lock);
atomic_set(&hdev->in_reset, 0);
@ -260,6 +261,7 @@ static int device_early_init(struct hl_device *hdev)
*/
static void device_early_fini(struct hl_device *hdev)
{
mutex_destroy(&hdev->mmu_cache_lock);
mutex_destroy(&hdev->send_cpu_message_lock);
hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr);

View file

@ -4819,7 +4819,8 @@ static const struct hl_asic_funcs goya_funcs = {
.set_dram_bar_base = goya_set_ddr_bar_base,
.init_iatu = goya_init_iatu,
.rreg = hl_rreg,
.wreg = hl_wreg
.wreg = hl_wreg,
.halt_coresight = goya_halt_coresight
};
/*

View file

@ -202,6 +202,7 @@ void goya_add_device_attr(struct hl_device *hdev,
struct attribute_group *dev_attr_grp);
int goya_armcp_info_get(struct hl_device *hdev);
int goya_debug_coresight(struct hl_device *hdev, void *data);
void goya_halt_coresight(struct hl_device *hdev);
void goya_mmu_prepare(struct hl_device *hdev, u32 asid);
int goya_mmu_clear_pgt_range(struct hl_device *hdev);

View file

@ -626,3 +626,20 @@ int goya_debug_coresight(struct hl_device *hdev, void *data)
return rc;
}
void goya_halt_coresight(struct hl_device *hdev)
{
struct hl_debug_params params = {};
int i, rc;
for (i = GOYA_ETF_FIRST ; i <= GOYA_ETF_LAST ; i++) {
params.reg_idx = i;
rc = goya_config_etf(hdev, &params);
if (rc)
dev_err(hdev->dev, "halt ETF failed, %d/%d\n", rc, i);
}
rc = goya_config_etr(hdev, &params);
if (rc)
dev_err(hdev->dev, "halt ETR failed, %d\n", rc);
}

View file

@ -501,6 +501,7 @@ enum hl_pll_frequency {
* @init_iatu: Initialize the iATU unit inside the PCI controller.
* @rreg: Read a register. Needed for simulator support.
* @wreg: Write a register. Needed for simulator support.
* @halt_coresight: stop the ETF and ETR traces.
*/
struct hl_asic_funcs {
int (*early_init)(struct hl_device *hdev);
@ -578,6 +579,7 @@ struct hl_asic_funcs {
int (*init_iatu)(struct hl_device *hdev);
u32 (*rreg)(struct hl_device *hdev, u32 reg);
void (*wreg)(struct hl_device *hdev, u32 reg, u32 val);
void (*halt_coresight)(struct hl_device *hdev);
};

View file

@ -404,15 +404,12 @@ int hl_mmu_init(struct hl_device *hdev)
/* MMU H/W init was already done in device hw_init() */
mutex_init(&hdev->mmu_cache_lock);
hdev->mmu_pgt_pool =
gen_pool_create(__ffs(prop->mmu_hop_table_size), -1);
if (!hdev->mmu_pgt_pool) {
dev_err(hdev->dev, "Failed to create page gen pool\n");
rc = -ENOMEM;
goto err_pool_create;
return -ENOMEM;
}
rc = gen_pool_add(hdev->mmu_pgt_pool, prop->mmu_pgt_addr +
@ -436,8 +433,6 @@ int hl_mmu_init(struct hl_device *hdev)
err_pool_add:
gen_pool_destroy(hdev->mmu_pgt_pool);
err_pool_create:
mutex_destroy(&hdev->mmu_cache_lock);
return rc;
}
@ -459,7 +454,6 @@ void hl_mmu_fini(struct hl_device *hdev)
kvfree(hdev->mmu_shadow_hop0);
gen_pool_destroy(hdev->mmu_pgt_pool);
mutex_destroy(&hdev->mmu_cache_lock);
/* MMU H/W fini will be done in device hw_fini() */
}

View file

@ -413,6 +413,10 @@ struct hl_debug_params_spmu {
#define HL_DEBUG_OP_SPMU 5
/* Opcode for timestamp */
#define HL_DEBUG_OP_TIMESTAMP 6
/* Opcode for setting the device into or out of debug mode. The enable
* variable should be 1 for enabling debug mode and 0 for disabling it
*/
#define HL_DEBUG_OP_SET_MODE 7
struct hl_debug_args {
/*
@ -574,8 +578,22 @@ struct hl_debug_args {
*
* This IOCTL allows the user to get debug traces from the chip.
*
* The user needs to provide the register index and essential data such as
* buffer address and size.
* Before the user can send configuration requests of the various
* debug/profile engines, it needs to set the device into debug mode.
* This is because the debug/profile infrastructure is shared component in the
* device and we can't allow multiple users to access it at the same time.
*
* Once a user set the device into debug mode, the driver won't allow other
* users to "work" with the device, i.e. open a FD. If there are multiple users
* opened on the device, the driver won't allow any user to debug the device.
*
* For each configuration request, the user needs to provide the register index
* and essential data such as buffer address and size.
*
* Once the user has finished using the debug/profile engines, he should
* set the device into non-debug mode, i.e. disable debug mode.
*
* The driver can decide to "kick out" the user if he abuses this interface.
*
*/
#define HL_IOCTL_DEBUG \