Commit ca62433f authored by Oded Gabbay's avatar Oded Gabbay

habanalabs: support clock gating enable/disable

In Gaudi there is a feature of clock gating certain engines.
Therefore, add this property to the device structure.

In addition, due to a limitation of this feature, the driver needs to
dynamically enable or disable this feature during run-time. Therefore, add
ASIC interface functions to enable/disable this function from the common
code.

Moreover, this feature must be turned off when the user wishes to debug the
ASIC by reading/writing registers and/or memory through the driver's
debugfs. Therefore, add an option to enable/disable clock gating via the
debugfs interface.
Signed-off-by: default avatarOded Gabbay <oded.gabbay@gmail.com>
parent 803917f9
...@@ -8,6 +8,16 @@ Description: Sets the device address to be used for read or write through ...@@ -8,6 +8,16 @@ Description: Sets the device address to be used for read or write through
only when the IOMMU is disabled. only when the IOMMU is disabled.
The acceptable value is a string that starts with "0x" The acceptable value is a string that starts with "0x"
What: /sys/kernel/debug/habanalabs/hl<n>/clk_gate
Date: May 2020
KernelVersion: 5.8
Contact: oded.gabbay@gmail.com
Description: Allow the root user to disable/enable in runtime the clock
gating mechanism in Gaudi. Due to how Gaudi is built, the
clock gating needs to be disabled in order to access the
registers of the TPC and MME engines. This is sometimes needed
during debug by the user and hence the user needs this option
What: /sys/kernel/debug/habanalabs/hl<n>/command_buffers What: /sys/kernel/debug/habanalabs/hl<n>/command_buffers
Date: Jan 2019 Date: Jan 2019
KernelVersion: 5.1 KernelVersion: 5.1
......
...@@ -970,6 +970,55 @@ static ssize_t hl_device_write(struct file *f, const char __user *buf, ...@@ -970,6 +970,55 @@ static ssize_t hl_device_write(struct file *f, const char __user *buf,
return count; return count;
} }
static ssize_t hl_clk_gate_read(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;
char tmp_buf[200];
ssize_t rc;
if (*ppos)
return 0;
sprintf(tmp_buf, "%d\n", hdev->clock_gating);
rc = simple_read_from_buffer(buf, strlen(tmp_buf) + 1, ppos, tmp_buf,
strlen(tmp_buf) + 1);
return rc;
}
static ssize_t hl_clk_gate_write(struct file *f, const 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;
u32 value;
ssize_t rc;
if (atomic_read(&hdev->in_reset)) {
dev_warn_ratelimited(hdev->dev,
"Can't change clock gating during reset\n");
return 0;
}
rc = kstrtouint_from_user(buf, count, 10, &value);
if (rc)
return rc;
if (value) {
hdev->clock_gating = 1;
if (hdev->asic_funcs->enable_clock_gating)
hdev->asic_funcs->enable_clock_gating(hdev);
} else {
if (hdev->asic_funcs->disable_clock_gating)
hdev->asic_funcs->disable_clock_gating(hdev);
hdev->clock_gating = 0;
}
return count;
}
static ssize_t hl_stop_on_err_read(struct file *f, char __user *buf, static ssize_t hl_stop_on_err_read(struct file *f, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
...@@ -1058,6 +1107,12 @@ static const struct file_operations hl_device_fops = { ...@@ -1058,6 +1107,12 @@ static const struct file_operations hl_device_fops = {
.write = hl_device_write .write = hl_device_write
}; };
static const struct file_operations hl_clk_gate_fops = {
.owner = THIS_MODULE,
.read = hl_clk_gate_read,
.write = hl_clk_gate_write
};
static const struct file_operations hl_stop_on_err_fops = { static const struct file_operations hl_stop_on_err_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.read = hl_stop_on_err_read, .read = hl_stop_on_err_read,
...@@ -1201,6 +1256,12 @@ void hl_debugfs_add_device(struct hl_device *hdev) ...@@ -1201,6 +1256,12 @@ void hl_debugfs_add_device(struct hl_device *hdev)
dev_entry, dev_entry,
&hl_device_fops); &hl_device_fops);
debugfs_create_file("clk_gate",
0200,
dev_entry->root,
dev_entry,
&hl_clk_gate_fops);
debugfs_create_file("stop_on_err", debugfs_create_file("stop_on_err",
0644, 0644,
dev_entry->root, dev_entry->root,
......
...@@ -603,6 +603,9 @@ int hl_device_set_debug_mode(struct hl_device *hdev, bool enable) ...@@ -603,6 +603,9 @@ int hl_device_set_debug_mode(struct hl_device *hdev, bool enable)
hdev->in_debug = 0; hdev->in_debug = 0;
if (!hdev->hard_reset_pending)
hdev->asic_funcs->enable_clock_gating(hdev);
goto out; goto out;
} }
...@@ -613,6 +616,7 @@ int hl_device_set_debug_mode(struct hl_device *hdev, bool enable) ...@@ -613,6 +616,7 @@ int hl_device_set_debug_mode(struct hl_device *hdev, bool enable)
goto out; goto out;
} }
hdev->asic_funcs->disable_clock_gating(hdev);
hdev->in_debug = 1; hdev->in_debug = 1;
out: out:
......
...@@ -5018,6 +5018,16 @@ int goya_armcp_info_get(struct hl_device *hdev) ...@@ -5018,6 +5018,16 @@ int goya_armcp_info_get(struct hl_device *hdev)
return 0; return 0;
} }
static void goya_enable_clock_gating(struct hl_device *hdev)
{
}
static void goya_disable_clock_gating(struct hl_device *hdev)
{
}
static bool goya_is_device_idle(struct hl_device *hdev, u32 *mask, static bool goya_is_device_idle(struct hl_device *hdev, u32 *mask,
struct seq_file *s) struct seq_file *s)
{ {
...@@ -5239,6 +5249,8 @@ static const struct hl_asic_funcs goya_funcs = { ...@@ -5239,6 +5249,8 @@ static const struct hl_asic_funcs goya_funcs = {
.mmu_invalidate_cache = goya_mmu_invalidate_cache, .mmu_invalidate_cache = goya_mmu_invalidate_cache,
.mmu_invalidate_cache_range = goya_mmu_invalidate_cache_range, .mmu_invalidate_cache_range = goya_mmu_invalidate_cache_range,
.send_heartbeat = goya_send_heartbeat, .send_heartbeat = goya_send_heartbeat,
.enable_clock_gating = goya_enable_clock_gating,
.disable_clock_gating = goya_disable_clock_gating,
.debug_coresight = goya_debug_coresight, .debug_coresight = goya_debug_coresight,
.is_device_idle = goya_is_device_idle, .is_device_idle = goya_is_device_idle,
.soft_reset_late_init = goya_soft_reset_late_init, .soft_reset_late_init = goya_soft_reset_late_init,
......
...@@ -578,6 +578,8 @@ enum hl_pll_frequency { ...@@ -578,6 +578,8 @@ enum hl_pll_frequency {
* @mmu_invalidate_cache_range: flush specific MMU STLB cache lines with * @mmu_invalidate_cache_range: flush specific MMU STLB cache lines with
* ASID-VA-size mask. * ASID-VA-size mask.
* @send_heartbeat: send is-alive packet to ArmCP and verify response. * @send_heartbeat: send is-alive packet to ArmCP and verify response.
* @enable_clock_gating: enable clock gating for reducing power consumption.
* @disable_clock_gating: disable clock for accessing registers on HBW.
* @debug_coresight: perform certain actions on Coresight for debugging. * @debug_coresight: perform certain actions on Coresight for debugging.
* @is_device_idle: return true if device is idle, false otherwise. * @is_device_idle: return true if device is idle, false otherwise.
* @soft_reset_late_init: perform certain actions needed after soft reset. * @soft_reset_late_init: perform certain actions needed after soft reset.
...@@ -678,6 +680,8 @@ struct hl_asic_funcs { ...@@ -678,6 +680,8 @@ struct hl_asic_funcs {
void (*mmu_invalidate_cache_range)(struct hl_device *hdev, bool is_hard, void (*mmu_invalidate_cache_range)(struct hl_device *hdev, bool is_hard,
u32 asid, u64 va, u64 size); u32 asid, u64 va, u64 size);
int (*send_heartbeat)(struct hl_device *hdev); int (*send_heartbeat)(struct hl_device *hdev);
void (*enable_clock_gating)(struct hl_device *hdev);
void (*disable_clock_gating)(struct hl_device *hdev);
int (*debug_coresight)(struct hl_device *hdev, void *data); int (*debug_coresight)(struct hl_device *hdev, void *data);
bool (*is_device_idle)(struct hl_device *hdev, u32 *mask, bool (*is_device_idle)(struct hl_device *hdev, u32 *mask,
struct seq_file *s); struct seq_file *s);
...@@ -1408,6 +1412,7 @@ struct hl_device_idle_busy_ts { ...@@ -1408,6 +1412,7 @@ struct hl_device_idle_busy_ts {
* huge pages. * huge pages.
* @init_done: is the initialization of the device done. * @init_done: is the initialization of the device done.
* @mmu_enable: is MMU enabled. * @mmu_enable: is MMU enabled.
* @clock_gating: is clock gating enabled.
* @device_cpu_disabled: is the device CPU disabled (due to timeouts) * @device_cpu_disabled: is the device CPU disabled (due to timeouts)
* @dma_mask: the dma mask that was set for this device * @dma_mask: the dma mask that was set for this device
* @in_debug: is device under debug. This, together with fpriv_list, enforces * @in_debug: is device under debug. This, together with fpriv_list, enforces
...@@ -1494,6 +1499,7 @@ struct hl_device { ...@@ -1494,6 +1499,7 @@ struct hl_device {
u8 dram_default_page_mapping; u8 dram_default_page_mapping;
u8 pmmu_huge_range; u8 pmmu_huge_range;
u8 init_done; u8 init_done;
u8 clock_gating;
u8 device_cpu_disabled; u8 device_cpu_disabled;
u8 dma_mask; u8 dma_mask;
u8 in_debug; u8 in_debug;
......
...@@ -231,6 +231,7 @@ static void set_driver_behavior_per_device(struct hl_device *hdev) ...@@ -231,6 +231,7 @@ static void set_driver_behavior_per_device(struct hl_device *hdev)
hdev->fw_loading = 1; hdev->fw_loading = 1;
hdev->cpu_queues_enable = 1; hdev->cpu_queues_enable = 1;
hdev->heartbeat = 1; hdev->heartbeat = 1;
hdev->clock_gating = 1;
hdev->reset_pcilink = 0; hdev->reset_pcilink = 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment