forked from Minki/linux
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:
parent
d8dd7b0a81
commit
c216477363
126
Documentation/ABI/testing/debugfs-driver-habanalabs
Normal file
126
Documentation/ABI/testing/debugfs-driver-habanalabs
Normal 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
|
@ -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_submission.o mmu.o
|
||||
|
||||
habanalabs-$(CONFIG_DEBUG_FS) += debugfs.o
|
||||
|
||||
include $(src)/goya/Makefile
|
||||
habanalabs-y += $(HL_GOYA_FILES)
|
||||
|
@ -38,6 +38,8 @@ static void cb_release(struct kref *ref)
|
||||
cb = container_of(ref, struct hl_cb, refcount);
|
||||
hdev = cb->hdev;
|
||||
|
||||
hl_debugfs_remove_cb(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 <<= PAGE_SHIFT;
|
||||
|
||||
hl_debugfs_add_cb(cb);
|
||||
|
||||
return 0;
|
||||
|
||||
release_cb:
|
||||
|
@ -149,6 +149,8 @@ static void free_job(struct hl_device *hdev, struct hl_cs_job *job)
|
||||
list_del(&job->cs_node);
|
||||
spin_unlock(&cs->job_lock);
|
||||
|
||||
hl_debugfs_remove_job(hdev, job);
|
||||
|
||||
if (job->ext_queue)
|
||||
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);
|
||||
|
||||
if (cs->timedout)
|
||||
@ -480,6 +488,8 @@ static int _hl_cs_ioctl(struct hl_fpriv *hpriv, void __user *chunks,
|
||||
|
||||
*cs_seq = cs->sequence;
|
||||
|
||||
hl_debugfs_add_cs(cs);
|
||||
|
||||
/* Validate ALL the CS chunks before submitting the CS */
|
||||
for (i = 0, parse_cnt = 0 ; i < num_chunks ; i++, parse_cnt++) {
|
||||
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)
|
||||
cs_get(cs);
|
||||
|
||||
hl_debugfs_add_job(hdev, job);
|
||||
|
||||
rc = cs_parser(hpriv, job);
|
||||
if (rc) {
|
||||
dev_err(hdev->dev,
|
||||
|
1072
drivers/misc/habanalabs/debugfs.c
Normal file
1072
drivers/misc/habanalabs/debugfs.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,8 @@ static void hpriv_release(struct kref *ref)
|
||||
|
||||
put_pid(hpriv->taskpid);
|
||||
|
||||
hl_debugfs_remove_file(hpriv);
|
||||
|
||||
mutex_destroy(&hpriv->restore_phase_mutex);
|
||||
|
||||
kfree(hpriv);
|
||||
@ -834,6 +836,8 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
|
||||
goto free_cb_pool;
|
||||
}
|
||||
|
||||
hl_debugfs_add_device(hdev);
|
||||
|
||||
if (hdev->asic_funcs->get_hw_state(hdev) == HL_DEVICE_HW_STATE_DIRTY) {
|
||||
dev_info(hdev->dev,
|
||||
"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);
|
||||
|
||||
hl_debugfs_remove_device(hdev);
|
||||
|
||||
hl_sysfs_fini(hdev);
|
||||
|
||||
/*
|
||||
|
@ -4370,6 +4370,8 @@ int goya_context_switch(struct hl_device *hdev, u32 asid)
|
||||
job->user_cb_size = cb_size;
|
||||
job->hw_queue_id = GOYA_QUEUE_ID_DMA_0;
|
||||
|
||||
hl_debugfs_add_job(hdev, job);
|
||||
|
||||
parser.ctx_id = HL_KERNEL_ASID_ID;
|
||||
parser.cs_sequence = 0;
|
||||
parser.job_id = job->id;
|
||||
@ -4402,6 +4404,7 @@ int goya_context_switch(struct hl_device *hdev, u32 asid)
|
||||
|
||||
free_job:
|
||||
hl_userptr_delete_list(hdev, &job->userptr_list);
|
||||
hl_debugfs_remove_job(hdev, job);
|
||||
kfree(job);
|
||||
cb->cs_cnt--;
|
||||
|
||||
@ -4432,6 +4435,106 @@ void goya_restore_phase_topology(struct hl_device *hdev)
|
||||
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)
|
||||
{
|
||||
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->hw_queue_id = GOYA_QUEUE_ID_DMA_0;
|
||||
|
||||
hl_debugfs_add_job(hdev, job);
|
||||
|
||||
parser.ctx_id = HL_KERNEL_ASID_ID;
|
||||
parser.cs_sequence = 0;
|
||||
parser.job_id = job->id;
|
||||
@ -4808,6 +4913,7 @@ static int goya_mmu_clear_pgt_range(struct hl_device *hdev)
|
||||
|
||||
free_job:
|
||||
hl_userptr_delete_list(hdev, &job->userptr_list);
|
||||
hl_debugfs_remove_job(hdev, job);
|
||||
kfree(job);
|
||||
cb->cs_cnt--;
|
||||
|
||||
@ -5222,6 +5328,8 @@ static const struct hl_asic_funcs goya_funcs = {
|
||||
.update_eq_ci = goya_update_eq_ci,
|
||||
.context_switch = goya_context_switch,
|
||||
.restore_phase_topology = goya_restore_phase_topology,
|
||||
.debugfs_read32 = goya_debugfs_read32,
|
||||
.debugfs_write32 = goya_debugfs_write32,
|
||||
.add_device_attr = goya_add_device_attr,
|
||||
.handle_eqe = goya_handle_eqe,
|
||||
.set_pll_profile = goya_set_pll_profile,
|
||||
|
@ -165,6 +165,10 @@ struct goya_device {
|
||||
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_send_cpu_message(struct hl_device *hdev, u32 *msg, u16 len,
|
||||
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);
|
||||
void goya_set_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr,
|
||||
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_add_device_attr(struct hl_device *hdev,
|
||||
struct attribute_group *dev_attr_grp);
|
||||
|
@ -238,6 +238,7 @@ struct hl_cb_mgr {
|
||||
* @refcount: reference counter for usage of the CB.
|
||||
* @hdev: pointer to device this CB belongs to.
|
||||
* @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.
|
||||
* @kernel_address: Holds the CB's kernel virtual address.
|
||||
* @bus_address: Holds the CB's DMA address.
|
||||
@ -253,6 +254,7 @@ struct hl_cb {
|
||||
struct kref refcount;
|
||||
struct hl_device *hdev;
|
||||
spinlock_t lock;
|
||||
struct list_head debugfs_list;
|
||||
struct list_head pool_list;
|
||||
u64 kernel_address;
|
||||
dma_addr_t bus_address;
|
||||
@ -453,6 +455,8 @@ enum hl_pll_frequency {
|
||||
* @update_eq_ci: update event queue CI.
|
||||
* @context_switch: called upon ASID context switch.
|
||||
* @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.
|
||||
* @handle_eqe: handle event queue entry (IRQ) from ArmCP.
|
||||
* @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);
|
||||
int (*context_switch)(struct hl_device *hdev, u32 asid);
|
||||
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,
|
||||
struct attribute_group *dev_attr_grp);
|
||||
void (*handle_eqe)(struct hl_device *hdev,
|
||||
@ -584,6 +590,7 @@ struct hl_va_range {
|
||||
* @mem_hash_lock: protects the mem_hash.
|
||||
* @mmu_lock: protects the MMU page tables. Any change to the PGT, modifing the
|
||||
* 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
|
||||
* to user so user could inquire about CS. It is used as
|
||||
* index to cs_pending array.
|
||||
@ -608,6 +615,7 @@ struct hl_ctx {
|
||||
struct hl_va_range dram_va_range;
|
||||
struct mutex mem_hash_lock;
|
||||
struct mutex mmu_lock;
|
||||
struct list_head debugfs_list;
|
||||
u64 cs_sequence;
|
||||
spinlock_t cs_lock;
|
||||
atomic64_t dram_phys_mem;
|
||||
@ -666,6 +674,7 @@ struct hl_userptr {
|
||||
* @fence: pointer to the fence object of this CS.
|
||||
* @work_tdr: delayed work node for TDR.
|
||||
* @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.
|
||||
* @submitted: true if CS was submitted to H/W.
|
||||
* @completed: true if CS was completed by device.
|
||||
@ -683,6 +692,7 @@ struct hl_cs {
|
||||
struct dma_fence *fence;
|
||||
struct delayed_work work_tdr;
|
||||
struct list_head mirror_node;
|
||||
struct list_head debugfs_list;
|
||||
u64 sequence;
|
||||
u8 submitted;
|
||||
u8 completed;
|
||||
@ -701,6 +711,7 @@ struct hl_cs {
|
||||
* @finish_work: workqueue object to run when job is completed.
|
||||
* @userptr_list: linked-list of userptr mappings that belong to this job and
|
||||
* wait for completion.
|
||||
* @debugfs_list: node in debugfs list of command submission jobs.
|
||||
* @id: the id of this job inside a CS.
|
||||
* @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.
|
||||
@ -714,6 +725,7 @@ struct hl_cs_job {
|
||||
struct hl_cb *patched_cb;
|
||||
struct work_struct finish_work;
|
||||
struct list_head userptr_list;
|
||||
struct list_head debugfs_list;
|
||||
u32 id;
|
||||
u32 hw_queue_id;
|
||||
u32 user_cb_size;
|
||||
@ -844,6 +856,7 @@ struct hl_vm {
|
||||
* @ctx: current executing context.
|
||||
* @ctx_mgr: context manager to handle multiple context 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.
|
||||
* @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_mgr ctx_mgr;
|
||||
struct hl_cb_mgr cb_mgr;
|
||||
struct list_head debugfs_list;
|
||||
struct kref refcount;
|
||||
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
|
||||
*/
|
||||
@ -953,6 +1045,7 @@ struct hl_device_reset_work {
|
||||
* @hwmon_dev: H/W monitor device.
|
||||
* @pm_mng_profile: current power management profile.
|
||||
* @hl_chip_info: ASIC's sensors information.
|
||||
* @hl_debugfs: device's debugfs manager.
|
||||
* @cb_pool: list of preallocated CBs.
|
||||
* @cb_pool_lock: protects the CB pool.
|
||||
* @user_ctx: current user context executing.
|
||||
@ -1018,6 +1111,8 @@ struct hl_device {
|
||||
enum hl_pm_mng_profile pm_mng_profile;
|
||||
struct hwmon_chip_info *hl_chip_info;
|
||||
|
||||
struct hl_dbg_device_entry hl_debugfs;
|
||||
|
||||
struct list_head cb_pool;
|
||||
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);
|
||||
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 */
|
||||
long hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||
int hl_cb_ioctl(struct hl_fpriv *hpriv, void *data);
|
||||
|
@ -146,6 +146,8 @@ int hl_device_open(struct inode *inode, struct file *filp)
|
||||
*/
|
||||
hl_device_set_frequency(hdev, PLL_HIGH);
|
||||
|
||||
hl_debugfs_add_file(hpriv);
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
@ -413,17 +415,20 @@ static int __init hl_init(void)
|
||||
goto remove_major;
|
||||
}
|
||||
|
||||
hl_debugfs_init();
|
||||
|
||||
rc = pci_register_driver(&hl_pci_driver);
|
||||
if (rc) {
|
||||
pr_err("failed to register pci device\n");
|
||||
goto remove_class;
|
||||
goto remove_debugfs;
|
||||
}
|
||||
|
||||
pr_debug("driver loaded\n");
|
||||
|
||||
return 0;
|
||||
|
||||
remove_class:
|
||||
remove_debugfs:
|
||||
hl_debugfs_fini();
|
||||
class_destroy(hl_class);
|
||||
remove_major:
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
unregister_chrdev_region(MKDEV(hl_major, 0), HL_MAX_MINORS);
|
||||
|
||||
|
@ -1290,6 +1290,8 @@ int hl_pin_host_memory(struct hl_device *hdev, u64 addr, u32 size,
|
||||
goto free_sgt;
|
||||
}
|
||||
|
||||
hl_debugfs_add_userptr(hdev, userptr);
|
||||
|
||||
return 0;
|
||||
|
||||
free_sgt:
|
||||
@ -1315,6 +1317,8 @@ int hl_unpin_host_memory(struct hl_device *hdev, struct hl_userptr *userptr)
|
||||
{
|
||||
struct page **pages;
|
||||
|
||||
hl_debugfs_remove_userptr(hdev, userptr);
|
||||
|
||||
if (userptr->dma_mapped)
|
||||
hdev->asic_funcs->hl_dma_unmap_sg(hdev,
|
||||
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;
|
||||
}
|
||||
|
||||
hl_debugfs_add_ctx_mem_hash(hdev, ctx);
|
||||
|
||||
return 0;
|
||||
|
||||
dram_vm_err:
|
||||
@ -1598,6 +1604,8 @@ void hl_vm_ctx_fini(struct hl_ctx *ctx)
|
||||
struct hlist_node *tmp_node;
|
||||
int i;
|
||||
|
||||
hl_debugfs_remove_ctx_mem_hash(hdev, ctx);
|
||||
|
||||
if (!hash_empty(ctx->mem_hash))
|
||||
dev_notice(hdev->dev, "ctx is freed while it has va in use\n");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user