From a9a9da47f8e6c1fe24c8bfe36c7f5ee6fc3700a1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 16 Apr 2019 16:15:54 +0200 Subject: mailbox: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Jassi Brar Signed-off-by: Greg Kroah-Hartman --- drivers/mailbox/bcm-flexrm-mailbox.c | 28 +++++----------------------- drivers/mailbox/bcm-pdc-mailbox.c | 8 ++------ 2 files changed, 7 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c index a64116586b4c..43b336316fde 100644 --- a/drivers/mailbox/bcm-flexrm-mailbox.c +++ b/drivers/mailbox/bcm-flexrm-mailbox.c @@ -296,8 +296,6 @@ struct flexrm_mbox { struct dma_pool *bd_pool; struct dma_pool *cmpl_pool; struct dentry *root; - struct dentry *config; - struct dentry *stats; struct mbox_controller controller; }; @@ -1603,7 +1601,6 @@ static int flexrm_mbox_probe(struct platform_device *pdev) 1 << RING_CMPL_ALIGN_ORDER, 0); if (!mbox->cmpl_pool) { ret = -ENOMEM; - goto fail_destroy_bd_pool; } /* Allocate platform MSIs for each ring */ @@ -1624,28 +1621,15 @@ static int flexrm_mbox_probe(struct platform_device *pdev) /* Create debugfs root entry */ mbox->root = debugfs_create_dir(dev_name(mbox->dev), NULL); - if (IS_ERR_OR_NULL(mbox->root)) { - ret = PTR_ERR_OR_ZERO(mbox->root); - goto fail_free_msis; - } /* Create debugfs config entry */ - mbox->config = debugfs_create_devm_seqfile(mbox->dev, - "config", mbox->root, - flexrm_debugfs_conf_show); - if (IS_ERR_OR_NULL(mbox->config)) { - ret = PTR_ERR_OR_ZERO(mbox->config); - goto fail_free_debugfs_root; - } + debugfs_create_devm_seqfile(mbox->dev, "config", mbox->root, + flexrm_debugfs_conf_show); /* Create debugfs stats entry */ - mbox->stats = debugfs_create_devm_seqfile(mbox->dev, - "stats", mbox->root, - flexrm_debugfs_stats_show); - if (IS_ERR_OR_NULL(mbox->stats)) { - ret = PTR_ERR_OR_ZERO(mbox->stats); - goto fail_free_debugfs_root; - } + debugfs_create_devm_seqfile(mbox->dev, "stats", mbox->root, + flexrm_debugfs_stats_show); + skip_debugfs: /* Initialize mailbox controller */ @@ -1676,11 +1660,9 @@ skip_debugfs: fail_free_debugfs_root: debugfs_remove_recursive(mbox->root); -fail_free_msis: platform_msi_domain_free_irqs(dev); fail_destroy_cmpl_pool: dma_pool_destroy(mbox->cmpl_pool); -fail_destroy_bd_pool: dma_pool_destroy(mbox->bd_pool); fail: return ret; diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index ccf3d62af7e7..a8c291386142 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -406,8 +406,6 @@ struct pdc_state { */ struct scatterlist *src_sg[PDC_RING_ENTRIES]; - struct dentry *debugfs_stats; /* debug FS stats file for this PDC */ - /* counters */ u32 pdc_requests; /* number of request messages submitted */ u32 pdc_replies; /* number of reply messages received */ @@ -512,9 +510,8 @@ static void pdc_setup_debugfs(struct pdc_state *pdcs) debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); /* S_IRUSR == 0400 */ - pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, 0400, - debugfs_dir, pdcs, - &pdc_debugfs_stats); + debugfs_create_file(spu_stats_name, 0400, debugfs_dir, pdcs, + &pdc_debugfs_stats); } static void pdc_free_debugfs(void) @@ -1614,7 +1611,6 @@ static int pdc_probe(struct platform_device *pdev) if (err) goto cleanup_buf_pool; - pdcs->debugfs_stats = NULL; pdc_setup_debugfs(pdcs); dev_dbg(dev, "pdc_probe() successful"); -- cgit v1.2.3-59-g8ed1b From ddaf29fd9bb6a8192153bc097615765d202b0ab3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 May 2019 11:26:43 +0200 Subject: firmware: Free temporary page table after vmapping Once after performing vmap() to map the S/G pages, our own page table becomes superfluous since the pages can be released via vfree() automatically. Let's change the buffer release code and discard the page table array for saving some memory. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_loader/fallback.c | 7 ++++++- drivers/base/firmware_loader/main.c | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index f962488546b6..a0a1856aac84 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -222,7 +222,7 @@ static ssize_t firmware_loading_show(struct device *dev, /* one pages buffer should be mapped/unmapped only once */ static int map_fw_priv_pages(struct fw_priv *fw_priv) { - if (!fw_priv->is_paged_buf) + if (!fw_priv->pages) return 0; vunmap(fw_priv->data); @@ -230,6 +230,11 @@ static int map_fw_priv_pages(struct fw_priv *fw_priv) PAGE_KERNEL_RO); if (!fw_priv->data) return -ENOMEM; + + /* page table is no longer needed after mapping, let's free */ + vfree(fw_priv->pages); + fw_priv->pages = NULL; + return 0; } diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 7eaaf5ee5ba6..aed1a7c56713 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -252,13 +252,13 @@ static void __free_fw_priv(struct kref *ref) spin_unlock(&fwc->lock); #ifdef CONFIG_FW_LOADER_USER_HELPER - if (fw_priv->is_paged_buf) { + if (fw_priv->pages) { + /* free leftover pages */ int i; - vunmap(fw_priv->data); for (i = 0; i < fw_priv->nr_pages; i++) __free_page(fw_priv->pages[i]); vfree(fw_priv->pages); - } else + } #endif if (!fw_priv->allocated_size) vfree(fw_priv->data); -- cgit v1.2.3-59-g8ed1b From 8f58570b98c090a4544ef9eaea1f419706672845 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 May 2019 11:26:44 +0200 Subject: firmware: Unify the paged buffer release helper Use a common helper to release the paged buffer resources. This is rather a preparation for the upcoming decompression support. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_loader/fallback.c | 8 +------- drivers/base/firmware_loader/firmware.h | 6 ++++++ drivers/base/firmware_loader/main.c | 27 ++++++++++++++++++--------- 3 files changed, 25 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index a0a1856aac84..8970a5315e85 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -259,7 +259,6 @@ static ssize_t firmware_loading_store(struct device *dev, struct fw_priv *fw_priv; ssize_t written = count; int loading = simple_strtol(buf, NULL, 10); - int i; mutex_lock(&fw_lock); fw_priv = fw_sysfs->fw_priv; @@ -270,12 +269,7 @@ static ssize_t firmware_loading_store(struct device *dev, case 1: /* discarding any previous partial load */ if (!fw_sysfs_done(fw_priv)) { - for (i = 0; i < fw_priv->nr_pages; i++) - __free_page(fw_priv->pages[i]); - vfree(fw_priv->pages); - fw_priv->pages = NULL; - fw_priv->page_array_size = 0; - fw_priv->nr_pages = 0; + fw_free_paged_buf(fw_priv); fw_state_start(fw_priv); } break; diff --git a/drivers/base/firmware_loader/firmware.h b/drivers/base/firmware_loader/firmware.h index 4c1395f8e7ed..d20d4e7f9e71 100644 --- a/drivers/base/firmware_loader/firmware.h +++ b/drivers/base/firmware_loader/firmware.h @@ -133,4 +133,10 @@ static inline void fw_state_done(struct fw_priv *fw_priv) int assign_fw(struct firmware *fw, struct device *device, enum fw_opt opt_flags); +#ifdef CONFIG_FW_LOADER_USER_HELPER +void fw_free_paged_buf(struct fw_priv *fw_priv); +#else +static inline void fw_free_paged_buf(struct fw_priv *fw_priv) {} +#endif + #endif /* __FIRMWARE_LOADER_H */ diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index aed1a7c56713..083fc3e4f2fd 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -251,15 +251,7 @@ static void __free_fw_priv(struct kref *ref) list_del(&fw_priv->list); spin_unlock(&fwc->lock); -#ifdef CONFIG_FW_LOADER_USER_HELPER - if (fw_priv->pages) { - /* free leftover pages */ - int i; - for (i = 0; i < fw_priv->nr_pages; i++) - __free_page(fw_priv->pages[i]); - vfree(fw_priv->pages); - } -#endif + fw_free_paged_buf(fw_priv); /* free leftover pages */ if (!fw_priv->allocated_size) vfree(fw_priv->data); kfree_const(fw_priv->fw_name); @@ -274,6 +266,23 @@ static void free_fw_priv(struct fw_priv *fw_priv) spin_unlock(&fwc->lock); } +#ifdef CONFIG_FW_LOADER_USER_HELPER +void fw_free_paged_buf(struct fw_priv *fw_priv) +{ + int i; + + if (!fw_priv->pages) + return; + + for (i = 0; i < fw_priv->nr_pages; i++) + __free_page(fw_priv->pages[i]); + vfree(fw_priv->pages); + fw_priv->pages = NULL; + fw_priv->page_array_size = 0; + fw_priv->nr_pages = 0; +} +#endif + /* direct firmware loading support */ static char fw_path_para[256]; static const char * const fw_path[] = { -- cgit v1.2.3-59-g8ed1b From 993f5d11a9631face2bb597826b86f476a9b915b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 May 2019 11:26:45 +0200 Subject: firmware: Use kvmalloc for page tables This is a minor optimization to use kvmalloc() variant for allocating the page table for the SG-buffer. They aren't so big in general, so kmalloc() would fit often better. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_loader/fallback.c | 7 ++++--- drivers/base/firmware_loader/main.c | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index 8970a5315e85..b5cd96fd0e77 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -232,7 +232,7 @@ static int map_fw_priv_pages(struct fw_priv *fw_priv) return -ENOMEM; /* page table is no longer needed after mapping, let's free */ - vfree(fw_priv->pages); + kvfree(fw_priv->pages); fw_priv->pages = NULL; return 0; @@ -397,7 +397,8 @@ static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size) fw_priv->page_array_size * 2); struct page **new_pages; - new_pages = vmalloc(array_size(new_array_size, sizeof(void *))); + new_pages = kvmalloc_array(new_array_size, sizeof(void *), + GFP_KERNEL); if (!new_pages) { fw_load_abort(fw_sysfs); return -ENOMEM; @@ -406,7 +407,7 @@ static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size) fw_priv->page_array_size * sizeof(void *)); memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) * (new_array_size - fw_priv->page_array_size)); - vfree(fw_priv->pages); + kvfree(fw_priv->pages); fw_priv->pages = new_pages; fw_priv->page_array_size = new_array_size; } diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 083fc3e4f2fd..2e74a1b73dae 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -276,7 +276,7 @@ void fw_free_paged_buf(struct fw_priv *fw_priv) for (i = 0; i < fw_priv->nr_pages; i++) __free_page(fw_priv->pages[i]); - vfree(fw_priv->pages); + kvfree(fw_priv->pages); fw_priv->pages = NULL; fw_priv->page_array_size = 0; fw_priv->nr_pages = 0; -- cgit v1.2.3-59-g8ed1b From 225afca60b8a21bb53ca461eef78a60958ff95e4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 11 Jun 2019 20:55:28 +0200 Subject: vmw_balloon: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Julien Freche Cc: "VMware, Inc." Cc: Arnd Bergmann Cc: linux-kernel@vger.kernel.org Acked-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index ad807d5a3141..fdf5ad757226 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -1516,19 +1516,10 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset) DEFINE_SHOW_ATTRIBUTE(vmballoon_debug); -static int __init vmballoon_debugfs_init(struct vmballoon *b) +static void __init vmballoon_debugfs_init(struct vmballoon *b) { - int error; - b->dbg_entry = debugfs_create_file("vmmemctl", S_IRUGO, NULL, b, &vmballoon_debug_fops); - if (IS_ERR(b->dbg_entry)) { - error = PTR_ERR(b->dbg_entry); - pr_err("failed to create debugfs entry, error: %d\n", error); - return error; - } - - return 0; } static void __exit vmballoon_debugfs_exit(struct vmballoon *b) @@ -1541,9 +1532,8 @@ static void __exit vmballoon_debugfs_exit(struct vmballoon *b) #else -static inline int vmballoon_debugfs_init(struct vmballoon *b) +static inline void vmballoon_debugfs_init(struct vmballoon *b) { - return 0; } static inline void vmballoon_debugfs_exit(struct vmballoon *b) @@ -1555,7 +1545,6 @@ static inline void vmballoon_debugfs_exit(struct vmballoon *b) static int __init vmballoon_init(void) { enum vmballoon_page_size_type page_size; - int error; /* * Check if we are running on VMware's hypervisor and bail out @@ -1571,9 +1560,7 @@ static int __init vmballoon_init(void) INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work); - error = vmballoon_debugfs_init(&balloon); - if (error) - return error; + vmballoon_debugfs_init(&balloon); spin_lock_init(&balloon.comm_lock); init_rwsem(&balloon.conf_sem); -- cgit v1.2.3-59-g8ed1b From 5a2338dbf97fac3a93e2ffefa5ab907ac5a9ba56 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 11 Jun 2019 20:32:13 +0200 Subject: lkdtm: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Arnd Bergmann Cc: linux-kernel@vger.kernel.org Acked-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/core.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 1972dad966f5..bae3b3763f3e 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -429,22 +429,13 @@ static int __init lkdtm_module_init(void) /* Register debugfs interface */ lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); - if (!lkdtm_debugfs_root) { - pr_err("creating root dir failed\n"); - return -ENODEV; - } /* Install debugfs trigger files. */ for (i = 0; i < ARRAY_SIZE(crashpoints); i++) { struct crashpoint *cur = &crashpoints[i]; - struct dentry *de; - de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, - cur, &cur->fops); - if (de == NULL) { - pr_err("could not create crashpoint %s\n", cur->name); - goto out_err; - } + debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, cur, + &cur->fops); } /* Install crashpoint if one was selected. */ -- cgit v1.2.3-59-g8ed1b From 909bad2d978737592b70a0546edfa8bd023ab147 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 11 Jun 2019 20:45:03 +0200 Subject: ti-st: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: linux-kernel@vger.kernel.org Reviewed-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_kim.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index e7cfdbd1f66d..93821c11bff9 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -761,10 +761,6 @@ static int kim_probe(struct platform_device *pdev) pr_info("sysfs entries created\n"); kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); - if (!kim_debugfs_dir) { - pr_err(" debugfs entries creation failed "); - return 0; - } debugfs_create_file("version", S_IRUGO, kim_debugfs_dir, kim_gdata, &version_fops); -- cgit v1.2.3-59-g8ed1b From 2472d64af2d3561954e2f05365a67692bb852f2a Mon Sep 17 00:00:00 2001 From: Sven Van Asbroeck Date: Mon, 17 Jun 2019 14:23:54 -0400 Subject: firmware: improve LSM/IMA security behaviour The firmware loader queries if LSM/IMA permits it to load firmware via the sysfs fallback. Unfortunately, the code does the opposite: it expressly permits sysfs fw loading if security_kernel_load_data( LOADING_FIRMWARE) returns -EACCES. This happens because a zero-on-success return value is cast to a bool that's true on success. Fix the return value handling so we get the correct behaviour. Fixes: 6e852651f28e ("firmware: add call to LSM hook before firmware sysfs fallback") Cc: Stable Cc: Mimi Zohar Cc: Kees Cook To: Luis Chamberlain Cc: Greg Kroah-Hartman Cc: "Rafael J. Wysocki" Cc: linux-kernel@vger.kernel.org Signed-off-by: Sven Van Asbroeck Reviewed-by: Mimi Zohar Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_loader/fallback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index b5cd96fd0e77..29becea1910d 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -659,7 +659,7 @@ static bool fw_run_sysfs_fallback(enum fw_opt opt_flags) /* Also permit LSMs and IMA to fail firmware sysfs fallback */ ret = security_kernel_load_data(LOADING_FIRMWARE); if (ret < 0) - return ret; + return false; return fw_force_sysfs_fallback(opt_flags); } -- cgit v1.2.3-59-g8ed1b From 5342e7093ff298d9cbd40f9342b607adb02b2dd0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 11 Jun 2019 14:26:24 +0200 Subject: firmware: Factor out the paged buffer handling code This is merely a preparation for the upcoming compressed firmware support and no functional changes. It moves the code to handle the paged buffer allocation and mapping out of fallback.c into the main code, so that they can be used commonly. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_loader/fallback.c | 61 ++++----------------------------- drivers/base/firmware_loader/firmware.h | 4 +++ drivers/base/firmware_loader/main.c | 52 ++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index 29becea1910d..62ee90b4db56 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -219,25 +219,6 @@ static ssize_t firmware_loading_show(struct device *dev, return sprintf(buf, "%d\n", loading); } -/* one pages buffer should be mapped/unmapped only once */ -static int map_fw_priv_pages(struct fw_priv *fw_priv) -{ - if (!fw_priv->pages) - return 0; - - vunmap(fw_priv->data); - fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0, - PAGE_KERNEL_RO); - if (!fw_priv->data) - return -ENOMEM; - - /* page table is no longer needed after mapping, let's free */ - kvfree(fw_priv->pages); - fw_priv->pages = NULL; - - return 0; -} - /** * firmware_loading_store() - set value in the 'loading' control file * @dev: device pointer @@ -283,7 +264,7 @@ static ssize_t firmware_loading_store(struct device *dev, * see the mapped 'buf->data' once the loading * is completed. * */ - rc = map_fw_priv_pages(fw_priv); + rc = fw_map_paged_buf(fw_priv); if (rc) dev_err(dev, "%s: map pages failed\n", __func__); @@ -388,41 +369,13 @@ out: static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size) { - struct fw_priv *fw_priv= fw_sysfs->fw_priv; - int pages_needed = PAGE_ALIGN(min_size) >> PAGE_SHIFT; - - /* If the array of pages is too small, grow it... */ - if (fw_priv->page_array_size < pages_needed) { - int new_array_size = max(pages_needed, - fw_priv->page_array_size * 2); - struct page **new_pages; + int err; - new_pages = kvmalloc_array(new_array_size, sizeof(void *), - GFP_KERNEL); - if (!new_pages) { - fw_load_abort(fw_sysfs); - return -ENOMEM; - } - memcpy(new_pages, fw_priv->pages, - fw_priv->page_array_size * sizeof(void *)); - memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) * - (new_array_size - fw_priv->page_array_size)); - kvfree(fw_priv->pages); - fw_priv->pages = new_pages; - fw_priv->page_array_size = new_array_size; - } - - while (fw_priv->nr_pages < pages_needed) { - fw_priv->pages[fw_priv->nr_pages] = - alloc_page(GFP_KERNEL | __GFP_HIGHMEM); - - if (!fw_priv->pages[fw_priv->nr_pages]) { - fw_load_abort(fw_sysfs); - return -ENOMEM; - } - fw_priv->nr_pages++; - } - return 0; + err = fw_grow_paged_buf(fw_sysfs->fw_priv, + PAGE_ALIGN(min_size) >> PAGE_SHIFT); + if (err) + fw_load_abort(fw_sysfs); + return err; } /** diff --git a/drivers/base/firmware_loader/firmware.h b/drivers/base/firmware_loader/firmware.h index d20d4e7f9e71..35f4e58b2d98 100644 --- a/drivers/base/firmware_loader/firmware.h +++ b/drivers/base/firmware_loader/firmware.h @@ -135,8 +135,12 @@ int assign_fw(struct firmware *fw, struct device *device, #ifdef CONFIG_FW_LOADER_USER_HELPER void fw_free_paged_buf(struct fw_priv *fw_priv); +int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed); +int fw_map_paged_buf(struct fw_priv *fw_priv); #else static inline void fw_free_paged_buf(struct fw_priv *fw_priv) {} +int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) { return -ENXIO; } +int fw_map_paged_buf(struct fw_priv *fw_priv) { return -ENXIO; } #endif #endif /* __FIRMWARE_LOADER_H */ diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 2e74a1b73dae..7e12732f4705 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -281,6 +281,58 @@ void fw_free_paged_buf(struct fw_priv *fw_priv) fw_priv->page_array_size = 0; fw_priv->nr_pages = 0; } + +int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) +{ + /* If the array of pages is too small, grow it */ + if (fw_priv->page_array_size < pages_needed) { + int new_array_size = max(pages_needed, + fw_priv->page_array_size * 2); + struct page **new_pages; + + new_pages = kvmalloc_array(new_array_size, sizeof(void *), + GFP_KERNEL); + if (!new_pages) + return -ENOMEM; + memcpy(new_pages, fw_priv->pages, + fw_priv->page_array_size * sizeof(void *)); + memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) * + (new_array_size - fw_priv->page_array_size)); + kvfree(fw_priv->pages); + fw_priv->pages = new_pages; + fw_priv->page_array_size = new_array_size; + } + + while (fw_priv->nr_pages < pages_needed) { + fw_priv->pages[fw_priv->nr_pages] = + alloc_page(GFP_KERNEL | __GFP_HIGHMEM); + + if (!fw_priv->pages[fw_priv->nr_pages]) + return -ENOMEM; + fw_priv->nr_pages++; + } + + return 0; +} + +int fw_map_paged_buf(struct fw_priv *fw_priv) +{ + /* one pages buffer should be mapped/unmapped only once */ + if (!fw_priv->pages) + return 0; + + vunmap(fw_priv->data); + fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0, + PAGE_KERNEL_RO); + if (!fw_priv->data) + return -ENOMEM; + + /* page table is no longer needed after mapping, let's free */ + kvfree(fw_priv->pages); + fw_priv->pages = NULL; + + return 0; +} #endif /* direct firmware loading support */ -- cgit v1.2.3-59-g8ed1b From 82fd7a8142a10b8eb41313074b3859d82c0857dc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 11 Jun 2019 14:26:25 +0200 Subject: firmware: Add support for loading compressed files This patch adds the support for loading compressed firmware files. The primary motivation is to reduce the storage size; e.g. currently the files in /lib/firmware on my machine counts up to 419MB, while they can be reduced to 130MB by file compression. The patch introduces a new kconfig option CONFIG_FW_LOADER_COMPRESS. Even with this option set, the firmware loader still tries to load the original firmware file as-is at first, but then falls back to the file with ".xz" extension when it's not found, and the decompressed file content is returned to the caller of request_firmware(). So, no change is needed for the rest. Currently only XZ format is supported. A caveat is that the kernel XZ helper code supports only CRC32 (or none) integrity check type, so you'll have to compress the files via xz -C crc32 option. Since we can't determine the expanded size immediately from an XZ file, the patch re-uses the paged buffer that was used for the user-mode fallback; it puts the decompressed content page, which are vmapped at the end. The paged buffer code is conditionally built with a new Kconfig that is selected automatically. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_loader/Kconfig | 18 ++++ drivers/base/firmware_loader/firmware.h | 8 +- drivers/base/firmware_loader/main.c | 147 ++++++++++++++++++++++++++++++-- 3 files changed, 161 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/base/firmware_loader/Kconfig b/drivers/base/firmware_loader/Kconfig index 38f2da6f5c2b..3f9e274e2ed3 100644 --- a/drivers/base/firmware_loader/Kconfig +++ b/drivers/base/firmware_loader/Kconfig @@ -26,6 +26,9 @@ config FW_LOADER if FW_LOADER +config FW_LOADER_PAGED_BUF + bool + config EXTRA_FIRMWARE string "Build named firmware blobs into the kernel binary" help @@ -67,6 +70,7 @@ config EXTRA_FIRMWARE_DIR config FW_LOADER_USER_HELPER bool "Enable the firmware sysfs fallback mechanism" + select FW_LOADER_PAGED_BUF help This option enables a sysfs loading facility to enable firmware loading to the kernel through userspace as a fallback mechanism @@ -151,5 +155,19 @@ config FW_LOADER_USER_HELPER_FALLBACK If you are unsure about this, say N here. +config FW_LOADER_COMPRESS + bool "Enable compressed firmware support" + select FW_LOADER_PAGED_BUF + select XZ_DEC + help + This option enables the support for loading compressed firmware + files. The caller of firmware API receives the decompressed file + content. The compressed file is loaded as a fallback, only after + loading the raw file failed at first. + + Currently only XZ-compressed files are supported, and they have to + be compressed with either none or crc32 integrity check type (pass + "-C crc32" option to xz command). + endif # FW_LOADER endmenu diff --git a/drivers/base/firmware_loader/firmware.h b/drivers/base/firmware_loader/firmware.h index 35f4e58b2d98..7048a41973ed 100644 --- a/drivers/base/firmware_loader/firmware.h +++ b/drivers/base/firmware_loader/firmware.h @@ -64,12 +64,14 @@ struct fw_priv { void *data; size_t size; size_t allocated_size; -#ifdef CONFIG_FW_LOADER_USER_HELPER +#ifdef CONFIG_FW_LOADER_PAGED_BUF bool is_paged_buf; - bool need_uevent; struct page **pages; int nr_pages; int page_array_size; +#endif +#ifdef CONFIG_FW_LOADER_USER_HELPER + bool need_uevent; struct list_head pending_list; #endif const char *fw_name; @@ -133,7 +135,7 @@ static inline void fw_state_done(struct fw_priv *fw_priv) int assign_fw(struct firmware *fw, struct device *device, enum fw_opt opt_flags); -#ifdef CONFIG_FW_LOADER_USER_HELPER +#ifdef CONFIG_FW_LOADER_PAGED_BUF void fw_free_paged_buf(struct fw_priv *fw_priv); int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed); int fw_map_paged_buf(struct fw_priv *fw_priv); diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 7e12732f4705..bf44c79beae9 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -266,7 +267,7 @@ static void free_fw_priv(struct fw_priv *fw_priv) spin_unlock(&fwc->lock); } -#ifdef CONFIG_FW_LOADER_USER_HELPER +#ifdef CONFIG_FW_LOADER_PAGED_BUF void fw_free_paged_buf(struct fw_priv *fw_priv) { int i; @@ -335,6 +336,105 @@ int fw_map_paged_buf(struct fw_priv *fw_priv) } #endif +/* + * XZ-compressed firmware support + */ +#ifdef CONFIG_FW_LOADER_COMPRESS +/* show an error and return the standard error code */ +static int fw_decompress_xz_error(struct device *dev, enum xz_ret xz_ret) +{ + if (xz_ret != XZ_STREAM_END) { + dev_warn(dev, "xz decompression failed (xz_ret=%d)\n", xz_ret); + return xz_ret == XZ_MEM_ERROR ? -ENOMEM : -EINVAL; + } + return 0; +} + +/* single-shot decompression onto the pre-allocated buffer */ +static int fw_decompress_xz_single(struct device *dev, struct fw_priv *fw_priv, + size_t in_size, const void *in_buffer) +{ + struct xz_dec *xz_dec; + struct xz_buf xz_buf; + enum xz_ret xz_ret; + + xz_dec = xz_dec_init(XZ_SINGLE, (u32)-1); + if (!xz_dec) + return -ENOMEM; + + xz_buf.in_size = in_size; + xz_buf.in = in_buffer; + xz_buf.in_pos = 0; + xz_buf.out_size = fw_priv->allocated_size; + xz_buf.out = fw_priv->data; + xz_buf.out_pos = 0; + + xz_ret = xz_dec_run(xz_dec, &xz_buf); + xz_dec_end(xz_dec); + + fw_priv->size = xz_buf.out_pos; + return fw_decompress_xz_error(dev, xz_ret); +} + +/* decompression on paged buffer and map it */ +static int fw_decompress_xz_pages(struct device *dev, struct fw_priv *fw_priv, + size_t in_size, const void *in_buffer) +{ + struct xz_dec *xz_dec; + struct xz_buf xz_buf; + enum xz_ret xz_ret; + struct page *page; + int err = 0; + + xz_dec = xz_dec_init(XZ_DYNALLOC, (u32)-1); + if (!xz_dec) + return -ENOMEM; + + xz_buf.in_size = in_size; + xz_buf.in = in_buffer; + xz_buf.in_pos = 0; + + fw_priv->is_paged_buf = true; + fw_priv->size = 0; + do { + if (fw_grow_paged_buf(fw_priv, fw_priv->nr_pages + 1)) { + err = -ENOMEM; + goto out; + } + + /* decompress onto the new allocated page */ + page = fw_priv->pages[fw_priv->nr_pages - 1]; + xz_buf.out = kmap(page); + xz_buf.out_pos = 0; + xz_buf.out_size = PAGE_SIZE; + xz_ret = xz_dec_run(xz_dec, &xz_buf); + kunmap(page); + fw_priv->size += xz_buf.out_pos; + /* partial decompression means either end or error */ + if (xz_buf.out_pos != PAGE_SIZE) + break; + } while (xz_ret == XZ_OK); + + err = fw_decompress_xz_error(dev, xz_ret); + if (!err) + err = fw_map_paged_buf(fw_priv); + + out: + xz_dec_end(xz_dec); + return err; +} + +static int fw_decompress_xz(struct device *dev, struct fw_priv *fw_priv, + size_t in_size, const void *in_buffer) +{ + /* if the buffer is pre-allocated, we can perform in single-shot mode */ + if (fw_priv->data) + return fw_decompress_xz_single(dev, fw_priv, in_size, in_buffer); + else + return fw_decompress_xz_pages(dev, fw_priv, in_size, in_buffer); +} +#endif /* CONFIG_FW_LOADER_COMPRESS */ + /* direct firmware loading support */ static char fw_path_para[256]; static const char * const fw_path[] = { @@ -354,7 +454,12 @@ module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644); MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path"); static int -fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) +fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, + const char *suffix, + int (*decompress)(struct device *dev, + struct fw_priv *fw_priv, + size_t in_size, + const void *in_buffer)) { loff_t size; int i, len; @@ -362,9 +467,11 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) char *path; enum kernel_read_file_id id = READING_FIRMWARE; size_t msize = INT_MAX; + void *buffer = NULL; /* Already populated data member means we're loading into a buffer */ - if (fw_priv->data) { + if (!decompress && fw_priv->data) { + buffer = fw_priv->data; id = READING_FIRMWARE_PREALLOC_BUFFER; msize = fw_priv->allocated_size; } @@ -378,15 +485,15 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) if (!fw_path[i][0]) continue; - len = snprintf(path, PATH_MAX, "%s/%s", - fw_path[i], fw_priv->fw_name); + len = snprintf(path, PATH_MAX, "%s/%s%s", + fw_path[i], fw_priv->fw_name, suffix); if (len >= PATH_MAX) { rc = -ENAMETOOLONG; break; } fw_priv->size = 0; - rc = kernel_read_file_from_path(path, &fw_priv->data, &size, + rc = kernel_read_file_from_path(path, &buffer, &size, msize, id); if (rc) { if (rc != -ENOENT) @@ -397,8 +504,24 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) path); continue; } - dev_dbg(device, "direct-loading %s\n", fw_priv->fw_name); - fw_priv->size = size; + if (decompress) { + dev_dbg(device, "f/w decompressing %s\n", + fw_priv->fw_name); + rc = decompress(device, fw_priv, size, buffer); + /* discard the superfluous original content */ + vfree(buffer); + buffer = NULL; + if (rc) { + fw_free_paged_buf(fw_priv); + continue; + } + } else { + dev_dbg(device, "direct-loading %s\n", + fw_priv->fw_name); + if (!fw_priv->data) + fw_priv->data = buffer; + fw_priv->size = size; + } fw_state_done(fw_priv); break; } @@ -645,7 +768,13 @@ _request_firmware(const struct firmware **firmware_p, const char *name, if (ret <= 0) /* error or already assigned */ goto out; - ret = fw_get_filesystem_firmware(device, fw->priv); + ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL); +#ifdef CONFIG_FW_LOADER_COMPRESS + if (ret == -ENOENT) + ret = fw_get_filesystem_firmware(device, fw->priv, ".xz", + fw_decompress_xz); +#endif + if (ret) { if (!(opt_flags & FW_OPT_NO_WARN)) dev_warn(device, -- cgit v1.2.3-59-g8ed1b From 72c9f26b583c54e89de386e0eb63398c07d95cfa Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Jun 2019 20:38:30 +0200 Subject: thermal: intel: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Zhang Rui Cc: Eduardo Valentin Cc: linux-pm@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Reviewed-by: Daniel Lezcano Signed-off-by: Greg Kroah-Hartman --- drivers/thermal/intel/x86_pkg_temp_thermal.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c index 1ef937d799e4..f0441ac25555 100644 --- a/drivers/thermal/intel/x86_pkg_temp_thermal.c +++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c @@ -87,29 +87,14 @@ static struct dentry *debugfs; static unsigned int pkg_interrupt_cnt; static unsigned int pkg_work_cnt; -static int pkg_temp_debugfs_init(void) +static void pkg_temp_debugfs_init(void) { - struct dentry *d; - debugfs = debugfs_create_dir("pkg_temp_thermal", NULL); - if (!debugfs) - return -ENOENT; - - d = debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs, - &pkg_interrupt_cnt); - if (!d) - goto err_out; - - d = debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs, - &pkg_work_cnt); - if (!d) - goto err_out; - return 0; - -err_out: - debugfs_remove_recursive(debugfs); - return -ENOENT; + debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs, + &pkg_interrupt_cnt); + debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs, + &pkg_work_cnt); } /* -- cgit v1.2.3-59-g8ed1b From c008c6754c109fed660221e4d8b8194bbcd003ed Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Jun 2019 20:38:10 +0200 Subject: thermal: intel_powerclamp: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Zhang Rui Cc: Eduardo Valentin Cc: Daniel Lezcano Cc: Finn Thain Cc: linux-pm@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Reviewed-by: Daniel Lezcano Signed-off-by: Greg Kroah-Hartman --- drivers/thermal/intel/intel_powerclamp.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c index ac7256b5f020..39c6b589f2ed 100644 --- a/drivers/thermal/intel/intel_powerclamp.c +++ b/drivers/thermal/intel/intel_powerclamp.c @@ -713,17 +713,9 @@ DEFINE_SHOW_ATTRIBUTE(powerclamp_debug); static inline void powerclamp_create_debug_files(void) { debug_dir = debugfs_create_dir("intel_powerclamp", NULL); - if (!debug_dir) - return; - - if (!debugfs_create_file("powerclamp_calib", S_IRUGO, debug_dir, - cal_data, &powerclamp_debug_fops)) - goto file_error; - return; - -file_error: - debugfs_remove_recursive(debug_dir); + debugfs_create_file("powerclamp_calib", S_IRUGO, debug_dir, cal_data, + &powerclamp_debug_fops); } static enum cpuhp_state hp_state; -- cgit v1.2.3-59-g8ed1b From f9d5de4064e57017b75cfed9c7cfdff73bb52681 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Jun 2019 20:37:53 +0200 Subject: thermal: tegra: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Zhang Rui Cc: Eduardo Valentin Cc: Daniel Lezcano Cc: Thierry Reding Cc: Jonathan Hunter Cc: Wei Ni Cc: Yangtao Li Cc: linux-pm@vger.kernel.org Acked-by: Thierry Reding Signed-off-by: Greg Kroah-Hartman --- drivers/thermal/tegra/soctherm.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index fcf70a3728b6..43941eb734eb 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c @@ -1485,23 +1485,13 @@ DEFINE_SHOW_ATTRIBUTE(regs); static void soctherm_debug_init(struct platform_device *pdev) { struct tegra_soctherm *tegra = platform_get_drvdata(pdev); - struct dentry *root, *file; + struct dentry *root; root = debugfs_create_dir("soctherm", NULL); - if (!root) { - dev_err(&pdev->dev, "failed to create debugfs directory\n"); - return; - } tegra->debugfs_dir = root; - file = debugfs_create_file("reg_contents", 0644, root, - pdev, ®s_fops); - if (!file) { - dev_err(&pdev->dev, "failed to create debugfs file\n"); - debugfs_remove_recursive(tegra->debugfs_dir); - tegra->debugfs_dir = NULL; - } + debugfs_create_file("reg_contents", 0644, root, pdev, ®s_fops); } #else static inline void soctherm_debug_init(struct platform_device *pdev) {} -- cgit v1.2.3-59-g8ed1b From 4a14abc4bbe58aa465f0f5599bf4c612cfeb367f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Jun 2019 17:54:18 +0200 Subject: cxl: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Because there's no need to check, also make the return value of the local debugfs_create_io_x64() call void, as no one ever did anything with the return value (as they did not need to.) And make the cxl_debugfs_* calls return void as no one was even checking their return value at all. Cc: linuxppc-dev@lists.ozlabs.org Acked-by: Andrew Donnellan Reviewed-by: Frederic Barrat Reviewed-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cxl/cxl.h | 15 ++++++--------- drivers/misc/cxl/debugfs.c | 36 +++++++++++------------------------- 2 files changed, 17 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index a73c9e669d78..5dc0f6093f9d 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -908,11 +908,11 @@ void cxl_update_dedicated_ivtes_psl8(struct cxl_context *ctx); #ifdef CONFIG_DEBUG_FS -int cxl_debugfs_init(void); +void cxl_debugfs_init(void); void cxl_debugfs_exit(void); -int cxl_debugfs_adapter_add(struct cxl *adapter); +void cxl_debugfs_adapter_add(struct cxl *adapter); void cxl_debugfs_adapter_remove(struct cxl *adapter); -int cxl_debugfs_afu_add(struct cxl_afu *afu); +void cxl_debugfs_afu_add(struct cxl_afu *afu); void cxl_debugfs_afu_remove(struct cxl_afu *afu); void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct dentry *dir); void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir); @@ -921,27 +921,24 @@ void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir); #else /* CONFIG_DEBUG_FS */ -static inline int __init cxl_debugfs_init(void) +static inline void __init cxl_debugfs_init(void) { - return 0; } static inline void cxl_debugfs_exit(void) { } -static inline int cxl_debugfs_adapter_add(struct cxl *adapter) +static inline void cxl_debugfs_adapter_add(struct cxl *adapter) { - return 0; } static inline void cxl_debugfs_adapter_remove(struct cxl *adapter) { } -static inline int cxl_debugfs_afu_add(struct cxl_afu *afu) +static inline void cxl_debugfs_afu_add(struct cxl_afu *afu) { - return 0; } static inline void cxl_debugfs_afu_remove(struct cxl_afu *afu) diff --git a/drivers/misc/cxl/debugfs.c b/drivers/misc/cxl/debugfs.c index 1fda22c24c93..7b987bf498b5 100644 --- a/drivers/misc/cxl/debugfs.c +++ b/drivers/misc/cxl/debugfs.c @@ -26,11 +26,11 @@ static int debugfs_io_u64_set(void *data, u64 val) DEFINE_DEBUGFS_ATTRIBUTE(fops_io_x64, debugfs_io_u64_get, debugfs_io_u64_set, "0x%016llx\n"); -static struct dentry *debugfs_create_io_x64(const char *name, umode_t mode, - struct dentry *parent, u64 __iomem *value) +static void debugfs_create_io_x64(const char *name, umode_t mode, + struct dentry *parent, u64 __iomem *value) { - return debugfs_create_file_unsafe(name, mode, parent, - (void __force *)value, &fops_io_x64); + debugfs_create_file_unsafe(name, mode, parent, (void __force *)value, + &fops_io_x64); } void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct dentry *dir) @@ -54,25 +54,22 @@ void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir) debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_TRACE)); } -int cxl_debugfs_adapter_add(struct cxl *adapter) +void cxl_debugfs_adapter_add(struct cxl *adapter) { struct dentry *dir; char buf[32]; if (!cxl_debugfs) - return -ENODEV; + return; snprintf(buf, 32, "card%i", adapter->adapter_num); dir = debugfs_create_dir(buf, cxl_debugfs); - if (IS_ERR(dir)) - return PTR_ERR(dir); adapter->debugfs = dir; debugfs_create_io_x64("err_ivte", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_ErrIVTE)); if (adapter->native->sl_ops->debugfs_add_adapter_regs) adapter->native->sl_ops->debugfs_add_adapter_regs(adapter, dir); - return 0; } void cxl_debugfs_adapter_remove(struct cxl *adapter) @@ -96,18 +93,16 @@ void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir) debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_SLICE_TRACE)); } -int cxl_debugfs_afu_add(struct cxl_afu *afu) +void cxl_debugfs_afu_add(struct cxl_afu *afu) { struct dentry *dir; char buf[32]; if (!afu->adapter->debugfs) - return -ENODEV; + return; snprintf(buf, 32, "psl%i.%i", afu->adapter->adapter_num, afu->slice); dir = debugfs_create_dir(buf, afu->adapter->debugfs); - if (IS_ERR(dir)) - return PTR_ERR(dir); afu->debugfs = dir; debugfs_create_io_x64("sr", S_IRUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_SR_An)); @@ -118,8 +113,6 @@ int cxl_debugfs_afu_add(struct cxl_afu *afu) if (afu->adapter->native->sl_ops->debugfs_add_afu_regs) afu->adapter->native->sl_ops->debugfs_add_afu_regs(afu, dir); - - return 0; } void cxl_debugfs_afu_remove(struct cxl_afu *afu) @@ -127,19 +120,12 @@ void cxl_debugfs_afu_remove(struct cxl_afu *afu) debugfs_remove_recursive(afu->debugfs); } -int __init cxl_debugfs_init(void) +void __init cxl_debugfs_init(void) { - struct dentry *ent; - if (!cpu_has_feature(CPU_FTR_HVMODE)) - return 0; - - ent = debugfs_create_dir("cxl", NULL); - if (IS_ERR(ent)) - return PTR_ERR(ent); - cxl_debugfs = ent; + return; - return 0; + cxl_debugfs = debugfs_create_dir("cxl", NULL); } void cxl_debugfs_exit(void) -- cgit v1.2.3-59-g8ed1b From 7e9f02a7896bf12bddfa28c4fdc442aa6cc6eda1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 11 Jun 2019 20:43:23 +0200 Subject: mic: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Ashutosh Dixit Cc: linux-kernel@vger.kernel.org Reviewed-by: Arnd Bergmann Reviewed-by: Sudeep Dutt Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mic/card/mic_debugfs.c | 18 ++---------------- drivers/misc/mic/cosm/cosm_debugfs.c | 4 ---- drivers/misc/mic/host/mic_debugfs.c | 4 ---- drivers/misc/mic/scif/scif_debugfs.c | 5 ----- drivers/misc/mic/vop/vop_debugfs.c | 4 ---- 5 files changed, 2 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mic/card/mic_debugfs.c b/drivers/misc/mic/card/mic_debugfs.c index 7a4140874888..fa2b5fefb791 100644 --- a/drivers/misc/mic/card/mic_debugfs.c +++ b/drivers/misc/mic/card/mic_debugfs.c @@ -63,25 +63,13 @@ DEFINE_SHOW_ATTRIBUTE(mic_intr); */ void __init mic_create_card_debug_dir(struct mic_driver *mdrv) { - struct dentry *d; - if (!mic_dbg) return; mdrv->dbg_dir = debugfs_create_dir(mdrv->name, mic_dbg); - if (!mdrv->dbg_dir) { - dev_err(mdrv->dev, "Cant create dbg_dir %s\n", mdrv->name); - return; - } - - d = debugfs_create_file("intr_test", 0444, mdrv->dbg_dir, - mdrv, &mic_intr_fops); - if (!d) { - dev_err(mdrv->dev, - "Cant create dbg intr_test %s\n", mdrv->name); - return; - } + debugfs_create_file("intr_test", 0444, mdrv->dbg_dir, mdrv, + &mic_intr_fops); } /** @@ -101,8 +89,6 @@ void mic_delete_card_debug_dir(struct mic_driver *mdrv) void __init mic_init_card_debugfs(void) { mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!mic_dbg) - pr_err("can't create debugfs dir\n"); } /** diff --git a/drivers/misc/mic/cosm/cosm_debugfs.c b/drivers/misc/mic/cosm/cosm_debugfs.c index 71c216d0504d..340ea7171411 100644 --- a/drivers/misc/mic/cosm/cosm_debugfs.c +++ b/drivers/misc/mic/cosm/cosm_debugfs.c @@ -105,8 +105,6 @@ void cosm_create_debug_dir(struct cosm_device *cdev) scnprintf(name, sizeof(name), "mic%d", cdev->index); cdev->dbg_dir = debugfs_create_dir(name, cosm_dbg); - if (!cdev->dbg_dir) - return; debugfs_create_file("log_buf", 0444, cdev->dbg_dir, cdev, &log_buf_fops); @@ -125,8 +123,6 @@ void cosm_delete_debug_dir(struct cosm_device *cdev) void cosm_init_debugfs(void) { cosm_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!cosm_dbg) - pr_err("can't create debugfs dir\n"); } void cosm_exit_debugfs(void) diff --git a/drivers/misc/mic/host/mic_debugfs.c b/drivers/misc/mic/host/mic_debugfs.c index c6e3c764699f..370f98c7b752 100644 --- a/drivers/misc/mic/host/mic_debugfs.c +++ b/drivers/misc/mic/host/mic_debugfs.c @@ -125,8 +125,6 @@ void mic_create_debug_dir(struct mic_device *mdev) scnprintf(name, sizeof(name), "mic%d", mdev->id); mdev->dbg_dir = debugfs_create_dir(name, mic_dbg); - if (!mdev->dbg_dir) - return; debugfs_create_file("smpt", 0444, mdev->dbg_dir, mdev, &mic_smpt_fops); @@ -155,8 +153,6 @@ void mic_delete_debug_dir(struct mic_device *mdev) void __init mic_init_debugfs(void) { mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!mic_dbg) - pr_err("can't create debugfs dir\n"); } /** diff --git a/drivers/misc/mic/scif/scif_debugfs.c b/drivers/misc/mic/scif/scif_debugfs.c index a6820480105a..8fe38e7ca6e6 100644 --- a/drivers/misc/mic/scif/scif_debugfs.c +++ b/drivers/misc/mic/scif/scif_debugfs.c @@ -103,11 +103,6 @@ DEFINE_SHOW_ATTRIBUTE(scif_rma); void __init scif_init_debugfs(void) { scif_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!scif_dbg) { - dev_err(scif_info.mdev.this_device, - "can't create debugfs dir scif\n"); - return; - } debugfs_create_file("scif_dev", 0444, scif_dbg, NULL, &scif_dev_fops); debugfs_create_file("scif_rma", 0444, scif_dbg, NULL, &scif_rma_fops); diff --git a/drivers/misc/mic/vop/vop_debugfs.c b/drivers/misc/mic/vop/vop_debugfs.c index 2ccef52aca23..d4551d522188 100644 --- a/drivers/misc/mic/vop/vop_debugfs.c +++ b/drivers/misc/mic/vop/vop_debugfs.c @@ -186,10 +186,6 @@ void vop_init_debugfs(struct vop_info *vi) snprintf(name, sizeof(name), "%s%d", KBUILD_MODNAME, vi->vpdev->dnode); vi->dbg = debugfs_create_dir(name, NULL); - if (!vi->dbg) { - pr_err("can't create debugfs dir vop\n"); - return; - } debugfs_create_file("dp", 0444, vi->dbg, vi, &vop_dp_fops); debugfs_create_file("vdev_info", 0444, vi->dbg, vi, &vop_vdev_info_fops); } -- cgit v1.2.3-59-g8ed1b From d7ef4857d947a0c9ba26bfe02bac1629bda9f9a0 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 11 Jun 2019 20:41:07 +0200 Subject: genwq: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Frank Haverkamp Cc: linux-kernel@vger.kernel.org Reviewed-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/misc/genwqe/card_base.c | 5 -- drivers/misc/genwqe/card_base.h | 2 +- drivers/misc/genwqe/card_debugfs.c | 165 +++++++------------------------------ drivers/misc/genwqe/card_dev.c | 6 +- 4 files changed, 32 insertions(+), 146 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c index d137d0fab9bf..f9f329651037 100644 --- a/drivers/misc/genwqe/card_base.c +++ b/drivers/misc/genwqe/card_base.c @@ -1377,10 +1377,6 @@ static int __init genwqe_init_module(void) class_genwqe->devnode = genwqe_devnode; debugfs_genwqe = debugfs_create_dir(GENWQE_DEVNAME, NULL); - if (!debugfs_genwqe) { - rc = -ENOMEM; - goto err_out; - } rc = pci_register_driver(&genwqe_driver); if (rc != 0) { @@ -1392,7 +1388,6 @@ static int __init genwqe_init_module(void) err_out0: debugfs_remove(debugfs_genwqe); - err_out: class_destroy(class_genwqe); return rc; } diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h index 77ed3967c5b0..d9e4a6e5fe3c 100644 --- a/drivers/misc/genwqe/card_base.h +++ b/drivers/misc/genwqe/card_base.h @@ -445,7 +445,7 @@ int genwqe_device_create(struct genwqe_dev *cd); int genwqe_device_remove(struct genwqe_dev *cd); /* debugfs */ -int genwqe_init_debugfs(struct genwqe_dev *cd); +void genwqe_init_debugfs(struct genwqe_dev *cd); void genqwe_exit_debugfs(struct genwqe_dev *cd); int genwqe_read_softreset(struct genwqe_dev *cd); diff --git a/drivers/misc/genwqe/card_debugfs.c b/drivers/misc/genwqe/card_debugfs.c index 6f7e39f07811..3e319743e5a3 100644 --- a/drivers/misc/genwqe/card_debugfs.c +++ b/drivers/misc/genwqe/card_debugfs.c @@ -324,11 +324,9 @@ static int info_show(struct seq_file *s, void *unused) DEFINE_SHOW_ATTRIBUTE(info); -int genwqe_init_debugfs(struct genwqe_dev *cd) +void genwqe_init_debugfs(struct genwqe_dev *cd) { struct dentry *root; - struct dentry *file; - int ret; char card_name[64]; char name[64]; unsigned int i; @@ -336,153 +334,50 @@ int genwqe_init_debugfs(struct genwqe_dev *cd) sprintf(card_name, "%s%d_card", GENWQE_DEVNAME, cd->card_idx); root = debugfs_create_dir(card_name, cd->debugfs_genwqe); - if (!root) { - ret = -ENOMEM; - goto err0; - } /* non privileged interfaces are done here */ - file = debugfs_create_file("ddcb_info", S_IRUGO, root, cd, - &ddcb_info_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("info", S_IRUGO, root, cd, - &info_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_x64("err_inject", 0666, root, &cd->err_inject); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_u32("ddcb_software_timeout", 0666, root, - &cd->ddcb_software_timeout); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_u32("kill_timeout", 0666, root, - &cd->kill_timeout); - if (!file) { - ret = -ENOMEM; - goto err1; - } + debugfs_create_file("ddcb_info", S_IRUGO, root, cd, &ddcb_info_fops); + debugfs_create_file("info", S_IRUGO, root, cd, &info_fops); + debugfs_create_x64("err_inject", 0666, root, &cd->err_inject); + debugfs_create_u32("ddcb_software_timeout", 0666, root, + &cd->ddcb_software_timeout); + debugfs_create_u32("kill_timeout", 0666, root, &cd->kill_timeout); /* privileged interfaces follow here */ if (!genwqe_is_privileged(cd)) { cd->debugfs_root = root; - return 0; + return; } - file = debugfs_create_file("curr_regs", S_IRUGO, root, cd, - &curr_regs_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("curr_dbg_uid0", S_IRUGO, root, cd, - &curr_dbg_uid0_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("curr_dbg_uid1", S_IRUGO, root, cd, - &curr_dbg_uid1_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("curr_dbg_uid2", S_IRUGO, root, cd, - &curr_dbg_uid2_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("prev_regs", S_IRUGO, root, cd, - &prev_regs_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("prev_dbg_uid0", S_IRUGO, root, cd, - &prev_dbg_uid0_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("prev_dbg_uid1", S_IRUGO, root, cd, - &prev_dbg_uid1_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("prev_dbg_uid2", S_IRUGO, root, cd, - &prev_dbg_uid2_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } + debugfs_create_file("curr_regs", S_IRUGO, root, cd, &curr_regs_fops); + debugfs_create_file("curr_dbg_uid0", S_IRUGO, root, cd, + &curr_dbg_uid0_fops); + debugfs_create_file("curr_dbg_uid1", S_IRUGO, root, cd, + &curr_dbg_uid1_fops); + debugfs_create_file("curr_dbg_uid2", S_IRUGO, root, cd, + &curr_dbg_uid2_fops); + debugfs_create_file("prev_regs", S_IRUGO, root, cd, &prev_regs_fops); + debugfs_create_file("prev_dbg_uid0", S_IRUGO, root, cd, + &prev_dbg_uid0_fops); + debugfs_create_file("prev_dbg_uid1", S_IRUGO, root, cd, + &prev_dbg_uid1_fops); + debugfs_create_file("prev_dbg_uid2", S_IRUGO, root, cd, + &prev_dbg_uid2_fops); for (i = 0; i < GENWQE_MAX_VFS; i++) { sprintf(name, "vf%u_jobtimeout_msec", i); - - file = debugfs_create_u32(name, 0666, root, - &cd->vf_jobtimeout_msec[i]); - if (!file) { - ret = -ENOMEM; - goto err1; - } + debugfs_create_u32(name, 0666, root, + &cd->vf_jobtimeout_msec[i]); } - file = debugfs_create_file("jobtimer", S_IRUGO, root, cd, - &jtimer_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("queue_working_time", S_IRUGO, root, cd, - &queue_working_time_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_u32("skip_recovery", 0666, root, - &cd->skip_recovery); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_u32("use_platform_recovery", 0666, root, - &cd->use_platform_recovery); - if (!file) { - ret = -ENOMEM; - goto err1; - } + debugfs_create_file("jobtimer", S_IRUGO, root, cd, &jtimer_fops); + debugfs_create_file("queue_working_time", S_IRUGO, root, cd, + &queue_working_time_fops); + debugfs_create_u32("skip_recovery", 0666, root, &cd->skip_recovery); + debugfs_create_u32("use_platform_recovery", 0666, root, + &cd->use_platform_recovery); cd->debugfs_root = root; - return 0; -err1: - debugfs_remove_recursive(root); -err0: - return ret; } void genqwe_exit_debugfs(struct genwqe_dev *cd) diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c index 8c1b63a4337b..b5942e8943ef 100644 --- a/drivers/misc/genwqe/card_dev.c +++ b/drivers/misc/genwqe/card_dev.c @@ -1307,14 +1307,10 @@ int genwqe_device_create(struct genwqe_dev *cd) goto err_cdev; } - rc = genwqe_init_debugfs(cd); - if (rc != 0) - goto err_debugfs; + genwqe_init_debugfs(cd); return 0; - err_debugfs: - device_destroy(cd->class_genwqe, cd->devnum_genwqe); err_cdev: cdev_del(&cd->cdev_genwqe); err_add: -- cgit v1.2.3-59-g8ed1b From 5666d896e838c974c535b3949353c83d68ce4384 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 11 Jun 2019 20:38:16 +0200 Subject: mei: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Tomas Winkler Cc: Arnd Bergmann Cc: linux-kernel@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/debugfs.c | 47 +++++++++++----------------------------------- drivers/misc/mei/main.c | 8 +------- drivers/misc/mei/mei_dev.h | 7 ++----- 3 files changed, 14 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c index 0970142bcace..df6bf8b81936 100644 --- a/drivers/misc/mei/debugfs.c +++ b/drivers/misc/mei/debugfs.c @@ -233,47 +233,22 @@ void mei_dbgfs_deregister(struct mei_device *dev) * * @dev: the mei device structure * @name: the mei device name - * - * Return: 0 on success, <0 on failure. */ -int mei_dbgfs_register(struct mei_device *dev, const char *name) +void mei_dbgfs_register(struct mei_device *dev, const char *name) { - struct dentry *dir, *f; + struct dentry *dir; dir = debugfs_create_dir(name, NULL); - if (!dir) - return -ENOMEM; - dev->dbgfs_dir = dir; - f = debugfs_create_file("meclients", S_IRUSR, dir, - dev, &mei_dbgfs_fops_meclients); - if (!f) { - dev_err(dev->dev, "meclients: registration failed\n"); - goto err; - } - f = debugfs_create_file("active", S_IRUSR, dir, - dev, &mei_dbgfs_fops_active); - if (!f) { - dev_err(dev->dev, "active: registration failed\n"); - goto err; - } - f = debugfs_create_file("devstate", S_IRUSR, dir, - dev, &mei_dbgfs_fops_devstate); - if (!f) { - dev_err(dev->dev, "devstate: registration failed\n"); - goto err; - } - f = debugfs_create_file("allow_fixed_address", S_IRUSR | S_IWUSR, dir, - &dev->allow_fixed_address, - &mei_dbgfs_fops_allow_fa); - if (!f) { - dev_err(dev->dev, "allow_fixed_address: registration failed\n"); - goto err; - } - return 0; -err: - mei_dbgfs_deregister(dev); - return -ENODEV; + debugfs_create_file("meclients", S_IRUSR, dir, dev, + &mei_dbgfs_fops_meclients); + debugfs_create_file("active", S_IRUSR, dir, dev, + &mei_dbgfs_fops_active); + debugfs_create_file("devstate", S_IRUSR, dir, dev, + &mei_dbgfs_fops_devstate); + debugfs_create_file("allow_fixed_address", S_IRUSR | S_IWUSR, dir, + &dev->allow_fixed_address, + &mei_dbgfs_fops_allow_fa); } diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index ad02097d7fee..f894d1f8a53e 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -984,16 +984,10 @@ int mei_register(struct mei_device *dev, struct device *parent) goto err_dev_create; } - ret = mei_dbgfs_register(dev, dev_name(clsdev)); - if (ret) { - dev_err(clsdev, "cannot register debugfs ret = %d\n", ret); - goto err_dev_dbgfs; - } + mei_dbgfs_register(dev, dev_name(clsdev)); return 0; -err_dev_dbgfs: - device_destroy(mei_class, devno); err_dev_create: cdev_del(&dev->cdev); err_dev_add: diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index fca832fcac57..f71a023aed3c 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -718,13 +718,10 @@ bool mei_hbuf_acquire(struct mei_device *dev); bool mei_write_is_idle(struct mei_device *dev); #if IS_ENABLED(CONFIG_DEBUG_FS) -int mei_dbgfs_register(struct mei_device *dev, const char *name); +void mei_dbgfs_register(struct mei_device *dev, const char *name); void mei_dbgfs_deregister(struct mei_device *dev); #else -static inline int mei_dbgfs_register(struct mei_device *dev, const char *name) -{ - return 0; -} +static inline void mei_dbgfs_register(struct mei_device *dev, const char *name) {} static inline void mei_dbgfs_deregister(struct mei_device *dev) {} #endif /* CONFIG_DEBUG_FS */ -- cgit v1.2.3-59-g8ed1b From 5d8a437c583de22451e2787a20bdf12a52bfb447 Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Fri, 14 Jun 2019 19:27:45 +0530 Subject: firmware: ti_sci: Use the correct style for SPDX License Identifier This patch corrects the SPDX License Identifier style in header file related to Firmware Drivers for Texas Instruments SCI Protocol. For C header files Documentation/process/license-rules.rst mandates C-like comments (opposed to C source files where C++ style should be used) Changes made by using a script provided by Joe Perches here: https://lkml.org/lkml/2019/2/7/46 Suggested-by: Joe Perches Signed-off-by: Nishad Kamdar Reviewed-by: Lokesh Vutla Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/ti_sci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index 4983827151bf..adbeeefaca92 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: BSD-3-Clause +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Texas Instruments System Control Interface (TISCI) Protocol * -- cgit v1.2.3-59-g8ed1b From d2527682160a09e4eb5e9abcf37e83ee5239561a Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Thu, 13 Jun 2019 19:30:03 +0530 Subject: firmware: arm_scmi: Use the correct style for SPDX License Identifier This patch corrects the SPDX License Identifier style in header file related to Firmware Drivers for ARM SCMI Message Protocol. For C header files Documentation/process/license-rules.rst mandates C-like comments (opposed to C source files where C++ style should be used) Changes made by using a script provided by Joe Perches here: https://lkml.org/lkml/2019/2/7/46 Suggested-by: Joe Perches Signed-off-by: Nishad Kamdar Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/arm_scmi/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 937a930ce87d..44fd4f9404a9 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * System Control and Management Interface (SCMI) Message Protocol * driver common header file containing some definitions, structures -- cgit v1.2.3-59-g8ed1b From 200f3a3fec0c1efab6dcdadc18c65eb61b4c89ce Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Jun 2019 17:52:46 +0200 Subject: coresight: cpu-debug: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Suzuki K Poulose Cc: Alexander Shishkin Cc: linux-arm-kernel@lists.infradead.org Reviewed-by: Mathieu Poirier Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-cpu-debug.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index e8819d750938..6446ed69ab2f 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -525,23 +525,12 @@ static const struct file_operations debug_func_knob_fops = { static int debug_func_init(void) { - struct dentry *file; int ret; /* Create debugfs node */ debug_debugfs_dir = debugfs_create_dir("coresight_cpu_debug", NULL); - if (!debug_debugfs_dir) { - pr_err("%s: unable to create debugfs directory\n", __func__); - return -ENOMEM; - } - - file = debugfs_create_file("enable", 0644, debug_debugfs_dir, NULL, - &debug_func_knob_fops); - if (!file) { - pr_err("%s: unable to create enable knob file\n", __func__); - ret = -ENOMEM; - goto err; - } + debugfs_create_file("enable", 0644, debug_debugfs_dir, NULL, + &debug_func_knob_fops); /* Register function to be called for panic */ ret = atomic_notifier_chain_register(&panic_notifier_list, -- cgit v1.2.3-59-g8ed1b From 1012592cce2c59d85b7f535eb21d38d131167f07 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Jun 2019 17:58:30 +0200 Subject: watchdog: mei_wdt: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Tomas Winkler Cc: Wim Van Sebroeck Cc: linux-watchdog@vger.kernel.org Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/mei_wdt.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/mei_wdt.c b/drivers/watchdog/mei_wdt.c index 8023cf28657a..96a770938ff0 100644 --- a/drivers/watchdog/mei_wdt.c +++ b/drivers/watchdog/mei_wdt.c @@ -539,38 +539,23 @@ static void dbgfs_unregister(struct mei_wdt *wdt) wdt->dbgfs_dir = NULL; } -static int dbgfs_register(struct mei_wdt *wdt) +static void dbgfs_register(struct mei_wdt *wdt) { - struct dentry *dir, *f; + struct dentry *dir; dir = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!dir) - return -ENOMEM; - wdt->dbgfs_dir = dir; - f = debugfs_create_file("state", S_IRUSR, dir, wdt, &dbgfs_fops_state); - if (!f) - goto err; - f = debugfs_create_file("activation", S_IRUSR, - dir, wdt, &dbgfs_fops_activation); - if (!f) - goto err; + debugfs_create_file("state", S_IRUSR, dir, wdt, &dbgfs_fops_state); - return 0; -err: - dbgfs_unregister(wdt); - return -ENODEV; + debugfs_create_file("activation", S_IRUSR, dir, wdt, + &dbgfs_fops_activation); } #else static inline void dbgfs_unregister(struct mei_wdt *wdt) {} - -static inline int dbgfs_register(struct mei_wdt *wdt) -{ - return 0; -} +static inline void dbgfs_register(struct mei_wdt *wdt) {} #endif /* CONFIG_DEBUG_FS */ static int mei_wdt_probe(struct mei_cl_device *cldev, @@ -623,8 +608,7 @@ static int mei_wdt_probe(struct mei_cl_device *cldev, if (ret) goto err_disable; - if (dbgfs_register(wdt)) - dev_warn(&cldev->dev, "cannot register debugfs\n"); + dbgfs_register(wdt); return 0; -- cgit v1.2.3-59-g8ed1b From 8bff68b80964134085a2f58642f22f6ea1b54857 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Jun 2019 17:58:09 +0200 Subject: watchdog: bcm_kona_wdt: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Wim Van Sebroeck Cc: Florian Fainelli Cc: Ray Jui Cc: Scott Branden Cc: bcm-kernel-feedback-list@broadcom.com Cc: linux-watchdog@vger.kernel.org Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/bcm_kona_wdt.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/bcm_kona_wdt.c b/drivers/watchdog/bcm_kona_wdt.c index e2ad44816359..921291025680 100644 --- a/drivers/watchdog/bcm_kona_wdt.c +++ b/drivers/watchdog/bcm_kona_wdt.c @@ -143,24 +143,18 @@ static void bcm_kona_wdt_debug_init(struct platform_device *pdev) wdt->debugfs = NULL; dir = debugfs_create_dir(BCM_KONA_WDT_NAME, NULL); - if (IS_ERR_OR_NULL(dir)) - return; - if (debugfs_create_file("info", S_IFREG | S_IRUGO, dir, wdt, - &bcm_kona_fops)) - wdt->debugfs = dir; - else - debugfs_remove_recursive(dir); + debugfs_create_file("info", S_IFREG | S_IRUGO, dir, wdt, + &bcm_kona_fops); + wdt->debugfs = dir; } static void bcm_kona_wdt_debug_exit(struct platform_device *pdev) { struct bcm_kona_wdt *wdt = platform_get_drvdata(pdev); - if (wdt && wdt->debugfs) { + if (wdt) debugfs_remove_recursive(wdt->debugfs); - wdt->debugfs = NULL; - } } #else -- cgit v1.2.3-59-g8ed1b From 10ff826ab0a46e6fbac324b3a633c4943e2a745e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 11 Jun 2019 20:05:47 +0200 Subject: power: avs: smartreflex: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. And even when not checking the return value, no need to cast away the call to (void), as these functions were never a "must check" type of a function, so remove that odd cast. Cc: Kevin Hilman Cc: Nishanth Menon Cc: linux-pm@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/power/avs/smartreflex.c | 41 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/power/avs/smartreflex.c b/drivers/power/avs/smartreflex.c index c96c01e09740..4684e7df833a 100644 --- a/drivers/power/avs/smartreflex.c +++ b/drivers/power/avs/smartreflex.c @@ -899,38 +899,19 @@ static int omap_sr_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__); - if (!sr_dbg_dir) { + if (!sr_dbg_dir) sr_dbg_dir = debugfs_create_dir("smartreflex", NULL); - if (IS_ERR_OR_NULL(sr_dbg_dir)) { - ret = PTR_ERR(sr_dbg_dir); - pr_err("%s:sr debugfs dir creation failed(%d)\n", - __func__, ret); - goto err_list_del; - } - } sr_info->dbg_dir = debugfs_create_dir(sr_info->name, sr_dbg_dir); - if (IS_ERR_OR_NULL(sr_info->dbg_dir)) { - dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n", - __func__); - ret = PTR_ERR(sr_info->dbg_dir); - goto err_debugfs; - } - (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, - sr_info->dbg_dir, (void *)sr_info, &pm_sr_fops); - (void) debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir, - &sr_info->err_weight); - (void) debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir, - &sr_info->err_maxlimit); + debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, sr_info->dbg_dir, + (void *)sr_info, &pm_sr_fops); + debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir, + &sr_info->err_weight); + debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir, + &sr_info->err_maxlimit); nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir); - if (IS_ERR_OR_NULL(nvalue_dir)) { - dev_err(&pdev->dev, "%s: Unable to create debugfs directory for n-values\n", - __func__); - ret = PTR_ERR(nvalue_dir); - goto err_debugfs; - } if (sr_info->nvalue_count == 0 || !sr_info->nvalue_table) { dev_warn(&pdev->dev, "%s: %s: No Voltage table for the corresponding vdd. Cannot create debugfs entries for n-values\n", @@ -945,12 +926,12 @@ static int omap_sr_probe(struct platform_device *pdev) snprintf(name, sizeof(name), "volt_%lu", sr_info->nvalue_table[i].volt_nominal); - (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir, - &(sr_info->nvalue_table[i].nvalue)); + debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir, + &(sr_info->nvalue_table[i].nvalue)); snprintf(name, sizeof(name), "errminlimit_%lu", sr_info->nvalue_table[i].volt_nominal); - (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir, - &(sr_info->nvalue_table[i].errminlimit)); + debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir, + &(sr_info->nvalue_table[i].errminlimit)); } -- cgit v1.2.3-59-g8ed1b From a6cd400ac8a8b39b6830621eb51db351e1048f79 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Jun 2019 20:37:29 +0200 Subject: thermal: bcm2835: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Zhang Rui Cc: Eduardo Valentin Cc: Daniel Lezcano Cc: Florian Fainelli Cc: Ray Jui Cc: Scott Branden Cc: bcm-kernel-feedback-list@broadcom.com Cc: linux-pm@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/thermal/broadcom/bcm2835_thermal.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/broadcom/bcm2835_thermal.c b/drivers/thermal/broadcom/bcm2835_thermal.c index ba39647a690c..3199977f1e73 100644 --- a/drivers/thermal/broadcom/bcm2835_thermal.c +++ b/drivers/thermal/broadcom/bcm2835_thermal.c @@ -123,8 +123,6 @@ static void bcm2835_thermal_debugfs(struct platform_device *pdev) struct debugfs_regset32 *regset; data->debugfsdir = debugfs_create_dir("bcm2835_thermal", NULL); - if (!data->debugfsdir) - return; regset = devm_kzalloc(&pdev->dev, sizeof(*regset), GFP_KERNEL); if (!regset) -- cgit v1.2.3-59-g8ed1b From 58cb346c7188f04bafa2a089ab0b093f5642572c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Jun 2019 15:55:12 -0300 Subject: drivers: base/node.c: fixes a kernel-doc markups There was a typo at the name of the vars inside the kernel-doc comment, causing those warnings: ./drivers/base/node.c:690: warning: Function parameter or member 'mem_nid' not described in 'register_memory_node_under_compute_node' ./drivers/base/node.c:690: warning: Function parameter or member 'cpu_nid' not described in 'register_memory_node_under_compute_node' ./drivers/base/node.c:690: warning: Excess function parameter 'mem_node' description in 'register_memory_node_under_compute_node' ./drivers/base/node.c:690: warning: Excess function parameter 'cpu_node' description in 'register_memory_node_under_compute_node' There's also a description missing here: ./drivers/base/node.c:78: warning: Function parameter or member 'hmem_attrs' not described in 'node_access_nodes' Copy an existing description from another function call. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/base/node.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/node.c b/drivers/base/node.c index 8598fcbd2a17..aa878fbcf705 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -66,6 +66,7 @@ static DEVICE_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL); * @dev: Device for this memory access class * @list_node: List element in the node's access list * @access: The access class rank + * @hmem_attrs: Heterogeneous memory performance attributes */ struct node_access_nodes { struct device dev; @@ -673,8 +674,8 @@ int register_cpu_under_node(unsigned int cpu, unsigned int nid) /** * register_memory_node_under_compute_node - link memory node to its compute * node for a given access class. - * @mem_node: Memory node number - * @cpu_node: Cpu node number + * @mem_nid: Memory node number + * @cpu_nid: Cpu node number * @access: Access class to register * * Description: -- cgit v1.2.3-59-g8ed1b From 4489f161b739f01ab60a58784f6ef7de9d7a1352 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Jun 2019 17:53:27 -0300 Subject: docs: driver-model: convert docs to ReST and rename to *.rst Convert the various documents at the driver-model, preparing them to be part of the driver-api book. The conversion is actually: - add blank lines and identation in order to identify paragraphs; - fix tables markups; - add some lists markups; - mark literal blocks; - adjust title markups. At its new index.rst, let's add a :orphan: while this is not linked to the main index.rst file, in order to avoid build warnings. Signed-off-by: Mauro Carvalho Chehab Acked-by: Jeff Kirsher # ice Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/gpio/driver.rst | 2 +- Documentation/driver-model/binding.rst | 98 ++++++ Documentation/driver-model/binding.txt | 98 ------ Documentation/driver-model/bus.rst | 146 ++++++++ Documentation/driver-model/bus.txt | 143 -------- Documentation/driver-model/class.rst | 149 ++++++++ Documentation/driver-model/class.txt | 147 -------- Documentation/driver-model/design-patterns.rst | 116 +++++++ Documentation/driver-model/design-patterns.txt | 116 ------- Documentation/driver-model/device.rst | 109 ++++++ Documentation/driver-model/device.txt | 106 ------ Documentation/driver-model/devres.rst | 414 +++++++++++++++++++++++ Documentation/driver-model/devres.txt | 412 ----------------------- Documentation/driver-model/driver.rst | 223 ++++++++++++ Documentation/driver-model/driver.txt | 215 ------------ Documentation/driver-model/index.rst | 26 ++ Documentation/driver-model/overview.rst | 124 +++++++ Documentation/driver-model/overview.txt | 123 ------- Documentation/driver-model/platform.rst | 246 ++++++++++++++ Documentation/driver-model/platform.txt | 244 -------------- Documentation/driver-model/porting.rst | 448 +++++++++++++++++++++++++ Documentation/driver-model/porting.txt | 447 ------------------------ Documentation/eisa.txt | 4 +- Documentation/hwmon/submitting-patches.rst | 2 +- drivers/base/platform.c | 2 +- drivers/gpio/gpio-cs5535.c | 2 +- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- scripts/coccinelle/free/devm_free.cocci | 2 +- 28 files changed, 2107 insertions(+), 2059 deletions(-) create mode 100644 Documentation/driver-model/binding.rst delete mode 100644 Documentation/driver-model/binding.txt create mode 100644 Documentation/driver-model/bus.rst delete mode 100644 Documentation/driver-model/bus.txt create mode 100644 Documentation/driver-model/class.rst delete mode 100644 Documentation/driver-model/class.txt create mode 100644 Documentation/driver-model/design-patterns.rst delete mode 100644 Documentation/driver-model/design-patterns.txt create mode 100644 Documentation/driver-model/device.rst delete mode 100644 Documentation/driver-model/device.txt create mode 100644 Documentation/driver-model/devres.rst delete mode 100644 Documentation/driver-model/devres.txt create mode 100644 Documentation/driver-model/driver.rst delete mode 100644 Documentation/driver-model/driver.txt create mode 100644 Documentation/driver-model/index.rst create mode 100644 Documentation/driver-model/overview.rst delete mode 100644 Documentation/driver-model/overview.txt create mode 100644 Documentation/driver-model/platform.rst delete mode 100644 Documentation/driver-model/platform.txt create mode 100644 Documentation/driver-model/porting.rst delete mode 100644 Documentation/driver-model/porting.txt (limited to 'drivers') diff --git a/Documentation/driver-api/gpio/driver.rst b/Documentation/driver-api/gpio/driver.rst index 1ce7fcd0f989..f931597fe7be 100644 --- a/Documentation/driver-api/gpio/driver.rst +++ b/Documentation/driver-api/gpio/driver.rst @@ -399,7 +399,7 @@ symbol: will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the callbacks need to embed the gpio_chip in its state container and obtain a pointer to the container using container_of(). - (See Documentation/driver-model/design-patterns.txt) + (See Documentation/driver-model/design-patterns.rst) - gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip, as discussed above regarding different types of cascaded irqchips. The diff --git a/Documentation/driver-model/binding.rst b/Documentation/driver-model/binding.rst new file mode 100644 index 000000000000..7ea1d7a41e1d --- /dev/null +++ b/Documentation/driver-model/binding.rst @@ -0,0 +1,98 @@ +============== +Driver Binding +============== + +Driver binding is the process of associating a device with a device +driver that can control it. Bus drivers have typically handled this +because there have been bus-specific structures to represent the +devices and the drivers. With generic device and device driver +structures, most of the binding can take place using common code. + + +Bus +~~~ + +The bus type structure contains a list of all devices that are on that bus +type in the system. When device_register is called for a device, it is +inserted into the end of this list. The bus object also contains a +list of all drivers of that bus type. When driver_register is called +for a driver, it is inserted at the end of this list. These are the +two events which trigger driver binding. + + +device_register +~~~~~~~~~~~~~~~ + +When a new device is added, the bus's list of drivers is iterated over +to find one that supports it. In order to determine that, the device +ID of the device must match one of the device IDs that the driver +supports. The format and semantics for comparing IDs is bus-specific. +Instead of trying to derive a complex state machine and matching +algorithm, it is up to the bus driver to provide a callback to compare +a device against the IDs of a driver. The bus returns 1 if a match was +found; 0 otherwise. + +int match(struct device * dev, struct device_driver * drv); + +If a match is found, the device's driver field is set to the driver +and the driver's probe callback is called. This gives the driver a +chance to verify that it really does support the hardware, and that +it's in a working state. + +Device Class +~~~~~~~~~~~~ + +Upon the successful completion of probe, the device is registered with +the class to which it belongs. Device drivers belong to one and only one +class, and that is set in the driver's devclass field. +devclass_add_device is called to enumerate the device within the class +and actually register it with the class, which happens with the +class's register_dev callback. + + +Driver +~~~~~~ + +When a driver is attached to a device, the device is inserted into the +driver's list of devices. + + +sysfs +~~~~~ + +A symlink is created in the bus's 'devices' directory that points to +the device's directory in the physical hierarchy. + +A symlink is created in the driver's 'devices' directory that points +to the device's directory in the physical hierarchy. + +A directory for the device is created in the class's directory. A +symlink is created in that directory that points to the device's +physical location in the sysfs tree. + +A symlink can be created (though this isn't done yet) in the device's +physical directory to either its class directory, or the class's +top-level directory. One can also be created to point to its driver's +directory also. + + +driver_register +~~~~~~~~~~~~~~~ + +The process is almost identical for when a new driver is added. +The bus's list of devices is iterated over to find a match. Devices +that already have a driver are skipped. All the devices are iterated +over, to bind as many devices as possible to the driver. + + +Removal +~~~~~~~ + +When a device is removed, the reference count for it will eventually +go to 0. When it does, the remove callback of the driver is called. It +is removed from the driver's list of devices and the reference count +of the driver is decremented. All symlinks between the two are removed. + +When a driver is removed, the list of devices that it supports is +iterated over, and the driver's remove callback is called for each +one. The device is removed from that list and the symlinks removed. diff --git a/Documentation/driver-model/binding.txt b/Documentation/driver-model/binding.txt deleted file mode 100644 index abfc8e290d53..000000000000 --- a/Documentation/driver-model/binding.txt +++ /dev/null @@ -1,98 +0,0 @@ - -Driver Binding - -Driver binding is the process of associating a device with a device -driver that can control it. Bus drivers have typically handled this -because there have been bus-specific structures to represent the -devices and the drivers. With generic device and device driver -structures, most of the binding can take place using common code. - - -Bus -~~~ - -The bus type structure contains a list of all devices that are on that bus -type in the system. When device_register is called for a device, it is -inserted into the end of this list. The bus object also contains a -list of all drivers of that bus type. When driver_register is called -for a driver, it is inserted at the end of this list. These are the -two events which trigger driver binding. - - -device_register -~~~~~~~~~~~~~~~ - -When a new device is added, the bus's list of drivers is iterated over -to find one that supports it. In order to determine that, the device -ID of the device must match one of the device IDs that the driver -supports. The format and semantics for comparing IDs is bus-specific. -Instead of trying to derive a complex state machine and matching -algorithm, it is up to the bus driver to provide a callback to compare -a device against the IDs of a driver. The bus returns 1 if a match was -found; 0 otherwise. - -int match(struct device * dev, struct device_driver * drv); - -If a match is found, the device's driver field is set to the driver -and the driver's probe callback is called. This gives the driver a -chance to verify that it really does support the hardware, and that -it's in a working state. - -Device Class -~~~~~~~~~~~~ - -Upon the successful completion of probe, the device is registered with -the class to which it belongs. Device drivers belong to one and only one -class, and that is set in the driver's devclass field. -devclass_add_device is called to enumerate the device within the class -and actually register it with the class, which happens with the -class's register_dev callback. - - -Driver -~~~~~~ - -When a driver is attached to a device, the device is inserted into the -driver's list of devices. - - -sysfs -~~~~~ - -A symlink is created in the bus's 'devices' directory that points to -the device's directory in the physical hierarchy. - -A symlink is created in the driver's 'devices' directory that points -to the device's directory in the physical hierarchy. - -A directory for the device is created in the class's directory. A -symlink is created in that directory that points to the device's -physical location in the sysfs tree. - -A symlink can be created (though this isn't done yet) in the device's -physical directory to either its class directory, or the class's -top-level directory. One can also be created to point to its driver's -directory also. - - -driver_register -~~~~~~~~~~~~~~~ - -The process is almost identical for when a new driver is added. -The bus's list of devices is iterated over to find a match. Devices -that already have a driver are skipped. All the devices are iterated -over, to bind as many devices as possible to the driver. - - -Removal -~~~~~~~ - -When a device is removed, the reference count for it will eventually -go to 0. When it does, the remove callback of the driver is called. It -is removed from the driver's list of devices and the reference count -of the driver is decremented. All symlinks between the two are removed. - -When a driver is removed, the list of devices that it supports is -iterated over, and the driver's remove callback is called for each -one. The device is removed from that list and the symlinks removed. - diff --git a/Documentation/driver-model/bus.rst b/Documentation/driver-model/bus.rst new file mode 100644 index 000000000000..016b15a6e8ea --- /dev/null +++ b/Documentation/driver-model/bus.rst @@ -0,0 +1,146 @@ +========= +Bus Types +========= + +Definition +~~~~~~~~~~ +See the kerneldoc for the struct bus_type. + +int bus_register(struct bus_type * bus); + + +Declaration +~~~~~~~~~~~ + +Each bus type in the kernel (PCI, USB, etc) should declare one static +object of this type. They must initialize the name field, and may +optionally initialize the match callback:: + + struct bus_type pci_bus_type = { + .name = "pci", + .match = pci_bus_match, + }; + +The structure should be exported to drivers in a header file: + +extern struct bus_type pci_bus_type; + + +Registration +~~~~~~~~~~~~ + +When a bus driver is initialized, it calls bus_register. This +initializes the rest of the fields in the bus object and inserts it +into a global list of bus types. Once the bus object is registered, +the fields in it are usable by the bus driver. + + +Callbacks +~~~~~~~~~ + +match(): Attaching Drivers to Devices +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The format of device ID structures and the semantics for comparing +them are inherently bus-specific. Drivers typically declare an array +of device IDs of devices they support that reside in a bus-specific +driver structure. + +The purpose of the match callback is to give the bus an opportunity to +determine if a particular driver supports a particular device by +comparing the device IDs the driver supports with the device ID of a +particular device, without sacrificing bus-specific functionality or +type-safety. + +When a driver is registered with the bus, the bus's list of devices is +iterated over, and the match callback is called for each device that +does not have a driver associated with it. + + + +Device and Driver Lists +~~~~~~~~~~~~~~~~~~~~~~~ + +The lists of devices and drivers are intended to replace the local +lists that many buses keep. They are lists of struct devices and +struct device_drivers, respectively. Bus drivers are free to use the +lists as they please, but conversion to the bus-specific type may be +necessary. + +The LDM core provides helper functions for iterating over each list:: + + int bus_for_each_dev(struct bus_type * bus, struct device * start, + void * data, + int (*fn)(struct device *, void *)); + + int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, + void * data, int (*fn)(struct device_driver *, void *)); + +These helpers iterate over the respective list, and call the callback +for each device or driver in the list. All list accesses are +synchronized by taking the bus's lock (read currently). The reference +count on each object in the list is incremented before the callback is +called; it is decremented after the next object has been obtained. The +lock is not held when calling the callback. + + +sysfs +~~~~~~~~ +There is a top-level directory named 'bus'. + +Each bus gets a directory in the bus directory, along with two default +directories:: + + /sys/bus/pci/ + |-- devices + `-- drivers + +Drivers registered with the bus get a directory in the bus's drivers +directory:: + + /sys/bus/pci/ + |-- devices + `-- drivers + |-- Intel ICH + |-- Intel ICH Joystick + |-- agpgart + `-- e100 + +Each device that is discovered on a bus of that type gets a symlink in +the bus's devices directory to the device's directory in the physical +hierarchy:: + + /sys/bus/pci/ + |-- devices + | |-- 00:00.0 -> ../../../root/pci0/00:00.0 + | |-- 00:01.0 -> ../../../root/pci0/00:01.0 + | `-- 00:02.0 -> ../../../root/pci0/00:02.0 + `-- drivers + + +Exporting Attributes +~~~~~~~~~~~~~~~~~~~~ + +:: + + struct bus_attribute { + struct attribute attr; + ssize_t (*show)(struct bus_type *, char * buf); + ssize_t (*store)(struct bus_type *, const char * buf, size_t count); + }; + +Bus drivers can export attributes using the BUS_ATTR_RW macro that works +similarly to the DEVICE_ATTR_RW macro for devices. For example, a +definition like this:: + + static BUS_ATTR_RW(debug); + +is equivalent to declaring:: + + static bus_attribute bus_attr_debug; + +This can then be used to add and remove the attribute from the bus's +sysfs directory using:: + + int bus_create_file(struct bus_type *, struct bus_attribute *); + void bus_remove_file(struct bus_type *, struct bus_attribute *); diff --git a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt deleted file mode 100644 index c247b488a567..000000000000 --- a/Documentation/driver-model/bus.txt +++ /dev/null @@ -1,143 +0,0 @@ - -Bus Types - -Definition -~~~~~~~~~~ -See the kerneldoc for the struct bus_type. - -int bus_register(struct bus_type * bus); - - -Declaration -~~~~~~~~~~~ - -Each bus type in the kernel (PCI, USB, etc) should declare one static -object of this type. They must initialize the name field, and may -optionally initialize the match callback. - -struct bus_type pci_bus_type = { - .name = "pci", - .match = pci_bus_match, -}; - -The structure should be exported to drivers in a header file: - -extern struct bus_type pci_bus_type; - - -Registration -~~~~~~~~~~~~ - -When a bus driver is initialized, it calls bus_register. This -initializes the rest of the fields in the bus object and inserts it -into a global list of bus types. Once the bus object is registered, -the fields in it are usable by the bus driver. - - -Callbacks -~~~~~~~~~ - -match(): Attaching Drivers to Devices -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The format of device ID structures and the semantics for comparing -them are inherently bus-specific. Drivers typically declare an array -of device IDs of devices they support that reside in a bus-specific -driver structure. - -The purpose of the match callback is to give the bus an opportunity to -determine if a particular driver supports a particular device by -comparing the device IDs the driver supports with the device ID of a -particular device, without sacrificing bus-specific functionality or -type-safety. - -When a driver is registered with the bus, the bus's list of devices is -iterated over, and the match callback is called for each device that -does not have a driver associated with it. - - - -Device and Driver Lists -~~~~~~~~~~~~~~~~~~~~~~~ - -The lists of devices and drivers are intended to replace the local -lists that many buses keep. They are lists of struct devices and -struct device_drivers, respectively. Bus drivers are free to use the -lists as they please, but conversion to the bus-specific type may be -necessary. - -The LDM core provides helper functions for iterating over each list. - -int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, - int (*fn)(struct device *, void *)); - -int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, - void * data, int (*fn)(struct device_driver *, void *)); - -These helpers iterate over the respective list, and call the callback -for each device or driver in the list. All list accesses are -synchronized by taking the bus's lock (read currently). The reference -count on each object in the list is incremented before the callback is -called; it is decremented after the next object has been obtained. The -lock is not held when calling the callback. - - -sysfs -~~~~~~~~ -There is a top-level directory named 'bus'. - -Each bus gets a directory in the bus directory, along with two default -directories: - - /sys/bus/pci/ - |-- devices - `-- drivers - -Drivers registered with the bus get a directory in the bus's drivers -directory: - - /sys/bus/pci/ - |-- devices - `-- drivers - |-- Intel ICH - |-- Intel ICH Joystick - |-- agpgart - `-- e100 - -Each device that is discovered on a bus of that type gets a symlink in -the bus's devices directory to the device's directory in the physical -hierarchy: - - /sys/bus/pci/ - |-- devices - | |-- 00:00.0 -> ../../../root/pci0/00:00.0 - | |-- 00:01.0 -> ../../../root/pci0/00:01.0 - | `-- 00:02.0 -> ../../../root/pci0/00:02.0 - `-- drivers - - -Exporting Attributes -~~~~~~~~~~~~~~~~~~~~ -struct bus_attribute { - struct attribute attr; - ssize_t (*show)(struct bus_type *, char * buf); - ssize_t (*store)(struct bus_type *, const char * buf, size_t count); -}; - -Bus drivers can export attributes using the BUS_ATTR_RW macro that works -similarly to the DEVICE_ATTR_RW macro for devices. For example, a -definition like this: - -static BUS_ATTR_RW(debug); - -is equivalent to declaring: - -static bus_attribute bus_attr_debug; - -This can then be used to add and remove the attribute from the bus's -sysfs directory using: - -int bus_create_file(struct bus_type *, struct bus_attribute *); -void bus_remove_file(struct bus_type *, struct bus_attribute *); - - diff --git a/Documentation/driver-model/class.rst b/Documentation/driver-model/class.rst new file mode 100644 index 000000000000..fff55b80e86a --- /dev/null +++ b/Documentation/driver-model/class.rst @@ -0,0 +1,149 @@ +============== +Device Classes +============== + +Introduction +~~~~~~~~~~~~ +A device class describes a type of device, like an audio or network +device. The following device classes have been identified: + + + + +Each device class defines a set of semantics and a programming interface +that devices of that class adhere to. Device drivers are the +implementation of that programming interface for a particular device on +a particular bus. + +Device classes are agnostic with respect to what bus a device resides +on. + + +Programming Interface +~~~~~~~~~~~~~~~~~~~~~ +The device class structure looks like:: + + + typedef int (*devclass_add)(struct device *); + typedef void (*devclass_remove)(struct device *); + +See the kerneldoc for the struct class. + +A typical device class definition would look like:: + + struct device_class input_devclass = { + .name = "input", + .add_device = input_add_device, + .remove_device = input_remove_device, + }; + +Each device class structure should be exported in a header file so it +can be used by drivers, extensions and interfaces. + +Device classes are registered and unregistered with the core using:: + + int devclass_register(struct device_class * cls); + void devclass_unregister(struct device_class * cls); + + +Devices +~~~~~~~ +As devices are bound to drivers, they are added to the device class +that the driver belongs to. Before the driver model core, this would +typically happen during the driver's probe() callback, once the device +has been initialized. It now happens after the probe() callback +finishes from the core. + +The device is enumerated in the class. Each time a device is added to +the class, the class's devnum field is incremented and assigned to the +device. The field is never decremented, so if the device is removed +from the class and re-added, it will receive a different enumerated +value. + +The class is allowed to create a class-specific structure for the +device and store it in the device's class_data pointer. + +There is no list of devices in the device class. Each driver has a +list of devices that it supports. The device class has a list of +drivers of that particular class. To access all of the devices in the +class, iterate over the device lists of each driver in the class. + + +Device Drivers +~~~~~~~~~~~~~~ +Device drivers are added to device classes when they are registered +with the core. A driver specifies the class it belongs to by setting +the struct device_driver::devclass field. + + +sysfs directory structure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +There is a top-level sysfs directory named 'class'. + +Each class gets a directory in the class directory, along with two +default subdirectories:: + + class/ + `-- input + |-- devices + `-- drivers + + +Drivers registered with the class get a symlink in the drivers/ directory +that points to the driver's directory (under its bus directory):: + + class/ + `-- input + |-- devices + `-- drivers + `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/ + + +Each device gets a symlink in the devices/ directory that points to the +device's directory in the physical hierarchy:: + + class/ + `-- input + |-- devices + | `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ + `-- drivers + + +Exporting Attributes +~~~~~~~~~~~~~~~~~~~~ + +:: + + struct devclass_attribute { + struct attribute attr; + ssize_t (*show)(struct device_class *, char * buf, size_t count, loff_t off); + ssize_t (*store)(struct device_class *, const char * buf, size_t count, loff_t off); + }; + +Class drivers can export attributes using the DEVCLASS_ATTR macro that works +similarly to the DEVICE_ATTR macro for devices. For example, a definition +like this:: + + static DEVCLASS_ATTR(debug,0644,show_debug,store_debug); + +is equivalent to declaring:: + + static devclass_attribute devclass_attr_debug; + +The bus driver can add and remove the attribute from the class's +sysfs directory using:: + + int devclass_create_file(struct device_class *, struct devclass_attribute *); + void devclass_remove_file(struct device_class *, struct devclass_attribute *); + +In the example above, the file will be named 'debug' in placed in the +class's directory in sysfs. + + +Interfaces +~~~~~~~~~~ +There may exist multiple mechanisms for accessing the same device of a +particular class type. Device interfaces describe these mechanisms. + +When a device is added to a device class, the core attempts to add it +to every interface that is registered with the device class. diff --git a/Documentation/driver-model/class.txt b/Documentation/driver-model/class.txt deleted file mode 100644 index 1fefc480a80b..000000000000 --- a/Documentation/driver-model/class.txt +++ /dev/null @@ -1,147 +0,0 @@ - -Device Classes - - -Introduction -~~~~~~~~~~~~ -A device class describes a type of device, like an audio or network -device. The following device classes have been identified: - - - - -Each device class defines a set of semantics and a programming interface -that devices of that class adhere to. Device drivers are the -implementation of that programming interface for a particular device on -a particular bus. - -Device classes are agnostic with respect to what bus a device resides -on. - - -Programming Interface -~~~~~~~~~~~~~~~~~~~~~ -The device class structure looks like: - - -typedef int (*devclass_add)(struct device *); -typedef void (*devclass_remove)(struct device *); - -See the kerneldoc for the struct class. - -A typical device class definition would look like: - -struct device_class input_devclass = { - .name = "input", - .add_device = input_add_device, - .remove_device = input_remove_device, -}; - -Each device class structure should be exported in a header file so it -can be used by drivers, extensions and interfaces. - -Device classes are registered and unregistered with the core using: - -int devclass_register(struct device_class * cls); -void devclass_unregister(struct device_class * cls); - - -Devices -~~~~~~~ -As devices are bound to drivers, they are added to the device class -that the driver belongs to. Before the driver model core, this would -typically happen during the driver's probe() callback, once the device -has been initialized. It now happens after the probe() callback -finishes from the core. - -The device is enumerated in the class. Each time a device is added to -the class, the class's devnum field is incremented and assigned to the -device. The field is never decremented, so if the device is removed -from the class and re-added, it will receive a different enumerated -value. - -The class is allowed to create a class-specific structure for the -device and store it in the device's class_data pointer. - -There is no list of devices in the device class. Each driver has a -list of devices that it supports. The device class has a list of -drivers of that particular class. To access all of the devices in the -class, iterate over the device lists of each driver in the class. - - -Device Drivers -~~~~~~~~~~~~~~ -Device drivers are added to device classes when they are registered -with the core. A driver specifies the class it belongs to by setting -the struct device_driver::devclass field. - - -sysfs directory structure -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -There is a top-level sysfs directory named 'class'. - -Each class gets a directory in the class directory, along with two -default subdirectories: - - class/ - `-- input - |-- devices - `-- drivers - - -Drivers registered with the class get a symlink in the drivers/ directory -that points to the driver's directory (under its bus directory): - - class/ - `-- input - |-- devices - `-- drivers - `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/ - - -Each device gets a symlink in the devices/ directory that points to the -device's directory in the physical hierarchy: - - class/ - `-- input - |-- devices - | `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ - `-- drivers - - -Exporting Attributes -~~~~~~~~~~~~~~~~~~~~ -struct devclass_attribute { - struct attribute attr; - ssize_t (*show)(struct device_class *, char * buf, size_t count, loff_t off); - ssize_t (*store)(struct device_class *, const char * buf, size_t count, loff_t off); -}; - -Class drivers can export attributes using the DEVCLASS_ATTR macro that works -similarly to the DEVICE_ATTR macro for devices. For example, a definition -like this: - -static DEVCLASS_ATTR(debug,0644,show_debug,store_debug); - -is equivalent to declaring: - -static devclass_attribute devclass_attr_debug; - -The bus driver can add and remove the attribute from the class's -sysfs directory using: - -int devclass_create_file(struct device_class *, struct devclass_attribute *); -void devclass_remove_file(struct device_class *, struct devclass_attribute *); - -In the example above, the file will be named 'debug' in placed in the -class's directory in sysfs. - - -Interfaces -~~~~~~~~~~ -There may exist multiple mechanisms for accessing the same device of a -particular class type. Device interfaces describe these mechanisms. - -When a device is added to a device class, the core attempts to add it -to every interface that is registered with the device class. - diff --git a/Documentation/driver-model/design-patterns.rst b/Documentation/driver-model/design-patterns.rst new file mode 100644 index 000000000000..41eb8f41f7dd --- /dev/null +++ b/Documentation/driver-model/design-patterns.rst @@ -0,0 +1,116 @@ +============================= +Device Driver Design Patterns +============================= + +This document describes a few common design patterns found in device drivers. +It is likely that subsystem maintainers will ask driver developers to +conform to these design patterns. + +1. State Container +2. container_of() + + +1. State Container +~~~~~~~~~~~~~~~~~~ + +While the kernel contains a few device drivers that assume that they will +only be probed() once on a certain system (singletons), it is custom to assume +that the device the driver binds to will appear in several instances. This +means that the probe() function and all callbacks need to be reentrant. + +The most common way to achieve this is to use the state container design +pattern. It usually has this form:: + + struct foo { + spinlock_t lock; /* Example member */ + (...) + }; + + static int foo_probe(...) + { + struct foo *foo; + + foo = devm_kzalloc(dev, sizeof(*foo), GFP_KERNEL); + if (!foo) + return -ENOMEM; + spin_lock_init(&foo->lock); + (...) + } + +This will create an instance of struct foo in memory every time probe() is +called. This is our state container for this instance of the device driver. +Of course it is then necessary to always pass this instance of the +state around to all functions that need access to the state and its members. + +For example, if the driver is registering an interrupt handler, you would +pass around a pointer to struct foo like this:: + + static irqreturn_t foo_handler(int irq, void *arg) + { + struct foo *foo = arg; + (...) + } + + static int foo_probe(...) + { + struct foo *foo; + + (...) + ret = request_irq(irq, foo_handler, 0, "foo", foo); + } + +This way you always get a pointer back to the correct instance of foo in +your interrupt handler. + + +2. container_of() +~~~~~~~~~~~~~~~~~ + +Continuing on the above example we add an offloaded work:: + + struct foo { + spinlock_t lock; + struct workqueue_struct *wq; + struct work_struct offload; + (...) + }; + + static void foo_work(struct work_struct *work) + { + struct foo *foo = container_of(work, struct foo, offload); + + (...) + } + + static irqreturn_t foo_handler(int irq, void *arg) + { + struct foo *foo = arg; + + queue_work(foo->wq, &foo->offload); + (...) + } + + static int foo_probe(...) + { + struct foo *foo; + + foo->wq = create_singlethread_workqueue("foo-wq"); + INIT_WORK(&foo->offload, foo_work); + (...) + } + +The design pattern is the same for an hrtimer or something similar that will +return a single argument which is a pointer to a struct member in the +callback. + +container_of() is a macro defined in + +What container_of() does is to obtain a pointer to the containing struct from +a pointer to a member by a simple subtraction using the offsetof() macro from +standard C, which allows something similar to object oriented behaviours. +Notice that the contained member must not be a pointer, but an actual member +for this to work. + +We can see here that we avoid having global pointers to our struct foo * +instance this way, while still keeping the number of parameters passed to the +work function to a single pointer. diff --git a/Documentation/driver-model/design-patterns.txt b/Documentation/driver-model/design-patterns.txt deleted file mode 100644 index ba7b2df64904..000000000000 --- a/Documentation/driver-model/design-patterns.txt +++ /dev/null @@ -1,116 +0,0 @@ - -Device Driver Design Patterns -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This document describes a few common design patterns found in device drivers. -It is likely that subsystem maintainers will ask driver developers to -conform to these design patterns. - -1. State Container -2. container_of() - - -1. State Container -~~~~~~~~~~~~~~~~~~ - -While the kernel contains a few device drivers that assume that they will -only be probed() once on a certain system (singletons), it is custom to assume -that the device the driver binds to will appear in several instances. This -means that the probe() function and all callbacks need to be reentrant. - -The most common way to achieve this is to use the state container design -pattern. It usually has this form: - -struct foo { - spinlock_t lock; /* Example member */ - (...) -}; - -static int foo_probe(...) -{ - struct foo *foo; - - foo = devm_kzalloc(dev, sizeof(*foo), GFP_KERNEL); - if (!foo) - return -ENOMEM; - spin_lock_init(&foo->lock); - (...) -} - -This will create an instance of struct foo in memory every time probe() is -called. This is our state container for this instance of the device driver. -Of course it is then necessary to always pass this instance of the -state around to all functions that need access to the state and its members. - -For example, if the driver is registering an interrupt handler, you would -pass around a pointer to struct foo like this: - -static irqreturn_t foo_handler(int irq, void *arg) -{ - struct foo *foo = arg; - (...) -} - -static int foo_probe(...) -{ - struct foo *foo; - - (...) - ret = request_irq(irq, foo_handler, 0, "foo", foo); -} - -This way you always get a pointer back to the correct instance of foo in -your interrupt handler. - - -2. container_of() -~~~~~~~~~~~~~~~~~ - -Continuing on the above example we add an offloaded work: - -struct foo { - spinlock_t lock; - struct workqueue_struct *wq; - struct work_struct offload; - (...) -}; - -static void foo_work(struct work_struct *work) -{ - struct foo *foo = container_of(work, struct foo, offload); - - (...) -} - -static irqreturn_t foo_handler(int irq, void *arg) -{ - struct foo *foo = arg; - - queue_work(foo->wq, &foo->offload); - (...) -} - -static int foo_probe(...) -{ - struct foo *foo; - - foo->wq = create_singlethread_workqueue("foo-wq"); - INIT_WORK(&foo->offload, foo_work); - (...) -} - -The design pattern is the same for an hrtimer or something similar that will -return a single argument which is a pointer to a struct member in the -callback. - -container_of() is a macro defined in - -What container_of() does is to obtain a pointer to the containing struct from -a pointer to a member by a simple subtraction using the offsetof() macro from -standard C, which allows something similar to object oriented behaviours. -Notice that the contained member must not be a pointer, but an actual member -for this to work. - -We can see here that we avoid having global pointers to our struct foo * -instance this way, while still keeping the number of parameters passed to the -work function to a single pointer. diff --git a/Documentation/driver-model/device.rst b/Documentation/driver-model/device.rst new file mode 100644 index 000000000000..2b868d49d349 --- /dev/null +++ b/Documentation/driver-model/device.rst @@ -0,0 +1,109 @@ +========================== +The Basic Device Structure +========================== + +See the kerneldoc for the struct device. + + +Programming Interface +~~~~~~~~~~~~~~~~~~~~~ +The bus driver that discovers the device uses this to register the +device with the core:: + + int device_register(struct device * dev); + +The bus should initialize the following fields: + + - parent + - name + - bus_id + - bus + +A device is removed from the core when its reference count goes to +0. The reference count can be adjusted using:: + + struct device * get_device(struct device * dev); + void put_device(struct device * dev); + +get_device() will return a pointer to the struct device passed to it +if the reference is not already 0 (if it's in the process of being +removed already). + +A driver can access the lock in the device structure using:: + + void lock_device(struct device * dev); + void unlock_device(struct device * dev); + + +Attributes +~~~~~~~~~~ + +:: + + struct device_attribute { + struct attribute attr; + ssize_t (*show)(struct device *dev, struct device_attribute *attr, + char *buf); + ssize_t (*store)(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); + }; + +Attributes of devices can be exported by a device driver through sysfs. + +Please see Documentation/filesystems/sysfs.txt for more information +on how sysfs works. + +As explained in Documentation/kobject.txt, device attributes must be +created before the KOBJ_ADD uevent is generated. The only way to realize +that is by defining an attribute group. + +Attributes are declared using a macro called DEVICE_ATTR:: + + #define DEVICE_ATTR(name,mode,show,store) + +Example::: + + static DEVICE_ATTR(type, 0444, show_type, NULL); + static DEVICE_ATTR(power, 0644, show_power, store_power); + +This declares two structures of type struct device_attribute with respective +names 'dev_attr_type' and 'dev_attr_power'. These two attributes can be +organized as follows into a group:: + + static struct attribute *dev_attrs[] = { + &dev_attr_type.attr, + &dev_attr_power.attr, + NULL, + }; + + static struct attribute_group dev_attr_group = { + .attrs = dev_attrs, + }; + + static const struct attribute_group *dev_attr_groups[] = { + &dev_attr_group, + NULL, + }; + +This array of groups can then be associated with a device by setting the +group pointer in struct device before device_register() is invoked:: + + dev->groups = dev_attr_groups; + device_register(dev); + +The device_register() function will use the 'groups' pointer to create the +device attributes and the device_unregister() function will use this pointer +to remove the device attributes. + +Word of warning: While the kernel allows device_create_file() and +device_remove_file() to be called on a device at any time, userspace has +strict expectations on when attributes get created. When a new device is +registered in the kernel, a uevent is generated to notify userspace (like +udev) that a new device is available. If attributes are added after the +device is registered, then userspace won't get notified and userspace will +not know about the new attributes. + +This is important for device driver that need to publish additional +attributes for a device at driver probe time. If the device driver simply +calls device_create_file() on the device structure passed to it, then +userspace will never be notified of the new attributes. diff --git a/Documentation/driver-model/device.txt b/Documentation/driver-model/device.txt deleted file mode 100644 index 2403eb856187..000000000000 --- a/Documentation/driver-model/device.txt +++ /dev/null @@ -1,106 +0,0 @@ - -The Basic Device Structure -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -See the kerneldoc for the struct device. - - -Programming Interface -~~~~~~~~~~~~~~~~~~~~~ -The bus driver that discovers the device uses this to register the -device with the core: - -int device_register(struct device * dev); - -The bus should initialize the following fields: - - - parent - - name - - bus_id - - bus - -A device is removed from the core when its reference count goes to -0. The reference count can be adjusted using: - -struct device * get_device(struct device * dev); -void put_device(struct device * dev); - -get_device() will return a pointer to the struct device passed to it -if the reference is not already 0 (if it's in the process of being -removed already). - -A driver can access the lock in the device structure using: - -void lock_device(struct device * dev); -void unlock_device(struct device * dev); - - -Attributes -~~~~~~~~~~ -struct device_attribute { - struct attribute attr; - ssize_t (*show)(struct device *dev, struct device_attribute *attr, - char *buf); - ssize_t (*store)(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count); -}; - -Attributes of devices can be exported by a device driver through sysfs. - -Please see Documentation/filesystems/sysfs.txt for more information -on how sysfs works. - -As explained in Documentation/kobject.txt, device attributes must be -created before the KOBJ_ADD uevent is generated. The only way to realize -that is by defining an attribute group. - -Attributes are declared using a macro called DEVICE_ATTR: - -#define DEVICE_ATTR(name,mode,show,store) - -Example: - -static DEVICE_ATTR(type, 0444, show_type, NULL); -static DEVICE_ATTR(power, 0644, show_power, store_power); - -This declares two structures of type struct device_attribute with respective -names 'dev_attr_type' and 'dev_attr_power'. These two attributes can be -organized as follows into a group: - -static struct attribute *dev_attrs[] = { - &dev_attr_type.attr, - &dev_attr_power.attr, - NULL, -}; - -static struct attribute_group dev_attr_group = { - .attrs = dev_attrs, -}; - -static const struct attribute_group *dev_attr_groups[] = { - &dev_attr_group, - NULL, -}; - -This array of groups can then be associated with a device by setting the -group pointer in struct device before device_register() is invoked: - - dev->groups = dev_attr_groups; - device_register(dev); - -The device_register() function will use the 'groups' pointer to create the -device attributes and the device_unregister() function will use this pointer -to remove the device attributes. - -Word of warning: While the kernel allows device_create_file() and -device_remove_file() to be called on a device at any time, userspace has -strict expectations on when attributes get created. When a new device is -registered in the kernel, a uevent is generated to notify userspace (like -udev) that a new device is available. If attributes are added after the -device is registered, then userspace won't get notified and userspace will -not know about the new attributes. - -This is important for device driver that need to publish additional -attributes for a device at driver probe time. If the device driver simply -calls device_create_file() on the device structure passed to it, then -userspace will never be notified of the new attributes. diff --git a/Documentation/driver-model/devres.rst b/Documentation/driver-model/devres.rst new file mode 100644 index 000000000000..4ac99122b5f1 --- /dev/null +++ b/Documentation/driver-model/devres.rst @@ -0,0 +1,414 @@ +================================ +Devres - Managed Device Resource +================================ + +Tejun Heo + +First draft 10 January 2007 + +.. contents + + 1. Intro : Huh? Devres? + 2. Devres : Devres in a nutshell + 3. Devres Group : Group devres'es and release them together + 4. Details : Life time rules, calling context, ... + 5. Overhead : How much do we have to pay for this? + 6. List of managed interfaces: Currently implemented managed interfaces + + +1. Intro +-------- + +devres came up while trying to convert libata to use iomap. Each +iomapped address should be kept and unmapped on driver detach. For +example, a plain SFF ATA controller (that is, good old PCI IDE) in +native mode makes use of 5 PCI BARs and all of them should be +maintained. + +As with many other device drivers, libata low level drivers have +sufficient bugs in ->remove and ->probe failure path. Well, yes, +that's probably because libata low level driver developers are lazy +bunch, but aren't all low level driver developers? After spending a +day fiddling with braindamaged hardware with no document or +braindamaged document, if it's finally working, well, it's working. + +For one reason or another, low level drivers don't receive as much +attention or testing as core code, and bugs on driver detach or +initialization failure don't happen often enough to be noticeable. +Init failure path is worse because it's much less travelled while +needs to handle multiple entry points. + +So, many low level drivers end up leaking resources on driver detach +and having half broken failure path implementation in ->probe() which +would leak resources or even cause oops when failure occurs. iomap +adds more to this mix. So do msi and msix. + + +2. Devres +--------- + +devres is basically linked list of arbitrarily sized memory areas +associated with a struct device. Each devres entry is associated with +a release function. A devres can be released in several ways. No +matter what, all devres entries are released on driver detach. On +release, the associated release function is invoked and then the +devres entry is freed. + +Managed interface is created for resources commonly used by device +drivers using devres. For example, coherent DMA memory is acquired +using dma_alloc_coherent(). The managed version is called +dmam_alloc_coherent(). It is identical to dma_alloc_coherent() except +for the DMA memory allocated using it is managed and will be +automatically released on driver detach. Implementation looks like +the following:: + + struct dma_devres { + size_t size; + void *vaddr; + dma_addr_t dma_handle; + }; + + static void dmam_coherent_release(struct device *dev, void *res) + { + struct dma_devres *this = res; + + dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle); + } + + dmam_alloc_coherent(dev, size, dma_handle, gfp) + { + struct dma_devres *dr; + void *vaddr; + + dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp); + ... + + /* alloc DMA memory as usual */ + vaddr = dma_alloc_coherent(...); + ... + + /* record size, vaddr, dma_handle in dr */ + dr->vaddr = vaddr; + ... + + devres_add(dev, dr); + + return vaddr; + } + +If a driver uses dmam_alloc_coherent(), the area is guaranteed to be +freed whether initialization fails half-way or the device gets +detached. If most resources are acquired using managed interface, a +driver can have much simpler init and exit code. Init path basically +looks like the following:: + + my_init_one() + { + struct mydev *d; + + d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + d->ring = dmam_alloc_coherent(...); + if (!d->ring) + return -ENOMEM; + + if (check something) + return -EINVAL; + ... + + return register_to_upper_layer(d); + } + +And exit path:: + + my_remove_one() + { + unregister_from_upper_layer(d); + shutdown_my_hardware(); + } + +As shown above, low level drivers can be simplified a lot by using +devres. Complexity is shifted from less maintained low level drivers +to better maintained higher layer. Also, as init failure path is +shared with exit path, both can get more testing. + +Note though that when converting current calls or assignments to +managed devm_* versions it is up to you to check if internal operations +like allocating memory, have failed. Managed resources pertains to the +freeing of these resources *only* - all other checks needed are still +on you. In some cases this may mean introducing checks that were not +necessary before moving to the managed devm_* calls. + + +3. Devres group +--------------- + +Devres entries can be grouped using devres group. When a group is +released, all contained normal devres entries and properly nested +groups are released. One usage is to rollback series of acquired +resources on failure. For example:: + + if (!devres_open_group(dev, NULL, GFP_KERNEL)) + return -ENOMEM; + + acquire A; + if (failed) + goto err; + + acquire B; + if (failed) + goto err; + ... + + devres_remove_group(dev, NULL); + return 0; + + err: + devres_release_group(dev, NULL); + return err_code; + +As resource acquisition failure usually means probe failure, constructs +like above are usually useful in midlayer driver (e.g. libata core +layer) where interface function shouldn't have side effect on failure. +For LLDs, just returning error code suffices in most cases. + +Each group is identified by `void *id`. It can either be explicitly +specified by @id argument to devres_open_group() or automatically +created by passing NULL as @id as in the above example. In both +cases, devres_open_group() returns the group's id. The returned id +can be passed to other devres functions to select the target group. +If NULL is given to those functions, the latest open group is +selected. + +For example, you can do something like the following:: + + int my_midlayer_create_something() + { + if (!devres_open_group(dev, my_midlayer_create_something, GFP_KERNEL)) + return -ENOMEM; + + ... + + devres_close_group(dev, my_midlayer_create_something); + return 0; + } + + void my_midlayer_destroy_something() + { + devres_release_group(dev, my_midlayer_create_something); + } + + +4. Details +---------- + +Lifetime of a devres entry begins on devres allocation and finishes +when it is released or destroyed (removed and freed) - no reference +counting. + +devres core guarantees atomicity to all basic devres operations and +has support for single-instance devres types (atomic +lookup-and-add-if-not-found). Other than that, synchronizing +concurrent accesses to allocated devres data is caller's +responsibility. This is usually non-issue because bus ops and +resource allocations already do the job. + +For an example of single-instance devres type, read pcim_iomap_table() +in lib/devres.c. + +All devres interface functions can be called without context if the +right gfp mask is given. + + +5. Overhead +----------- + +Each devres bookkeeping info is allocated together with requested data +area. With debug option turned off, bookkeeping info occupies 16 +bytes on 32bit machines and 24 bytes on 64bit (three pointers rounded +up to ull alignment). If singly linked list is used, it can be +reduced to two pointers (8 bytes on 32bit, 16 bytes on 64bit). + +Each devres group occupies 8 pointers. It can be reduced to 6 if +singly linked list is used. + +Memory space overhead on ahci controller with two ports is between 300 +and 400 bytes on 32bit machine after naive conversion (we can +certainly invest a bit more effort into libata core layer). + + +6. List of managed interfaces +----------------------------- + +CLOCK + devm_clk_get() + devm_clk_get_optional() + devm_clk_put() + devm_clk_hw_register() + devm_of_clk_add_hw_provider() + devm_clk_hw_register_clkdev() + +DMA + dmaenginem_async_device_register() + dmam_alloc_coherent() + dmam_alloc_attrs() + dmam_free_coherent() + dmam_pool_create() + dmam_pool_destroy() + +DRM + devm_drm_dev_init() + +GPIO + devm_gpiod_get() + devm_gpiod_get_index() + devm_gpiod_get_index_optional() + devm_gpiod_get_optional() + devm_gpiod_put() + devm_gpiod_unhinge() + devm_gpiochip_add_data() + devm_gpio_request() + devm_gpio_request_one() + devm_gpio_free() + +I2C + devm_i2c_new_dummy_device() + +IIO + devm_iio_device_alloc() + devm_iio_device_free() + devm_iio_device_register() + devm_iio_device_unregister() + devm_iio_kfifo_allocate() + devm_iio_kfifo_free() + devm_iio_triggered_buffer_setup() + devm_iio_triggered_buffer_cleanup() + devm_iio_trigger_alloc() + devm_iio_trigger_free() + devm_iio_trigger_register() + devm_iio_trigger_unregister() + devm_iio_channel_get() + devm_iio_channel_release() + devm_iio_channel_get_all() + devm_iio_channel_release_all() + +INPUT + devm_input_allocate_device() + +IO region + devm_release_mem_region() + devm_release_region() + devm_release_resource() + devm_request_mem_region() + devm_request_region() + devm_request_resource() + +IOMAP + devm_ioport_map() + devm_ioport_unmap() + devm_ioremap() + devm_ioremap_nocache() + devm_ioremap_wc() + devm_ioremap_resource() : checks resource, requests memory region, ioremaps + devm_iounmap() + pcim_iomap() + pcim_iomap_regions() : do request_region() and iomap() on multiple BARs + pcim_iomap_table() : array of mapped addresses indexed by BAR + pcim_iounmap() + +IRQ + devm_free_irq() + devm_request_any_context_irq() + devm_request_irq() + devm_request_threaded_irq() + devm_irq_alloc_descs() + devm_irq_alloc_desc() + devm_irq_alloc_desc_at() + devm_irq_alloc_desc_from() + devm_irq_alloc_descs_from() + devm_irq_alloc_generic_chip() + devm_irq_setup_generic_chip() + devm_irq_sim_init() + +LED + devm_led_classdev_register() + devm_led_classdev_unregister() + +MDIO + devm_mdiobus_alloc() + devm_mdiobus_alloc_size() + devm_mdiobus_free() + +MEM + devm_free_pages() + devm_get_free_pages() + devm_kasprintf() + devm_kcalloc() + devm_kfree() + devm_kmalloc() + devm_kmalloc_array() + devm_kmemdup() + devm_kstrdup() + devm_kvasprintf() + devm_kzalloc() + +MFD + devm_mfd_add_devices() + +MUX + devm_mux_chip_alloc() + devm_mux_chip_register() + devm_mux_control_get() + +PER-CPU MEM + devm_alloc_percpu() + devm_free_percpu() + +PCI + devm_pci_alloc_host_bridge() : managed PCI host bridge allocation + devm_pci_remap_cfgspace() : ioremap PCI configuration space + devm_pci_remap_cfg_resource() : ioremap PCI configuration space resource + pcim_enable_device() : after success, all PCI ops become managed + pcim_pin_device() : keep PCI device enabled after release + +PHY + devm_usb_get_phy() + devm_usb_put_phy() + +PINCTRL + devm_pinctrl_get() + devm_pinctrl_put() + devm_pinctrl_register() + devm_pinctrl_unregister() + +POWER + devm_reboot_mode_register() + devm_reboot_mode_unregister() + +PWM + devm_pwm_get() + devm_pwm_put() + +REGULATOR + devm_regulator_bulk_get() + devm_regulator_get() + devm_regulator_put() + devm_regulator_register() + +RESET + devm_reset_control_get() + devm_reset_controller_register() + +SERDEV + devm_serdev_device_open() + +SLAVE DMA ENGINE + devm_acpi_dma_controller_register() + +SPI + devm_spi_register_master() + +WATCHDOG + devm_watchdog_register_device() diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt deleted file mode 100644 index 69c7fa7f616c..000000000000 --- a/Documentation/driver-model/devres.txt +++ /dev/null @@ -1,412 +0,0 @@ -Devres - Managed Device Resource -================================ - -Tejun Heo - -First draft 10 January 2007 - - -1. Intro : Huh? Devres? -2. Devres : Devres in a nutshell -3. Devres Group : Group devres'es and release them together -4. Details : Life time rules, calling context, ... -5. Overhead : How much do we have to pay for this? -6. List of managed interfaces : Currently implemented managed interfaces - - - 1. Intro - -------- - -devres came up while trying to convert libata to use iomap. Each -iomapped address should be kept and unmapped on driver detach. For -example, a plain SFF ATA controller (that is, good old PCI IDE) in -native mode makes use of 5 PCI BARs and all of them should be -maintained. - -As with many other device drivers, libata low level drivers have -sufficient bugs in ->remove and ->probe failure path. Well, yes, -that's probably because libata low level driver developers are lazy -bunch, but aren't all low level driver developers? After spending a -day fiddling with braindamaged hardware with no document or -braindamaged document, if it's finally working, well, it's working. - -For one reason or another, low level drivers don't receive as much -attention or testing as core code, and bugs on driver detach or -initialization failure don't happen often enough to be noticeable. -Init failure path is worse because it's much less travelled while -needs to handle multiple entry points. - -So, many low level drivers end up leaking resources on driver detach -and having half broken failure path implementation in ->probe() which -would leak resources or even cause oops when failure occurs. iomap -adds more to this mix. So do msi and msix. - - - 2. Devres - --------- - -devres is basically linked list of arbitrarily sized memory areas -associated with a struct device. Each devres entry is associated with -a release function. A devres can be released in several ways. No -matter what, all devres entries are released on driver detach. On -release, the associated release function is invoked and then the -devres entry is freed. - -Managed interface is created for resources commonly used by device -drivers using devres. For example, coherent DMA memory is acquired -using dma_alloc_coherent(). The managed version is called -dmam_alloc_coherent(). It is identical to dma_alloc_coherent() except -for the DMA memory allocated using it is managed and will be -automatically released on driver detach. Implementation looks like -the following. - - struct dma_devres { - size_t size; - void *vaddr; - dma_addr_t dma_handle; - }; - - static void dmam_coherent_release(struct device *dev, void *res) - { - struct dma_devres *this = res; - - dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle); - } - - dmam_alloc_coherent(dev, size, dma_handle, gfp) - { - struct dma_devres *dr; - void *vaddr; - - dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp); - ... - - /* alloc DMA memory as usual */ - vaddr = dma_alloc_coherent(...); - ... - - /* record size, vaddr, dma_handle in dr */ - dr->vaddr = vaddr; - ... - - devres_add(dev, dr); - - return vaddr; - } - -If a driver uses dmam_alloc_coherent(), the area is guaranteed to be -freed whether initialization fails half-way or the device gets -detached. If most resources are acquired using managed interface, a -driver can have much simpler init and exit code. Init path basically -looks like the following. - - my_init_one() - { - struct mydev *d; - - d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); - if (!d) - return -ENOMEM; - - d->ring = dmam_alloc_coherent(...); - if (!d->ring) - return -ENOMEM; - - if (check something) - return -EINVAL; - ... - - return register_to_upper_layer(d); - } - -And exit path, - - my_remove_one() - { - unregister_from_upper_layer(d); - shutdown_my_hardware(); - } - -As shown above, low level drivers can be simplified a lot by using -devres. Complexity is shifted from less maintained low level drivers -to better maintained higher layer. Also, as init failure path is -shared with exit path, both can get more testing. - -Note though that when converting current calls or assignments to -managed devm_* versions it is up to you to check if internal operations -like allocating memory, have failed. Managed resources pertains to the -freeing of these resources *only* - all other checks needed are still -on you. In some cases this may mean introducing checks that were not -necessary before moving to the managed devm_* calls. - - - 3. Devres group - --------------- - -Devres entries can be grouped using devres group. When a group is -released, all contained normal devres entries and properly nested -groups are released. One usage is to rollback series of acquired -resources on failure. For example, - - if (!devres_open_group(dev, NULL, GFP_KERNEL)) - return -ENOMEM; - - acquire A; - if (failed) - goto err; - - acquire B; - if (failed) - goto err; - ... - - devres_remove_group(dev, NULL); - return 0; - - err: - devres_release_group(dev, NULL); - return err_code; - -As resource acquisition failure usually means probe failure, constructs -like above are usually useful in midlayer driver (e.g. libata core -layer) where interface function shouldn't have side effect on failure. -For LLDs, just returning error code suffices in most cases. - -Each group is identified by void *id. It can either be explicitly -specified by @id argument to devres_open_group() or automatically -created by passing NULL as @id as in the above example. In both -cases, devres_open_group() returns the group's id. The returned id -can be passed to other devres functions to select the target group. -If NULL is given to those functions, the latest open group is -selected. - -For example, you can do something like the following. - - int my_midlayer_create_something() - { - if (!devres_open_group(dev, my_midlayer_create_something, GFP_KERNEL)) - return -ENOMEM; - - ... - - devres_close_group(dev, my_midlayer_create_something); - return 0; - } - - void my_midlayer_destroy_something() - { - devres_release_group(dev, my_midlayer_create_something); - } - - - 4. Details - ---------- - -Lifetime of a devres entry begins on devres allocation and finishes -when it is released or destroyed (removed and freed) - no reference -counting. - -devres core guarantees atomicity to all basic devres operations and -has support for single-instance devres types (atomic -lookup-and-add-if-not-found). Other than that, synchronizing -concurrent accesses to allocated devres data is caller's -responsibility. This is usually non-issue because bus ops and -resource allocations already do the job. - -For an example of single-instance devres type, read pcim_iomap_table() -in lib/devres.c. - -All devres interface functions can be called without context if the -right gfp mask is given. - - - 5. Overhead - ----------- - -Each devres bookkeeping info is allocated together with requested data -area. With debug option turned off, bookkeeping info occupies 16 -bytes on 32bit machines and 24 bytes on 64bit (three pointers rounded -up to ull alignment). If singly linked list is used, it can be -reduced to two pointers (8 bytes on 32bit, 16 bytes on 64bit). - -Each devres group occupies 8 pointers. It can be reduced to 6 if -singly linked list is used. - -Memory space overhead on ahci controller with two ports is between 300 -and 400 bytes on 32bit machine after naive conversion (we can -certainly invest a bit more effort into libata core layer). - - - 6. List of managed interfaces - ----------------------------- - -CLOCK - devm_clk_get() - devm_clk_get_optional() - devm_clk_put() - devm_clk_hw_register() - devm_of_clk_add_hw_provider() - devm_clk_hw_register_clkdev() - -DMA - dmaenginem_async_device_register() - dmam_alloc_coherent() - dmam_alloc_attrs() - dmam_free_coherent() - dmam_pool_create() - dmam_pool_destroy() - -DRM - devm_drm_dev_init() - -GPIO - devm_gpiod_get() - devm_gpiod_get_index() - devm_gpiod_get_index_optional() - devm_gpiod_get_optional() - devm_gpiod_put() - devm_gpiod_unhinge() - devm_gpiochip_add_data() - devm_gpio_request() - devm_gpio_request_one() - devm_gpio_free() - -I2C - devm_i2c_new_dummy_device() - -IIO - devm_iio_device_alloc() - devm_iio_device_free() - devm_iio_device_register() - devm_iio_device_unregister() - devm_iio_kfifo_allocate() - devm_iio_kfifo_free() - devm_iio_triggered_buffer_setup() - devm_iio_triggered_buffer_cleanup() - devm_iio_trigger_alloc() - devm_iio_trigger_free() - devm_iio_trigger_register() - devm_iio_trigger_unregister() - devm_iio_channel_get() - devm_iio_channel_release() - devm_iio_channel_get_all() - devm_iio_channel_release_all() - -INPUT - devm_input_allocate_device() - -IO region - devm_release_mem_region() - devm_release_region() - devm_release_resource() - devm_request_mem_region() - devm_request_region() - devm_request_resource() - -IOMAP - devm_ioport_map() - devm_ioport_unmap() - devm_ioremap() - devm_ioremap_nocache() - devm_ioremap_wc() - devm_ioremap_resource() : checks resource, requests memory region, ioremaps - devm_iounmap() - pcim_iomap() - pcim_iomap_regions() : do request_region() and iomap() on multiple BARs - pcim_iomap_table() : array of mapped addresses indexed by BAR - pcim_iounmap() - -IRQ - devm_free_irq() - devm_request_any_context_irq() - devm_request_irq() - devm_request_threaded_irq() - devm_irq_alloc_descs() - devm_irq_alloc_desc() - devm_irq_alloc_desc_at() - devm_irq_alloc_desc_from() - devm_irq_alloc_descs_from() - devm_irq_alloc_generic_chip() - devm_irq_setup_generic_chip() - devm_irq_sim_init() - -LED - devm_led_classdev_register() - devm_led_classdev_unregister() - -MDIO - devm_mdiobus_alloc() - devm_mdiobus_alloc_size() - devm_mdiobus_free() - -MEM - devm_free_pages() - devm_get_free_pages() - devm_kasprintf() - devm_kcalloc() - devm_kfree() - devm_kmalloc() - devm_kmalloc_array() - devm_kmemdup() - devm_kstrdup() - devm_kvasprintf() - devm_kzalloc() - -MFD - devm_mfd_add_devices() - -MUX - devm_mux_chip_alloc() - devm_mux_chip_register() - devm_mux_control_get() - -PER-CPU MEM - devm_alloc_percpu() - devm_free_percpu() - -PCI - devm_pci_alloc_host_bridge() : managed PCI host bridge allocation - devm_pci_remap_cfgspace() : ioremap PCI configuration space - devm_pci_remap_cfg_resource() : ioremap PCI configuration space resource - pcim_enable_device() : after success, all PCI ops become managed - pcim_pin_device() : keep PCI device enabled after release - -PHY - devm_usb_get_phy() - devm_usb_put_phy() - -PINCTRL - devm_pinctrl_get() - devm_pinctrl_put() - devm_pinctrl_register() - devm_pinctrl_unregister() - -POWER - devm_reboot_mode_register() - devm_reboot_mode_unregister() - -PWM - devm_pwm_get() - devm_pwm_put() - -REGULATOR - devm_regulator_bulk_get() - devm_regulator_get() - devm_regulator_put() - devm_regulator_register() - -RESET - devm_reset_control_get() - devm_reset_controller_register() - -SERDEV - devm_serdev_device_open() - -SLAVE DMA ENGINE - devm_acpi_dma_controller_register() - -SPI - devm_spi_register_master() - -WATCHDOG - devm_watchdog_register_device() diff --git a/Documentation/driver-model/driver.rst b/Documentation/driver-model/driver.rst new file mode 100644 index 000000000000..11d281506a04 --- /dev/null +++ b/Documentation/driver-model/driver.rst @@ -0,0 +1,223 @@ +============== +Device Drivers +============== + +See the kerneldoc for the struct device_driver. + + +Allocation +~~~~~~~~~~ + +Device drivers are statically allocated structures. Though there may +be multiple devices in a system that a driver supports, struct +device_driver represents the driver as a whole (not a particular +device instance). + +Initialization +~~~~~~~~~~~~~~ + +The driver must initialize at least the name and bus fields. It should +also initialize the devclass field (when it arrives), so it may obtain +the proper linkage internally. It should also initialize as many of +the callbacks as possible, though each is optional. + +Declaration +~~~~~~~~~~~ + +As stated above, struct device_driver objects are statically +allocated. Below is an example declaration of the eepro100 +driver. This declaration is hypothetical only; it relies on the driver +being converted completely to the new model:: + + static struct device_driver eepro100_driver = { + .name = "eepro100", + .bus = &pci_bus_type, + + .probe = eepro100_probe, + .remove = eepro100_remove, + .suspend = eepro100_suspend, + .resume = eepro100_resume, + }; + +Most drivers will not be able to be converted completely to the new +model because the bus they belong to has a bus-specific structure with +bus-specific fields that cannot be generalized. + +The most common example of this are device ID structures. A driver +typically defines an array of device IDs that it supports. The format +of these structures and the semantics for comparing device IDs are +completely bus-specific. Defining them as bus-specific entities would +sacrifice type-safety, so we keep bus-specific structures around. + +Bus-specific drivers should include a generic struct device_driver in +the definition of the bus-specific driver. Like this:: + + struct pci_driver { + const struct pci_device_id *id_table; + struct device_driver driver; + }; + +A definition that included bus-specific fields would look like +(using the eepro100 driver again):: + + static struct pci_driver eepro100_driver = { + .id_table = eepro100_pci_tbl, + .driver = { + .name = "eepro100", + .bus = &pci_bus_type, + .probe = eepro100_probe, + .remove = eepro100_remove, + .suspend = eepro100_suspend, + .resume = eepro100_resume, + }, + }; + +Some may find the syntax of embedded struct initialization awkward or +even a bit ugly. So far, it's the best way we've found to do what we want... + +Registration +~~~~~~~~~~~~ + +:: + + int driver_register(struct device_driver *drv); + +The driver registers the structure on startup. For drivers that have +no bus-specific fields (i.e. don't have a bus-specific driver +structure), they would use driver_register and pass a pointer to their +struct device_driver object. + +Most drivers, however, will have a bus-specific structure and will +need to register with the bus using something like pci_driver_register. + +It is important that drivers register their driver structure as early as +possible. Registration with the core initializes several fields in the +struct device_driver object, including the reference count and the +lock. These fields are assumed to be valid at all times and may be +used by the device model core or the bus driver. + + +Transition Bus Drivers +~~~~~~~~~~~~~~~~~~~~~~ + +By defining wrapper functions, the transition to the new model can be +made easier. Drivers can ignore the generic structure altogether and +let the bus wrapper fill in the fields. For the callbacks, the bus can +define generic callbacks that forward the call to the bus-specific +callbacks of the drivers. + +This solution is intended to be only temporary. In order to get class +information in the driver, the drivers must be modified anyway. Since +converting drivers to the new model should reduce some infrastructural +complexity and code size, it is recommended that they are converted as +class information is added. + +Access +~~~~~~ + +Once the object has been registered, it may access the common fields of +the object, like the lock and the list of devices:: + + int driver_for_each_dev(struct device_driver *drv, void *data, + int (*callback)(struct device *dev, void *data)); + +The devices field is a list of all the devices that have been bound to +the driver. The LDM core provides a helper function to operate on all +the devices a driver controls. This helper locks the driver on each +node access, and does proper reference counting on each device as it +accesses it. + + +sysfs +~~~~~ + +When a driver is registered, a sysfs directory is created in its +bus's directory. In this directory, the driver can export an interface +to userspace to control operation of the driver on a global basis; +e.g. toggling debugging output in the driver. + +A future feature of this directory will be a 'devices' directory. This +directory will contain symlinks to the directories of devices it +supports. + + + +Callbacks +~~~~~~~~~ + +:: + + int (*probe) (struct device *dev); + +The probe() entry is called in task context, with the bus's rwsem locked +and the driver partially bound to the device. Drivers commonly use +container_of() to convert "dev" to a bus-specific type, both in probe() +and other routines. That type often provides device resource data, such +as pci_dev.resource[] or platform_device.resources, which is used in +addition to dev->platform_data to initialize the driver. + +This callback holds the driver-specific logic to bind the driver to a +given device. That includes verifying that the device is present, that +it's a version the driver can handle, that driver data structures can +be allocated and initialized, and that any hardware can be initialized. +Drivers often store a pointer to their state with dev_set_drvdata(). +When the driver has successfully bound itself to that device, then probe() +returns zero and the driver model code will finish its part of binding +the driver to that device. + +A driver's probe() may return a negative errno value to indicate that +the driver did not bind to this device, in which case it should have +released all resources it allocated:: + + int (*remove) (struct device *dev); + +remove is called to unbind a driver from a device. This may be +called if a device is physically removed from the system, if the +driver module is being unloaded, during a reboot sequence, or +in other cases. + +It is up to the driver to determine if the device is present or +not. It should free any resources allocated specifically for the +device; i.e. anything in the device's driver_data field. + +If the device is still present, it should quiesce the device and place +it into a supported low-power state:: + + int (*suspend) (struct device *dev, pm_message_t state); + +suspend is called to put the device in a low power state:: + + int (*resume) (struct device *dev); + +Resume is used to bring a device back from a low power state. + + +Attributes +~~~~~~~~~~ + +:: + + struct driver_attribute { + struct attribute attr; + ssize_t (*show)(struct device_driver *driver, char *buf); + ssize_t (*store)(struct device_driver *, const char *buf, size_t count); + }; + +Device drivers can export attributes via their sysfs directories. +Drivers can declare attributes using a DRIVER_ATTR_RW and DRIVER_ATTR_RO +macro that works identically to the DEVICE_ATTR_RW and DEVICE_ATTR_RO +macros. + +Example:: + + DRIVER_ATTR_RW(debug); + +This is equivalent to declaring:: + + struct driver_attribute driver_attr_debug; + +This can then be used to add and remove the attribute from the +driver's directory using:: + + int driver_create_file(struct device_driver *, const struct driver_attribute *); + void driver_remove_file(struct device_driver *, const struct driver_attribute *); diff --git a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt deleted file mode 100644 index d661e6f7e6a0..000000000000 --- a/Documentation/driver-model/driver.txt +++ /dev/null @@ -1,215 +0,0 @@ - -Device Drivers - -See the kerneldoc for the struct device_driver. - - -Allocation -~~~~~~~~~~ - -Device drivers are statically allocated structures. Though there may -be multiple devices in a system that a driver supports, struct -device_driver represents the driver as a whole (not a particular -device instance). - -Initialization -~~~~~~~~~~~~~~ - -The driver must initialize at least the name and bus fields. It should -also initialize the devclass field (when it arrives), so it may obtain -the proper linkage internally. It should also initialize as many of -the callbacks as possible, though each is optional. - -Declaration -~~~~~~~~~~~ - -As stated above, struct device_driver objects are statically -allocated. Below is an example declaration of the eepro100 -driver. This declaration is hypothetical only; it relies on the driver -being converted completely to the new model. - -static struct device_driver eepro100_driver = { - .name = "eepro100", - .bus = &pci_bus_type, - - .probe = eepro100_probe, - .remove = eepro100_remove, - .suspend = eepro100_suspend, - .resume = eepro100_resume, -}; - -Most drivers will not be able to be converted completely to the new -model because the bus they belong to has a bus-specific structure with -bus-specific fields that cannot be generalized. - -The most common example of this are device ID structures. A driver -typically defines an array of device IDs that it supports. The format -of these structures and the semantics for comparing device IDs are -completely bus-specific. Defining them as bus-specific entities would -sacrifice type-safety, so we keep bus-specific structures around. - -Bus-specific drivers should include a generic struct device_driver in -the definition of the bus-specific driver. Like this: - -struct pci_driver { - const struct pci_device_id *id_table; - struct device_driver driver; -}; - -A definition that included bus-specific fields would look like -(using the eepro100 driver again): - -static struct pci_driver eepro100_driver = { - .id_table = eepro100_pci_tbl, - .driver = { - .name = "eepro100", - .bus = &pci_bus_type, - .probe = eepro100_probe, - .remove = eepro100_remove, - .suspend = eepro100_suspend, - .resume = eepro100_resume, - }, -}; - -Some may find the syntax of embedded struct initialization awkward or -even a bit ugly. So far, it's the best way we've found to do what we want... - -Registration -~~~~~~~~~~~~ - -int driver_register(struct device_driver * drv); - -The driver registers the structure on startup. For drivers that have -no bus-specific fields (i.e. don't have a bus-specific driver -structure), they would use driver_register and pass a pointer to their -struct device_driver object. - -Most drivers, however, will have a bus-specific structure and will -need to register with the bus using something like pci_driver_register. - -It is important that drivers register their driver structure as early as -possible. Registration with the core initializes several fields in the -struct device_driver object, including the reference count and the -lock. These fields are assumed to be valid at all times and may be -used by the device model core or the bus driver. - - -Transition Bus Drivers -~~~~~~~~~~~~~~~~~~~~~~ - -By defining wrapper functions, the transition to the new model can be -made easier. Drivers can ignore the generic structure altogether and -let the bus wrapper fill in the fields. For the callbacks, the bus can -define generic callbacks that forward the call to the bus-specific -callbacks of the drivers. - -This solution is intended to be only temporary. In order to get class -information in the driver, the drivers must be modified anyway. Since -converting drivers to the new model should reduce some infrastructural -complexity and code size, it is recommended that they are converted as -class information is added. - -Access -~~~~~~ - -Once the object has been registered, it may access the common fields of -the object, like the lock and the list of devices. - -int driver_for_each_dev(struct device_driver * drv, void * data, - int (*callback)(struct device * dev, void * data)); - -The devices field is a list of all the devices that have been bound to -the driver. The LDM core provides a helper function to operate on all -the devices a driver controls. This helper locks the driver on each -node access, and does proper reference counting on each device as it -accesses it. - - -sysfs -~~~~~ - -When a driver is registered, a sysfs directory is created in its -bus's directory. In this directory, the driver can export an interface -to userspace to control operation of the driver on a global basis; -e.g. toggling debugging output in the driver. - -A future feature of this directory will be a 'devices' directory. This -directory will contain symlinks to the directories of devices it -supports. - - - -Callbacks -~~~~~~~~~ - - int (*probe) (struct device * dev); - -The probe() entry is called in task context, with the bus's rwsem locked -and the driver partially bound to the device. Drivers commonly use -container_of() to convert "dev" to a bus-specific type, both in probe() -and other routines. That type often provides device resource data, such -as pci_dev.resource[] or platform_device.resources, which is used in -addition to dev->platform_data to initialize the driver. - -This callback holds the driver-specific logic to bind the driver to a -given device. That includes verifying that the device is present, that -it's a version the driver can handle, that driver data structures can -be allocated and initialized, and that any hardware can be initialized. -Drivers often store a pointer to their state with dev_set_drvdata(). -When the driver has successfully bound itself to that device, then probe() -returns zero and the driver model code will finish its part of binding -the driver to that device. - -A driver's probe() may return a negative errno value to indicate that -the driver did not bind to this device, in which case it should have -released all resources it allocated. - - int (*remove) (struct device * dev); - -remove is called to unbind a driver from a device. This may be -called if a device is physically removed from the system, if the -driver module is being unloaded, during a reboot sequence, or -in other cases. - -It is up to the driver to determine if the device is present or -not. It should free any resources allocated specifically for the -device; i.e. anything in the device's driver_data field. - -If the device is still present, it should quiesce the device and place -it into a supported low-power state. - - int (*suspend) (struct device * dev, pm_message_t state); - -suspend is called to put the device in a low power state. - - int (*resume) (struct device * dev); - -Resume is used to bring a device back from a low power state. - - -Attributes -~~~~~~~~~~ -struct driver_attribute { - struct attribute attr; - ssize_t (*show)(struct device_driver *driver, char *buf); - ssize_t (*store)(struct device_driver *, const char * buf, size_t count); -}; - -Device drivers can export attributes via their sysfs directories. -Drivers can declare attributes using a DRIVER_ATTR_RW and DRIVER_ATTR_RO -macro that works identically to the DEVICE_ATTR_RW and DEVICE_ATTR_RO -macros. - -Example: - -DRIVER_ATTR_RW(debug); - -This is equivalent to declaring: - -struct driver_attribute driver_attr_debug; - -This can then be used to add and remove the attribute from the -driver's directory using: - -int driver_create_file(struct device_driver *, const struct driver_attribute *); -void driver_remove_file(struct device_driver *, const struct driver_attribute *); diff --git a/Documentation/driver-model/index.rst b/Documentation/driver-model/index.rst new file mode 100644 index 000000000000..9f85d579ce56 --- /dev/null +++ b/Documentation/driver-model/index.rst @@ -0,0 +1,26 @@ +:orphan: + +============ +Driver Model +============ + +.. toctree:: + :maxdepth: 1 + + binding + bus + class + design-patterns + device + devres + driver + overview + platform + porting + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/driver-model/overview.rst b/Documentation/driver-model/overview.rst new file mode 100644 index 000000000000..d4d1e9b40e0c --- /dev/null +++ b/Documentation/driver-model/overview.rst @@ -0,0 +1,124 @@ +============================= +The Linux Kernel Device Model +============================= + +Patrick Mochel + +Drafted 26 August 2002 +Updated 31 January 2006 + + +Overview +~~~~~~~~ + +The Linux Kernel Driver Model is a unification of all the disparate driver +models that were previously used in the kernel. It is intended to augment the +bus-specific drivers for bridges and devices by consolidating a set of data +and operations into globally accessible data structures. + +Traditional driver models implemented some sort of tree-like structure +(sometimes just a list) for the devices they control. There wasn't any +uniformity across the different bus types. + +The current driver model provides a common, uniform data model for describing +a bus and the devices that can appear under the bus. The unified bus +model includes a set of common attributes which all busses carry, and a set +of common callbacks, such as device discovery during bus probing, bus +shutdown, bus power management, etc. + +The common device and bridge interface reflects the goals of the modern +computer: namely the ability to do seamless device "plug and play", power +management, and hot plug. In particular, the model dictated by Intel and +Microsoft (namely ACPI) ensures that almost every device on almost any bus +on an x86-compatible system can work within this paradigm. Of course, +not every bus is able to support all such operations, although most +buses support most of those operations. + + +Downstream Access +~~~~~~~~~~~~~~~~~ + +Common data fields have been moved out of individual bus layers into a common +data structure. These fields must still be accessed by the bus layers, +and sometimes by the device-specific drivers. + +Other bus layers are encouraged to do what has been done for the PCI layer. +struct pci_dev now looks like this:: + + struct pci_dev { + ... + + struct device dev; /* Generic device interface */ + ... + }; + +Note first that the struct device dev within the struct pci_dev is +statically allocated. This means only one allocation on device discovery. + +Note also that that struct device dev is not necessarily defined at the +front of the pci_dev structure. This is to make people think about what +they're doing when switching between the bus driver and the global driver, +and to discourage meaningless and incorrect casts between the two. + +The PCI bus layer freely accesses the fields of struct device. It knows about +the structure of struct pci_dev, and it should know the structure of struct +device. Individual PCI device drivers that have been converted to the current +driver model generally do not and should not touch the fields of struct device, +unless there is a compelling reason to do so. + +The above abstraction prevents unnecessary pain during transitional phases. +If it were not done this way, then when a field was renamed or removed, every +downstream driver would break. On the other hand, if only the bus layer +(and not the device layer) accesses the struct device, it is only the bus +layer that needs to change. + + +User Interface +~~~~~~~~~~~~~~ + +By virtue of having a complete hierarchical view of all the devices in the +system, exporting a complete hierarchical view to userspace becomes relatively +easy. This has been accomplished by implementing a special purpose virtual +file system named sysfs. + +Almost all mainstream Linux distros mount this filesystem automatically; you +can see some variation of the following in the output of the "mount" command:: + + $ mount + ... + none on /sys type sysfs (rw,noexec,nosuid,nodev) + ... + $ + +The auto-mounting of sysfs is typically accomplished by an entry similar to +the following in the /etc/fstab file:: + + none /sys sysfs defaults 0 0 + +or something similar in the /lib/init/fstab file on Debian-based systems:: + + none /sys sysfs nodev,noexec,nosuid 0 0 + +If sysfs is not automatically mounted, you can always do it manually with:: + + # mount -t sysfs sysfs /sys + +Whenever a device is inserted into the tree, a directory is created for it. +This directory may be populated at each layer of discovery - the global layer, +the bus layer, or the device layer. + +The global layer currently creates two files - 'name' and 'power'. The +former only reports the name of the device. The latter reports the +current power state of the device. It will also be used to set the current +power state. + +The bus layer may also create files for the devices it finds while probing the +bus. For example, the PCI layer currently creates 'irq' and 'resource' files +for each PCI device. + +A device-specific driver may also export files in its directory to expose +device-specific data or tunable interfaces. + +More information about the sysfs directory layout can be found in +the other documents in this directory and in the file +Documentation/filesystems/sysfs.txt. diff --git a/Documentation/driver-model/overview.txt b/Documentation/driver-model/overview.txt deleted file mode 100644 index 6a8f9a8075d8..000000000000 --- a/Documentation/driver-model/overview.txt +++ /dev/null @@ -1,123 +0,0 @@ -The Linux Kernel Device Model - -Patrick Mochel - -Drafted 26 August 2002 -Updated 31 January 2006 - - -Overview -~~~~~~~~ - -The Linux Kernel Driver Model is a unification of all the disparate driver -models that were previously used in the kernel. It is intended to augment the -bus-specific drivers for bridges and devices by consolidating a set of data -and operations into globally accessible data structures. - -Traditional driver models implemented some sort of tree-like structure -(sometimes just a list) for the devices they control. There wasn't any -uniformity across the different bus types. - -The current driver model provides a common, uniform data model for describing -a bus and the devices that can appear under the bus. The unified bus -model includes a set of common attributes which all busses carry, and a set -of common callbacks, such as device discovery during bus probing, bus -shutdown, bus power management, etc. - -The common device and bridge interface reflects the goals of the modern -computer: namely the ability to do seamless device "plug and play", power -management, and hot plug. In particular, the model dictated by Intel and -Microsoft (namely ACPI) ensures that almost every device on almost any bus -on an x86-compatible system can work within this paradigm. Of course, -not every bus is able to support all such operations, although most -buses support most of those operations. - - -Downstream Access -~~~~~~~~~~~~~~~~~ - -Common data fields have been moved out of individual bus layers into a common -data structure. These fields must still be accessed by the bus layers, -and sometimes by the device-specific drivers. - -Other bus layers are encouraged to do what has been done for the PCI layer. -struct pci_dev now looks like this: - -struct pci_dev { - ... - - struct device dev; /* Generic device interface */ - ... -}; - -Note first that the struct device dev within the struct pci_dev is -statically allocated. This means only one allocation on device discovery. - -Note also that that struct device dev is not necessarily defined at the -front of the pci_dev structure. This is to make people think about what -they're doing when switching between the bus driver and the global driver, -and to discourage meaningless and incorrect casts between the two. - -The PCI bus layer freely accesses the fields of struct device. It knows about -the structure of struct pci_dev, and it should know the structure of struct -device. Individual PCI device drivers that have been converted to the current -driver model generally do not and should not touch the fields of struct device, -unless there is a compelling reason to do so. - -The above abstraction prevents unnecessary pain during transitional phases. -If it were not done this way, then when a field was renamed or removed, every -downstream driver would break. On the other hand, if only the bus layer -(and not the device layer) accesses the struct device, it is only the bus -layer that needs to change. - - -User Interface -~~~~~~~~~~~~~~ - -By virtue of having a complete hierarchical view of all the devices in the -system, exporting a complete hierarchical view to userspace becomes relatively -easy. This has been accomplished by implementing a special purpose virtual -file system named sysfs. - -Almost all mainstream Linux distros mount this filesystem automatically; you -can see some variation of the following in the output of the "mount" command: - -$ mount -... -none on /sys type sysfs (rw,noexec,nosuid,nodev) -... -$ - -The auto-mounting of sysfs is typically accomplished by an entry similar to -the following in the /etc/fstab file: - -none /sys sysfs defaults 0 0 - -or something similar in the /lib/init/fstab file on Debian-based systems: - -none /sys sysfs nodev,noexec,nosuid 0 0 - -If sysfs is not automatically mounted, you can always do it manually with: - -# mount -t sysfs sysfs /sys - -Whenever a device is inserted into the tree, a directory is created for it. -This directory may be populated at each layer of discovery - the global layer, -the bus layer, or the device layer. - -The global layer currently creates two files - 'name' and 'power'. The -former only reports the name of the device. The latter reports the -current power state of the device. It will also be used to set the current -power state. - -The bus layer may also create files for the devices it finds while probing the -bus. For example, the PCI layer currently creates 'irq' and 'resource' files -for each PCI device. - -A device-specific driver may also export files in its directory to expose -device-specific data or tunable interfaces. - -More information about the sysfs directory layout can be found in -the other documents in this directory and in the file -Documentation/filesystems/sysfs.txt. - diff --git a/Documentation/driver-model/platform.rst b/Documentation/driver-model/platform.rst new file mode 100644 index 000000000000..334dd4071ae4 --- /dev/null +++ b/Documentation/driver-model/platform.rst @@ -0,0 +1,246 @@ +============================ +Platform Devices and Drivers +============================ + +See for the driver model interface to the +platform bus: platform_device, and platform_driver. This pseudo-bus +is used to connect devices on busses with minimal infrastructure, +like those used to integrate peripherals on many system-on-chip +processors, or some "legacy" PC interconnects; as opposed to large +formally specified ones like PCI or USB. + + +Platform devices +~~~~~~~~~~~~~~~~ +Platform devices are devices that typically appear as autonomous +entities in the system. This includes legacy port-based devices and +host bridges to peripheral buses, and most controllers integrated +into system-on-chip platforms. What they usually have in common +is direct addressing from a CPU bus. Rarely, a platform_device will +be connected through a segment of some other kind of bus; but its +registers will still be directly addressable. + +Platform devices are given a name, used in driver binding, and a +list of resources such as addresses and IRQs:: + + struct platform_device { + const char *name; + u32 id; + struct device dev; + u32 num_resources; + struct resource *resource; + }; + + +Platform drivers +~~~~~~~~~~~~~~~~ +Platform drivers follow the standard driver model convention, where +discovery/enumeration is handled outside the drivers, and drivers +provide probe() and remove() methods. They support power management +and shutdown notifications using the standard conventions:: + + struct platform_driver { + int (*probe)(struct platform_device *); + int (*remove)(struct platform_device *); + void (*shutdown)(struct platform_device *); + int (*suspend)(struct platform_device *, pm_message_t state); + int (*suspend_late)(struct platform_device *, pm_message_t state); + int (*resume_early)(struct platform_device *); + int (*resume)(struct platform_device *); + struct device_driver driver; + }; + +Note that probe() should in general verify that the specified device hardware +actually exists; sometimes platform setup code can't be sure. The probing +can use device resources, including clocks, and device platform_data. + +Platform drivers register themselves the normal way:: + + int platform_driver_register(struct platform_driver *drv); + +Or, in common situations where the device is known not to be hot-pluggable, +the probe() routine can live in an init section to reduce the driver's +runtime memory footprint:: + + int platform_driver_probe(struct platform_driver *drv, + int (*probe)(struct platform_device *)) + +Kernel modules can be composed of several platform drivers. The platform core +provides helpers to register and unregister an array of drivers:: + + int __platform_register_drivers(struct platform_driver * const *drivers, + unsigned int count, struct module *owner); + void platform_unregister_drivers(struct platform_driver * const *drivers, + unsigned int count); + +If one of the drivers fails to register, all drivers registered up to that +point will be unregistered in reverse order. Note that there is a convenience +macro that passes THIS_MODULE as owner parameter:: + + #define platform_register_drivers(drivers, count) + + +Device Enumeration +~~~~~~~~~~~~~~~~~~ +As a rule, platform specific (and often board-specific) setup code will +register platform devices:: + + int platform_device_register(struct platform_device *pdev); + + int platform_add_devices(struct platform_device **pdevs, int ndev); + +The general rule is to register only those devices that actually exist, +but in some cases extra devices might be registered. For example, a kernel +might be configured to work with an external network adapter that might not +be populated on all boards, or likewise to work with an integrated controller +that some boards might not hook up to any peripherals. + +In some cases, boot firmware will export tables describing the devices +that are populated on a given board. Without such tables, often the +only way for system setup code to set up the correct devices is to build +a kernel for a specific target board. Such board-specific kernels are +common with embedded and custom systems development. + +In many cases, the memory and IRQ resources associated with the platform +device are not enough to let the device's driver work. Board setup code +will often provide additional information using the device's platform_data +field to hold additional information. + +Embedded systems frequently need one or more clocks for platform devices, +which are normally kept off until they're actively needed (to save power). +System setup also associates those clocks with the device, so that that +calls to clk_get(&pdev->dev, clock_name) return them as needed. + + +Legacy Drivers: Device Probing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Some drivers are not fully converted to the driver model, because they take +on a non-driver role: the driver registers its platform device, rather than +leaving that for system infrastructure. Such drivers can't be hotplugged +or coldplugged, since those mechanisms require device creation to be in a +different system component than the driver. + +The only "good" reason for this is to handle older system designs which, like +original IBM PCs, rely on error-prone "probe-the-hardware" models for hardware +configuration. Newer systems have largely abandoned that model, in favor of +bus-level support for dynamic configuration (PCI, USB), or device tables +provided by the boot firmware (e.g. PNPACPI on x86). There are too many +conflicting options about what might be where, and even educated guesses by +an operating system will be wrong often enough to make trouble. + +This style of driver is discouraged. If you're updating such a driver, +please try to move the device enumeration to a more appropriate location, +outside the driver. This will usually be cleanup, since such drivers +tend to already have "normal" modes, such as ones using device nodes that +were created by PNP or by platform device setup. + +None the less, there are some APIs to support such legacy drivers. Avoid +using these calls except with such hotplug-deficient drivers:: + + struct platform_device *platform_device_alloc( + const char *name, int id); + +You can use platform_device_alloc() to dynamically allocate a device, which +you will then initialize with resources and platform_device_register(). +A better solution is usually:: + + struct platform_device *platform_device_register_simple( + const char *name, int id, + struct resource *res, unsigned int nres); + +You can use platform_device_register_simple() as a one-step call to allocate +and register a device. + + +Device Naming and Driver Binding +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The platform_device.dev.bus_id is the canonical name for the devices. +It's built from two components: + + * platform_device.name ... which is also used to for driver matching. + + * platform_device.id ... the device instance number, or else "-1" + to indicate there's only one. + +These are concatenated, so name/id "serial"/0 indicates bus_id "serial.0", and +"serial/3" indicates bus_id "serial.3"; both would use the platform_driver +named "serial". While "my_rtc"/-1 would be bus_id "my_rtc" (no instance id) +and use the platform_driver called "my_rtc". + +Driver binding is performed automatically by the driver core, invoking +driver probe() after finding a match between device and driver. If the +probe() succeeds, the driver and device are bound as usual. There are +three different ways to find such a match: + + - Whenever a device is registered, the drivers for that bus are + checked for matches. Platform devices should be registered very + early during system boot. + + - When a driver is registered using platform_driver_register(), all + unbound devices on that bus are checked for matches. Drivers + usually register later during booting, or by module loading. + + - Registering a driver using platform_driver_probe() works just like + using platform_driver_register(), except that the driver won't + be probed later if another device registers. (Which is OK, since + this interface is only for use with non-hotpluggable devices.) + + +Early Platform Devices and Drivers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The early platform interfaces provide platform data to platform device +drivers early on during the system boot. The code is built on top of the +early_param() command line parsing and can be executed very early on. + +Example: "earlyprintk" class early serial console in 6 steps + +1. Registering early platform device data +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The architecture code registers platform device data using the function +early_platform_add_devices(). In the case of early serial console this +should be hardware configuration for the serial port. Devices registered +at this point will later on be matched against early platform drivers. + +2. Parsing kernel command line +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The architecture code calls parse_early_param() to parse the kernel +command line. This will execute all matching early_param() callbacks. +User specified early platform devices will be registered at this point. +For the early serial console case the user can specify port on the +kernel command line as "earlyprintk=serial.0" where "earlyprintk" is +the class string, "serial" is the name of the platform driver and +0 is the platform device id. If the id is -1 then the dot and the +id can be omitted. + +3. Installing early platform drivers belonging to a certain class +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The architecture code may optionally force registration of all early +platform drivers belonging to a certain class using the function +early_platform_driver_register_all(). User specified devices from +step 2 have priority over these. This step is omitted by the serial +driver example since the early serial driver code should be disabled +unless the user has specified port on the kernel command line. + +4. Early platform driver registration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Compiled-in platform drivers making use of early_platform_init() are +automatically registered during step 2 or 3. The serial driver example +should use early_platform_init("earlyprintk", &platform_driver). + +5. Probing of early platform drivers belonging to a certain class +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The architecture code calls early_platform_driver_probe() to match +registered early platform devices associated with a certain class with +registered early platform drivers. Matched devices will get probed(). +This step can be executed at any point during the early boot. As soon +as possible may be good for the serial port case. + +6. Inside the early platform driver probe() +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The driver code needs to take special care during early boot, especially +when it comes to memory allocation and interrupt registration. The code +in the probe() function can use is_early_platform_device() to check if +it is called at early platform device or at the regular platform device +time. The early serial driver performs register_console() at this point. + +For further information, see . diff --git a/Documentation/driver-model/platform.txt b/Documentation/driver-model/platform.txt deleted file mode 100644 index 9d9e47dfc013..000000000000 --- a/Documentation/driver-model/platform.txt +++ /dev/null @@ -1,244 +0,0 @@ -Platform Devices and Drivers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -See for the driver model interface to the -platform bus: platform_device, and platform_driver. This pseudo-bus -is used to connect devices on busses with minimal infrastructure, -like those used to integrate peripherals on many system-on-chip -processors, or some "legacy" PC interconnects; as opposed to large -formally specified ones like PCI or USB. - - -Platform devices -~~~~~~~~~~~~~~~~ -Platform devices are devices that typically appear as autonomous -entities in the system. This includes legacy port-based devices and -host bridges to peripheral buses, and most controllers integrated -into system-on-chip platforms. What they usually have in common -is direct addressing from a CPU bus. Rarely, a platform_device will -be connected through a segment of some other kind of bus; but its -registers will still be directly addressable. - -Platform devices are given a name, used in driver binding, and a -list of resources such as addresses and IRQs. - -struct platform_device { - const char *name; - u32 id; - struct device dev; - u32 num_resources; - struct resource *resource; -}; - - -Platform drivers -~~~~~~~~~~~~~~~~ -Platform drivers follow the standard driver model convention, where -discovery/enumeration is handled outside the drivers, and drivers -provide probe() and remove() methods. They support power management -and shutdown notifications using the standard conventions. - -struct platform_driver { - int (*probe)(struct platform_device *); - int (*remove)(struct platform_device *); - void (*shutdown)(struct platform_device *); - int (*suspend)(struct platform_device *, pm_message_t state); - int (*suspend_late)(struct platform_device *, pm_message_t state); - int (*resume_early)(struct platform_device *); - int (*resume)(struct platform_device *); - struct device_driver driver; -}; - -Note that probe() should in general verify that the specified device hardware -actually exists; sometimes platform setup code can't be sure. The probing -can use device resources, including clocks, and device platform_data. - -Platform drivers register themselves the normal way: - - int platform_driver_register(struct platform_driver *drv); - -Or, in common situations where the device is known not to be hot-pluggable, -the probe() routine can live in an init section to reduce the driver's -runtime memory footprint: - - int platform_driver_probe(struct platform_driver *drv, - int (*probe)(struct platform_device *)) - -Kernel modules can be composed of several platform drivers. The platform core -provides helpers to register and unregister an array of drivers: - - int __platform_register_drivers(struct platform_driver * const *drivers, - unsigned int count, struct module *owner); - void platform_unregister_drivers(struct platform_driver * const *drivers, - unsigned int count); - -If one of the drivers fails to register, all drivers registered up to that -point will be unregistered in reverse order. Note that there is a convenience -macro that passes THIS_MODULE as owner parameter: - - #define platform_register_drivers(drivers, count) - - -Device Enumeration -~~~~~~~~~~~~~~~~~~ -As a rule, platform specific (and often board-specific) setup code will -register platform devices: - - int platform_device_register(struct platform_device *pdev); - - int platform_add_devices(struct platform_device **pdevs, int ndev); - -The general rule is to register only those devices that actually exist, -but in some cases extra devices might be registered. For example, a kernel -might be configured to work with an external network adapter that might not -be populated on all boards, or likewise to work with an integrated controller -that some boards might not hook up to any peripherals. - -In some cases, boot firmware will export tables describing the devices -that are populated on a given board. Without such tables, often the -only way for system setup code to set up the correct devices is to build -a kernel for a specific target board. Such board-specific kernels are -common with embedded and custom systems development. - -In many cases, the memory and IRQ resources associated with the platform -device are not enough to let the device's driver work. Board setup code -will often provide additional information using the device's platform_data -field to hold additional information. - -Embedded systems frequently need one or more clocks for platform devices, -which are normally kept off until they're actively needed (to save power). -System setup also associates those clocks with the device, so that that -calls to clk_get(&pdev->dev, clock_name) return them as needed. - - -Legacy Drivers: Device Probing -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Some drivers are not fully converted to the driver model, because they take -on a non-driver role: the driver registers its platform device, rather than -leaving that for system infrastructure. Such drivers can't be hotplugged -or coldplugged, since those mechanisms require device creation to be in a -different system component than the driver. - -The only "good" reason for this is to handle older system designs which, like -original IBM PCs, rely on error-prone "probe-the-hardware" models for hardware -configuration. Newer systems have largely abandoned that model, in favor of -bus-level support for dynamic configuration (PCI, USB), or device tables -provided by the boot firmware (e.g. PNPACPI on x86). There are too many -conflicting options about what might be where, and even educated guesses by -an operating system will be wrong often enough to make trouble. - -This style of driver is discouraged. If you're updating such a driver, -please try to move the device enumeration to a more appropriate location, -outside the driver. This will usually be cleanup, since such drivers -tend to already have "normal" modes, such as ones using device nodes that -were created by PNP or by platform device setup. - -None the less, there are some APIs to support such legacy drivers. Avoid -using these calls except with such hotplug-deficient drivers. - - struct platform_device *platform_device_alloc( - const char *name, int id); - -You can use platform_device_alloc() to dynamically allocate a device, which -you will then initialize with resources and platform_device_register(). -A better solution is usually: - - struct platform_device *platform_device_register_simple( - const char *name, int id, - struct resource *res, unsigned int nres); - -You can use platform_device_register_simple() as a one-step call to allocate -and register a device. - - -Device Naming and Driver Binding -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The platform_device.dev.bus_id is the canonical name for the devices. -It's built from two components: - - * platform_device.name ... which is also used to for driver matching. - - * platform_device.id ... the device instance number, or else "-1" - to indicate there's only one. - -These are concatenated, so name/id "serial"/0 indicates bus_id "serial.0", and -"serial/3" indicates bus_id "serial.3"; both would use the platform_driver -named "serial". While "my_rtc"/-1 would be bus_id "my_rtc" (no instance id) -and use the platform_driver called "my_rtc". - -Driver binding is performed automatically by the driver core, invoking -driver probe() after finding a match between device and driver. If the -probe() succeeds, the driver and device are bound as usual. There are -three different ways to find such a match: - - - Whenever a device is registered, the drivers for that bus are - checked for matches. Platform devices should be registered very - early during system boot. - - - When a driver is registered using platform_driver_register(), all - unbound devices on that bus are checked for matches. Drivers - usually register later during booting, or by module loading. - - - Registering a driver using platform_driver_probe() works just like - using platform_driver_register(), except that the driver won't - be probed later if another device registers. (Which is OK, since - this interface is only for use with non-hotpluggable devices.) - - -Early Platform Devices and Drivers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The early platform interfaces provide platform data to platform device -drivers early on during the system boot. The code is built on top of the -early_param() command line parsing and can be executed very early on. - -Example: "earlyprintk" class early serial console in 6 steps - -1. Registering early platform device data -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The architecture code registers platform device data using the function -early_platform_add_devices(). In the case of early serial console this -should be hardware configuration for the serial port. Devices registered -at this point will later on be matched against early platform drivers. - -2. Parsing kernel command line -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The architecture code calls parse_early_param() to parse the kernel -command line. This will execute all matching early_param() callbacks. -User specified early platform devices will be registered at this point. -For the early serial console case the user can specify port on the -kernel command line as "earlyprintk=serial.0" where "earlyprintk" is -the class string, "serial" is the name of the platform driver and -0 is the platform device id. If the id is -1 then the dot and the -id can be omitted. - -3. Installing early platform drivers belonging to a certain class -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The architecture code may optionally force registration of all early -platform drivers belonging to a certain class using the function -early_platform_driver_register_all(). User specified devices from -step 2 have priority over these. This step is omitted by the serial -driver example since the early serial driver code should be disabled -unless the user has specified port on the kernel command line. - -4. Early platform driver registration -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Compiled-in platform drivers making use of early_platform_init() are -automatically registered during step 2 or 3. The serial driver example -should use early_platform_init("earlyprintk", &platform_driver). - -5. Probing of early platform drivers belonging to a certain class -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The architecture code calls early_platform_driver_probe() to match -registered early platform devices associated with a certain class with -registered early platform drivers. Matched devices will get probed(). -This step can be executed at any point during the early boot. As soon -as possible may be good for the serial port case. - -6. Inside the early platform driver probe() -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The driver code needs to take special care during early boot, especially -when it comes to memory allocation and interrupt registration. The code -in the probe() function can use is_early_platform_device() to check if -it is called at early platform device or at the regular platform device -time. The early serial driver performs register_console() at this point. - -For further information, see . diff --git a/Documentation/driver-model/porting.rst b/Documentation/driver-model/porting.rst new file mode 100644 index 000000000000..ae4bf843c1d6 --- /dev/null +++ b/Documentation/driver-model/porting.rst @@ -0,0 +1,448 @@ +======================================= +Porting Drivers to the New Driver Model +======================================= + +Patrick Mochel + +7 January 2003 + + +Overview + +Please refer to `Documentation/driver-model/*.rst` for definitions of +various driver types and concepts. + +Most of the work of porting devices drivers to the new model happens +at the bus driver layer. This was intentional, to minimize the +negative effect on kernel drivers, and to allow a gradual transition +of bus drivers. + +In a nutshell, the driver model consists of a set of objects that can +be embedded in larger, bus-specific objects. Fields in these generic +objects can replace fields in the bus-specific objects. + +The generic objects must be registered with the driver model core. By +doing so, they will exported via the sysfs filesystem. sysfs can be +mounted by doing:: + + # mount -t sysfs sysfs /sys + + + +The Process + +Step 0: Read include/linux/device.h for object and function definitions. + +Step 1: Registering the bus driver. + + +- Define a struct bus_type for the bus driver:: + + struct bus_type pci_bus_type = { + .name = "pci", + }; + + +- Register the bus type. + + This should be done in the initialization function for the bus type, + which is usually the module_init(), or equivalent, function:: + + static int __init pci_driver_init(void) + { + return bus_register(&pci_bus_type); + } + + subsys_initcall(pci_driver_init); + + + The bus type may be unregistered (if the bus driver may be compiled + as a module) by doing:: + + bus_unregister(&pci_bus_type); + + +- Export the bus type for others to use. + + Other code may wish to reference the bus type, so declare it in a + shared header file and export the symbol. + +From include/linux/pci.h:: + + extern struct bus_type pci_bus_type; + + +From file the above code appears in:: + + EXPORT_SYMBOL(pci_bus_type); + + + +- This will cause the bus to show up in /sys/bus/pci/ with two + subdirectories: 'devices' and 'drivers':: + + # tree -d /sys/bus/pci/ + /sys/bus/pci/ + |-- devices + `-- drivers + + + +Step 2: Registering Devices. + +struct device represents a single device. It mainly contains metadata +describing the relationship the device has to other entities. + + +- Embed a struct device in the bus-specific device type:: + + + struct pci_dev { + ... + struct device dev; /* Generic device interface */ + ... + }; + + It is recommended that the generic device not be the first item in + the struct to discourage programmers from doing mindless casts + between the object types. Instead macros, or inline functions, + should be created to convert from the generic object type:: + + + #define to_pci_dev(n) container_of(n, struct pci_dev, dev) + + or + + static inline struct pci_dev * to_pci_dev(struct kobject * kobj) + { + return container_of(n, struct pci_dev, dev); + } + + This allows the compiler to verify type-safety of the operations + that are performed (which is Good). + + +- Initialize the device on registration. + + When devices are discovered or registered with the bus type, the + bus driver should initialize the generic device. The most important + things to initialize are the bus_id, parent, and bus fields. + + The bus_id is an ASCII string that contains the device's address on + the bus. The format of this string is bus-specific. This is + necessary for representing devices in sysfs. + + parent is the physical parent of the device. It is important that + the bus driver sets this field correctly. + + The driver model maintains an ordered list of devices that it uses + for power management. This list must be in order to guarantee that + devices are shutdown before their physical parents, and vice versa. + The order of this list is determined by the parent of registered + devices. + + Also, the location of the device's sysfs directory depends on a + device's parent. sysfs exports a directory structure that mirrors + the device hierarchy. Accurately setting the parent guarantees that + sysfs will accurately represent the hierarchy. + + The device's bus field is a pointer to the bus type the device + belongs to. This should be set to the bus_type that was declared + and initialized before. + + Optionally, the bus driver may set the device's name and release + fields. + + The name field is an ASCII string describing the device, like + + "ATI Technologies Inc Radeon QD" + + The release field is a callback that the driver model core calls + when the device has been removed, and all references to it have + been released. More on this in a moment. + + +- Register the device. + + Once the generic device has been initialized, it can be registered + with the driver model core by doing:: + + device_register(&dev->dev); + + It can later be unregistered by doing:: + + device_unregister(&dev->dev); + + This should happen on buses that support hotpluggable devices. + If a bus driver unregisters a device, it should not immediately free + it. It should instead wait for the driver model core to call the + device's release method, then free the bus-specific object. + (There may be other code that is currently referencing the device + structure, and it would be rude to free the device while that is + happening). + + + When the device is registered, a directory in sysfs is created. + The PCI tree in sysfs looks like:: + + /sys/devices/pci0/ + |-- 00:00.0 + |-- 00:01.0 + | `-- 01:00.0 + |-- 00:02.0 + | `-- 02:1f.0 + | `-- 03:00.0 + |-- 00:1e.0 + | `-- 04:04.0 + |-- 00:1f.0 + |-- 00:1f.1 + | |-- ide0 + | | |-- 0.0 + | | `-- 0.1 + | `-- ide1 + | `-- 1.0 + |-- 00:1f.2 + |-- 00:1f.3 + `-- 00:1f.5 + + Also, symlinks are created in the bus's 'devices' directory + that point to the device's directory in the physical hierarchy:: + + /sys/bus/pci/devices/ + |-- 00:00.0 -> ../../../devices/pci0/00:00.0 + |-- 00:01.0 -> ../../../devices/pci0/00:01.0 + |-- 00:02.0 -> ../../../devices/pci0/00:02.0 + |-- 00:1e.0 -> ../../../devices/pci0/00:1e.0 + |-- 00:1f.0 -> ../../../devices/pci0/00:1f.0 + |-- 00:1f.1 -> ../../../devices/pci0/00:1f.1 + |-- 00:1f.2 -> ../../../devices/pci0/00:1f.2 + |-- 00:1f.3 -> ../../../devices/pci0/00:1f.3 + |-- 00:1f.5 -> ../../../devices/pci0/00:1f.5 + |-- 01:00.0 -> ../../../devices/pci0/00:01.0/01:00.0 + |-- 02:1f.0 -> ../../../devices/pci0/00:02.0/02:1f.0 + |-- 03:00.0 -> ../../../devices/pci0/00:02.0/02:1f.0/03:00.0 + `-- 04:04.0 -> ../../../devices/pci0/00:1e.0/04:04.0 + + + +Step 3: Registering Drivers. + +struct device_driver is a simple driver structure that contains a set +of operations that the driver model core may call. + + +- Embed a struct device_driver in the bus-specific driver. + + Just like with devices, do something like:: + + struct pci_driver { + ... + struct device_driver driver; + }; + + +- Initialize the generic driver structure. + + When the driver registers with the bus (e.g. doing pci_register_driver()), + initialize the necessary fields of the driver: the name and bus + fields. + + +- Register the driver. + + After the generic driver has been initialized, call:: + + driver_register(&drv->driver); + + to register the driver with the core. + + When the driver is unregistered from the bus, unregister it from the + core by doing:: + + driver_unregister(&drv->driver); + + Note that this will block until all references to the driver have + gone away. Normally, there will not be any. + + +- Sysfs representation. + + Drivers are exported via sysfs in their bus's 'driver's directory. + For example:: + + /sys/bus/pci/drivers/ + |-- 3c59x + |-- Ensoniq AudioPCI + |-- agpgart-amdk7 + |-- e100 + `-- serial + + +Step 4: Define Generic Methods for Drivers. + +struct device_driver defines a set of operations that the driver model +core calls. Most of these operations are probably similar to +operations the bus already defines for drivers, but taking different +parameters. + +It would be difficult and tedious to force every driver on a bus to +simultaneously convert their drivers to generic format. Instead, the +bus driver should define single instances of the generic methods that +forward call to the bus-specific drivers. For instance:: + + + static int pci_device_remove(struct device * dev) + { + struct pci_dev * pci_dev = to_pci_dev(dev); + struct pci_driver * drv = pci_dev->driver; + + if (drv) { + if (drv->remove) + drv->remove(pci_dev); + pci_dev->driver = NULL; + } + return 0; + } + + +The generic driver should be initialized with these methods before it +is registered:: + + /* initialize common driver fields */ + drv->driver.name = drv->name; + drv->driver.bus = &pci_bus_type; + drv->driver.probe = pci_device_probe; + drv->driver.resume = pci_device_resume; + drv->driver.suspend = pci_device_suspend; + drv->driver.remove = pci_device_remove; + + /* register with core */ + driver_register(&drv->driver); + + +Ideally, the bus should only initialize the fields if they are not +already set. This allows the drivers to implement their own generic +methods. + + +Step 5: Support generic driver binding. + +The model assumes that a device or driver can be dynamically +registered with the bus at any time. When registration happens, +devices must be bound to a driver, or drivers must be bound to all +devices that it supports. + +A driver typically contains a list of device IDs that it supports. The +bus driver compares these IDs to the IDs of devices registered with it. +The format of the device IDs, and the semantics for comparing them are +bus-specific, so the generic model does attempt to generalize them. + +Instead, a bus may supply a method in struct bus_type that does the +comparison:: + + int (*match)(struct device * dev, struct device_driver * drv); + +match should return positive value if the driver supports the device, +and zero otherwise. It may also return error code (for example +-EPROBE_DEFER) if determining that given driver supports the device is +not possible. + +When a device is registered, the bus's list of drivers is iterated +over. bus->match() is called for each one until a match is found. + +When a driver is registered, the bus's list of devices is iterated +over. bus->match() is called for each device that is not already +claimed by a driver. + +When a device is successfully bound to a driver, device->driver is +set, the device is added to a per-driver list of devices, and a +symlink is created in the driver's sysfs directory that points to the +device's physical directory:: + + /sys/bus/pci/drivers/ + |-- 3c59x + | `-- 00:0b.0 -> ../../../../devices/pci0/00:0b.0 + |-- Ensoniq AudioPCI + |-- agpgart-amdk7 + | `-- 00:00.0 -> ../../../../devices/pci0/00:00.0 + |-- e100 + | `-- 00:0c.0 -> ../../../../devices/pci0/00:0c.0 + `-- serial + + +This driver binding should replace the existing driver binding +mechanism the bus currently uses. + + +Step 6: Supply a hotplug callback. + +Whenever a device is registered with the driver model core, the +userspace program /sbin/hotplug is called to notify userspace. +Users can define actions to perform when a device is inserted or +removed. + +The driver model core passes several arguments to userspace via +environment variables, including + +- ACTION: set to 'add' or 'remove' +- DEVPATH: set to the device's physical path in sysfs. + +A bus driver may also supply additional parameters for userspace to +consume. To do this, a bus must implement the 'hotplug' method in +struct bus_type:: + + int (*hotplug) (struct device *dev, char **envp, + int num_envp, char *buffer, int buffer_size); + +This is called immediately before /sbin/hotplug is executed. + + +Step 7: Cleaning up the bus driver. + +The generic bus, device, and driver structures provide several fields +that can replace those defined privately to the bus driver. + +- Device list. + +struct bus_type contains a list of all devices registered with the bus +type. This includes all devices on all instances of that bus type. +An internal list that the bus uses may be removed, in favor of using +this one. + +The core provides an iterator to access these devices:: + + int bus_for_each_dev(struct bus_type * bus, struct device * start, + void * data, int (*fn)(struct device *, void *)); + + +- Driver list. + +struct bus_type also contains a list of all drivers registered with +it. An internal list of drivers that the bus driver maintains may +be removed in favor of using the generic one. + +The drivers may be iterated over, like devices:: + + int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, + void * data, int (*fn)(struct device_driver *, void *)); + + +Please see drivers/base/bus.c for more information. + + +- rwsem + +struct bus_type contains an rwsem that protects all core accesses to +the device and driver lists. This can be used by the bus driver +internally, and should be used when accessing the device or driver +lists the bus maintains. + + +- Device and driver fields. + +Some of the fields in struct device and struct device_driver duplicate +fields in the bus-specific representations of these objects. Feel free +to remove the bus-specific ones and favor the generic ones. Note +though, that this will likely mean fixing up all the drivers that +reference the bus-specific fields (though those should all be 1-line +changes). diff --git a/Documentation/driver-model/porting.txt b/Documentation/driver-model/porting.txt deleted file mode 100644 index 453053f1661f..000000000000 --- a/Documentation/driver-model/porting.txt +++ /dev/null @@ -1,447 +0,0 @@ - -Porting Drivers to the New Driver Model - -Patrick Mochel - -7 January 2003 - - -Overview - -Please refer to Documentation/driver-model/*.txt for definitions of -various driver types and concepts. - -Most of the work of porting devices drivers to the new model happens -at the bus driver layer. This was intentional, to minimize the -negative effect on kernel drivers, and to allow a gradual transition -of bus drivers. - -In a nutshell, the driver model consists of a set of objects that can -be embedded in larger, bus-specific objects. Fields in these generic -objects can replace fields in the bus-specific objects. - -The generic objects must be registered with the driver model core. By -doing so, they will exported via the sysfs filesystem. sysfs can be -mounted by doing - - # mount -t sysfs sysfs /sys - - - -The Process - -Step 0: Read include/linux/device.h for object and function definitions. - -Step 1: Registering the bus driver. - - -- Define a struct bus_type for the bus driver. - -struct bus_type pci_bus_type = { - .name = "pci", -}; - - -- Register the bus type. - This should be done in the initialization function for the bus type, - which is usually the module_init(), or equivalent, function. - -static int __init pci_driver_init(void) -{ - return bus_register(&pci_bus_type); -} - -subsys_initcall(pci_driver_init); - - - The bus type may be unregistered (if the bus driver may be compiled - as a module) by doing: - - bus_unregister(&pci_bus_type); - - -- Export the bus type for others to use. - - Other code may wish to reference the bus type, so declare it in a - shared header file and export the symbol. - -From include/linux/pci.h: - -extern struct bus_type pci_bus_type; - - -From file the above code appears in: - -EXPORT_SYMBOL(pci_bus_type); - - - -- This will cause the bus to show up in /sys/bus/pci/ with two - subdirectories: 'devices' and 'drivers'. - -# tree -d /sys/bus/pci/ -/sys/bus/pci/ -|-- devices -`-- drivers - - - -Step 2: Registering Devices. - -struct device represents a single device. It mainly contains metadata -describing the relationship the device has to other entities. - - -- Embed a struct device in the bus-specific device type. - - -struct pci_dev { - ... - struct device dev; /* Generic device interface */ - ... -}; - - It is recommended that the generic device not be the first item in - the struct to discourage programmers from doing mindless casts - between the object types. Instead macros, or inline functions, - should be created to convert from the generic object type. - - -#define to_pci_dev(n) container_of(n, struct pci_dev, dev) - -or - -static inline struct pci_dev * to_pci_dev(struct kobject * kobj) -{ - return container_of(n, struct pci_dev, dev); -} - - This allows the compiler to verify type-safety of the operations - that are performed (which is Good). - - -- Initialize the device on registration. - - When devices are discovered or registered with the bus type, the - bus driver should initialize the generic device. The most important - things to initialize are the bus_id, parent, and bus fields. - - The bus_id is an ASCII string that contains the device's address on - the bus. The format of this string is bus-specific. This is - necessary for representing devices in sysfs. - - parent is the physical parent of the device. It is important that - the bus driver sets this field correctly. - - The driver model maintains an ordered list of devices that it uses - for power management. This list must be in order to guarantee that - devices are shutdown before their physical parents, and vice versa. - The order of this list is determined by the parent of registered - devices. - - Also, the location of the device's sysfs directory depends on a - device's parent. sysfs exports a directory structure that mirrors - the device hierarchy. Accurately setting the parent guarantees that - sysfs will accurately represent the hierarchy. - - The device's bus field is a pointer to the bus type the device - belongs to. This should be set to the bus_type that was declared - and initialized before. - - Optionally, the bus driver may set the device's name and release - fields. - - The name field is an ASCII string describing the device, like - - "ATI Technologies Inc Radeon QD" - - The release field is a callback that the driver model core calls - when the device has been removed, and all references to it have - been released. More on this in a moment. - - -- Register the device. - - Once the generic device has been initialized, it can be registered - with the driver model core by doing: - - device_register(&dev->dev); - - It can later be unregistered by doing: - - device_unregister(&dev->dev); - - This should happen on buses that support hotpluggable devices. - If a bus driver unregisters a device, it should not immediately free - it. It should instead wait for the driver model core to call the - device's release method, then free the bus-specific object. - (There may be other code that is currently referencing the device - structure, and it would be rude to free the device while that is - happening). - - - When the device is registered, a directory in sysfs is created. - The PCI tree in sysfs looks like: - -/sys/devices/pci0/ -|-- 00:00.0 -|-- 00:01.0 -| `-- 01:00.0 -|-- 00:02.0 -| `-- 02:1f.0 -| `-- 03:00.0 -|-- 00:1e.0 -| `-- 04:04.0 -|-- 00:1f.0 -|-- 00:1f.1 -| |-- ide0 -| | |-- 0.0 -| | `-- 0.1 -| `-- ide1 -| `-- 1.0 -|-- 00:1f.2 -|-- 00:1f.3 -`-- 00:1f.5 - - Also, symlinks are created in the bus's 'devices' directory - that point to the device's directory in the physical hierarchy. - -/sys/bus/pci/devices/ -|-- 00:00.0 -> ../../../devices/pci0/00:00.0 -|-- 00:01.0 -> ../../../devices/pci0/00:01.0 -|-- 00:02.0 -> ../../../devices/pci0/00:02.0 -|-- 00:1e.0 -> ../../../devices/pci0/00:1e.0 -|-- 00:1f.0 -> ../../../devices/pci0/00:1f.0 -|-- 00:1f.1 -> ../../../devices/pci0/00:1f.1 -|-- 00:1f.2 -> ../../../devices/pci0/00:1f.2 -|-- 00:1f.3 -> ../../../devices/pci0/00:1f.3 -|-- 00:1f.5 -> ../../../devices/pci0/00:1f.5 -|-- 01:00.0 -> ../../../devices/pci0/00:01.0/01:00.0 -|-- 02:1f.0 -> ../../../devices/pci0/00:02.0/02:1f.0 -|-- 03:00.0 -> ../../../devices/pci0/00:02.0/02:1f.0/03:00.0 -`-- 04:04.0 -> ../../../devices/pci0/00:1e.0/04:04.0 - - - -Step 3: Registering Drivers. - -struct device_driver is a simple driver structure that contains a set -of operations that the driver model core may call. - - -- Embed a struct device_driver in the bus-specific driver. - - Just like with devices, do something like: - -struct pci_driver { - ... - struct device_driver driver; -}; - - -- Initialize the generic driver structure. - - When the driver registers with the bus (e.g. doing pci_register_driver()), - initialize the necessary fields of the driver: the name and bus - fields. - - -- Register the driver. - - After the generic driver has been initialized, call - - driver_register(&drv->driver); - - to register the driver with the core. - - When the driver is unregistered from the bus, unregister it from the - core by doing: - - driver_unregister(&drv->driver); - - Note that this will block until all references to the driver have - gone away. Normally, there will not be any. - - -- Sysfs representation. - - Drivers are exported via sysfs in their bus's 'driver's directory. - For example: - -/sys/bus/pci/drivers/ -|-- 3c59x -|-- Ensoniq AudioPCI -|-- agpgart-amdk7 -|-- e100 -`-- serial - - -Step 4: Define Generic Methods for Drivers. - -struct device_driver defines a set of operations that the driver model -core calls. Most of these operations are probably similar to -operations the bus already defines for drivers, but taking different -parameters. - -It would be difficult and tedious to force every driver on a bus to -simultaneously convert their drivers to generic format. Instead, the -bus driver should define single instances of the generic methods that -forward call to the bus-specific drivers. For instance: - - -static int pci_device_remove(struct device * dev) -{ - struct pci_dev * pci_dev = to_pci_dev(dev); - struct pci_driver * drv = pci_dev->driver; - - if (drv) { - if (drv->remove) - drv->remove(pci_dev); - pci_dev->driver = NULL; - } - return 0; -} - - -The generic driver should be initialized with these methods before it -is registered. - - /* initialize common driver fields */ - drv->driver.name = drv->name; - drv->driver.bus = &pci_bus_type; - drv->driver.probe = pci_device_probe; - drv->driver.resume = pci_device_resume; - drv->driver.suspend = pci_device_suspend; - drv->driver.remove = pci_device_remove; - - /* register with core */ - driver_register(&drv->driver); - - -Ideally, the bus should only initialize the fields if they are not -already set. This allows the drivers to implement their own generic -methods. - - -Step 5: Support generic driver binding. - -The model assumes that a device or driver can be dynamically -registered with the bus at any time. When registration happens, -devices must be bound to a driver, or drivers must be bound to all -devices that it supports. - -A driver typically contains a list of device IDs that it supports. The -bus driver compares these IDs to the IDs of devices registered with it. -The format of the device IDs, and the semantics for comparing them are -bus-specific, so the generic model does attempt to generalize them. - -Instead, a bus may supply a method in struct bus_type that does the -comparison: - - int (*match)(struct device * dev, struct device_driver * drv); - -match should return positive value if the driver supports the device, -and zero otherwise. It may also return error code (for example --EPROBE_DEFER) if determining that given driver supports the device is -not possible. - -When a device is registered, the bus's list of drivers is iterated -over. bus->match() is called for each one until a match is found. - -When a driver is registered, the bus's list of devices is iterated -over. bus->match() is called for each device that is not already -claimed by a driver. - -When a device is successfully bound to a driver, device->driver is -set, the device is added to a per-driver list of devices, and a -symlink is created in the driver's sysfs directory that points to the -device's physical directory: - -/sys/bus/pci/drivers/ -|-- 3c59x -| `-- 00:0b.0 -> ../../../../devices/pci0/00:0b.0 -|-- Ensoniq AudioPCI -|-- agpgart-amdk7 -| `-- 00:00.0 -> ../../../../devices/pci0/00:00.0 -|-- e100 -| `-- 00:0c.0 -> ../../../../devices/pci0/00:0c.0 -`-- serial - - -This driver binding should replace the existing driver binding -mechanism the bus currently uses. - - -Step 6: Supply a hotplug callback. - -Whenever a device is registered with the driver model core, the -userspace program /sbin/hotplug is called to notify userspace. -Users can define actions to perform when a device is inserted or -removed. - -The driver model core passes several arguments to userspace via -environment variables, including - -- ACTION: set to 'add' or 'remove' -- DEVPATH: set to the device's physical path in sysfs. - -A bus driver may also supply additional parameters for userspace to -consume. To do this, a bus must implement the 'hotplug' method in -struct bus_type: - - int (*hotplug) (struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); - -This is called immediately before /sbin/hotplug is executed. - - -Step 7: Cleaning up the bus driver. - -The generic bus, device, and driver structures provide several fields -that can replace those defined privately to the bus driver. - -- Device list. - -struct bus_type contains a list of all devices registered with the bus -type. This includes all devices on all instances of that bus type. -An internal list that the bus uses may be removed, in favor of using -this one. - -The core provides an iterator to access these devices. - -int bus_for_each_dev(struct bus_type * bus, struct device * start, - void * data, int (*fn)(struct device *, void *)); - - -- Driver list. - -struct bus_type also contains a list of all drivers registered with -it. An internal list of drivers that the bus driver maintains may -be removed in favor of using the generic one. - -The drivers may be iterated over, like devices: - -int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, - void * data, int (*fn)(struct device_driver *, void *)); - - -Please see drivers/base/bus.c for more information. - - -- rwsem - -struct bus_type contains an rwsem that protects all core accesses to -the device and driver lists. This can be used by the bus driver -internally, and should be used when accessing the device or driver -lists the bus maintains. - - -- Device and driver fields. - -Some of the fields in struct device and struct device_driver duplicate -fields in the bus-specific representations of these objects. Feel free -to remove the bus-specific ones and favor the generic ones. Note -though, that this will likely mean fixing up all the drivers that -reference the bus-specific fields (though those should all be 1-line -changes). - diff --git a/Documentation/eisa.txt b/Documentation/eisa.txt index 2806e5544e43..f388545a85a7 100644 --- a/Documentation/eisa.txt +++ b/Documentation/eisa.txt @@ -103,7 +103,7 @@ id_table an array of NULL terminated EISA id strings, (driver_data). driver a generic driver, such as described in - Documentation/driver-model/driver.txt. Only .name, + Documentation/driver-model/driver.rst. Only .name, .probe and .remove members are mandatory. =============== ==================================================== @@ -152,7 +152,7 @@ state set of flags indicating the state of the device. Current flags are EISA_CONFIG_ENABLED and EISA_CONFIG_FORCED. res set of four 256 bytes I/O regions allocated to this device dma_mask DMA mask set from the parent device. -dev generic device (see Documentation/driver-model/device.txt) +dev generic device (see Documentation/driver-model/device.rst) ======== ============================================================ You can get the 'struct eisa_device' from 'struct device' using the diff --git a/Documentation/hwmon/submitting-patches.rst b/Documentation/hwmon/submitting-patches.rst index f9796b9d9db6..d5b05d3e54ba 100644 --- a/Documentation/hwmon/submitting-patches.rst +++ b/Documentation/hwmon/submitting-patches.rst @@ -89,7 +89,7 @@ increase the chances of your change being accepted. console. Excessive logging can seriously affect system performance. * Use devres functions whenever possible to allocate resources. For rationale - and supported functions, please see Documentation/driver-model/devres.txt. + and supported functions, please see Documentation/driver-model/devres.rst. If a function is not supported by devres, consider using devm_add_action(). * If the driver has a detect function, make sure it is silent. Debug messages diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 4d1729853d1a..713903290385 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -5,7 +5,7 @@ * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs * - * Please see Documentation/driver-model/platform.txt for more + * Please see Documentation/driver-model/platform.rst for more * information. */ diff --git a/drivers/gpio/gpio-cs5535.c b/drivers/gpio/gpio-cs5535.c index 6314225dbed0..3611a0571667 100644 --- a/drivers/gpio/gpio-cs5535.c +++ b/drivers/gpio/gpio-cs5535.c @@ -41,7 +41,7 @@ MODULE_PARM_DESC(mask, "GPIO channel mask."); /* * FIXME: convert this singleton driver to use the state container - * design pattern, see Documentation/driver-model/design-patterns.txt + * design pattern, see Documentation/driver-model/design-patterns.rst */ static struct cs5535_gpio_chip { struct gpio_chip chip; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 7843abf4d44d..98a62072d81e 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2237,7 +2237,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) struct ice_hw *hw; int err; - /* this driver uses devres, see Documentation/driver-model/devres.txt */ + /* this driver uses devres, see Documentation/driver-model/devres.rst */ err = pcim_enable_device(pdev); if (err) return err; diff --git a/scripts/coccinelle/free/devm_free.cocci b/scripts/coccinelle/free/devm_free.cocci index b2a2cf8bf81f..e32236a979a8 100644 --- a/scripts/coccinelle/free/devm_free.cocci +++ b/scripts/coccinelle/free/devm_free.cocci @@ -2,7 +2,7 @@ /// functions. Values allocated using the devm_functions are freed when /// the device is detached, and thus the use of the standard freeing /// function would cause a double free. -/// See Documentation/driver-model/devres.txt for more information. +/// See Documentation/driver-model/devres.rst for more information. /// /// A difficulty of detecting this problem is that the standard freeing /// function might be called from a different function than the one -- cgit v1.2.3-59-g8ed1b From 65bbdd49b4722a09901469e57497850311c017dc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 14 Jun 2019 10:43:11 +0100 Subject: lkdtm: remove redundant initialization of ret The variable ret is being initialized with the value -EINVAL however this value is never read and ret is being re-assigned later on. Hence the initialization is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Acked-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index bae3b3763f3e..d416359daf06 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -387,7 +387,7 @@ static int __init lkdtm_module_init(void) { struct crashpoint *crashpoint = NULL; const struct crashtype *crashtype = NULL; - int ret = -EINVAL; + int ret; int i; /* Neither or both of these need to be set */ -- cgit v1.2.3-59-g8ed1b From 209de31034522fae53f789f52c9461c557011d70 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Fri, 14 Jun 2019 18:53:56 +0100 Subject: staging: most-core: Use bus_find_device_by_name Use bus_find_device_by_name() helper instead of writing our own helper. Cc: Greg Kroah-Hartman Cc: "Rafael J. Wysocki" Cc: Christian Gromm Cc: "Gustavo A. R. Silva" Cc: Colin Ian King Signed-off-by: Suzuki K Poulose Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/core.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/most/core.c b/drivers/staging/most/core.c index 86a8545c8d97..b9841adb7181 100644 --- a/drivers/staging/most/core.c +++ b/drivers/staging/most/core.c @@ -561,13 +561,6 @@ static int split_string(char *buf, char **a, char **b, char **c, char **d) return 0; } -static int match_bus_dev(struct device *dev, void *data) -{ - char *mdev_name = data; - - return !strcmp(dev_name(dev), mdev_name); -} - /** * get_channel - get pointer to channel * @mdev: name of the device interface @@ -579,7 +572,7 @@ static struct most_channel *get_channel(char *mdev, char *mdev_ch) struct most_interface *iface; struct most_channel *c, *tmp; - dev = bus_find_device(&mc.bus, NULL, mdev, match_bus_dev); + dev = bus_find_device_by_name(&mc.bus, NULL, mdev); if (!dev) return NULL; iface = to_most_interface(dev); -- cgit v1.2.3-59-g8ed1b From 29d14b668d2f2e7b692525ee3f69bf12b06be0f0 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Fri, 14 Jun 2019 18:53:57 +0100 Subject: mfd: Remove unused helper syscon_regmap_lookup_by_pdevname Nobody uses the exported helper syscon_regmap_lookup_by_pdevname, to lookup a device by name. Let us remove it. Suggested-by: Arnd Bergman Cc: Arnd Bergman Cc: Greg Kroah-Hartman Cc: "Rafael J. Wysocki" Signed-off-by: Suzuki K Poulose Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/syscon.c | 21 --------------------- include/linux/mfd/syscon.h | 6 ------ 2 files changed, 27 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 8ce1e41d632c..b65e585fc8c6 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -190,27 +190,6 @@ struct regmap *syscon_regmap_lookup_by_compatible(const char *s) } EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); -static int syscon_match_pdevname(struct device *dev, void *data) -{ - return !strcmp(dev_name(dev), (const char *)data); -} - -struct regmap *syscon_regmap_lookup_by_pdevname(const char *s) -{ - struct device *dev; - struct syscon *syscon; - - dev = driver_find_device(&syscon_driver.driver, NULL, (void *)s, - syscon_match_pdevname); - if (!dev) - return ERR_PTR(-EPROBE_DEFER); - - syscon = dev_get_drvdata(dev); - - return syscon->regmap; -} -EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname); - struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, const char *property) { diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h index f0273c9e972b..8cfda0554381 100644 --- a/include/linux/mfd/syscon.h +++ b/include/linux/mfd/syscon.h @@ -19,7 +19,6 @@ struct device_node; #ifdef CONFIG_MFD_SYSCON extern struct regmap *syscon_node_to_regmap(struct device_node *np); extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s); -extern struct regmap *syscon_regmap_lookup_by_pdevname(const char *s); extern struct regmap *syscon_regmap_lookup_by_phandle( struct device_node *np, const char *property); @@ -34,11 +33,6 @@ static inline struct regmap *syscon_regmap_lookup_by_compatible(const char *s) return ERR_PTR(-ENOTSUPP); } -static inline struct regmap *syscon_regmap_lookup_by_pdevname(const char *s) -{ - return ERR_PTR(-ENOTSUPP); -} - static inline struct regmap *syscon_regmap_lookup_by_phandle( struct device_node *np, const char *property) -- cgit v1.2.3-59-g8ed1b From e6374f6b2e9c9f9a7cf5418157ad7f30f3abd70e Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Fri, 14 Jun 2019 18:53:58 +0100 Subject: acpi: utils: Cleanup acpi_dev_match_cb The prototype of bus_find_device() will be unified with that of class_find_device() subsequently, but for this purpose the callback functions passed to it need to take (const void *) as the second argument. Consequently, they cannot modify the memory pointed to by that argument which currently is not the case for acpi_dev_match_cb(). However, acpi_dev_match_cb() really need not modify the "match" object passed to it, because acpi_dev_get_first_match_dev() which uses it via bus_find_device() can easily convert the result of bus_find_device() into the pointer to return. For this reason, update acpi_dev_match_cb() to avoid the redundant memory updates. Cc: Len Brown Cc: linux-acpi@vger.kernel.org Signed-off-by: Suzuki K Poulose Reviewed-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/utils.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 7def63ab00c0..1391b63cadfd 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -725,8 +725,6 @@ bool acpi_dev_found(const char *hid) EXPORT_SYMBOL(acpi_dev_found); struct acpi_dev_match_info { - const char *dev_name; - struct acpi_device *adev; struct acpi_device_id hid[2]; const char *uid; s64 hrv; @@ -746,9 +744,6 @@ static int acpi_dev_match_cb(struct device *dev, void *data) strcmp(adev->pnp.unique_id, match->uid))) return 0; - match->dev_name = acpi_dev_name(adev); - match->adev = adev; - if (match->hrv == -1) return 1; @@ -818,7 +813,7 @@ acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv) match.hrv = hrv; dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb); - return dev ? match.adev : NULL; + return dev ? to_acpi_device(dev) : NULL; } EXPORT_SYMBOL(acpi_dev_get_first_match_dev); -- cgit v1.2.3-59-g8ed1b From 418e3ea157efb0eb2c6dd412a8d5f052477c7f5a Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Fri, 14 Jun 2019 18:53:59 +0100 Subject: bus_find_device: Unify the match callback with class_find_device There is an arbitrary difference between the prototypes of bus_find_device() and class_find_device() preventing their callers from passing the same pair of data and match() arguments to both of them, which is the const qualifier used in the prototype of class_find_device(). If that qualifier is also used in the bus_find_device() prototype, it will be possible to pass the same match() callback function to both bus_find_device() and class_find_device(), which will allow some optimizations to be made in order to avoid code duplication going forward. Also with that, constify the "data" parameter as it is passed as a const to the match function. For this reason, change the prototype of bus_find_device() to match the prototype of class_find_device() and adjust its callers to use the const qualifier in accordance with the new prototype of it. Cc: Alexander Shishkin Cc: Andrew Lunn Cc: Andreas Noever Cc: Arnd Bergmann Cc: Bjorn Helgaas Cc: Corey Minyard Cc: Christian Borntraeger Cc: David Kershner Cc: "David S. Miller" Cc: David Airlie Cc: Felipe Balbi Cc: Frank Rowand Cc: Grygorii Strashko Cc: Harald Freudenberger Cc: Hartmut Knaack Cc: Heiko Stuebner Cc: Jason Gunthorpe Cc: Jonathan Cameron Cc: "James E.J. Bottomley" Cc: Len Brown Cc: Mark Brown Cc: Michael Ellerman Cc: Michael Jamet Cc: "Martin K. Petersen" Cc: Peter Oberparleiter Cc: Sebastian Ott Cc: Srinivas Kandagatla Cc: Yehezkel Bernat Cc: rafael@kernel.org Acked-by: Corey Minyard Acked-by: David Kershner Acked-by: Mark Brown Acked-by: Rafael J. Wysocki Acked-by: Srinivas Kandagatla Acked-by: Wolfram Sang # for the I2C parts Acked-by: Rob Herring Signed-off-by: Suzuki K Poulose Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/ibmebus.c | 4 ++-- drivers/acpi/acpi_lpss.c | 4 ++-- drivers/acpi/sleep.c | 2 +- drivers/acpi/utils.c | 4 ++-- drivers/base/bus.c | 6 +++--- drivers/base/devcon.c | 2 +- drivers/char/ipmi/ipmi_si_platform.c | 2 +- drivers/firmware/efi/dev-path-parser.c | 4 ++-- drivers/gpu/drm/drm_mipi_dsi.c | 2 +- drivers/hwtracing/coresight/coresight.c | 6 +++--- drivers/hwtracing/coresight/of_coresight.c | 2 +- drivers/hwtracing/intel_th/core.c | 5 ++--- drivers/i2c/i2c-core-acpi.c | 4 ++-- drivers/i2c/i2c-core-of.c | 4 ++-- drivers/iio/inkern.c | 2 +- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 2 +- drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c | 2 +- drivers/net/ethernet/ti/cpsw-phy-sel.c | 4 ++-- drivers/net/ethernet/ti/davinci_emac.c | 2 +- drivers/net/ethernet/toshiba/tc35815.c | 4 ++-- drivers/nvmem/core.c | 2 +- drivers/of/of_mdio.c | 2 +- drivers/of/platform.c | 2 +- drivers/pci/probe.c | 2 +- drivers/pci/search.c | 4 ++-- drivers/s390/cio/css.c | 4 ++-- drivers/s390/cio/device.c | 4 ++-- drivers/s390/cio/scm.c | 4 ++-- drivers/s390/crypto/ap_bus.c | 8 ++++---- drivers/scsi/scsi_proc.c | 2 +- drivers/spi/spi.c | 4 ++-- drivers/thunderbolt/switch.c | 4 ++-- drivers/usb/core/devio.c | 4 ++-- drivers/usb/core/usb.c | 4 ++-- drivers/usb/phy/phy-am335x-control.c | 4 ++-- drivers/usb/phy/phy-isp1301.c | 4 ++-- drivers/visorbus/visorbus_main.c | 4 ++-- include/linux/device.h | 4 ++-- sound/soc/rockchip/rk3399_gru_sound.c | 2 +- 39 files changed, 67 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/platforms/pseries/ibmebus.c b/arch/powerpc/platforms/pseries/ibmebus.c index 84e8ec4011ba..b91eb0929ed1 100644 --- a/arch/powerpc/platforms/pseries/ibmebus.c +++ b/arch/powerpc/platforms/pseries/ibmebus.c @@ -147,13 +147,13 @@ static const struct dma_map_ops ibmebus_dma_ops = { .unmap_page = ibmebus_unmap_page, }; -static int ibmebus_match_path(struct device *dev, void *data) +static int ibmebus_match_path(struct device *dev, const void *data) { struct device_node *dn = to_platform_device(dev)->dev.of_node; return (of_find_node_by_path(data) == dn); } -static int ibmebus_match_node(struct device *dev, void *data) +static int ibmebus_match_node(struct device *dev, const void *data) { return to_platform_device(dev)->dev.of_node == data; } diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index cf768608437e..dc2ca78748a2 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -511,10 +511,10 @@ struct hid_uid { const char *uid; }; -static int match_hid_uid(struct device *dev, void *data) +static int match_hid_uid(struct device *dev, const void *data) { struct acpi_device *adev = ACPI_COMPANION(dev); - struct hid_uid *id = data; + const struct hid_uid *id = data; if (!adev) return 0; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index a34deccd7317..fcf4386ecc78 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -454,7 +454,7 @@ static int acpi_pm_prepare(void) return error; } -static int find_powerf_dev(struct device *dev, void *data) +static int find_powerf_dev(struct device *dev, const void *data) { struct acpi_device *device = to_acpi_device(dev); const char *hid = acpi_device_hid(device); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 1391b63cadfd..e3974a8f8fd4 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -730,10 +730,10 @@ struct acpi_dev_match_info { s64 hrv; }; -static int acpi_dev_match_cb(struct device *dev, void *data) +static int acpi_dev_match_cb(struct device *dev, const void *data) { struct acpi_device *adev = to_acpi_device(dev); - struct acpi_dev_match_info *match = data; + const struct acpi_dev_match_info *match = data; unsigned long long hrv; acpi_status status; diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 0a58e969f8b7..df3cac739813 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -323,8 +323,8 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev); * return to the caller and not iterate over any more devices. */ struct device *bus_find_device(struct bus_type *bus, - struct device *start, void *data, - int (*match)(struct device *dev, void *data)) + struct device *start, const void *data, + int (*match)(struct device *dev, const void *data)) { struct klist_iter i; struct device *dev; @@ -342,7 +342,7 @@ struct device *bus_find_device(struct bus_type *bus, } EXPORT_SYMBOL_GPL(bus_find_device); -static int match_name(struct device *dev, void *data) +static int match_name(struct device *dev, const void *data) { const char *name = data; diff --git a/drivers/base/devcon.c b/drivers/base/devcon.c index 04db9ae235e4..ac026d5fc672 100644 --- a/drivers/base/devcon.c +++ b/drivers/base/devcon.c @@ -107,7 +107,7 @@ static struct bus_type *generic_match_buses[] = { NULL, }; -static int device_fwnode_match(struct device *dev, void *fwnode) +static int device_fwnode_match(struct device *dev, const void *fwnode) { return dev_fwnode(dev) == fwnode; } diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c index f2a91c4d8cab..fd94c4238449 100644 --- a/drivers/char/ipmi/ipmi_si_platform.c +++ b/drivers/char/ipmi/ipmi_si_platform.c @@ -426,7 +426,7 @@ static int ipmi_remove(struct platform_device *pdev) return ipmi_si_remove_by_dev(&pdev->dev); } -static int pdev_match_name(struct device *dev, void *data) +static int pdev_match_name(struct device *dev, const void *data) { struct platform_device *pdev = to_platform_device(dev); const char *name = data; diff --git a/drivers/firmware/efi/dev-path-parser.c b/drivers/firmware/efi/dev-path-parser.c index 85ec99f97841..20123384271c 100644 --- a/drivers/firmware/efi/dev-path-parser.c +++ b/drivers/firmware/efi/dev-path-parser.c @@ -17,9 +17,9 @@ struct acpi_hid_uid { char uid[11]; /* UINT_MAX + null byte */ }; -static int __init match_acpi_dev(struct device *dev, void *data) +static int __init match_acpi_dev(struct device *dev, const void *data) { - struct acpi_hid_uid hid_uid = *(struct acpi_hid_uid *)data; + struct acpi_hid_uid hid_uid = *(const struct acpi_hid_uid *)data; struct acpi_device *adev = to_acpi_device(dev); if (acpi_match_device_ids(adev, hid_uid.hid)) diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 80b75501f5c6..ad19df0686c9 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -93,7 +93,7 @@ static struct bus_type mipi_dsi_bus_type = { .pm = &mipi_dsi_device_pm_ops, }; -static int of_device_match(struct device *dev, void *data) +static int of_device_match(struct device *dev, const void *data) { return dev->of_node == data; } diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 4b130281236a..b67ab6a09587 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -498,9 +498,9 @@ struct coresight_device *coresight_get_sink(struct list_head *path) return csdev; } -static int coresight_enabled_sink(struct device *dev, void *data) +static int coresight_enabled_sink(struct device *dev, const void *data) { - bool *reset = data; + const bool *reset = data; struct coresight_device *csdev = to_coresight_device(dev); if ((csdev->type == CORESIGHT_DEV_TYPE_SINK || @@ -544,7 +544,7 @@ struct coresight_device *coresight_get_enabled_sink(bool deactivate) return dev ? to_coresight_device(dev) : NULL; } -static int coresight_sink_by_id(struct device *dev, void *data) +static int coresight_sink_by_id(struct device *dev, const void *data) { struct coresight_device *csdev = to_coresight_device(dev); unsigned long hash; diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index 7045930fc958..3fc200ec1c03 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c @@ -18,7 +18,7 @@ #include -static int of_dev_node_match(struct device *dev, void *data) +static int of_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data; } diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index 033dce563c99..55922896d862 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -789,10 +789,9 @@ static int intel_th_populate(struct intel_th *th) return 0; } -static int match_devt(struct device *dev, void *data) +static int match_devt(struct device *dev, const void *data) { - dev_t devt = (dev_t)(unsigned long)data; - + dev_t devt = (dev_t)(unsigned long)(void *)data; return dev->devt == devt; } diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index d84095591e45..8af35f114821 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -318,7 +318,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev) } EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); -static int i2c_acpi_find_match_adapter(struct device *dev, void *data) +static int i2c_acpi_find_match_adapter(struct device *dev, const void *data) { struct i2c_adapter *adapter = i2c_verify_adapter(dev); @@ -328,7 +328,7 @@ static int i2c_acpi_find_match_adapter(struct device *dev, void *data) return ACPI_HANDLE(dev) == (acpi_handle)data; } -static int i2c_acpi_find_match_device(struct device *dev, void *data) +static int i2c_acpi_find_match_device(struct device *dev, const void *data) { return ACPI_COMPANION(dev) == data; } diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 406e5f695a7e..2eb59a260ad4 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -112,12 +112,12 @@ void of_i2c_register_devices(struct i2c_adapter *adap) of_node_put(bus); } -static int of_dev_node_match(struct device *dev, void *data) +static int of_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data; } -static int of_dev_or_parent_node_match(struct device *dev, void *data) +static int of_dev_or_parent_node_match(struct device *dev, const void *data) { if (dev->of_node == data) return 1; diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 4a5eff3f18bc..c46fb59d92cb 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -93,7 +93,7 @@ static const struct iio_chan_spec #ifdef CONFIG_OF -static int iio_dev_node_match(struct device *dev, void *data) +static int iio_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data && dev->type == &iio_device_type; } diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 4c5d0f160c10..fd90b05849c8 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -4497,7 +4497,7 @@ static const struct acpi_device_id hns_roce_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, hns_roce_acpi_match); -static int hns_roce_node_match(struct device *dev, void *fwnode) +static int hns_roce_node_match(struct device *dev, const void *fwnode) { return dev->fwnode == fwnode; } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c index 09c16d88172e..bb6586d0e5af 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c @@ -754,7 +754,7 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev) return (void *)misc_op; } -static int hns_dsaf_dev_match(struct device *dev, void *fwnode) +static int hns_dsaf_dev_match(struct device *dev, const void *fwnode) { return dev->fwnode == fwnode; } diff --git a/drivers/net/ethernet/ti/cpsw-phy-sel.c b/drivers/net/ethernet/ti/cpsw-phy-sel.c index 48e0924259f5..4e184eecc8e1 100644 --- a/drivers/net/ethernet/ti/cpsw-phy-sel.c +++ b/drivers/net/ethernet/ti/cpsw-phy-sel.c @@ -151,9 +151,9 @@ static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv, } static struct platform_driver cpsw_phy_sel_driver; -static int match(struct device *dev, void *data) +static int match(struct device *dev, const void *data) { - struct device_node *node = (struct device_node *)data; + const struct device_node *node = (const struct device_node *)data; return dev->of_node == node && dev->driver == &cpsw_phy_sel_driver.driver; } diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 4bf65cab79e6..57d131a04db3 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1371,7 +1371,7 @@ static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd) return -EOPNOTSUPP; } -static int match_first_device(struct device *dev, void *data) +static int match_first_device(struct device *dev, const void *data) { if (dev->parent && dev->parent->of_node) return of_device_is_compatible(dev->parent->of_node, diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c index c50a9772f4af..8479a440527b 100644 --- a/drivers/net/ethernet/toshiba/tc35815.c +++ b/drivers/net/ethernet/toshiba/tc35815.c @@ -694,10 +694,10 @@ err_out: * should provide a "tc35815-mac" device with a MAC address in its * platform_data. */ -static int tc35815_mac_match(struct device *dev, void *data) +static int tc35815_mac_match(struct device *dev, const void *data) { struct platform_device *plat_dev = to_platform_device(dev); - struct pci_dev *pci_dev = data; + const struct pci_dev *pci_dev = data; unsigned int id = pci_dev->irq; return !strcmp(plat_dev->name, "tc35815-mac") && plat_dev->id == id; } diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index c7892c3da91f..ac5d945be88a 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -76,7 +76,7 @@ static struct bus_type nvmem_bus_type = { .name = "nvmem", }; -static int of_nvmem_match(struct device *dev, void *nvmem_np) +static int of_nvmem_match(struct device *dev, const void *nvmem_np) { return dev->of_node == nvmem_np; } diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index de6157357e26..dfe12948c834 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -282,7 +282,7 @@ unregister: EXPORT_SYMBOL(of_mdiobus_register); /* Helper function for of_phy_find_device */ -static int of_phy_match(struct device *dev, void *phy_np) +static int of_phy_match(struct device *dev, const void *phy_np) { return dev->of_node == phy_np; } diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 04ad312fd85b..008d79e33c2d 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -37,7 +37,7 @@ static const struct of_device_id of_skipped_node_table[] = { {} /* Empty terminated list */ }; -static int of_dev_node_match(struct device *dev, void *data) +static int of_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 0e8e2c186f50..f9ef7ad3f75d 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -64,7 +64,7 @@ static struct resource *get_pci_domain_busn_res(int domain_nr) return &r->res; } -static int find_anything(struct device *dev, void *data) +static int find_anything(struct device *dev, const void *data) { return 1; } diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 5c7922612733..7f4e65872b8d 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -236,10 +236,10 @@ struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus, } EXPORT_SYMBOL(pci_get_domain_bus_and_slot); -static int match_pci_dev_by_id(struct device *dev, void *data) +static int match_pci_dev_by_id(struct device *dev, const void *data) { struct pci_dev *pdev = to_pci_dev(dev); - struct pci_device_id *id = data; + const struct pci_device_id *id = data; if (pci_match_one_device(id, pdev)) return 1; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index aea502922646..a2c97830efe0 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -434,10 +434,10 @@ static int css_probe_device(struct subchannel_id schid, struct schib *schib) } static int -check_subchannel(struct device * dev, void * data) +check_subchannel(struct device *dev, const void *data) { struct subchannel *sch; - struct subchannel_id *schid = data; + struct subchannel_id *schid = (void *)data; sch = to_subchannel(dev); return schid_equal(&sch->schid, schid); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 1540229a37bb..d32f373e5bc7 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -642,10 +642,10 @@ static int ccw_device_add(struct ccw_device *cdev) return device_add(dev); } -static int match_dev_id(struct device *dev, void *data) +static int match_dev_id(struct device *dev, const void *data) { struct ccw_device *cdev = to_ccwdev(dev); - struct ccw_dev_id *dev_id = data; + struct ccw_dev_id *dev_id = (void *)data; return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id); } diff --git a/drivers/s390/cio/scm.c b/drivers/s390/cio/scm.c index 6bca1d5455d4..9f26d4310bb3 100644 --- a/drivers/s390/cio/scm.c +++ b/drivers/s390/cio/scm.c @@ -174,10 +174,10 @@ out: kobject_uevent(&scmdev->dev.kobj, KOBJ_CHANGE); } -static int check_address(struct device *dev, void *data) +static int check_address(struct device *dev, const void *data) { struct scm_device *scmdev = to_scm_dev(dev); - struct sale *sale = data; + const struct sale *sale = data; return scmdev->address == sale->sa; } diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index b9fc502c58c2..b7902b643ec8 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1356,16 +1356,16 @@ static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func) * Helper function to be used with bus_find_dev * matches for the card device with the given id */ -static int __match_card_device_with_id(struct device *dev, void *data) +static int __match_card_device_with_id(struct device *dev, const void *data) { - return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long) data; + return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long)(void *) data; } /* * Helper function to be used with bus_find_dev * matches for the queue device with a given qid */ -static int __match_queue_device_with_qid(struct device *dev, void *data) +static int __match_queue_device_with_qid(struct device *dev, const void *data) { return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long) data; } @@ -1374,7 +1374,7 @@ static int __match_queue_device_with_qid(struct device *dev, void *data) * Helper function to be used with bus_find_dev * matches any queue device with given queue id */ -static int __match_queue_device_with_queue_id(struct device *dev, void *data) +static int __match_queue_device_with_queue_id(struct device *dev, const void *data) { return is_queue_dev(dev) && AP_QID_QUEUE(to_ap_queue(dev)->qid) == (int)(long) data; diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 7f0ceb65c3f3..c074631086a4 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -372,7 +372,7 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, return err; } -static int always_match(struct device *dev, void *data) +static int always_match(struct device *dev, const void *data) { return 1; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5e75944ad5d1..3da1121f7572 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3538,7 +3538,7 @@ EXPORT_SYMBOL_GPL(spi_write_then_read); /*-------------------------------------------------------------------------*/ #if IS_ENABLED(CONFIG_OF) -static int __spi_of_device_match(struct device *dev, void *data) +static int __spi_of_device_match(struct device *dev, const void *data) { return dev->of_node == data; } @@ -3639,7 +3639,7 @@ static int spi_acpi_controller_match(struct device *dev, const void *data) return ACPI_COMPANION(dev->parent) == data; } -static int spi_acpi_device_match(struct device *dev, void *data) +static int spi_acpi_device_match(struct device *dev, const void *data) { return ACPI_COMPANION(dev) == data; } diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index c1b016574fb4..c9a7e4a779cd 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -1946,10 +1946,10 @@ struct tb_sw_lookup { u64 route; }; -static int tb_switch_match(struct device *dev, void *data) +static int tb_switch_match(struct device *dev, const void *data) { struct tb_switch *sw = tb_to_switch(dev); - struct tb_sw_lookup *lookup = data; + const struct tb_sw_lookup *lookup = data; if (!sw) return 0; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index fa783531ee88..7bd7de7273a3 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -947,9 +947,9 @@ error: return ret; } -static int match_devt(struct device *dev, void *data) +static int match_devt(struct device *dev, const void *data) { - return dev->devt == (dev_t) (unsigned long) data; + return dev->devt == (dev_t)(unsigned long)(void *)data; } static struct usb_device *usbdev_lookup_by_devt(dev_t devt) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7fcb9f782931..1678e305e037 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -325,9 +325,9 @@ struct find_interface_arg { struct device_driver *drv; }; -static int __find_interface(struct device *dev, void *data) +static int __find_interface(struct device *dev, const void *data) { - struct find_interface_arg *arg = data; + const struct find_interface_arg *arg = data; struct usb_interface *intf; if (!is_usb_interface(dev)) diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c index a3cb25cb74f8..d16dfc320faa 100644 --- a/drivers/usb/phy/phy-am335x-control.c +++ b/drivers/usb/phy/phy-am335x-control.c @@ -118,9 +118,9 @@ static const struct of_device_id omap_control_usb_id_table[] = { MODULE_DEVICE_TABLE(of, omap_control_usb_id_table); static struct platform_driver am335x_control_driver; -static int match(struct device *dev, void *data) +static int match(struct device *dev, const void *data) { - struct device_node *node = (struct device_node *)data; + const struct device_node *node = (const struct device_node *)data; return dev->of_node == node && dev->driver == &am335x_control_driver.driver; } diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c index 93b7d6a30aad..6cf6fbd39237 100644 --- a/drivers/usb/phy/phy-isp1301.c +++ b/drivers/usb/phy/phy-isp1301.c @@ -142,9 +142,9 @@ static struct i2c_driver isp1301_driver = { module_i2c_driver(isp1301_driver); -static int match(struct device *dev, void *data) +static int match(struct device *dev, const void *data) { - struct device_node *node = (struct device_node *)data; + const struct device_node *node = (const struct device_node *)data; return (dev->of_node == node) && (dev->driver == &isp1301_driver.driver); } diff --git a/drivers/visorbus/visorbus_main.c b/drivers/visorbus/visorbus_main.c index 0b2434cc4ecd..152fd29f04f2 100644 --- a/drivers/visorbus/visorbus_main.c +++ b/drivers/visorbus/visorbus_main.c @@ -171,10 +171,10 @@ struct visor_busdev { u32 dev_no; }; -static int match_visorbus_dev_by_id(struct device *dev, void *data) +static int match_visorbus_dev_by_id(struct device *dev, const void *data) { struct visor_device *vdev = to_visor_device(dev); - struct visor_busdev *id = data; + const struct visor_busdev *id = data; if (vdev->chipset_bus_no == id->bus_no && vdev->chipset_dev_no == id->dev_no) diff --git a/include/linux/device.h b/include/linux/device.h index e85264fb6616..cbbdcadc660e 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -166,8 +166,8 @@ void subsys_dev_iter_exit(struct subsys_dev_iter *iter); int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *dev, void *data)); struct device *bus_find_device(struct bus_type *bus, struct device *start, - void *data, - int (*match)(struct device *dev, void *data)); + const void *data, + int (*match)(struct device *dev, const void *data)); struct device *bus_find_device_by_name(struct bus_type *bus, struct device *start, const char *name); diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index 3d0cc6e90d7b..c04c9ed185b7 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -405,7 +405,7 @@ static const struct dailink_match_data dailink_match[] = { }, }; -static int of_dev_node_match(struct device *dev, void *data) +static int of_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data; } -- cgit v1.2.3-59-g8ed1b From 92ce7e83b4e5c86687d748ba53cb755acdce1256 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Fri, 14 Jun 2019 18:54:00 +0100 Subject: driver_find_device: Unify the match function with class_find_device() The driver_find_device() accepts a match function pointer to filter the devices for lookup, similar to bus/class_find_device(). However, there is a minor difference in the prototype for the match parameter for driver_find_device() with the now unified version accepted by {bus/class}_find_device(), where it doesn't accept a "const" qualifier for the data argument. This prevents us from reusing the generic match functions for driver_find_device(). For this reason, change the prototype of the driver_find_device() to make the "match" parameter in line with {bus/class}_find_device() and adjust its callers to use the const qualifier. Also, we could now promote the "data" parameter to const as we pass it down as a const parameter to the match functions. Cc: Corey Minyard Cc: Russell King Cc: Thierry Reding Cc: Greg Kroah-Hartman Cc: "Rafael J. Wysocki" Cc: Will Deacon Cc: Joerg Roedel Cc: Peter Oberparleiter Cc: Sebastian Ott Cc: David Airlie Cc: Daniel Vetter Cc: Nehal Shah Cc: Shyam Sundar S K Cc: Lee Jones Cc: Christian Borntraeger Signed-off-by: Suzuki K Poulose Signed-off-by: Greg Kroah-Hartman --- drivers/amba/tegra-ahb.c | 4 ++-- drivers/base/driver.c | 4 ++-- drivers/char/ipmi/ipmi_msghandler.c | 8 ++++---- drivers/gpu/drm/tegra/dc.c | 4 ++-- drivers/i2c/busses/i2c-amd-mp2-pci.c | 2 +- drivers/iommu/arm-smmu-v3.c | 2 +- drivers/iommu/arm-smmu.c | 2 +- drivers/mfd/altera-sysmgr.c | 4 ++-- drivers/s390/cio/ccwgroup.c | 4 ++-- drivers/s390/cio/chsc_sch.c | 2 +- drivers/s390/cio/device.c | 2 +- include/linux/device.h | 4 ++-- 12 files changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c index 3751d811be39..42175a67ba0e 100644 --- a/drivers/amba/tegra-ahb.c +++ b/drivers/amba/tegra-ahb.c @@ -143,10 +143,10 @@ static inline void gizmo_writel(struct tegra_ahb *ahb, u32 value, u32 offset) } #ifdef CONFIG_TEGRA_IOMMU_SMMU -static int tegra_ahb_match_by_smmu(struct device *dev, void *data) +static int tegra_ahb_match_by_smmu(struct device *dev, const void *data) { struct tegra_ahb *ahb = dev_get_drvdata(dev); - struct device_node *dn = data; + const struct device_node *dn = data; return (ahb->dev->of_node == dn) ? 1 : 0; } diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 857c8f1b876e..4e5ca632f35e 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -73,8 +73,8 @@ EXPORT_SYMBOL_GPL(driver_for_each_device); * return to the caller and not iterate over any more devices. */ struct device *driver_find_device(struct device_driver *drv, - struct device *start, void *data, - int (*match)(struct device *dev, void *data)) + struct device *start, const void *data, + int (*match)(struct device *dev, const void *data)) { struct klist_iter i; struct device *dev; diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 1dc10740fc0f..6707659cffd6 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2819,9 +2819,9 @@ static const struct device_type bmc_device_type = { .groups = bmc_dev_attr_groups, }; -static int __find_bmc_guid(struct device *dev, void *data) +static int __find_bmc_guid(struct device *dev, const void *data) { - guid_t *guid = data; + const guid_t *guid = data; struct bmc_device *bmc; int rv; @@ -2857,9 +2857,9 @@ struct prod_dev_id { unsigned char device_id; }; -static int __find_bmc_prod_dev_id(struct device *dev, void *data) +static int __find_bmc_prod_dev_id(struct device *dev, const void *data) { - struct prod_dev_id *cid = data; + const struct prod_dev_id *cid = data; struct bmc_device *bmc; int rv; diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 607a6ea17ecc..52109a63e797 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -2375,10 +2375,10 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc) return 0; } -static int tegra_dc_match_by_pipe(struct device *dev, void *data) +static int tegra_dc_match_by_pipe(struct device *dev, const void *data) { struct tegra_dc *dc = dev_get_drvdata(dev); - unsigned int pipe = (unsigned long)data; + unsigned int pipe = (unsigned long)(void *)data; return dc->pipe == pipe; } diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c index 455e1f36a2a3..c7fe3b44a860 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -457,7 +457,7 @@ static struct pci_driver amd_mp2_pci_driver = { }; module_pci_driver(amd_mp2_pci_driver); -static int amd_mp2_device_match(struct device *dev, void *data) +static int amd_mp2_device_match(struct device *dev, const void *data) { return 1; } diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 4d5a694f02c2..d787856f9dcf 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -2023,7 +2023,7 @@ arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) static struct platform_driver arm_smmu_driver; -static int arm_smmu_match_node(struct device *dev, void *data) +static int arm_smmu_match_node(struct device *dev, const void *data) { return dev->fwnode == data; } diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 5e54cc0a28b3..4ce429b74655 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1431,7 +1431,7 @@ static bool arm_smmu_capable(enum iommu_cap cap) } } -static int arm_smmu_match_node(struct device *dev, void *data) +static int arm_smmu_match_node(struct device *dev, const void *data) { return dev->fwnode == data; } diff --git a/drivers/mfd/altera-sysmgr.c b/drivers/mfd/altera-sysmgr.c index 8976f82785bb..2ee14d8a6d31 100644 --- a/drivers/mfd/altera-sysmgr.c +++ b/drivers/mfd/altera-sysmgr.c @@ -92,9 +92,9 @@ static struct regmap_config altr_sysmgr_regmap_cfg = { * Matching function used by driver_find_device(). * Return: True if match is found, otherwise false. */ -static int sysmgr_match_phandle(struct device *dev, void *data) +static int sysmgr_match_phandle(struct device *dev, const void *data) { - return dev->of_node == (struct device_node *)data; + return dev->of_node == (const struct device_node *)data; } /** diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 4ebf6d4fc66c..ea17615789c9 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -581,7 +581,7 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver) } EXPORT_SYMBOL(ccwgroup_driver_register); -static int __ccwgroup_match_all(struct device *dev, void *data) +static int __ccwgroup_match_all(struct device *dev, const void *data) { return 1; } @@ -608,7 +608,7 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) } EXPORT_SYMBOL(ccwgroup_driver_unregister); -static int __ccwgroupdev_check_busid(struct device *dev, void *id) +static int __ccwgroupdev_check_busid(struct device *dev, const void *id) { char *bus_id = id; diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 8d9f36625ba5..8f080d3fd380 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -203,7 +203,7 @@ static void chsc_cleanup_sch_driver(void) static DEFINE_SPINLOCK(chsc_lock); -static int chsc_subchannel_match_next_free(struct device *dev, void *data) +static int chsc_subchannel_match_next_free(struct device *dev, const void *data) { struct subchannel *sch = to_subchannel(dev); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index d32f373e5bc7..f27536ba58eb 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1653,7 +1653,7 @@ EXPORT_SYMBOL_GPL(ccw_device_force_console); * get ccw_device matching the busid, but only if owned by cdrv */ static int -__ccwdev_check_busid(struct device *dev, void *id) +__ccwdev_check_busid(struct device *dev, const void *id) { char *bus_id; diff --git a/include/linux/device.h b/include/linux/device.h index cbbdcadc660e..4d7c88131a4d 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -336,8 +336,8 @@ extern int __must_check driver_for_each_device(struct device_driver *drv, int (*fn)(struct device *dev, void *)); struct device *driver_find_device(struct device_driver *drv, - struct device *start, void *data, - int (*match)(struct device *dev, void *data)); + struct device *start, const void *data, + int (*match)(struct device *dev, const void *data)); void driver_deferred_probe_add(struct device *dev); int driver_deferred_probe_check_state(struct device *dev); -- cgit v1.2.3-59-g8ed1b From 65b66682344a15ba2069d4dd8d0cc39cc3aed7e9 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Fri, 14 Jun 2019 18:54:01 +0100 Subject: drivers: Add generic helper to match by of_node Add a helper to match device by the of_node. This will be later used to provide wrappers to the device iterators for {bus/class/driver}_find_device(). Convert other users to reuse this new helper. Cc: Alan Tull Cc: Andrew Lunn Cc: Daniel Vetter Cc: David Airlie Cc: "David S. Miller" Cc: devicetree@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: Florian Fainelli Cc: Frank Rowand Cc: Greg Kroah-Hartman Cc: Heiner Kallweit Cc: Jiri Slaby Cc: Jonathan Hunter Cc: Lee Jones Cc: Liam Girdwood Cc: linux-fpga@vger.kernel.org Cc: linux-i2c@vger.kernel.org Cc: linux-spi@vger.kernel.org Cc: Maarten Lankhorst Cc: Mark Brown Cc: Mathieu Poirier Cc: Maxime Ripard Cc: Moritz Fischer Cc: Peter Rosin Cc: Rob Herring Cc: Srinivas Kandagatla Cc: Thierry Reding Cc: Thor Thayer Cc: Wolfram Sang Cc: "Rafael J. Wysocki" Cc: Greg Kroah-Hartman Cc: Ulf Hansson Cc: Joe Perches Signed-off-by: Suzuki K Poulose Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 6 ++++++ drivers/fpga/of-fpga-region.c | 7 +------ include/linux/device.h | 2 ++ 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/base/core.c b/drivers/base/core.c index fd7511e04e62..92119080474c 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -3328,3 +3328,9 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2) dev->of_node_reused = true; } EXPORT_SYMBOL_GPL(device_set_of_node_from_dev); + +int device_match_of_node(struct device *dev, const void *np) +{ + return dev->of_node == np; +} +EXPORT_SYMBOL_GPL(device_match_of_node); diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c index 75f64abf9c81..e405309baadc 100644 --- a/drivers/fpga/of-fpga-region.c +++ b/drivers/fpga/of-fpga-region.c @@ -22,11 +22,6 @@ static const struct of_device_id fpga_region_of_match[] = { }; MODULE_DEVICE_TABLE(of, fpga_region_of_match); -static int fpga_region_of_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - /** * of_fpga_region_find - find FPGA region * @np: device node of FPGA Region @@ -37,7 +32,7 @@ static int fpga_region_of_node_match(struct device *dev, const void *data) */ static struct fpga_region *of_fpga_region_find(struct device_node *np) { - return fpga_region_class_find(NULL, np, fpga_region_of_node_match); + return fpga_region_class_find(NULL, np, device_match_of_node); } /** diff --git a/include/linux/device.h b/include/linux/device.h index 4d7c88131a4d..709308560d32 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -163,6 +163,8 @@ void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter); void subsys_dev_iter_exit(struct subsys_dev_iter *iter); +int device_match_of_node(struct device *dev, const void *np); + int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *dev, void *data)); struct device *bus_find_device(struct bus_type *bus, struct device *start, -- cgit v1.2.3-59-g8ed1b From fb59b7824da884e042f44dad9c713f221ded93c9 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Jun 2019 09:46:53 +0100 Subject: drivers: s390/cio: Fix compilation warning about const qualifiers Update __ccwdev_check_busid() and __ccwgroupdev_check_busid() to use "const" qualifiers to fix the compiler warning. Reported-by: kbuild test robot Cc: gregkh@linuxfoundation.org Cc: devel@driverdev.osuosl.org Signed-off-by: Suzuki K Poulose Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/ccwgroup.c | 2 +- drivers/s390/cio/device.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index ea17615789c9..c522e9313c50 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -610,7 +610,7 @@ EXPORT_SYMBOL(ccwgroup_driver_unregister); static int __ccwgroupdev_check_busid(struct device *dev, const void *id) { - char *bus_id = id; + const char *bus_id = id; return (strcmp(bus_id, dev_name(dev)) == 0); } diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index f27536ba58eb..113248227137 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1655,9 +1655,7 @@ EXPORT_SYMBOL_GPL(ccw_device_force_console); static int __ccwdev_check_busid(struct device *dev, const void *id) { - char *bus_id; - - bus_id = id; + const char *bus_id = id; return (strcmp(bus_id, dev_name(dev)) == 0); } -- cgit v1.2.3-59-g8ed1b From 0fd33116c1d8f8f9ff973c3d17280148068d77f4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 27 May 2019 14:27:03 +0200 Subject: arch_topology: Remove error messages on out-of-memory conditions There is no need to print error messages if kcalloc() or alloc_cpumask_var() fail, as the memory allocation core already takes care of that. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20190527122703.6303-1-geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/base/arch_topology.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 1739d7e1952a..8486c399ddb7 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -137,7 +137,6 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu) sizeof(*raw_capacity), GFP_KERNEL); if (!raw_capacity) { - pr_err("cpu_capacity: failed to allocate memory for raw capacities\n"); cap_parsing_failed = true; return false; } @@ -217,10 +216,8 @@ static int __init register_cpufreq_notifier(void) if (!acpi_disabled || !raw_capacity) return -EINVAL; - if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) { - pr_err("cpu_capacity: failed to allocate memory for cpus_to_visit\n"); + if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) return -ENOMEM; - } cpumask_copy(cpus_to_visit, cpu_possible_mask); -- cgit v1.2.3-59-g8ed1b From 83b44fe343b5abfcb1b2261289bd0cfcfcfd60a8 Mon Sep 17 00:00:00 2001 From: James Morse Date: Mon, 24 Jun 2019 18:36:56 +0100 Subject: drivers: base: cacheinfo: Ensure cpu hotplug work is done before Intel RDT The cacheinfo structures are alloced/freed by cpu online/offline callbacks. Originally these were only used by sysfs to expose the cache topology to user space. Without any in-kernel dependencies CPUHP_AP_ONLINE_DYN was an appropriate choice. resctrl has started using these structures to identify CPUs that share a cache. It updates its 'domain' structures from cpu online/offline callbacks. These depend on the cacheinfo structures (resctrl_online_cpu()->domain_add_cpu()->get_cache_id()-> get_cpu_cacheinfo()). These also run as CPUHP_AP_ONLINE_DYN. Now that there is an in-kernel dependency, move the cacheinfo work earlier so we know its done before resctrl's CPUHP_AP_ONLINE_DYN work runs. Fixes: 2264d9c74dda1 ("x86/intel_rdt: Build structures for each resource based on cache topology") Cc: Cc: Fenghua Yu Cc: Reinette Chatre Signed-off-by: James Morse Link: https://lore.kernel.org/r/20190624173656.202407-1-james.morse@arm.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/cacheinfo.c | 3 ++- include/linux/cpuhotplug.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index a7359535caf5..b444f89a2041 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -655,7 +655,8 @@ static int cacheinfo_cpu_pre_down(unsigned int cpu) static int __init cacheinfo_sysfs_init(void) { - return cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "base/cacheinfo:online", + return cpuhp_setup_state(CPUHP_AP_BASE_CACHEINFO_ONLINE, + "base/cacheinfo:online", cacheinfo_cpu_online, cacheinfo_cpu_pre_down); } device_initcall(cacheinfo_sysfs_init); diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 6a381594608c..50c893f03c21 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -175,6 +175,7 @@ enum cpuhp_state { CPUHP_AP_WATCHDOG_ONLINE, CPUHP_AP_WORKQUEUE_ONLINE, CPUHP_AP_RCUTREE_ONLINE, + CPUHP_AP_BASE_CACHEINFO_ONLINE, CPUHP_AP_ONLINE_DYN, CPUHP_AP_ONLINE_DYN_END = CPUHP_AP_ONLINE_DYN + 30, CPUHP_AP_X86_HPET_ONLINE, -- cgit v1.2.3-59-g8ed1b From 62a6bc3a1e4f4ee9ae0076fa295f9af1c3725ce3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 21 Jun 2019 17:17:25 +0200 Subject: driver: core: Allow subsystems to continue deferring probe Some subsystems, such as pinctrl, allow continuing to defer probe indefinitely. This is useful for devices that depend on resources provided by devices that are only probed after the init stage. One example of this can be seen on Tegra, where the DPAUX hardware contains pinmuxing controls for pins that it shares with an I2C controller. The I2C controller is typically used for communication with a monitor over HDMI (DDC). However, other instances of the I2C controller are used to access system critical components, such as a PMIC. The I2C controller driver will therefore usually be a builtin driver, whereas the DPAUX driver is part of the display driver that is loaded from a module to avoid bloating the kernel image with all of the DRM/KMS subsystem. In this particular case the pins used by this I2C/DDC controller become accessible very late in the boot process. However, since the controller is only used in conjunction with display, that's not an issue. Unfortunately the driver core currently outputs a warning message when a device fails to get the pinctrl before the end of the init stage. That can be confusing for the user because it may sound like an unwanted error occurred, whereas it's really an expected and harmless situation. In order to eliminate this warning, this patch allows callers of the driver_deferred_probe_check_state() helper to specify that they want to continue deferring probe, regardless of whether we're past the init stage or not. All of the callers of that function are updated for the new signature, but only the pinctrl subsystem passes a true value in the new persist parameter if appropriate. Signed-off-by: Thierry Reding Reviewed-by: Rafael J. Wysocki Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20190621151725.20414-1-thierry.reding@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 55 +++++++++++++++++++++++++++++++++++++------- drivers/pinctrl/devicetree.c | 7 +++--- include/linux/device.h | 1 + 3 files changed, 51 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 0df9b4461766..994a90747420 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -235,6 +235,19 @@ static int __init deferred_probe_timeout_setup(char *str) } __setup("deferred_probe_timeout=", deferred_probe_timeout_setup); +static int __driver_deferred_probe_check_state(struct device *dev) +{ + if (!initcalls_done) + return -EPROBE_DEFER; + + if (!deferred_probe_timeout) { + dev_WARN(dev, "deferred probe timeout, ignoring dependency"); + return -ETIMEDOUT; + } + + return 0; +} + /** * driver_deferred_probe_check_state() - Check deferred probe state * @dev: device to check @@ -248,14 +261,40 @@ __setup("deferred_probe_timeout=", deferred_probe_timeout_setup); */ int driver_deferred_probe_check_state(struct device *dev) { - if (initcalls_done) { - if (!deferred_probe_timeout) { - dev_WARN(dev, "deferred probe timeout, ignoring dependency"); - return -ETIMEDOUT; - } - dev_warn(dev, "ignoring dependency for device, assuming no driver"); - return -ENODEV; - } + int ret; + + ret = __driver_deferred_probe_check_state(dev); + if (ret < 0) + return ret; + + dev_warn(dev, "ignoring dependency for device, assuming no driver"); + + return -ENODEV; +} + +/** + * driver_deferred_probe_check_state_continue() - check deferred probe state + * @dev: device to check + * + * Returns -ETIMEDOUT if deferred probe debug timeout has expired, or + * -EPROBE_DEFER otherwise. + * + * Drivers or subsystems can opt-in to calling this function instead of + * directly returning -EPROBE_DEFER. + * + * This is similar to driver_deferred_probe_check_state(), but it allows the + * subsystem to keep deferring probe after built-in drivers have had a chance + * to probe. One scenario where that is useful is if built-in drivers rely on + * resources that are provided by modular drivers. + */ +int driver_deferred_probe_check_state_continue(struct device *dev) +{ + int ret; + + ret = __driver_deferred_probe_check_state(dev); + if (ret < 0) + return ret; + return -EPROBE_DEFER; } diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index f7e354f85518..88ddbb2e30de 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -112,12 +112,11 @@ static int dt_to_map_one_config(struct pinctrl *p, np_pctldev = of_get_next_parent(np_pctldev); if (!np_pctldev || of_node_is_root(np_pctldev)) { of_node_put(np_pctldev); - ret = driver_deferred_probe_check_state(p->dev); /* keep deferring if modules are enabled unless we've timed out */ - if (IS_ENABLED(CONFIG_MODULES) && !allow_default && ret == -ENODEV) - ret = -EPROBE_DEFER; + if (IS_ENABLED(CONFIG_MODULES) && !allow_default) + return driver_deferred_probe_check_state_continue(p->dev); - return ret; + return driver_deferred_probe_check_state(p->dev); } /* If we're creating a hog we can use the passed pctldev */ if (hog_pctldev && (np_pctldev == p->dev->of_node)) { diff --git a/include/linux/device.h b/include/linux/device.h index 709308560d32..ef61e2d50ecc 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -343,6 +343,7 @@ struct device *driver_find_device(struct device_driver *drv, void driver_deferred_probe_add(struct device *dev); int driver_deferred_probe_check_state(struct device *dev); +int driver_deferred_probe_check_state_continue(struct device *dev); /** * struct subsys_interface - interfaces to device functions -- cgit v1.2.3-59-g8ed1b