habanalabs: add debugfs support

This patch adds debugfs support to the driver. It allows the user-space to
display information that is contained in the internal structures of the
driver, such as:
- active command submissions
- active user virtual memory mappings
- number of allocated command buffers

It also enables the user to perform reads and writes through Goya's PCI
bars.

Reviewed-by: Mike Rapoport <rppt@linux.ibm.com>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Oded Gabbay 2019-02-16 00:39:24 +02:00 committed by Greg Kroah-Hartman
parent d8dd7b0a81
commit c216477363
11 changed files with 1546 additions and 2 deletions

View File

@ -0,0 +1,126 @@
What: /sys/kernel/debug/habanalabs/hl<n>/addr
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"
What: /sys/kernel/debug/habanalabs/hl<n>/command_buffers
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Displays a list with information about the currently allocated
command buffers
What: /sys/kernel/debug/habanalabs/hl<n>/command_submission
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Displays a list with information about the currently active
command submissions
What: /sys/kernel/debug/habanalabs/hl<n>/command_submission_jobs
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Displays a list with detailed information about each JOB (CB) of
each active command submission
What: /sys/kernel/debug/habanalabs/hl<n>/data32
Date: Jan 2019
KernelVersion: 5.1
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
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
What: /sys/kernel/debug/habanalabs/hl<n>/device
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Enables the root user to set the device to specific state.
Valid values are "disable", "enable", "suspend", "resume".
User can read this property to see the valid values
What: /sys/kernel/debug/habanalabs/hl<n>/i2c_addr
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Sets I2C device address for I2C transaction that is generated
by the device's CPU
What: /sys/kernel/debug/habanalabs/hl<n>/i2c_bus
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Sets I2C bus address for I2C transaction that is generated by
the device's CPU
What: /sys/kernel/debug/habanalabs/hl<n>/i2c_data
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Triggers an I2C transaction that is generated by the device's
CPU. Writing to this file generates a write transaction while
reading from the file generates a read transcation
What: /sys/kernel/debug/habanalabs/hl<n>/i2c_reg
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Sets I2C register id for I2C transaction that is generated by
the device's CPU
What: /sys/kernel/debug/habanalabs/hl<n>/led0
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Sets the state of the first S/W led on the device
What: /sys/kernel/debug/habanalabs/hl<n>/led1
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Sets the state of the second S/W led on the device
What: /sys/kernel/debug/habanalabs/hl<n>/led2
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Sets the state of the third S/W led on the device
What: /sys/kernel/debug/habanalabs/hl<n>/mmu
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Displays the hop values and physical address for a given ASID
and virtual address. The user should write the ASID and VA into
the file and then read the file to get the result.
e.g. to display info about VA 0x1000 for ASID 1 you need to do:
echo "1 0x1000" > /sys/kernel/debug/habanalabs/hl0/mmu
What: /sys/kernel/debug/habanalabs/hl<n>/set_power_state
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Sets the PCI power state. Valid values are "1" for D0 and "2"
for D3Hot
What: /sys/kernel/debug/habanalabs/hl<n>/userptr
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Displays a list with information about the currently user
pointers (user virtual addresses) that are pinned and mapped
to DMA addresses
What: /sys/kernel/debug/habanalabs/hl<n>/vm
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Description: Displays a list with information about all the active virtual
address mappings per ASID

View File

@ -8,5 +8,7 @@ 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_buffer.o hw_queue.o irq.o sysfs.o hwmon.o memory.o \
command_submission.o mmu.o command_submission.o mmu.o
habanalabs-$(CONFIG_DEBUG_FS) += debugfs.o
include $(src)/goya/Makefile include $(src)/goya/Makefile
habanalabs-y += $(HL_GOYA_FILES) habanalabs-y += $(HL_GOYA_FILES)

View File

