mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	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
	 Oded Gabbay
						Oded Gabbay