@@ -143,7 +143,7 @@ config SCSI_UFS_TI_J721E
If unsure, say N.
config SCSI_UFS_BSG
- bool "Universal Flash Storage BSG device node"
+ tristate "Universal Flash Storage BSG device node"
depends on SCSI_UFSHCD
select BLK_DEV_BSGLIB
help
@@ -6,7 +6,7 @@ obj-$(CONFIG_SCSI_UFS_CDNS_PLATFORM) += cdns-pltfrm.o
obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o
ufshcd-core-y += ufshcd.o ufs-sysfs.o
-ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o
+obj-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o
obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o
@@ -4,6 +4,7 @@
*
* Copyright (C) 2018 Western Digital Corporation
*/
+#include <linux/platform_device.h>
#include "ufs_bsg.h"
static int ufs_bsg_get_query_desc_size(struct ufs_hba *hba, int *desc_len,
@@ -158,53 +159,45 @@ static int ufs_bsg_request(struct bsg_job *job)
/**
* ufs_bsg_remove - detach and remove the added ufs-bsg node
- * @hba: per adapter object
+ * @pdev: Pointer to platform device handle
*
- * Should be called when unloading the driver.
+ * Return zero for success and non-zero for failure
*/
-void ufs_bsg_remove(struct ufs_hba *hba)
+static int ufs_bsg_remove(struct platform_device *pdev)
{
- struct device *bsg_dev = &hba->bsg_dev;
+ struct ufs_hba *hba;
+
+ hba = (struct ufs_hba *)pdev->dev.platform_data;
+ if (!hba)
+ return -ENODEV;
if (!hba->bsg_queue)
- return;
+ return 0;
bsg_remove_queue(hba->bsg_queue);
+ hba->bsg_queue = NULL;
- device_del(bsg_dev);
- put_device(bsg_dev);
-}
-
-static inline void ufs_bsg_node_release(struct device *dev)
-{
- put_device(dev->parent);
+ return 0;
}
/**
- * ufs_bsg_probe - Add ufs bsg device node
- * @hba: per adapter object
+ * ufs_bsg_probe - Probe routine of the driver
+ * @pdev: Pointer to platform device handle
*
- * Called during initial loading of the driver, and before scsi_scan_host.
+ * Return zero for success and non-zero for failure
*/
-int ufs_bsg_probe(struct ufs_hba *hba)
+static int ufs_bsg_probe(struct platform_device *pdev)
{
- struct device *bsg_dev = &hba->bsg_dev;
- struct Scsi_Host *shost = hba->host;
- struct device *parent = &shost->shost_gendev;
+ struct ufs_hba *hba;
+ struct device *bsg_dev;
struct request_queue *q;
int ret;
- device_initialize(bsg_dev);
-
- bsg_dev->parent = get_device(parent);
- bsg_dev->release = ufs_bsg_node_release;
-
- dev_set_name(bsg_dev, "ufs-bsg");
-
- ret = device_add(bsg_dev);
- if (ret)
- goto out;
+ hba = (struct ufs_hba *)pdev->dev.platform_data;
+ if (!hba)
+ return -ENODEV;
+ bsg_dev = &pdev->dev;
q = bsg_setup_queue(bsg_dev, dev_name(bsg_dev), ufs_bsg_request, NULL, 0);
if (IS_ERR(q)) {
ret = PTR_ERR(q);
@@ -216,7 +209,19 @@ int ufs_bsg_probe(struct ufs_hba *hba)
return 0;
out:
- dev_err(bsg_dev, "fail to initialize a bsg dev %d\n", shost->host_no);
- put_device(bsg_dev);
+ dev_err(bsg_dev, "fail to initialize bsg node, err %d\n", ret);
return ret;
}
+
+static struct platform_driver ufs_bsg_driver = {
+ .probe = ufs_bsg_probe,
+ .remove = ufs_bsg_remove,
+ .driver = {
+ .name = "ufs-bsg",
+ },
+};
+
+module_platform_driver(ufs_bsg_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ufs-bsg");
@@ -12,12 +12,4 @@
#include "ufshcd.h"
#include "ufs.h"
-#ifdef CONFIG_SCSI_UFS_BSG
-void ufs_bsg_remove(struct ufs_hba *hba);
-int ufs_bsg_probe(struct ufs_hba *hba);
-#else
-static inline void ufs_bsg_remove(struct ufs_hba *hba) {}
-static inline int ufs_bsg_probe(struct ufs_hba *hba) {return 0; }
-#endif
-
#endif /* UFS_BSG_H */
@@ -393,6 +393,7 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
void __iomem *mmio_base;
int irq, err;
struct device *dev = &pdev->dev;
+ struct platform_device *bsg_pdev;
mmio_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mmio_base)) {
@@ -440,6 +441,17 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
+ bsg_pdev = platform_device_register_data(dev, "ufs-bsg",
+ hba->host->host_no, hba,
+ sizeof(struct ufs_hba));
+ /* Failure here is non-fatal */
+ if (IS_ERR(bsg_pdev)) {
+ err = PTR_ERR(bsg_pdev);
+ dev_warn(dev, "Register bsg platform device failed %d\n", err);
+ } else {
+ hba->bsg_pdev = bsg_pdev;
+ }
+
return 0;
dealloc_host:
@@ -42,6 +42,7 @@
#include <linux/nls.h>
#include <linux/of.h>
#include <linux/bitfield.h>
+#include <linux/platform_device.h>
#include "ufshcd.h"
#include "ufs_quirks.h"
#include "unipro.h"
@@ -2093,6 +2094,7 @@ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
ufshcd_release(hba);
return ret;
}
+EXPORT_SYMBOL_GPL(ufshcd_send_uic_cmd);
/**
* ufshcd_map_sg - Map scatter-gather list to prdt
@@ -6024,6 +6026,7 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
return err;
}
+EXPORT_SYMBOL_GPL(ufshcd_exec_raw_upiu_cmd);
/**
* ufshcd_eh_device_reset_handler - device reset handler registered to
@@ -7043,9 +7046,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
}
hba->clk_scaling.is_allowed = true;
}
-
- ufs_bsg_probe(hba);
-
scsi_scan_host(hba->host);
pm_runtime_put_sync(hba->dev);
}
@@ -8248,7 +8248,7 @@ int ufshcd_shutdown(struct ufs_hba *hba)
*/
void ufshcd_remove(struct ufs_hba *hba)
{
- ufs_bsg_remove(hba);
+ platform_device_unregister(hba->bsg_pdev);
ufs_sysfs_remove_nodes(hba->dev);
scsi_remove_host(hba->host);
scsi_host_put(hba->host);
@@ -734,7 +734,7 @@ struct ufs_hba {
struct ufs_desc_size desc_size;
atomic_t scsi_block_reqs_cnt;
- struct device bsg_dev;
+ struct platform_device *bsg_pdev;
struct request_queue *bsg_queue;
};
In order to improve the flexibility of ufs-bsg, modularizing it is a good choice. This change introduces tristate to ufs-bsg to allow users compile it as an external module. Signed-off-by: Can Guo <cang@codeaurora.org>