diff --git a/drivers/media/platform/tegra/camera/fusa-capture/capture-common.c b/drivers/media/platform/tegra/camera/fusa-capture/capture-common.c index 8782ad63..82ab559c 100644 --- a/drivers/media/platform/tegra/camera/fusa-capture/capture-common.c +++ b/drivers/media/platform/tegra/camera/fusa-capture/capture-common.c @@ -62,13 +62,19 @@ struct capture_mapping { }; /** - * @brief Determine whether all the bits of @a other are set in @a self. + * @brief Determines if all flags in @a other are set in @a self. * - * @param[in] self Bitmask flag to be compared - * @param[in] other Bitmask value(s) to compare + * This function performs the following operations: + * - Computes the bitwise AND of @a self and @a other. + * - Compares the result with @a other to determine compatibility. * - * @retval true compatible - * @retval false not compatible + * @param[in] self The source flags to be checked. + * Valid range: [0 .. UINT32_MAX]. + * @param[in] other The flags to verify against @a self. + * Valid range: [0 .. UINT32_MAX]. + * + * @retval true All flags in @a other are set in @a self. + * @retval false Not all flags in @a other are set in @a self. */ static inline bool flag_compatible( unsigned int self, @@ -78,12 +84,20 @@ static inline bool flag_compatible( } /** - * @brief Determine whether BUFFER_RDWR is set in @a flag. + * @brief Extracts the access mode from the provided flag. * - * @param[in] flag Bitmask flag to be compared + * This function performs the following operations: + * - Applies a bitmask to the input flag to isolate the access mode bits using + * @ref BUFFER_RDWR. * - * @retval true BUFFER_RDWR set - * @retval false BUFFER_RDWR not set + * @param[in] flag The input flags containing access mode information. + * Valid range: [0 .. UINT32_MAX]. + * + * @retval 0 No access mode flags are set. + * @retval @ref BUFFER_READ Read access mode is set. + * @retval @ref BUFFER_WRITE Write access mode is set. + * @retval (@ref BUFFER_READ | @ref BUFFER_WRITE) Both read and write access + * modes are set. */ static inline unsigned int flag_access_mode( unsigned int flag) @@ -92,11 +106,22 @@ static inline unsigned int flag_access_mode( } /** - * @brief Map capture common buffer access flag to a Linux dma_data_direction. + * @brief Determines the DMA data direction based on the provided flag. * - * @param[in] flag Bitmask access flag of capture common buffer + * This function performs the following operations: + * - Calls @ref flag_access_mode() to determine the access mode from @a flag. + * - Uses the access mode to index into a predefined array mapping to the corresponding + * @ref dma_data_direction. * - * @returns @ref dma_data_direction mapping + * @param[in] flag Flag indicating the desired DMA data direction. + * Valid range: [0 .. UINT32_MAX]. + * + * @retval DMA_BIDIRECTIONAL Returned when @ref flag_access_mode() indicates + * bidirectional access. + * @retval DMA_TO_DEVICE Returned when @ref flag_access_mode() indicates + * write access. + * @retval DMA_FROM_DEVICE Returned when @ref flag_access_mode() indicates + * read access. */ static inline enum dma_data_direction flag_dma_direction( unsigned int flag) @@ -112,11 +137,36 @@ static inline enum dma_data_direction flag_dma_direction( } /** - * @brief Retrieve the scatterlist IOVA address of the capture surface mapping. + * @brief Maps a capture mapping and memory offset to a DMA IOVA address. * - * @param[in] pin The capture_mapping of the buffer + * This inline function calculates the I/O Virtual Address (IOVA) based on a given + * capture mapping and a memory offset. The implementation varies depending + * on the Linux kernel version: * - * @returns Physical address of scatterlist mapping + * - **For Linux versions below 5.10.0:** + * - Retrieves the DMA address from the scatter-gather table using @ref sg_dma_address(). + * - If @ref sg_dma_address() returns 0, obtains the physical address using @ref sg_phys(). + * - Adds the provided @a mem_offset to the obtained address. + * + * - **For Linux versions 5.10.0 and above:** + * - Traverses the scatterlist using @ref for_each_sgtable_dma_sg(). + * - For each scatterlist entry, obtains the length using @ref sg_dma_len(). + * - Retrieves the address using @ref sg_dma_address() or @ref sg_phys(). + * - Checks for overflow using @ref check_add_overflow(). + * - If an overflow is detected or no suitable scatterlist entry is found, returns 0. + * + * @param[in] pin Pointer to the @ref capture_mapping structure. + * Valid value: non-null. + * @param[in] mem_offset Memory offset to be added to the base address. + * Valid range: [0 .. UINT64_MAX]. + * + * @retval (dma_addr_t) The calculated IOVA address based on @a pin and @a mem_offset. + * @retval 0 Indicates either: + * - An overflow occurred during address calculation as detected by + * @ref check_add_overflow(). + * - No suitable scatterlist entry was found using + * @ref for_each_sgtable_dma_sg(), @ref sg_phys(), or + * @ref sg_dma_address(). */ static inline dma_addr_t mapping_iova( const struct capture_mapping *pin, @@ -152,11 +202,16 @@ static inline dma_addr_t mapping_iova( } /** - * @brief Retrieve the dma_buf pointer of a capture surface mapping. + * @brief Retrieves the DMA buffer from a capture mapping. * - * @param[in] pin The capture_mapping of the buffer + * This function performs the following operations: + * - Accesses the @a buf member of the provided @ref capture_mapping structure. * - * @returns Pointer to the capture_mapping @ref dma_buf + * @param[in] pin Pointer to the @ref capture_mapping structure. + * Valid value: non-null. + * + * @retval (dma_buf *) Pointer to the @ref dma_buf structure contained in @a pin. + * @retval NULL If the @a buf member in @a pin is not set. */ static inline struct dma_buf *mapping_buf( const struct capture_mapping *pin) @@ -165,13 +220,17 @@ static inline struct dma_buf *mapping_buf( } /** - * @brief Determine whether BUFFER_ADD is set in the capture surface mapping's - * access flag. + * @brief Checks if the mapping is preserved based on the BUFFER_ADD flag. * - * @param[in] pin The capture_mapping of the buffer + * This function performs the following operations: + * - Validates the input parameter. + * - Checks if the BUFFER_ADD flag is set in the provided @ref capture_mapping structure. * - * @retval true BUFFER_ADD set - * @retval false BUFFER_ADD not set + * @param[in] pin Pointer to the @ref capture_mapping structure. + * Valid value: non-null. + * + * @retval true Indicates that the BUFFER_ADD flag is set, preserving the mapping. + * @retval false Indicates that the BUFFER_ADD flag is not set, not preserving the mapping. */ static inline bool mapping_preserved( const struct capture_mapping *pin) @@ -180,14 +239,24 @@ static inline bool mapping_preserved( } /** - * @brief Set or unset the BUFFER_ADD bit in the capture surface mapping's - * access flag, and correspondingly increment or decrement the mapping's refcnt. + * @brief Sets or clears the BUFFER_ADD flag and updates the reference count. * - * @param[in] pin The capture_mapping of the buffer - * @param[in] val The capture_mapping of the buffer + * This inline function modifies the BUFFER_ADD flag within the provided + * @ref capture_mapping structure based on the boolean value provided. It also + * updates the reference count accordingly: * - * @retval true BUFFER_ADD set - * @retval false BUFFER_ADD not set + * - If @a val is `true`: + * - Sets the BUFFER_ADD flag in the @a pin structure. + * - Increments the reference count using @ref atomic_inc(). + * + * - If @a val is `false`: + * - Clears the BUFFER_ADD flag in the @a pin structure. + * - Decrements the reference count using @ref atomic_dec(). + * + * @param[in, out] pin Pointer to the @ref capture_mapping structure. + * Valid value: non-null. + * @param[in] val lean value indicating whether to preserve mapping. + * Valid value: `true` or `false`. */ static inline void set_mapping_preservation( struct capture_mapping *pin, @@ -203,16 +272,34 @@ static inline void set_mapping_preservation( } /** - * @brief Iteratively search a capture buffer management table to find the entry - * with @a buf, and @a flag bits set in the capture mapping. + * @brief Searches for a capture mapping in the buffer table matching the specified buffer and flag. * - * On success, the capture mapping is incremented by one if it is non-zero. + * This function performs the following operations: + * - Acquires a read lock on the buffer table using @ref read_lock(). + * - Iterates over possible hash entries using @ref hash_for_each_possible() to find a + * matching @ref capture_mapping. + * - For each entry, checks if the buffer matches and the flags are compatible using + * @ref flag_compatible(). + * - If a match is found, attempts to increment the reference count using + * @ref atomic_inc_not_zero(). + * - If the reference count is successfully incremented, releases the read lock using + * @ref read_unlock() and returns the matching @ref capture_mapping. + * - Releases the read lock using @ref read_unlock() if no matching mapping is found + * or the reference count cannot be incremented. * - * @param[in] tab The capture buffer management table - * @param[in] buf The mapping dma_buf pointer to match - * @param[in] flag The mapping bitmask access flag to compare + * @param[in] tab Pointer to the @ref capture_buffer_table structure. + * Valid value: non-null. + * @param[in] buf Pointer to the @ref dma_buf structure to search for. + * Valid value: non-null. + * @param[in] flag Flags to match against the capture mappings. + * Valid range: [0 .. UINT32_MAX]. * - * @returns @ref capture_mapping pointer (success), NULL (failure) + * @retval (capture_mapping *) Pointer to the matching @ref capture_mapping structure if found. + * @retval NULL No matching capture mapping was found or + * @ref atomic_inc_not_zero() failed, influenced by + * @ref read_lock(), @ref hash_for_each_possible(), + * @ref flag_compatible(), @ref atomic_inc_not_zero() or + * @ref read_unlock(). */ static struct capture_mapping *find_mapping( struct capture_buffer_table *tab, @@ -243,14 +330,41 @@ static struct capture_mapping *find_mapping( } /** - * @brief Add an NvRm buffer to the buffer management table and initialize its - * refcnt to 1. + * @brief Retrieves or creates a capture mapping for a given file descriptor and flags. * - * @param[in] tab The capture buffer management table - * @param[in] fd The NvRm handle - * @param[in] flag The mapping bitmask access flag to set + * This function performs the following operations: + * - Checks if the input parameter @a tab is non-null. + * - Calls @ref dma_buf_get() to obtain a @ref dma_buf structure for the provided file + * descriptor @a fd. + * - Calls @ref find_mapping() to search for an existing @ref capture_mapping that matches + * the buffer @a buf and flags @a flag. + * - If a matching mapping is found, calls @ref dma_buf_put() to release the buffer and returns + * the existing mapping. + * - Allocates a new @ref capture_mapping structure using @ref kmem_cache_alloc(). + * - Calls @ref dma_buf_attach() to attach the buffer @a buf to the device associated with + * @a tab. + * - If @ref dma_buf_attach() fails, frees the allocated mapping with @ref kmem_cache_free(). + * - Determines the DMA data direction by calling @ref flag_dma_direction() with @a flag. + * - Calls @ref dma_buf_map_attachment() to map the DMA buffer. + * - If @ref dma_buf_map_attachment() fails, detaches the buffer with @ref dma_buf_detach(). + * - Initializes the @ref capture_mapping structure with the provided flags and buffer. + * - Sets the reference count to 1 and initializes the hash node. + * - Acquires a write lock on the buffer table using @ref write_lock(). + * - Adds the new mapping to the buffer table's hash using @ref hash_add(). + * - Releases the write lock using @ref write_unlock(). * - * @returns @ref capture_mapping pointer (success), PTR_ERR (failure) + * @param[in] tab Pointer to the @ref capture_buffer_table structure. + * Valid value: non-null. + * @param[in] fd File descriptor associated with the DMA buffer. + * Valid range: [0 .. UINT32_MAX]. + * @param[in] flag Flags indicating the desired DMA data direction. + * Valid range: [0 .. UINT32_MAX]. + * + * @retval (capture_mapping *) Pointer to the matching or newly created @ref capture_mapping. + * @retval @ref ERR_PTR(-EINVAL) If @a tab is `NULL`. + * @retval @ref ERR_CAST(buf) If @ref dma_buf_get() fails. + * @retval @ref ERR_PTR(-ENOMEM) If memory allocation via @ref kmem_cache_alloc() fails. + * @retval @ref ERR_PTR() If @ref dma_buf_attach() or @ref dma_buf_map_attachment() fails. */ static struct capture_mapping *get_mapping( struct capture_buffer_table *tab, @@ -318,6 +432,24 @@ err0: return err; } +/** + * @brief Creates and initializes a capture buffer table for the specified device. + * + * This function performs the following operations: + * - Allocates memory for a @ref capture_buffer_table structure using @ref kmalloc(). + * - Initializes a memory cache for @ref capture_mapping structures using @ref KMEM_CACHE(). + * - If @ref KMEM_CACHE() fails, frees the allocated table using @ref kfree(). + * - Sets the device pointer within the table to the provided @a dev. + * - Initializes the hash table using @ref hash_init(). + * - Initializes the read-write lock using @ref rwlock_init(). + * + * @param[in] dev Pointer to the @ref device structure. + * Valid value: non-null. + * + * @retval (capture_buffer_table *) Pointer to the newly created @ref capture_buffer_table. + * @retval NULL If memory allocation via @ref kmalloc() or cache creation via + * @ref KMEM_CACHE() fails. + */ struct capture_buffer_table *create_buffer_table( struct device *dev) { @@ -342,6 +474,28 @@ struct capture_buffer_table *create_buffer_table( } EXPORT_SYMBOL_GPL(create_buffer_table); +/** + * @brief Destroys and frees the specified capture buffer table. + * + * This function performs the following operations: + * - Checks if the input parameter @a tab is non-null. + * - Iterates over all capture mappings in the buffer table using + * @ref hash_for_each_safe(). + * - For each @ref capture_mapping: + * - Acquires a write lock on the buffer table using @ref write_lock(). + * - Removes the mapping from the hash table using @ref hash_del(). + * - Releases the write lock using @ref write_unlock(). + * - Unmaps the DMA attachment using @ref dma_buf_unmap_attachment(). + * - Detaches the DMA buffer using @ref dma_buf_detach(). + * - Releases the DMA buffer using @ref dma_buf_put(). + * - Frees the capture mapping structure using @ref kmem_cache_free(). + * - Destroys the memory cache for capture mappings using + * @ref kmem_cache_destroy(). + * - Frees the buffer table using @ref kfree(). + * + * @param[in] tab Pointer to the @ref capture_buffer_table structure. + * Valid value: non-null. + */ void destroy_buffer_table( struct capture_buffer_table *tab) { @@ -387,6 +541,43 @@ EXPORT_SYMBOL_GPL(destroy_buffer_table); static DEFINE_MUTEX(req_lock); +/** + * @brief Requests to add or remove a buffer in the capture buffer table. + * + * This function performs the following operations: + * - Validates the input parameters. + * - Acquires the request mutex lock using @ref mutex_lock(). + * - If adding a buffer: + * - Calls @ref get_mapping() to retrieve the mapping for the given @a memfd and access + * mode obtained from @ref flag_access_mode(). + * - Checks if @ref get_mapping() returned an error using @ref IS_ERR(). + * - Checks if the mapping is already preserved using @ref mapping_preserved(). + * - If removing a buffer: + * - Calls @ref dma_buf_get() to obtain the DMA buffer for the given @a memfd. + * - Checks if @ref dma_buf_get() returned an error using @ref IS_ERR(). + * - Calls @ref find_mapping() to find the corresponding capture mapping. + * - Calls @ref dma_buf_put() to release the DMA buffer reference. + * - Sets the mapping preservation state by calling @ref set_mapping_preservation(). + * - Releases the capture mapping by calling @ref put_mapping(). + * - Releases the request mutex lock using @ref mutex_unlock(). + * + * In case of any errors during the operations, the function ensures that the mutex + * lock is released before returning the error code. + * + * @param[in] tab Pointer to the @ref capture_buffer_table structure. + * Valid value: non-null. + * @param[in] memfd File descriptor associated with the buffer. + * Valid range: [0 .. UINT32_MAX]. + * @param[in] flag Flags indicating the operation to perform. + * Valid range: [0 .. UINT32_MAX]. + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL If the input buffer table @a tab is NULL. + * @retval -EEXIST If attempting to add a buffer that already exists, as determined + * by @ref mapping_preserved(). + * @retval -ENOENT If attempting to remove a buffer that does not exist in the table. + * @retval (int) Errors returned by @ref get_mapping() or @ref dma_buf_get(). + */ int capture_buffer_request( struct capture_buffer_table *tab, uint32_t memfd, @@ -449,6 +640,22 @@ end: } EXPORT_SYMBOL_GPL(capture_buffer_request); +/** + * @brief Adds a buffer to the capture buffer table with read-write permissions. + * + * This function performs the following operations: + * - Calls @ref capture_buffer_request() to request the addition of a buffer identified + * by @a fd to the capture buffer table @a t with flags BUFFER_ADD | BUFFER_RDWR. + * - The flags indicate that the buffer should be added and have read-write access. + * + * @param[in] t Pointer to the @ref capture_buffer_table structure. + * Valid value: non-null. + * @param[in] fd File descriptor representing the buffer to be added. + * Valid range: [0 .. UINT32_MAX]. + * + * @retval 0 Buffer added successfully. + * @retval (int) Errors returned by @ref capture_buffer_request(). + */ int capture_buffer_add( struct capture_buffer_table *t, uint32_t fd) @@ -457,6 +664,30 @@ int capture_buffer_add( } EXPORT_SYMBOL_GPL(capture_buffer_add); +/** + * @brief Releases a capture mapping and cleans up if it is no longer referenced. + * + * This function performs the following operations: + * - Decrements the reference count of the @ref capture_mapping structure using + * @ref atomic_dec_and_test(). + * - If the reference count reaches zero: + * - Checks if the mapping is preserved using @ref mapping_preserved(). + * - If the mapping is preserved, increments the reference count using + * @ref atomic_inc(). + * - Otherwise: + * - Acquires a write lock on the buffer table using @ref write_lock(). + * - Removes the mapping from the hash table using @ref hash_del(). + * - Releases the write lock using @ref write_unlock(). + * - Unmaps the DMA attachment using @ref dma_buf_unmap_attachment(). + * - Detaches the DMA buffer using @ref dma_buf_detach(). + * - Releases the DMA buffer using @ref dma_buf_put(). + * - Frees the capture mapping structure using @ref kmem_cache_free(). + * + * @param[in] t Pointer to the @ref capture_buffer_table structure. + * Valid value: non-null. + * @param[in] pin Pointer to the @ref capture_mapping structure. + * Valid value: non-null. + */ void put_mapping( struct capture_buffer_table *t, struct capture_mapping *pin) @@ -485,6 +716,46 @@ void put_mapping( } EXPORT_SYMBOL_GPL(put_mapping); +/** + * @brief Pins a memory buffer and retrieves its IOVA address based on the handle and offset. + * + * This function performs the following operations: + * - Checks if the memory handle @a mem_handle is zero. + * - Validates that the number of unpins in @a unpins does not exceed + * @ref MAX_PIN_BUFFER_PER_REQUEST. + * - Calls @ref get_mapping() to retrieve or create a @ref capture_mapping based on + * the buffer context @a buf_ctx and memory handle @a mem_handle with flags + * @ref BUFFER_RDWR. + * - Calls @ref mapping_buf() to obtain the @ref dma_buf associated with the mapping. + * - Retrieves the size of the DMA buffer. + * - Validates that the memory offset @a mem_offset is within the bounds of the buffer size. + * - Calls @ref mapping_iova() to compute the IOVA address for the given memory offset. + * - Updates the memory information base address and size using @a meminfo_base_address and + * @a meminfo_size with the computed IOVA and remaining size. + * - Adds the @ref capture_mapping to the @a unpins structure and increments the + * unpins count. + * + * @param[in] buf_ctx Pointer to the @ref capture_buffer_table structure. + * Valid value: non-null. + * @param[in] mem_handle File descriptor associated with the memory buffer. + * Valid range: [1 .. UINT32_MAX]. + * @param[in] mem_offset Memory offset within the buffer. + * Valid range: [0 .. UINT64_MAX]. + * @param[out] meminfo_base_address Pointer to store the IOVA base address. + * Valid value: non-null. + * @param[out] meminfo_size Pointer to store the size of the memory region. + * Valid value: non-null. + * @param[in, out] unpins Pointer to the @ref capture_common_unpins structure. + * Valid value: non-null. + * + * @retval 0 No buffer was processed (mem_handle is zero) or the operation + * succeeded. + * @retval -ENOMEM The number of unpins exceeded @c MAX_PIN_BUFFER_PER_REQUEST. + * Influenced by the check on @p unpins->num_unpins. + * @retval -EINVAL Failed to retrieve a valid mapping using @ref get_mapping(), + * the memory offset is out of bounds, or an invalid IOVA was + * computed using @ref mapping_iova(). + */ int capture_common_pin_and_get_iova(struct capture_buffer_table *buf_ctx, uint32_t mem_handle, uint64_t mem_offset, uint64_t *meminfo_base_address, uint64_t *meminfo_size, @@ -534,6 +805,41 @@ int capture_common_pin_and_get_iova(struct capture_buffer_table *buf_ctx, } EXPORT_SYMBOL_GPL(capture_common_pin_and_get_iova); +/** + * @brief Sets up a progress status notifier by mapping a DMA buffer and initializing + * the notifier structure. + * + * This function performs the following operations: + * - Acquires a DMA buffer reference using @ref dma_buf_get(). + * - Validates that the combined @a buffer_size and @a mem_offset do not exceed the + * maximum allowable size. + * - Checks that the sum of @a buffer_size and @a mem_offset does not exceed the size + * of the DMA buffer. + * - If it does, releases the DMA buffer using @ref dma_buf_put(). + * - Maps the DMA buffer using @ref dma_buf_vmap(). + * - If @ref dma_buf_vmap() fails, releases the DMA buffer using @ref dma_buf_put(). + * - Clears the mapped memory region using @ref memset(). + * - Initializes the @ref capture_common_status_notifier structure with the DMA buffer, + * virtual address, and memory offset. + * + * In case of any errors during the operations, the function ensures that the DMA buffer + * reference is released before returning the error code. + * + * @param[in, out] status_notifier Pointer to the @ref capture_common_status_notifier structure. + * Valid value: non-null. + * @param[in] mem Memory handle representing the buffer. + * Valid range: [0 .. UINT32_MAX]. + * @param[in] buffer_size Size of the buffer to be mapped. + * Valid range: [0 .. UINT32_MAX - mem_offset]. + * @param[in] mem_offset Offset within the buffer. + * Valid range: [0 .. UINT32_MAX]. + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL The combined buffer size and memory offset exceed allowable limits, + * or the memory offset is out of bounds. + * @retval -ENOMEM Failed to map the DMA buffer using @ref dma_buf_vmap(). + * @retval (int) Errors returned by @ref dma_buf_get() or @ref PTR_ERR_OR_ZERO(). + */ int capture_common_setup_progress_status_notifier( struct capture_common_status_notifier *status_notifier, uint32_t mem, @@ -583,6 +889,29 @@ int capture_common_setup_progress_status_notifier( } EXPORT_SYMBOL_GPL(capture_common_setup_progress_status_notifier); +/** + * @brief Releases the progress status notifier by unmapping the DMA buffer and + * clearing the notifier structure. + * + * This function performs the following operations: + * - Retrieves the DMA buffer and virtual address from the provided + * @ref capture_common_status_notifier structure. + * - Initializes the appropriate DMA buffer map structure based on the + * compilation configuration. + * - If NV_LINUX_IOSYS_MAP_H_PRESENT is defined, initializes the @ref iosys_map structure + * calling @ref IOSYS_MAP_INIT_VADDR() given the status notifier virtual address. + * - Else, initializes the @ref dma_buf_map structure using @ref DMA_BUF_MAP_INIT_VADDR(). + * - If the DMA buffer is not NULL: + * - If the virtual address is not NULL, calls @ref dma_buf_vunmap() to unmap the DMA buffer. + * - Calls @ref dma_buf_put() to release the DMA buffer reference. + * - Resets the @ref capture_common_status_notifier structure members to NULL or 0. + * + * @param[in, out] progress_status_notifier Pointer to the + * @ref capture_common_status_notifier structure. + * Valid value: non-null. + * + * @retval 0 Operation completed successfully. + */ int capture_common_release_progress_status_notifier( struct capture_common_status_notifier *progress_status_notifier) { @@ -609,6 +938,30 @@ int capture_common_release_progress_status_notifier( } EXPORT_SYMBOL_GPL(capture_common_release_progress_status_notifier); +/** + * @brief Sets the progress status for a specific buffer slot. + * + * This function performs the following operations: + * - Calculates the status notifier address by adding the memory offset to the virtual address. + * - Validates that the provided @a buffer_slot is within the range of @a buffer_depth. + * - Sanitizes @a buffer_slot using @ref array_index_nospec(). + * - Inserts a memory barrier using @ref wmb() to ensure proper memory ordering. + * - Updates the progress status notifier buffer at the sanitized @a buffer_slot with @a new_val. + * + * @param[in, out] progress_status_notifier Pointer to the + * @ref capture_common_status_notifier structure. + * Valid value: non-null. + * @param[in] buffer_slot Index of the buffer slot to set the status. + * Valid range: [0 .. buffer_depth - 1]. + * @param[in] buffer_depth Total number of buffer slots. + * Valid range: [1 .. UINT32_MAX]. + * @param[in] new_val New value to set in the progress status. + * Valid range: [0 .. UINT8_MAX]. + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL If @a buffer_slot is out of range as validated by @ref array_index_nospec() + * or if the memory offset is invalid. + */ int capture_common_set_progress_status( struct capture_common_status_notifier *progress_status_notifier, uint32_t buffer_slot, @@ -638,6 +991,35 @@ int capture_common_set_progress_status( } EXPORT_SYMBOL_GPL(capture_common_set_progress_status); +/** + * @brief Pins a memory buffer and retrieves its IOVA address and associated data. + * + * This function performs the following operations: + * - Obtains a reference to the DMA buffer using @ref dma_buf_get() with the memory handle @a mem. + * - Attaches the DMA buffer to the device @a dev using @ref dma_buf_attach(). + * - Maps the DMA buffer attachment with bidirectional access using @ref dma_buf_map_attachment(). + * - Checks if the DMA scatter-gather list DMA address is zero using @ref sg_dma_address(). + * - If zero, retrieves the physical address using @ref sg_phys() and updates the DMA address. + * - Maps the DMA buffer into the virtual address space using @ref dma_buf_vmap(). + * - If @ref dma_buf_vmap() fails, sets @ref unpin_data virtual address to NULL. + * - Clears the mapped memory region using @ref memset(). + * - Initializes the @ref capture_common_buf structure with the DMA buffer, virtual address, + * IOVA address, attachment, and scatter-gather table. + * - If any step fails, cleans up by calling @ref capture_common_unpin_memory(). + * + * @param[in] dev Pointer to the @ref device structure. + * Valid value: non-null. + * @param[in] mem Memory handle representing the buffer. + * Valid range: [1 .. UINT32_MAX]. + * @param[in, out] unpin_data Pointer to the @ref capture_common_buf structure to populate. + * Valid value: non-null. + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL If the buffer handle is invalid or buffer offset exceeds buffer size. + * @retval -ENOMEM Failed to map the DMA buffer using @ref dma_buf_vmap(). + * @retval (int) Errors returned by @ref dma_buf_get(), @ref dma_buf_attach(), + * or @ref dma_buf_map_attachment(), as retrieved by @ref PTR_ERR(). + */ int capture_common_pin_memory( struct device *dev, uint32_t mem, @@ -694,6 +1076,30 @@ fail: } EXPORT_SYMBOL_GPL(capture_common_pin_memory); +/** + * @brief Unpins previously pinned memory and performs necessary cleanup. + * + * This function performs the following operations: + * - Initializes a mapping structure based on the presence of + * NV_LINUX_IOSYS_MAP_H_PRESENT. + * - If present, initialize mapping structure by calling @ref IOSYS_MAP_INIT_VADDR() + * with the virtual address of the provided @ref capture_common_buf. + * - Else, initialize mapping structure by calling @ref DMA_BUF_MAP_INIT_VADDR() + * with the virtual address of the provided @ref capture_common_buf. + * - If the virtual address of @a unpin_data is non-null, calls @ref dma_buf_vunmap() + * to unmap the virtual address. + * - If the scatter gather table of @a unpin_data is non-null, calls + * @ref dma_buf_unmap_attachment() to unmap the DMA attachment with the @ref DMA_BIDIRECTIONAL + * flag. + * - If the buffer attattchment of @a unpin_data is non-null, calls @ref dma_buf_detach() + * to detach the DMA buffer from the device. + * - If DMA buffer of @a unpin_data is non-null, calls @ref dma_buf_put() + * to release the DMA buffer. + * - Resets all fields in the @ref capture_common_buf structure to NULL or zero. + * + * @param[in, out] unpin_data Pointer to the @ref capture_common_buf structure to be cleaned up. + * Valid value: non-null. + */ void capture_common_unpin_memory( struct capture_common_buf *unpin_data) { diff --git a/drivers/media/platform/tegra/camera/fusa-capture/capture-isp-channel.c b/drivers/media/platform/tegra/camera/fusa-capture/capture-isp-channel.c index d36e759b..7d4ced8a 100644 --- a/drivers/media/platform/tegra/camera/fusa-capture/capture-isp-channel.c +++ b/drivers/media/platform/tegra/camera/fusa-capture/capture-isp-channel.c @@ -199,19 +199,41 @@ static struct isp_channel_drv *chdrv_; static DEFINE_MUTEX(chdrv_lock); /** - * @brief Open an ISP channel character device node, power on the camera - * subsystem and initialize the channel driver context. + * @brief Opens an ISP channel for the given @a inode and @a file. * - * The act of opening an ISP channel character device node does not entail the + * This function handles the opening of an Image Signal Processor (ISP) channel by performing + * the following steps: + * - Acquires the channel driver lock using @ref mutex_lock_interruptible(). + * - Retrieves the channel number from the provided @ref inode. + * - Validates the availability of the channel driver and the specified channel number. + * - Releases the channel driver lock using @ref mutex_unlock(). + * - Allocates and initializes a new @ref tegra_isp_channel structure. + * - Initializes the capture process by calling @ref isp_capture_init(). + * - Acquires the channel driver lock using @ref mutex_lock(). + * - Registers the channel within the channel driver's channel array. + * - Releases the channel driver lock using @ref mutex_unlock(). + * - Associates the channel with the opened file by setting private data for provided @ref file. + * - Opens the file in a non-seekable mode using @ref nonseekable_open(). + * + * If any step fails, the function performs necessary cleanup, including shutting down the + * capture process by calling @ref isp_capture_shutdown() and freeing allocated memory + * by calling @ref kfree(). + * + * @note The act of opening an ISP channel character device node does not entail the * reservation of an ISP channel, ISP_CAPTURE_SETUP must be called afterwards * to request an allocation by RCE. * - * This is the @a open file operation handler for an ISP channel node. + * @param[in] inode Pointer to the @ref inode structure representing the file inode. + * Valid Value: non-NULL. + * @param[in] file Pointer to the @ref file structure representing the opened file. + * Valid Value: non-NULL. * - * @param[in] inode ISP channel character device inode struct - * @param[in] file ISP channel character device file struct - * - * @returns 0 (success), neg. errno (failure) + * @retval 0 Successfully opened the ISP channel. + * @retval -ENOMEM Memory allocation @ref kzalloc() for the channel failed. + * @retval -ENODEV Channel driver is unavailable or the channel number is invalid. + * @retval -EBUSY The requested channel is already in use. + * @retval -ERESTARTSYS The lock acquisition was interrupted. + * @retval (int) Initialization or file opening failed. */ static int isp_channel_open( struct inode *inode, @@ -270,18 +292,23 @@ init_err: } /** - * @brief Release an ISP channel character device node, power off the camera - * subsystem and free the ISP channel driver context. + * @brief Releases an ISP channel and performs necessary cleanup. * - * Under normal operation, ISP_CAPTURE_RESET followed by ISP_CAPTURE_RELEASE - * should be called before releasing the file handle on the device node. + * This function releases the ISP channel associated with the provided @a file and @a inode. + * It performs the following operations: + * - Calls @ref isp_capture_shutdown() to shut down the ISP capture process. + * - Acquires the channel driver's lock by invoking @ref mutex_lock(). + * - Verifies that the channel being released matches the registered channel using @ref WARN_ON(). + * - Removes the channel from the driver's channel array by setting the corresponding entry to NULL. + * - Releases the channel driver's lock by calling @ref mutex_unlock(). + * - Frees the memory allocated for the channel using @ref kfree(). * - * This is the @a release file operation handler for an ISP channel node. + * @param[in] inode Pointer to the @ref inode structure representing the file's inode. + * Valid Value: non-NULL. + * @param[in] file Pointer to the @ref file structure representing the opened file. + * Valid Value: non-NULL. * - * @param[in] inode ISP channel character device inode struct - * @param[in] file ISP channel character device file struct - * - * @returns 0 + * @retval 0 Successfully released the ISP channel and performed cleanup. */ static int isp_channel_release( struct inode *inode, @@ -320,6 +347,79 @@ static int isp_channel_release( * * @returns 0 (success), neg. errno (failure) */ +/** + * @brief Handles ioctl commands for the ISP channel. + * + * This function performs the following operations: + * - Retrieves the ISP channel associated with the opened file. + * - Validates the existence of the channel. + * - Extracts the ioctl command number using @ref _IOC_NR(). + * - Executes the corresponding operation based on the command number: + * - For ISP_CAPTURE_SETUP: + * - Copies the @ref isp_capture_setup structure from user space using + * @ref copy_from_user(). + * - Calls @ref isp_get_nvhost_device() to obtain the NVHost device. + * - Ensures the ISP device is valid. + * - Invokes @ref isp_capture_setup() with the setup data. + * - For ISP_CAPTURE_RESET: + * - Copies the reset parameter from user space using @ref copy_from_user(). + * - Calls @ref isp_capture_reset() with the reset value. + * - For ISP_CAPTURE_RELEASE: + * - Copies the release parameter from user space using @ref copy_from_user(). + * - Invokes @ref isp_capture_release() to release the capture. + * - For ISP_CAPTURE_GET_INFO: + * - Initializes the @ref isp_capture_info structure. + * - Calls @ref isp_capture_get_info() to retrieve capture information. + * - Copies the information back to user space using @ref copy_to_user(). + * - For ISP_CAPTURE_REQUEST: + * - Copies the capture request data from user space using + * @ref copy_from_user(). + * - Calls @ref isp_capture_request() to process the capture request. + * - For ISP_CAPTURE_STATUS: + * - Copies the timeout value from user space using @ref copy_from_user(). + * - Invokes @ref isp_capture_status() with the timeout. + * - For ISP_CAPTURE_PROGRAM_REQUEST: + * - Copies the program request data from user space using + * @ref copy_from_user(). + * - Calls @ref isp_capture_program_request() to submit the program request. + * - For ISP_CAPTURE_PROGRAM_STATUS: + * - Invokes @ref isp_capture_program_status() to get program status. + * - For ISP_CAPTURE_REQUEST_EX: + * - Copies the extended request data from user space using + * @ref copy_from_user(). + * - Calls @ref isp_capture_request_ex() to submit the extended request. + * - For ISP_CAPTURE_SET_PROGRESS_STATUS_NOTIFIER: + * - Copies the notifier data from user space using + * @ref copy_from_user(). + * - Invokes @ref isp_capture_set_progress_status_notifier() to set the notifier. + * - For ISP_CAPTURE_BUFFER_REQUEST: + * - Copies the buffer request data from user space using + * @ref copy_from_user(). + * - Calls @ref isp_capture_buffer_request() to request buffers. + * - Handles errors by setting appropriate error codes. + * + * @param[in] file Pointer to the @ref file structure representing the opened file. + * Valid Value: non-NULL. + * @param[in] cmd Ioctl command number. + * Valid Range: Defined in @ref ISP_CHANNEL_IOCTLS. + * @param[in] arg Argument for the ioctl command, typically a pointer to user data. + * Valid Value: Depends on @a cmd. + * + * @retval 0 Successfully executed the ioctl command. + * @retval -EINVAL If the channel is invalid or the channel + * device is NULL, potentially due to @ref + * _IOC_NR() or @ref isp_get_nvhost_device(). + * @retval -EFAULT If copying data from/to user space fails + * using @ref copy_from_user() or @ref copy_to_user(). + * @retval -ENOIOCTLCMD If an unknown ioctl command is received. + * @retval (int) Errors returned by @ref isp_capture_setup(), + * @ref isp_capture_reset(), @ref isp_capture_release(), + * @ref isp_capture_get_info(), @ref isp_capture_request(), + * @ref isp_capture_status(), @ref isp_capture_program_request(), + * @ref isp_capture_program_status(), @ref isp_capture_request_ex(), + * @ref isp_capture_set_progress_status_notifier(), + * or @ref isp_capture_buffer_request(). + */ static long isp_channel_ioctl( struct file *file, unsigned int cmd, @@ -501,6 +601,39 @@ static const struct file_operations isp_channel_fops = { static struct class *isp_channel_class; static int isp_channel_major = -1; +/** + * @brief Registers and initializes the ISP channel driver. + * + * This function performs the following operations: + * - Allocates memory for the @ref isp_channel_drv structure with space for + * the specified maximum number of ISP channels using @ref kzalloc(). + * - Initializes the driver structure fields, including setting the platform + * device TO @a ndev and the maximum number of channels to @a max_isp_channels. + * - Initializes the driver mutex lock using @ref mutex_init(). + * - Acquires the global channel driver lock by invoking @ref mutex_lock(). + * - Checks if a channel driver is already registered using @ref WARN_ON(). + * If a driver is already registered, it releases the lock and frees the allocated + * memory with @ref kfree(). + * - Sets the global channel driver reference to the newly allocated driver and + * releases the global lock using @ref mutex_unlock. + * - Validates the ISP channel major number is not negative. + * - Iterates over the number of channels and creates device nodes for each + * channel using @ref device_create(). + * + * @param[in] ndev Pointer to the @ref platform_device structure representing the + * platform device. + * Valid Value: non-NULL. + * @param[in] max_isp_channels Maximum number of ISP channels to support. + * Valid Range: [0 .. UINT32_MAX]. + * + * @retval 0 Successfully registered and initialized the ISP channel driver. + * @retval -ENOMEM If memory allocation for the driver structure fails, + * as indicated by @ref kzalloc(). + * @retval -EBUSY If an ISP channel driver is already registered, detected via + * @ref WARN_ON(). + * @retval -EINVAL If the ISP channel major number is invalid, as checked before + * device creation. + */ int isp_channel_drv_register( struct platform_device *ndev, unsigned int max_isp_channels) @@ -544,6 +677,27 @@ int isp_channel_drv_register( } EXPORT_SYMBOL(isp_channel_drv_register); +/** + * @brief Registers file operations for the ISP channel driver. + * + * This function performs the following operations: + * - Retrieves the global ISP channel driver instance. + * - Checks if the channel driver is initialized by verifying the global driver reference. + * - Acquires the global channel driver lock using @ref mutex_lock(). + * - If the driver operations are not set, assigns the provided operations. + * - If the operations are already registered, logs a debug message using + * @ref dev_dbg(). + * - Releases the global channel driver lock using @ref mutex_unlock(). + * - Returns a status code based on the operation outcome. + * + * @param[in] ops Pointer to the @ref isp_channel_drv_ops structure containing the + * file operations to be registered. + * Valid Value: non-NULL. + * + * @retval 0 Successfully registered the file operations. + * @retval -EPROBE_DEFER The ISP channel driver is not yet initialized, + * as indicated by @ref chdrv_ being NULL. + */ int isp_channel_drv_fops_register( const struct isp_channel_drv_ops *ops) { @@ -570,6 +724,24 @@ error: } EXPORT_SYMBOL(isp_channel_drv_fops_register); +/** + * @brief Unregisters the ISP channel driver and performs cleanup. + * + * This function performs the following operations: + * - Acquires the global channel driver lock using @ref mutex_lock(). + * - Retrieves the current ISP channel driver instance from the global reference. + * - Clears the global channel driver reference to indicate that it is no longer registered. + * - Validates that the provided device matches the driver's device using @ref WARN_ON(). + * - Releases the global channel driver lock using @ref mutex_unlock(). + * - Checks if the ISP channel major number is valid. If invalid, logs an error using + * @ref pr_err() and exits. + * - Iterates over all registered channels and destroys each device node using + * @ref device_destroy(). + * - Frees the memory allocated for the ISP channel driver using @ref kfree(). + * + * @param[in] dev Pointer to the @ref device structure representing the device to unregister. + * Valid Value: non-NULL. + */ void isp_channel_drv_unregister( struct device *dev) { @@ -598,9 +770,18 @@ void isp_channel_drv_unregister( EXPORT_SYMBOL(isp_channel_drv_unregister); /** - * @brief Initialize the ISP channel driver device (major). + * @brief Initializes and registers the ISP channel driver. * - * @returns 0 (success), PTR_ERR or neg. ISP channel major no. (failuure) + * This function performs the following operations: + * - Creates the ISP channel device class using @ref class_create(). + * - Registers a character device for the ISP channel with @ref register_chrdev(). + * - If registration fails, destroys the created device class using + * @ref class_destroy(). + * - Returns status based on the operation outcomes. + * + * @retval 0 Successfully initialized and registered the ISP channel driver. + * @retval (int) Error returned by @ref PTR_ERR() if @ref class_create() fails or by + * @ref register_chrdev() if character device registration fails. */ int isp_channel_drv_init(void) { @@ -624,7 +805,12 @@ int isp_channel_drv_init(void) EXPORT_SYMBOL(isp_channel_drv_init); /** - * @brief De-initialize the ISP channel driver device (major). + * @brief Cleans up and unregisters the ISP channel driver. + * + * This function performs the following operations: + * - Calls @ref unregister_chrdev() to unregister the character device associated + * with the ISP channel driver. + * - Calls @ref class_destroy() to destroy the device class for ISP channels. */ void isp_channel_drv_exit(void) { diff --git a/drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c b/drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c index 88002886..d74bb81a 100644 --- a/drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c +++ b/drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c @@ -162,12 +162,33 @@ struct isp_capture { /** * @brief Initialize an ISP syncpoint and get its GoS backing. * - * @param[in] chan ISP channel context - * @param[in] name Syncpoint name - * @param[in] enable Whether to initialize or just clear @a sp - * @param[out] sp Syncpoint handle + * This function performs the following operations: + * - Initializes the @a sp structure to zeroes. + * - If @a enable is false, returns success. + * - Allocates a synchronization point by calling + * @ref struct tegra_isp_channel::ops::alloc_syncpt(). + * - Gets the syncpoint handle using @ref host1x_syncpt_get_by_id_noref(). + * - Reads the syncpoint value using @ref host1x_syncpt_read(). + * - Retrieves GOS backing information by calling + * @ref struct tegra_isp_channel::ops::get_syncpt_gos_backing(). + * - Sets the GOS index and offset in the @a sp structure. + * - On failure after allocation, releases the synchronization point with + * @ref struct tegra_isp_channel::ops::release_syncpt() and re-initializes the @a sp + * structure. * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid Value: non-NULL. + * @param[in] name Name of the synchronization point. + * Valid Value: non-NULL. + * @param[in] enable Flag to enable or disable the synchronization point setup. + * Valid Value: true or false. + * @param[out] sp Pointer to the @ref syncpoint_info structure to be populated. + * Valid Value: non-NULL. + * + * @retval 0 On successful setup or if @a enable is false. + * @retval -EINVAL If @ref host1x_syncpt_get_by_id_noref() fails. + * @retval (int) If @ref struct tegra_isp_channel::ops::alloc_syncpt() or + * @ref struct tegra_isp_channel::ops::get_syncpt_gos_backing() fails. */ static int isp_capture_setup_syncpt( struct tegra_isp_channel *chan, @@ -217,6 +238,19 @@ cleanup: return err; } +/** + * @brief Fast-forwards a synchronization point in the ISP channel. + * + * This function performs the following operations: + * - Validates the synchronization point ID. + * - If the ID is valid, invokes @ref struct tegra_isp_channel::ops::fast_forward_syncpt() + * with the device handle, synchronization point ID, and threshold. + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] sp Pointer to the @ref syncpoint_info structure. + * Valid value: non-NULL. + */ static void isp_capture_fastforward_syncpt( struct tegra_isp_channel *chan, struct syncpoint_info *sp) @@ -225,6 +259,19 @@ static void isp_capture_fastforward_syncpt( chan->ops->fast_forward_syncpt(chan->ndev, sp->id, sp->threshold); } +/** + * @brief Fast-forwards synchronization points in the ISP capture process. + * + * This function performs the following operations: + * - Retrieves the @ref isp_capture structure from the provided channel. + * - Invokes @ref isp_capture_fastforward_syncpt() with the channel and the + * progress synchronization point. + * - Invokes @ref isp_capture_fastforward_syncpt() with the channel and the + * statistics progress synchronization point. + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + */ static void isp_capture_fastforward_syncpts( struct tegra_isp_channel *chan) { @@ -235,10 +282,20 @@ static void isp_capture_fastforward_syncpts( } /** - * @brief Release an ISP syncpoint and clear its handle. + * @brief Releases a synchronization point in the ISP channel and clears its + * associated information. * - * @param[in] chan ISP channel context - * @param[out] sp Syncpoint handle + * This function performs the following operations: + * - Validates the synchronization point ID. + * - If the ID is valid, invokes @ref struct tegra_isp_channel::ops::release_syncpt() with the + * device handle and synchronization point ID. + * - Resets the synchronization point information by clearing the structure + * using @ref memset(). + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] sp Pointer to the @ref syncpoint_info structure. + * Valid value: non-NULL. */ static void isp_capture_release_syncpt( struct tegra_isp_channel *chan, @@ -251,11 +308,19 @@ static void isp_capture_release_syncpt( } /** - * @brief Release the ISP channel progress and stats progress syncpoints. + * @brief Releases synchronization points in the ISP capture process. * - * @param[in] chan ISP channel context + * This function performs the following operations: + * - Retrieves the @ref isp_capture structure from the provided channel. + * - Checks if the capture structure is valid. + * If invalid, returns early. + * - Invokes @ref isp_capture_release_syncpt() with the channel and the + * progress synchronization point. + * - Invokes @ref isp_capture_release_syncpt() with the channel and the + * statistics progress synchronization point. * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. */ static void isp_capture_release_syncpts( struct tegra_isp_channel *chan) @@ -271,11 +336,26 @@ static void isp_capture_release_syncpts( } /** - * @brief Set up the ISP channel progress and stats progress syncpoints. + * @brief Sets up synchronization points for the ISP capture channel. * - * @param[in] chan ISP channel context + * This function performs the following operations: + * - Validates the capture data associated with the ISP channel. + * - If @ref HAVE_ISP_GOS_TABLES is defined, retrieves the GOS tables by calling + * @ref struct tegra_isp_channel::ops::get_gos_table(). + * - Calls @ref isp_capture_setup_syncpt() to set up the "progress" synchronization + * point. + * - Calls @ref isp_capture_setup_syncpt() to set up the "stats_progress" synchronization + * point. + * - In case of any failure during setup, releases all synchronization points by calling + * @ref isp_capture_release_syncpts(). * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * + * @retval 0 On successful setup of all synchronization points. + * @retval -ENODEV If the capture data is uninitialized. + * @retval (int) If @ref isp_capture_setup_syncpt() fails for any synchronization + * point or if @ref isp_capture_release_syncpts() fails during error handling. */ static int isp_capture_setup_syncpts( struct tegra_isp_channel *chan) @@ -313,13 +393,23 @@ fail: } /** - * @brief Read the value of an ISP channel syncpoint. + * @brief Reads the value of a synchronization point in the ISP channel. * - * @param[in] chan ISP channel context - * @param[in] sp Syncpoint handle - * @param[out] val Syncpoint value + * This function performs the following operations: + * - Checks if the synchronization point ID is valid. + * - If valid, gets the syncpoint handle using @ref host1x_syncpt_get_by_id_noref(). + * - If handle is valid, reads its value using @ref host1x_syncpt_read(). * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] sp Pointer to the @ref syncpoint_info structure. + * Valid value: non-NULL. + * @param[out] val Pointer to a variable where the synchronization point value + * will be stored. + * Valid value: non-NULL. + * + * @retval 0 On successful reading of the synchronization point value. + * @retval -EINVAL If @ref host1x_syncpt_get_by_id_noref() fails. */ static int isp_capture_read_syncpt( struct tegra_isp_channel *chan, @@ -345,17 +435,40 @@ static int isp_capture_read_syncpt( } /** - * @brief Patch the descriptor GoS SID (@a gos_relative) and syncpoint shim - * address (@a sp_relative) with the ISP IOVA-mapped addresses of a syncpoint - * (@a fence_offset). + * @brief Populates fence information for ISP capture using synchronization points. * - * @param[in] chan ISP channel context - * @param[in] fence_offset Syncpoint offset from process descriptor queue - * [byte] - * @param[in] gos_relative GoS SID offset from @a fence_offset [byte] - * @param[in] sp_relative Shim address from @a fence_offset [byte] + * This function performs the following operations: + * - Adjusts the relocation page address using @a fence_offset, @a reloc_page_addr and + * @ref PAGE_MASK. + * - Validates the relocation page address. + * - Reads the raw synchronization point value from the ISP IOVA-mapped relocation address using + * @ref __raw_readq(). + * - Extracts the synchronization point ID from the raw syncpoint. + * - Calls @ref struct tegra_isp_channel::ops::get_syncpt_gos_backing() with the channel device, + * synchronization point ID, and retrieves synchronization point address, GoS index, + * and GoS offset. + * - Combines GoS index and GoS offset in a GoS information buffer. + * - Updates the relocation page address for GoS information. + * - Writes the GoS information to the updated relocation page address using @ref __raw_writeq(). + * - Updates the relocation page address for synchronization point information. + * - Writes the synchronization point address to the updated relocation page address using + * @ref __raw_writeq(). * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] fence_offset Offset value for the fence. + * Valid range: [0 .. UINT16_MAX]. + * @param[in] gos_relative Relative byte offset for GoS. + * Valid range: non-negative. + * @param[in] sp_relative Relative byte offset for synchronization point. + * Valid range: non-negative. + * @param[in] reloc_page_addr Pointer to the relocation page address. + * Valid value: non-NULL. + * + * @retval 0 On successful completion. + * @retval -ENOMEM If the relocation page address is invalid. + * @retval (int) Errors returned from invocation of + * @ref struct tegra_isp_channel::ops::get_syncpt_gos_backing(). */ static int isp_capture_populate_fence_info( struct tegra_isp_channel *chan, @@ -409,15 +522,37 @@ ret: } /** - * @brief Patch the inputfence syncpoints of a process descriptor w/ ISP - * IOVA-mapped addresses. + * @brief Sets up input fence syncpoints for ISP capture requests. * - * @param[in] chan ISP channel context - * @param[in] req ISP process request - * @param[in] request_offset Descriptor offset from process descriptor queue - * [byte] + * This function performs the following operations: + * - Validates the capture data within the provided channel. + * - Checks if input fences are present for the given capture request. + * - Allocates memory for input fence relocations by calling @ref kcalloc(). + * - Copies input fence relocation data from user space using @ref copy_from_user(). + * - Maps the DMA buffer using @ref dma_buf_vmap() and retrieves the mapped address. + * - Iterates through each input fence relocation: + * - Calculates the input fence offset, handling overflow using @ref check_add_overflow(). + * - Calls @ref isp_capture_populate_fence_info() with the channel, calculated + * offset, GoS relative offset, synchronization point relative offset, and + * relocation page address. + * - Unmaps the DMA buffer using @ref dma_buf_vunmap() and frees allocated memory + * in case of failure. * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] req Pointer to the @ref isp_capture_req structure. + * Valid value: non-NULL. + * @param[in] request_offset Offset value for the capture request. + * Valid range: depends on context. + * + * @retval 0 On successful completion. + * @retval -ENODEV If the ISP capture is uninitialized. + * @retval -ENOMEM If memory allocation via @ref kcalloc() or buffer mapping + * via @ref dma_buf_vmap() fails. + * @retval -EFAULT If copying from user space fails via @ref copy_from_user(). + * @retval -EOVERFLOW If input fence offset calculation results in overflow via + * @ref check_add_overflow(). + * @retval (int) Errors returned from invocation of @ref isp_capture_populate_fence_info(). */ static int isp_capture_setup_inputfences( struct tegra_isp_channel *chan, @@ -504,15 +639,40 @@ fail: } /** - * @brief Patch the prefence syncpoints of a process descriptor w/ ISP - * IOVA-mapped addresses. + * @brief Sets up prefence syncpoints for ISP capture requests. * - * @param[in] chan ISP channel context - * @param[in] req ISP process request - * @param[in] request_offset Descriptor offset from process descriptor queue - * [byte] + * This function performs the following operations: + * - Validates the capture data within the provided channel is not NULL. + * - Validates the capture request structure. + * - Checks if prefences are present for the given capture request. + * - Allocates memory for prefence relocations by calling @ref kcalloc(). + * - Copies prefence relocation data from user space using @ref copy_from_user(). + * - Maps the DMA buffer by calling @ref dma_buf_vmap() and retrieves the mapped address. + * - Iterates through each prefence relocation entry: + * - Calculates the prefence offset, handling overflow using @ref check_add_overflow(). + * - Calls @ref isp_capture_populate_fence_info() with the channel, calculated + * offset, GoS relative offset, synchronization point relative offset, and + * relocation page address. + * - Implements a speculative barrier using @ref spec_bar(). + * - On failure, unmaps the DMA buffer using @ref dma_buf_vunmap() and frees allocated + * memory. * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] req Pointer to the @ref isp_capture_req structure. + * Valid value: non-NULL. + * @param[in] request_offset Byte offset value for the capture request. + * Valid range: [0 .. UINT16_MAX]. + * + * @retval 0 On successful setup or if no prefences are configured. + * @retval -ENODEV If the ISP capture data is uninitialized or the request is NULL. + * @retval -ENOMEM If memory allocation via @ref kcalloc() or buffer mapping + * via @ref dma_buf_vmap() fails. + * @retval -EFAULT If copying data from user space fails via @ref copy_from_user(). + * @retval -EOVERFLOW If prefence offset calculation results in overflow via + * @ref check_add_overflow(). + * @retval (int) Errors returned from invocation of + * @ref isp_capture_populate_fence_info(). */ static int isp_capture_setup_prefences( struct tegra_isp_channel *chan, @@ -603,11 +763,24 @@ fail: } /** - * @brief Unpin and free the list of pinned capture_mapping's associated with an - * ISP process request. + * @brief Unpins buffers for a specified capture request in the ISP channel. * - * @param[in] chan ISP channel context - * @param[in] buffer_index Process descriptor queue index + * This function performs the following operations: + * - Retrieves the capture data from the provided channel. + * - Validates that the capture data is initialized. If not, returns immediately. + * - Acquires the unpins list lock using @ref mutex_lock(). + * - Validates the buffer index against the queue depth. + * If invalid, returns immediately. + * - Retrieves the list of unpins for the specified buffer index. + * - If there are unpins, iterates through them: + * - Calls @ref put_mapping() for each unpin entry. + * - Resets the unpins list using @ref memset(). + * - Releases the unpins list lock using @ref mutex_unlock(). + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid Value: non-NULL. + * @param[in] buffer_index Index of the buffer to unpin. + * Valid range: [0 .. (queue_depth - 1)]. */ static void isp_capture_request_unpin( struct tegra_isp_channel *chan, @@ -639,11 +812,24 @@ static void isp_capture_request_unpin( } /** - * @brief Unpin and free the list of pinned capture_mapping's associated with an - * ISP program request. + * @brief Unpins buffers for a specified ISP program request in the ISP channel. * - * @param[in] chan ISP channel context - * @param[in] buffer_index Program descriptor queue index + * This function performs the following operations: + * - Retrieves the capture data from the provided channel. + * - Validates that the capture data is initialized. If not, returns immediately. + * - Acquires the unpins list lock using @ref mutex_lock(). + * - Validates the buffer index against the queue depth. + * If invalid, returns immediately. + * - Retrieves the list of unpins for the specified buffer index. + * - If there are unpins, iterates through them: + * - Calls @ref put_mapping() for each unpin entry. + * - Resets the unpins list using @ref memset(). + * - Releases the unpins list lock using @ref mutex_unlock(). + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] buffer_index Index of the buffer to unpin. + * Valid range: [0 .. (queue_depth - 1)]. */ static void isp_capture_program_request_unpin( struct tegra_isp_channel *chan, @@ -674,6 +860,28 @@ static void isp_capture_program_request_unpin( mutex_unlock(&capture->program_desc_ctx.unpins_list_lock); } +/** + * @brief Retrieves the number of statistical progress flags set in a program request. + * + * This function performs the following operations: + * - Calculates the offset by multiplying the buffer index with the request size + * using @ref __builtin_umul_overflow(). + * - Creates a program handle by adding the offset to the base address of the requests. + * - Checks if the program handle is valid. + * - Computes and returns the number of set bits in the stats_aidx_flag field of + * the program using @ref hweight32(). + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] req Pointer to the @ref isp_program_req structure. + * Valid value: non-NULL. + * + * @retval 0 If the program handle could not be created. + * @retval -EOVERFLOW If the calculation of the offset overflows using + * @ref __builtin_umul_overflow(). + * @retval (int) Number of set bits in the @c stats_aidx_flag field, as + * computed by @ref hweight32(). + */ static uint32_t isp_capture_get_num_stats_progress( struct tegra_isp_channel *chan, struct isp_program_req *req) @@ -702,14 +910,44 @@ static uint32_t isp_capture_get_num_stats_progress( } /** - * @brief Prepare and submit a pin and relocation request for a program - * descriptor, the resultant mappings are added to the channel program - * descriptor queue's @em unpins_list. + * @brief Prepares a program request for ISP capture. * - * @param[in] chan ISP channel context - * @param[in] req ISP program request + * This function performs the following operations: + * - Validates the capture data within the provided channel. + * - Checks if the ISP channel is properly set up by checking that channel + * ID is not @ref CAPTURE_CHANNEL_ISP_INVALID_ID. + * - Validates the program request structure. + * - Ensures that the unpins list is initialized. + * - Verifies that the requested buffer index is within the queue depth. + * - Executes a speculative barrier using @ref spec_bar(). + * - Acquires the reset lock using @ref mutex_lock(). + * - Processes any pending completions if a reset flag is set using + * @ref try_wait_for_completion(). + * - Sets reset flag to false. + * - Releases the reset lock after processing using @ref mutex_unlock(). + * - Acquires the unpins list lock using @ref mutex_lock(). + * - Checks if the program request is still in use. + * - Retrieves memory information for the specified buffer index. + * - Calculates the request offset based on the buffer index and request size. + * - Checks for overflow in the offset calculation using @ref check_add_overflow(). + * - Calls @ref capture_common_pin_and_get_iova() to pin memory and obtain IOVA. + * - Releases the unpins list lock using @ref mutex_unlock(). + * - Retrieves the number of statistical progress flags by calling + * @ref isp_capture_get_num_stats_progress(). * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] req Pointer to the @ref isp_program_req structure. + * Valid value: non-NULL. + * + * @retval 0 On successful preparation of the program request. + * @retval -ENODEV If the ISP capture is uninitialized or the channel setup is invalid. + * @retval -EINVAL If the program request is invalid, the unpins list is incomplete, + * or the buffer index is out of bounds. + * @retval -EOVERFLOW If the offset calculation overflows via @ref check_add_overflow(). + * @retval -EBUSY If the program request is still in use. + * @retval (int) Errors returned from invocation of + * @ref capture_common_pin_and_get_iova(). */ static int isp_capture_program_prepare( struct tegra_isp_channel *chan, @@ -800,10 +1038,19 @@ static int isp_capture_program_prepare( } /** - * @brief Unpin an ISP process request and flush the memory. + * @brief Cleans up IVC capture by unpinning buffers and synchronizing DMA. * - * @param[in] capture ISP channel capture context - * @param[in] buffer_index Process descriptor queue index + * This function performs the following operations: + * - Retrieves the ISP channel from the capture structure. + * - Validates the ISP channel; if invalid, returns. + * - Calls @ref isp_capture_request_unpin() with the channel and buffer index. + * - Synchronizes the DMA buffer range for CPU access by calling + * @ref dma_sync_single_range_for_cpu(). + * + * @param[in] capture Pointer to the @ref isp_capture structure. + * Valid value: non-NULL. + * @param[in] buffer_index Index of the buffer to clean up. + * Valid range: [0 .. (queue_depth - 1)]. */ static inline void isp_capture_ivc_capture_cleanup( struct isp_capture *capture, @@ -825,14 +1072,19 @@ static inline void isp_capture_ivc_capture_cleanup( } /** - * @brief Signal completion or write progress status to notifier for ISP capture - * indication from RCE. + * @brief Signals capture progress status or completes the capture response. * - * If the ISP channel's progress status notifier is not set, the capture - * completion will be signalled. + * This function performs the following operations: + * - Checks if the progress status notifier is set. + * - If set, calls @ref capture_common_set_progress_status() with the progress + * status notifier, buffer index, progress status buffer depth, and completion + * status. + * - Otherwise, completes the capture response by calling @ref complete(). * - * @param[in] capture ISP channel capture context - * @param[in] buffer_index Process descriptor queue index + * @param[in] capture Pointer to the @ref isp_capture structure. + * Valid value: non-NULL. + * @param[in] buffer_index Index of the buffer to signal. + * Valid range: [0 .. (queue_depth - 1)]. */ static inline void isp_capture_ivc_capture_signal( struct isp_capture *capture, @@ -854,10 +1106,19 @@ static inline void isp_capture_ivc_capture_signal( } /** - * @brief Unpin an ISP program request and flush the memory. + * @brief Cleans up program resources for a specified ISP capture buffer. * - * @param[in] capture ISP channel capture context - * @param[in] buffer_index Program descriptor queue index + * This function performs the following operations: + * - Retrieves the ISP channel from the capture structure. + * - Validates the ISP channel; if invalid, returns early. + * - Calls @ref isp_capture_program_request_unpin() with the channel and buffer index. + * - Synchronizes the DMA buffer range for CPU access by calling + * @ref dma_sync_single_range_for_cpu(). + * + * @param[in] capture Pointer to the @ref isp_capture structure. + * Valid value: non-NULL. + * @param[in] buffer_index Index of the buffer to clean up. + * Valid range: [0 .. (queue_depth - 1)]. */ static inline void isp_capture_ivc_program_cleanup( struct isp_capture *capture, @@ -879,14 +1140,26 @@ static inline void isp_capture_ivc_program_cleanup( } /** - * @brief Signal completion or write progress status to notifier for ISP program - * indication from RCE. + * @brief Signals ISP program progress status or completes the program response. * - * If the ISP channel's progress status notifier is not set, the program - * completion will be signalled. + * This function performs the following operations: + * - Checks if the progress status notifier is set. + * - If set: + * - Finds the buffer slot by summing buffer index and progress status buffer depth + * and checks for overflow by calling @ref check_add_overflow(). + * - Finds the buffer depth by summing the the program status buffer depth and + * progress status buffer depth and checks for overflow by calling + * @ref check_add_overflow(). + * - Returns immediately in case of overflow. + * - Calls @ref capture_common_set_progress_status() with the progress status + * notifier, the two above sums, and @ref PROGRESS_STATUS_DONE. + * - Otherwise: + * - Completes the program response by calling @ref complete(). * - * @param[in] capture ISP channel capture context - * @param[in] buffer_index Program descriptor queue index + * @param[in] capture Pointer to the @ref isp_capture structure. + * Valid value: non-NULL. + * @param[in] buffer_index Index of the program descriptor buffer to signal. + * Valid range: [0 .. (queue_depth - 1)]. */ static inline void isp_capture_ivc_program_signal( struct isp_capture *capture, @@ -923,10 +1196,33 @@ static inline void isp_capture_ivc_program_signal( } /** - * @brief ISP channel callback function for @em capture IVC messages. + * @brief Handles IVC status callbacks for ISP capture. * - * @param[in] ivc_resp IVC @ref CAPTURE_MSG from RCE - * @param[in] pcontext ISP channel capture context + * This function performs the following operations: + * - Casts @a ivc_resp to a @ref CAPTURE_MSG type. + * - Casts @a pcontext to a @ref isp_capture type. + * - Validates that the @ref CAPTURE_MSG, @ref isp_capture, and ISP channel are + * initialized. If invalid, returns immediately. + * - Processes the status message based on the message ID: + * - For @ref CAPTURE_ISP_STATUS_IND: + * - Retrieves the buffer index. + * - Calls @ref isp_capture_ivc_capture_cleanup() and + * @ref isp_capture_ivc_capture_signal(). + * - For @ref CAPTURE_ISP_PROGRAM_STATUS_IND: + * - Retrieves the buffer index. + * - Calls @ref isp_capture_ivc_program_cleanup() and + * @ref isp_capture_ivc_program_signal(). + * - For @ref CAPTURE_ISP_EX_STATUS_IND: + * - Retrieves the process buffer index and program buffer index. + * - Calls @ref isp_capture_ivc_program_cleanup(), + * @ref isp_capture_ivc_capture_cleanup(), and + * @ref isp_capture_ivc_capture_signal(). + * - For unknown message IDs, logs an error. + * + * @param[in] ivc_resp Pointer to the IVC response data. + * Valid value: non-NULL. + * @param[in] pcontext Pointer to the ISP channel capture context structure. + * Valid value: non-NULL. */ static void isp_capture_ivc_status_callback( const void *ivc_resp, @@ -995,15 +1291,39 @@ static void isp_capture_ivc_status_callback( } /** - * @brief Send a @em capture-control IVC message to RCE on an ISP channel, and - * block w/ timeout, waiting for the RCE response. + * @brief Sends a @em capture-control message over IVC for ISP capture. * - * @param[in] chan ISP channel context - * @param[in] msg IVC message payload - * @param[in] size Size of @a msg [byte] - * @param[in] resp_id IVC message identifier, see @CAPTURE_MSG_IDS + * This function performs the following operations: + * - Retrieves the capture data from the provided channel. + * - Validates that the capture data is initialized. + * - Logs a debug message indicating the message being sent using @ref dev_dbg(). + * - Sets the response message ID to the provided @a resp_id. + * - Acquires the control message lock using @ref mutex_lock(). + * - Sends the control message by calling @ref tegra_capture_ivc_control_submit(). + * - Waits for the capture response with a timeout by calling + * @ref wait_for_completion_timeout(). + * - Compares the response header with the expected header using @ref memcmp(). + * - Releases the control message lock using @ref mutex_unlock(). + * - Logs a debug message indicating the received response using @ref dev_dbg(). * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] msg Pointer to the @ref CAPTURE_CONTROL_MSG structure. + * Valid value: non-NULL. + * @param[in] size Size of the control message in bytes. + * Valid range: depends on context. + * @param[in] resp_id Response message ID to set. + * Valid range: depends on context. + * + * @retval 0 On successful sending of the control message and + * receiving the expected response. + * @retval -ENODEV If the ISP capture context is invalid. + * @retval -ETIMEDOUT If waiting for the capture response times out using + * @ref wait_for_completion_timeout(). + * @retval -EINVAL If the response received is unexpected as determined by + * @ref memcmp(). + * @retval (int) Errors returned from invocation of + * @ref tegra_capture_ivc_control_submit(). */ static int isp_capture_ivc_send_control(struct tegra_isp_channel *chan, const struct CAPTURE_CONTROL_MSG *msg, size_t size, @@ -1060,11 +1380,26 @@ fail: } /** - * @brief ISP channel callback function for @em capture-control IVC messages, - * this unblocks the channel's @em capture-control completion. + * @brief Handles control callbacks for ISP capture over IVC. * - * @param[in] ivc_resp IVC @ref CAPTURE_CONTROL_MSG from RCE - * @param[in] pcontext ISP channel capture context + * This function performs the following operations: + * - Casts @a ivc_resp to a @ref CAPTURE_CONTROL_MSG type. + * - Casts @a pcontext to a @ref isp_capture type. + * - Validates that the @ref CAPTURE_CONTROL_MSG, @ref isp_capture, and ISP channel are + * initialized. If not, returns immediately. + * - Retrieves the ISP channel from the capture structure. + * - Processes the control message based on the message ID: + * - For @ref CAPTURE_CHANNEL_ISP_SETUP_RESP, @ref CAPTURE_CHANNEL_ISP_RESET_RESP, and + * @ref CAPTURE_CHANNEL_ISP_RELEASE_RESP: + * - Copies the control message to the capture response message using @ref memcpy(). + * - Completes the capture response by calling @ref complete(). + * - For unknown message IDs: + * - Logs an error using @ref dev_err(). + * + * @param[in] ivc_resp Pointer to the IVC response data. + * Valid value: non-NULL. + * @param[in] pcontext Pointer to the context structure. + * Valid value: non-NULL. */ static void isp_capture_ivc_control_callback( const void *ivc_resp, @@ -1105,6 +1440,33 @@ static void isp_capture_ivc_control_callback( } } +/** + * @brief Initializes the ISP capture channel. + * + * This function performs the following operations: + * - Validates the input channel pointer is not NULL. + * - Calls @ref of_find_node_by_path() to locate the rtcpu device node. + * - Checks the availability of the device node using @ref of_device_is_available(). + * - Calls @ref of_find_device_by_node() to obtain the rtcpu platform device. + * - Allocates memory for the ISP capture structure using @ref kzalloc(). + * - Initializes completion variables with @ref init_completion(). + * - Initializes mutexes using @ref mutex_init(). + * - Associates the capture structure with the provided channel. + * - Sets channel ID to @ref CAPTURE_CHANNEL_ISP_INVALID_ID. + * - Sets reset flags to false. + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * + * @retval 0 On successful initialization. + * @retval -ENODEV If the channel context is invalid, + * @ref of_find_node_by_path(), + * @ref of_device_is_available(), + * @ref of_find_device_by_node(), + * @ref init_completion(), or + * @ref mutex_init() fails. + * @retval -ENOMEM If memory allocation via @ref kzalloc() fails. + */ int isp_capture_init( struct tegra_isp_channel *chan) { @@ -1157,6 +1519,21 @@ int isp_capture_init( return 0; } +/** + * @brief Shuts down the ISP capture functionality for a given channel. + * + * This function performs the following operations: + * - Validates the input channel is non-NULL. + * - Retrieves the capture data from the channel. + * - If the capture channel ID is valid: + * - Calls @ref isp_capture_reset(). + * - Calls @ref isp_capture_release(). + * - Frees the capture structure using @ref kfree(). + * - Sets the channel's capture data pointer to NULL. + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid Value: non-NULL. + */ void isp_capture_shutdown( struct tegra_isp_channel *chan) { @@ -1183,6 +1560,21 @@ void isp_capture_shutdown( chan->capture_data = NULL; } +/** + * @brief Initializes the NvHost device for the ISP capture channel. + * + * This function performs the following operations: + * - Retrieves driver data using @ref platform_get_drvdata(). + * - Validates the ISP capture setup structure by checking if @a setup is non-NULL. + * - Extracts the ISP unit index from the setup structure. + * - Checks if the ISP unit index is within the valid range. + * - Assigns the NvHost device and corresponding node to the ISP channel. + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] setup Pointer to the @ref isp_capture_setup structure. + * Valid value: non-NULL. + */ void isp_get_nvhost_device( struct tegra_isp_channel *chan, struct isp_capture_setup *setup) @@ -1208,6 +1600,38 @@ void isp_get_nvhost_device( chan->ndev = info->isp_pdevices[isp_inst]; } +/** + * @brief Initializes capture descriptors for the ISP channel. + * + * This function performs the following operations: + * - Pins the process descriptor ring buffer to RTCPU by calling + * @ref capture_common_pin_memory(). + * - Pins the process descriptor ring buffer to ISP by calling + * @ref capture_buffer_add(). + * - Caches ISP capture descriptor ring buffer details. + * - Allocates the unpins list based on the queue depth using @ref vzalloc(). + * - If allocation fails, unpins the memory using @ref capture_common_unpin_memory() + * and frees allocated memory with @ref vfree(). + * - Allocates memory info ring buffer for ISP capture descriptors using + * @ref dma_alloc_coherent(). + * - If allocation fails, frees the unpins list using @ref vfree() + * and unpins the memory with @ref capture_common_unpin_memory(). + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] capture Pointer to the @ref isp_capture structure. + * Valid value: non-NULL. + * @param[in] setup Pointer to the @ref isp_capture_setup structure. + * Valid value: non-NULL. + * @param[in] buffer_ctx Pointer to the @ref capture_buffer_table structure. + * Valid value: non-NULL. + * + * @retval 0 On successful setup of capture descriptors. + * @retval -ENOMEM If memory allocation with @ref vzalloc() or + * @ref dma_alloc_coherent() fails. + * @retval (int) If @ref capture_common_pin_memory() or + * @ref capture_buffer_add() fails. + */ static int setup_capture_descriptors( struct tegra_isp_channel *chan, struct isp_capture *capture, @@ -1268,6 +1692,43 @@ static int setup_capture_descriptors( return 0; } +/** + * @brief Sets up program descriptors for the ISP channel. + * + * This function performs the following operations: + * - Pins the ISP program descriptor ring buffer to RTCPU by calling + * @ref capture_common_pin_memory(). + * - Pins the ISP program descriptor ring buffer to ISP by calling + * @ref capture_buffer_add(). + * - If the memory setup fails, unpins memory using + * @ref capture_common_unpin_memory(). + * - Caches ISP program descriptor ring buffer details to ISP channel capture context. + * - Allocates the ISP program unpin list based on the queue depth using + * @ref vzalloc(). + * - If allocation fails, unpins memory using + * @ref capture_common_unpin_memory() and frees the unpins list with + * @ref vfree(). + * - Allocates memory info ring buffer for ISP program descriptors using + * @ref dma_alloc_coherent(). + * - If allocation fails, frees the unpins list with @ref vfree() and + * unpins memory using @ref capture_common_unpin_memory(). + * + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid Value: non-NULL. + * @param[in, out] capture Pointer to the @ref isp_capture structure. + * Valid Value: non-NULL. + * @param[in] setup Pointer to the @ref isp_capture_setup structure. + * Valid Value: non-NULL. + * @param[in, out] buffer_ctx Pointer to the @ref capture_buffer_table structure. + * Valid Value: non-NULL. + * + * @retval 0 On successful setup of program descriptors. + * @retval -ENOMEM If memory allocation with @ref vzalloc() or + * @ref dma_alloc_coherent() fails. + * @retval (int) If @ref capture_common_pin_memory() or + * @ref capture_buffer_add() fails. + */ static int setup_program_descriptors( struct tegra_isp_channel *chan, struct isp_capture *capture, @@ -1334,6 +1795,68 @@ static int setup_program_descriptors( return 0; } +/** + * @brief Initializes the ISP capture setup for the given channel. + * + * This function performs the following operations: + * - Retrieves driver data by calling @ref platform_get_drvdata(). + * - Validates that the provided channel is initialized. + * - Retrieves and validates the capture data from the channel. + * - Checks if the capture channel is already set up by verifying channel ID. + * - Validates setup parameters including channel flags, queue depth, and request size are + * non-zero, and ISP unit ID is within the number of configured ISP devices. + * - Creates a buffer table by calling @ref create_buffer_table(). + * - Sets up capture descriptors by calling @ref setup_capture_descriptors(). + * - Sets up program descriptors by calling @ref setup_program_descriptors(). + * - Sets up synchronization points by calling @ref isp_capture_setup_syncpts(). + * - Registers a control callback by calling @ref tegra_capture_ivc_register_control_cb(). + * - Initializes the control message structure. + * - Populates a @ref capture_channel_isp_config configuration structure using properties of + * input @ref isp_capture_setup structure. + * - If ISP GOS tables are enabled, configures them accordingly. + * - Iterates through configured GOS tables and assigns ISP GOS tables in the capture channel + * to ISP GOS tables in the channel configuration structure. + * - Sends the control message by calling @ref isp_capture_ivc_send_control(). + * - Checks the response message is successful. + * - Sets the channel ID based on the response message. + * - Notifies the channel ID by calling @ref tegra_capture_ivc_notify_chan_id(). + * - Registers a capture callback by calling @ref tegra_capture_ivc_register_capture_cb(). + * - Assigns the buffer context to the capture structure. + * - In case of any failure, releases resources by invoking: + * - @ref isp_capture_release() to release input @ref tegra_isp_channel structure in case of + * callback update or registration failure. + * - @ref destroy_buffer_table() to destroy buffer table. + * - @ref tegra_capture_ivc_unregister_control_cb() to unregister the control callback. + * - @ref dma_free_coherent() to free memory info ring buffers. + * - @ref vfree() to free allocated unpins lists. + * - @ref capture_common_unpin_memory() to unpin the program and capture descriptor requests + * memory. + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] setup Pointer to the @ref isp_capture_setup structure. + * Valid value: non-NULL. + * + * @retval 0 On successful setup of capture descriptors. + * @retval -ENODEV If the channel is NULL, capture is uninitialized, or external + * functions such as @ref platform_get_drvdata() fail. + * @retval -EEXIST If the capture channel is already set up. + * @retval -EINVAL If the capture setup parameters are invalid. + * @retval -ENOMEM If memory allocation with @ref create_buffer_table(), + * @ref setup_capture_descriptors(), @ref setup_program_descriptors(), + * @ref vzalloc(), or @ref dma_alloc_coherent() fails. + * @retval -EIO If the capture response is unexpected via + * @ref isp_capture_ivc_send_control(). + * @retval (int) Errors returned from external functions such as + * @ref capture_common_pin_memory(), + * @ref capture_buffer_add(), + * @ref setup_capture_descriptors(), + * @ref setup_program_descriptors(), + * @ref isp_capture_setup_syncpts(), + * @ref tegra_capture_ivc_register_control_cb(), + * @ref tegra_capture_ivc_notify_chan_id(), + * or @ref tegra_capture_ivc_register_capture_cb(). + */ int isp_capture_setup( struct tegra_isp_channel *chan, struct isp_capture_setup *setup) @@ -1518,6 +2041,67 @@ pin_fail: return err; } +/** + * @brief Releases ISP capture resources and cleans up the capture channel. + * + * This function performs the following operations: + * - Validates the input channel by checking if it is non-NULL. + * - Retrieves and validates the capture data from the channel. + * - Logs the capture release event using @ref nv_camera_log(). + * - Checks if the channel is set up by verifying channel ID is not + * @ref CAPTURE_CHANNEL_ISP_INVALID_ID. + * - Initializes the control message structure using @ref memset(). + * - Configures the control message with the release request by setting + * msg_id, channel_id, and reset_flags. + * - Sends the control message by calling @ref isp_capture_ivc_send_control(). + * - If sending fails, reboots the RTCPU device using @ref tegra_camrtc_reboot(). + * - Checks the response message's result for success. + * - Unregisters the capture callback by calling @ref tegra_capture_ivc_unregister_capture_cb(). + * - Unregisters the control callback by calling @ref tegra_capture_ivc_unregister_control_cb(). + * - Iterates through the program descriptor queue: + * - Completes the program response using @ref complete(). + * - Unpins the program request using @ref isp_capture_program_request_unpin(). + * - Unpins the program descriptor requests memory by calling @ref capture_common_unpin_memory(). + * - Iterates through the capture descriptor queue: + * - Completes the capture response using @ref complete(). + * - Unpins the capture request using @ref isp_capture_request_unpin(). + * - Executes a speculative barrier using @ref spec_bar(). + * - Releases synchronization points by calling @ref isp_capture_release_syncpts(). + * - Unpins the capture descriptor requests memory using @ref capture_common_unpin_memory(). + * - Frees the unpins lists using @ref vfree() and sets the pointers to NULL. + * - Frees memory info ring buffers by calling @ref dma_free_coherent(). + * - Releases the progress status notifier if set by calling + * @ref capture_common_release_progress_status_notifier(). + * - Destroys the buffer table using @ref destroy_buffer_table() and sets + * the buffer context to NULL. + * - Invalidates the channel ID by setting channel ID to @ref CAPTURE_CHANNEL_ISP_INVALID_ID. + * - Returns the accumulated error code. + * + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] reset_flags Reset flags for the capture release. + * Valid range: [0 .. UINT32_MAX]. + * + * @retval 0 On successful release of ISP capture resources. + * @retval -ENODEV If the channel is NULL, capture is uninitialized, + * or the channel is not set up. + * @retval -EIO If sending the control message fails or the response + * is invalid, involving @ref isp_capture_ivc_send_control() + * or @ref tegra_camrtc_reboot(). + * @retval -ETIMEDOUT If waiting for the capture response times out via + * @ref wait_for_completion_timeout(). + * @retval -EINVAL If the response received from @ref isp_capture_ivc_send_control() + * is not successful. + * @retval -ENOMEM If memory allocation fails during cleanup operations. + * @retval (int) Errors returned from external functions such as + * @ref tegra_capture_ivc_unregister_capture_cb(), + * @ref tegra_capture_ivc_unregister_control_cb(), + * @ref isp_capture_release_syncpts(), + * @ref capture_common_unpin_memory(), + * @ref dma_free_coherent(), + * @ref vfree(), or @ref destroy_buffer_table(). + */ int isp_capture_release( struct tegra_isp_channel *chan, uint32_t reset_flags) @@ -1636,6 +2220,58 @@ int isp_capture_release( return err; } +/** + * @brief Resets the ISP capture channel with specified reset flags. + * + * This function performs the following operations: + * - Validates the input channel by checking if it is non-NULL. + * - Retrieves and validates the capture data from the channel. + * - Logs the capture reset event using @ref nv_camera_log(). + * - Checks if the channel is set up by verifying the channel ID. + * - Acquires the reset lock using @ref mutex_lock(). + * - Sets the reset flags for both program and capture operations. + * - If @ref CAPTURE_ISP_RESET_BARRIER_IND is defined: + * - Initializes the capture message structure using @ref memset(). + * - Configures the capture message with the reset request by setting + * msg_id and channel_id. + * - Submits the capture reset message by calling @ref tegra_capture_ivc_capture_submit(). + * - Initializes the control message structure using @ref memset(). + * - Configures the control message with the reset request by setting + * msg_id, channel_id, and reset_flags. + * - Sends the control message by calling @ref isp_capture_ivc_send_control(). + * - If @ref CAPTURE_ISP_RESET_BARRIER_IND is defined: + * - Checks the response result for timeout. + * - Checks the response result for success. + * - Fast-forwards synchronization points by calling @ref isp_capture_fastforward_syncpts(). + * + * Error Handling: + * - Iterates through the program descriptor queue: + * - Unpins the program request using @ref isp_capture_program_request_unpin(). + * - Completes the program response using @ref complete(). + * - Executes a speculative barrier using @ref spec_bar(). + * - Iterates through the capture descriptor queue: + * - Unpins the capture request using @ref isp_capture_request_unpin(). + * - Completes the capture response using @ref complete(). + * - Executes another speculative barrier using @ref spec_bar(). + * - Releases the reset lock using @ref mutex_unlock(). + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] reset_flags Reset flags for the capture reset. + * Valid range: [0 .. UINT32_MAX]. + * + * @retval 0 On successful reset of the ISP capture channel. + * @retval -ENODEV If the channel is NULL, capture is uninitialized, + * or the channel is not set up. + * @retval -EAGAIN If the ISP reset operation times out, involving + * @ref tegra_capture_ivc_capture_submit(). + * @retval -EINVAL If the response received from @ref isp_capture_ivc_send_control() + * is not successful. + * @retval -EIO If sending the control message fails or the RTCPU device + * needs to reboot, involving @ref isp_capture_ivc_send_control() + * or @ref tegra_camrtc_reboot(). + * @retval (int) If @ref tegra_capture_ivc_capture_submit() fails. + */ int isp_capture_reset( struct tegra_isp_channel *chan, uint32_t reset_flags) @@ -1738,6 +2374,33 @@ error: return err; } +/** + * @brief Retrieves information about the ISP capture channel. + * + * This function performs the following operations: + * - Validates the input channel by checking if it is non-NULL. + * - Retrieves and validates the capture data from the channel. + * - Logs the capture get_info event using @ref nv_camera_log(). + * - Checks if the channel is set up by verifying the channel ID. + * - Validates the output info parameter by checking if it is non-NULL. + * - Assigns the channel ID to the info structure. + * - Assigns the progress and stats progress syncpoint IDs to the info structure. + * - Reads the current value of the progress syncpoint by calling + * @ref isp_capture_read_syncpt(). + * - Reads the current value of the stats progress syncpoint by calling + * @ref isp_capture_read_syncpt(). + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[out] info Pointer to the @ref isp_capture_info structure to be filled. + * Valid value: non-NULL. + * + * @retval 0 On successful retrieval of capture information. + * @retval -ENODEV If the channel is NULL, capture data is uninitialized, + * or the channel is not set up. + * @retval -EINVAL If the output info parameter is NULL. + * @retval (int) Errors returned from invocation of @ref isp_capture_read_syncpt(). + */ int isp_capture_get_info( struct tegra_isp_channel *chan, struct isp_capture_info *info) @@ -1794,8 +2457,38 @@ int isp_capture_get_info( } /** - * Pin/map buffers and save iova boundaries into corresponding - * memoryinfo struct. + * @brief Pins and maps ISP capture request buffers and save IOVA boundaries. + * + * This function performs the following operations: + * - Retrieves the capture descriptor context from the channel structure. + * - Calculates descriptor and request offsets, checking for overflow using + * @ref check_mul_overflow() and @ref check_add_overflow(). + * - Retrieves the capture descriptor based on the calculated descriptor offset. + * - Calculates the ISP pushbuffer2 memory offset, ensuring no overflow occurs. + * - Pins the pushbuffer2 memory region by calling + * @ref capture_common_pin_and_get_iova(). + * - Iterates through input surfaces and pins each using + * @ref capture_common_pin_and_get_iova(). + * - Iterates through output surfaces and pins each using + * @ref capture_common_pin_and_get_iova(). + * - Pins statistics surfaces by iterating through predefined arrays and + * calling @ref capture_common_pin_and_get_iova() for each surface. + * - Pins the engine status surface using @ref capture_common_pin_and_get_iova(). + * - In case of any error during the above steps, unpin cleanup is handled by + * @ref isp_capture_request_unpin(). + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] req Pointer to the @ref isp_capture_req structure. + * Valid value: non-NULL. + * @param[in, out] request_unpins Pointer to the @ref capture_common_unpins structure + * used for managing unpin operations. + * Valid value: non-NULL. + * + * @retval 0 On successful pinning of all request buffers. + * @retval -EOVERFLOW If an overflow is detected during offset calculations via + * @ref check_mul_overflow() or @ref check_add_overflow(). + * @retval (int) Errors propagated from @ref capture_common_pin_and_get_iova(). */ static int pin_isp_capture_request_buffers_locked( struct tegra_isp_channel *chan, @@ -1932,6 +2625,31 @@ fail: return err; } +/** + * @brief Retrieves the number of progress steps for a capture request. + * + * This function performs the following operations: + * - Calculates the descriptor offset by multiplying the buffer index with the + * request size using @ref check_mul_overflow(). + * - Retrieves the capture descriptor from the calculated offset. + * - Extracts the slice height and height from the descriptor's surface configurations. + * - Adjusts the slice height by subtracting 1 using @ref check_sub_overflow(). + * - Adjusts the height by adding the adjusted slice height using @ref check_add_overflow(). + * - Calculates and returns the number of progress steps by dividing the adjusted + * height by the slice height. + * + * In case of any overflow during calculations, the function returns 0. + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] req Pointer to the @ref isp_capture_req structure. + * Valid value: non-NULL. + * + * @retval 0 If any overflow check fails via @ref check_mul_overflow(), + * @ref check_sub_overflow(), or @ref check_add_overflow(). + * @retval (int) The number of progress steps, calculated by dividing the + * adjusted height by the slice height. + */ static uint32_t isp_capture_get_num_progress( struct tegra_isp_channel *chan, struct isp_capture_req *req) @@ -1962,6 +2680,50 @@ static uint32_t isp_capture_get_num_progress( return (adjust_height / sliceHeight); } +/** + * @brief Submits a capture request to the ISP channel. + * + * This function performs the following operations: + * - Validates the input channel and capture request are not null. + * - Ensures the capture channel is initialized and valid. + * - Ensures buffer index is not out of bounds of configured queue depth. + * - If reset capture flag is set, waits for any pending completions before proceeding + * using @ref try_wait_for_completion(). + * - Calculates the request offset based on the buffer index. + * - Calls @ref isp_capture_setup_inputfences() and @ref isp_capture_setup_prefences() + * to configure input and pre-fences for the capture request. + * - Checks if descriptor unpins list for the buffer index is empty, or if it is still + * in use by RTCPU. + * - Checks and pins the request buffers using + * @ref pin_isp_capture_request_buffers_locked(). + * - Submits the capture message via @ref tegra_capture_ivc_capture_submit(). + * - Updates synchronization points upon successful submission incrementing + * @ref isp_capture_get_num_progress(). + * - In case of an error, unpins the request buffers using @ref isp_capture_request_unpin(). + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure representing + * the ISP channel. + * Valid value: non-NULL. + * @param[in] req Pointer to the @ref isp_capture_req structure containing + * the capture request details. + * Valid value: non-NULL and must reference a valid buffer index + * within the queue depth of the capture context. + * + * @retval 0 On successful submission of the capture request. + * @retval -ENODEV If the channel context is invalid, capture is + * uninitialized, or the capture channel is not set up. + * @retval -EINVAL If the capture request is invalid, the capture + * descriptor context is incomplete, or the buffer + * index is out of bounds. + * @retval -EBUSY If the descriptor for the buffer index is still + * in use by RTCPU. + * @retval (int) If any external function such as + * @ref isp_capture_setup_inputfences(), + * @ref isp_capture_setup_prefences(), + * @ref pin_isp_capture_request_buffers_locked(), + * or @ref tegra_capture_ivc_capture_submit() + * fails, the corresponding error code is returned. + */ int isp_capture_request( struct tegra_isp_channel *chan, struct isp_capture_req *req) @@ -2088,6 +2850,39 @@ fail: return err; } +/** + * @brief Retrieves the capture status for the specified ISP channel. + * + * This function performs the following operations: + * - Validates the input channel context. + * - Retrieves the capture data from the channel structure. + * - Checks if the capture data is not null and capture channel is valid. + * - If given timeout is negative, waits for capture response completion + * using @ref wait_for_completion_killable(). + * - Otherwise, waits using @ref wait_for_completion_killable_timeout(). + * - Acquires the capture channel reset lock using @ref mutex_lock(). + * - Checks if a reset capture flag is set. + * - Releases the capture channel reset lock using @ref mutex_unlock(). + * - Returns any errors encountered during the wait operations via + * @ref wait_for_completion_killable() or @ref wait_for_completion_killable_timeout(). + * - On successful completion, returns 0. + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] timeout_ms Timeout in milliseconds to wait for capture status. + * Valid range: Negative value indicates wait forever, + * non-negative values specify waiting duration. + * + * @retval 0 On successful completion. + * @retval -ENODEV If the channel context is invalid, capture data is + * uninitialized, or the channel is not properly set up. + * @retval -ETIMEDOUT If waiting for capture status timed out via + * @ref wait_for_completion_killable_timeout(). + * @retval -EIO If a reset capture flag is detected via + * @ref mutex_lock() and @ref mutex_unlock(). + * @retval (int) Errors propagated from @ref wait_for_completion_killable() + * or @ref wait_for_completion_killable_timeout(). + */ int isp_capture_status( struct tegra_isp_channel *chan, int32_t timeout_ms) @@ -2147,6 +2942,36 @@ int isp_capture_status( return 0; } +/** + * @brief Submits a program capture request to the ISP channel. + * + * This function performs the following operations: + * - Validates the input channel context is not null. + * - Retrieves the capture data from the channel structure. + * - Validates the program capture request is not null. + * - Calls @ref isp_capture_program_prepare() to prepare the program request data. + * - Initializes a capture message structure. + * - Sets header message ID to @ref CAPTURE_ISP_PROGRAM_REQUEST_REQ. + * - Sets necessary fields in the capture message based on the request based on + * request and input @a chan. + * - Submits the capture message via @ref tegra_capture_ivc_capture_submit(). + * - If submission fails, calls @ref isp_capture_program_request_unpin() to + * unpin the request buffer. + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] req Pointer to the @ref isp_program_req structure containing + * the program capture request details. + * Valid value: non-NULL. + * + * @retval 0 On successful submission of the program capture request. + * @retval -ENODEV If the channel context is invalid or capture data is + * uninitialized. + * @retval -EINVAL If the program request is invalid. + * @retval (int) If @ref isp_capture_program_prepare() or + * @ref tegra_capture_ivc_capture_submit() fails, the + * corresponding error code is returned. + */ int isp_capture_program_request( struct tegra_isp_channel *chan, struct isp_program_req *req) @@ -2204,6 +3029,28 @@ int isp_capture_program_request( return 0; } +/** + * @brief Retrieves the program capture status for the specified ISP channel. + * + * This function performs the following operations: + * - Validates the input channel context. + * - Retrieves the capture data from the channel. + * - Validates that capture data and channel ID. + * - Waits for the capture program response using @ref wait_for_completion_killable(). + * - Acquires capture channel reset lock using @ref mutex_lock(). + * - Checks if a reset capture program flag is set. + * - Releases capture channel reset lock using @ref mutex_unlock(). + * - Returns the status of the operations. + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * + * @retval 0 On successful completion. + * @retval -ENODEV If the channel context is invalid, capture data is + * uninitialized, or the channel is not properly set up. + * @retval -EIO If a reset capture program flag is detected. + * @retval (int) Errors returned from @ref wait_for_completion_killable(). + */ int isp_capture_program_status( struct tegra_isp_channel *chan) { @@ -2252,6 +3099,33 @@ int isp_capture_program_status( return 0; } +/** + * @brief Submits extended (joint program and capture) request to the ISP channel. + * + * This function performs the following operations: + * - Validates the input channel and extended capture request. + * - If the buffer index in the request is set to its maximum value, + * forwards the request to @ref isp_capture_request(). + * - Otherwise, calls @ref isp_capture_program_prepare() to prepare + * the program request data. + * - Submits the capture request by calling @ref isp_capture_request(). + * - If submitting the capture request fails, calls @ref + * isp_capture_program_request_unpin() to unpin the prepared program. + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] req Pointer to the @ref isp_capture_req_ex structure containing + * the extended capture request details. + * Valid value: non-NULL. + * + * @retval 0 On successful submission of the extended capture request. + * @retval -ENODEV If the channel context is invalid or capture is + * uninitialized. + * @retval -EINVAL If the extended capture request is invalid. + * @retval (int) If @ref isp_capture_program_prepare() or + * @ref isp_capture_request() fails, the corresponding error + * code is returned. + */ int isp_capture_request_ex( struct tegra_isp_channel *chan, struct isp_capture_req_ex *req) @@ -2296,6 +3170,33 @@ int isp_capture_request_ex( return err; } +/** + * @brief Sets the progress status notifier for the ISP capture channel. + * + * This function performs the following operations: + * - Validates the input channel and progress status request. + * - Ensures input channel, capture data, and request are non-null. + * - Ensures program and process request buffer depths are valid. + * - Logs the progress status setup using @ref nv_camera_log(). + * - Calls @ref capture_common_setup_progress_status_notifier() to configure + * the progress status notifier. + * - Sets the progress status buffer depths for capture and program contexts. + * - Marks the progress status notifier as set. + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] req Pointer to the @ref isp_capture_progress_status_req structure + * containing the progress status request details. + * Valid value: non-NULL, with valid memory and buffer depths. + * + * @retval 0 On successful setup of the progress status notifier. + * @retval -ENODEV If the channel context is invalid or capture is + * uninitialized. + * @retval -EINVAL If the progress status request is invalid, including + * invalid memory or buffer depth parameters. + * @retval -EFAULT If @ref capture_common_setup_progress_status_notifier() + * fails, indicating a fault in setting up the notifier. + */ int isp_capture_set_progress_status_notifier( struct tegra_isp_channel *chan, struct isp_capture_progress_status_req *req) @@ -2403,6 +3304,29 @@ int isp_capture_set_progress_status_notifier( return err; } +/** + * @brief Submits a buffer request to the ISP capture channel. + * + * This function performs the following operations: + * - Validates the input channel context. + * - Validates the buffer request parameter. + * - Retrieves the capture data from the channel structure. + * - Calls @ref capture_buffer_request() to submit the buffer request with the + * specified memory and flags. + * + * @param[in] chan Pointer to the @ref tegra_isp_channel structure. + * Valid value: non-NULL. + * @param[in] req Pointer to the @ref isp_buffer_req structure containing + * the buffer request details. + * Valid value: non-NULL. + * + * @retval 0 On successful submission of the buffer request. + * @retval -ENODEV If the channel context is invalid or capture data is + * uninitialized. + * @retval -EINVAL If the buffer request is invalid. + * @retval (int) If @ref capture_buffer_request() fails, the corresponding + * error code is returned. + */ int isp_capture_buffer_request( struct tegra_isp_channel *chan, struct isp_buffer_req *req) @@ -2434,12 +3358,23 @@ int isp_capture_buffer_request( } /** - * @brief Helper to parse isp-devices Chip ID + * @brief Determines if the ISP capture device chip ID is a Tegra T26x. * - * @param[in] of_node Pointer to @ref device_node - * containing isp-devices phandle - * @returns true If isp-devices is configured for T26X. - * @returns false If T26X not mentioned. + * This function performs the following operations: + * - Parses the device tree phandle "nvidia,isp-devices" using @ref of_parse_phandle(). + * - Reads the "compatible" property from the node using @ref of_property_read_string(). + * - If reading the property fails, releases the node with @ref of_node_put(). + * - Checks if the "compatible" string contains "tegra26" using @ref strstr(). + * - Releases the node using @ref of_node_put(). + * - Determines if "tegra26" is found in the compatible string. + * + * @param[in] of_node Pointer to the @ref device_node structure representing the device. + * Valid value: non-NULL. + * + * @retval true If the ISP capture device is identified as Tegra T26x. + * @retval false If @ref of_parse_phandle(), @ref of_property_read_string(), + * @ref of_node_put(), or @ref strstr() fails to identify the + * device as Tegra T26x. */ static inline bool isp_capture_is_t26x(struct device_node *of_node) { @@ -2463,6 +3398,38 @@ static inline bool isp_capture_is_t26x(struct device_node *of_node) return is_t26x; } +/** + * @brief Probes and initializes ISP capture devices for the platform. + * + * This function performs the following operations: + * - Allocates memory for @ref tegra_capture_isp_data using @ref devm_kzalloc(). + * - Reads the "nvidia,isp-max-channels" property from the device tree using + * @ref of_property_read_u32(). + * - Determines if the device is Tegra T26x by calling @ref isp_capture_is_t26x(). + * - Validates the maximum number of ISP channels based on the device type. + * - Iterates through the "nvidia,isp-devices" nodes using @ref of_parse_phandle() + * and finds corresponding devices using @ref of_find_device_by_node(). + * - Releases device tree nodes after finding devices using @ref of_node_put(). + * - Associates the allocated data with the platform device using + * @ref platform_set_drvdata(). + * - Registers ISP channels by calling @ref isp_channel_drv_register(). + * - In case of any error after allocation, releases allocated devices using + * @ref put_device(). + * + * @param[in] pdev + * Pointer to the @ref platform_device structure. + * + * Valid value: non-NULL. + * + * @retval 0 On successful probing and initialization of ISP capture devices. + * @retval -ENOMEM If memory allocation via @ref devm_kzalloc() fails. + * @retval -EINVAL If reading device property via @ref of_property_read_u32() fails, + * max channels read via @ref of_property_read_u32() exceeds + * channel limits, iterating "nvidia,isp-devices" nodes exceeds + * array size, or no ISP devices are found. + * @retval -ENODEV If ISP devices are not found using @ref of_find_device_by_node(). + * @retval (int) On failure of @ref isp_channel_drv_register(). + */ static int capture_isp_probe(struct platform_device *pdev) { uint32_t i; @@ -2543,6 +3510,22 @@ cleanup: return err; } +/** + * @brief Removes and cleans up ISP capture devices for the platform. + * + * This function performs the following operations: + * - Logs the removal process using @ref dev_dbg(). + * - Retrieves the capture data associated with the platform device using + * @ref platform_get_drvdata(). + * - Iterates through all ISP devices and releases each device using + * @ref put_device(). + * - Returns a success status upon completion. + * + * @param[in] pdev Pointer to the @ref platform_device structure. + * Valid value: non-NULL. + * + * @retval 0 On successful removal and cleanup of ISP capture devices. + */ static int capture_isp_remove(struct platform_device *pdev) { struct tegra_capture_isp_data *info; @@ -2565,11 +3548,34 @@ static const struct of_device_id capture_isp_of_match[] = { }; #if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */ +/** + * @brief Wrapper function to remove and clean up ISP capture devices. + * + * This function performs the following operations: + * - Calls @ref capture_isp_remove() to remove and clean up ISP capture + * devices associated with the platform device. + * + * @param[in] pdev Pointer to the @ref platform_device structure. + * Valid value: non-NULL. + */ static void capture_isp_remove_wrapper(struct platform_device *pdev) { capture_isp_remove(pdev); } #else +/** + * @brief Wrapper function to remove the ISP capture device. + * + * This function performs the following operations: + * - Calls @ref capture_isp_remove() to remove the ISP capture device. + * - Returns the status of the remove operation. + * + * @param[in] pdev Pointer to the @ref platform_device structure. + * Valid value: non-NULL. + * + * @retval 0 On successful removal of the ISP capture device. + * @retval (int) Errors returned from @ref capture_isp_remove(). + */ static int capture_isp_remove_wrapper(struct platform_device *pdev) { return capture_isp_remove(pdev); @@ -2586,6 +3592,19 @@ static struct platform_driver capture_isp_driver = { } }; +/** + * @brief Initializes and registers the ISP capture driver. + * + * This function performs the following operations: + * - Calls @ref isp_channel_drv_init() to initialize the ISP channel driver. + * - Calls @ref platform_driver_register() to register the capture ISP platform driver. + * - If registration fails, calls @ref isp_channel_drv_exit() to clean up. + * + * @retval 0 On successful initialization and registration of the ISP + * capture driver. + * @retval (int) If @ref isp_channel_drv_init() or @ref platform_driver_register() + * fails, the corresponding error code is returned. + */ static int __init capture_isp_init(void) { int err; @@ -2600,6 +3619,15 @@ static int __init capture_isp_init(void) } return 0; } + +/** + * @brief Cleans up and unregisters the ISP capture driver. + * + * This function performs the following operations: + * - Calls @ref isp_channel_drv_exit() to clean up the ISP channel driver. + * - Calls @ref platform_driver_unregister() to unregister the capture ISP platform + * driver. + */ static void __exit capture_isp_exit(void) { isp_channel_drv_exit(); diff --git a/drivers/media/platform/tegra/camera/fusa-capture/capture-vi-channel.c b/drivers/media/platform/tegra/camera/fusa-capture/capture-vi-channel.c index e0cfca20..0a218ecc 100644 --- a/drivers/media/platform/tegra/camera/fusa-capture/capture-vi-channel.c +++ b/drivers/media/platform/tegra/camera/fusa-capture/capture-vi-channel.c @@ -155,6 +155,25 @@ /** @} */ +/** + * @brief Unpins previously pinned buffers for a VI capture channel. + * + * This function unpins buffers associated with a specified buffer index in a VI capture channel. + * It performs the following operations: + * - Validates the input capture channel pointer. + * - Retrieves and validates the capture data from the channel. + * - Locks the unpins list mutex using @ref mutex_lock(). + * - Accesses the unpins list for the specified buffer index. + * - If there are pending unpins, iterates through each and releases the mappings + * by calling @ref put_mapping(). + * - Resets the unpins data using @ref memset(). + * - Unlocks the unpins list mutex using @ref mutex_unlock(). + * + * @param[in] chan Pointer to the @ref tegra_vi_channel structure. + * Valid value: non-NULL. + * @param[in] buffer_index Index of the buffer to unpin. + * Valid range: corresponds to entries in the unpins list. + */ void vi_capture_request_unpin( struct tegra_vi_channel *chan, uint32_t buffer_index) @@ -191,6 +210,39 @@ EXPORT_SYMBOL(vi_capture_request_unpin); static struct vi_channel_drv *chdrv_; static DEFINE_MUTEX(chdrv_lock); +/** + * @brief Opens a VI channel with the specified configuration. + * + * This function performs the following operations: + * - Attempts to acquire the channel driver lock using @ref mutex_lock_interruptible(). + * - Retrieves the channel driver instance. + * - Validates that the channel driver is initialized and the channel index is within + * the available range. + * - Releases the channel driver lock using @ref mutex_unlock(). + * - Allocates memory for a new @ref tegra_vi_channel structure using @ref kzalloc(). + * - Initializes the channel structure with driver data and operations. + * - Initializes capture settings by calling @ref vi_capture_init(). + * - Acquires the channel driver's lock using @ref mutex_lock(). + * - Checks if the specified channel is already in use via @ref rcu_access_pointer(). + * - Assigns the new channel to the driver's channel array using @ref rcu_assign_pointer(). + * - Releases the channel driver's lock. + * - On failure, cleans up resources by calling @ref vi_capture_shutdown() and + * @ref kfree(). + * + * @param[in] channel The index of the channel to open. + * Valid range: [0 .. @ref vi_channel_drv.num_channels - 1] + * @param[in] is_mem_pinned Flag indicating whether memory should be pinned. + * Valid value: true or false. + * + * @retval (tegra_vi_channel *) Pointer to @ref tegra_vi_channel On successful completion. + * @retval ERR_PTR(-ERESTARTSYS) If @ref mutex_lock_interruptible() is interrupted. + * @retval ERR_PTR(-ENODEV) If the channel driver is unavailable or + * the channel index is out of range. + * @retval ERR_PTR(-ENOMEM) If memory allocation via @ref kzalloc() fails. + * @retval ERR_PTR(-EBUSY) If the specified channel is already open via + * @ref rcu_access_pointer(). + * @retval ERR_PTR(err) Errors propagated from @ref vi_capture_init(). + */ struct tegra_vi_channel *vi_channel_open_ex( unsigned int channel, bool is_mem_pinned) @@ -243,6 +295,25 @@ error: } EXPORT_SYMBOL(vi_channel_open_ex); +/** + * @brief Closes a VI channel and releases associated resources. + * + * This function performs the following operations: + * - Shuts down the capture on the specified channel using @ref vi_capture_shutdown(). + * - Acquires the channel driver's lock using @ref mutex_lock(). + * - Verifies that the channel being closed is the one stored in the driver's channel array + * using @ref rcu_access_pointer(). + * - Sets the corresponding entry in the driver's channel array to NULL using @ref RCU_INIT_POINTER(). + * - Releases the channel driver's lock using @ref mutex_unlock(). + * - Frees the memory allocated for the channel structure using @ref kfree_rcu(). + * + * @param[in] channel The index of the channel to close. + * Valid range: [0 .. @ref vi_channel_drv.num_channels - 1] + * @param[in] chan Pointer to the @ref tegra_vi_channel structure to close. + * Valid value: non-NULL. + * + * @retval 0 On successful completion. + */ int vi_channel_close_ex( unsigned int channel, struct tegra_vi_channel *chan) @@ -264,15 +335,33 @@ int vi_channel_close_ex( EXPORT_SYMBOL(vi_channel_close_ex); /** - * @brief Open a VI channel character device node; pass parameters to - * @ref vi_channel_open_ex subroutine to complete initialization. + * @brief Opens a VI channel and associates it with a file instance. * - * This is the @a open file operation handler for a VI channel node. + * This function performs the following operations: + * - Retrieves the channel index from the provided @ref inode using @ref iminor(). + * - Calls @ref vi_channel_open_ex() with the channel index and a memory pinned flag. + * - Checks if the returned channel pointer is an error using @ref IS_ERR(). + * - Assigns the opened channel to the @ref file's private data. + * - Calls @ref nonseekable_open() to perform standard file opening operations. + * - Returns the result of @ref nonseekable_open(). * - * @param[in] inode VI channel character device inode struct - * @param[in] file VI channel character device file struct + * @param[in] inode Pointer to the @ref inode structure representing the file. + * Valid value: non-NULL. + * @param[in] file Pointer to the @ref file structure representing the opened file. + * Valid value: non-NULL. * - * @returns 0 (success), neg. errno (failure) + * @retval 0 On successful opening of the VI channel. + * @retval -ERESTARTSYS If @ref vi_channel_open_ex() fails due to + * @ref mutex_lock_interruptible() being interrupted. + * @retval -ENODEV If @ref vi_channel_open_ex() fails because the channel + * driver is unavailable or the channel index is out of range. + * @retval -ENOMEM If @ref vi_channel_open_ex() fails due to memory + * allocation failure via @ref kzalloc(). + * @retval -EBUSY If @ref vi_channel_open_ex() fails because the specified + * channel is already open via @ref rcu_access_pointer(). + * @retval (int) If @ref vi_channel_open_ex() fails via @ref vi_capture_init() + * or if @ref nonseekable_open() fails, returns the corresponding + * error code via @ref nonseekable_open(). */ static int vi_channel_open( struct inode *inode, @@ -291,15 +380,20 @@ static int vi_channel_open( } /** - * @brief Release a VI channel character device node; pass parameters to - * @ref vi_channel_close_ex subroutine to complete release. + * @brief Releases a VI channel and cleans up associated resources. * - * This is the @a release file operation handler for a VI channel node. + * This function performs the following operations: + * - Retrieves the channel index from the provided @ref inode using @ref iminor(). + * - Obtains the channel data from the @a file's private data. + * - Calls @ref vi_channel_close_ex() with the channel index and channel data to close the VI channel. + * - Returns 0 to indicate successful release. * - * @param[in] inode VI channel character device inode struct - * @param[in] file VI channel character device file struct + * @param[in] inode Pointer to the @ref inode structure representing the file. + * Valid value: non-NULL. + * @param[in] file Pointer to the @ref file structure representing the opened file. + * Valid value: non-NULL. * - * @returns 0 + * @retval 0 On successful release of the VI channel. */ static int vi_channel_release( struct inode *inode, @@ -314,8 +408,34 @@ static int vi_channel_release( } /** - * Pin/map buffers and save iova boundaries into corresponding - * memoryinfo struct. + * @brief Pins buffers for a VI capture request while holding the necessary lock. + * + * This function performs the following operations: + * - Retrieves the capture data from the provided channel. + * - Calculates the buffer amount and checks for multiplication overflow by calling + * @ref check_mul_overflow(). + * - Computes the pointer to the capture descriptor based on the buffer amount. + * - Validates that the number of surfaces does not exceed the maximum allowed by using + * @ref BUG_ON(). + * - Iterates over the ATOMP surfaces and calls @ref capture_common_pin_and_get_iova() + * for each surface to pin and obtain IOVA mappings. + * - Attempts to pin and obtain an IOVA mapping for the engine status surface by calling + * @ref capture_common_pin_and_get_iova(). + * @note Cleanup of unpinned buffers is handled by @ref vi_capture_request_unpin(). + * + * @param[in] chan Pointer to the @ref tegra_vi_channel structure. + * Valid value: non-NULL. + * @param[in] req Pointer to the @ref vi_capture_req structure representing + * the capture request. + * Valid value: non-NULL. + * @param[in, out] request_unpins Pointer to the @ref capture_common_unpins structure + * used for managing unpin operations. + * Valid value: non-NULL. + * + * @retval 0 On successful pinning of all buffers. + * @retval -EFAULT If @ref check_mul_overflow() detects an overflow. + * @retval (int) If @ref capture_common_pin_and_get_iova() fails while pinning ATOMP + * surfaces or the engine status surface. */ static int pin_vi_capture_request_buffers_locked(struct tegra_vi_channel *chan, struct vi_capture_req *req, @@ -371,20 +491,86 @@ fail: } /** - * @brief Process an IOCTL call on a VI channel character device. + * @brief Handles IOCTL commands for a VI channel. * - * Depending on the specific IOCTL, the argument (@a arg) may be a pointer to a - * defined struct payload that is copied from or back to user-space. This memory - * is allocated and mapped from user-space and must be kept available until - * after the IOCTL call completes. + * This function performs the following operations: + * - Retrieves the channel data from the @ref file's private data. + * - Validates that the channel and capture context are initialized. + * - Determines the command number using @ref _IOC_NR(). + * - Processes the command based on its number: + * - **VI_CAPTURE_SETUP:** + * - Copies setup data from user space using @ref copy_from_user(). + * - Calls @ref vi_get_nvhost_device() to obtain the NVHost device. + * - Validates the request size. + * - Checks if buffer setup is already done. + * - Creates a buffer table using @ref create_buffer_table(). + * - Pins memory using @ref capture_common_pin_memory() and validates buffer size. + * - Sets up capture using @ref vi_capture_setup(). + * - Handles errors by cleaning up resources using @ref capture_common_unpin_memory() + * and @ref destroy_buffer_table(). + * - **VI_CAPTURE_RESET:** + * - Copies reset flags from user space using @ref copy_from_user(). + * - Calls @ref vi_capture_reset() to reset the capture. + * - If successful, unpins all requests using @ref vi_capture_request_unpin(). + * - **VI_CAPTURE_RELEASE:** + * - Copies release flags from user space using @ref copy_from_user(). + * - Calls @ref vi_capture_release() to release the capture. + * - If successful, unpins all requests using @ref vi_capture_request_unpin(), + * unpins memory using @ref capture_common_unpin_memory(), destroys the buffer + * table using @ref destroy_buffer_table(), and frees the unpins list using vfree(). + * - **VI_CAPTURE_GET_INFO:** + * - Initializes an info structure. + * - Calls @ref vi_capture_get_info() to retrieve capture information. + * - Copies info back to user space using @ref copy_to_user(). + * - **VI_CAPTURE_SET_CONFIG:** + * - Copies control message from user space using @ref copy_from_user(). + * - Calls @ref vi_capture_control_message_from_user() to set the configuration. + * - **VI_CAPTURE_REQUEST:** + * - Copies capture request from user space using @ref copy_from_user(). + * - Validates the number of relocs, buffer index, and non-null unpins list. + * - Calls @ref mutex_lock() to lock the unpins list mutex. + * - Pins request buffers using @ref pin_vi_capture_request_buffers_locked(). + * - Calls @ref mutex_unlock() to unlock the unpins list mutex. + * - Submits the capture request using @ref vi_capture_request(). + * - Unpins on failure using @ref vi_capture_request_unpin(). + * - **VI_CAPTURE_STATUS:** + * - Copies timeout value from user space using @ref copy_from_user(). + * - Calls @ref vi_capture_status() to get the capture status. + * - **VI_CAPTURE_SET_PROGRESS_STATUS_NOTIFIER:** + * - Copies progress status request from user space using @ref copy_from_user(). + * - Calls @ref vi_capture_set_progress_status_notifier() to set the notifier. + * - **VI_CAPTURE_BUFFER_REQUEST:** + * - Copies buffer request from user space using @ref copy_from_user(). + * - Calls @ref capture_buffer_request() to handle the buffer request. + * - Returns the appropriate status code based on the operation outcome. * - * This is the @a ioctl file operation handler for a VI channel node. + * In case of any errors during the processing of commands, the function ensures that + * resources are properly cleaned up to maintain system stability. * - * @param[in] file VI channel character device file struct - * @param[in] cmd VI channel IOCTL command - * @param[in,out] arg IOCTL argument; numerical value or pointer + * @param[in] file Pointer to the @ref file structure representing the opened file. + * Valid value: non-NULL. + * @param[in] cmd IOCTL command number to be processed. + * Valid range: Defined by @ref VI_CHANNEL_IOCTLS. + * @param[in] arg Argument for the IOCTL command, typically a user space pointer. + * Valid value: depends on the command. * - * @returns 0 (success), neg. errno (failure) + * @retval 0 On successful processing of the IOCTL command. + * @retval -EINVAL If the channel is invalid, context is uninitialized, or + * specific validation checks fail via @ref vi_get_nvhost_device(). + * @retval -EFAULT If copying data from or to user space fails using @ref copy_from_user() + * or @ref copy_to_user(), or if memory setup fails by invoking + * @ref capture_common_pin_memory() or @ref create_buffer_table(). + * @retval -ENOMEM If buffer size does not match queue depth during setup. + * @retval -EBUSY If a descriptor is still in use by RTCU via @ref vi_capture_request_unpin(). + * @retval -ENOIOCTLCMD If an unknown IOCTL command is received. + * @retval (int) Specific errors returned by external functions such as + * @ref vi_capture_setup(), @ref vi_capture_reset(), + * @ref vi_capture_release(), @ref vi_capture_get_info(), + * @ref vi_capture_control_message_from_user(), + * @ref pin_vi_capture_request_buffers_locked(), + * @ref vi_capture_request(), @ref vi_capture_status(), + * @ref vi_capture_set_progress_status_notifier(), + * or @ref capture_buffer_request(). */ static long vi_channel_ioctl( struct file *file, @@ -659,6 +845,31 @@ static const struct file_operations vi_channel_fops = { static struct class *vi_channel_class; static int vi_channel_major; +/** + * @brief Registers a VI channel driver with a specified number of channels. + * + * This function performs the following operations: + * - Allocates memory for the channel driver structure and channel pointers using + * @ref devm_kzalloc(). + * - Initializes the channel driver structure with the platform device and the number + * of channels. + * - Initializes the driver's mutex lock using @ref mutex_init(). + * - Acquires the global driver lock using @ref mutex_lock(). + * - Assigns the newly allocated driver structure to the global driver reference. + * - Releases the global driver lock using @ref mutex_unlock(). + * - Iterates over the number of channels and creates device entries for each channel + * using @ref device_create(). + * + * @param[in] ndev Pointer to the @ref platform_device structure representing the + * platform device. + * Valid value: non-NULL. + * @param[in] max_vi_channels Maximum number of VI channels to register. + * Valid range: [0 .. UINT32_MAX]. + * + * @retval 0 On successful registration of the VI channel driver. + * @retval -ENOMEM If memory allocation via @ref devm_kzalloc() fails. + * @retval -EBUSY If a VI channel driver is already registered. + */ int vi_channel_drv_register( struct platform_device *ndev, unsigned int max_vi_channels) @@ -705,6 +916,25 @@ error: } EXPORT_SYMBOL(vi_channel_drv_register); +/** + * @brief Registers the operations for the VI channel driver. + * + * This function performs the following operations: + * - Retrieves the channel driver instance from the global variable. + * - Checks if the channel driver instance is initialized. + * - Acquires the channel driver lock using @ref mutex_lock(). + * - If the operations table in the channel driver is not already set, assigns the provided + * operations to it. + * - If the operations table is already registered, logs a debug message using @ref dev_dbg(). + * - Releases the channel driver lock using @ref mutex_unlock(). + * + * @param[in] ops Pointer to the @ref vi_channel_drv_ops structure containing + * the operations to register. + * Valid value: non-NULL. + * + * @retval 0 On successful registration of the operations. + * @retval -EPROBE_DEFER If the channel driver is NULL. + */ int vi_channel_drv_fops_register( const struct vi_channel_drv_ops *ops) { @@ -731,6 +961,21 @@ error: } EXPORT_SYMBOL(vi_channel_drv_fops_register); +/** + * @brief Unregisters a VI channel driver and releases associated resources. + * + * This function performs the following operations: + * - Acquires the global driver lock using @ref mutex_lock(). + * - Retrieves the current channel driver instance. + * - Clears the global driver reference. + * - Releases the global driver lock using @ref mutex_unlock(). + * - Validates the major number. + * - Iterates over the number of channels and destroys each device using @ref device_destroy(). + * - Frees the memory allocated for the channel driver structure using @ref devm_kfree(). + * + * @param[in] dev Pointer to the @ref device structure representing the device. + * Valid value: non-NULL. + */ void vi_channel_drv_unregister( struct device *dev) { @@ -760,9 +1005,19 @@ void vi_channel_drv_unregister( EXPORT_SYMBOL(vi_channel_drv_unregister); /** - * @brief Initialize the VI channel driver device (major). + * @brief Initializes the VI channel driver by creating the device class and registering + * character devices. * - * @returns 0 (success), PTR_ERR or neg. VI channel major no. (failure) + * This function performs the following operations: + * - Creates a device class for VI channels using @ref class_create(). + * - Registers a character device with dynamic major number allocation using + * @ref register_chrdev(). + * - If character device registration fails, destroys the created device class + * using @ref class_destroy(). + * + * @retval 0 On successful initialization and registration. + * @retval -ENOMEM If device class creation fails due to insufficient memory. + * @retval -EINVAL If character device registration fails. */ int vi_channel_drv_init(void) { @@ -785,7 +1040,11 @@ int vi_channel_drv_init(void) } /** - * @brief De-initialize the VI channel driver device (major). + * @brief Unregisters the VI channel driver (major) and releases associated resources. + * + * This function performs the following operations: + * - Unregisters the character device for the VI channel using @ref unregister_chrdev(). + * - Destroys the VI channel device class using @ref class_destroy(). */ void vi_channel_drv_exit(void) { diff --git a/drivers/media/platform/tegra/camera/fusa-capture/capture-vi.c b/drivers/media/platform/tegra/camera/fusa-capture/capture-vi.c index cd813ccb..82f4c3b4 100644 --- a/drivers/media/platform/tegra/camera/fusa-capture/capture-vi.c +++ b/drivers/media/platform/tegra/camera/fusa-capture/capture-vi.c @@ -143,12 +143,30 @@ struct tegra_capture_vi_data { /** * @brief Initialize a VI syncpoint and get its GoS backing. * - * @param[in] chan VI channel context - * @param[in] name Syncpoint name - * @param[in] enable Whether to initialize or just clear @a sp - * @param[out] sp Syncpoint handle + * This function performs the following operations: + * - Clears the syncpoint handle if enable is false. + * - Allocates a syncpoint with the given name using + * @ref struct syncpoint_info::ops::alloc_syncpt(). + * - Gets the syncpoint handle using @ref host1x_syncpt_get_by_id_noref(). + * - Reads the syncpoint value using @ref host1x_syncpt_read(). + * - Gets the GoS backing for the syncpoint using + * @ref struct syncpoint_info::ops::get_gos_backing(). + * - In case of failure during any step, releases the allocated syncpoint and clears + * the handle using @ref struct syncpoint_info::ops::release_syncpt(). * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan VI channel context. + * Valid value: non-NULL + * @param[in] name Syncpoint name. + * Valid value: non-NULL + * @param[in] enable Whether to initialize or just clear the syncpoint. + * Valid range: [true, false] + * @param[out] sp Syncpoint handle to initialize. + * Valid value: non-NULL + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL Error returned from @ref host1x_syncpt_get_by_id_noref(). + * @retval (int) Error codes returned from @ref struct syncpoint_info::ops::alloc_syncpt() or + * @ref struct syncpoint_info::ops::get_syncpt_gos_backing(). */ static int vi_capture_setup_syncpt( struct tegra_vi_channel *chan, @@ -200,7 +218,12 @@ cleanup: /** * @brief Fast forward a VI syncpoint to its threshold value. * - * @param[in] chan VI channel context + * This function performs the following operation: + * - If progress syncpoint exists, calls @ref struct syncpoint_info::ops::fast_forward_syncpt() to advance the + * syncpoint to its threshold value. + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. */ static void vi_capture_fastforward_syncpt( struct tegra_vi_channel *chan) @@ -216,8 +239,14 @@ static void vi_capture_fastforward_syncpt( /** * @brief Release a VI syncpoint and clear its handle. * - * @param[in] chan VI channel context - * @param[out] sp Syncpoint handle + * This function performs the following operations: + * - If syncpoint ID exists, releases it using @ref struct syncpoint_info::ops::release_syncpt(). + * - Clears the syncpoint handle structure. + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[out] sp Syncpoint handle to release. + * Valid value: non-NULL. */ static void vi_capture_release_syncpt( struct tegra_vi_channel *chan, @@ -230,10 +259,15 @@ static void vi_capture_release_syncpt( } /** - * @brief Release the VI channel progress, embedded data and line timer - * syncpoints. + * @brief Release the VI channel progress, embedded data and line timer syncpoints. * - * @param[in] chan VI channel context + * This function performs the following operations: + * - Releases the progress syncpoint using @ref vi_capture_release_syncpt() + * - Releases the embedded data syncpoint using @ref vi_capture_release_syncpt() + * - Releases the line timer syncpoint using @ref vi_capture_release_syncpt() + * + * @param[in] chan VI channel context + * Valid value: non-NULL */ static void vi_capture_release_syncpts( struct tegra_vi_channel *chan) @@ -246,14 +280,22 @@ static void vi_capture_release_syncpts( } /** - * @brief Set up the VI channel progress, embedded data and line timer - * syncpoints. + * @brief Set up the VI channel progress, embedded data and line timer syncpoints. * - * @param[in] chan VI channel context - * @param[in] flags Bitmask for channel flags, see - * @ref CAPTURE_CHANNEL_FLAGS + * This function performs the following operations: + * - Gets the GoS table using @ref struct tegra_vi_channel::ops::get_gos_table(). + * - Sets up the progress syncpoint using @ref vi_capture_setup_syncpt(). + * - Sets up the embedded data syncpoint if enabled using @ref vi_capture_setup_syncpt(). + * - Sets up the line timer syncpoint if enabled using @ref vi_capture_setup_syncpt(). + * - In case of failure, releases all allocated syncpoints using @ref vi_capture_release_syncpts(). * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan VI channel context. + * Valid value: non-NULL + * @param[in] flags Bitmask for channel flags. + * Valid range: @ref CAPTURE_CHANNEL_FLAGS + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL Error returned from @ref vi_capture_setup_syncpt(). */ static int vi_capture_setup_syncpts( struct tegra_vi_channel *chan, @@ -293,11 +335,19 @@ fail: /** * @brief Read the value of a VI channel syncpoint. * - * @param[in] chan VI channel context - * @param[in] sp Syncpoint handle - * @param[out] val Syncpoint value + * This function performs the following operation: + * - If syncpoint ID exists, gets the syncpoint handle using @ref host1x_syncpt_get_by_id_noref(). + * - If handle is valid, reads its value using @ref host1x_syncpt_read(). * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan VI channel context. + * Valid value: non-NULL + * @param[in] sp Syncpoint handle. + * Valid value: non-NULL + * @param[out] val Syncpoint value. + * Valid value: non-NULL + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL Error returned from @ref host1x_syncpt_get_by_id_noref(). */ static int vi_capture_read_syncpt( struct tegra_vi_channel *chan, @@ -323,10 +373,20 @@ static int vi_capture_read_syncpt( } /** - * @brief VI channel callback function for @em capture IVC messages. + * @brief VI channel callback function for capture IVC messages. * - * @param[in] ivc_resp IVC @ref CAPTURE_MSG from RCE - * @param[in] pcontext VI channel capture context + * This function performs the following operations: + * - Validates input parameters. + * - For CAPTURE_STATUS_IND messages: + * - Unpins memory if pinned using @ref vi_capture_request_unpin(). + * - Synchronizes DMA memory using @ref dma_sync_single_range_for_cpu(). + * - Updates progress status using @ref capture_common_set_progress_status() if enabled. + * - Otherwise completes the capture response using @ref complete(). + * + * @param[in] ivc_resp IVC @ref CAPTURE_MSG from RCE. + * Valid value: non-NULL. + * @param[in] pcontext VI channel capture context. + * Valid value: non-NULL. */ static void vi_capture_ivc_status_callback( const void *ivc_resp, @@ -382,15 +442,28 @@ static void vi_capture_ivc_status_callback( } /** - * @brief Send a @em capture-control IVC message to RCE on a VI channel, and - * block w/ timeout, waiting for the RCE response. + * @brief Send a capture-control IVC message to RCE on a VI channel. * - * @param[in] chan VI channel context - * @param[in] msg IVC message payload - * @param[in] size Size of @a msg [byte] - * @param[in] resp_id IVC message identifier, see @CAPTURE_MSG_IDS + * This function performs the following operations: + * - Locks the control message mutex using @ref mutex_lock(). + * - Submits the capture control message using @ref tegra_capture_ivc_control_submit(). + * - Waits for the response with timeout using @ref wait_for_completion_timeout(). + * - Validates the response header matches the request using @ref memcmp(). + * - Unlocks the control message mutex using @ref mutex_unlock(). * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[in] msg IVC message payload. + * Valid value: non-NULL + * @param[in] size Size of message in bytes. + * Valid value: non-zero. + * @param[in] resp_id IVC message identifier. + * Valid range: @ref CAPTURE_MSG_IDS. + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL Response header validation failed. + * @retval -ETIMEDOUT Response timed out. + * @retval (int) Error codes returned from @ref tegra_capture_ivc_control_submit(). */ static int vi_capture_ivc_send_control( struct tegra_vi_channel *chan, @@ -443,11 +516,18 @@ fail: } /** - * @brief VI channel callback function for @em capture-control IVC messages, - * this unblocks the channel's @em capture-control completion. + * @brief VI channel callback function for capture-control IVC messages. * - * @param[in] ivc_resp IVC @ref CAPTURE_CONTROL_MSG from RCE - * @param[in] pcontext VI channel capture context + * This function performs the following operations: + * - Validates input parameters. + * - For supported control message responses: + * - Copies the response message to the channel's control response buffer using @ref memcpy(). + * - Completes the control response wait using @ref complete(). + * + * @param[in] ivc_resp IVC @ref CAPTURE_CONTROL_MSG from RCE. + * Valid value: non-NULL. + * @param[in] pcontext VI channel capture context. + * Valid value: non-NULL. */ static void vi_capture_ivc_control_callback( const void *ivc_resp, @@ -499,6 +579,27 @@ static void vi_capture_ivc_control_callback( } } +/** + * @brief Initialize a VI capture channel. + * + * This function performs the following operations: + * - Finds and validates the RTCPU device node using @ref of_find_node_by_path(). + * - Checks device availability using @ref of_device_is_available(). + * - Gets platform device using @ref of_find_device_by_node(). + * - Allocates and initializes the VI capture channel context using @ref kzalloc(). + * - Initializes completion objects using @ref init_completion(). + * - Initializes mutex locks using @ref mutex_init(). + * - Sets up initial channel state. + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[in] is_mem_pinned Whether memory is pinned. + * Valid range: [true, false]. + * + * @retval 0 Operation completed successfully. + * @retval -ENODEV RTCPU device node not found or invalid. + * @retval -ENOMEM Failed to allocate capture channel context from @ref kzalloc(). + */ int vi_capture_init( struct tegra_vi_channel *chan, bool is_mem_pinned) @@ -552,6 +653,22 @@ int vi_capture_init( } EXPORT_SYMBOL_GPL(vi_capture_init); +/** + * @brief Shutdown and cleanup a VI capture channel. + * + * This function performs the following operations: + * - Validates input parameters. + * - Resets the channel using @ref vi_capture_reset() if active. + * - Releases CSI stream using @ref csi_stream_release() if active. + * - Releases the channel using @ref vi_capture_release(). + * - Unpins memory using @ref vi_capture_request_unpin() if memory was pinned. + * - Unpins capture requests using @ref capture_common_unpin_memory(). + * - Destroys buffer table using @ref destroy_buffer_table() if exists. + * - Frees allocated resources using @ref kfree() and @ref vfree(). + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + */ void vi_capture_shutdown( struct tegra_vi_channel *chan) { @@ -601,6 +718,22 @@ void vi_capture_shutdown( } EXPORT_SYMBOL_GPL(vi_capture_shutdown); +/** + * @brief Get the nvhost device for a VI channel based on CSI stream ID. + * + * This function performs the following operations: + * - Retrieves the platform driver data for the channel's capture device + * using @ref platform_get_drvdata(). + * - Gets the VI instance from the mapping table using CSI stream ID. + * - Validates the VI instance ID. + * - Applies array bounds check using @ref array_index_nospec(). + * - Sets the channel's device and nvhost device pointers from platform device. + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[in] setup VI capture setup parameters. + * Valid value: non-NULL. + */ void vi_get_nvhost_device( struct tegra_vi_channel *chan, struct vi_capture_setup *setup) @@ -630,6 +763,23 @@ void vi_get_nvhost_device( } EXPORT_SYMBOL_GPL(vi_get_nvhost_device); +/** + * @brief Get the nvhost device for a given CSI stream ID. + * + * This function performs the following operations: + * - Retrieves the platform driver data for the channel's capture device + * using @ref platform_get_drvdata(). + * - Gets the VI instance ID from the mapping table using CSI stream ID. + * - Returns the corresponding platform device. + * + * @param[in] pdev Platform device pointer. + * Valid value: non-NULL. + * @param[in] csi_stream_id CSI stream identifier. + * Valid range: [0, MAX_NVCSI_STREAM_IDS - 1]. + * + * @retval device* Pointer to the nvhost device on success. + * @retval NULL If CSI stream ID is invalid. + */ struct device *vi_csi_stream_to_nvhost_device( struct platform_device *pdev, uint32_t csi_stream_id) @@ -647,6 +797,44 @@ struct device *vi_csi_stream_to_nvhost_device( } EXPORT_SYMBOL(vi_csi_stream_to_nvhost_device); +/** + * @brief Set up a VI capture channel. + * + * This function performs the following operations: + * - Validates input parameters and channel state. + * - Retrieves the platform driver data for the channel's capture device + * using @ref platform_get_drvdata(). + * - Gets the VI instance from mapping table using CSI stream ID. + * - If the channel's device is NULL, gets the nvhost device for the channel + * using @ref vi_get_nvhost_device(). + * - Validates setup parameters and capture channel ID. + * - Copies setup parameters to channel context. + * - Sets up channel syncpoints using @ref vi_capture_setup_syncpts(). + * - Registers control callback using @ref tegra_capture_ivc_register_control_cb(). + * - Allocates memory for memoryinfo ring buffer using @ref dma_alloc_coherent(). + * - Allocates memory for unpins list using @ref vzalloc(). + * - If @ref HAVE_VI_GOS_TABLES is defined, copies GoS tables to config. + * - Sends channel setup request using @ref vi_capture_ivc_send_control(). + * - Updates channel state with response info. + * - Updates control callback with capture channel ID using + * @ref tegra_capture_ivc_notify_capture_cb(). + * - Registers capture callback using @ref tegra_capture_ivc_register_capture_cb(). + * - Updates global channels array. + * - In case of failure, releases allocated resources using @ref vfree(), + * @ref dma_free_coherent(), @ref tegra_capture_ivc_unregister_control_cb(), + * and @ref vi_capture_release_syncpts(). + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[in] setup VI capture setup parameters. + * Valid value: non-NULL. + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL Invalid input parameters or response. + * @retval -EEXIST Channel already set up. + * @retval -ENODEV Capture channel is not initialized. + * @retval (int) Error codes from helper functions. + */ int vi_capture_setup( struct tegra_vi_channel *chan, struct vi_capture_setup *setup) @@ -908,6 +1096,20 @@ syncpt_fail: } EXPORT_SYMBOL_GPL(vi_capture_setup); +/** + * @brief Get a VI channel handle for a given CSI stream and virtual channel ID. + * + * This function performs the following operation: + * - Returns the VI channel handle from the global channels array if valid IDs. + * + * @param[in] stream_id CSI stream identifier. + * Valid range: [0, MAX_NVCSI_STREAM_IDS - 1]. + * @param[in] virtual_channel_id Virtual channel identifier. + * Valid range: [0, MAX_VIRTUAL_CHANNEL_PER_STREAM - 1]. + * + * @retval tegra_vi_channel* VI channel handle if found. + * @retval NULL If IDs are invalid or no channel exists. + */ struct tegra_vi_channel *get_tegra_vi_channel( unsigned int stream_id, unsigned int virtual_channel_id) @@ -918,6 +1120,30 @@ struct tegra_vi_channel *get_tegra_vi_channel( return channels[stream_id][virtual_channel_id]; } +/** + * @brief Reset a VI capture channel. + * + * This function performs the following operations: + * - Validates input parameters and channel state. + * - Locks the reset lock using @ref mutex_lock(). + * - If @ref CAPTURE_RESET_BARRIER_IND is defined, sends reset barrier + * indication using @ref tegra_capture_ivc_capture_submit(). + * - Sends channel reset request using @ref vi_capture_ivc_send_control(). + * - If @ref CAPTURE_RESET_BARRIER_IND is defined, checks reset response. + * - Fast forwards syncpoints using @ref vi_capture_fastforward_syncpt(). + * - Unlocks the reset lock using @ref mutex_unlock(). + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[in] reset_flags Channel reset flags. + * Valid range: @ref CAPTURE_CHANNEL_RESET_FLAGS. + * + * @retval 0 Operation completed successfully. + * @retval -ENODEV Channel not initialized. + * @retval -EAGAIN Reset timed out. + * @retval -EINVAL Invalid response from RCE. + * @retval (int) Error codes from helper functions. + */ int vi_capture_reset( struct tegra_vi_channel *chan, uint32_t reset_flags) @@ -992,6 +1218,33 @@ submit_fail: } EXPORT_SYMBOL_GPL(vi_capture_reset); +/** + * @brief Release a VI capture channel. + * + * This function performs the following operations: + * - Validates input parameters and channel state. + * - Sends channel release request using @ref vi_capture_ivc_send_control(). + * - If returns error, reboots the RTCPU using @ref tegra_camrtc_reboot(). + * - Frees memory info ringbuffer using @ref dma_free_coherent() if allocated. + * - Unregisters callbacks using @ref tegra_capture_ivc_unregister_capture_cb() + * and @ref tegra_capture_ivc_unregister_control_cb(). + * - Completes any pending capture responses using @ref complete(). + * - Releases syncpoints using @ref vi_capture_release_syncpts(). + * - Clears channel state and removes from global channels array. + * - Releases progress status notifier using @ref capture_common_release_progress_status_notifier() + * if set. + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[in] reset_flags Channel reset flags. + * Valid range: @ref CAPTURE_CHANNEL_RESET_FLAGS. + * + * @retval 0 Operation completed successfully. + * @retval -ENODEV Channel not initialized. + * @retval -EIO @ref vi_capture_ivc_send_control() failed or response is not CAPTURE_OK. + * @retval (int) Error codes from @ref tegra_capture_ivc_unregister_capture_cb() + * and @ref tegra_capture_ivc_unregister_control_cb(). + */ int vi_capture_release( struct tegra_vi_channel *chan, uint32_t reset_flags) @@ -1094,6 +1347,30 @@ int vi_capture_release( } EXPORT_SYMBOL_GPL(vi_capture_release); +/** + * @brief Send a control message to RCE through IVC for a VI channel. + * + * This function performs the following operations: + * - Sets the channel ID in the message header. + * - Determines the expected response message ID based on request type. + * - For PHY stream open requests, checks channel stream is not already opened + * and copies stream ID and CSI port to channel context. + * - For PHY stream close requests, checks channel stream is opened. + * - For TPG start requests, copies virtual channel ID to channel context. + * - Sends the control message using @ref vi_capture_ivc_send_control(). + * - Updates stream state for PHY stream operations. + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[in] msg_cpy Control message to send. + * Valid value: non-NULL. + * @param[in] size Size of message in bytes. + * Valid value: non-zero. + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL Invalid message ID or response ID. + * @retval (int) Error codes from @ref vi_capture_ivc_send_control(). + */ static int vi_capture_control_send_message( struct tegra_vi_channel *chan, struct CAPTURE_CONTROL_MSG *msg_cpy, @@ -1196,9 +1473,17 @@ static int vi_capture_control_send_message( /** * @brief Disable the VI channel's NVCSI TPG stream in RCE. * - * @param[in] chan VI channel context + * This function performs the following operations: + * - Prepares TPG stop request message. + * - Sends request to RCE using @ref vi_capture_ivc_send_control(). + * - Validates response from RCE. * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL Invalid response from RCE. + * @retval (int) Error codes from @ref vi_capture_ivc_send_control(). */ static int csi_stream_tpg_disable( struct tegra_vi_channel *chan) @@ -1226,11 +1511,19 @@ static int csi_stream_tpg_disable( } /** - * @brief Disable the VI channel's NVCSI stream in RCE. + * @brief Close the VI channel's NVCSI stream in RCE. * - * @param[in] chan VI channel context + * This function performs the following operations: + * - Prepares stream close request message. + * - Sends request to RCE using @ref vi_capture_control_send_message(). + * - Validates response from RCE. * - * @returns 0 (success), neg. errno (failure) + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL Invalid response from RCE. + * @retval (int) Error codes from @ref vi_capture_control_send_message(). */ static int csi_stream_close( struct tegra_vi_channel *chan) @@ -1256,6 +1549,20 @@ static int csi_stream_close( return 0; } +/** + * @brief Release the VI channel's NVCSI stream resources. + * + * This function performs the following operations: + * - If stream ID is invalid, returns success. + * - If TPG virtual channel is active, disables it using @ref csi_stream_tpg_disable(). + * - If stream is open, closes it using @ref csi_stream_close(). + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * + * @retval 0 Operation completed successfully. + * @retval (int) Error codes from @ref csi_stream_tpg_disable() or @ref csi_stream_close(). + */ int csi_stream_release( struct tegra_vi_channel *chan) { @@ -1287,6 +1594,27 @@ int csi_stream_release( return err; } +/** + * @brief Process a VI capture control message from userspace. + * + * This function performs the following operations: + * - Validates input parameters. + * - Copies message from userspace using @ref kzalloc() and @ref copy_from_user(). + * - Sends control message using @ref vi_capture_control_send_message(). + * - Copies response back to userspace using @ref copy_to_user(). + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[in] msg Control message from userspace. + * Valid value: non-NULL with valid pointers. + * + * @retval 0 Operation completed successfully. + * @retval -ENODEV Channel not initialized. + * @retval -EINVAL Invalid message parameters. + * @retval -ENOMEM Failed to allocate message copy buffer from @ref kzalloc(). + * @retval (int) Error codes from @ref vi_capture_control_send_message(), @ref copy_to_user(), + * or @ref copy_from_user(). + */ int vi_capture_control_message_from_user( struct tegra_vi_channel *chan, struct vi_capture_control_msg *msg) @@ -1352,6 +1680,27 @@ fail: } EXPORT_SYMBOL_GPL(vi_capture_control_message_from_user); +/** + * @brief Process a VI capture control message from kernel space. + * + * This function performs the following operations: + * - Validates input parameters. + * - Copies message from kernel buffer using @ref kzalloc() and @ref memcpy(). + * - Sends control message using @ref vi_capture_control_send_message(). + * - Copies response to output buffer using @ref memcpy(). + * - Frees message copy buffer using @ref kfree(). + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[in] msg Control message from kernel. + * Valid value: non-NULL with valid pointers. + * + * @retval 0 Operation completed successfully. + * @retval -ENODEV Channel not initialized. + * @retval -EINVAL Invalid message parameters. + * @retval -ENOMEM Failed to allocate message copy buffer from @ref kzalloc(). + * @retval (int) Error codes from @ref vi_capture_control_send_message(). + */ int vi_capture_control_message( struct tegra_vi_channel *chan, struct vi_capture_control_msg *msg) @@ -1401,6 +1750,27 @@ fail: return err; } +/** + * @brief Get information about a VI capture channel. + * + * This function performs the following operations: + * - Validates input parameters and channel state. + * - Retrieves syncpoint IDs and values using @ref vi_capture_read_syncpt(). + * - Returns channel configuration information including: + * - Progress, embedded data and line timer syncpoints. + * - Hardware channel ID. + * - VI channel masks. + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[out] info Capture channel information structure. + * Valid value: non-NULL. + * + * @retval 0 Operation completed successfully. + * @retval -ENODEV Channel not initialized. + * @retval -EINVAL Invalid info parameter. + * @retval (int) Error codes from @ref vi_capture_read_syncpt(). + */ int vi_capture_get_info( struct tegra_vi_channel *chan, struct vi_capture_info *info) @@ -1452,6 +1822,24 @@ int vi_capture_get_info( } EXPORT_SYMBOL_GPL(vi_capture_get_info); +/** + * @brief Calculate number of progress syncpoints needed for a capture request. + * + * This function performs the following operations: + * - Gets capture descriptor for the given buffer index using @ref check_mul_overflow(). + * - Calculates required progress syncpoints based on: + * - Minimum of 2 for PXL_SOF and PXL_EOF. + * - Additional points for flush operations if enabled. + * - Adjusts count if HEIGHT is divisible by TRIPLINE. + * - Handles overflow conditions in calculations. + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[in] req Capture request parameters. + * Valid value: non-NULL. + * + * @retval (uint32_t) Number of progress syncpoints needed. + */ static uint32_t vi_capture_get_num_progress( struct tegra_vi_channel *chan, struct vi_capture_req *req) @@ -1513,6 +1901,29 @@ static uint32_t vi_capture_get_num_progress( return (uint32_t)numProgress; } +/** + * @brief Submit a capture request to a VI channel. + * + * This function performs the following operations: + * - Validates input parameters and channel state. + * - Locks the reset lock using @ref mutex_lock(). + * - Prepares capture request message. + * - Logs the capture request using @ref nv_camera_log_vi_submit(). + * - Submits request using @ref tegra_capture_ivc_capture_submit(). + * - Calculates progress points using @ref vi_capture_get_num_progress(). + * - Updates progress syncpoint threshold using @ref check_add_overflow(). + * - Unlocks the reset lock using @ref mutex_unlock(). + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[in] req Capture request parameters. + * Valid value: non-NULL. + * + * @retval 0 Operation completed successfully. + * @retval -ENODEV Channel not initialized. + * @retval -EINVAL Invalid request parameter. + * @retval (int) Error codes from @ref tegra_capture_ivc_capture_submit(). + */ int vi_capture_request( struct tegra_vi_channel *chan, struct vi_capture_req *req) @@ -1583,6 +1994,28 @@ int vi_capture_request( } EXPORT_SYMBOL_GPL(vi_capture_request); +/** + * @brief Wait for capture status completion on a VI channel. + * + * This function performs the following operations: + * - Validates input parameters and channel state. + * - Waits for capture completion with specified timeout using + * @ref wait_for_completion_interruptible() if selected timtout is negative, + * or @ref wait_for_completion_timeout() otherwise. + * - Convert timeout value to jiffies using @ref msecs_to_jiffies(). + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[in] timeout_ms Timeout in milliseconds. + * Valid range: [-1, INT_MAX]. + * -1 means wait forever. + * + * @retval 0 Operation completed successfully. + * @retval -ENODEV Channel not initialized. + * @retval -ETIMEDOUT Wait timed out. + * @retval (int) Error codes from @ref wait_for_completion_interruptible() + * or @ref wait_for_completion_timeout(). + */ int vi_capture_status( struct tegra_vi_channel *chan, int32_t timeout_ms) @@ -1638,6 +2071,25 @@ int vi_capture_status( } EXPORT_SYMBOL_GPL(vi_capture_status); +/** + * @brief Set up progress status notification for a VI channel. + * + * This function performs the following operations: + * - Validates input parameters and channel state. + * - Verifies buffer depth is sufficient for queue depth. + * - Sets up progress status notifier using @ref capture_common_setup_progress_status_notifier(). + * - Updates channel state for progress status notification. + * + * @param[in] chan VI channel context. + * Valid value: non-NULL. + * @param[in] req Progress status request parameters. + * Valid value: non-NULL with valid memory parameters. + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL Invalid request parameters. + * @retval -ENODEV Channel not initialized. + * @retval -EFAULT Error from @ref capture_common_setup_progress_status_notifier(). + */ int vi_capture_set_progress_status_notifier( struct tegra_vi_channel *chan, struct vi_capture_progress_status_req *req) @@ -1689,6 +2141,27 @@ int vi_capture_set_progress_status_notifier( } EXPORT_SYMBOL_GPL(vi_capture_set_progress_status_notifier); +/** + * @brief Read CSI-to-VI mapping table from device tree. + * + * This function performs the following operations: + * - Reads mapping table size using @ref of_property_read_u32(). + * - Ensures mapping table size is within valid range. + * - Validates mapping element names using @ref of_property_count_strings(). + * - Checks element order using @ref of_property_match_string(). + * - Reads and validates CSI stream ID and VI unit ID pairs using + * @ref of_property_read_u32_index(). + * - Checks each CSI stream ID is unique and within valid range. + * - Checks each VI unit ID is within valid range. + * - Populates VI instance mapping table. + * + * @param[in] pdev Platform device pointer. + * Valid value: non-NULL. + * + * @retval 0 Operation completed successfully. + * @retval -EINVAL Invalid mapping parameters or device tree entries. + * @retval (int) Error codes from @ref of_property_read_u32_index(). + */ static int csi_vi_get_mapping_table(struct platform_device *pdev) { uint32_t index = 0; @@ -1781,6 +2254,34 @@ static int csi_vi_get_mapping_table(struct platform_device *pdev) return 0; } +/** + * @brief Probe function for VI capture driver. + * + * This function performs the following operations: + * - Allocates and initializes driver data using @ref devm_kzalloc(). + * - Reads maximum VI channels using @ref of_property_read_u32(). + * - Validates maximum VI channels is less than @ref NUM_VI_CHANNELS. + * - Gets VI device nodes using @ref of_parse_phandle(). + * - Gets platform devices using @ref of_find_device_by_node(). + * - Release each VI device node using @ref of_node_put(). + * - Sets driver data using @ref platform_set_drvdata(). + * - If more than one VI device, reads CSI-VI mapping using @ref csi_vi_get_mapping_table(). + * - Registers VI channel driver using @ref vi_channel_drv_register(). + * - If error, exits VI channel driver subsystem using @ref vi_channel_drv_exit(). + * - Initializes media controller using @ref tegra_capture_vi_media_controller_init(). + * + * @param[in] pdev Platform device pointer. + * Valid value: non-NULL. + * + * @retval 0 Operation completed successfully. + * @retval -ENOMEM Memory allocation failed from @ref devm_kzalloc(). + * @retval -EINVAL Invalid device tree parameters or error from @ref of_property_read_u32(). + * @retval -ENODEV Required devices not found from @ref of_parse_phandle() or + * @ref of_find_device_by_node(). + * @retval (int) Error codes from @ref csi_vi_get_mapping_table(), + * @ref vi_channel_drv_register(), + * or @ref tegra_capture_vi_media_controller_init(). + */ static int capture_vi_probe(struct platform_device *pdev) { uint32_t ii; @@ -1880,6 +2381,21 @@ cleanup: return err; } +/** + * @brief Remove function for VI capture driver. + * + * This function performs the following operations: + * - Retrieves capture driver data using @ref platform_get_drvdata(). + * - Releases VI device references using @ref put_device(). + * - Unregisters VI channel driver using @ref vi_channel_drv_unregister(). + * - Cleans up media controller using @ref tegra_vi_media_controller_cleanup(). + * - Exits VI channel driver using @ref vi_channel_drv_exit(). + * + * @param[in] pdev Platform device pointer. + * Valid value: non-NULL. + * + * @retval 0 Operation completed successfully. + */ static int capture_vi_remove(struct platform_device *pdev) { struct tegra_capture_vi_data *info; @@ -1909,11 +2425,33 @@ static const struct of_device_id capture_vi_of_match[] = { MODULE_DEVICE_TABLE(of, capture_vi_of_match); #if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */ +/** + * @brief Wrapper function for VI capture driver removal (void return version). + * + * This function performs the following operations: + * - Calls @ref capture_vi_remove() to perform actual driver cleanup. + * - Used for Linux kernel version 6.11 and later where remove returns void. + * + * @param[in] pdev Platform device pointer. + * Valid value: non-NULL. + */ static void capture_vi_remove_wrapper(struct platform_device *pdev) { capture_vi_remove(pdev); } #else +/** + * @brief Wrapper function for VI capture driver removal (int return version). + * + * This function performs the following operations: + * - Calls @ref capture_vi_remove() to perform actual driver cleanup. + * - Used for Linux kernel versions before 6.11 where remove returns int. + * + * @param[in] pdev Platform device pointer. + * Valid value: non-NULL. + * + * @retval (int) Return value from @ref capture_vi_remove(). + */ static int capture_vi_remove_wrapper(struct platform_device *pdev) { return capture_vi_remove(pdev); @@ -1930,6 +2468,17 @@ static struct platform_driver capture_vi_driver = { } }; +/** + * @brief Module initialization function for VI capture driver. + * + * This function performs the following operations: + * - Initializes VI channel driver subsystem using @ref vi_channel_drv_init(). + * - Registers platform driver using @ref platform_driver_register(). + * - If error, exits VI channel driver subsystem using @ref vi_channel_drv_exit(). + * + * @retval 0 Operation completed successfully. + * @retval (int) Error codes from @ref vi_channel_drv_init() or @ref platform_driver_register(). + */ static int __init capture_vi_init(void) { int err; @@ -1945,6 +2494,14 @@ static int __init capture_vi_init(void) return 0; } + +/** + * @brief Module exit function for VI capture driver. + * + * This function performs the following operations: + * - Exits VI channel driver subsystem using @ref vi_channel_drv_exit(). + * - Unregisters platform driver using @ref platform_driver_unregister(). + */ static void __exit capture_vi_exit(void) { vi_channel_drv_exit(); diff --git a/drivers/platform/tegra/rtcpu/camchar.c b/drivers/platform/tegra/rtcpu/camchar.c index 67fd36e7..1d021597 100644 --- a/drivers/platform/tegra/rtcpu/camchar.c +++ b/drivers/platform/tegra/rtcpu/camchar.c @@ -44,6 +44,29 @@ static DEFINE_SPINLOCK(tegra_camchar_lock); static dev_t tegra_camchar_major_number; static struct class *tegra_camchar_class; +/** + * @brief Opens the Tegra camera character device. + * + * This function performs the following operations: + * - Retrieves the device-specific data from the provided @ref inode structure + * using @ref container_of(). + * - Checks if the device is already open. + * - Calls @ref tegra_ivc_channel_runtime_get() to obtain a runtime reference + * to the channel. + * - Marks the device as open and the connection as not established. + * - Assigns the channel to the file's private data. + * - Calls @ref nonseekable_open() to complete the open operation. + * + * @param[in] in Pointer to the @ref inode structure representing the device. + * Valid value: non-null. + * @param[in, out] f Pointer to the @ref file structure for the device file. + * Valid value: non-null. + * + * @retval EOK Successfully opened the device. + * @retval -EBUSY The device is already open. + * @retval (int) Returned errors from @ref tegra_ivc_channel_runtime_get() or + * @ref nonseekable_open(). + */ static int tegra_camchar_open(struct inode *in, struct file *f) { struct tegra_camchar_data *data; @@ -64,6 +87,23 @@ static int tegra_camchar_open(struct inode *in, struct file *f) return nonseekable_open(in, f); } +/** + * @brief Releases the Tegra camera character device. + * + * This function performs the following operations: + * - Retrieves the channel from the file's private data. + * - Obtains the device-specific data by calling @ref tegra_ivc_channel_get_drvdata(). + * - Calls @ref tegra_ivc_channel_runtime_put() to release the runtime reference + * to the channel. + * - Marks the device as closed. + * + * @param[in] in Pointer to the @ref inode structure representing the device. + * Valid value: non-null. + * @param[in] fp Pointer to the @ref file structure for the device file. + * Valid value: non-null. + * + * @retval EOK Successfully released the device. + */ static int tegra_camchar_release(struct inode *in, struct file *fp) { struct tegra_ivc_channel *ch = fp->private_data; @@ -76,6 +116,31 @@ static int tegra_camchar_release(struct inode *in, struct file *fp) return 0; } +/** + * @brief Polls the Tegra CamChar device for I/O readiness. + * + * This function performs the following operations: + * - Retrieves the driver data associated with the file pointer using + * @ref tegra_ivc_channel_get_drvdata(). + * - Waits for events on the device's wait queue by calling @ref poll_wait(). + * - Locks the I/O lock using @ref mutex_lock() to ensure exclusive access. + * - Checks if the device can be read by invoking @ref tegra_ivc_can_read(). + * - Checks if the device can be written by invoking @ref tegra_ivc_can_write(). + * - Unlocks the I/O lock using @ref mutex_unlock() after the checks. + * - Sets the appropriate event flags in the return value based on readability and writability. + * + * @param[in] fp Pointer to the @ref file structure. + * Valid value: non-null. + * @param[in] pt Pointer to the @ref poll_table_struct. + * Valid value: non-null. + * + * @retval 0 No events are available for + * reading or writing. + * @retval (EPOLLIN | EPOLLRDNORM) Data is available for reading. + * @retval (EPOLLOUT | EPOLLWRNORM) Space is available for writing. + * @retval (EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM) Data is available for both + * reading and writing. + */ static __poll_t tegra_camchar_poll(struct file *fp, struct poll_table_struct *pt) { __poll_t ret = 0; @@ -94,6 +159,45 @@ static __poll_t tegra_camchar_poll(struct file *fp, struct poll_table_struct *pt return ret; } +/** + * @brief Reads data from the Tegra camera character device. + * + * This function performs the following operations: + * - Retrieves the channel from the file's private data. + * - Obtains the device-specific data by calling @ref tegra_ivc_channel_get_drvdata(). + * - Checks if the channel is ready by verifying the @ref tegra_ivc_channel.is_ready flag. + * - Limits the read length to the minimum of the requested length and the channel's + * frame size using @ref min_t(). + * - If the adjusted length is zero, returns immediately with no data to read. + * - Attempts to acquire the I/O lock interruptibly by calling @ref mutex_lock_interruptible(). + * - Prepares to wait on the device's wait queue by calling @ref prepare_to_wait(). + * - Calls @ref tegra_ivc_read() to perform the actual read operation. + * - Releases the I/O lock using @ref mutex_unlock(). + * - Exit read operation if @ref tegra_ivc_read() returns @ref -ENOMEM and: + * - A signal is pending based on @ref signal_pending(). + * - If the file is opened with @ref O_NONBLOCK flag enabled. + * - Otherwise, retries the read operation. + * - Cleans up the wait by calling @ref finish_wait(). + * + * @param[in] fp Pointer to the @ref file structure. + * Valid value: non-null. + * @param[out] buffer User-space buffer to store the read data. + * Valid value: non-null. + * @param[in] len Number of bytes to read. + * Valid range: [0 .. channel's frame size]. + * @param[in, out] offset File position offset. + * Valid value: non-null. + * + * @retval -EIO If the channel is not ready. + * @retval 0 If the adjusted read length is zero. + * @retval -EINTR If the read operation was interrupted by a signal, + * as determined by @ref signal_pending(). + * @retval -EAGAIN If the file is opened with @ref O_NONBLOCK and no data is available, + * as determined by @ref tegra_ivc_read(). + * @retval (ssize_t) If postive, number of bytes successfully read. If negative, error + * codes returned from @ref tegra_ivc_read() or + * @ref mutex_lock_interruptible(). + */ static ssize_t tegra_camchar_read(struct file *fp, char __user *buffer, size_t len, loff_t *offset) { @@ -134,6 +238,58 @@ static ssize_t tegra_camchar_read(struct file *fp, char __user *buffer, size_t l return ret; } +/** + * @brief Writes data to the Tegra CamChar device. + * + * This function performs the following operations: + * - Retrieves the channel from the file's private data. + * - Obtains the device-specific data by calling + * @ref tegra_ivc_channel_get_drvdata(). + * - Defines a wait queue using @ref DEFINE_WAIT(). + * - Checks if the channel is ready using @ref WARN_ON(). + * - Limits the write length to the minimum of the requested length and the + * channel's frame size using @ref min_t(). + * - If the adjusted length is zero, returns 0 indicating no data to write. + * - Enters a loop to attempt the write operation: + * - Acquires the I/O lock interruptibly by calling + * @ref mutex_lock_interruptible(). + * - If the lock acquisition is interrupted, breaks the loop. + * - Prepares to wait on the device's wait queue by calling + * @ref prepare_to_wait(). + * - Calls @ref tegra_ivc_write() to perform the actual write operation. + * - Releases the I/O lock using @ref mutex_unlock(). + * - If the write operation is successful, marks the connection as established. + * - Handles specific error conditions: + * - If @ref tegra_ivc_write() returns @ref -ENOMEM or @ref ECONNRESET, + * and a signal is pending as determined by @ref signal_pending(). + * - If the file is opened with @c O_NONBLOCK and no data can be written. + * - Otherwise, calls @ref schedule() to retry the write operation. + * - Cleans up the wait by calling @ref finish_wait(). + * - If a connection reset occurs and the connection was established, breaks + * the loop. + * + * @param[in] fp Pointer to the @ref file structure. + * Valid Value: non-NULL. + * @param[in] buffer User-space buffer containing the data to write. + * Valid Value: non-NULL. + * @param[in] len Number of bytes to write. + * Valid Range: [0 .. channel's frame size]. + * @param[in, out] offset File position offset. + * Valid Value: non-NULL. + * + * @retval -EIO If the channel is not ready, as determined by + * @ref WARN_ON(). + * @retval 0 If the adjusted write length is zero. + * @retval -EINTR If the write operation was interrupted by a signal, + * as determined by @ref mutex_lock_interruptible() + * or @ref signal_pending(). + * @retval -EAGAIN If the file is opened with @ref O_NONBLOCK and no data + * can be written, as determined by @ref tegra_ivc_write(). + * @retval (ssize_t) If positive, number of bytes successfully written. If negative, + * error codes returned from @ref tegra_ivc_write(), + * @ref mutex_lock_interruptible(), or other internal + * mechanisms such as @ref schedule() or @ref finish_wait(). + */ static ssize_t tegra_camchar_write(struct file *fp, const char __user *buffer, size_t len, loff_t *offset) { @@ -182,6 +338,36 @@ static ssize_t tegra_camchar_write(struct file *fp, const char __user *buffer, return ret; } +/** + * @brief Handles ioctl commands for the Tegra camera character device. + * + * This function performs the following operations: + * - Retrieves the channel from the file's private data. + * - Obtains the device-specific data by calling @ref tegra_ivc_channel_get_drvdata(). + * - Acquires the I/O lock by calling @ref mutex_lock(). + * - Processes the ioctl command @a cmd using a switch statement: + * - For the @ref FIONREAD command: + * - Checks if the device can be read by invoking @ref tegra_ivc_can_read(). + * - Copies channel frame size to user space by calling @ref put_user(). + * - For the @ref CCIOGNFRAMES command: + * - Copies the number of frames in the channel to user space by calling @ref put_user(). + * - For the @ref CCIOGNBYTES command: + * - Copies the channel's frame size to user space by calling @ref put_user(). + * - Releases the I/O lock by calling @ref mutex_unlock(). + * + * @param[in] fp Pointer to the @ref file structure. + * Valid value: non-null. + * @param[in] cmd Ioctl command number. + * Valid value: Supported ioctl commands such as + * @ref FIONREAD, @ref CCIOGNFRAMES, and @ref CCIOGNBYTES. + * @param[in] arg User-space pointer where the ioctl result will be stored. + * Valid value: Valid user-space address. + * + * @retval 0 Successfully handled the @c FIONREAD command and data is copied + * to user space. + * @retval -ENOTTY The ioctl command @a cmd is not supported. + * @retval (long) Error codes returned from @ref mutex_lock() or @ref put_user(). + */ static long tegra_camchar_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { @@ -231,6 +417,32 @@ static const struct file_operations tegra_camchar_fops = { #endif }; +/** + * @brief Initializes the Tegra camera character device driver. + * + * This function performs the following operations: + * - Allocates a range of character device numbers by calling + * @ref alloc_chrdev_region(). + * - Extracts the major number from the allocated device number using @ref MAJOR(). + * - Creates a device class for the character device by calling + * @ref class_create() or @ref class_create(). + * - Checks if class creation was successful. If it fails: + * - Unregisters the allocated device numbers by calling + * @ref unregister_chrdev_region(). + * - Registers the IVC driver by calling @ref tegra_ivc_driver_register(). + * - Checks if driver registration was successful. If it fails: + * - Destroys the created class using @ref class_destroy(). + * - Unregisters the allocated device numbers by calling + * @ref unregister_chrdev_region(). + * - Logs an informational message indicating successful loading of the driver. + * + * @param[in] drv Pointer to the @ref tegra_ivc_driver structure. + * Valid value: non-null. + * + * @retval 0 Successfully initialized the device driver. + * @retval (int) Error returned from @ref alloc_chrdev_region(), @ref class_create(), + * @ref PTR_ERR(), or @ref tegra_ivc_driver_register(). + */ static int __init tegra_camchar_init(struct tegra_ivc_driver *drv) { int ret; @@ -270,6 +482,21 @@ init_err_class: return ret; } +/** + * @brief Exits and cleans up the Tegra camera character device driver. + * + * This function performs the following operations: + * - Creates a device number using @ref MKDEV() with the major number and minor number 0. + * - Unregisters the IVC driver by calling @ref tegra_ivc_driver_unregister(). + * - Destroys the device class by calling @ref class_destroy(). + * - Unregisters the allocated character device numbers by calling + * @ref unregister_chrdev_region(). + * - Resets the major number to 0. + * - Logs an informational message indicating successful unloading of the driver. + * + * @param[in] drv Pointer to the @ref tegra_ivc_driver structure. + * Valid value: non-null. + */ static void __exit tegra_camchar_exit(struct tegra_ivc_driver *drv) { dev_t num = MKDEV(tegra_camchar_major_number, 0); @@ -282,6 +509,17 @@ static void __exit tegra_camchar_exit(struct tegra_ivc_driver *drv) pr_info("camchar: unloaded rtcpu character device driver\n"); } +/** + * @brief Notifies the Tegra camera character device of an event. + * + * This function performs the following operations: + * - Obtains the device-specific data by calling @ref tegra_ivc_channel_get_drvdata(). + * - Wakes up any processes waiting on the device's wait queue by calling + * @ref wake_up_interruptible(). + * + * @param[in] ch Pointer to the @ref tegra_ivc_channel structure. + * Valid value: non-null. + */ static void tegra_camchar_notify(struct tegra_ivc_channel *ch) { struct tegra_camchar_data *dev_data = tegra_ivc_channel_get_drvdata(ch); @@ -289,6 +527,19 @@ static void tegra_camchar_notify(struct tegra_ivc_channel *ch) wake_up_interruptible(&dev_data->waitq); } +/** + * @brief Allocates and returns the first available minor number for the CamChar device. + * + * This function performs the following operations: + * - Acquires the spinlock by calling @ref spin_lock(). + * - Finds the first available minor number by calling @ref find_first_zero_bit(). + * - If an available minor number is found: + * - Marks it as used by calling @ref set_bit(). + * - Releases the spinlock by calling @ref spin_unlock(). + * + * @retval (int) An available minor number, determined by @ref find_first_zero_bit(). + * @retval -ENODEV If no available minor number was found. + */ static int tegra_camchar_get_minor(void) { int minor; @@ -306,6 +557,19 @@ static int tegra_camchar_get_minor(void) return minor; } +/** + * @brief Releases a minor number for the Tegra camera character device. + * + * This function performs the following operations: + * - Acquires the spinlock by calling @ref spin_lock(). + * - Checks if the provided minor number is within the valid range. + * - If valid, clears the corresponding bit in @ref tegra_camchar_minor_map + * using @ref clear_bit(). + * - Releases the spinlock by calling @ref spin_unlock(). + * + * @param[in] minor Minor number to release. + * Valid range: [0 .. @ref DEVICE_COUNT - 1]. + */ static void tegra_camchar_put_minor(unsigned minor) { spin_lock(&tegra_camchar_lock); @@ -316,6 +580,37 @@ static void tegra_camchar_put_minor(unsigned minor) spin_unlock(&tegra_camchar_lock); } +/** + * @brief Probes and initializes the Tegra CamChar device. + * + * This function performs the following operations: + * - Retrieves the device name from the device tree by invoking @ref of_device_get_match_data() + * with the provided @ref ch.dev. + * - If device name is NULL, read string from device tree property "nvidia,devname" using + * @ref of_property_read_string(). + * - Allocates memory for device data using @ref devm_kzalloc(). + * - Initializes the character device structure using @ref cdev_init(). + * - Sets the owner of the character device to @ref THIS_MODULE. + * - Initializes the wait queue head using @ref init_waitqueue_head(). + * - Initializes the I/O mutex using @ref mutex_init(). + * - Associates the device data with the provided @ref tegra_ivc_channel using + * @ref tegra_ivc_channel_set_drvdata(). + * - Allocates a minor number retrieved using @ref tegra_camchar_get_minor(). + * - Creates a device number using @ref MKDEV(). + * - Adds the character device to the system using @ref cdev_add(). + * - In case of failure, release minor number using @ref tegra_camchar_put_minor(). + * - Creates the device in sysfs using @ref device_create(). + * - In case of failure, release minor number using @ref tegra_camchar_put_minor(). + * + * @param[in] ch Pointer to the @ref tegra_ivc_channel structure. + * Valid value: non-null. + * + * @retval EOK Successfully probed and initialized the device. + * @retval -ENOMEM @ref devm_kzalloc() failed. + * @retval -ENODEV No available minor number was found using @ref tegra_camchar_get_minor(). + * @retval (int) Other error codes indicating failure during device initialization originating + * from @ref cdev_add(), @ref device_create, or @ref of_property_read_string(). + */ static int tegra_camchar_probe(struct tegra_ivc_channel *ch) { const char *devname; @@ -369,6 +664,21 @@ static int tegra_camchar_probe(struct tegra_ivc_channel *ch) return ret; } +/** + * @brief Removes the Tegra CamChar device. + * + * This function performs the following operations: + * - Retrieves the device-specific data by calling + * @ref tegra_ivc_channel_get_drvdata(). + * - Obtains the device number from the device data. + * - Destroys the device by calling @ref device_destroy(). + * - Deletes the character device by calling @ref cdev_del(). + * - Releases the allocated minor number by calling + * @ref tegra_camchar_put_minor(). + * + * @param[in] ch Pointer to the @ref tegra_ivc_channel structure. + * Valid Value: non-NULL. + */ static void tegra_camchar_remove(struct tegra_ivc_channel *ch) { struct tegra_camchar_data *data = tegra_ivc_channel_get_drvdata(ch);