mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 09:11:26 +03:00
vblk:vmtd:oops: doxygen comments for external API
Jira SSV-12897 Change-Id: Ie4b8d54a601a3a904e02f9f93e4ae52ae0447b3c Signed-off-by: Sanjith T D <std@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3336860 GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com> Reviewed-by: svcacv <svcacv@nvidia.com> Reviewed-by: Sreenivas Velpula <svelpula@nvidia.com> Reviewed-by: Vipin Kumar <vipink@nvidia.com>
This commit is contained in:
@@ -127,6 +127,42 @@ static int32_t wait_for_fops_completion(struct vblk_dev *vblkdev_oops, bool is_r
|
||||
return retry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup oops_driver_read_write OOPSDriver::Read/Write
|
||||
*
|
||||
* @ingroup oops_driver_read_write
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Read data from virtual block device
|
||||
*
|
||||
* Reads data from virtual block device by:
|
||||
* 1. Validating read parameters and context
|
||||
* 2. Calculating block position and count
|
||||
* 3. Preparing read request for Storage Server
|
||||
* 4. Sending request via IVC
|
||||
* 5. Waiting for response and copying data
|
||||
*
|
||||
* @param[out] buf Buffer to read data into
|
||||
* @param[in] bytes Number of bytes to read
|
||||
* @param[in] pos Starting position to read from
|
||||
* @return Number of bytes read on success, negative errno on failure
|
||||
*
|
||||
* @pre Device must be initialized and IVC channel ready
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t vblk_oops_read(char *buf, size_t bytes, loff_t pos)
|
||||
{
|
||||
struct vsc_request *vsc_req;
|
||||
@@ -221,6 +257,35 @@ fail:
|
||||
return -ENOMSG;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write data to virtual block device
|
||||
*
|
||||
* Writes data to virtual block device by:
|
||||
* 1. Validating write parameters and context
|
||||
* 2. Calculating block position and count
|
||||
* 3. Preparing write request for Storage Server
|
||||
* 4. Sending request via IVC
|
||||
* 5. Waiting for response and verifying completion
|
||||
*
|
||||
* @param[in] buf Buffer containing data to write
|
||||
* @param[in] bytes Number of bytes to write
|
||||
* @param[in] pos Starting position to write to
|
||||
* @return Number of bytes written on success, negative errno on failure
|
||||
*
|
||||
* @pre Device must be initialized and IVC channel ready
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t vblk_oops_write(const char *buf, size_t bytes,
|
||||
loff_t pos)
|
||||
{
|
||||
@@ -241,7 +306,8 @@ static ssize_t vblk_oops_write(const char *buf, size_t bytes,
|
||||
*/
|
||||
if (in_atomic()) {
|
||||
dev_warn(vblkdev_oops->device,
|
||||
"%s invoked in atomic context..aborting\n", __func__);
|
||||
"%s invoked in atomic context..returning EBUSY to retry from workqueue\n",
|
||||
__func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@@ -334,6 +400,35 @@ fail:
|
||||
* - no need to check for VSC response. Send request and assume it is all good
|
||||
* since the caller is not going to do anything meaningful if we report error
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Write data to virtual block device during panic
|
||||
*
|
||||
* Best-effort write during system panic by:
|
||||
* 1. Validating basic parameters
|
||||
* 2. Calculating block position and count
|
||||
* 3. Preparing write request for Storage Server
|
||||
* 4. Sending request via IVC without waiting for response
|
||||
*
|
||||
* @param[in] buf Buffer containing data to write
|
||||
* @param[in] bytes Number of bytes to write
|
||||
* @param[in] pos Starting position to write to
|
||||
* @return Number of bytes written on success, 0 on failure
|
||||
*
|
||||
* @pre Device must be initialized, system in panic state
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: Yes
|
||||
* - Signal handler: Yes
|
||||
* - Thread-safe: No
|
||||
* - Async/Sync: Async
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t vblk_oops_panic_write(const char *buf, size_t bytes,
|
||||
loff_t pos)
|
||||
{
|
||||
@@ -415,6 +510,7 @@ static ssize_t vblk_oops_panic_write(const char *buf, size_t bytes,
|
||||
*/
|
||||
return bytes;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/* Set up virtual device. */
|
||||
static void setup_device(struct vblk_dev *vblkdev)
|
||||
@@ -683,6 +779,39 @@ static int vblk_oops_get_configinfo(struct vblk_dev *vblkdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup oops_driver_request_handler OOPSDriver::Request Handler
|
||||
*
|
||||
* @ingroup oops_driver_request_handler
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Initialize the OOPS virtual block device
|
||||
*
|
||||
* Initializes the virtual block device by:
|
||||
* 1. Checking if IVC channel reset is complete
|
||||
* 2. If reset complete and data can be read from IVC channel:
|
||||
* - Gets device configuration from Storage Server
|
||||
* - Sets up device parameters
|
||||
* - Registers with pstore_zone
|
||||
*
|
||||
* @param[in] ws Work structure pointer containing device info
|
||||
* @return None
|
||||
*
|
||||
* @pre Device structure must be allocated and work structure initialized
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Async
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: Yes
|
||||
* - Runtime: No
|
||||
* - De-Init: No
|
||||
*/
|
||||
static void vblk_oops_init_device(struct work_struct *ws)
|
||||
{
|
||||
struct vblk_dev *vblkdev = container_of(ws, struct vblk_dev, init.work);
|
||||
@@ -709,6 +838,40 @@ static void vblk_oops_init_device(struct work_struct *ws)
|
||||
}
|
||||
}
|
||||
|
||||
/**@} */
|
||||
|
||||
/**
|
||||
* @defgroup oops_driver_probe OOPSDriver::Probe
|
||||
*
|
||||
* @ingroup oops_driver_probe
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Probe function to initialize OOPS storage device driver
|
||||
*
|
||||
* Sets up virtual block device for storing kernel crash dumps by:
|
||||
* - Allocating device structure
|
||||
* - Reading device tree properties
|
||||
* - Setting up IVC channel
|
||||
* - Configuring pstore parameters
|
||||
*
|
||||
* @param[in] pdev Platform device pointer from device tree
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre Platform must be running in virtualized environment with hypervisor
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: Yes
|
||||
* - Runtime: No
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int tegra_hv_vblk_oops_probe(struct platform_device *pdev)
|
||||
{
|
||||
static struct device_node *vblk_node;
|
||||
@@ -804,6 +967,8 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**@} */
|
||||
|
||||
static int tegra_hv_vblk_oops_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vblk_dev *vblkdev = platform_get_drvdata(pdev);
|
||||
@@ -815,7 +980,36 @@ static int tegra_hv_vblk_oops_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup oops_driver_suspend_resume OOPSDriver::Suspend/Resume
|
||||
*
|
||||
* @ingroup oops_driver_suspend_resume
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/**
|
||||
* @brief Suspend the OOPS storage device
|
||||
*
|
||||
* Resets the IVC channel during system suspend.
|
||||
*
|
||||
* @param[in] dev Device structure pointer
|
||||
* @return 0 on success
|
||||
*
|
||||
* @pre Device must be initialized and active
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int tegra_hv_vblk_oops_suspend(struct device *dev)
|
||||
{
|
||||
/* Reset the channel */
|
||||
@@ -826,6 +1020,28 @@ static int tegra_hv_vblk_oops_suspend(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resume the OOPS storage device
|
||||
*
|
||||
* Waits for IVC channel reset completion during system resume.
|
||||
*
|
||||
* @param[in] dev Device structure pointer
|
||||
* @return 0 on success, -EIO on timeout
|
||||
*
|
||||
* @pre Device must be in suspended state
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int tegra_hv_vblk_oops_resume(struct device *dev)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -841,12 +1057,15 @@ static int tegra_hv_vblk_oops_resume(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct dev_pm_ops tegra_hv_vblk_oops_pm_ops = {
|
||||
.suspend_noirq = tegra_hv_vblk_oops_suspend,
|
||||
.resume_noirq = tegra_hv_vblk_oops_resume,
|
||||
};
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id tegra_hv_vblk_oops_match[] = {
|
||||
{ .compatible = "nvidia,tegra-hv-oops-storage", },
|
||||
@@ -855,6 +1074,34 @@ static const struct of_device_id tegra_hv_vblk_oops_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, tegra_hv_vblk_oops_match);
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
/**
|
||||
* @defgroup oops_driver_module_init_exit OOPSDriver::Module Init/Exit
|
||||
*
|
||||
* @ingroup oops_driver_module_init_exit
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Function for OOPS device removal
|
||||
*
|
||||
* Unreserves the IVC channel and mempool during device removal.
|
||||
*
|
||||
* @param[in] pdev Platform device pointer
|
||||
* @return void or int depending on kernel version
|
||||
*
|
||||
* @pre Device must have been previously probed successfully
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: No
|
||||
* - De-Init: Yes
|
||||
*/
|
||||
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
|
||||
static void tegra_hv_vblk_oops_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
@@ -880,18 +1127,62 @@ static struct platform_driver tegra_hv_vblk_oops_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Initialize the Tegra Hypervisor Virtual OOPS Block Device driver
|
||||
*
|
||||
* Initializes the virtual block device driver for storing kernel crash dumps.
|
||||
* Registers the platform driver for OOPS storage functionality.
|
||||
*
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre None
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: Yes
|
||||
* - Runtime: No
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int __init tegra_hv_vblk_driver_init(void)
|
||||
{
|
||||
return platform_driver_register(&tegra_hv_vblk_oops_driver);
|
||||
}
|
||||
module_init(tegra_hv_vblk_driver_init);
|
||||
|
||||
/**
|
||||
* @brief Cleanup and remove the Tegra Hypervisor Virtual OOPS Block Device driver
|
||||
*
|
||||
* Unregisters the platform driver for OOPS storage functionality.
|
||||
*
|
||||
* @return None
|
||||
*
|
||||
* @pre Driver must have been initialized via tegra_hv_vblk_driver_init()
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: No
|
||||
* - De-Init: Yes
|
||||
*/
|
||||
static void __exit tegra_hv_vblk_driver_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&tegra_hv_vblk_oops_driver);
|
||||
}
|
||||
module_exit(tegra_hv_vblk_driver_exit);
|
||||
|
||||
/** @} */
|
||||
MODULE_AUTHOR("Haribabu Narayanan <hnarayanan@nvidia.com>");
|
||||
MODULE_DESCRIPTION("Virtual OOPS storage device over Tegra Hypervisor IVC channel");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -191,7 +191,42 @@ static int vblk_common_ioctl(struct vblk_dev *vblkdev, fmode_t mode,
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup vscd_ioctl LinuxVSCD::IOCTL
|
||||
*
|
||||
* @ingroup vscd_ioctl
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Handles IOCTL commands for firmware update operations
|
||||
*
|
||||
* This function processes IOCTL commands specifically for firmware updates.
|
||||
* It temporarily enables FFU passthrough command permissions, processes the IOCTL,
|
||||
* then disables FFU permissions again. This provides controlled access to firmware
|
||||
* update capabilities through a dedicated interface.
|
||||
*
|
||||
* @param[in] bdev Pointer to the block device structure
|
||||
* @param[in] mode File mode flags
|
||||
* @param[in] cmd IOCTL command code
|
||||
* @param[in] arg Command-specific argument
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Block device must be opened through FFU interface
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
int vblk_ffu_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
@@ -207,7 +242,37 @@ int vblk_ffu_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The ioctl() implementation */
|
||||
/**
|
||||
* @brief Handles IOCTL commands for normal block device operations
|
||||
*
|
||||
* This function processes IOCTL commands for the block device, supporting:
|
||||
* - MMC IOC commands (single and multi)
|
||||
* - SCSI generic (SG_IO) commands
|
||||
* - UFS combo query commands
|
||||
* The function validates permissions and delegates to specific handlers.
|
||||
*
|
||||
* @param[in] bdev Pointer to the block device structure
|
||||
* @param[in] mode File mode flags
|
||||
* @param[in] cmd IOCTL command code
|
||||
* @param[in] arg Command-specific argument
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Block device must be opened
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
int vblk_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
@@ -221,7 +286,35 @@ int vblk_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The ioctl() implementation for block device node */
|
||||
/**
|
||||
* @brief Handles IOCTL commands for non-control device nodes
|
||||
*
|
||||
* This function rejects IOCTL commands that are only supported on the control device node.
|
||||
* It returns -ENOTTY for MMC, SCSI, and UFS commands when called on regular block device nodes.
|
||||
* This enforces access control by requiring privileged operations to use the control node.
|
||||
*
|
||||
* @param[in] bdev Pointer to the block device structure
|
||||
* @param[in] mode File mode flags
|
||||
* @param[in] cmd IOCTL command code
|
||||
* @param[in] arg Command-specific argument
|
||||
* @return -ENOTTY to indicate command is not supported
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Block device must be opened
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
int vblk_ioctl_not_supported(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
@@ -245,3 +338,4 @@ int vblk_ioctl_not_supported(struct block_device *bdev, fmode_t mode,
|
||||
|
||||
return ret;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@@ -755,6 +755,47 @@ bio_exit:
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup vscd_request_worker LinuxVSCD::Request Worker
|
||||
*
|
||||
* @ingroup vscd_request_worker
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Worker thread that handles block device requests and completions
|
||||
*
|
||||
* This worker thread is responsible for:
|
||||
* 1. Processing completed block I/O requests from the virtual storage server
|
||||
* 2. Submitting new block I/O requests to the virtual storage server
|
||||
* 3. Managing the request queue and IVC communication
|
||||
*
|
||||
* The worker runs in a loop waiting for requests to be queued. When woken up, it:
|
||||
* - Acquires the IVC lock to synchronize access to the IVC channel
|
||||
* - Processes any completed requests from the server via complete_bio_req()
|
||||
* - Submits new pending requests to the server via submit_bio_req()
|
||||
* - Continues processing until no more requests are pending
|
||||
*
|
||||
* @param[in] data Pointer to the vblk_dev device structure
|
||||
* @param[out] None
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre
|
||||
* - vblk device must be initialized
|
||||
* - IVC channel must be established
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Async
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int vblk_request_worker(void *data)
|
||||
{
|
||||
struct vblk_dev *vblkdev = (struct vblk_dev *)data;
|
||||
@@ -782,9 +823,45 @@ static int vblk_request_worker(void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The simple form of the request function. */
|
||||
/**
|
||||
* @brief Block request handler callback for multi-queue block device
|
||||
*
|
||||
* This function is the main request handler for the virtual block device driver.
|
||||
* When the block layer submits I/O requests, this callback:
|
||||
* 1. Marks the request as started using blk_mq_start_request()
|
||||
* 2. Allocates a new request entry structure
|
||||
* 3. Adds the request to the device's pending request list
|
||||
* 4. Wakes up the worker thread to process the request
|
||||
*
|
||||
* The actual I/O processing is done asynchronously by the worker thread, which:
|
||||
* - Submits requests to the virtual storage server via IVC
|
||||
* - Handles completions and error cases
|
||||
* - Manages the request lifecycle
|
||||
*
|
||||
* @param[in] hctx Block multi-queue hardware context
|
||||
* @param[in] bd Block request data containing the request to process
|
||||
*
|
||||
* @return BLK_STS_OK on success, BLK_STS_IOERR on failure
|
||||
*
|
||||
* @pre
|
||||
* - Block device must be initialized
|
||||
* - Request queue must be setup
|
||||
* - Worker thread must be running
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Async
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static blk_status_t vblk_request(struct blk_mq_hw_ctx *hctx,
|
||||
const struct blk_mq_queue_data *bd)
|
||||
const struct blk_mq_queue_data *bd)
|
||||
{
|
||||
struct req_entry *entry;
|
||||
struct request *req = bd->rq;
|
||||
@@ -813,8 +890,43 @@ static blk_status_t vblk_request(struct blk_mq_hw_ctx *hctx,
|
||||
|
||||
return BLK_STS_OK;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/* Open and release */
|
||||
/**
|
||||
* @defgroup vscd_open_release LinuxVSCD::Open/Release
|
||||
*
|
||||
* @ingroup vscd_open_release
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Opens a virtual block device for normal I/O operations
|
||||
*
|
||||
* This function is called when a block device is opened for I/O operations.
|
||||
* It increments the user count and checks for media changes if this is the first user.
|
||||
* The media change check ensures the device state is current before allowing access.
|
||||
*
|
||||
* @param[in] disk Pointer to the gendisk structure representing the block device
|
||||
* @param[in] mode File mode flags indicating how the device should be opened
|
||||
* @return 0 on success
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Disk structure must be valid
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
#if defined(NV_BLOCK_DEVICE_OPERATIONS_OPEN_HAS_GENDISK_ARG) /* Linux v6.5 */
|
||||
static int vblk_open(struct gendisk *disk, fmode_t mode)
|
||||
{
|
||||
@@ -839,6 +951,33 @@ static int vblk_open(struct block_device *device, fmode_t mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Opens a virtual block device for IOCTL operations
|
||||
*
|
||||
* This function is called when opening the IOCTL-specific device node.
|
||||
* It increments the IOCTL user count, checks for media changes if first user,
|
||||
* and initializes FFU passthrough command permissions to disabled state.
|
||||
*
|
||||
* @param[in] disk Pointer to the gendisk structure representing the block device
|
||||
* @param[in] mode File mode flags indicating how the device should be opened
|
||||
* @return 0 on success
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Disk structure must be valid
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
#if defined(NV_BLOCK_DEVICE_OPERATIONS_OPEN_HAS_GENDISK_ARG) /* Linux v6.5 */
|
||||
static int vblk_ioctl_open(struct gendisk *disk, fmode_t mode)
|
||||
{
|
||||
@@ -864,6 +1003,33 @@ static int vblk_ioctl_open(struct block_device *device, fmode_t mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Opens a virtual block device for firmware update operations
|
||||
*
|
||||
* This function is called when opening the FFU-specific device node.
|
||||
* It increments the FFU user count, checks for media changes if first user,
|
||||
* and initializes FFU passthrough command permissions to disabled state.
|
||||
*
|
||||
* @param[in] disk Pointer to the gendisk structure representing the block device
|
||||
* @param[in] mode File mode flags indicating how the device should be opened
|
||||
* @return 0 on success
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Disk structure must be valid
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
#if defined(NV_BLOCK_DEVICE_OPERATIONS_OPEN_HAS_GENDISK_ARG)
|
||||
static int vblk_ffu_open(struct gendisk *disk, fmode_t mode)
|
||||
{
|
||||
@@ -887,6 +1053,33 @@ static int vblk_ffu_open(struct block_device *device, fmode_t mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases a virtual block device after IOCTL operations
|
||||
*
|
||||
* This function is called when closing the IOCTL-specific device node.
|
||||
* It safely decrements the IOCTL user count using overflow checking to prevent underflow.
|
||||
* The IOCTL interface remains available for other users if count is non-zero.
|
||||
*
|
||||
* @param[in] disk Pointer to the gendisk structure representing the block device
|
||||
* @param[in] mode File mode flags indicating how the device was opened
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Disk structure must be valid
|
||||
* - Device must have been previously opened for IOCTL operations
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: Yes
|
||||
*/
|
||||
#if defined(NV_BLOCK_DEVICE_OPERATIONS_RELEASE_HAS_NO_MODE_ARG) /* Linux v6.5 */
|
||||
static void vblk_ioctl_release(struct gendisk *disk)
|
||||
#else
|
||||
@@ -906,6 +1099,33 @@ static void vblk_ioctl_release(struct gendisk *disk, fmode_t mode)
|
||||
spin_unlock(&vblkdev->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases a virtual block device after firmware update operations
|
||||
*
|
||||
* This function is called when closing the FFU-specific device node.
|
||||
* It safely decrements the FFU user count using overflow checking to prevent underflow.
|
||||
* The FFU interface remains available for other users if count is non-zero.
|
||||
*
|
||||
* @param[in] disk Pointer to the gendisk structure representing the block device
|
||||
* @param[in] mode File mode flags indicating how the device was opened
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Disk structure must be valid
|
||||
* - Device must have been previously opened for FFU operations
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: Yes
|
||||
*/
|
||||
#if defined(NV_BLOCK_DEVICE_OPERATIONS_RELEASE_HAS_NO_MODE_ARG)
|
||||
static void vblk_ffu_release(struct gendisk *disk)
|
||||
#else
|
||||
@@ -921,7 +1141,33 @@ static void vblk_ffu_release(struct gendisk *disk, fmode_t mode)
|
||||
spin_unlock(&vblkdev->lock);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Releases a virtual block device after normal I/O operations
|
||||
*
|
||||
* This function is called when a block device is closed after I/O operations.
|
||||
* It safely decrements the user count using overflow checking to prevent underflow.
|
||||
* The device remains operational for other users if the count is non-zero.
|
||||
*
|
||||
* @param[in] disk Pointer to the gendisk structure representing the block device
|
||||
* @param[in] mode File mode flags indicating how the device was opened
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Disk structure must be valid
|
||||
* - Device must have been previously opened
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: Yes
|
||||
*/
|
||||
#if defined(NV_BLOCK_DEVICE_OPERATIONS_RELEASE_HAS_NO_MODE_ARG) /* Linux v6.5 */
|
||||
static void vblk_release(struct gendisk *disk)
|
||||
#else
|
||||
@@ -941,6 +1187,33 @@ static void vblk_release(struct gendisk *disk, fmode_t mode)
|
||||
spin_unlock(&vblkdev->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the geometry information for the virtual block device
|
||||
*
|
||||
* This function returns the logical geometry (heads, sectors, cylinders) for the block device.
|
||||
* It uses fixed values for heads and sectors, and calculates cylinders based on device capacity.
|
||||
* This information is used by legacy tools that expect disk geometry information.
|
||||
*
|
||||
* @param[in] device Pointer to the block device structure
|
||||
* @param[out] geo Pointer to hd_geometry structure to fill with geometry information
|
||||
* @return 0 on success
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Block device structure must be valid
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int vblk_getgeo(struct block_device *device, struct hd_geometry *geo)
|
||||
{
|
||||
geo->heads = VS_LOG_HEADS;
|
||||
@@ -950,6 +1223,7 @@ static int vblk_getgeo(struct block_device *device, struct hd_geometry *geo)
|
||||
|
||||
return 0;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/* The device operations structure. */
|
||||
static const struct block_device_operations vblk_ops_no_ioctl = {
|
||||
@@ -978,9 +1252,45 @@ static const struct block_device_operations vblk_ops_ffu = {
|
||||
.ioctl = vblk_ffu_ioctl
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
vblk_phys_dev_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
/**
|
||||
* @defgroup vscd_sysfs LinuxVSCD::Sysfs
|
||||
*
|
||||
* @ingroup vscd_sysfs
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Shows the physical device type (EMMC/UFS) backing this virtual block device
|
||||
*
|
||||
* This function implements the sysfs show function for the "phys_dev" attribute.
|
||||
* It reads the physical device type from the vblk device configuration and returns
|
||||
* a string indicating whether the underlying storage device is EMMC or UFS.
|
||||
*
|
||||
* @param[in] dev Pointer to the device structure
|
||||
* @param[in] attr Pointer to the device attribute structure
|
||||
* @param[out] buf Buffer to store the attribute value string
|
||||
*
|
||||
* @return Number of bytes written to buffer on success, negative errno on failure
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Configuration must be valid
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t vblk_phys_dev_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct gendisk *disk = dev_to_disk(dev);
|
||||
struct vblk_dev *vblk = disk->private_data;
|
||||
@@ -993,9 +1303,39 @@ vblk_phys_dev_show(struct device *dev, struct device_attribute *attr,
|
||||
return snprintf(buf, 16, "Unknown\n");
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
vblk_phys_base_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
/**
|
||||
* @brief Shows the physical base address of the storage device
|
||||
*
|
||||
* This function implements the sysfs show function for the "phys_base" attribute.
|
||||
* It reads the physical base address from the vblk device configuration and formats
|
||||
* it as a hexadecimal string. This represents the base address of the physical
|
||||
* storage device in memory.
|
||||
*
|
||||
* @param[in] dev Pointer to the device structure
|
||||
* @param[in] attr Pointer to the device attribute structure
|
||||
* @param[out] buf Buffer to store the attribute value string
|
||||
*
|
||||
* @return Number of bytes written to buffer on success, negative errno on failure
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Configuration must be valid
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t vblk_phys_base_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct gendisk *disk = dev_to_disk(dev);
|
||||
struct vblk_dev *vblk = disk->private_data;
|
||||
@@ -1003,9 +1343,39 @@ vblk_phys_base_show(struct device *dev, struct device_attribute *attr,
|
||||
return snprintf(buf, 16, "0x%llx\n", vblk->config.phys_base);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
vblk_storage_type_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
/**
|
||||
* @brief Shows the storage type/partition (RPMB, BOOT, LUNx) of this virtual block device
|
||||
*
|
||||
* This function implements the sysfs show function for the "storage_type" attribute.
|
||||
* It reads the storage type from the vblk device configuration and returns a string
|
||||
* indicating the type of storage partition this device represents (e.g. RPMB, BOOT,
|
||||
* or one of the logical unit numbers LUN0-LUN7).
|
||||
*
|
||||
* @param[in] dev Pointer to the device structure
|
||||
* @param[in] attr Pointer to the device attribute structure
|
||||
* @param[out] buf Buffer to store the attribute value string
|
||||
*
|
||||
* @return Number of bytes written to buffer on success, negative errno on failure
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Configuration must be valid
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t vblk_storage_type_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct gendisk *disk = dev_to_disk(dev);
|
||||
struct vblk_dev *vblk = disk->private_data;
|
||||
@@ -1038,9 +1408,39 @@ vblk_storage_type_show(struct device *dev, struct device_attribute *attr,
|
||||
return snprintf(buf, 16, "Unknown\n");
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
vblk_speed_mode_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
/**
|
||||
* @brief Shows the speed mode configuration of the storage device
|
||||
*
|
||||
* This function implements the sysfs show function for the "speed_mode" attribute.
|
||||
* It reads the speed mode string from the vblk device configuration and returns it.
|
||||
* The speed mode indicates the operating speed configuration of the underlying
|
||||
* physical storage device (e.g. HS400, HS200 for eMMC or HS-G3 for UFS).
|
||||
*
|
||||
* @param[in] dev Pointer to the device structure
|
||||
* @param[in] attr Pointer to the device attribute structure
|
||||
* @param[out] buf Buffer to store the attribute value string
|
||||
*
|
||||
* @return Number of bytes written to buffer on success, negative errno on failure
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Configuration must be valid
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t vblk_speed_mode_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct gendisk *disk = dev_to_disk(dev);
|
||||
struct vblk_dev *vblk = disk->private_data;
|
||||
@@ -1068,6 +1468,7 @@ static const struct blk_mq_ops vblk_mq_ops = {
|
||||
.queue_rq = vblk_request,
|
||||
};
|
||||
|
||||
/** @} */
|
||||
#if (IS_ENABLED(CONFIG_TEGRA_HSIERRRPTINJ))
|
||||
|
||||
/* Error report injection test support is included */
|
||||
@@ -1874,6 +2275,51 @@ static void vblk_init_device(struct work_struct *ws)
|
||||
mutex_unlock(&vblkdev->ivc_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup vscd_irq_timer LinuxVSCD::IRQ/Timer
|
||||
*
|
||||
* @ingroup vscd_irq_timer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Interrupt handler for IVC (Inter-VM Communication) events
|
||||
*
|
||||
* This function handles interrupts from the IVC channel for the virtual block device.
|
||||
* It performs two key tasks depending on device initialization state:
|
||||
*
|
||||
* 1. For initialized devices:
|
||||
* - Wakes up the worker thread by completing the worker completion
|
||||
* - Worker thread then processes any pending IVC messages/requests
|
||||
*
|
||||
* 2. For uninitialized devices:
|
||||
* - Schedules initialization work on appropriate CPU
|
||||
* - CPU selection based on schedulable_vcpu_number if specified, else uses default CPU
|
||||
* - Initialization includes setting up device config, queues and other resources
|
||||
*
|
||||
* The handler ensures proper synchronization between interrupt context and worker thread
|
||||
* for processing IVC messages.
|
||||
*
|
||||
* @param[in] irq Interrupt number
|
||||
* @param[in] data Pointer to the virtual block device structure (struct vblk_dev)
|
||||
* @return IRQ_HANDLED to indicate interrupt was processed
|
||||
*
|
||||
* @pre
|
||||
* - IVC channel must be configured
|
||||
* - Device structure must be allocated and basic init done
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: Yes
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Async
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static irqreturn_t ivc_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct vblk_dev *vblkdev = (struct vblk_dev *)data;
|
||||
@@ -1889,6 +2335,49 @@ static irqreturn_t ivc_irq_handler(int irq, void *data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Timer callback function to handle block I/O request timeouts
|
||||
*
|
||||
* This function is called when a block I/O request timer expires, indicating that
|
||||
* the request has taken longer than expected to complete. It handles timeout
|
||||
* conditions by:
|
||||
* 1. Converting the timer structure back to the request structure using container_of
|
||||
* 2. Logging an error message with:
|
||||
* - The request ID that timed out
|
||||
* - Current system counter value
|
||||
* - Original request schedule time
|
||||
* This helps identify stuck or slow I/O requests for debugging purposes.
|
||||
*
|
||||
* @param[in] timer Pointer to the timer_list structure that expired
|
||||
*
|
||||
* @pre
|
||||
* - Timer must be initialized and started for a valid vsc_request
|
||||
* - vblkdev device structure must be valid
|
||||
* - Request must be in-flight when timer expires
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: Yes
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Async
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static void bio_request_timeout_callback(struct timer_list *timer)
|
||||
{
|
||||
struct vsc_request *req = from_timer(req, timer, timer);
|
||||
|
||||
dev_err(req->vblkdev->device, "Request id %d timed out. curr ctr: %llu sched ctr: %llu\n",
|
||||
req->id, _arch_counter_get_cntvct(), req->time);
|
||||
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
static void vblk_request_config(struct work_struct *ws)
|
||||
{
|
||||
struct vblk_dev *vblkdev = container_of(ws, struct vblk_dev, rq_cfg);
|
||||
@@ -1922,15 +2411,6 @@ free_ivc:
|
||||
tegra_hv_ivc_unreserve(vblkdev->ivck);
|
||||
}
|
||||
|
||||
static void bio_request_timeout_callback(struct timer_list *timer)
|
||||
{
|
||||
struct vsc_request *req = from_timer(req, timer, timer);
|
||||
|
||||
dev_err(req->vblkdev->device, "Request id %d timed out. curr ctr: %llu sched ctr: %llu\n",
|
||||
req->id, _arch_counter_get_cntvct(), req->time);
|
||||
|
||||
}
|
||||
|
||||
static void tegra_create_timers(struct vblk_dev *vblkdev)
|
||||
{
|
||||
uint32_t i;
|
||||
@@ -1940,6 +2420,45 @@ static void tegra_create_timers(struct vblk_dev *vblkdev)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup vscd_probe_remove LinuxVSCD::Probe/Remove
|
||||
*
|
||||
* @ingroup vscd_probe_remove
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Probe function to initialize and setup virtual block device driver
|
||||
*
|
||||
* This function initializes a virtual block device that provides virtualized storage access
|
||||
* in a hypervisor environment. It performs the following key steps:
|
||||
* 1. Allocates and initializes the virtual block device structure
|
||||
* 2. Sets up IVC (Inter-VM Communication) channel for storage commands
|
||||
* 3. Configures the block device parameters like size, operations etc.
|
||||
* 4. Creates block device nodes:
|
||||
* - Main block device for regular I/O
|
||||
* - IOCTL device node for control operations
|
||||
* - FFU (Firmware Field Update) device node
|
||||
* 5. Initializes request queues and work queues
|
||||
* 6. Sets up device attributes
|
||||
*
|
||||
* @param[in] dev Platform device pointer from device tree
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre Platform must be running in virtualized environment with hypervisor
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: Yes
|
||||
* - Runtime: No
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int tegra_hv_vblk_probe(struct platform_device *pdev)
|
||||
{
|
||||
static struct device_node *vblk_node;
|
||||
@@ -2034,6 +2553,34 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove function to cleanup and remove virtual block device driver
|
||||
*
|
||||
* This function performs cleanup when the virtual block device is removed.
|
||||
* Key cleanup steps include:
|
||||
* 1. Waits for pending requests to complete
|
||||
* 2. Removes block device nodes (main, ioctl and ffu)
|
||||
* 3. Cleans up request queues
|
||||
* 4. Frees IVC channels and shared memory
|
||||
* 5. Frees device structures and resources
|
||||
*
|
||||
* @param[in] dev Platform device pointer for the device being removed
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre Device must have been previously probed successfully
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: No
|
||||
* - De-Init: Yes
|
||||
*/
|
||||
static int tegra_hv_vblk_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vblk_dev *vblkdev = platform_get_drvdata(pdev);
|
||||
@@ -2079,7 +2626,50 @@ static int tegra_hv_vblk_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup vscd_suspend_resume LinuxVSCD::Suspend/Resume
|
||||
*
|
||||
* @ingroup vscd_suspend_resume
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/**
|
||||
* @brief Suspends the virtual block device driver
|
||||
*
|
||||
* This function handles the suspend operation for the virtual block device by:
|
||||
* 1. Stopping hardware request queues for both regular I/O and IOCTL operations
|
||||
* 2. Setting queue state to suspended
|
||||
* 3. Waiting for any inflight requests to complete
|
||||
* 4. Disabling IVC interrupts once queue is empty
|
||||
*
|
||||
* The function ensures clean suspension by:
|
||||
* - Using spinlocks to safely stop queues
|
||||
* - Tracking inflight requests via completion mechanism
|
||||
* - Properly handling both regular and IOCTL queues
|
||||
* - Disabling interrupts only after all requests complete
|
||||
*
|
||||
* @param[in] dev Pointer to device structure
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Driver must be in active state
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int tegra_hv_vblk_suspend(struct device *dev)
|
||||
{
|
||||
struct vblk_dev *vblkdev = dev_get_drvdata(dev);
|
||||
@@ -2111,6 +2701,41 @@ static int tegra_hv_vblk_suspend(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resumes the virtual block device driver
|
||||
*
|
||||
* This function handles the resume operation for the virtual block device by:
|
||||
* 1. Setting queue state back to active
|
||||
* 2. Reinitializing completion tracking
|
||||
* 3. Re-enabling IVC interrupts
|
||||
* 4. Restarting hardware request queues for both regular I/O and IOCTL operations
|
||||
* 5. Waking up worker thread to process any pending requests
|
||||
*
|
||||
* The function ensures clean resume by:
|
||||
* - Using spinlocks to safely restart queues
|
||||
* - Properly handling both regular and IOCTL queues
|
||||
* - Re-enabling interrupts before processing requests
|
||||
* - Signaling worker thread to check for pending work
|
||||
*
|
||||
* @param[in] dev Pointer to device structure
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Driver must be in suspended state
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int tegra_hv_vblk_resume(struct device *dev)
|
||||
{
|
||||
struct vblk_dev *vblkdev = dev_get_drvdata(dev);
|
||||
@@ -2141,6 +2766,8 @@ static int tegra_hv_vblk_resume(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
static const struct dev_pm_ops tegra_hv_vblk_pm_ops = {
|
||||
.suspend = tegra_hv_vblk_suspend,
|
||||
.resume = tegra_hv_vblk_resume,
|
||||
@@ -2180,6 +2807,40 @@ static struct platform_driver tegra_hv_vblk_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @defgroup vscd_module_init_exit LinuxVSCD::Module Init/Exit
|
||||
*
|
||||
* @ingroup vscd_module_init_exit
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Initialize the Tegra Hypervisor Virtual Block Device driver
|
||||
*
|
||||
* This function initializes the virtual block device driver that enables storage
|
||||
* virtualization in Tegra Hypervisor environments. It performs the following:
|
||||
* - Registers the block device driver with the kernel
|
||||
* - Allocates major number for block devices
|
||||
* - Initializes the virtual block device framework
|
||||
* - Sets up IVC (Inter-VM Communication) channels for storage operations
|
||||
* - Creates sysfs entries for device attributes
|
||||
*
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre None
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: Yes
|
||||
* - Runtime: No
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int __init tegra_hv_vblk_driver_init(void)
|
||||
{
|
||||
vblk_major = 0;
|
||||
@@ -2193,12 +2854,42 @@ static int __init tegra_hv_vblk_driver_init(void)
|
||||
}
|
||||
module_init(tegra_hv_vblk_driver_init);
|
||||
|
||||
/**
|
||||
* @brief Cleanup and remove the Tegra Hypervisor Virtual Block Device driver
|
||||
*
|
||||
* This function performs cleanup when the virtual block device driver is removed.
|
||||
* It handles:
|
||||
* - Unregistering the block device driver
|
||||
* - Freeing allocated major number
|
||||
* - Cleaning up IVC channels
|
||||
* - Removing sysfs entries
|
||||
* - Freeing allocated resources
|
||||
*
|
||||
* @return None
|
||||
*
|
||||
* @pre Driver must have been initialized via tegra_hv_vblk_driver_init()
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: No
|
||||
* - De-Init: Yes
|
||||
*/
|
||||
static void __exit tegra_hv_vblk_driver_exit(void)
|
||||
{
|
||||
unregister_blkdev(vblk_major, "vblk");
|
||||
platform_driver_unregister(&tegra_hv_vblk_driver);
|
||||
}
|
||||
module_exit(tegra_hv_vblk_driver_exit);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
MODULE_AUTHOR("Dilan Lee <dilee@nvidia.com>");
|
||||
MODULE_DESCRIPTION("Virtual storage device over Tegra Hypervisor IVC channel");
|
||||
|
||||
@@ -69,6 +69,46 @@ static inline struct vmtd_dev *mtd_to_vmtd(struct mtd_info *mtd)
|
||||
return container_of(mtd, struct vmtd_dev, mtd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup vscd_mtd_irq_timer LinuxMtdVSCD::IRQ/Timer
|
||||
*
|
||||
* @ingroup vscd_mtd_irq_timer
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Interrupt handler for IVC (Inter-VM Communication) channel
|
||||
*
|
||||
* This function serves as the interrupt service routine for the IVC channel.
|
||||
* When an IVC interrupt occurs, it:
|
||||
* 1. Signals completion of an IVC transaction by calling complete()
|
||||
* 2. Wakes up any threads waiting on IVC communication
|
||||
* 3. Enables further IVC communication to proceed
|
||||
*
|
||||
* The handler is essential for the asynchronous nature of IVC communication,
|
||||
* allowing the driver to efficiently handle command/response sequences without
|
||||
* busy waiting.
|
||||
*
|
||||
* @param[in] irq The interrupt number being handled
|
||||
* @param[in] data Pointer to the vmtd_dev structure (passed as void*)
|
||||
* @return IRQ_HANDLED indicating successful handling of the interrupt
|
||||
*
|
||||
* @pre
|
||||
* - IVC channel must be properly initialized
|
||||
* - Completion structure must be initialized
|
||||
* - IRQ must be properly registered with this handler
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: Yes
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: Yes
|
||||
* - Runtime: Yes
|
||||
* - De-Init: Yes
|
||||
*/
|
||||
static irqreturn_t ivc_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct vmtd_dev *vmtddev = (struct vmtd_dev *)data;
|
||||
@@ -76,6 +116,9 @@ static irqreturn_t ivc_irq_handler(int irq, void *data)
|
||||
complete(&vmtddev->msg_complete);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
static int vmtd_send_cmd(struct vmtd_dev *vmtddev, struct vs_request *vs_req)
|
||||
{
|
||||
@@ -206,9 +249,48 @@ static int vmtd_get_configinfo(struct vmtd_dev *vmtddev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read an address range from the flash chip. The address range
|
||||
* may be any size provided it is within the physical boundaries.
|
||||
/**
|
||||
* @defgroup vscd_mtd_request_handler LinuxMtdVSCD::Request Handler
|
||||
*
|
||||
* @ingroup vscd_mtd_request_handler
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Reads data from the virtual MTD device
|
||||
*
|
||||
* This function reads data from the virtual MTD device by:
|
||||
* 1. Validating read boundaries against device size
|
||||
* 2. Breaking down large reads into smaller chunks based on max_read_bytes_per_io
|
||||
* 3. For each chunk:
|
||||
* - Preparing VS_MTD_READ request
|
||||
* - Sending request through IVC channel
|
||||
* - Waiting for response from physical device
|
||||
* - Copying data from shared buffer to user buffer
|
||||
* 4. Maintaining thread safety through mutex locking
|
||||
*
|
||||
* @param[in] mtd Pointer to MTD device information structure
|
||||
* @param[in] from Starting offset in the device to read from
|
||||
* @param[in] len Number of bytes to read
|
||||
* @param[out] retlen Pointer to store number of bytes actually read
|
||||
* @param[out] buf Buffer to store read data
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - IVC channel must be operational
|
||||
* - Shared memory buffer must be mapped
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int vmtd_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf)
|
||||
@@ -264,9 +346,44 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write an address range from the flash chip. The address range
|
||||
* may be any size provided it is within the physical boundaries.
|
||||
/**
|
||||
* @brief Writes data to the virtual MTD device
|
||||
*
|
||||
* This function writes data to the virtual MTD device by:
|
||||
* 1. Validating write boundaries against device size
|
||||
* 2. Breaking down large writes into smaller chunks based on max_write_bytes_per_io
|
||||
* 3. For each chunk:
|
||||
* - Copying data from user buffer to shared memory
|
||||
* - Preparing VS_MTD_WRITE request
|
||||
* - Sending request through IVC channel
|
||||
* - Waiting for write confirmation
|
||||
* 4. Maintaining thread safety through mutex locking
|
||||
* 5. Handling write failures and partial writes
|
||||
*
|
||||
* @param[in] mtd Pointer to MTD device information structure
|
||||
* @param[in] to Starting offset in the device to write to
|
||||
* @param[in] len Number of bytes to write
|
||||
* @param[out] retlen Pointer to store number of bytes actually written
|
||||
* @param[in] buf Buffer containing data to write
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - IVC channel must be operational
|
||||
* - Shared memory buffer must be mapped
|
||||
* - Device must not be in read-only mode
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int vmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf)
|
||||
@@ -323,9 +440,42 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Erase an address range from the flash chip. The address range
|
||||
* may be any size provided it is within the physical boundaries.
|
||||
/**
|
||||
* @brief Erases a region of the virtual MTD device
|
||||
*
|
||||
* This function erases a specified region of the virtual MTD device by:
|
||||
* 1. Validating erase boundaries against device size
|
||||
* 2. Preparing VS_MTD_ERASE request with:
|
||||
* - Starting address (instr->addr)
|
||||
* - Length of region to erase (instr->len)
|
||||
* 3. Sending single erase command through IVC channel
|
||||
* 4. Waiting for erase completion confirmation
|
||||
* 5. Maintaining thread safety through mutex locking
|
||||
* 6. Handling erase failures
|
||||
*
|
||||
* @param[in] mtd Pointer to MTD device information structure
|
||||
* @param[in] instr Erase instruction structure containing:
|
||||
* - Address to start erasing from
|
||||
* - Length of region to erase
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - IVC channel must be operational
|
||||
* - Device must not be in read-only mode
|
||||
* - Erase region must be aligned to erase block size
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int vmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
{
|
||||
@@ -366,8 +516,51 @@ static int vmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup vscd_mtd_suspend_resume LinuxMtdVSCD::Suspend/Resume
|
||||
*
|
||||
* @ingroup vscd_mtd_suspend_resume
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
/**
|
||||
* @brief Suspends the virtual MTD device operations
|
||||
*
|
||||
* This function performs the following operations during system suspend:
|
||||
* 1. Checks if the device is properly set up
|
||||
* 2. Acquires the device mutex to prevent concurrent access
|
||||
* 3. Disables the IVC interrupt to prevent further communications
|
||||
* 4. Resets the IVC channel to ensure clean state during suspend
|
||||
*
|
||||
* The function ensures that all ongoing MTD operations are properly halted
|
||||
* and the communication channel with the hypervisor is safely suspended.
|
||||
*
|
||||
* @param[in] dev Pointer to the device structure
|
||||
* @return 0 on success
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - System must be in suspend transition
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int tegra_virt_mtd_suspend(struct device *dev)
|
||||
{
|
||||
struct vmtd_dev *vmtddev = dev_get_drvdata(dev);
|
||||
@@ -379,6 +572,37 @@ static int tegra_virt_mtd_suspend(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resumes the virtual MTD device operations
|
||||
*
|
||||
* This function performs the following operations during system resume:
|
||||
* 1. Checks if the device was properly set up before suspend
|
||||
* 2. Re-enables the IVC interrupt to restore communication
|
||||
* 3. Releases the device mutex to allow MTD operations
|
||||
*
|
||||
* The function restores the device to operational state after system resume,
|
||||
* re-establishing the communication channel with the hypervisor and
|
||||
* allowing MTD operations to proceed.
|
||||
*
|
||||
* @param[in] dev Pointer to the device structure
|
||||
* @return 0 on success
|
||||
*
|
||||
* @pre
|
||||
* - Device must have been previously suspended
|
||||
* - System must be in resume transition
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int tegra_virt_mtd_resume(struct device *dev)
|
||||
{
|
||||
struct vmtd_dev *vmtddev = dev_get_drvdata(dev);
|
||||
@@ -397,6 +621,10 @@ static const struct dev_pm_ops tegra_hv_vmtd_pm_ops = {
|
||||
};
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
static int vmtd_setup_device(struct vmtd_dev *vmtddev)
|
||||
{
|
||||
mutex_init(&vmtddev->lock);
|
||||
@@ -449,6 +677,41 @@ static int vmtd_setup_device(struct vmtd_dev *vmtddev)
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup vscd_mtd_sysfs LinuxMtdVSCD::Sysfs
|
||||
*
|
||||
* @ingroup vscd_mtd_sysfs
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Shows the physical device type of the virtual MTD device
|
||||
*
|
||||
* This function retrieves and displays the physical device type that underlies
|
||||
* the virtual MTD device. Currently, it checks if the device is a QSPI device
|
||||
* and returns the appropriate string representation. If the device type is not
|
||||
* recognized, it returns "unknown!".
|
||||
*
|
||||
* @param[in] dev Pointer to the device structure
|
||||
* @param[in] attr Pointer to device attribute structure
|
||||
* @param[out] buf Buffer to store the device type string
|
||||
* @return Number of characters written to the buffer
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Configuration must be properly set up
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t vmtd_phys_dev_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -461,6 +724,34 @@ static ssize_t vmtd_phys_dev_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR(phys_dev, 0444, vmtd_phys_dev_show, NULL);
|
||||
|
||||
/**
|
||||
* @brief Shows the physical base address of the virtual MTD device
|
||||
*
|
||||
* This function retrieves and displays the physical base address of the underlying
|
||||
* MTD device in hexadecimal format. This address represents the starting memory
|
||||
* location of the physical flash device in the system's memory map.
|
||||
*
|
||||
* @param[in] dev Pointer to the device structure
|
||||
* @param[in] attr Pointer to device attribute structure
|
||||
* @param[out] buf Buffer to store the base address string
|
||||
* @return Number of characters written to the buffer
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Configuration must be properly set up
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t vmtd_phys_base_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -470,6 +761,34 @@ static ssize_t vmtd_phys_base_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR(phys_base, 0444, vmtd_phys_base_show, NULL);
|
||||
|
||||
/**
|
||||
* @brief Shows the manufacturer ID of the MTD device
|
||||
*
|
||||
* This function retrieves and displays the manufacturer ID of the flash device
|
||||
* in hexadecimal format. The manufacturer ID is a unique identifier that
|
||||
* indicates the company that manufactured the flash memory chip.
|
||||
*
|
||||
* @param[in] dev Pointer to the device structure
|
||||
* @param[in] attr Pointer to device attribute structure
|
||||
* @param[out] buf Buffer to store the manufacturer ID string
|
||||
* @return Number of characters written to the buffer
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Configuration must be properly set up
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t manufacturer_id_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -479,6 +798,34 @@ static ssize_t manufacturer_id_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RO(manufacturer_id);
|
||||
|
||||
/**
|
||||
* @brief Shows the device ID of the MTD device
|
||||
*
|
||||
* This function retrieves and displays the device ID of the flash device
|
||||
* in hexadecimal format. The device ID is a unique identifier that
|
||||
* specifies the particular model or variant of the flash memory chip.
|
||||
*
|
||||
* @param[in] dev Pointer to the device structure
|
||||
* @param[in] attr Pointer to device attribute structure
|
||||
* @param[out] buf Buffer to store the device ID string
|
||||
* @return Number of characters written to the buffer
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Configuration must be properly set up
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t device_id_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -488,6 +835,34 @@ static ssize_t device_id_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RO(device_id);
|
||||
|
||||
/**
|
||||
* @brief Shows the QSPI device size in bytes
|
||||
*
|
||||
* This function retrieves and displays the total size of the QSPI flash device
|
||||
* in bytes. This represents the total storage capacity of the physical flash
|
||||
* memory device that is being virtualized.
|
||||
*
|
||||
* @param[in] dev Pointer to the device structure
|
||||
* @param[in] attr Pointer to device attribute structure
|
||||
* @param[out] buf Buffer to store the device size string
|
||||
* @return Number of characters written to the buffer
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - Configuration must be properly set up
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t qspi_device_size_bytes_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -497,6 +872,39 @@ static ssize_t qspi_device_size_bytes_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RO(qspi_device_size_bytes);
|
||||
|
||||
/**
|
||||
* @brief Shows the ECC (Error Correction Code) status of the MTD device
|
||||
*
|
||||
* This function performs an ECC status check and returns the current ECC state.
|
||||
* It sends a VS_MTD_ECC request to the physical device and interprets the response.
|
||||
* Possible status values are:
|
||||
* - ECC_NO_ERROR: No errors detected
|
||||
* - ECC_ONE_BIT_CORRECTED: Single-bit error detected and corrected
|
||||
* - ECC_TWO_BIT_ERROR: Double-bit error detected (uncorrectable)
|
||||
* - ECC_DISABLED: ECC functionality is disabled
|
||||
* - ECC_REQUEST_FAILED: Failed to get ECC status
|
||||
*
|
||||
* @param[in] dev Pointer to the device structure
|
||||
* @param[in] attr Pointer to device attribute structure
|
||||
* @param[out] buf Buffer to store the ECC status string
|
||||
* @return Number of characters written to the buffer
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - IVC channel must be operational
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t ecc_status_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -538,6 +946,35 @@ static ssize_t ecc_status_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RO(ecc_status);
|
||||
|
||||
/**
|
||||
* @brief Shows the address of the chunk where ECC failure occurred
|
||||
*
|
||||
* This function retrieves and displays the memory address of the chunk where
|
||||
* the last ECC error was detected. The address is displayed in hexadecimal format.
|
||||
* After reading the address, it resets the stored address to 0 to prepare for
|
||||
* the next ECC error detection.
|
||||
*
|
||||
* @param[in] dev Pointer to the device structure
|
||||
* @param[in] attr Pointer to device attribute structure
|
||||
* @param[out] buf Buffer to store the failure chunk address string
|
||||
* @return Number of characters written to the buffer
|
||||
*
|
||||
* @pre
|
||||
* - Device must be initialized
|
||||
* - ECC status should have been checked previously
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: Yes
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: Yes
|
||||
* - De-Init: No
|
||||
*/
|
||||
static ssize_t failure_chunk_addr_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -551,6 +988,9 @@ static ssize_t failure_chunk_addr_show(struct device *dev,
|
||||
|
||||
}
|
||||
static DEVICE_ATTR_RO(failure_chunk_addr);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
static const struct attribute *vmtd_storage_attrs[] = {
|
||||
&dev_attr_phys_dev.attr,
|
||||
@@ -685,6 +1125,46 @@ static int32_t vmtd_init_device(struct vmtd_dev *vmtddev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup vscd_mtd_probe_remove LinuxMtdVSCD::Probe/Remove
|
||||
*
|
||||
* @ingroup vscd_mtd_probe_remove
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Probes and initializes the virtual MTD device driver
|
||||
*
|
||||
* This function performs the following initialization steps:
|
||||
* 1. Verifies hypervisor mode and device tree node
|
||||
* 2. Allocates and initializes vmtd device structure
|
||||
* 3. Reserves IVC channel for command/response communication
|
||||
* 4. Reserves IVM memory pool for data transfer
|
||||
* 5. Maps shared memory buffer for data transfer
|
||||
* 6. Sets up interrupt handling for IVC communication
|
||||
* 7. Initializes the virtual MTD device with configuration from physical device
|
||||
* 8. Creates sysfs entries for device attributes
|
||||
* 9. Registers error injection callbacks if enabled
|
||||
*
|
||||
* @param[in] pdev Platform device structure containing device information
|
||||
* @return 0 on success, negative errno on failure
|
||||
*
|
||||
* @pre
|
||||
* - System must be running in Tegra hypervisor mode
|
||||
* - Valid device tree node must be present
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: Yes
|
||||
* - Runtime: No
|
||||
* - De-Init: No
|
||||
*/
|
||||
static int tegra_virt_mtd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node __maybe_unused *np;
|
||||
@@ -816,7 +1296,38 @@ static struct of_device_id tegra_virt_mtd_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, tegra_virt_mtd_match);
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
|
||||
/**
|
||||
* @brief Removes and cleans up the virtual MTD device driver
|
||||
*
|
||||
* This function performs the following cleanup steps:
|
||||
* 1. Unreserves the IVC channel used for command/response communication
|
||||
* 2. Unreserves the IVM memory pool used for data transfer
|
||||
* 3. Deregisters error injection callbacks if enabled
|
||||
* 4. Frees allocated resources
|
||||
*
|
||||
* The function exists in two variants based on kernel version:
|
||||
* - Returns void for Linux v6.11 and later
|
||||
* - Returns int for earlier versions
|
||||
*
|
||||
* @param[in] pdev Platform device structure containing device information
|
||||
* @return void or 0 depending on kernel version
|
||||
*
|
||||
* @pre
|
||||
* - Driver must be successfully probed and initialized
|
||||
*
|
||||
* @usage
|
||||
* - Allowed context for the API call
|
||||
* - Interrupt handler: No
|
||||
* - Signal handler: No
|
||||
* - Thread-safe: Yes
|
||||
* - Async/Sync: Sync
|
||||
* - Re-entrant: No
|
||||
* - API Group
|
||||
* - Init: No
|
||||
* - Runtime: No
|
||||
* - De-Init: Yes
|
||||
*/
|
||||
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
|
||||
static void tegra_virt_mtd_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
tegra_virt_mtd_remove(pdev);
|
||||
@@ -827,6 +1338,9 @@ static int tegra_virt_mtd_remove_wrapper(struct platform_device *pdev)
|
||||
return tegra_virt_mtd_remove(pdev);
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
static struct platform_driver tegra_virt_mtd_driver = {
|
||||
.probe = tegra_virt_mtd_probe,
|
||||
|
||||
Reference in New Issue
Block a user