@ -38,6 +38,8 @@ static void cb_release(struct kref *ref)
cb = container_of(ref, struct hl_cb, refcount); cb = container_of(ref, struct hl_cb, refcount);
hdev = cb->hdev; hdev = cb->hdev;
hl_debugfs_remove_cb(cb);
cb_do_release(hdev, cb); cb_do_release(hdev, cb);
} }
@ -163,6 +165,8 @@ int hl_cb_create(struct hl_device *hdev, struct hl_cb_mgr *mgr,
*handle = cb->id | HL_MMAP_CB_MASK; *handle = cb->id | HL_MMAP_CB_MASK;
*handle <<= PAGE_SHIFT; *handle <<= PAGE_SHIFT;
hl_debugfs_add_cb(cb);
return 0; return 0;
release_cb: release_cb:

View File

@ -149,6 +149,8 @@ static void free_job(struct hl_device *hdev, struct hl_cs_job *job)
list_del(&job->cs_node); list_del(&job->cs_node);
spin_unlock(&cs->job_lock); spin_unlock(&cs->job_lock);
hl_debugfs_remove_job(hdev, job);
if (job->ext_queue) if (job->ext_queue)
cs_put(cs); cs_put(cs);
@ -212,6 +214,12 @@ static void cs_do_release(struct kref *ref)
} }
} }
/*
* Must be called before hl_ctx_put because inside we use ctx to get
* the device
*/
hl_debugfs_remove_cs(cs);
hl_ctx_put(cs->ctx); hl_ctx_put(cs->ctx);
if (cs->timedout) if (cs->timedout)
@ -480,6 +488,8 @@ static int _hl_cs_ioctl(struct hl_fpriv *hpriv, void __user *chunks,
*cs_seq = cs->sequence; *cs_seq = cs->sequence;
hl_debugfs_add_cs(cs);
/* Validate ALL the CS chunks before submitting the CS */ /* Validate ALL the CS chunks before submitting the CS */
for (i = 0, parse_cnt = 0 ; i < num_chunks ; i++, parse_cnt++) { for (i = 0, parse_cnt = 0 ; i < num_chunks ; i++, parse_cnt++) {
struct hl_cs_chunk *chunk = &cs_chunk_array[i]; struct hl_cs_chunk *chunk = &cs_chunk_array[i];
@ -528,6 +538,8 @@ static int _hl_cs_ioctl(struct hl_fpriv *hpriv, void __user *chunks,
if (job->ext_queue) if (job->ext_queue)
cs_get(cs); cs_get(cs);
hl_debugfs_add_job(hdev, job);
rc = cs_parser(hpriv, job); rc = cs_parser(hpriv, job);
if (rc) { if (rc) {
dev_err(hdev->dev, dev_err(hdev->dev,

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,8 @@ static void hpriv_release(struct kref *ref)
put_pid(hpriv->taskpid); put_pid(hpriv->taskpid);
hl_debugfs_remove_file(hpriv);
mutex_destroy(&hpriv->restore_phase_mutex); mutex_destroy(&hpriv->restore_phase_mutex);
kfree(hpriv); kfree(hpriv);
@ -834,6 +836,8 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
goto free_cb_pool; goto free_cb_pool;
} }
hl_debugfs_add_device(hdev);
if (hdev->asic_funcs->get_hw_state(hdev) == HL_DEVICE_HW_STATE_DIRTY) { if (hdev->asic_funcs->get_hw_state(hdev) == HL_DEVICE_HW_STATE_DIRTY) {
dev_info(hdev->dev, dev_info(hdev->dev,
"H/W state is dirty, must reset before initializing\n"); "H/W state is dirty, must reset before initializing\n");
@ -972,6 +976,8 @@ void hl_device_fini(struct hl_device *hdev)
device_late_fini(hdev); device_late_fini(hdev);
hl_debugfs_remove_device(hdev);
hl_sysfs_fini(hdev); hl_sysfs_fini(hdev);
/* /*

View File

@ -4370,6 +4370,8 @@ int goya_context_switch(struct hl_device *hdev, u32 asid)
job->user_cb_size = cb_size; job->user_cb_size = cb_size;
job->hw_queue_id = GOYA_QUEUE_ID_DMA_0; job->hw_queue_id = GOYA_QUEUE_ID_DMA_0;
hl_debugfs_add_job(hdev, job);
parser.ctx_id = HL_KERNEL_ASID_ID; parser.ctx_id = HL_KERNEL_ASID_ID;
parser.cs_sequence = 0; parser.cs_sequence = 0;
parser.job_id = job->id; parser.job_id = job->id;
@ -4402,6 +4404,7 @@ int goya_context_switch(struct hl_device *hdev, u32 asid)
free_job: free_job:
hl_userptr_delete_list(hdev, &job->userptr_list); hl_userptr_delete_list(hdev, &job->userptr_list);
hl_debugfs_remove_job(hdev, job);
kfree(job); kfree(job);
cb->cs_cnt--; cb->cs_cnt--;
@ -4432,6 +4435,106 @@ void goya_restore_phase_topology(struct hl_device *hdev)
i = RREG32(mmSYNC_MNGR_SOB_OBJ_0); i = RREG32(mmSYNC_MNGR_SOB_OBJ_0);
} }
/*
* goya_debugfs_read32 - read a 32bit value from a given device address
*
* @hdev: pointer to hl_device structure
* @addr: address in device
* @val: returned value
*
* In case of DDR address that is not mapped into the default aperture that
* the DDR bar exposes, the function will configure the iATU so that the DDR
* bar will be positioned at a base address that allows reading from the
* required address. Configuring the iATU during normal operation can
* lead to undefined behavior and therefore, should be done with extreme care
*
*/
int goya_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
int rc = 0;
if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) {
*val = RREG32(addr - CFG_BASE);
} else if ((addr >= SRAM_BASE_ADDR) &&
(addr < SRAM_BASE_ADDR + SRAM_SIZE)) {
*val = readl(hdev->pcie_bar[SRAM_CFG_BAR_ID] +
(addr - SRAM_BASE_ADDR));
} else if ((addr >= DRAM_PHYS_BASE) &&
(addr < DRAM_PHYS_BASE + hdev->asic_prop.dram_size)) {
u64 bar_base_addr = DRAM_PHYS_BASE +
(addr & ~(prop->dram_pci_bar_size - 0x1ull));
rc = goya_set_ddr_bar_base(hdev, bar_base_addr);
if (!rc) {
*val = readl(hdev->pcie_bar[DDR_BAR_ID] +
(addr - bar_base_addr));
rc = goya_set_ddr_bar_base(hdev, DRAM_PHYS_BASE +
(MMU_PAGE_TABLES_ADDR &
~(prop->dram_pci_bar_size - 0x1ull)));
}
} else {
rc = -EFAULT;
}
return rc;
}
/*
* goya_debugfs_write32 - write a 32bit value to a given device address
*
* @hdev: pointer to hl_device structure
* @addr: address in device
* @val: returned value
*
* In case of DDR address that is not mapped into the default aperture that
* the DDR bar exposes, the function will configure the iATU so that the DDR
* bar will be positioned at a base address that allows writing to the
* required address. Configuring the iATU during normal operation can
* lead to undefined behavior and therefore, should be done with extreme care
*
*/
int goya_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
int rc = 0;
if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) {
WREG32(addr - CFG_BASE, val);
} else if ((addr >= SRAM_BASE_ADDR) &&
(addr < SRAM_BASE_ADDR + SRAM_SIZE)) {
writel(val, hdev->pcie_bar[SRAM_CFG_BAR_ID] +
(addr - SRAM_BASE_ADDR));
} else if ((addr >= DRAM_PHYS_BASE) &&
(addr < DRAM_PHYS_BASE + hdev->asic_prop.dram_size)) {
u64 bar_base_addr = DRAM_PHYS_BASE +
(addr & ~(prop->dram_pci_bar_size - 0x1ull));
rc = goya_set_ddr_bar_base(hdev, bar_base_addr);
if (!rc) {
writel(val, hdev->pcie_bar[DDR_BAR_ID] +
(addr - bar_base_addr));
rc = goya_set_ddr_bar_base(hdev, DRAM_PHYS_BASE +
(MMU_PAGE_TABLES_ADDR &
~(prop->dram_pci_bar_size - 0x1ull)));
}
} else {
rc = -EFAULT;
}
return rc;
}
static u64 goya_read_pte(struct hl_device *hdev, u64 addr) static u64 goya_read_pte(struct hl_device *hdev, u64 addr)
{ {
struct goya_device *goya = hdev->asic_specific; struct goya_device *goya = hdev->asic_specific;
@ -4780,6 +4883,8 @@ static int goya_mmu_clear_pgt_range(struct hl_device *hdev)
job->user_cb_size = cb_size; job->user_cb_size = cb_size;
job->hw_queue_id = GOYA_QUEUE_ID_DMA_0; job->hw_queue_id = GOYA_QUEUE_ID_DMA_0;
hl_debugfs_add_job(hdev, job);
parser.ctx_id = HL_KERNEL_ASID_ID; parser.ctx_id = HL_KERNEL_ASID_ID;
parser.cs_sequence = 0; parser.cs_sequence = 0;
parser.job_id = job->id; parser.job_id = job->id;
@ -4808,6 +4913,7 @@ static int goya_mmu_clear_pgt_range(struct hl_device *hdev)
free_job: free_job:
hl_userptr_delete_list(hdev, &job->userptr_list); hl_userptr_delete_list(hdev, &job->userptr_list);
hl_debugfs_remove_job(hdev, job);
kfree(job); kfree(job);
cb->cs_cnt--; cb->cs_cnt--;
@ -5222,6 +5328,8 @@ static const struct hl_asic_funcs goya_funcs = {
.update_eq_ci = goya_update_eq_ci, .update_eq_ci = goya_update_eq_ci,
.context_switch = goya_context_switch, .context_switch = goya_context_switch,
.restore_phase_topology = goya_restore_phase_topology, .restore_phase_topology = goya_restore_phase_topology,
.debugfs_read32 = goya_debugfs_read32,
.debugfs_write32 = goya_debugfs_write32,
.add_device_attr = goya_add_device_attr, .add_device_attr = goya_add_device_attr,
.handle_eqe = goya_handle_eqe, .handle_eqe = goya_handle_eqe,
.set_pll_profile = goya_set_pll_profile, .set_pll_profile = goya_set_pll_profile,

View File

@ -165,6 +165,10 @@ struct goya_device {
u32 hw_cap_initialized; u32 hw_cap_initialized;
}; };
int goya_debugfs_i2c_read(struct hl_device *hdev, u8 i2c_bus,
u8 i2c_addr, u8 i2c_reg, u32 *val);
int goya_debugfs_i2c_write(struct hl_device *hdev, u8 i2c_bus,
u8 i2c_addr, u8 i2c_reg, u32 val);
int goya_test_cpu_queue(struct hl_device *hdev); int goya_test_cpu_queue(struct hl_device *hdev);
int goya_send_cpu_message(struct hl_device *hdev, u32 *msg, u16 len, int goya_send_cpu_message(struct hl_device *hdev, u32 *msg, u16 len,
u32 timeout, long *result); u32 timeout, long *result);
@ -175,6 +179,7 @@ long goya_get_fan_speed(struct hl_device *hdev, int sensor_index, u32 attr);
long goya_get_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr); long goya_get_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr);
void goya_set_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr, void goya_set_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr,
long value); long value);
void goya_debugfs_led_set(struct hl_device *hdev, u8 led, u8 state);
void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq); void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq);
void goya_add_device_attr(struct hl_device *hdev, void goya_add_device_attr(struct hl_device *hdev,
struct attribute_group *dev_attr_grp); struct attribute_group *dev_attr_grp);

