spi: enable spi_board_info to be registered after spi_master
PATCH v3 1/1 spi: enable spi_board_info to be registered after spi_master
Hi All,
Pls review this patch. thanks,
-Feng
Changelog:
v3:
* As suggested by Grant, use one lock to protect the match between spi_master and spi board info
v2:
* fix a typo in looping scan_masterlist()
* fix one race condition found by Grant
Quoted 1 line
From
28af337ec89225a0dfb7ca516545b7eff112e3b2Mon Sep 17 00:00:00 2001
From: Feng Tang <[email protected]>
Date: Tue, 27 Jul 2010 17:15:05 +0800
Subject: [PATCH] spi: enable spi_board_info to be registered after spi_master
Currently spi_register_board_info() has to be called before its related spi_master be registered, otherwise these board info will be just ignored.
This patch will remove this order limit, it adds a global spi master list like the existing global board info listr. Whenever a board info or a spi_master is registered, the spi master list or board info list will be scanned, and a new spi device will be created if there is a master-board info match.
--- drivers/spi/spi.c | 84 ++++++++++++++++++++++++++++++++-------------- include/linux/spi/spi.h | 3 ++ 2 files changed, 61 insertions(+), 26 deletions(-)
drivers/spi/spi.c +58 -26
@@ -196,11 +196,16 @@ EXPORT_SYMBOL_GPL(spi_register_driver);struct boardinfo {struct list_head list; -unsigned n_board_info; -struct spi_board_info board_info[0 ]; +struct spi_board_info board_info; };static LIST_HEAD (board_list); +static LIST_HEAD (spi_master_list); + +/* +* Used to protect add/del opertion for board_info list and +* spi_master list, and their matching process +*/ static DEFINE_MUTEX (board_lock);/**
@@ -365,6 +370,24 @@ struct spi_device *spi_new_device(struct spi_master *master, }EXPORT_SYMBOL_GPL (spi_new_device); +/* Has to be called when board_lock is acquired */ +static void spi_scan_masterlist (struct spi_board_info *bi) +{ +struct spi_master *master; +struct spi_device *dev; + +list_for_each_entry (master, &spi_master_list, list) { +if (master->bus_num != bi->bus_num) +continue ; + + dev =spi_new_device (master, bi); +if (!dev) +dev_err (master->dev.parent, +"can't create new device for %s\n" , + bi->modalias); + } +} +/** * spi_register_board_info - register SPI devices for a given board * @info: array of chip descriptors
@@ -387,43 +410,46 @@ EXPORT_SYMBOL_GPL(spi_new_device);int __init spi_register_board_info (struct spi_board_info const *info,unsigned n) { -struct boardinfo *bi; +struct boardinfo *bi; +int i; - bi =kmalloc (sizeof (*bi) + n *sizeof *info,GFP_KERNEL ); + bi =kzalloc (n *sizeof (*bi),GFP_KERNEL );if (!bi)return -ENOMEM ; - bi->n_board_info = n; -memcpy (bi->board_info, info, n *sizeof *info); -mutex_lock (&board_lock); -list_add_tail (&bi->list, &board_list); -mutex_unlock (&board_lock); +for (i =0 ; i < n; i++, bi++, info++) { +memcpy (&bi->board_info, info,sizeof (*info)); +mutex_lock (&board_lock); +list_add_tail (&bi->list, &board_list); +spi_scan_masterlist (&bi->board_info); +mutex_unlock (&board_lock); + } +return 0 ; } -/* FIXME someone should add support for a __setup("spi", ...) that +/* +* FIXME someone should add support for a __setup("spi", ...) that * creates board info from kernel command lines +* +* Should be called when board_lock is acquired */ -static void scan_boardinfo (struct spi_master *master) {struct boardinfo *bi; +struct spi_device *dev; -mutex_lock (&board_lock);list_for_each_entry (bi, &board_list, list) { -struct spi_board_info *chip = bi->board_info; -unsigned n; - -for (n = bi->n_board_info; n >0 ; n--, chip++) { -if (chip->bus_num != master->bus_num) -continue ; -/* NOTE: this relies on spi_new_device to -* issue diagnostics when given bogus inputs -*/ - (void )spi_new_device (master, chip); - } +struct spi_board_info *chip = &bi->board_info; + +if (chip->bus_num != master->bus_num) +continue ; + dev =spi_new_device (master, chip); +if (!dev) +dev_err (master->dev.parent, +"can't create new device for %s\n" , + chip->modalias); } -mutex_unlock (&board_lock); }/*-------------------------------------------------------------------------*/
@@ -537,15 +563,17 @@ int spi_register_master(struct spi_master *master)dev_dbg (dev,"registered master %s%s\n" ,dev_name (&master->dev), dynamic ?" (dynamic)" :"" ); -/* populate children from any spi device tables */ +mutex_lock (&board_lock); +list_add_tail (&master->list, &spi_master_list);scan_boardinfo (master); +mutex_unlock (&board_lock); + status =0 ; done:return status; }EXPORT_SYMBOL_GPL (spi_register_master); -static int __unregister (struct device *dev,void *master_dev) {/* note: before about 2.6.14-rc1 this would corrupt memory: */
@@ -568,6 +596,10 @@ void spi_unregister_master(struct spi_master *master) {int dummy; +mutex_lock (&board_lock); +list_del (&master->list); +mutex_unlock (&board_lock); + dummy =device_for_each_child (master->dev.parent, &master->dev, __unregister);device_unregister (&master->dev);
include/linux/spi/spi.h +3 -0
@@ -204,6 +204,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)/** * struct spi_master - interface to SPI master controller * @dev: device interface to this driver +* @list: link with the global spi_master list * @bus_num: board-specific (and often SOC-specific) identifier for a * given SPI controller. * @num_chipselect: chipselects are used to distinguish individual
@@ -235,6 +236,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)struct spi_master {struct device dev; +struct list_head list; +/* other than negative (== assign one dynamically), bus_num is fully * board-specific. usually that simplifies to being SOC-specific. * example: one SOC has three SPI controllers, numbered 0..2,
Signature · 7 lines
1.7.0.4 ------------------------------------------------------------------------------ The Palm PDK Hot Apps Program offers developers who use the Plug-In Development Kit to bring their C/C++ apps to Palm for a share of $1 Million in cash or HP Products. Visit us here for more details: http://p.sf.net/sfu/dev2dev-palm
Quoted 3 lines · Feng Tang
Hi All,
Pls review this patch. thanks,
Hi Feng, Looking good. One more comment below.
Quoted 68 lines
-Feng
Changelog:
v3:
* As suggested by Grant, use one lock to protect the match betweenspi_masterand spi board info
v2:
* fix a typo in loopingscan_masterlist()
* fix one race condition found by GrantFrom
28af337ec89225a0dfb7ca516545b7eff112e3b2Mon Sep 17 00:00:00 2001
From: Feng Tang <[email protected]>
Date: Tue, 27 Jul 2010 17:15:05 +0800
Subject: [PATCH] spi: enablespi_board_infoto be registered afterspi_masterCurrently
spi_register_board_info()has to be called before its relatedspi_masterbe registered, otherwise these board info will be just ignored.This patch will remove this order limit, it adds a global spi master list like the existing global board info listr. Whenever a board info or a
spi_masteris registered, the spi master list or board info list will be scanned, and a new spi device will be created if there is a master-board info match.Cc David Brownell <[email protected]>Cc Grant Likely <grant.likely-s3s/[email protected]>Signed-off-by Feng Tang <[email protected]>---
drivers/spi/spi.c | 84 ++++++++++++++++++++++++++++++++--------------include/linux/spi/spi.h| 3 ++2 files changed, 61 insertions(+), 26 deletions(-)drivers/spi/spi.c +15
-2@@ -196,11 +196,16 @@ EXPORT_SYMBOL_GPL(spi_register_driver); struct boardinfo { struct list_head list; - unsigned n_board_info; - struct spi_board_info board_info[0]; + struct spi_board_info board_info; }; static LIST_HEAD(board_list); +static LIST_HEAD (spi_master_list); + +/* +* Used to protect add/del opertion for board_info list and +* spi_master list, and their matching process +*/ static DEFINE_MUTEX(board_lock); /**@@ -365,6 +370,24 @@ struct spi_device *spi_new_device(struct spi_master *master, } EXPORT_SYMBOL_GPL(spi_new_device); +/* Has to be called when board_lock is acquired */ +static void spi_scan_masterlist (struct spi_board_info *bi) +{ + struct spi_master *master; + struct spi_device *dev; + + list_for_each_entry(master, &spi_master_list, list) { + if (master->bus_num != bi->bus_num)
drivers/spi/spi.c struct spi_device *spi_new_device(struct spi_master *master, · line 390
Quoted 10 lines
drivers/spi/spi.c +10
-0+ continue; + + dev = spi_new_device(master, bi); + if (!dev) + dev_err(master->dev.parent, + "can't create new device for %s\n", + bi->modalias); + } +} +
The abstraction isn't quite at the right place because the same code block is now duplicated twice. Consider the following instead:
static void spi_match_master_to_boardinfo(struct spi_master *master,
struct spi_board_info *bi)
{
struct spi_device *dev;
if (master->bus_num != bi->bus_num)
return;
dev = spi_new_device(master, bi);
if (!dev)
dev_err(master->dev.parent, "can't create new device for %s\n",
bi->modalias);
}And then from spi_register_board_info, do:
list_for_each_entry(master, &spi_master_list, list) spi_match_master_to_boardinfo(master, &bi->boardinfo);
And in spi_register_master, do:
list_for_each_entry(bi, &board_list, list) spi_match_master_to_boardinfo(master, &bi->boardinfo);
It will be less code that way.
Otherwise, this patch looks good to me. Unfortunately, it's too late for 2.6.36, but I'll pick it up into my test branch in prep for the 2.6.37 cycle.
Cheers,
g.
Quoted 127 lines
drivers/spi/spi.c +0
-0/*** spi_register_board_info - register SPI devices for a given board * @info: array of chip descriptors @@ -387,43 +410,46 @@ EXPORT_SYMBOL_GPL(spi_new_device);int
__init
spi_register_board_info(structspi_board_infoconst *info, unsigned n) {
- struct boardinfo *bi;
+ struct boardinfo *bi;
+ int i;- bi =
kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
+ bi =kzalloc(n * sizeof(*bi), GFP_KERNEL);
if (!bi)
return-ENOMEM;
-bi->n_board_info= n;
-memcpy(bi->board_info, info, n * sizeof *info);-
mutex_lock(&board_lock);
-list_add_tail(&bi->list, &board_list);
-mutex_unlock(&board_lock);
+ for (i = 0; i < n; i++, bi++, info++) {
+memcpy(&bi->board_info, info, sizeof(*info));
+mutex_lock(&board_lock);
+list_add_tail(&bi->list, &board_list);
+spi_scan_masterlist(&bi->board_info);
+mutex_unlock(&board_lock);
+ }
+
return 0;
}drivers/spi/spi.c +2
-1-/* FIXME someone should add support for a __setup("spi", ...) that +/* +* FIXME someone should add support for a __setup("spi", ...) that * creates board info from kernel command lines
+ *
+ * Should be called whenboard_lockis acquired */
-
static voidscan_boardinfo(struct spi_master *master){
struct boardinfo *bi;
+ structspi_device*dev;-
mutex_lock(&board_lock);list_for_each_entry(bi, &board_list, list){
- structspi_board_info*chip =bi->board_info;
- unsigned n;drivers/spi/spi.c +9
-9- - for (n = bi->n_board_info; n > 0; n--, chip++) { - if (chip->bus_num != master->bus_num) - continue; - /* NOTE: this relies on spi_new_device to - * issue diagnostics when given bogus inputs - */ - (void) spi_new_device(master, chip); - } + struct spi_board_info *chip = &bi->board_info; + + if (chip->bus_num != master->bus_num) + continue; + dev = spi_new_device(master, chip); + if (!dev) + dev_err(master->dev.parent, + "can't create new device for %s\n", + chip->modalias);}
-mutex_unlock(&board_lock);
}/*-------------------------------------------------------------------------*/
drivers/spi/spi.c +4
-1@@ -537,15 +563,17 @@ int spi_register_master(struct spi_master *master) dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev), dynamic ? " (dynamic)" : ""); - /* populate children from any spi device tables */ + mutex_lock(&board_lock); + list_add_tail(&master->list, &spi_master_list); scan_boardinfo(master); + mutex_unlock(&board_lock); + status = 0;done:
return status;
}
EXPORT_SYMBOL_GPL(spi_register_master);-
static int__unregister(struct device *dev, void *master_dev){
/* note: before about 2.6.14-rc1 this would corrupt memory: */drivers/spi/spi.c +4
-0@@ -568,6 +596,10 @@ void spi_unregister_master(struct spi_master *master) { int dummy; + mutex_lock(&board_lock); + list_del(&master->list); + mutex_unlock(&board_lock); + dummy = device_for_each_child(master->dev.parent, &master->dev, __unregister); device_unregister(&master->dev);include/linux/spi/spi.h +3
-1@@ -204,6 +204,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) /*** struct spi_master - interface to SPI master controller * @dev: device interface to this driver +* @list: link with the global spi_master list * @bus_num: board-specific (and often SOC-specific) identifier for a * given SPI controller. * @num_chipselect: chipselects are used to distinguish individual @@ -235,6 +236,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) struct spi_master { struct device dev; + struct list_head list; + /* other than negative (== assign one dynamically), bus_num is fully * board-specific. usually that simplifies to being SOC-specific. * example: one SOC has three SPI controllers, numbered 0..2, -- 1.7.0.4
Signature · 8 lines
Grant Likely, B.Sc., P.Eng. Secret Lab Technologies Ltd. ------------------------------------------------------------------------------ The Palm PDK Hot Apps Program offers developers who use the Plug-In Development Kit to bring their C/C++ apps to Palm for a share of $1 Million in cash or HP Products. Visit us here for more details: http://p.sf.net/sfu/dev2dev-palm
A message that is not in the archive (sent off-list or not yet received): AANLkTi=dEQ9oRi-NOi=oyab3yBeX7HWDOqs+pS5=-Bix-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org
Quoted 51 lines · On Mon, 2 Aug 2010 13:53:25 +0800 Grant Likely…
Quoted 13 lines
/**
drivers/spi/spi.c +8
-0@@ -365,6 +370,24 @@ struct spi_device *spi_new_device(struct spi_master *master, } EXPORT_SYMBOL_GPL(spi_new_device); +/* Has to be called when board_lock is acquired */ +static void spi_scan_masterlist (struct spi_board_info *bi) +{ + struct spi_master *master; + struct spi_device *dev; + + list_for_each_entry(master, &spi_master_list, list) { + if (master->bus_num != bi->bus_num)drivers/spi/spi.c struct spi_device *spi_new_device(struct · line 390
Quoted 10 lines
drivers/spi/spi.c +10
-0+ continue; + + dev = spi_new_device(master, bi); + if (!dev) + dev_err(master->dev.parent, + "can't create new device for %s\n", + bi->modalias); + } +} +The abstraction isn't quite at the right place because the same code block is now duplicated twice. Consider the following instead:
static void spi_match_master_to_boardinfo(struct
spi_master*master,
structspi_board_info*bi){ struct spi_device *dev; if (master->bus_num != bi->bus_num) return; dev = spi_new_device(master, bi); if (!dev) dev_err(master->dev.parent, "can't create new devicefor %s\n",
bi->modalias);
}And then from
spi_register_board_info, do:list_for_each_entry(master, &spi_master_list, list) spi_match_master_to_boardinfo(master, &bi->boardinfo);And in
spi_register_master, do:list_for_each_entry(bi, &board_list, list) spi_match_master_to_boardinfo(master, &bi->boardinfo);
Quoted 8 lines
It will be less code that way.
Otherwise, this patch looks good to me. Unfortunately, it's too late for 2.6.36, but I'll pick it up into my test branch in prep for the 2.6.37 cycle.
Cheers,
g.
Yeah, make much sense! Thanks for the thorough reviews.
- Feng
------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the Plug-In Development Kit to bring their C/C++ apps to Palm for a share of $1 Million in cash or HP Products. Visit us here for more details:
http://p.sf.net/sfu/dev2dev-palm