View File

@ -238,6 +238,7 @@ struct hl_cb_mgr {
* @refcount: reference counter for usage of the CB. * @refcount: reference counter for usage of the CB.
* @hdev: pointer to device this CB belongs to. * @hdev: pointer to device this CB belongs to.
* @lock: spinlock to protect mmap/cs flows. * @lock: spinlock to protect mmap/cs flows.
* @debugfs_list: node in debugfs list of command buffers.
* @pool_list: node in pool list of command buffers. * @pool_list: node in pool list of command buffers.
* @kernel_address: Holds the CB's kernel virtual address. * @kernel_address: Holds the CB's kernel virtual address.
* @bus_address: Holds the CB's DMA address. * @bus_address: Holds the CB's DMA address.
@ -253,6 +254,7 @@ struct hl_cb {
struct kref refcount; struct kref refcount;
struct hl_device *hdev; struct hl_device *hdev;
spinlock_t lock; spinlock_t lock;
struct list_head debugfs_list;
struct list_head pool_list; struct list_head pool_list;
u64 kernel_address; u64 kernel_address;
dma_addr_t bus_address; dma_addr_t bus_address;
@ -453,6 +455,8 @@ enum hl_pll_frequency {
* @update_eq_ci: update event queue CI. * @update_eq_ci: update event queue CI.
* @context_switch: called upon ASID context switch. * @context_switch: called upon ASID context switch.
* @restore_phase_topology: clear all SOBs amd MONs. * @restore_phase_topology: clear all SOBs amd MONs.
* @debugfs_read32: debug interface for reading u32 from DRAM/SRAM.
* @debugfs_write32: debug interface for writing u32 to DRAM/SRAM.
* @add_device_attr: add ASIC specific device attributes. * @add_device_attr: add ASIC specific device attributes.
* @handle_eqe: handle event queue entry (IRQ) from ArmCP. * @handle_eqe: handle event queue entry (IRQ) from ArmCP.
* @set_pll_profile: change PLL profile (manual/automatic). * @set_pll_profile: change PLL profile (manual/automatic).
@ -521,6 +525,8 @@ struct hl_asic_funcs {
void (*update_eq_ci)(struct hl_device *hdev, u32 val); void (*update_eq_ci)(struct hl_device *hdev, u32 val);
int (*context_switch)(struct hl_device *hdev, u32 asid); int (*context_switch)(struct hl_device *hdev, u32 asid);
void (*restore_phase_topology)(struct hl_device *hdev); void (*restore_phase_topology)(struct hl_device *hdev);
int (*debugfs_read32)(struct hl_device *hdev, u64 addr, u32 *val);
int (*debugfs_write32)(struct hl_device *hdev, u64 addr, u32 val);
void (*add_device_attr)(struct hl_device *hdev, void (*add_device_attr)(struct hl_device *hdev,
struct attribute_group *dev_attr_grp); struct attribute_group *dev_attr_grp);
void (*handle_eqe)(struct hl_device *hdev, void (*handle_eqe)(struct hl_device *hdev,
@ -584,6 +590,7 @@ struct hl_va_range {
* @mem_hash_lock: protects the mem_hash. * @mem_hash_lock: protects the mem_hash.
* @mmu_lock: protects the MMU page tables. Any change to the PGT, modifing the * @mmu_lock: protects the MMU page tables. Any change to the PGT, modifing the
* MMU hash or walking the PGT requires talking this lock * MMU hash or walking the PGT requires talking this lock
* @debugfs_list: node in debugfs list of contexts.
* @cs_sequence: sequence number for CS. Value is assigned to a CS and passed * @cs_sequence: sequence number for CS. Value is assigned to a CS and passed
* to user so user could inquire about CS. It is used as * to user so user could inquire about CS. It is used as
* index to cs_pending array. * index to cs_pending array.
@ -608,6 +615,7 @@ struct hl_ctx {
struct hl_va_range dram_va_range; struct hl_va_range dram_va_range;
struct mutex mem_hash_lock; struct mutex mem_hash_lock;
struct mutex mmu_lock; struct mutex mmu_lock;
struct list_head debugfs_list;
u64 cs_sequence; u64 cs_sequence;
spinlock_t cs_lock; spinlock_t cs_lock;
atomic64_t dram_phys_mem; atomic64_t dram_phys_mem;
@ -666,6 +674,7 @@ struct hl_userptr {
* @fence: pointer to the fence object of this CS. * @fence: pointer to the fence object of this CS.
* @work_tdr: delayed work node for TDR. * @work_tdr: delayed work node for TDR.
* @mirror_node : node in device mirror list of command submissions. * @mirror_node : node in device mirror list of command submissions.
* @debugfs_list: node in debugfs list of command submissions.
* @sequence: the sequence number of this CS. * @sequence: the sequence number of this CS.
* @submitted: true if CS was submitted to H/W. * @submitted: true if CS was submitted to H/W.
* @completed: true if CS was completed by device. * @completed: true if CS was completed by device.
@ -683,6 +692,7 @@ struct hl_cs {
struct dma_fence *fence; struct dma_fence *fence;
struct delayed_work work_tdr; struct delayed_work work_tdr;
struct list_head mirror_node; struct list_head mirror_node;
struct list_head debugfs_list;
u64 sequence; u64 sequence;
u8 submitted; u8 submitted;
u8 completed; u8 completed;
@ -701,6 +711,7 @@ struct hl_cs {
* @finish_work: workqueue object to run when job is completed. * @finish_work: workqueue object to run when job is completed.
* @userptr_list: linked-list of userptr mappings that belong to this job and * @userptr_list: linked-list of userptr mappings that belong to this job and
* wait for completion. * wait for completion.
* @debugfs_list: node in debugfs list of command submission jobs.
* @id: the id of this job inside a CS. * @id: the id of this job inside a CS.
* @hw_queue_id: the id of the H/W queue this job is submitted to. * @hw_queue_id: the id of the H/W queue this job is submitted to.
* @user_cb_size: the actual size of the CB we got from the user. * @user_cb_size: the actual size of the CB we got from the user.
@ -714,6 +725,7 @@ struct hl_cs_job {
struct hl_cb *patched_cb; struct hl_cb *patched_cb;
struct work_struct finish_work; struct work_struct finish_work;
struct list_head userptr_list; struct list_head userptr_list;
struct list_head debugfs_list;
u32 id; u32 id;
u32 hw_queue_id; u32 hw_queue_id;
u32 user_cb_size; u32 user_cb_size;
@ -844,6 +856,7 @@ struct hl_vm {
* @ctx: current executing context. * @ctx: current executing context.
* @ctx_mgr: context manager to handle multiple context for this FD. * @ctx_mgr: context manager to handle multiple context for this FD.
* @cb_mgr: command buffer manager to handle multiple buffers for this FD. * @cb_mgr: command buffer manager to handle multiple buffers for this FD.
* @debugfs_list: list of relevant ASIC debugfs.
* @refcount: number of related contexts. * @refcount: number of related contexts.
* @restore_phase_mutex: lock for context switch and restore phase. * @restore_phase_mutex: lock for context switch and restore phase.
*/ */
@ -854,11 +867,90 @@ struct hl_fpriv {
struct hl_ctx *ctx; /* TODO: remove for multiple ctx */ struct hl_ctx *ctx; /* TODO: remove for multiple ctx */
struct hl_ctx_mgr ctx_mgr; struct hl_ctx_mgr ctx_mgr;
struct hl_cb_mgr cb_mgr; struct hl_cb_mgr cb_mgr;
struct list_head debugfs_list;
struct kref refcount; struct kref refcount;
struct mutex restore_phase_mutex; struct mutex restore_phase_mutex;
}; };
/*
* DebugFS
*/
/**
* struct hl_info_list - debugfs file ops.
* @name: file name.
* @show: function to output information.
* @write: function to write to the file.
*/
struct hl_info_list {
const char *name;
int (*show)(struct seq_file *s, void *data);
ssize_t (*write)(struct file *file, const char __user *buf,
size_t count, loff_t *f_pos);
};
/**
* struct hl_debugfs_entry - debugfs dentry wrapper.
* @dent: base debugfs entry structure.
* @info_ent: dentry realted ops.
* @dev_entry: ASIC specific debugfs manager.
*/
struct hl_debugfs_entry {
struct dentry *dent;
const struct hl_info_list *info_ent;
struct hl_dbg_device_entry *dev_entry;
};
/**
* struct hl_dbg_device_entry - ASIC specific debugfs manager.
* @root: root dentry.
* @hdev: habanalabs device structure.
* @entry_arr: array of available hl_debugfs_entry.
* @file_list: list of available debugfs files.
* @file_mutex: protects file_list.
* @cb_list: list of available CBs.
* @cb_spinlock: protects cb_list.
* @cs_list: list of available CSs.
* @cs_spinlock: protects cs_list.
* @cs_job_list: list of available CB jobs.
* @cs_job_spinlock: protects cs_job_list.
* @userptr_list: list of available userptrs (virtual memory chunk descriptor).
* @userptr_spinlock: protects userptr_list.
* @ctx_mem_hash_list: list of available contexts with MMU mappings.
* @ctx_mem_hash_spinlock: protects cb_list.
* @addr: next address to read/write from/to in read/write32.
* @mmu_addr: next virtual address to translate to physical address in mmu_show.
* @mmu_asid: ASID to use while translating in mmu_show.
* @i2c_bus: generic u8 debugfs file for bus value to use in i2c_data_read.
* @i2c_bus: generic u8 debugfs file for address value to use in i2c_data_read.
* @i2c_bus: generic u8 debugfs file for register value to use in i2c_data_read.
*/
struct hl_dbg_device_entry {
struct dentry *root;
struct hl_device *hdev;
struct hl_debugfs_entry *entry_arr;
struct list_head file_list;
struct mutex file_mutex;
struct list_head cb_list;
spinlock_t cb_spinlock;
struct list_head cs_list;
spinlock_t cs_spinlock;
struct list_head cs_job_list;
spinlock_t cs_job_spinlock;
struct list_head userptr_list;
spinlock_t userptr_spinlock;
struct list_head ctx_mem_hash_list;
spinlock_t ctx_mem_hash_spinlock;
u64 addr;
u64 mmu_addr;
u32 mmu_asid;
u8 i2c_bus;
u8 i2c_addr;
u8 i2c_reg;
};
/* /*
* DEVICES * DEVICES
*/ */
@ -953,6 +1045,7 @@ struct hl_device_reset_work {
* @hwmon_dev: H/W monitor device. * @hwmon_dev: H/W monitor device.
* @pm_mng_profile: current power management profile. * @pm_mng_profile: current power management profile.
* @hl_chip_info: ASIC's sensors information. * @hl_chip_info: ASIC's sensors information.
* @hl_debugfs: device's debugfs manager.
* @cb_pool: list of preallocated CBs. * @cb_pool: list of preallocated CBs.
* @cb_pool_lock: protects the CB pool. * @cb_pool_lock: protects the CB pool.
* @user_ctx: current user context executing. * @user_ctx: current user context executing.
@ -1018,6 +1111,8 @@ struct hl_device {
enum hl_pm_mng_profile pm_mng_profile; enum hl_pm_mng_profile pm_mng_profile;
struct hwmon_chip_info *hl_chip_info; struct hwmon_chip_info *hl_chip_info;
struct hl_dbg_device_entry hl_debugfs;
struct list_head cb_pool; struct list_head cb_pool;
spinlock_t cb_pool_lock; spinlock_t cb_pool_lock;
@ -1255,6 +1350,100 @@ void hl_set_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr,
u64 hl_get_max_power(struct hl_device *hdev); u64 hl_get_max_power(struct hl_device *hdev);
void hl_set_max_power(struct hl_device *hdev, u64 value); void hl_set_max_power(struct hl_device *hdev, u64 value);
#ifdef CONFIG_DEBUG_FS
void hl_debugfs_init(void);
void hl_debugfs_fini(void);
void hl_debugfs_add_device(struct hl_device *hdev);
void hl_debugfs_remove_device(struct hl_device *hdev);
void hl_debugfs_add_file(struct hl_fpriv *hpriv);
void hl_debugfs_remove_file(struct hl_fpriv *hpriv);
void hl_debugfs_add_cb(struct hl_cb *cb);
void hl_debugfs_remove_cb(struct hl_cb *cb);
void hl_debugfs_add_cs(struct hl_cs *cs);
void hl_debugfs_remove_cs(struct hl_cs *cs);
void hl_debugfs_add_job(struct hl_device *hdev, struct hl_cs_job *job);
void hl_debugfs_remove_job(struct hl_device *hdev, struct hl_cs_job *job);
void hl_debugfs_add_userptr(struct hl_device *hdev, struct hl_userptr *userptr);
void hl_debugfs_remove_userptr(struct hl_device *hdev,
struct hl_userptr *userptr);
void hl_debugfs_add_ctx_mem_hash(struct hl_device *hdev, struct hl_ctx *ctx);
void hl_debugfs_remove_ctx_mem_hash(struct hl_device *hdev, struct hl_ctx *ctx);
#else
static inline void __init hl_debugfs_init(void)
{
}
static inline void hl_debugfs_fini(void)
{
}
static inline void hl_debugfs_add_device(struct hl_device *hdev)
{
}
static inline void hl_debugfs_remove_device(struct hl_device *hdev)
{
}
static inline void hl_debugfs_add_file(struct hl_fpriv *hpriv)
{
}
static inline void hl_debugfs_remove_file(struct hl_fpriv *hpriv)
{
}
static inline void hl_debugfs_add_cb(struct hl_cb *cb)
{
}
static inline void hl_debugfs_remove_cb(struct hl_cb *cb)
{
}
static inline void hl_debugfs_add_cs(struct hl_cs *cs)
{
}
static inline void hl_debugfs_remove_cs(struct hl_cs *cs)
{
}
static inline void hl_debugfs_add_job(struct hl_device *hdev,
struct hl_cs_job *job)
{
}
static inline void hl_debugfs_remove_job(struct hl_device *hdev,
struct hl_cs_job *job)
{
}
static inline void hl_debugfs_add_userptr(struct hl_device *hdev,
struct hl_userptr *userptr)
{
}
static inline void hl_debugfs_remove_userptr(struct hl_device *hdev,
struct hl_userptr *userptr)
{
}
static inline void hl_debugfs_add_ctx_mem_hash(struct hl_device *hdev,
struct hl_ctx *ctx)
{
}
static inline void hl_debugfs_remove_ctx_mem_hash(struct hl_device *hdev,
struct hl_ctx *ctx)
{
}
#endif
/* IOCTLs */ /* IOCTLs */
long hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); long hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
int hl_cb_ioctl(struct hl_fpriv *hpriv, void *data); int hl_cb_ioctl(struct hl_fpriv *hpriv, void *data);

View File

@ -146,6 +146,8 @@ int hl_device_open(struct inode *inode, struct file *filp)
*/ */
hl_device_set_frequency(hdev, PLL_HIGH); hl_device_set_frequency(hdev, PLL_HIGH);
hl_debugfs_add_file(hpriv);
return 0; return 0;
out_err: out_err:
@ -413,17 +415,20 @@ static int __init hl_init(void)
goto remove_major; goto remove_major;
} }
hl_debugfs_init();
rc = pci_register_driver(&hl_pci_driver); rc = pci_register_driver(&hl_pci_driver);
if (rc) { if (rc) {
pr_err("failed to register pci device\n"); pr_err("failed to register pci device\n");
goto remove_class; goto remove_debugfs;
} }
pr_debug("driver loaded\n"); pr_debug("driver loaded\n");
return 0; return 0;
remove_class: remove_debugfs:
hl_debugfs_fini();
class_destroy(hl_class); class_destroy(hl_class);
remove_major: remove_major:
unregister_chrdev_region(MKDEV(hl_major, 0), HL_MAX_MINORS); unregister_chrdev_region(MKDEV(hl_major, 0), HL_MAX_MINORS);
@ -437,6 +442,13 @@ static void __exit hl_exit(void)
{ {
pci_unregister_driver(&hl_pci_driver); pci_unregister_driver(&hl_pci_driver);
/*
* Removing debugfs must be after all devices or simulator devices
* have been removed because otherwise we get a bug in the
* debugfs module for referencing NULL objects
*/
hl_debugfs_fini();
class_destroy(hl_class); class_destroy(hl_class);
unregister_chrdev_region(MKDEV(hl_major, 0), HL_MAX_MINORS); unregister_chrdev_region(MKDEV(hl_major, 0), HL_MAX_MINORS);

View File

@ -1290,6 +1290,8 @@ int hl_pin_host_memory(struct hl_device *hdev, u64 addr, u32 size,
goto free_sgt; goto free_sgt;
} }
hl_debugfs_add_userptr(hdev, userptr);
return 0; return 0;
free_sgt: free_sgt:
@ -1315,6 +1317,8 @@ int hl_unpin_host_memory(struct hl_device *hdev, struct hl_userptr *userptr)
{ {
struct page **pages; struct page **pages;
hl_debugfs_remove_userptr(hdev, userptr);
if (userptr->dma_mapped) if (userptr->dma_mapped)
hdev->asic_funcs->hl_dma_unmap_sg(hdev, hdev->asic_funcs->hl_dma_unmap_sg(hdev,
userptr->sgt->sgl, userptr->sgt->sgl,
@ -1476,6 +1480,8 @@ int hl_vm_ctx_init_with_ranges(struct hl_ctx *ctx, u64 host_range_start,
goto dram_vm_err; goto dram_vm_err;
} }
hl_debugfs_add_ctx_mem_hash(hdev, ctx);
return 0; return 0;
dram_vm_err: dram_vm_err:
@ -1598,6 +1604,8 @@ void hl_vm_ctx_fini(struct hl_ctx *ctx)
struct hlist_node *tmp_node; struct hlist_node *tmp_node;
int i; int i;
hl_debugfs_remove_ctx_mem_hash(hdev, ctx);
if (!hash_empty(ctx->mem_hash)) if (!hash_empty(ctx->mem_hash))
dev_notice(hdev->dev, "ctx is freed while it has va in use\n"); dev_notice(hdev->dev, "ctx is freed while it has va in use\n");