* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <20071216052308.A0FB11668D7-ZcXrCSuhvln6VZ3dlLfH/g4gEjPzgfUyLrfjE7I9kuVHxeISYlDBzl6hYfS7NtTn@public.gmane.org> @ 2007-12-27 20:58 ` Byron Bradley [not found] ` <57e2b00712271258l6ea661ai2bfd6b9e099c71be-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: Byron Bradley @ 2007-12-27 20:58 UTC (permalink / raw) To: David Brownell Cc: timtimred-f/KTTADhmRsdnm+yROfE0A, i2c-GZX6beZjE8VD60Wz+7aTrA On Dec 16, 2007 5:23 AM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > This adds a i2c_new_dummy() primitive to help work with devices > that consume multiple addresses, which include many I2C eeproms > and at least one RTC. > > Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> For the S35390A RTC driver I called i2c_new_dummy() in the probe function in a similar style to the at24 eeprom driver. This failed because the probe function is called inside an i2c_attach_device() which has already locked &adap->clist_lock. When you call the i2c_new_dummy() function it will itself call i2c_attach_device() but it will never be able to acquire &adap->clist_lock. Below is the lock detection and backtrace. ============================================= [ INFO: possible recursive locking detected ] 2.6.24-rc5-g7fffe9cc-dirty #38 --------------------------------------------- swapper/1 is trying to acquire lock: (&adap->clist_lock){--..}, at: [<c02b1ba4>] i2c_attach_client+0x28/0x1e8 but task is already holding lock: (&adap->clist_lock){--..}, at: [<c02b1ba4>] i2c_attach_client+0x28/0x1e8 other info that might help us debug this: 3 locks held by swapper/1: #0: (core_lists){--..}, at: [<c02b2294>] i2c_register_adapter+0x50/0x26c #1: (__i2c_board_lock){--..}, at: [<c02b23c4>] i2c_register_adapter+0x180/0x26c #2: (&adap->clist_lock){--..}, at: [<c02b1ba4>] i2c_attach_client+0x28/0x1e8 stack backtrace: [<c002df24>] (dump_stack+0x0/0x14) from [<c0067330>] (__lock_acquire+0x92c/0x10cc) [<c0066a04>] (__lock_acquire+0x0/0x10cc) from [<c0067b38>] (lock_acquire+0x68/0x80) [<c0067ad0>] (lock_acquire+0x0/0x80) from [<c035b880>] (mutex_lock_nested+0x9c/0x2cc) r7:c7c16000 r6:c7c18000 r5:60000013 r4:c7e0e4e8 [<c035b7e4>] (mutex_lock_nested+0x0/0x2cc) from [<c02b1ba4>] (i2c_attach_client+0x28/0x1e8) [<c02b1b7c>] (i2c_attach_client+0x0/0x1e8) from [<c02b2204>] (i2c_new_device+0xa8/0xe8) [<c02b215c>] (i2c_new_device+0x0/0xe8) from [<c02b26cc>] (i2c_new_dummy+0xb0/0xdc) r6:c7e0e488 r5:c036f848 r4:00000000 [<c02b261c>] (i2c_new_dummy+0x0/0xdc) from [<c02b0558>] (s35390a_probe+0x9c/0x330) r6:c7e0e800 r5:c7cbab00 r4:00000001 [<c02b04bc>] (s35390a_probe+0x0/0x330) from [<c02b0b08>] (i2c_device_probe+0x54/0x5c) r7:c0232b64 r6:c044721c r5:c7e0e828 r4:c7e0e800 [<c02b0ab4>] (i2c_device_probe+0x0/0x5c) from [<c0232a50>] (driver_probe_device+0xac/0x1c0) r6:c0447248 r5:c7c19d0c r4:c7e0e828 [<c02329a4>] (driver_probe_device+0x0/0x1c0) from [<c0232b74>] (__device_attach+0x10/0x14) r8:c7e0e628 r7:c0232b64 r6:c7e0e828 r5:c7c19d0c r4:00000000 [<c0232b64>] (__device_attach+0x0/0x14) from [<c0231b94>] (bus_for_each_drv+0x5c/0x88) [<c0231b38>] (bus_for_each_drv+0x0/0x88) from [<c0232c48>] (device_attach+0xa4/0xb0) r7:c7e0e530 r6:00000000 r5:c7e0e93c r4:c7e0e828 [<c0232ba4>] (device_attach+0x0/0xb0) from [<c0231af8>] (bus_attach_device+0x48/0x88) r5:c7e0e828 r4:c04473b0 [<c0231ab0>] (bus_attach_device+0x0/0x88) from [<c0230710>] (device_add+0x470/0x5e8) r5:c7e0e828 r4:c7e0e828 [<c02302a0>] (device_add+0x0/0x5e8) from [<c02308a8>] (device_register+0x20/0x24) [<c0230888>] (device_register+0x0/0x24) from [<c02b1c6c>] (i2c_attach_client+0xf0/0x1e8) r4:c7e0e920 [<c02b1b7c>] (i2c_attach_client+0x0/0x1e8) from [<c02b2204>] (i2c_new_device+0xa8/0xe8) [<c02b215c>] (i2c_new_device+0x0/0xe8) from [<c02b240c>] (i2c_register_adapter+0x1c8/0x26c) r6:c044733c r5:c7e0e488 r4:c7c0a240 [<c02b2244>] (i2c_register_adapter+0x0/0x26c) from [<c02b256c>] (i2c_add_numbered_adapter+0xbc/0x) r8:c042df28 r7:c042df34 r6:00000020 r5:c7e0e488 r4:00000000 [<c02b24b0>] (i2c_add_numbered_adapter+0x0/0xcc) from [<c02b467c>] (mv64xxx_i2c_probe+0x174/0x228) r5:c042dc28 r4:c7e0e400 [<c02b4508>] (mv64xxx_i2c_probe+0x0/0x228) from [<c02344dc>] (platform_drv_probe+0x20/0x24) [<c02344bc>] (platform_drv_probe+0x0/0x24) from [<c0232a50>] (driver_probe_device+0xac/0x1c0) [<c02329a4>] (driver_probe_device+0x0/0x1c0) from [<c0232d58>] (__driver_attach+0x104/0x10c) r8:c04421a8 r7:c0232c54 r6:c04478f4 r5:c042dc30 r4:c042dd44 [<c0232c54>] (__driver_attach+0x0/0x10c) from [<c0231d00>] (bus_for_each_dev+0x54/0x80) r6:c04478f4 r5:c7c19ef4 r4:00000000 [<c0231cac>] (bus_for_each_dev+0x0/0x80) from [<c02328b8>] (driver_attach+0x20/0x28) r7:c0023eb4 r6:00000000 r5:c04478f4 r4:c04478fc [<c0232898>] (driver_attach+0x0/0x28) from [<c0232104>] (bus_add_driver+0x84/0x1e0) [<c0232080>] (bus_add_driver+0x0/0x1e0) from [<c0232fac>] (driver_register+0x54/0x90) r8:c7c18000 r7:c0023eb4 r6:00000000 r5:00000000 r4:c04478f4 [<c0232f58>] (driver_register+0x0/0x90) from [<c0234768>] (platform_driver_register+0x6c/0x88) r4:00000000 [<c02346fc>] (platform_driver_register+0x0/0x88) from [<c001e454>] (mv64xxx_i2c_init+0x14/0x1c) [<c001e440>] (mv64xxx_i2c_init+0x0/0x1c) from [<c0008958>] (kernel_init+0x98/0x2ac) [<c00088c0>] (kernel_init+0x0/0x2ac) from [<c00459b8>] (do_exit+0x0/0x810) -- Byron Bradley ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <57e2b00712271258l6ea661ai2bfd6b9e099c71be-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <57e2b00712271258l6ea661ai2bfd6b9e099c71be-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2007-12-27 21:53 ` David Brownell [not found] ` <200712271353.05857.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: David Brownell @ 2007-12-27 21:53 UTC (permalink / raw) To: Byron Bradley Cc: timtimred-f/KTTADhmRsdnm+yROfE0A, i2c-GZX6beZjE8VD60Wz+7aTrA On Thursday 27 December 2007, Byron Bradley wrote: > On Dec 16, 2007 5:23 AM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > This adds a i2c_new_dummy() primitive to help work with devices > > that consume multiple addresses, which include many I2C eeproms > > and at least one RTC. > > > > Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> > > For the S35390A RTC driver I called i2c_new_dummy() in the probe > function in a similar style to the at24 eeprom driver. This failed > because the probe function is called inside an i2c_attach_device() > which has already locked &adap->clist_lock. When you call the > i2c_new_dummy() function it will itself call i2c_attach_device() but > it will never be able to acquire &adap->clist_lock. Right ... make the s35390a driver be a new-style driver. Or, Jean has patches in his queue [1] to remove other lists from i2c_core which duplicate driver model core behavior. I think i2c_adapter.children and i2c_adapter.clist_lock have not yet been removed, even though they're redundant given the driver model's device.klist_children records. So if you're ambitious and don't want to just make that RTC driver be a new-style driver, you could just get rid of that functionality duplication. (Me, I'd take the easier route and just make it be a new-style driver!) - Dave [1] http://khali.linux-fr.org/devel/linux-2.6/jdelvare-i2c/ ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200712271353.05857.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <200712271353.05857.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-12-27 22:09 ` Byron Bradley [not found] ` <57e2b00712271409n6c98f76o45116cd92b01f396-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: Byron Bradley @ 2007-12-27 22:09 UTC (permalink / raw) To: David Brownell Cc: timtimred-f/KTTADhmRsdnm+yROfE0A, i2c-GZX6beZjE8VD60Wz+7aTrA On Dec 27, 2007 9:53 PM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > On Thursday 27 December 2007, Byron Bradley wrote: > > On Dec 16, 2007 5:23 AM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > > This adds a i2c_new_dummy() primitive to help work with devices > > > that consume multiple addresses, which include many I2C eeproms > > > and at least one RTC. > > > > > > Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> > > > > For the S35390A RTC driver I called i2c_new_dummy() in the probe > > function in a similar style to the at24 eeprom driver. This failed > > because the probe function is called inside an i2c_attach_device() > > which has already locked &adap->clist_lock. When you call the > > i2c_new_dummy() function it will itself call i2c_attach_device() but > > it will never be able to acquire &adap->clist_lock. > > Right ... make the s35390a driver be a new-style driver. > > Or, Jean has patches in his queue [1] to remove other lists > from i2c_core which duplicate driver model core behavior. > I think i2c_adapter.children and i2c_adapter.clist_lock have > not yet been removed, even though they're redundant given the > driver model's device.klist_children records. > > So if you're ambitious and don't want to just make that RTC > driver be a new-style driver, you could just get rid of that > functionality duplication. (Me, I'd take the easier route and > just make it be a new-style driver!) I believe this is already a new-style driver. It uses the RTC framework, the module init calls i2c_add_driver() and the struct i2c_driver provides a .probe and a .remove function. Is there something else that I'm missing? Thanks, -- Byron Bradley ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <57e2b00712271409n6c98f76o45116cd92b01f396-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <57e2b00712271409n6c98f76o45116cd92b01f396-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2007-12-27 23:06 ` David Brownell [not found] ` <200712271506.43069.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: David Brownell @ 2007-12-27 23:06 UTC (permalink / raw) To: Byron Bradley Cc: timtimred-f/KTTADhmRsdnm+yROfE0A, i2c-GZX6beZjE8VD60Wz+7aTrA On Thursday 27 December 2007, Byron Bradley wrote: > On Dec 27, 2007 9:53 PM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > On Thursday 27 December 2007, Byron Bradley wrote: > > > On Dec 16, 2007 5:23 AM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > > > This adds a i2c_new_dummy() primitive to help work with devices > > > > that consume multiple addresses, which include many I2C eeproms > > > > and at least one RTC. > > > > > > > > Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> > > > > > > For the S35390A RTC driver I called i2c_new_dummy() in the probe > > > function in a similar style to the at24 eeprom driver. This failed > > > because the probe function is called inside an i2c_attach_device() You mean i2c_attach_client() ... > > > which has already locked &adap->clist_lock. When you call the > > > i2c_new_dummy() function it will itself call i2c_attach_device() but > > > it will never be able to acquire &adap->clist_lock. > > > > Right ... make the s35390a driver be a new-style driver. > > > > ... > > > > So if you're ambitious and don't want to just make that RTC > > driver be a new-style driver, you could just get rid of that > > functionality duplication. (Me, I'd take the easier route and > > just make it be a new-style driver!) > > I believe this is already a new-style driver. It uses the RTC > framework, the module init calls i2c_add_driver() and the struct > i2c_driver provides a .probe and a .remove function. Indeed; sorry, I skimmed over that stacktrace too quickly. > Is there something else that I'm missing? I'm not sure yet. I certainly tested that updated at24 driver with lockdep active, and it didn't report such a warning. It's possible lockdep on that platform isn't fully functional yet; I'll see if that problem triggers on a different arch (after some intentional misconfiguration to call this utility). One thing that looks odd in your stack trace is that it shows i2c_attach_client() calling mutex_lock_nested(), which is most certainly not what it does in rc6-git-current ... in fact, a nested call is made (rather curiously) only in i2c_transfer(). Do you have other I2C patches that may be causing problems? - Dave ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200712271506.43069.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <200712271506.43069.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-12-27 23:37 ` Byron Bradley 2007-12-27 23:59 ` David Brownell 1 sibling, 0 replies; 43+ messages in thread From: Byron Bradley @ 2007-12-27 23:37 UTC (permalink / raw) To: David Brownell Cc: timtimred-f/KTTADhmRsdnm+yROfE0A, i2c-GZX6beZjE8VD60Wz+7aTrA On Dec 27, 2007 11:06 PM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > On Thursday 27 December 2007, Byron Bradley wrote: > > On Dec 27, 2007 9:53 PM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > > On Thursday 27 December 2007, Byron Bradley wrote: > > > > On Dec 16, 2007 5:23 AM, David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > > > > This adds a i2c_new_dummy() primitive to help work with devices > > > > > that consume multiple addresses, which include many I2C eeproms > > > > > and at least one RTC. > > > > > > > > > > Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> > > > > > > > > For the S35390A RTC driver I called i2c_new_dummy() in the probe > > > > function in a similar style to the at24 eeprom driver. This failed > > > > because the probe function is called inside an i2c_attach_device() > > You mean i2c_attach_client() ... Yes sorry, not sure where I got device from. > > > > which has already locked &adap->clist_lock. When you call the > > > > i2c_new_dummy() function it will itself call i2c_attach_device() but > > > > it will never be able to acquire &adap->clist_lock. > > > > > > Right ... make the s35390a driver be a new-style driver. > > > > > > ... > > > > > > So if you're ambitious and don't want to just make that RTC > > > driver be a new-style driver, you could just get rid of that > > > functionality duplication. (Me, I'd take the easier route and > > > just make it be a new-style driver!) > > > > I believe this is already a new-style driver. It uses the RTC > > framework, the module init calls i2c_add_driver() and the struct > > i2c_driver provides a .probe and a .remove function. > > Indeed; sorry, I skimmed over that stacktrace too quickly. > > > > Is there something else that I'm missing? > > I'm not sure yet. I certainly tested that updated at24 driver > with lockdep active, and it didn't report such a warning. It's > possible lockdep on that platform isn't fully functional yet; > I'll see if that problem triggers on a different arch (after > some intentional misconfiguration to call this utility). > > One thing that looks odd in your stack trace is that it shows > i2c_attach_client() calling mutex_lock_nested(), which is most > certainly not what it does in rc6-git-current ... in fact, a > nested call is made (rather curiously) only in i2c_transfer(). I'm using the Orion git repo (http://git.kernel.org/?p=linux/kernel/git/nico/orion.git;a=summary) which is being rebased but is currently on 2.6.24-rc5. I will try the latest 2.6-git with the Orion patches and see if that fixes anything. > Do you have other I2C patches that may be causing problems? No other I2C patches. Cheers, -- Byron Bradley ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <200712271506.43069.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-12-27 23:37 ` Byron Bradley @ 2007-12-27 23:59 ` David Brownell 1 sibling, 0 replies; 43+ messages in thread From: David Brownell @ 2007-12-27 23:59 UTC (permalink / raw) To: Byron Bradley Cc: timtimred-f/KTTADhmRsdnm+yROfE0A, i2c-GZX6beZjE8VD60Wz+7aTrA On Thursday 27 December 2007, David Brownell wrote: > > Is there something else that I'm missing? > > I'm not sure yet. I certainly tested that updated at24 driver > with lockdep active, and it didn't report such a warning. It's > possible lockdep on that platform isn't fully functional yet; > I'll see if that problem triggers on a different arch (after > some intentional misconfiguration to call this utility). Just tried it on ARM, and it worked just fine. Lockdep reported no warnings, and that hacked 24c512 EEPROM claims three extra addresses using i2c_new_dummy(). - Dave > One thing that looks odd in your stack trace is that it shows > i2c_attach_client() calling mutex_lock_nested(), which is most > certainly not what it does in rc6-git-current ... in fact, a > nested call is made (rather curiously) only in i2c_transfer(). > > Do you have other I2C patches that may be causing problems? ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200712281230.17840.david-b@pacbell.net>]
[parent not found: <57e2b00712281645y70f6ec74s57945dc53f113ec8@mail.gmail.com>]
[parent not found: <57e2b00712281645y70f6ec74s57945dc53f113ec8-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <57e2b00712281645y70f6ec74s57945dc53f113ec8-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2007-12-30 3:05 ` David Brownell [not found] ` <200712291905.15160.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: David Brownell @ 2007-12-30 3:05 UTC (permalink / raw) To: Byron Bradley; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA > > OK, but why don't I get the warnings you get? > > > > That's not just on ARM, note. > > > > > > Making i2c_attach_client() not use the lock that way should be > > easy enough, I'll have a look at that, but I'm concerned about > > the seeming lockdep misbehavior here... as in, if it gets this > > wrong then how else is it broken and what other bugs has it > > been hiding? I still don't know why you get lockdep warnings and I don't ... but here's a patch that should help, by removing that lock! :) - Dave ================ Remove further duplication between i2c core and driver model: the per-adapter list of clients (adapter->clients, client->list) and its lock (adapter->clist_lock) duplicate adapter->dev.children. LIGHTLY TESTED ... goes on top of two patches from Jean's I2C queue, i2c-remove-redundant-i2c_adapter-list.patch i2c-remove-redundant-i2c_driver-list.patch Continuing in that naming scheme, this might be called i2c-remove-redundant-i2c_client-list.patch --- drivers/i2c/i2c-core.c | 189 ++++++++++++++++++++++--------------------------- drivers/i2c/i2c-dev.c | 33 ++++---- include/linux/i2c.h | 4 - 3 files changed, 102 insertions(+), 124 deletions(-) --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -256,7 +256,6 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { - struct i2c_adapter *adapter = client->adapter; struct i2c_driver *driver = client->driver; if (driver && !is_newstyle_driver(driver)) { @@ -265,11 +264,6 @@ void i2c_unregister_device(struct i2c_cl WARN_ON(1); return; } - - mutex_lock(&adapter->clist_lock); - list_del(&client->list); - mutex_unlock(&adapter->clist_lock); - device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); @@ -381,8 +375,6 @@ static int i2c_register_adapter(struct i int res = 0, dummy; mutex_init(&adap->bus_lock); - mutex_init(&adap->clist_lock); - INIT_LIST_HEAD(&adap->clients); mutex_lock(&core_lists); @@ -525,6 +517,38 @@ static int i2c_do_del_adapter(struct dev return res; } +static struct i2c_client *verify_client(struct device *dev) +{ + if (dev->bus != &i2c_bus_type) + return NULL; + return to_i2c_client(dev); +} + +static int detach_all_clients(struct device *dev, void *x) +{ + struct i2c_client *client = verify_client(dev); + struct i2c_driver *driver; + int res; + + if (!client) + return 0; + + driver = client->driver; + + /* new style, follow standard driver model */ + if (!driver || is_newstyle_driver(driver)) { + i2c_unregister_device(client); + return 0; + } + + /* legacy drivers create and remove clients themselves */ + if ((res = driver->detach_client(client))) + dev_err(dev, "detach_client [%s] failed at address 0x%02x\n", + client->name, client->addr); + + return res; +} + /** * i2c_del_adapter - unregister I2C adapter * @adap: the adapter being unregistered @@ -535,8 +559,6 @@ static int i2c_do_del_adapter(struct dev */ int i2c_del_adapter(struct i2c_adapter *adap) { - struct list_head *item, *_n; - struct i2c_client *client; int res = 0; mutex_lock(&core_lists); @@ -557,26 +579,9 @@ int i2c_del_adapter(struct i2c_adapter * /* detach any active clients. This must be done first, because * it can fail; in which case we give up. */ - list_for_each_safe(item, _n, &adap->clients) { - struct i2c_driver *driver; - - client = list_entry(item, struct i2c_client, list); - driver = client->driver; - - /* new style, follow standard driver model */ - if (!driver || is_newstyle_driver(driver)) { - i2c_unregister_device(client); - continue; - } - - /* legacy drivers create and remove clients themselves */ - if ((res = driver->detach_client(client))) { - dev_err(&adap->dev, "detach_client failed for client " - "[%s] at address 0x%02x\n", client->name, - client->addr); - goto out_unlock; - } - } + res = device_for_each_child(&adap->dev, NULL, detach_all_clients); + if (res) + goto out_unlock; /* clean up the sysfs representation */ init_completion(&adap->dev_released); @@ -655,6 +660,20 @@ int i2c_register_driver(struct module *o } EXPORT_SYMBOL(i2c_register_driver); +static int detach_legacy_clients(struct device *dev, void *driver) +{ + struct i2c_client *client = verify_client(dev); + + if (client && client->driver == driver) { + dev_dbg(dev, "detaching client [%s] at 0x%02x\n", + client->name, client->addr); + if (client->driver->detach_client(client)) + dev_err(dev, "failed detach_client [%s] at 0x%02x\n", + client->name, client->addr); + } + return 0; +} + /** * i2c_del_driver - unregister I2C driver * @driver: the driver being unregistered @@ -662,8 +681,6 @@ EXPORT_SYMBOL(i2c_register_driver); */ void i2c_del_driver(struct i2c_driver *driver) { - struct list_head *item2, *_n; - struct i2c_client *client; struct i2c_adapter *adap; mutex_lock(&core_lists); @@ -684,22 +701,9 @@ void i2c_del_driver(struct i2c_driver *d "for driver [%s]\n", driver->driver.name); } - } else { - list_for_each_safe(item2, _n, &adap->clients) { - client = list_entry(item2, struct i2c_client, list); - if (client->driver != driver) - continue; - dev_dbg(&adap->dev, "detaching client [%s] " - "at 0x%02x\n", client->name, - client->addr); - if (driver->detach_client(client)) { - dev_err(&adap->dev, "detach_client " - "failed for client [%s] at " - "0x%02x\n", client->name, - client->addr); - } - } - } + } else + device_for_each_child(&adap->dev, driver, + detach_legacy_clients); } up(&i2c_adapter_class.sem); @@ -713,28 +717,19 @@ EXPORT_SYMBOL(i2c_del_driver); /* ------------------------------------------------------------------------- */ -static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr) +static int i2c_checkaddr(struct device *dev, void *addrp) { - struct list_head *item; - struct i2c_client *client; + struct i2c_client *client = verify_client(dev); + int addr = *(int *)addrp; - list_for_each(item,&adapter->clients) { - client = list_entry(item, struct i2c_client, list); - if (client->addr == addr) - return -EBUSY; - } + if (client && client->addr == addr) + return -EBUSY; return 0; } static int i2c_check_addr(struct i2c_adapter *adapter, int addr) { - int rval; - - mutex_lock(&adapter->clist_lock); - rval = __i2c_check_addr(adapter, addr); - mutex_unlock(&adapter->clist_lock); - - return rval; + return device_for_each_child(&adapter->dev, &addr, i2c_checkaddr); } int i2c_attach_client(struct i2c_client *client) @@ -742,13 +737,6 @@ int i2c_attach_client(struct i2c_client struct i2c_adapter *adapter = client->adapter; int res = 0; - mutex_lock(&adapter->clist_lock); - if (__i2c_check_addr(client->adapter, client->addr)) { - res = -EBUSY; - goto out_unlock; - } - list_add_tail(&client->list,&adapter->clients); - client->usage_count = 0; client->dev.parent = &client->adapter->dev; @@ -765,12 +753,16 @@ int i2c_attach_client(struct i2c_client snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), "%d-%04x", i2c_adapter_id(adapter), client->addr); + res = device_register(&client->dev); + if (res) { + dev_err(&adapter->dev, + "Failed to register i2c client %s at 0x%02x (%d)\n", + client->name, client->addr, res); + return res; + } + dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", client->name, client->dev.bus_id); - res = device_register(&client->dev); - if (res) - goto out_list; - mutex_unlock(&adapter->clist_lock); if (adapter->client_register) { if (adapter->client_register(client)) { @@ -781,14 +773,6 @@ int i2c_attach_client(struct i2c_client } return 0; - -out_list: - list_del(&client->list); - dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " - "(%d)\n", client->name, client->addr, res); -out_unlock: - mutex_unlock(&adapter->clist_lock); - return res; } EXPORT_SYMBOL(i2c_attach_client); @@ -813,11 +797,8 @@ int i2c_detach_client(struct i2c_client } } - mutex_lock(&adapter->clist_lock); - list_del(&client->list); init_completion(&client->released); device_unregister(&client->dev); - mutex_unlock(&adapter->clist_lock); wait_for_completion(&client->released); out: @@ -873,24 +854,28 @@ int i2c_release_client(struct i2c_client } EXPORT_SYMBOL(i2c_release_client); +struct i2c_cmd_arg { + unsigned cmd; + void *arg; +}; + +static int i2c_cmd(struct device *dev, void *_arg) +{ + struct i2c_client *client = verify_client(dev); + struct i2c_cmd_arg *arg = _arg; + + if (client) + client->driver->command(client, arg->cmd, arg->arg); + return 0; +} + void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) { - struct list_head *item; - struct i2c_client *client; + struct i2c_cmd_arg cmd_arg; - mutex_lock(&adap->clist_lock); - list_for_each(item,&adap->clients) { - client = list_entry(item, struct i2c_client, list); - if (!try_module_get(client->driver->driver.owner)) - continue; - if (NULL != client->driver->command) { - mutex_unlock(&adap->clist_lock); - client->driver->command(client,cmd,arg); - mutex_lock(&adap->clist_lock); - } - module_put(client->driver->driver.owner); - } - mutex_unlock(&adap->clist_lock); + cmd_arg.cmd = cmd; + cmd_arg.arg = arg; + device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd); } EXPORT_SYMBOL(i2c_clients_command); @@ -1151,7 +1136,6 @@ i2c_new_probed_device(struct i2c_adapter return NULL; } - mutex_lock(&adap->clist_lock); for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { /* Check address validity */ if (addr_list[i] < 0x03 || addr_list[i] > 0x77) { @@ -1161,7 +1145,7 @@ i2c_new_probed_device(struct i2c_adapter } /* Check address availability */ - if (__i2c_check_addr(adap, addr_list[i])) { + if (i2c_check_addr(adap, addr_list[i])) { dev_dbg(&adap->dev, "Address 0x%02x already in " "use, not probing\n", addr_list[i]); continue; @@ -1189,7 +1173,6 @@ i2c_new_probed_device(struct i2c_adapter break; } } - mutex_unlock(&adap->clist_lock); if (addr_list[i] == I2C_CLIENT_END) { dev_dbg(&adap->dev, "Probing failed, no device found\n"); --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -182,27 +182,26 @@ static ssize_t i2cdev_write (struct file return ret; } -/* This address checking function differs from the one in i2c-core - in that it considers an address with a registered device, but no - bounded driver, as NOT busy. */ -static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) +static int i2cdev_check(struct device *dev, void *addrp) { - struct list_head *item; struct i2c_client *client; - int res = 0; - mutex_lock(&adapter->clist_lock); - list_for_each(item, &adapter->clients) { - client = list_entry(item, struct i2c_client, list); - if (client->addr == addr) { - if (client->driver) - res = -EBUSY; - break; - } - } - mutex_unlock(&adapter->clist_lock); + if (!dev->bus || strcmp("i2c", dev->bus->name) != 0) + return 0; - return res; + client = to_i2c_client(dev); + if (client->addr != *(unsigned int *)addrp) + return 0; + + return dev->driver ? -EBUSY : 0; +} + +/* This address checking function differs from the one in i2c-core + in that it considers an address with a registered device, but no + driver to it, as NOT busy. */ +static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) +{ + return device_for_each_child(&adapter->dev, &addr, i2cdev_check); } static int i2cdev_ioctl(struct inode *inode, struct file *file, --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -159,7 +159,6 @@ struct i2c_driver { * @irq: indicates the IRQ generated by this device (if any) * @driver_name: Identifies new-style driver used with this device; also * used as the module name for hotplug/coldplug modprobe support. - * @list: list of active/busy clients * @released: used to synchronize client releases & detaches and references * * An i2c_client identifies a single device (i.e. chip) connected to an @@ -179,7 +178,6 @@ struct i2c_client { struct device dev; /* the device structure */ int irq; /* irq issued by device (or -1) */ char driver_name[KOBJ_NAME_LEN]; - struct list_head list; struct completion released; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev) @@ -317,14 +315,12 @@ struct i2c_adapter { /* data fields that are valid for all devices */ u8 level; /* nesting level for lockdep */ struct mutex bus_lock; - struct mutex clist_lock; int timeout; int retries; struct device dev; /* the adapter device */ int nr; - struct list_head clients; char name[48]; struct completion dev_released; }; ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200712291905.15160.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <200712291905.15160.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2008-01-04 22:16 ` Jean Delvare [not found] ` <20080104231633.135f2875-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 2008-01-06 11:23 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare 2008-01-17 22:24 ` [patch 2.6.24-rc5-git] add i2c_new_dummy() utility David Brownell 2 siblings, 1 reply; 43+ messages in thread From: Jean Delvare @ 2008-01-04 22:16 UTC (permalink / raw) To: David Brownell; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA Hi David, On Sat, 29 Dec 2007 19:05:14 -0800, David Brownell wrote: > Remove further duplication between i2c core and driver model: the > per-adapter list of clients (adapter->clients, client->list) and > its lock (adapter->clist_lock) duplicate adapter->dev.children. > > LIGHTLY TESTED ... goes on top of two patches from Jean's I2C queue, > > i2c-remove-redundant-i2c_adapter-list.patch > i2c-remove-redundant-i2c_driver-list.patch > > Continuing in that naming scheme, this might be called > > i2c-remove-redundant-i2c_client-list.patch > > --- > drivers/i2c/i2c-core.c | 189 ++++++++++++++++++++++--------------------------- > drivers/i2c/i2c-dev.c | 33 ++++---- > include/linux/i2c.h | 4 - > 3 files changed, 102 insertions(+), 124 deletions(-) This breaks drivers/media/video/mxb.c, drivers/media/video/dpc7146.c and drivers/media/video/tvmixer.c. These 3 drivers walk the clients list that your patch wants to remove. I guess that we need to replace their code by something equivalent that would walk the driver model's children list instead of i2c-core's internal one? -- Jean Delvare ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <20080104231633.135f2875-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <20080104231633.135f2875-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2008-01-04 23:48 ` David Brownell [not found] ` <200801041548.54825.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: David Brownell @ 2008-01-04 23:48 UTC (permalink / raw) To: Jean Delvare; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA On Friday 04 January 2008, Jean Delvare wrote: > Hi David, > > On Sat, 29 Dec 2007 19:05:14 -0800, David Brownell wrote: > > Remove further duplication between i2c core and driver model: the > > per-adapter list of clients (adapter->clients, client->list) and > > its lock (adapter->clist_lock) duplicate adapter->dev.children. > > > > LIGHTLY TESTED ... goes on top of two patches from Jean's I2C queue, > > > > i2c-remove-redundant-i2c_adapter-list.patch > > i2c-remove-redundant-i2c_driver-list.patch > > > > Continuing in that naming scheme, this might be called > > > > i2c-remove-redundant-i2c_client-list.patch > > > > --- > > drivers/i2c/i2c-core.c | 189 ++++++++++++++++++++++--------------------------- > > drivers/i2c/i2c-dev.c | 33 ++++---- > > include/linux/i2c.h | 4 - > > 3 files changed, 102 insertions(+), 124 deletions(-) > > This breaks drivers/media/video/mxb.c, drivers/media/video/dpc7146.c > and drivers/media/video/tvmixer.c. These 3 drivers walk the clients > list that your patch wants to remove. Whoops. Good thing I warned y'all that it was only lightly tested! Presumably this was the result of a "build every line of I2C code" test. Those all seem to do the same thing: list_for_each_entry() scan to find specific devices connected to their private adapter. > I guess that we need to replace > their code by something equivalent that would walk the driver model's > children list instead of i2c-core's internal one? Like the device_for_each_child() scanning in the i2-core parts of that patch ... yes, that's probably the least invasive change for the moment. Eventually I'd like to see the relevant code using new-style driver binding, but that seems a bit much to change at the moment. Changing the users of i2c_adapter.clients could be safely done before removing that list (and its lock, ignored by most of those drivers if not all of them). Which should simplify testing such changes by a bit. - Dave ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200801041548.54825.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <200801041548.54825.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2008-01-06 9:57 ` Jean Delvare 0 siblings, 0 replies; 43+ messages in thread From: Jean Delvare @ 2008-01-06 9:57 UTC (permalink / raw) To: David Brownell; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA Hi David, On Fri, 4 Jan 2008 15:48:54 -0800, David Brownell wrote: > On Friday 04 January 2008, Jean Delvare wrote: > > This breaks drivers/media/video/mxb.c, drivers/media/video/dpc7146.c > > and drivers/media/video/tvmixer.c. These 3 drivers walk the clients > > list that your patch wants to remove. > > Whoops. Good thing I warned y'all that it was only lightly tested! > Presumably this was the result of a "build every line of I2C code" > test. This is my default build mode ;) I'm doing changes to i2c all the time so I want to know quickly if a given change breaks some driver. > Those all seem to do the same thing: list_for_each_entry() scan to > find specific devices connected to their private adapter. True. > > I guess that we need to replace > > their code by something equivalent that would walk the driver model's > > children list instead of i2c-core's internal one? > > Like the device_for_each_child() scanning in the i2-core parts of > that patch ... yes, that's probably the least invasive change for > the moment. Eventually I'd like to see the relevant code using > new-style driver binding, but that seems a bit much to change at > the moment. That was pretty much my conclusion as well. > Changing the users of i2c_adapter.clients could be safely done > before removing that list (and its lock, ignored by most of > those drivers if not all of them). Which should simplify testing > such changes by a bit. Agreed, I'll write such patches later today and will send them to the v4l list for review and testing. -- Jean Delvare ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200712291905.15160.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2008-01-04 22:16 ` Jean Delvare @ 2008-01-06 11:23 ` Jean Delvare [not found] ` <20080106122356.78556b8a-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 2008-01-17 22:24 ` [patch 2.6.24-rc5-git] add i2c_new_dummy() utility David Brownell 2 siblings, 1 reply; 43+ messages in thread From: Jean Delvare @ 2008-01-06 11:23 UTC (permalink / raw) To: David Brownell; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA Hi David, On Sat, 29 Dec 2007 19:05:14 -0800, David Brownell wrote: > Remove further duplication between i2c core and driver model: the > per-adapter list of clients (adapter->clients, client->list) and > its lock (adapter->clist_lock) duplicate adapter->dev.children. > > LIGHTLY TESTED ... goes on top of two patches from Jean's I2C queue, > > i2c-remove-redundant-i2c_adapter-list.patch > i2c-remove-redundant-i2c_driver-list.patch > > Continuing in that naming scheme, this might be called > > i2c-remove-redundant-i2c_client-list.patch > Review: > --- > drivers/i2c/i2c-core.c | 189 ++++++++++++++++++++++--------------------------- > drivers/i2c/i2c-dev.c | 33 ++++---- > include/linux/i2c.h | 4 - > 3 files changed, 102 insertions(+), 124 deletions(-) > > --- a/drivers/i2c/i2c-core.c > +++ b/drivers/i2c/i2c-core.c > @@ -256,7 +256,6 @@ EXPORT_SYMBOL_GPL(i2c_new_device); > */ > void i2c_unregister_device(struct i2c_client *client) > { > - struct i2c_adapter *adapter = client->adapter; > struct i2c_driver *driver = client->driver; > > if (driver && !is_newstyle_driver(driver)) { > @@ -265,11 +264,6 @@ void i2c_unregister_device(struct i2c_cl > WARN_ON(1); > return; > } > - > - mutex_lock(&adapter->clist_lock); > - list_del(&client->list); > - mutex_unlock(&adapter->clist_lock); > - > device_unregister(&client->dev); > } > EXPORT_SYMBOL_GPL(i2c_unregister_device); > @@ -381,8 +375,6 @@ static int i2c_register_adapter(struct i > int res = 0, dummy; > > mutex_init(&adap->bus_lock); > - mutex_init(&adap->clist_lock); > - INIT_LIST_HEAD(&adap->clients); > > mutex_lock(&core_lists); > > @@ -525,6 +517,38 @@ static int i2c_do_del_adapter(struct dev > return res; > } > > +static struct i2c_client *verify_client(struct device *dev) > +{ > + if (dev->bus != &i2c_bus_type) Is this paranoia, or can this test really succeed? I thought that all children of an i2c adapter node would always be i2c clients. > + return NULL; > + return to_i2c_client(dev); > +} > + > +static int detach_all_clients(struct device *dev, void *x) > +{ > + struct i2c_client *client = verify_client(dev); > + struct i2c_driver *driver; > + int res; > + > + if (!client) > + return 0; > + > + driver = client->driver; > + > + /* new style, follow standard driver model */ > + if (!driver || is_newstyle_driver(driver)) { > + i2c_unregister_device(client); > + return 0; > + } > + > + /* legacy drivers create and remove clients themselves */ > + if ((res = driver->detach_client(client))) > + dev_err(dev, "detach_client [%s] failed at address 0x%02x\n", > + client->name, client->addr); > + > + return res; > +} > + > /** > * i2c_del_adapter - unregister I2C adapter > * @adap: the adapter being unregistered > @@ -535,8 +559,6 @@ static int i2c_do_del_adapter(struct dev > */ > int i2c_del_adapter(struct i2c_adapter *adap) > { > - struct list_head *item, *_n; > - struct i2c_client *client; > int res = 0; > > mutex_lock(&core_lists); > @@ -557,26 +579,9 @@ int i2c_del_adapter(struct i2c_adapter * > > /* detach any active clients. This must be done first, because > * it can fail; in which case we give up. */ > - list_for_each_safe(item, _n, &adap->clients) { > - struct i2c_driver *driver; > - > - client = list_entry(item, struct i2c_client, list); > - driver = client->driver; > - > - /* new style, follow standard driver model */ > - if (!driver || is_newstyle_driver(driver)) { > - i2c_unregister_device(client); > - continue; > - } > - > - /* legacy drivers create and remove clients themselves */ > - if ((res = driver->detach_client(client))) { > - dev_err(&adap->dev, "detach_client failed for client " > - "[%s] at address 0x%02x\n", client->name, > - client->addr); > - goto out_unlock; > - } > - } > + res = device_for_each_child(&adap->dev, NULL, detach_all_clients); > + if (res) > + goto out_unlock; > > /* clean up the sysfs representation */ > init_completion(&adap->dev_released); > @@ -655,6 +660,20 @@ int i2c_register_driver(struct module *o > } > EXPORT_SYMBOL(i2c_register_driver); > > +static int detach_legacy_clients(struct device *dev, void *driver) > +{ > + struct i2c_client *client = verify_client(dev); > + > + if (client && client->driver == driver) { > + dev_dbg(dev, "detaching client [%s] at 0x%02x\n", > + client->name, client->addr); > + if (client->driver->detach_client(client)) > + dev_err(dev, "failed detach_client [%s] at 0x%02x\n", > + client->name, client->addr); > + } > + return 0; > +} > + > /** > * i2c_del_driver - unregister I2C driver > * @driver: the driver being unregistered > @@ -662,8 +681,6 @@ EXPORT_SYMBOL(i2c_register_driver); > */ > void i2c_del_driver(struct i2c_driver *driver) > { > - struct list_head *item2, *_n; > - struct i2c_client *client; > struct i2c_adapter *adap; > > mutex_lock(&core_lists); > @@ -684,22 +701,9 @@ void i2c_del_driver(struct i2c_driver *d > "for driver [%s]\n", > driver->driver.name); > } > - } else { > - list_for_each_safe(item2, _n, &adap->clients) { > - client = list_entry(item2, struct i2c_client, list); > - if (client->driver != driver) > - continue; > - dev_dbg(&adap->dev, "detaching client [%s] " > - "at 0x%02x\n", client->name, > - client->addr); > - if (driver->detach_client(client)) { > - dev_err(&adap->dev, "detach_client " > - "failed for client [%s] at " > - "0x%02x\n", client->name, > - client->addr); > - } > - } > - } > + } else > + device_for_each_child(&adap->dev, driver, > + detach_legacy_clients); > } > up(&i2c_adapter_class.sem); > > @@ -713,28 +717,19 @@ EXPORT_SYMBOL(i2c_del_driver); > > /* ------------------------------------------------------------------------- */ > > -static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr) > +static int i2c_checkaddr(struct device *dev, void *addrp) I don't much like this name, why don't you keep __i2c_check_addr? > { > - struct list_head *item; > - struct i2c_client *client; > + struct i2c_client *client = verify_client(dev); > + int addr = *(int *)addrp; > > - list_for_each(item,&adapter->clients) { > - client = list_entry(item, struct i2c_client, list); > - if (client->addr == addr) > - return -EBUSY; > - } > + if (client && client->addr == addr) > + return -EBUSY; > return 0; > } > > static int i2c_check_addr(struct i2c_adapter *adapter, int addr) > { > - int rval; > - > - mutex_lock(&adapter->clist_lock); > - rval = __i2c_check_addr(adapter, addr); > - mutex_unlock(&adapter->clist_lock); > - > - return rval; > + return device_for_each_child(&adapter->dev, &addr, i2c_checkaddr); > } > > int i2c_attach_client(struct i2c_client *client) > @@ -742,13 +737,6 @@ int i2c_attach_client(struct i2c_client > struct i2c_adapter *adapter = client->adapter; > int res = 0; > > - mutex_lock(&adapter->clist_lock); > - if (__i2c_check_addr(client->adapter, client->addr)) { > - res = -EBUSY; > - goto out_unlock; > - } > - list_add_tail(&client->list,&adapter->clients); > - > client->usage_count = 0; > > client->dev.parent = &client->adapter->dev; > @@ -765,12 +753,16 @@ int i2c_attach_client(struct i2c_client > > snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), > "%d-%04x", i2c_adapter_id(adapter), client->addr); > + res = device_register(&client->dev); > + if (res) { > + dev_err(&adapter->dev, > + "Failed to register i2c client %s at 0x%02x (%d)\n", > + client->name, client->addr, res); > + return res; > + } > + > dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", > client->name, client->dev.bus_id); > - res = device_register(&client->dev); > - if (res) > - goto out_list; > - mutex_unlock(&adapter->clist_lock); > > if (adapter->client_register) { > if (adapter->client_register(client)) { > @@ -781,14 +773,6 @@ int i2c_attach_client(struct i2c_client > } > > return 0; > - > -out_list: > - list_del(&client->list); > - dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " > - "(%d)\n", client->name, client->addr, res); > -out_unlock: > - mutex_unlock(&adapter->clist_lock); > - return res; > } > EXPORT_SYMBOL(i2c_attach_client); > > @@ -813,11 +797,8 @@ int i2c_detach_client(struct i2c_client > } > } > > - mutex_lock(&adapter->clist_lock); > - list_del(&client->list); > init_completion(&client->released); > device_unregister(&client->dev); > - mutex_unlock(&adapter->clist_lock); > wait_for_completion(&client->released); > > out: > @@ -873,24 +854,28 @@ int i2c_release_client(struct i2c_client > } > EXPORT_SYMBOL(i2c_release_client); > > +struct i2c_cmd_arg { > + unsigned cmd; > + void *arg; > +}; > + > +static int i2c_cmd(struct device *dev, void *_arg) > +{ > + struct i2c_client *client = verify_client(dev); > + struct i2c_cmd_arg *arg = _arg; > + > + if (client) > + client->driver->command(client, arg->cmd, arg->arg); client->driver->command may or may not be defined. The original code was checking for this, and so should yours. > + return 0; > +} > + > void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) > { > - struct list_head *item; > - struct i2c_client *client; > + struct i2c_cmd_arg cmd_arg; > > - mutex_lock(&adap->clist_lock); > - list_for_each(item,&adap->clients) { > - client = list_entry(item, struct i2c_client, list); > - if (!try_module_get(client->driver->driver.owner)) > - continue; > - if (NULL != client->driver->command) { > - mutex_unlock(&adap->clist_lock); > - client->driver->command(client,cmd,arg); > - mutex_lock(&adap->clist_lock); > - } > - module_put(client->driver->driver.owner); > - } > - mutex_unlock(&adap->clist_lock); > + cmd_arg.cmd = cmd; > + cmd_arg.arg = arg; > + device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd); > } > EXPORT_SYMBOL(i2c_clients_command); > > @@ -1151,7 +1136,6 @@ i2c_new_probed_device(struct i2c_adapter > return NULL; > } > > - mutex_lock(&adap->clist_lock); > for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { > /* Check address validity */ > if (addr_list[i] < 0x03 || addr_list[i] > 0x77) { > @@ -1161,7 +1145,7 @@ i2c_new_probed_device(struct i2c_adapter > } > > /* Check address availability */ > - if (__i2c_check_addr(adap, addr_list[i])) { > + if (i2c_check_addr(adap, addr_list[i])) { > dev_dbg(&adap->dev, "Address 0x%02x already in " > "use, not probing\n", addr_list[i]); > continue; > @@ -1189,7 +1173,6 @@ i2c_new_probed_device(struct i2c_adapter > break; > } > } > - mutex_unlock(&adap->clist_lock); > > if (addr_list[i] == I2C_CLIENT_END) { > dev_dbg(&adap->dev, "Probing failed, no device found\n"); > --- a/drivers/i2c/i2c-dev.c > +++ b/drivers/i2c/i2c-dev.c > @@ -182,27 +182,26 @@ static ssize_t i2cdev_write (struct file > return ret; > } > > -/* This address checking function differs from the one in i2c-core > - in that it considers an address with a registered device, but no > - bounded driver, as NOT busy. */ > -static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) > +static int i2cdev_check(struct device *dev, void *addrp) > { > - struct list_head *item; > struct i2c_client *client; > - int res = 0; > > - mutex_lock(&adapter->clist_lock); > - list_for_each(item, &adapter->clients) { > - client = list_entry(item, struct i2c_client, list); > - if (client->addr == addr) { > - if (client->driver) > - res = -EBUSY; > - break; > - } > - } > - mutex_unlock(&adapter->clist_lock); > + if (!dev->bus || strcmp("i2c", dev->bus->name) != 0) Please just export i2c_bus_type is you need it, or even verify_client (then renamed to i2c_verify_client)? If the bus type check is really needed then we'll need it for the 3 v4l drivers I mentioned earlier anyway. Alternatively we could write and export an i2c_for_each_client() function doing all the required checks so that drivers don't have to care. What do you think? > + return 0; > > - return res; > + client = to_i2c_client(dev); > + if (client->addr != *(unsigned int *)addrp) > + return 0; > + > + return dev->driver ? -EBUSY : 0; > +} > + > +/* This address checking function differs from the one in i2c-core > + in that it considers an address with a registered device, but no > + driver to it, as NOT busy. */ > +static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) > +{ > + return device_for_each_child(&adapter->dev, &addr, i2cdev_check); > } > > static int i2cdev_ioctl(struct inode *inode, struct file *file, > --- a/include/linux/i2c.h > +++ b/include/linux/i2c.h > @@ -159,7 +159,6 @@ struct i2c_driver { > * @irq: indicates the IRQ generated by this device (if any) > * @driver_name: Identifies new-style driver used with this device; also > * used as the module name for hotplug/coldplug modprobe support. > - * @list: list of active/busy clients > * @released: used to synchronize client releases & detaches and references > * > * An i2c_client identifies a single device (i.e. chip) connected to an > @@ -179,7 +178,6 @@ struct i2c_client { > struct device dev; /* the device structure */ > int irq; /* irq issued by device (or -1) */ > char driver_name[KOBJ_NAME_LEN]; > - struct list_head list; > struct completion released; > }; > #define to_i2c_client(d) container_of(d, struct i2c_client, dev) > @@ -317,14 +315,12 @@ struct i2c_adapter { > /* data fields that are valid for all devices */ > u8 level; /* nesting level for lockdep */ > struct mutex bus_lock; > - struct mutex clist_lock; > > int timeout; > int retries; > struct device dev; /* the adapter device */ > > int nr; > - struct list_head clients; > char name[48]; > struct completion dev_released; > }; The rest looks OK... nice cleanup, thanks for doing this. -- Jean Delvare ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <20080106122356.78556b8a-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080106122356.78556b8a-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2008-01-06 19:30 ` David Brownell [not found] ` <200801061130.31774.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2008-01-06 19:43 ` i2c-remove-redundant-i2c_client-list.patch David Brownell 1 sibling, 1 reply; 43+ messages in thread From: David Brownell @ 2008-01-06 19:30 UTC (permalink / raw) To: Jean Delvare; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA On Sunday 06 January 2008, Jean Delvare wrote: > > +static struct i2c_client *verify_client(struct device *dev) > > +{ > > + if (dev->bus != &i2c_bus_type) > > Is this paranoia, or can this test really succeed? I thought that all > children of an i2c adapter node would always be i2c clients. Let's call it well-founded paranoia. I know that when the SPI code got a "remove class_device" patch, I had to fix an oops caused by an unexpected child ... and at the top of my current GIT snapshot is 911833440b498e3e4fe2f12c1ae2bd44400c7004 which fixed similar oopsing in SCSI. > > @@ -713,28 +717,19 @@ EXPORT_SYMBOL(i2c_del_driver); > > > > /* ------------------------------------------------------------------------- */ > > > > -static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr) > > +static int i2c_checkaddr(struct device *dev, void *addrp) > > I don't much like this name, why don't you keep __i2c_check_addr? Changing it is no problem. I guess the name bothered me too, my working copy uses "i2c_czechaddr", would you believe. ;) > > > > +struct i2c_cmd_arg { > > + unsigned cmd; > > + void *arg; > > +}; > > + > > +static int i2c_cmd(struct device *dev, void *_arg) > > +{ > > + struct i2c_client *client = verify_client(dev); > > + struct i2c_cmd_arg *arg = _arg; > > + > > + if (client) > > + client->driver->command(client, arg->cmd, arg->arg); > > client->driver->command may or may not be defined. The original code > was checking for this, and so should yours. OK. > > --- a/drivers/i2c/i2c-dev.c > > +++ b/drivers/i2c/i2c-dev.c > > ... > > - } > > - mutex_unlock(&adapter->clist_lock); > > + if (!dev->bus || strcmp("i2c", dev->bus->name) != 0) > > Please just export i2c_bus_type is you need it, or even verify_client > (then renamed to i2c_verify_client)? If the bus type check is really > needed then we'll need it for the 3 v4l drivers I mentioned earlier > anyway. Good point. I didn't like this part much, and that function can have other uses. I updated kobj_to_i2c_client() to use it too. > Alternatively we could write and export an i2c_for_each_client() > function doing all the required checks so that drivers don't have to > care. What do you think? Less good. We can't know in advance which things they care about. > > ... > > > > The rest looks OK... nice cleanup, thanks for doing this. It seemed appropriate. :) Though I was a bit worried it might have bugs in it, since all I had time to do was code it, and sanity check it with a couple variants of one new-style config. (I no longer have those monster "build all I2C drivers" configs around.) - Dave ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200801061130.31774.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200801061130.31774.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2008-01-08 14:18 ` Jean Delvare [not found] ` <20080108151817.35e05c6c-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: Jean Delvare @ 2008-01-08 14:18 UTC (permalink / raw) To: David Brownell; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA Hi David, On Sun, 6 Jan 2008 11:30:31 -0800, David Brownell wrote: > On Sunday 06 January 2008, Jean Delvare wrote: > > > +static struct i2c_client *verify_client(struct device *dev) > > > +{ > > > + if (dev->bus != &i2c_bus_type) > > > > Is this paranoia, or can this test really succeed? I thought that all > > children of an i2c adapter node would always be i2c clients. > > Let's call it well-founded paranoia. I know that when the SPI > code got a "remove class_device" patch, I had to fix an oops > caused by an unexpected child ... and at the top of my current > GIT snapshot is 911833440b498e3e4fe2f12c1ae2bd44400c7004 which > fixed similar oopsing in SCSI. OK, fine with me. > > > --- a/drivers/i2c/i2c-dev.c > > > +++ b/drivers/i2c/i2c-dev.c > > > ... > > > - } > > > - mutex_unlock(&adapter->clist_lock); > > > + if (!dev->bus || strcmp("i2c", dev->bus->name) != 0) > > > > Please just export i2c_bus_type is you need it, or even verify_client > > (then renamed to i2c_verify_client)? If the bus type check is really > > needed then we'll need it for the 3 v4l drivers I mentioned earlier > > anyway. > > Good point. I didn't like this part much, and that function can > have other uses. I updated kobj_to_i2c_client() to use it too. I wouldn't change kobj_to_i2c_client(). Drivers using it already know that their kobj is an i2c_client, so there's no need to check for that, and the use cases I've seen are in runtime paths that should be fast, I don't want to slow them down without a good reason. > > Alternatively we could write and export an i2c_for_each_client() > > function doing all the required checks so that drivers don't have to > > care. What do you think? > > Less good. We can't know in advance which things they care about. device_for_each_child() doesn't know either, and lets the caller pass an arbitrary pointer as a parameter to the callbask function. My idea was to do something similar, so i2c_for_each_client() would essentially be a wrapper for device_for_each_child(). Here's what I have: --- drivers/i2c/i2c-core.c | 28 ++++++++++++++++++++++++++++ drivers/i2c/i2c-dev.c | 10 ++++------ drivers/media/video/dpc7146.c | 8 ++------ drivers/media/video/mxb.c | 8 ++------ drivers/media/video/tvmixer.c | 9 +++------ include/linux/i2c.h | 3 +++ 6 files changed, 42 insertions(+), 24 deletions(-) --- linux-2.6.24-rc7.orig/drivers/i2c/i2c-core.c 2008-01-08 14:19:39.000000000 +0100 +++ linux-2.6.24-rc7/drivers/i2c/i2c-core.c 2008-01-08 15:09:38.000000000 +0100 @@ -215,6 +215,34 @@ struct i2c_client *i2c_verify_client(str } EXPORT_SYMBOL(i2c_verify_client); +struct i2c_for_each_client_data { + void *data; + int (*fn)(struct i2c_client *, void *); +}; + +static int __i2c_for_each_client(struct device *dev, void *d) +{ + struct i2c_for_each_client_data *_data = d; + struct i2c_client *client = i2c_verify_client(dev); + + if (!client) + return 0; + + return _data->fn(client, _data->data); +} + +int i2c_for_each_client(struct i2c_adapter *adapter, void *data, + int (*fn)(struct i2c_client *, void *)) +{ + struct i2c_for_each_client_data _data; + + _data.data = data; + _data.fn = fn; + + return device_for_each_child(&adapter->dev, &_data, + __i2c_for_each_client); +} +EXPORT_SYMBOL(i2c_for_each_client); /** * i2c_new_device - instantiate an i2c device for use with a new style driver --- linux-2.6.24-rc7.orig/include/linux/i2c.h 2008-01-08 14:19:15.000000000 +0100 +++ linux-2.6.24-rc7/include/linux/i2c.h 2008-01-08 15:09:34.000000000 +0100 @@ -181,6 +181,9 @@ struct i2c_client { extern struct i2c_client *i2c_verify_client(struct device *dev); +extern int i2c_for_each_client(struct i2c_adapter *adapter, void *data, + int (*fn)(struct i2c_client *, void *)); + static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj) { return i2c_verify_client(container_of(kobj, struct device, kobj)); --- linux-2.6.24-rc7.orig/drivers/media/video/dpc7146.c 2008-01-08 14:37:41.000000000 +0100 +++ linux-2.6.24-rc7/drivers/media/video/dpc7146.c 2008-01-08 14:59:28.000000000 +0100 @@ -87,13 +87,9 @@ struct dpc int cur_input; /* current input */ }; -static int dpc_check_clients(struct device *dev, void *data) +static int dpc_check_clients(struct i2c_client *client, void *data) { struct dpc* dpc = data; - struct i2c_client *client = i2c_verify_client(dev); - - if( !client ) - return 0; if( I2C_SAA7111A == client->addr ) dpc->saa7111a = client; @@ -128,7 +124,7 @@ static int dpc_probe(struct saa7146_dev* } /* loop through all i2c-devices on the bus and look who is there */ - device_for_each_child(&dpc->i2c_adapter.dev, dpc, dpc_check_clients); + i2c_for_each_client(&dpc->i2c_adapter, dpc, dpc_check_clients); /* check if all devices are present */ if( 0 == dpc->saa7111a ) { --- linux-2.6.24-rc7.orig/drivers/media/video/mxb.c 2008-01-08 14:37:33.000000000 +0100 +++ linux-2.6.24-rc7/drivers/media/video/mxb.c 2008-01-08 15:00:12.000000000 +0100 @@ -149,13 +149,9 @@ struct mxb static struct saa7146_extension extension; -static int mxb_check_clients(struct device *dev, void *data) +static int mxb_check_clients(struct i2c_client *client, void *data) { struct mxb* mxb = data; - struct i2c_client *client = i2c_verify_client(dev); - - if( !client ) - return 0; if( I2C_ADDR_TEA6420_1 == client->addr ) mxb->tea6420_1 = client; @@ -218,7 +214,7 @@ static int mxb_probe(struct saa7146_dev* } /* loop through all i2c-devices on the bus and look who is there */ - device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients); + i2c_for_each_client(&mxb->i2c_adapter, mxb, mxb_check_clients); /* check if all devices are present */ if( 0 == mxb->tea6420_1 || 0 == mxb->tea6420_2 || 0 == mxb->tea6415c --- linux-2.6.24-rc7.orig/drivers/media/video/tvmixer.c 2008-01-08 14:34:30.000000000 +0100 +++ linux-2.6.24-rc7/drivers/media/video/tvmixer.c 2008-01-08 15:01:27.000000000 +0100 @@ -235,18 +235,15 @@ static const struct file_operations tvmi /* ----------------------------------------------------------------------- */ -static int __tvmixer_adapters(struct device *dev, void *data) +static int __tvmixer_adapters(struct i2c_client *client, void *data) { - struct i2c_client *client = i2c_verify_client(dev); - - if (client) - tvmixer_clients(client); + tvmixer_clients(client); return 0; } static int tvmixer_adapters(struct i2c_adapter *adap) { - device_for_each_child(&adap->dev, NULL, __tvmixer_adapters); + i2c_for_each_client(adap, NULL, __tvmixer_adapters); return 0; } --- linux-2.6.24-rc7.orig/drivers/i2c/i2c-dev.c 2008-01-08 14:19:15.000000000 +0100 +++ linux-2.6.24-rc7/drivers/i2c/i2c-dev.c 2008-01-08 15:05:25.000000000 +0100 @@ -182,14 +182,12 @@ static ssize_t i2cdev_write (struct file return ret; } -static int i2cdev_check(struct device *dev, void *addrp) +static int i2cdev_check(struct i2c_client *client, void *addrp) { - struct i2c_client *client = i2c_verify_client(dev); - - if (!client || client->addr != *(unsigned int *)addrp) + if (client->addr != *(unsigned int *)addrp) return 0; - return dev->driver ? -EBUSY : 0; + return client->dev.driver ? -EBUSY : 0; } /* This address checking function differs from the one in i2c-core @@ -197,7 +195,7 @@ static int i2cdev_check(struct device *d driver to it, as NOT busy. */ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) { - return device_for_each_child(&adapter->dev, &addr, i2cdev_check); + return i2c_for_each_client(adapter, &addr, i2cdev_check); } static int i2cdev_ioctl(struct inode *inode, struct file *file, Admittedly it will slow down things a bit as each iteration of the loop will have one additional level of indirection. This makes the calling code somewhat simpler though. Whether it is worth the additional runtime cost, I just don't know. What do you think? > Though I was a bit worried it might have bugs in it, since all I had > time to do was code it, and sanity check it with a couple variants of > one new-style config. (I no longer have those monster "build all I2C > drivers" configs around.) I'll give it good testing, don't worry too much about that. -- Jean Delvare ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <20080108151817.35e05c6c-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080108151817.35e05c6c-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2008-01-08 16:20 ` Jean Delvare [not found] ` <20080108172001.33de6afc-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 2008-01-08 18:52 ` i2c-remove-redundant-i2c_client-list.patch David Brownell 2008-01-09 16:09 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare 2 siblings, 1 reply; 43+ messages in thread From: Jean Delvare @ 2008-01-08 16:20 UTC (permalink / raw) To: David Brownell; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA Hi David, On Tue, 8 Jan 2008 15:18:17 +0100, Jean Delvare wrote: > On Sun, 6 Jan 2008 11:30:31 -0800, David Brownell wrote: > > Though I was a bit worried it might have bugs in it, since all I had > > time to do was code it, and sanity check it with a couple variants of > > one new-style config. (I no longer have those monster "build all I2C > > drivers" configs around.) > > I'll give it good testing, don't worry too much about that. Hmm, I get a lockup when removing any legacy chip driver or any bus driver with legacy clients attached. It seems to remove the 1st client (no longer visible in sysfs) but never goes on with the second one. Call Trace: [<ffffffff802bdbd1>] sysfs_addrm_finish+0x191/0x1e0 [<ffffffff8041bca5>] schedule_timeout+0x95/0xd0 [<ffffffff802bdc50>] remove_dir+0x30/0x40 [<ffffffff802bdcb6>] sysfs_remove_dir+0x56/0x70 [<ffffffff8041bab8>] wait_for_common+0xc8/0x130 [<ffffffff80227e40>] default_wake_function+0x0/0x10 [<ffffffff80386e55>] device_del+0x1b5/0x290 [<ffffffff803ae4ce>] i2c_detach_client+0x4e/0x90 [<ffffffff882f0071>] :lm90:lm90_detach_client+0x71/0xa0 [<ffffffff803ae8ff>] detach_all_clients+0x6f/0xb0 [<ffffffff803ae890>] detach_all_clients+0x0/0xb0 [<ffffffff8038674d>] device_for_each_child+0x2d/0x60 [<ffffffff803af315>] i2c_del_adapter+0xa5/0x140 [<ffffffff8800b285>] :i2c_parport:i2c_parport_detach+0x55/0x110 [<ffffffff88000796>] :parport:parport_unregister_driver+0x46/0x80 [<ffffffff8024f001>] sys_delete_module+0x141/0x1e0 [<ffffffff8020b92e>] system_call+0x7e/0x83 Are you certain that it is safe to remove a device's child while walking the list of children? device_for_each_child() relies on a klist_iter, and the documentation of klist_next mentions increasing the reference count of the "active" list item. I would guess that you can't remove a list item while its reference count is not zero, and that would explain the lockup. The original code used list_for_each_safe(), which explicitly allows the removal of the items while walking the list. OTOH the header comment of lib/klist.c says: * The entire point is to provide an interface for iterating over a list * that is safe and allows for modification of the list during the * iteration (e.g. insertion and removal), including modification of the * current node on the list. So it is supposed to work somehow... -- Jean Delvare ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <20080108172001.33de6afc-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080108172001.33de6afc-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2008-01-08 19:12 ` David Brownell [not found] ` <200801081112.46972.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: David Brownell @ 2008-01-08 19:12 UTC (permalink / raw) To: Jean Delvare; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA On Tuesday 08 January 2008, Jean Delvare wrote: > Hi David, > > On Tue, 8 Jan 2008 15:18:17 +0100, Jean Delvare wrote: > > On Sun, 6 Jan 2008 11:30:31 -0800, David Brownell wrote: > > > Though I was a bit worried it might have bugs in it, since all I had > > > time to do was code it, and sanity check it with a couple variants of > > > one new-style config. (I no longer have those monster "build all I2C > > > drivers" configs around.) > > > > I'll give it good testing, don't worry too much about that. > > Hmm, I get a lockup when removing any legacy chip driver or any bus > driver with legacy clients attached. Lockup? More details ... > It seems to remove the 1st client > (no longer visible in sysfs) but never goes on with the second one. > > Call Trace: > [<ffffffff802bdbd1>] sysfs_addrm_finish+0x191/0x1e0 What's it doing at that line in the call? > [<ffffffff8041bca5>] schedule_timeout+0x95/0xd0 This looks like stack garbage... > [<ffffffff802bdc50>] remove_dir+0x30/0x40 > [<ffffffff802bdcb6>] sysfs_remove_dir+0x56/0x70 > [<ffffffff8041bab8>] wait_for_common+0xc8/0x130 > [<ffffffff80227e40>] default_wake_function+0x0/0x10 > [<ffffffff80386e55>] device_del+0x1b5/0x290 > [<ffffffff803ae4ce>] i2c_detach_client+0x4e/0x90 > [<ffffffff882f0071>] :lm90:lm90_detach_client+0x71/0xa0 > [<ffffffff803ae8ff>] detach_all_clients+0x6f/0xb0 > [<ffffffff803ae890>] detach_all_clients+0x0/0xb0 > [<ffffffff8038674d>] device_for_each_child+0x2d/0x60 > [<ffffffff803af315>] i2c_del_adapter+0xa5/0x140 > [<ffffffff8800b285>] :i2c_parport:i2c_parport_detach+0x55/0x110 > [<ffffffff88000796>] :parport:parport_unregister_driver+0x46/0x80 > [<ffffffff8024f001>] sys_delete_module+0x141/0x1e0 > [<ffffffff8020b92e>] system_call+0x7e/0x83 > > Are you certain that it is safe to remove a device's child while > walking the list of children? As you point out below, it's supposed to be safe ... > device_for_each_child() relies on a > klist_iter, and the documentation of klist_next mentions increasing the > reference count of the "active" list item. I would guess that you can't > remove a list item while its reference count is not zero, and that > would explain the lockup. The original code used list_for_each_safe(), > which explicitly allows the removal of the items while walking the list. > > OTOH the header comment of lib/klist.c says: > > * The entire point is to provide an interface for iterating over a list > * that is safe and allows for modification of the list during the > * iteration (e.g. insertion and removal), including modification of the > * current node on the list. > > So it is supposed to work somehow... Yeah, but then again ... the i2c stack does that oddball stuff with complete(&client->released) for legacy drivers, too. That's always been contrary to what the driver model expects, and I never quite bothered to sort out the issues. Maybe this is one of them (sigh). - Dave ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200801081112.46972.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200801081112.46972.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2008-01-08 20:50 ` Jean Delvare [not found] ` <20080108215042.534e32fa-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: Jean Delvare @ 2008-01-08 20:50 UTC (permalink / raw) To: David Brownell; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA On Tue, 8 Jan 2008 11:12:46 -0800, David Brownell wrote: > On Tuesday 08 January 2008, Jean Delvare wrote: > > Hi David, > > > > On Tue, 8 Jan 2008 15:18:17 +0100, Jean Delvare wrote: > > > On Sun, 6 Jan 2008 11:30:31 -0800, David Brownell wrote: > > > > Though I was a bit worried it might have bugs in it, since all I had > > > > time to do was code it, and sanity check it with a couple variants of > > > > one new-style config. (I no longer have those monster "build all I2C > > > > drivers" configs around.) > > > > > > I'll give it good testing, don't worry too much about that. > > > > Hmm, I get a lockup when removing any legacy chip driver or any bus > > driver with legacy clients attached. > > Lockup? More details ... There's not much to say. "rmmod lm90" (or "rmmod i2c-parport") never returns, that's about it. > > It seems to remove the 1st client > > (no longer visible in sysfs) but never goes on with the second one. > > > > Call Trace: > > [<ffffffff802bdbd1>] sysfs_addrm_finish+0x191/0x1e0 > > What's it doing at that line in the call? (From another run, thus the slightly different address:) (gdb) list *(sysfs_addrm_finish+0x191) 0xffffffff802bdc01 is in sysfs_addrm_finish (fs/sysfs/sysfs.h:138). 133 } 134 135 static inline void sysfs_put(struct sysfs_dirent *sd) 136 { 137 if (sd && atomic_dec_and_test(&sd->s_count)) 138 release_sysfs_dirent(sd); 139 } 140 141 /* 142 * inode.c (gdb) If you need more info, feel free to ask. > > [<ffffffff8041bca5>] schedule_timeout+0x95/0xd0 > > This looks like stack garbage... What makes you think so? A second stack trace shows it as well. > > > [<ffffffff802bdc50>] remove_dir+0x30/0x40 > > [<ffffffff802bdcb6>] sysfs_remove_dir+0x56/0x70 > > [<ffffffff8041bab8>] wait_for_common+0xc8/0x130 > > [<ffffffff80227e40>] default_wake_function+0x0/0x10 > > [<ffffffff80386e55>] device_del+0x1b5/0x290 > > [<ffffffff803ae4ce>] i2c_detach_client+0x4e/0x90 > > [<ffffffff882f0071>] :lm90:lm90_detach_client+0x71/0xa0 > > [<ffffffff803ae8ff>] detach_all_clients+0x6f/0xb0 > > [<ffffffff803ae890>] detach_all_clients+0x0/0xb0 > > [<ffffffff8038674d>] device_for_each_child+0x2d/0x60 > > [<ffffffff803af315>] i2c_del_adapter+0xa5/0x140 > > [<ffffffff8800b285>] :i2c_parport:i2c_parport_detach+0x55/0x110 > > [<ffffffff88000796>] :parport:parport_unregister_driver+0x46/0x80 > > [<ffffffff8024f001>] sys_delete_module+0x141/0x1e0 > > [<ffffffff8020b92e>] system_call+0x7e/0x83 > > > > Are you certain that it is safe to remove a device's child while > > walking the list of children? > > As you point out below, it's supposed to be safe ... > > > > device_for_each_child() relies on a > > klist_iter, and the documentation of klist_next mentions increasing the > > reference count of the "active" list item. I would guess that you can't > > remove a list item while its reference count is not zero, and that > > would explain the lockup. The original code used list_for_each_safe(), > > which explicitly allows the removal of the items while walking the list. > > > > OTOH the header comment of lib/klist.c says: > > > > * The entire point is to provide an interface for iterating over a list > > * that is safe and allows for modification of the list during the > > * iteration (e.g. insertion and removal), including modification of the > > * current node on the list. > > > > So it is supposed to work somehow... > > Yeah, but then again ... the i2c stack does that oddball stuff with > complete(&client->released) for legacy drivers, too. That's always > been contrary to what the driver model expects, and I never quite > bothered to sort out the issues. Maybe this is one of them (sigh). I see. I doubt I'll be of much help, as I could never figure out what this completion stuff was for in the first place. -- Jean Delvare ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <20080108215042.534e32fa-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080108215042.534e32fa-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2008-01-08 21:44 ` David Brownell [not found] ` <200801081344.45544.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: David Brownell @ 2008-01-08 21:44 UTC (permalink / raw) To: Jean Delvare; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA On Tuesday 08 January 2008, Jean Delvare wrote: > On Tue, 8 Jan 2008 11:12:46 -0800, David Brownell wrote: > > On Tuesday 08 January 2008, Jean Delvare wrote: > > > On Tue, 8 Jan 2008 15:18:17 +0100, Jean Delvare wrote: > > > > On Sun, 6 Jan 2008 11:30:31 -0800, David Brownell wrote: > > > > > Though I was a bit worried it might have bugs in it, since all I had > > > > > time to do was code it, and sanity check it with a couple variants of > > > > > one new-style config. (I no longer have those monster "build all I2C > > > > > drivers" configs around.) > > > > > > > > I'll give it good testing, don't worry too much about that. > > > > > > Hmm, I get a lockup when removing any legacy chip driver or any bus > > > driver with legacy clients attached. > > > > Lockup? More details ... > > There's not much to say. "rmmod lm90" (or "rmmod i2c-parport") never > returns, that's about it. The rest of the system behaves, or not? A "lockup" to me implies something so catastrophic that the hardware watchdog will soon fire and the system will reboot. I'm guessing that's not the case here. Stil not-good, but not as much of a catastrophe. > > > It seems to remove the 1st client > > > (no longer visible in sysfs) but never goes on with the second one. > > > > > > Call Trace: > > > [<ffffffff802bdbd1>] sysfs_addrm_finish+0x191/0x1e0 > > > > What's it doing at that line in the call? > > (From another run, thus the slightly different address:) > > (gdb) list *(sysfs_addrm_finish+0x191) > 0xffffffff802bdc01 is in sysfs_addrm_finish (fs/sysfs/sysfs.h:138). > 133 } > 134 > 135 static inline void sysfs_put(struct sysfs_dirent *sd) > 136 { > 137 if (sd && atomic_dec_and_test(&sd->s_count)) > 138 release_sysfs_dirent(sd); This isn't wholly meaningful to me. If release_sysfs_dirent() is wedging, then why does the stack show it's sysfs_addrm_finish()? I guess the right question is what's going on where the PC points. :) > 139 } > 140 > 141 /* > 142 * inode.c > (gdb) > > If you need more info, feel free to ask. > > > > [<ffffffff8041bca5>] schedule_timeout+0x95/0xd0 > > > > This looks like stack garbage... > > What makes you think so? A second stack trace shows it as well. Because schedule_timeout() doesn't call into sysfs. :) Some platforms have compiler options to make stack tracing be more sensible -- e.g. to always force frame pointers to be used, so that stackdump utilities don't ever need to guess. > > > device_for_each_child() relies on a > > > klist_iter, and the documentation of klist_next mentions increasing the > > > reference count of the "active" list item. I would guess that you can't > > > remove a list item while its reference count is not zero, and that > > > would explain the lockup. The original code used list_for_each_safe(), > > > which explicitly allows the removal of the items while walking the list. > > > > > > OTOH the header comment of lib/klist.c says: > > > > > > * The entire point is to provide an interface for iterating over a list > > > * that is safe and allows for modification of the list during the > > > * iteration (e.g. insertion and removal), including modification of the > > > * current node on the list. > > > > > > So it is supposed to work somehow... > > > > Yeah, but then again ... the i2c stack does that oddball stuff with > > complete(&client->released) for legacy drivers, too. That's always > > been contrary to what the driver model expects, and I never quite > > bothered to sort out the issues. Maybe this is one of them (sigh). > > I see. I doubt I'll be of much help, as I could never figure out what > this completion stuff was for in the first place. In which case I'm guessing it's stuff Greg did way back in the day. I cc'd him in hope that he can find time to comment on that ... My understanding is that it was written early in sysfs conversions to help ensure sysfs wasn't keeping an open handle on the device. However, that early scheme proved to be quite error prone and now things are set up differently. There was a particularly annoying class of problem with module removal. Devices allocated by a driver needed to be freed by that driver, which implies not unloading any driver's module until device nodes it had allocated were freed. The simple way around that restriction involves never having modules allocate such devices ... clearly not easy for legacy I2C drivers. Another way around it was to synchronize driver removal with the cleanup of those devices. And that's what the current I2C stack is (still) doing for legacy drivers, with that completion logic. - Dave p.s. Greg, for context: there are two patches in Jean's I2C queue to remove some redundant I2C lists, in favor of using versions maintained by i2c-core. $SUBJECT relates to a patch removing a third redundancy: i2c_adapter.clients and i2c_client.list, plus (the original problem) the lock for that list. ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200801081344.45544.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200801081344.45544.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2008-01-08 22:04 ` Greg KH [not found] ` <20080108220445.GB3873-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org> 2008-01-09 13:29 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare 1 sibling, 1 reply; 43+ messages in thread From: Greg KH @ 2008-01-08 22:04 UTC (permalink / raw) To: David Brownell; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA On Tue, Jan 08, 2008 at 01:44:45PM -0800, David Brownell wrote: > On Tuesday 08 January 2008, Jean Delvare wrote: > > > > device_for_each_child() relies on a > > > > klist_iter, and the documentation of klist_next mentions increasing the > > > > reference count of the "active" list item. I would guess that you can't > > > > remove a list item while its reference count is not zero, and that > > > > would explain the lockup. The original code used list_for_each_safe(), > > > > which explicitly allows the removal of the items while walking the list. > > > > > > > > OTOH the header comment of lib/klist.c says: > > > > > > > > ?*??The entire point is to provide an interface for iterating over a list > > > > ?*??that is safe and allows for modification of the list during the > > > > ?*??iteration (e.g. insertion and removal), including modification of the > > > > ?*??current node on the list. > > > > > > > > So it is supposed to work somehow... > > > > > > Yeah, but then again ... the i2c stack does that oddball stuff with > > > complete(&client->released) for legacy drivers, too. That's always > > > been contrary to what the driver model expects, and I never quite > > > bothered to sort out the issues. Maybe this is one of them (sigh). > > > > I see. I doubt I'll be of much help, as I could never figure out what > > this completion stuff was for in the first place. > > In which case I'm guessing it's stuff Greg did way back in the day. > I cc'd him in hope that he can find time to comment on that ... Ick, sorry about that mess :( > My understanding is that it was written early in sysfs conversions > to help ensure sysfs wasn't keeping an open handle on the device. > However, that early scheme proved to be quite error prone and now > things are set up differently. There was a particularly annoying > class of problem with module removal. Devices allocated by a driver > needed to be freed by that driver, which implies not unloading any > driver's module until device nodes it had allocated were freed. Yes, that should not be used anymore, and I thought we had removed it for some reason. I guess I was just wishing it were so... > The simple way around that restriction involves never having modules > allocate such devices ... clearly not easy for legacy I2C drivers. > Another way around it was to synchronize driver removal with the > cleanup of those devices. And that's what the current I2C stack is > (still) doing for legacy drivers, with that completion logic. > > - Dave > > p.s. Greg, for context: there are two patches in Jean's I2C queue > to remove some redundant I2C lists, in favor of using versions > maintained by i2c-core. $SUBJECT relates to a patch removing > a third redundancy: i2c_adapter.clients and i2c_client.list, > plus (the original problem) the lock for that list. That sounds like a good idea, if the above race doesn't happen :) Anything I can do to help out? thanks, greg k-h ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <20080108220445.GB3873-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080108220445.GB3873-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org> @ 2008-01-08 22:27 ` David Brownell 0 siblings, 0 replies; 43+ messages in thread From: David Brownell @ 2008-01-08 22:27 UTC (permalink / raw) To: Greg KH; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA On Tuesday 08 January 2008, Greg KH wrote: > > > > > So it is supposed to work somehow... > > > > > > > > Yeah, but then again ... the i2c stack does that oddball stuff with > > > > complete(&client->released) for legacy drivers, too. Also the i2c_adapter devices, which might have a similar issue lurking... > > > > That's always > > > > been contrary to what the driver model expects, and I never quite > > > > bothered to sort out the issues. Maybe this is one of them (sigh). > > > > > > I see. I doubt I'll be of much help, as I could never figure out what > > > this completion stuff was for in the first place. > > > > In which case I'm guessing it's stuff Greg did way back in the day. > > I cc'd him in hope that he can find time to comment on that ... > > Ick, sorry about that mess :( I was *hoping* for more than just sympathy! ;) > > My understanding is that it was written early in sysfs conversions > > to help ensure sysfs wasn't keeping an open handle on the device. > > However, that early scheme proved to be quite error prone and now > > things are set up differently. There was a particularly annoying > > class of problem with module removal. Devices allocated by a driver > > needed to be freed by that driver, which implies not unloading any > > driver's module until device nodes it had allocated were freed. > > Yes, that should not be used anymore, and I thought we had removed it > for some reason. I guess I was just wishing it were so... Do you remember any particular details about how it all got removed? Like in particular: > > The simple way around that restriction involves never having modules > > allocate such devices ... clearly not easy for legacy I2C drivers. Was there a better solution than that near-term unattractive one? It involves changing lots of legacy I2C code, making them provide proper remove methods and thus changing memory management policy ... Error prone, needs to be done slowly. > > Another way around it was to synchronize driver removal with the > > cleanup of those devices. And that's what the current I2C stack is > > (still) doing for legacy drivers, with that completion logic. > > > > - Dave > > > > p.s. Greg, for context: there are two patches in Jean's I2C queue > > to remove some redundant I2C lists, in favor of using versions > > maintained by i2c-core. $SUBJECT relates to a patch removing > > a third redundancy: i2c_adapter.clients and i2c_client.list, > > plus (the original problem) the lock for that list. > > That sounds like a good idea, if the above race doesn't happen :) > > Anything I can do to help out? Verify that could cause the hang Jean observed ... you're more on top of this driver model stuff than most folk. :) I'll forward you my copies of the three patches, so you can apply them and see the basic results of the cleanups. Then have a look and see if you agree with me about that one solution being "near-term unattractive", or can otherwise suggest a clean solution. - Dave ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200801081344.45544.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2008-01-08 22:04 ` i2c-remove-redundant-i2c_client-list.patch Greg KH @ 2008-01-09 13:29 ` Jean Delvare [not found] ` <20080109142906.23a55f5f-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 1 sibling, 1 reply; 43+ messages in thread From: Jean Delvare @ 2008-01-09 13:29 UTC (permalink / raw) To: David Brownell; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA Hi David, On Tue, 8 Jan 2008 13:44:45 -0800, David Brownell wrote: > On Tuesday 08 January 2008, Jean Delvare wrote: > > On Tue, 8 Jan 2008 11:12:46 -0800, David Brownell wrote: > > > On Tuesday 08 January 2008, Jean Delvare wrote: > > > > Hmm, I get a lockup when removing any legacy chip driver or any bus > > > > driver with legacy clients attached. > > > > > > Lockup? More details ... > > > > There's not much to say. "rmmod lm90" (or "rmmod i2c-parport") never > > returns, that's about it. > > The rest of the system behaves, or not? A "lockup" to me implies > something so catastrophic that the hardware watchdog will soon fire > and the system will reboot. > > I'm guessing that's not the case here. Stil not-good, but not as > much of a catastrophe. Sorry for being vague. Yes, the rest of the system behaves, only the "rmmod" process is stuck. > This isn't wholly meaningful to me. If release_sysfs_dirent() is > wedging, then why does the stack show it's sysfs_addrm_finish()? > I guess the right question is what's going on where the PC points. :) How do I know? I'm using SysRq+t to get the stack trace, it doesn't seem to give me any extra information. > > > > [<ffffffff8041bca5>] schedule_timeout+0x95/0xd0 > > > > > > This looks like stack garbage... > > > > What makes you think so? A second stack trace shows it as well. > > Because schedule_timeout() doesn't call into sysfs. :) True, but OTOH there are so many ways callback can be stored for later use that I am no longer surprised when I see apparently unrelated functions call each other ;) > Some platforms have compiler options to make stack tracing be > more sensible -- e.g. to always force frame pointers to be used, > so that stackdump utilities don't ever need to guess. I rebuilt my kernel with CONFIG_STACKTRACE=y and CONFIG_FRAME_POINTER=y, hopefully that's what you were thinking about. Here's what I get with these options: rmmod D 0000000000000002 0 4221 4204 ffff81002345bcd8 0000000000000046 ffff8100234ab080 ffff81003f848040 ffff81002345bd08 ffffffff80252327 0000000200000001 7fffffffffffffff 7fffffffffffffff ffff81002d1e6b60 ffff81002d1e6b58 0000000000000002 Call Trace: [<ffffffff80252327>] __lock_acquire+0x967/0x1080 [<ffffffff80443215>] schedule_timeout+0x95/0xd0 [<ffffffff8044545b>] _spin_unlock_irq+0x2b/0x40 [<ffffffff80251485>] trace_hardirqs_on+0xd5/0x170 [<ffffffff8044545b>] _spin_unlock_irq+0x2b/0x40 [<ffffffff8044301f>] wait_for_common+0xdf/0x150 [<ffffffff802292a0>] default_wake_function+0x0/0x10 [<ffffffff804430f8>] wait_for_completion+0x18/0x20 [<ffffffff803ce894>] i2c_detach_client+0x54/0x90 [<ffffffff88309071>] :lm90:lm90_detach_client+0x71/0x90 [<ffffffff803cd85c>] detach_legacy_clients+0x8c/0xc0 [<ffffffff803cd7d0>] detach_legacy_clients+0x0/0xc0 [<ffffffff803a4f13>] device_for_each_child+0x33/0x60 [<ffffffff803cebe6>] i2c_del_driver+0x126/0x140 [<ffffffff88309f10>] :lm90:sensors_lm90_exit+0x10/0x12 [<ffffffff8025a51c>] sys_delete_module+0x13c/0x1e0 [<ffffffff80251485>] trace_hardirqs_on+0xd5/0x170 [<ffffffff80444ada>] trace_hardirqs_on_thunk+0x35/0x3a [<ffffffff8020ba3e>] system_call+0x7e/0x83 Does it make more sense? The odd thing is: (gdb) list *(__lock_acquire+0x967) 0xffffffff80252327 is in __lock_acquire (kernel/lockdep.c:2353). 2348 * We maintain the dependency maps and validate the locking attempt: 2349 */ 2350 static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, 2351 int trylock, int read, int check, int hardirqs_off, 2352 unsigned long ip) 2353 { 2354 struct task_struct *curr = current; 2355 struct lock_class *class = NULL; 2356 struct held_lock *hlock; 2357 unsigned int depth, id; (gdb) Not sure how it can block on an opening curly brace ;) Maybe I should disable CONFIG_LOCKDEP for now. -- Jean Delvare ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <20080109142906.23a55f5f-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080109142906.23a55f5f-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2008-01-09 16:19 ` Jean Delvare [not found] ` <20080109171934.4f894bdc-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: Jean Delvare @ 2008-01-09 16:19 UTC (permalink / raw) To: David Brownell; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA On Wed, 9 Jan 2008 14:29:06 +0100, Jean Delvare wrote: > I rebuilt my kernel with CONFIG_STACKTRACE=y and > CONFIG_FRAME_POINTER=y, hopefully that's what you were thinking about. > Here's what I get with these options: > > rmmod D 0000000000000002 0 4221 4204 > ffff81002345bcd8 0000000000000046 ffff8100234ab080 ffff81003f848040 > ffff81002345bd08 ffffffff80252327 0000000200000001 7fffffffffffffff > 7fffffffffffffff ffff81002d1e6b60 ffff81002d1e6b58 0000000000000002 > Call Trace: > [<ffffffff80252327>] __lock_acquire+0x967/0x1080 > [<ffffffff80443215>] schedule_timeout+0x95/0xd0 > [<ffffffff8044545b>] _spin_unlock_irq+0x2b/0x40 > [<ffffffff80251485>] trace_hardirqs_on+0xd5/0x170 > [<ffffffff8044545b>] _spin_unlock_irq+0x2b/0x40 > [<ffffffff8044301f>] wait_for_common+0xdf/0x150 > [<ffffffff802292a0>] default_wake_function+0x0/0x10 > [<ffffffff804430f8>] wait_for_completion+0x18/0x20 > [<ffffffff803ce894>] i2c_detach_client+0x54/0x90 > [<ffffffff88309071>] :lm90:lm90_detach_client+0x71/0x90 > [<ffffffff803cd85c>] detach_legacy_clients+0x8c/0xc0 > [<ffffffff803cd7d0>] detach_legacy_clients+0x0/0xc0 > [<ffffffff803a4f13>] device_for_each_child+0x33/0x60 > [<ffffffff803cebe6>] i2c_del_driver+0x126/0x140 > [<ffffffff88309f10>] :lm90:sensors_lm90_exit+0x10/0x12 > [<ffffffff8025a51c>] sys_delete_module+0x13c/0x1e0 > [<ffffffff80251485>] trace_hardirqs_on+0xd5/0x170 > [<ffffffff80444ada>] trace_hardirqs_on_thunk+0x35/0x3a > [<ffffffff8020ba3e>] system_call+0x7e/0x83 > > Does it make more sense? The odd thing is: > > (gdb) list *(__lock_acquire+0x967) > 0xffffffff80252327 is in __lock_acquire (kernel/lockdep.c:2353). > 2348 * We maintain the dependency maps and validate the locking attempt: > 2349 */ > 2350 static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, > 2351 int trylock, int read, int check, int hardirqs_off, > 2352 unsigned long ip) > 2353 { > 2354 struct task_struct *curr = current; > 2355 struct lock_class *class = NULL; > 2356 struct held_lock *hlock; > 2357 unsigned int depth, id; > (gdb) > > Not sure how it can block on an opening curly brace ;) Maybe I should > disable CONFIG_LOCKDEP for now. Here's what I get with CONFIG_LOCKDEP=n: rmmod D ffffffff804365c0 0 4198 4181 ffff81002db39cd8 0000000000000082 ffff81002d907100 ffff81003f83d7e0 ffff81003c5d0370 ffff81002db39d08 ffff81002d8408f8 7fffffffffffffff 7fffffffffffffff ffff81002d840a38 0000000000000002 ffff81002db39d58 Call Trace: [<ffffffff80423c15>] schedule_timeout+0x95/0xd0 [<ffffffff802bfa30>] sysfs_remove_dir+0x60/0x80 [<ffffffff80308029>] kobject_put+0x19/0x20 [<ffffffff80423a28>] wait_for_common+0xc8/0x130 [<ffffffff80228330>] default_wake_function+0x0/0x10 [<ffffffff80423af8>] wait_for_completion+0x18/0x20 [<ffffffff803b4fd4>] i2c_detach_client+0x54/0x90 [<ffffffff882f4071>] :lm90:lm90_detach_client+0x71/0x90 [<ffffffff803b3fbc>] detach_legacy_clients+0x8c/0xc0 [<ffffffff803b3f30>] detach_legacy_clients+0x0/0xc0 [<ffffffff8038cbb3>] device_for_each_child+0x33/0x60 [<ffffffff803b531c>] i2c_del_driver+0x11c/0x140 [<ffffffff882f4f00>] :lm90:sensors_lm90_exit+0x10/0x12 [<ffffffff802501d2>] sys_delete_module+0x132/0x1d0 [<ffffffff8020b99e>] system_call+0x7e/0x83 (gdb) list *(schedule_timeout+0x95) 0xffffffff80423c15 is in schedule_timeout (kernel/timer.c:1059). 1054 * in the caller. Nothing more. We could take 1055 * MAX_SCHEDULE_TIMEOUT from one of the negative value 1056 * but I' d like to return a valid offset (>=0) to allow 1057 * the caller to do everything it want with the retval. 1058 */ 1059 schedule(); 1060 goto out; 1061 default: 1062 /* 1063 * Another bit of PARANOID. Note that the retval will be (gdb) Hope it helps, -- Jean Delvare ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <20080109171934.4f894bdc-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080109171934.4f894bdc-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2008-01-09 21:21 ` David Brownell [not found] ` <200801091321.29212.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: David Brownell @ 2008-01-09 21:21 UTC (permalink / raw) To: Jean Delvare; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA On Wednesday 09 January 2008, Jean Delvare wrote: > Here's what I get with CONFIG_LOCKDEP=n: OK, that's more like I'd expect. Essentially a self-deadlock: - increment usecount on the device - call i2c_detach_client(), which waits till usecount falls to zero and then frees the device (because this is a legacy driver) - expect to *then* be able to decrement the usecount, and continue Yuck. > rmmod D ffffffff804365c0 0 4198 4181 > ffff81002db39cd8 0000000000000082 ffff81002d907100 ffff81003f83d7e0 > ffff81003c5d0370 ffff81002db39d08 ffff81002d8408f8 7fffffffffffffff > 7fffffffffffffff ffff81002d840a38 0000000000000002 ffff81002db39d58 > Call Trace: > [<ffffffff80423c15>] schedule_timeout+0x95/0xd0 ... the schedule() call, which will be left when someone issues the completion being waited for ... > [<ffffffff802bfa30>] sysfs_remove_dir+0x60/0x80 > [<ffffffff80308029>] kobject_put+0x19/0x20 > [<ffffffff80423a28>] wait_for_common+0xc8/0x130 > [<ffffffff80228330>] default_wake_function+0x0/0x10 > [<ffffffff80423af8>] wait_for_completion+0x18/0x20 ... but that completion can never arrive ... > [<ffffffff803b4fd4>] i2c_detach_client+0x54/0x90 > [<ffffffff882f4071>] :lm90:lm90_detach_client+0x71/0x90 > [<ffffffff803b3fbc>] detach_legacy_clients+0x8c/0xc0 > [<ffffffff803b3f30>] detach_legacy_clients+0x0/0xc0 > [<ffffffff8038cbb3>] device_for_each_child+0x33/0x60 ... since this iteration holds the refount it won't yet drop ... > [<ffffffff803b531c>] i2c_del_driver+0x11c/0x140 > [<ffffffff882f4f00>] :lm90:sensors_lm90_exit+0x10/0x12 > [<ffffffff802501d2>] sys_delete_module+0x132/0x1d0 > [<ffffffff8020b99e>] system_call+0x7e/0x83 Right now I'm thinking that we'll need a multi-phase approach: (a) Start phasing out users of i2c_client.list and its lock, ASAP; merging those DVB driver patches, and some i2c-core changes. (b) But don't remove that list from the deletion path until ... (c) ... We have a solution that removes that wait_for_completion() and its infrastructure. (Note the similar i2c_adapter logic too, sigh.) (d) Meanwhile, come up with a different solution to the deadlock observed with i2c_adapter.clist ... which for some unknown reason has *NOT* shown up for me with lockdep. Of course, if (c) happens soon soon, this problem simplifies. And maybe someone will come up with a non-invasive solution to that problem ... but if nobody does so before, say, Monday, I'm thinking that (d) becomes a priority. - Dave ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200801091321.29212.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200801091321.29212.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2008-01-10 13:31 ` Jean Delvare [not found] ` <20080110143105.456ddaf0-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 2008-01-17 19:35 ` i2c-remove-redundant-i2c_client-list.patch David Brownell 1 sibling, 1 reply; 43+ messages in thread From: Jean Delvare @ 2008-01-10 13:31 UTC (permalink / raw) To: David Brownell; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA On Wed, 9 Jan 2008 13:21:28 -0800, David Brownell wrote: > Right now I'm thinking that we'll need a multi-phase approach: > > (a) Start phasing out users of i2c_client.list and its lock, ASAP; > merging those DVB driver patches, and some i2c-core changes. Fine with me. Can you please send the i2c-core patch? It would include i2c_verify_client(), then I can deal with the V4L drivers patch and these 2 patches can be pushed to -mm quickly. > (b) But don't remove that list from the deletion path until ... > > (c) ... We have a solution that removes that wait_for_completion() > and its infrastructure. (Note the similar i2c_adapter logic > too, sigh.) > > (d) Meanwhile, come up with a different solution to the deadlock > observed with i2c_adapter.clist ... which for some unknown > reason has *NOT* shown up for me with lockdep. > > Of course, if (c) happens soon soon, this problem simplifies. And > maybe someone will come up with a non-invasive solution to that > problem ... but if nobody does so before, say, Monday, I'm thinking > that (d) becomes a priority. I won't be able to help with this as I don't understand it fully, sorry. But I can do any amount of testing if someone sends patches. -- Jean Delvare ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <20080110143105.456ddaf0-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080110143105.456ddaf0-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2008-01-14 22:20 ` David Brownell [not found] ` <200801141420.49274.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2008-01-14 22:42 ` i2c-remove-redundant-i2c_client-list.patch David Brownell 1 sibling, 1 reply; 43+ messages in thread From: David Brownell @ 2008-01-14 22:20 UTC (permalink / raw) To: Jean Delvare; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA On Thursday 10 January 2008, Jean Delvare wrote: > On Wed, 9 Jan 2008 13:21:28 -0800, David Brownell wrote: > > Right now I'm thinking that we'll need a multi-phase approach: > > > > (a) Start phasing out users of i2c_client.list and its lock, ASAP; > > merging those DVB driver patches, and some i2c-core changes. > > Fine with me. Can you please send the i2c-core patch? It would include > i2c_verify_client(), then I can deal with the V4L drivers patch and > these 2 patches can be pushed to -mm quickly. OK, here's the trimmed-down patch that leaves the deletion paths untouched until we have a better solution. I've only build-tested it, but it's basically $SUBJECT without those troublesome paths. - Dave ======= CUT HERE The i2c_adapter.clients list of i2c_client nodes duplicates driver model state. This patch starts removing that list, letting us remove most existing users of those i2c-core lists. * The core I2C code now iterates over the driver model's list instead of the i2c-internal one in some places where it's safe: - Passing a command/ioctl to each client, a mechanims used almost exclusively by DVB adapters; - Device address checking, in both i2c-core and i2c-dev. * Provide i2c_verify_client() to use with driver model iterators. * Flag the relevant i2c_adapter and i2c_client fields as deprecated, to help prevent new users from appearing. For the moment the list needs to stick around, since some issues show up when deleting devices created by legacy I2C drivers. (They don't follow standard driver model rules. Removing those devices can cause self-deadlocks.) Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> --- drivers/i2c/i2c-core.c | 78 ++++++++++++++++++++++++++++--------------------- drivers/i2c/i2c-dev.c | 29 +++++++----------- include/linux/i2c.h | 8 +++-- 3 files changed, 63 insertions(+), 52 deletions(-) --- at91.orig/drivers/i2c/i2c-core.c 2008-01-14 13:56:28.000000000 -0800 +++ at91/drivers/i2c/i2c-core.c 2008-01-14 14:01:50.000000000 -0800 @@ -197,6 +197,25 @@ static struct bus_type i2c_bus_type = { .resume = i2c_device_resume, }; + +/** + * i2c_verify_client - return parameter as i2c_client, or NULL + * @dev: device, probably from some driver model iterator + * + * When traversing the driver model tree, perhaps using driver model + * iterators like @device_for_each_child(), you can't assume very much + * about the nodes you find. Use this function to avoid oopses caused + * by wrongly treating some non-I2C device as an i2c_client. + */ +struct i2c_client *i2c_verify_client(struct device *dev) +{ + return (dev->bus == &i2c_bus_type) + ? to_i2c_client(dev) + : NULL; +} +EXPORT_SYMBOL(i2c_verify_client); + + /** * i2c_new_device - instantiate an i2c device for use with a new style driver * @adap: the adapter managing the device @@ -713,28 +732,19 @@ EXPORT_SYMBOL(i2c_del_driver); /* ------------------------------------------------------------------------- */ -static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr) +static int __i2c_check_addr(struct device *dev, void *addrp) { - struct list_head *item; - struct i2c_client *client; + struct i2c_client *client = i2c_verify_client(dev); + int addr = *(int *)addrp; - list_for_each(item,&adapter->clients) { - client = list_entry(item, struct i2c_client, list); - if (client->addr == addr) - return -EBUSY; - } + if (client && client->addr == addr) + return -EBUSY; return 0; } static int i2c_check_addr(struct i2c_adapter *adapter, int addr) { - int rval; - - mutex_lock(&adapter->clist_lock); - rval = __i2c_check_addr(adapter, addr); - mutex_unlock(&adapter->clist_lock); - - return rval; + return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); } int i2c_attach_client(struct i2c_client *client) @@ -743,7 +753,7 @@ int i2c_attach_client(struct i2c_client int res = 0; mutex_lock(&adapter->clist_lock); - if (__i2c_check_addr(client->adapter, client->addr)) { + if (i2c_check_addr(client->adapter, client->addr)) { res = -EBUSY; goto out_unlock; } @@ -873,24 +883,28 @@ int i2c_release_client(struct i2c_client } EXPORT_SYMBOL(i2c_release_client); +struct i2c_cmd_arg { + unsigned cmd; + void *arg; +}; + +static int i2c_cmd(struct device *dev, void *_arg) +{ + struct i2c_client *client = i2c_verify_client(dev); + struct i2c_cmd_arg *arg = _arg; + + if (client && client->driver && client->driver->command) + client->driver->command(client, arg->cmd, arg->arg); + return 0; +} + void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) { - struct list_head *item; - struct i2c_client *client; + struct i2c_cmd_arg cmd_arg; - mutex_lock(&adap->clist_lock); - list_for_each(item,&adap->clients) { - client = list_entry(item, struct i2c_client, list); - if (!try_module_get(client->driver->driver.owner)) - continue; - if (NULL != client->driver->command) { - mutex_unlock(&adap->clist_lock); - client->driver->command(client,cmd,arg); - mutex_lock(&adap->clist_lock); - } - module_put(client->driver->driver.owner); - } - mutex_unlock(&adap->clist_lock); + cmd_arg.cmd = cmd; + cmd_arg.arg = arg; + device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd); } EXPORT_SYMBOL(i2c_clients_command); @@ -1161,7 +1175,7 @@ i2c_new_probed_device(struct i2c_adapter } /* Check address availability */ - if (__i2c_check_addr(adap, addr_list[i])) { + if (i2c_check_addr(adap, addr_list[i])) { dev_dbg(&adap->dev, "Address 0x%02x already in " "use, not probing\n", addr_list[i]); continue; --- at91.orig/drivers/i2c/i2c-dev.c 2008-01-14 13:54:05.000000000 -0800 +++ at91/drivers/i2c/i2c-dev.c 2008-01-14 14:03:43.000000000 -0800 @@ -182,27 +182,22 @@ static ssize_t i2cdev_write (struct file return ret; } +static int i2cdev_check(struct device *dev, void *addrp) +{ + struct i2c_client *client = i2c_verify_client(dev); + + if (!client || client->addr != *(unsigned int *)addrp) + return 0; + + return dev->driver ? -EBUSY : 0; +} + /* This address checking function differs from the one in i2c-core in that it considers an address with a registered device, but no - bounded driver, as NOT busy. */ + driver bound to it, as NOT busy. */ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) { - struct list_head *item; - struct i2c_client *client; - int res = 0; - - mutex_lock(&adapter->clist_lock); - list_for_each(item, &adapter->clients) { - client = list_entry(item, struct i2c_client, list); - if (client->addr == addr) { - if (client->driver) - res = -EBUSY; - break; - } - } - mutex_unlock(&adapter->clist_lock); - - return res; + return device_for_each_child(&adapter->dev, &addr, i2cdev_check); } static int i2cdev_ioctl(struct inode *inode, struct file *file, --- at91.orig/include/linux/i2c.h 2008-01-14 13:56:28.000000000 -0800 +++ at91/include/linux/i2c.h 2008-01-14 13:56:29.000000000 -0800 @@ -159,7 +159,7 @@ struct i2c_driver { * @irq: indicates the IRQ generated by this device (if any) * @driver_name: Identifies new-style driver used with this device; also * used as the module name for hotplug/coldplug modprobe support. - * @list: list of active/busy clients + * @list: list of active/busy clients (DEPRECATED) * @released: used to synchronize client releases & detaches and references * * An i2c_client identifies a single device (i.e. chip) connected to an @@ -179,11 +179,13 @@ struct i2c_client { struct device dev; /* the device structure */ int irq; /* irq issued by device (or -1) */ char driver_name[KOBJ_NAME_LEN]; - struct list_head list; + struct list_head list; /* DEPRECATED */ struct completion released; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev) +extern struct i2c_client *i2c_verify_client(struct device *dev); + static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj) { struct device * const dev = container_of(kobj, struct device, kobj); @@ -324,7 +326,7 @@ struct i2c_adapter { struct device dev; /* the adapter device */ int nr; - struct list_head clients; + struct list_head clients; /* DEPRECATED */ char name[48]; struct completion dev_released; }; _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200801141420.49274.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200801141420.49274.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2008-01-17 22:02 ` Jean Delvare 2008-01-18 10:14 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare 1 sibling, 0 replies; 43+ messages in thread From: Jean Delvare @ 2008-01-17 22:02 UTC (permalink / raw) To: David Brownell; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA Hi David, On Mon, 14 Jan 2008 14:20:48 -0800, David Brownell wrote: > OK, here's the trimmed-down patch that leaves the deletion > paths untouched until we have a better solution. I've only > build-tested it, but it's basically $SUBJECT without those > troublesome paths. > > - Dave > > ======= CUT HERE > The i2c_adapter.clients list of i2c_client nodes duplicates driver > model state. This patch starts removing that list, letting us remove > most existing users of those i2c-core lists. > > * The core I2C code now iterates over the driver model's list instead > of the i2c-internal one in some places where it's safe: > - Passing a command/ioctl to each client, a mechanims > used almost exclusively by DVB adapters; > - Device address checking, in both i2c-core and i2c-dev. > > * Provide i2c_verify_client() to use with driver model iterators. > > * Flag the relevant i2c_adapter and i2c_client fields as deprecated, > to help prevent new users from appearing. > > For the moment the list needs to stick around, since some issues show > up when deleting devices created by legacy I2C drivers. (They don't > follow standard driver model rules. Removing those devices can cause > self-deadlocks.) > > Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> > --- > drivers/i2c/i2c-core.c | 78 ++++++++++++++++++++++++++++--------------------- > drivers/i2c/i2c-dev.c | 29 +++++++----------- > include/linux/i2c.h | 8 +++-- > 3 files changed, 63 insertions(+), 52 deletions(-) Looks good to me, I've applied that. I was about to suggest possible improvements with regards to locking scope but I see that you have already submitted an incremental patch so I'll review it first. I've given some testing to this patch and I didn't see any problem. Thanks, -- Jean Delvare _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200801141420.49274.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2008-01-17 22:02 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare @ 2008-01-18 10:14 ` Jean Delvare [not found] ` <20080118111401.7ffdccc5-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 1 sibling, 1 reply; 43+ messages in thread From: Jean Delvare @ 2008-01-18 10:14 UTC (permalink / raw) To: David Brownell; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA Hi David, On Mon, 14 Jan 2008 14:20:48 -0800, David Brownell wrote: > OK, here's the trimmed-down patch that leaves the deletion > paths untouched until we have a better solution. I've only > build-tested it, but it's basically $SUBJECT without those > troublesome paths. > > - Dave > > ======= CUT HERE > The i2c_adapter.clients list of i2c_client nodes duplicates driver > model state. This patch starts removing that list, letting us remove > most existing users of those i2c-core lists. > > * The core I2C code now iterates over the driver model's list instead > of the i2c-internal one in some places where it's safe: > - Passing a command/ioctl to each client, a mechanims > used almost exclusively by DVB adapters; > - Device address checking, in both i2c-core and i2c-dev. > > * Provide i2c_verify_client() to use with driver model iterators. > > * Flag the relevant i2c_adapter and i2c_client fields as deprecated, > to help prevent new users from appearing. > > For the moment the list needs to stick around, since some issues show > up when deleting devices created by legacy I2C drivers. (They don't > follow standard driver model rules. Removing those devices can cause > self-deadlocks.) > > Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> > --- > drivers/i2c/i2c-core.c | 78 ++++++++++++++++++++++++++++--------------------- > drivers/i2c/i2c-dev.c | 29 +++++++----------- > include/linux/i2c.h | 8 +++-- > 3 files changed, 63 insertions(+), 52 deletions(-) > > --- at91.orig/drivers/i2c/i2c-core.c 2008-01-14 13:56:28.000000000 -0800 > +++ at91/drivers/i2c/i2c-core.c 2008-01-14 14:01:50.000000000 -0800 > (...) > @@ -713,28 +732,19 @@ EXPORT_SYMBOL(i2c_del_driver); > > /* ------------------------------------------------------------------------- */ > > -static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr) > +static int __i2c_check_addr(struct device *dev, void *addrp) > { > - struct list_head *item; > - struct i2c_client *client; > + struct i2c_client *client = i2c_verify_client(dev); > + int addr = *(int *)addrp; > > - list_for_each(item,&adapter->clients) { > - client = list_entry(item, struct i2c_client, list); > - if (client->addr == addr) > - return -EBUSY; > - } > + if (client && client->addr == addr) > + return -EBUSY; > return 0; > } > > static int i2c_check_addr(struct i2c_adapter *adapter, int addr) > { > - int rval; > - > - mutex_lock(&adapter->clist_lock); > - rval = __i2c_check_addr(adapter, addr); > - mutex_unlock(&adapter->clist_lock); > - > - return rval; > + return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); > } > > int i2c_attach_client(struct i2c_client *client) With this patch applied, any reason why i2c_new_probed_device() still acquires adapter->clist_lock? My understanding is that it was there because i2c_check_addr() was originally walking the internal client list, but as this is no longer the case, the locking is no longer needed, is it? Thanks, -- Jean Delvare _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <20080118111401.7ffdccc5-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080118111401.7ffdccc5-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2008-01-18 10:30 ` David Brownell 0 siblings, 0 replies; 43+ messages in thread From: David Brownell @ 2008-01-18 10:30 UTC (permalink / raw) To: Jean Delvare; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA On Friday 18 January 2008, Jean Delvare wrote: > > static int i2c_check_addr(struct i2c_adapter *adapter, int addr) > > { > > - int rval; > > - > > - mutex_lock(&adapter->clist_lock); > > - rval = __i2c_check_addr(adapter, addr); > > - mutex_unlock(&adapter->clist_lock); > > - > > - return rval; > > + return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); > > } > > > > int i2c_attach_client(struct i2c_client *client) > > With this patch applied, any reason why i2c_new_probed_device() still > acquires adapter->clist_lock? My understanding is that it was there > because i2c_check_addr() was originally walking the internal client > list, but as this is no longer the case, the locking is no longer > needed, is it? Doesn't look needed now, no. It previously called __i2c_check_addr(), which needed that lock; could have used the non-underscore version all along. - Dave _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080110143105.456ddaf0-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 2008-01-14 22:20 ` i2c-remove-redundant-i2c_client-list.patch David Brownell @ 2008-01-14 22:42 ` David Brownell 1 sibling, 0 replies; 43+ messages in thread From: David Brownell @ 2008-01-14 22:42 UTC (permalink / raw) To: Jean Delvare; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA On Thursday 10 January 2008, Jean Delvare wrote: > > (b) But don't remove that list from the deletion path until ... > > > > (c) ... We have a solution that removes that wait_for_completion() > > and its infrastructure. (Note the similar i2c_adapter logic > > too, sigh.) > > > > (d) Meanwhile, come up with a different solution to the deadlock > > observed with i2c_adapter.clist ... which for some unknown > > reason has *NOT* shown up for me with lockdep. > > > > Of course, if (c) happens soon soon, this problem simplifies. And > > maybe someone will come up with a non-invasive solution to that > > problem ... but if nobody does so before, say, Monday, I'm thinking > > that (d) becomes a priority. Oh, and for the record ... here's the part of $SUBJECT patch that does (b) without (c). No (d) yet, sigh. I suspect a few of these cleanups could become mergable with some work, but certainly not all of them. Goes on top of what I just posted. - Dave ============= CUT Finish removing i2c_adapter.clients and its support. NOTE: this has self-deadlock issues with legacy drivers. The issue seems to be an obsolete idiom whereby code deleting devices (in i2c-core both i2c_client and i2c_adapter nodes have this problem) waits for a completion event as a kind of synchronization. That's problematic since the driver model turns that kind of synchronization into a self-deadlock. --- drivers/i2c/i2c-core.c | 126 +++++++++++++++++++++---------------------------- include/linux/i2c.h | 4 - 2 files changed, 54 insertions(+), 76 deletions(-) --- at91.orig/drivers/i2c/i2c-core.c 2008-01-14 14:32:00.000000000 -0800 +++ at91/drivers/i2c/i2c-core.c 2008-01-14 14:32:19.000000000 -0800 @@ -275,7 +275,6 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { - struct i2c_adapter *adapter = client->adapter; struct i2c_driver *driver = client->driver; if (driver && !is_newstyle_driver(driver)) { @@ -284,11 +283,6 @@ void i2c_unregister_device(struct i2c_cl WARN_ON(1); return; } - - mutex_lock(&adapter->clist_lock); - list_del(&client->list); - mutex_unlock(&adapter->clist_lock); - device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); @@ -400,8 +394,6 @@ static int i2c_register_adapter(struct i int res = 0, dummy; mutex_init(&adap->bus_lock); - mutex_init(&adap->clist_lock); - INIT_LIST_HEAD(&adap->clients); mutex_lock(&core_lists); @@ -544,6 +536,32 @@ static int i2c_do_del_adapter(struct dev return res; } + +static int detach_all_clients(struct device *dev, void *x) +{ + struct i2c_client *client = i2c_verify_client(dev); + struct i2c_driver *driver; + int res; + + if (!client) + return 0; + + driver = client->driver; + + /* new style, follow standard driver model */ + if (!driver || is_newstyle_driver(driver)) { + i2c_unregister_device(client); + return 0; + } + + /* legacy drivers create and remove clients themselves */ + if ((res = driver->detach_client(client))) + dev_err(dev, "detach_client [%s] failed at address 0x%02x\n", + client->name, client->addr); + + return res; +} + /** * i2c_del_adapter - unregister I2C adapter * @adap: the adapter being unregistered @@ -554,8 +572,6 @@ static int i2c_do_del_adapter(struct dev */ int i2c_del_adapter(struct i2c_adapter *adap) { - struct list_head *item, *_n; - struct i2c_client *client; int res = 0; mutex_lock(&core_lists); @@ -576,26 +592,9 @@ int i2c_del_adapter(struct i2c_adapter * /* detach any active clients. This must be done first, because * it can fail; in which case we give up. */ - list_for_each_safe(item, _n, &adap->clients) { - struct i2c_driver *driver; - - client = list_entry(item, struct i2c_client, list); - driver = client->driver; - - /* new style, follow standard driver model */ - if (!driver || is_newstyle_driver(driver)) { - i2c_unregister_device(client); - continue; - } - - /* legacy drivers create and remove clients themselves */ - if ((res = driver->detach_client(client))) { - dev_err(&adap->dev, "detach_client failed for client " - "[%s] at address 0x%02x\n", client->name, - client->addr); - goto out_unlock; - } - } + res = device_for_each_child(&adap->dev, NULL, detach_all_clients); + if (res) + goto out_unlock; /* clean up the sysfs representation */ init_completion(&adap->dev_released); @@ -674,6 +673,20 @@ int i2c_register_driver(struct module *o } EXPORT_SYMBOL(i2c_register_driver); +static int detach_legacy_clients(struct device *dev, void *driver) +{ + struct i2c_client *client = i2c_verify_client(dev); + + if (client && client->driver == driver) { + dev_dbg(dev, "detaching client [%s] at 0x%02x\n", + client->name, client->addr); + if (client->driver->detach_client(client)) + dev_err(dev, "failed detach_client [%s] at 0x%02x\n", + client->name, client->addr); + } + return 0; +} + /** * i2c_del_driver - unregister I2C driver * @driver: the driver being unregistered @@ -681,8 +694,6 @@ EXPORT_SYMBOL(i2c_register_driver); */ void i2c_del_driver(struct i2c_driver *driver) { - struct list_head *item2, *_n; - struct i2c_client *client; struct i2c_adapter *adap; mutex_lock(&core_lists); @@ -703,22 +714,9 @@ void i2c_del_driver(struct i2c_driver *d "for driver [%s]\n", driver->driver.name); } - } else { - list_for_each_safe(item2, _n, &adap->clients) { - client = list_entry(item2, struct i2c_client, list); - if (client->driver != driver) - continue; - dev_dbg(&adap->dev, "detaching client [%s] " - "at 0x%02x\n", client->name, - client->addr); - if (driver->detach_client(client)) { - dev_err(&adap->dev, "detach_client " - "failed for client [%s] at " - "0x%02x\n", client->name, - client->addr); - } - } - } + } else + device_for_each_child(&adap->dev, driver, + detach_legacy_clients); } up(&i2c_adapter_class.sem); @@ -752,13 +750,6 @@ int i2c_attach_client(struct i2c_client struct i2c_adapter *adapter = client->adapter; int res = 0; - mutex_lock(&adapter->clist_lock); - if (i2c_check_addr(client->adapter, client->addr)) { - res = -EBUSY; - goto out_unlock; - } - list_add_tail(&client->list,&adapter->clients); - client->usage_count = 0; client->dev.parent = &client->adapter->dev; @@ -775,12 +766,16 @@ int i2c_attach_client(struct i2c_client snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), "%d-%04x", i2c_adapter_id(adapter), client->addr); + res = device_register(&client->dev); + if (res) { + dev_err(&adapter->dev, + "Failed to register i2c client %s at 0x%02x (%d)\n", + client->name, client->addr, res); + return res; + } + dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", client->name, client->dev.bus_id); - res = device_register(&client->dev); - if (res) - goto out_list; - mutex_unlock(&adapter->clist_lock); if (adapter->client_register) { if (adapter->client_register(client)) { @@ -791,14 +786,6 @@ int i2c_attach_client(struct i2c_client } return 0; - -out_list: - list_del(&client->list); - dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " - "(%d)\n", client->name, client->addr, res); -out_unlock: - mutex_unlock(&adapter->clist_lock); - return res; } EXPORT_SYMBOL(i2c_attach_client); @@ -823,11 +810,8 @@ int i2c_detach_client(struct i2c_client } } - mutex_lock(&adapter->clist_lock); - list_del(&client->list); init_completion(&client->released); device_unregister(&client->dev); - mutex_unlock(&adapter->clist_lock); wait_for_completion(&client->released); out: @@ -1165,7 +1149,6 @@ i2c_new_probed_device(struct i2c_adapter return NULL; } - mutex_lock(&adap->clist_lock); for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { /* Check address validity */ if (addr_list[i] < 0x03 || addr_list[i] > 0x77) { @@ -1203,7 +1186,6 @@ i2c_new_probed_device(struct i2c_adapter break; } } - mutex_unlock(&adap->clist_lock); if (addr_list[i] == I2C_CLIENT_END) { dev_dbg(&adap->dev, "Probing failed, no device found\n"); --- at91.orig/include/linux/i2c.h 2008-01-14 14:32:00.000000000 -0800 +++ at91/include/linux/i2c.h 2008-01-14 14:32:19.000000000 -0800 @@ -159,7 +159,6 @@ struct i2c_driver { * @irq: indicates the IRQ generated by this device (if any) * @driver_name: Identifies new-style driver used with this device; also * used as the module name for hotplug/coldplug modprobe support. - * @list: list of active/busy clients (DEPRECATED) * @released: used to synchronize client releases & detaches and references * * An i2c_client identifies a single device (i.e. chip) connected to an @@ -179,7 +178,6 @@ struct i2c_client { struct device dev; /* the device structure */ int irq; /* irq issued by device (or -1) */ char driver_name[KOBJ_NAME_LEN]; - struct list_head list; /* DEPRECATED */ struct completion released; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev) @@ -319,14 +317,12 @@ struct i2c_adapter { /* data fields that are valid for all devices */ u8 level; /* nesting level for lockdep */ struct mutex bus_lock; - struct mutex clist_lock; int timeout; int retries; struct device dev; /* the adapter device */ int nr; - struct list_head clients; /* DEPRECATED */ char name[48]; struct completion dev_released; }; _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200801091321.29212.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2008-01-10 13:31 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare @ 2008-01-17 19:35 ` David Brownell [not found] ` <200801171135.45797.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 1 sibling, 1 reply; 43+ messages in thread From: David Brownell @ 2008-01-17 19:35 UTC (permalink / raw) To: Jean Delvare; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA On Wednesday 09 January 2008, David Brownell wrote: > (a) Start phasing out users of i2c_client.list and its lock, ASAP; > merging those DVB driver patches, and some i2c-core changes. Posted: http://marc.info/?l=i2c&m=120034972711126&w=2 > (d) Meanwhile, come up with a different solution to the deadlock > observed with i2c_adapter.clist ... which for some unknown > reason has *NOT* shown up for me with lockdep. This should suffice. Could be merged with the patch above, or even made to not depend on it. And maybe the list_add should be moved after device_register() so the locking is only needed on that one path. That'd be a net code shrink and simplification... - Dave ====== CUT HERE This goes on top of the patch removing most i2c_adapter.clients usage, updating i2c_attach_client: - Don't call device_register() while holding clist_lock. This removes a self-deadlock when on the i2c_driver.probe() path, for drivers that need to attach new devices (e.g. dummies). - Remove a redundant address check. The driver model core does this as a consequence of guaranteeing unique names. - Move the "device registered" diagnostic so that it never lies; previously, on error paths it would falsely report success. --- drivers/i2c/i2c-core.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) --- at91.orig/drivers/i2c/i2c-core.c 2008-01-17 10:07:38.000000000 -0800 +++ at91/drivers/i2c/i2c-core.c 2008-01-17 10:11:04.000000000 -0800 @@ -752,13 +752,6 @@ int i2c_attach_client(struct i2c_client struct i2c_adapter *adapter = client->adapter; int res = 0; - mutex_lock(&adapter->clist_lock); - if (i2c_check_addr(client->adapter, client->addr)) { - res = -EBUSY; - goto out_unlock; - } - list_add_tail(&client->list,&adapter->clients); - client->usage_count = 0; client->dev.parent = &client->adapter->dev; @@ -773,14 +766,18 @@ int i2c_attach_client(struct i2c_client } else client->dev.release = i2c_client_dev_release; + mutex_lock(&adapter->clist_lock); + list_add_tail(&client->list,&adapter->clients); + mutex_unlock(&adapter->clist_lock); + snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), "%d-%04x", i2c_adapter_id(adapter), client->addr); - dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", - client->name, client->dev.bus_id); res = device_register(&client->dev); if (res) goto out_list; - mutex_unlock(&adapter->clist_lock); + + dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", + client->name, client->dev.bus_id); if (adapter->client_register) { if (adapter->client_register(client)) { @@ -793,7 +790,9 @@ int i2c_attach_client(struct i2c_client return 0; out_list: + mutex_lock(&adapter->clist_lock); list_del(&client->list); + mutex_unlock(&adapter->clist_lock); dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " "(%d)\n", client->name, client->addr, res); out_unlock: _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200801171135.45797.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200801171135.45797.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2008-01-17 19:59 ` David Brownell [not found] ` <200801171159.00291.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: David Brownell @ 2008-01-17 19:59 UTC (permalink / raw) To: Jean Delvare; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA On Thursday 17 January 2008, David Brownell wrote: > > (d) Meanwhile, come up with a different solution to the deadlock > > observed with i2c_adapter.clist ... which for some unknown > > reason has *NOT* shown up for me with lockdep. > > This should suffice. Could be merged with the patch above, > or even made to not depend on it. > > And maybe the list_add should be moved after device_register() > so the locking is only needed on that one path. That'd be a > net code shrink and simplification... Grr. Disregard that previous patch. This version fixes bugs in that one, and includes those cleanups too. To make it not depend on the previous patch, make it "__i2c_check_addr". ========= SNIP! This goes on top of the patch removing most i2c_adapter.clients usage, updating i2c_attach_client: - Don't call device_register() while holding clist_lock. This removes a self-deadlock when on the i2c_driver.probe() path, for drivers that need to attach new devices (e.g. dummies). - Remove a redundant address check. The driver model core does this as a consequence of guaranteeing unique names. - Move the "device registered" diagnostic so that it never lies; previously, on error paths it would falsely report success. --- drivers/i2c/i2c-core.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) --- at91.orig/drivers/i2c/i2c-core.c 2008-01-17 10:07:38.000000000 -0800 +++ at91/drivers/i2c/i2c-core.c 2008-01-17 11:53:01.000000000 -0800 @@ -752,13 +752,6 @@ int i2c_attach_client(struct i2c_client struct i2c_adapter *adapter = client->adapter; int res = 0; - mutex_lock(&adapter->clist_lock); - if (i2c_check_addr(client->adapter, client->addr)) { - res = -EBUSY; - goto out_unlock; - } - list_add_tail(&client->list,&adapter->clients); - client->usage_count = 0; client->dev.parent = &client->adapter->dev; @@ -775,13 +768,17 @@ int i2c_attach_client(struct i2c_client snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), "%d-%04x", i2c_adapter_id(adapter), client->addr); - dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", - client->name, client->dev.bus_id); res = device_register(&client->dev); if (res) - goto out_list; + goto out_err; + + mutex_lock(&adapter->clist_lock); + list_add_tail(&client->list,&adapter->clients); mutex_unlock(&adapter->clist_lock); + dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", + client->name, client->dev.bus_id); + if (adapter->client_register) { if (adapter->client_register(client)) { dev_dbg(&adapter->dev, "client_register " @@ -792,12 +789,9 @@ int i2c_attach_client(struct i2c_client return 0; -out_list: - list_del(&client->list); +out_err: dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " "(%d)\n", client->name, client->addr, res); -out_unlock: - mutex_unlock(&adapter->clist_lock); return res; } EXPORT_SYMBOL(i2c_attach_client); _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200801171159.00291.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200801171159.00291.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2008-01-18 9:32 ` Jean Delvare [not found] ` <20080118103209.4b92ac76-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: Jean Delvare @ 2008-01-18 9:32 UTC (permalink / raw) To: David Brownell; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA Hi David, On Thu, 17 Jan 2008 11:59:00 -0800, David Brownell wrote: > This goes on top of the patch removing most i2c_adapter.clients usage, > updating i2c_attach_client: > > - Don't call device_register() while holding clist_lock. This > removes a self-deadlock when on the i2c_driver.probe() path, > for drivers that need to attach new devices (e.g. dummies). > > - Remove a redundant address check. The driver model core does > this as a consequence of guaranteeing unique names. > > - Move the "device registered" diagnostic so that it never lies; > previously, on error paths it would falsely report success. > > --- > drivers/i2c/i2c-core.c | 22 ++++++++-------------- > 1 file changed, 8 insertions(+), 14 deletions(-) > > --- at91.orig/drivers/i2c/i2c-core.c 2008-01-17 10:07:38.000000000 -0800 > +++ at91/drivers/i2c/i2c-core.c 2008-01-17 11:53:01.000000000 -0800 > @@ -752,13 +752,6 @@ int i2c_attach_client(struct i2c_client > struct i2c_adapter *adapter = client->adapter; > int res = 0; > > - mutex_lock(&adapter->clist_lock); > - if (i2c_check_addr(client->adapter, client->addr)) { > - res = -EBUSY; > - goto out_unlock; > - } > - list_add_tail(&client->list,&adapter->clients); > - > client->usage_count = 0; > > client->dev.parent = &client->adapter->dev; > @@ -775,13 +768,17 @@ int i2c_attach_client(struct i2c_client > > snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), > "%d-%04x", i2c_adapter_id(adapter), client->addr); > - dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", > - client->name, client->dev.bus_id); > res = device_register(&client->dev); > if (res) > - goto out_list; > + goto out_err; > + > + mutex_lock(&adapter->clist_lock); > + list_add_tail(&client->list,&adapter->clients); > mutex_unlock(&adapter->clist_lock); > > + dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", > + client->name, client->dev.bus_id); > + > if (adapter->client_register) { > if (adapter->client_register(client)) { > dev_dbg(&adapter->dev, "client_register " > @@ -792,12 +789,9 @@ int i2c_attach_client(struct i2c_client > > return 0; > > -out_list: > - list_del(&client->list); > +out_err: > dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " > "(%d)\n", client->name, client->addr, res); > -out_unlock: > - mutex_unlock(&adapter->clist_lock); > return res; > } > EXPORT_SYMBOL(i2c_attach_client); This looks OK to me, I'll add this to my i2c tree. All it is really missing is your Signed-off-by line. This gave me the idea of a similar cleanup in i2c_detach_client: I fail to see why we hold the clist lock while unregistering the device. What do you think of the following cleanup? * * * * * We only need to hold adapter->clist_lock when we touch the client list. Signed-off-by: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>--- drivers/i2c/i2c-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) --- linux-2.6.24-rc8.orig/drivers/i2c/i2c-core.c 2008-01-18 09:56:07.000000000 +0100 +++ linux-2.6.24-rc8/drivers/i2c/i2c-core.c 2008-01-18 10:17:01.000000000 +0100 @@ -768,9 +768,10 @@ int i2c_detach_client(struct i2c_client mutex_lock(&adapter->clist_lock); list_del(&client->list); + mutex_unlock(&adapter->clist_lock); + init_completion(&client->released); device_unregister(&client->dev); - mutex_unlock(&adapter->clist_lock); wait_for_completion(&client->released); out: -- Jean Delvare _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <20080118103209.4b92ac76-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080118103209.4b92ac76-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2008-01-18 10:16 ` David Brownell [not found] ` <200801180216.22363.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: David Brownell @ 2008-01-18 10:16 UTC (permalink / raw) To: Jean Delvare; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA On Friday 18 January 2008, Jean Delvare wrote: > Hi David, > > On Thu, 17 Jan 2008 11:59:00 -0800, David Brownell wrote: > > This goes on top of the patch removing most i2c_adapter.clients usage, > > updating i2c_attach_client: > > > > ... > > This looks OK to me, I'll add this to my i2c tree. All it is really > missing is your Signed-off-by line. Feel free to cut'n'paste that one from another file. :) > This gave me the idea of a similar cleanup in i2c_detach_client: I fail > to see why we hold the clist lock while unregistering the device. What > do you think of the following cleanup? Looks OK. Similarly, i2c_new_probed_device() could use a driver model iterator instead of clist_lock. Something else to think about: clist_lock isn't used when iterating over i2c_adapter.clients. Maybe it should just be removed, and replaced *everywhere* by core_lists... - Dave > * * * * * > > We only need to hold adapter->clist_lock when we touch the client list. > > Signed-off-by: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>--- > drivers/i2c/i2c-core.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > --- linux-2.6.24-rc8.orig/drivers/i2c/i2c-core.c 2008-01-18 09:56:07.000000000 +0100 > +++ linux-2.6.24-rc8/drivers/i2c/i2c-core.c 2008-01-18 10:17:01.000000000 +0100 > @@ -768,9 +768,10 @@ int i2c_detach_client(struct i2c_client > > mutex_lock(&adapter->clist_lock); > list_del(&client->list); > + mutex_unlock(&adapter->clist_lock); > + > init_completion(&client->released); > device_unregister(&client->dev); > - mutex_unlock(&adapter->clist_lock); > wait_for_completion(&client->released); > > out: > > > -- > Jean Delvare > _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200801180216.22363.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200801180216.22363.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2008-01-18 12:10 ` Jean Delvare 0 siblings, 0 replies; 43+ messages in thread From: Jean Delvare @ 2008-01-18 12:10 UTC (permalink / raw) To: David Brownell; +Cc: Greg KH, i2c-GZX6beZjE8VD60Wz+7aTrA Hi David, On Fri, 18 Jan 2008 02:16:22 -0800, David Brownell wrote: > On Friday 18 January 2008, Jean Delvare wrote: > > This gave me the idea of a similar cleanup in i2c_detach_client: I fail > > to see why we hold the clist lock while unregistering the device. What > > do you think of the following cleanup? > > Looks OK. Similarly, i2c_new_probed_device() could > use a driver model iterator instead of clist_lock. I'm not sure I follow you here. i2c_new_probed_device() doesn't really walk the list of clients, all it does is calling i2c_check_addr(), as was discussed elsewhere in this thread. This left apart, I don't see what kind of "driver model iterator" you would want to use in this function. > Something else to think about: clist_lock isn't used > when iterating over i2c_adapter.clients. Maybe it should > just be removed, and replaced *everywhere* by core_lists... I don't really want to do that. The redundant client list will be dropped at some point in time, and it's easier to validate such changes with dedicated locks. Having a single lock for many things makes it quite hard to figure out what was being protected after the fact. -- Jean Delvare _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080108151817.35e05c6c-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 2008-01-08 16:20 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare @ 2008-01-08 18:52 ` David Brownell [not found] ` <200801081052.31413.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2008-01-09 16:09 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare 2 siblings, 1 reply; 43+ messages in thread From: David Brownell @ 2008-01-08 18:52 UTC (permalink / raw) To: Jean Delvare; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA On Tuesday 08 January 2008, Jean Delvare wrote: > > Good point. I didn't like this part much, and that function can > > have other uses. I updated kobj_to_i2c_client() to use it too. > > I wouldn't change kobj_to_i2c_client(). Drivers using it already know > that their kobj is an i2c_client, so there's no need to check for that, > and the use cases I've seen are in runtime paths that should be fast, I > don't want to slow them down without a good reason. Hmm, Mr. Grep says all the users of that are in drivers/i2c/chips ... basically mapping an eeprom binary attribute's kobj to the i2c_client of the base device. I have to say that not only would I not call those "should be fast" paths (how often does anyone read eeproms??), but I also have no problem using client = to_i2c_client(container_of(kobj, struct device, kobj)); instead of a fancy kobj_to_i2c_client() ... in fact, I would never have thought to look for any kobj_to_*() utilities. Although Mr. Grep tellse me there are a few others floating around; back it out if you feel strongly about it. > - return device_for_each_child(&adapter->dev, &addr, i2cdev_check); > + return i2c_for_each_client(adapter, &addr, i2cdev_check); > > ... > > Admittedly it will slow down things a bit as each iteration of the loop > will have one additional level of indirection. This makes the calling > code somewhat simpler though. Whether it is worth the additional > runtime cost, I just don't know. What do you think? My bias in such cases is towards interfaces that force less policy. So in this case that would be to expose i2_verify_client() instead of an i2c-specific iterator. The fact that it's got lower callstack overhead is a bonus. :) ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200801081052.31413.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200801081052.31413.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2008-01-08 19:57 ` Jean Delvare 0 siblings, 0 replies; 43+ messages in thread From: Jean Delvare @ 2008-01-08 19:57 UTC (permalink / raw) To: David Brownell; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA On Tue, 8 Jan 2008 10:52:31 -0800, David Brownell wrote: > On Tuesday 08 January 2008, Jean Delvare wrote: > > > Good point. I didn't like this part much, and that function can > > > have other uses. I updated kobj_to_i2c_client() to use it too. > > > > I wouldn't change kobj_to_i2c_client(). Drivers using it already know > > that their kobj is an i2c_client, so there's no need to check for that, > > and the use cases I've seen are in runtime paths that should be fast, I > > don't want to slow them down without a good reason. > > Hmm, Mr. Grep says all the users of that are in drivers/i2c/chips ... > basically mapping an eeprom binary attribute's kobj to the i2c_client > of the base device. I have to say that not only would I not call > those "should be fast" paths (how often does anyone read eeproms??), Sorry, I expressed myself incorrectly, I didn't mean to intend that these were hot paths, just that this was run-time code and not initialization code, which means that the speed matters a little more. But the key argument here is that the current code is not broken so I couldn't see the rationale for touching it. > but I also have no problem using > > client = to_i2c_client(container_of(kobj, struct device, kobj)); > > instead of a fancy kobj_to_i2c_client() ... in fact, I would never > have thought to look for any kobj_to_*() utilities. Although Mr. Grep > tellse me there are a few others floating around; back it out if you > feel strongly about it. I seem to remember that kobj_to_i2c_client() was originally declared inside one of these drivers by the driver author and I suggested to move it to i2c.h. > > - return device_for_each_child(&adapter->dev, &addr, i2cdev_check); > > + return i2c_for_each_client(adapter, &addr, i2cdev_check); > > > > ... > > > > Admittedly it will slow down things a bit as each iteration of the loop > > will have one additional level of indirection. This makes the calling > > code somewhat simpler though. Whether it is worth the additional > > runtime cost, I just don't know. What do you think? > > My bias in such cases is towards interfaces that force less policy. > So in this case that would be to expose i2_verify_client() instead > of an i2c-specific iterator. The fact that it's got lower callstack > overhead is a bonus. :) OK, fine with me, I'll forget about it then. -- Jean Delvare ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080108151817.35e05c6c-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 2008-01-08 16:20 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare 2008-01-08 18:52 ` i2c-remove-redundant-i2c_client-list.patch David Brownell @ 2008-01-09 16:09 ` Jean Delvare 2 siblings, 0 replies; 43+ messages in thread From: Jean Delvare @ 2008-01-09 16:09 UTC (permalink / raw) To: David Brownell; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA Quoting myself: > Admittedly it will slow down things a bit as each iteration of the loop > will have one additional level of indirection. This makes the calling > code somewhat simpler though. Whether it is worth the additional > runtime cost, I just don't know. What do you think? For the records, what I wrote above is not entirely true. By folding i2c_verify_client() into __i2c_for_each_client(), it is possible to get the exact same runtime cost (in terms of function call count) as we have without my proposed change. So performance is not a reason for not doing it. -- Jean Delvare ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <20080106122356.78556b8a-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 2008-01-06 19:30 ` i2c-remove-redundant-i2c_client-list.patch David Brownell @ 2008-01-06 19:43 ` David Brownell [not found] ` <200801061143.34020.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 1 sibling, 1 reply; 43+ messages in thread From: David Brownell @ 2008-01-06 19:43 UTC (permalink / raw) To: Jean Delvare; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA Remove further duplication between i2c core and driver model: the per-adapter list of clients (adapter->clients, client->list) and its lock (adapter->clist_lock) duplicate adapter->dev.children. Add and use a new i2c_verify_client() routine to help code which traverses the driver model tree. Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> --- LIGHTLY TESTED ... goes on top of two patches from Jean's I2C queue, i2c-remove-redundant-i2c_adapter-list.patch i2c-remove-redundant-i2c_driver-list.patch Updated per Jean's comments. (Note that the i2c_verify_client bit might usefully be split out into a separate patch, to simplify converting the V4L code that uses this i2c client list.) drivers/i2c/i2c-core.c | 202 ++++++++++++++++++++++++------------------------- drivers/i2c/i2c-dev.c | 29 ++----- include/linux/i2c.h | 9 -- 3 files changed, 114 insertions(+), 126 deletions(-) --- at91.orig/drivers/i2c/i2c-core.c 2008-01-06 10:47:45.000000000 -0800 +++ at91/drivers/i2c/i2c-core.c 2008-01-06 11:08:00.000000000 -0800 @@ -197,6 +197,25 @@ static struct bus_type i2c_bus_type = { .resume = i2c_device_resume, }; + +/** + * i2c_verify_client - return parameter as i2c_client, or NULL + * @dev: device, probably from some driver model iterator + * + * When traversing the driver model tree, perhaps using driver model + * iterators like @device_for_each_child(), you can't assume very much + * about the nodes you find. Use this function to avoid oopses caused + * by wrongly treating some non-I2C device as an i2c_client. + */ +struct i2c_client *i2c_verify_client(struct device *dev) +{ + return (dev->bus == &i2c_bus_type) + ? to_i2c_client(dev) + : NULL; +} +EXPORT_SYMBOL(i2c_verify_client); + + /** * i2c_new_device - instantiate an i2c device for use with a new style driver * @adap: the adapter managing the device @@ -256,7 +275,6 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { - struct i2c_adapter *adapter = client->adapter; struct i2c_driver *driver = client->driver; if (driver && !is_newstyle_driver(driver)) { @@ -265,11 +283,6 @@ void i2c_unregister_device(struct i2c_cl WARN_ON(1); return; } - - mutex_lock(&adapter->clist_lock); - list_del(&client->list); - mutex_unlock(&adapter->clist_lock); - device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); @@ -381,8 +394,6 @@ static int i2c_register_adapter(struct i int res = 0, dummy; mutex_init(&adap->bus_lock); - mutex_init(&adap->clist_lock); - INIT_LIST_HEAD(&adap->clients); mutex_lock(&core_lists); @@ -525,6 +536,32 @@ static int i2c_do_del_adapter(struct dev return res; } + +static int detach_all_clients(struct device *dev, void *x) +{ + struct i2c_client *client = i2c_verify_client(dev); + struct i2c_driver *driver; + int res; + + if (!client) + return 0; + + driver = client->driver; + + /* new style, follow standard driver model */ + if (!driver || is_newstyle_driver(driver)) { + i2c_unregister_device(client); + return 0; + } + + /* legacy drivers create and remove clients themselves */ + if ((res = driver->detach_client(client))) + dev_err(dev, "detach_client [%s] failed at address 0x%02x\n", + client->name, client->addr); + + return res; +} + /** * i2c_del_adapter - unregister I2C adapter * @adap: the adapter being unregistered @@ -535,8 +572,6 @@ static int i2c_do_del_adapter(struct dev */ int i2c_del_adapter(struct i2c_adapter *adap) { - struct list_head *item, *_n; - struct i2c_client *client; int res = 0; mutex_lock(&core_lists); @@ -557,26 +592,9 @@ int i2c_del_adapter(struct i2c_adapter * /* detach any active clients. This must be done first, because * it can fail; in which case we give up. */ - list_for_each_safe(item, _n, &adap->clients) { - struct i2c_driver *driver; - - client = list_entry(item, struct i2c_client, list); - driver = client->driver; - - /* new style, follow standard driver model */ - if (!driver || is_newstyle_driver(driver)) { - i2c_unregister_device(client); - continue; - } - - /* legacy drivers create and remove clients themselves */ - if ((res = driver->detach_client(client))) { - dev_err(&adap->dev, "detach_client failed for client " - "[%s] at address 0x%02x\n", client->name, - client->addr); - goto out_unlock; - } - } + res = device_for_each_child(&adap->dev, NULL, detach_all_clients); + if (res) + goto out_unlock; /* clean up the sysfs representation */ init_completion(&adap->dev_released); @@ -655,6 +673,20 @@ int i2c_register_driver(struct module *o } EXPORT_SYMBOL(i2c_register_driver); +static int detach_legacy_clients(struct device *dev, void *driver) +{ + struct i2c_client *client = i2c_verify_client(dev); + + if (client && client->driver == driver) { + dev_dbg(dev, "detaching client [%s] at 0x%02x\n", + client->name, client->addr); + if (client->driver->detach_client(client)) + dev_err(dev, "failed detach_client [%s] at 0x%02x\n", + client->name, client->addr); + } + return 0; +} + /** * i2c_del_driver - unregister I2C driver * @driver: the driver being unregistered @@ -662,8 +694,6 @@ EXPORT_SYMBOL(i2c_register_driver); */ void i2c_del_driver(struct i2c_driver *driver) { - struct list_head *item2, *_n; - struct i2c_client *client; struct i2c_adapter *adap; mutex_lock(&core_lists); @@ -684,22 +714,9 @@ void i2c_del_driver(struct i2c_driver *d "for driver [%s]\n", driver->driver.name); } - } else { - list_for_each_safe(item2, _n, &adap->clients) { - client = list_entry(item2, struct i2c_client, list); - if (client->driver != driver) - continue; - dev_dbg(&adap->dev, "detaching client [%s] " - "at 0x%02x\n", client->name, - client->addr); - if (driver->detach_client(client)) { - dev_err(&adap->dev, "detach_client " - "failed for client [%s] at " - "0x%02x\n", client->name, - client->addr); - } - } - } + } else + device_for_each_child(&adap->dev, driver, + detach_legacy_clients); } up(&i2c_adapter_class.sem); @@ -713,28 +730,19 @@ EXPORT_SYMBOL(i2c_del_driver); /* ------------------------------------------------------------------------- */ -static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr) +static int __i2c_check_addr(struct device *dev, void *addrp) { - struct list_head *item; - struct i2c_client *client; + struct i2c_client *client = i2c_verify_client(dev); + int addr = *(int *)addrp; - list_for_each(item,&adapter->clients) { - client = list_entry(item, struct i2c_client, list); - if (client->addr == addr) - return -EBUSY; - } + if (client && client->addr == addr) + return -EBUSY; return 0; } static int i2c_check_addr(struct i2c_adapter *adapter, int addr) { - int rval; - - mutex_lock(&adapter->clist_lock); - rval = __i2c_check_addr(adapter, addr); - mutex_unlock(&adapter->clist_lock); - - return rval; + return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); } int i2c_attach_client(struct i2c_client *client) @@ -742,13 +750,6 @@ int i2c_attach_client(struct i2c_client struct i2c_adapter *adapter = client->adapter; int res = 0; - mutex_lock(&adapter->clist_lock); - if (__i2c_check_addr(client->adapter, client->addr)) { - res = -EBUSY; - goto out_unlock; - } - list_add_tail(&client->list,&adapter->clients); - client->usage_count = 0; client->dev.parent = &client->adapter->dev; @@ -765,12 +766,16 @@ int i2c_attach_client(struct i2c_client snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), "%d-%04x", i2c_adapter_id(adapter), client->addr); + res = device_register(&client->dev); + if (res) { + dev_err(&adapter->dev, + "Failed to register i2c client %s at 0x%02x (%d)\n", + client->name, client->addr, res); + return res; + } + dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", client->name, client->dev.bus_id); - res = device_register(&client->dev); - if (res) - goto out_list; - mutex_unlock(&adapter->clist_lock); if (adapter->client_register) { if (adapter->client_register(client)) { @@ -781,14 +786,6 @@ int i2c_attach_client(struct i2c_client } return 0; - -out_list: - list_del(&client->list); - dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " - "(%d)\n", client->name, client->addr, res); -out_unlock: - mutex_unlock(&adapter->clist_lock); - return res; } EXPORT_SYMBOL(i2c_attach_client); @@ -813,11 +810,8 @@ int i2c_detach_client(struct i2c_client } } - mutex_lock(&adapter->clist_lock); - list_del(&client->list); init_completion(&client->released); device_unregister(&client->dev); - mutex_unlock(&adapter->clist_lock); wait_for_completion(&client->released); out: @@ -873,24 +867,28 @@ int i2c_release_client(struct i2c_client } EXPORT_SYMBOL(i2c_release_client); +struct i2c_cmd_arg { + unsigned cmd; + void *arg; +}; + +static int i2c_cmd(struct device *dev, void *_arg) +{ + struct i2c_client *client = i2c_verify_client(dev); + struct i2c_cmd_arg *arg = _arg; + + if (client && client->driver->command) + client->driver->command(client, arg->cmd, arg->arg); + return 0; +} + void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) { - struct list_head *item; - struct i2c_client *client; + struct i2c_cmd_arg cmd_arg; - mutex_lock(&adap->clist_lock); - list_for_each(item,&adap->clients) { - client = list_entry(item, struct i2c_client, list); - if (!try_module_get(client->driver->driver.owner)) - continue; - if (NULL != client->driver->command) { - mutex_unlock(&adap->clist_lock); - client->driver->command(client,cmd,arg); - mutex_lock(&adap->clist_lock); - } - module_put(client->driver->driver.owner); - } - mutex_unlock(&adap->clist_lock); + cmd_arg.cmd = cmd; + cmd_arg.arg = arg; + device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd); } EXPORT_SYMBOL(i2c_clients_command); @@ -1151,7 +1149,6 @@ i2c_new_probed_device(struct i2c_adapter return NULL; } - mutex_lock(&adap->clist_lock); for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { /* Check address validity */ if (addr_list[i] < 0x03 || addr_list[i] > 0x77) { @@ -1161,7 +1158,7 @@ i2c_new_probed_device(struct i2c_adapter } /* Check address availability */ - if (__i2c_check_addr(adap, addr_list[i])) { + if (i2c_check_addr(adap, addr_list[i])) { dev_dbg(&adap->dev, "Address 0x%02x already in " "use, not probing\n", addr_list[i]); continue; @@ -1189,7 +1186,6 @@ i2c_new_probed_device(struct i2c_adapter break; } } - mutex_unlock(&adap->clist_lock); if (addr_list[i] == I2C_CLIENT_END) { dev_dbg(&adap->dev, "Probing failed, no device found\n"); --- at91.orig/drivers/i2c/i2c-dev.c 2008-01-05 16:17:06.000000000 -0800 +++ at91/drivers/i2c/i2c-dev.c 2008-01-06 11:22:30.000000000 -0800 @@ -182,27 +182,22 @@ static ssize_t i2cdev_write (struct file return ret; } +static int i2cdev_check(struct device *dev, void *addrp) +{ + struct i2c_client *client = i2c_verify_client(dev); + + if (!client || client->addr != *(unsigned int *)addrp) + return 0; + + return dev->driver ? -EBUSY : 0; +} + /* This address checking function differs from the one in i2c-core in that it considers an address with a registered device, but no - bounded driver, as NOT busy. */ + driver to it, as NOT busy. */ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) { - struct list_head *item; - struct i2c_client *client; - int res = 0; - - mutex_lock(&adapter->clist_lock); - list_for_each(item, &adapter->clients) { - client = list_entry(item, struct i2c_client, list); - if (client->addr == addr) { - if (client->driver) - res = -EBUSY; - break; - } - } - mutex_unlock(&adapter->clist_lock); - - return res; + return device_for_each_child(&adapter->dev, &addr, i2cdev_check); } static int i2cdev_ioctl(struct inode *inode, struct file *file, --- at91.orig/include/linux/i2c.h 2008-01-06 10:47:45.000000000 -0800 +++ at91/include/linux/i2c.h 2008-01-06 11:10:38.000000000 -0800 @@ -159,7 +159,6 @@ struct i2c_driver { * @irq: indicates the IRQ generated by this device (if any) * @driver_name: Identifies new-style driver used with this device; also * used as the module name for hotplug/coldplug modprobe support. - * @list: list of active/busy clients * @released: used to synchronize client releases & detaches and references * * An i2c_client identifies a single device (i.e. chip) connected to an @@ -179,15 +178,15 @@ struct i2c_client { struct device dev; /* the device structure */ int irq; /* irq issued by device (or -1) */ char driver_name[KOBJ_NAME_LEN]; - struct list_head list; struct completion released; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev) +extern struct i2c_client *i2c_verify_client(struct device *dev); + static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj) { - struct device * const dev = container_of(kobj, struct device, kobj); - return to_i2c_client(dev); + return i2c_verify_client(container_of(kobj, struct device, kobj)); } static inline void *i2c_get_clientdata (struct i2c_client *dev) @@ -317,14 +316,12 @@ struct i2c_adapter { /* data fields that are valid for all devices */ u8 level; /* nesting level for lockdep */ struct mutex bus_lock; - struct mutex clist_lock; int timeout; int retries; struct device dev; /* the adapter device */ int nr; - struct list_head clients; char name[48]; struct completion dev_released; }; ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200801061143.34020.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: i2c-remove-redundant-i2c_client-list.patch [not found] ` <200801061143.34020.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2008-01-08 14:21 ` Jean Delvare 0 siblings, 0 replies; 43+ messages in thread From: Jean Delvare @ 2008-01-08 14:21 UTC (permalink / raw) To: David Brownell; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA On Sun, 6 Jan 2008 11:43:33 -0800, David Brownell wrote: > Remove further duplication between i2c core and driver model: the > per-adapter list of clients (adapter->clients, client->list) and > its lock (adapter->clist_lock) duplicate adapter->dev.children. > > Add and use a new i2c_verify_client() routine to help code which > traverses the driver model tree. > > Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> > --- > LIGHTLY TESTED ... goes on top of two patches from Jean's I2C queue, > > i2c-remove-redundant-i2c_adapter-list.patch > i2c-remove-redundant-i2c_driver-list.patch > > Updated per Jean's comments. (Note that the i2c_verify_client > bit might usefully be split out into a separate patch, to simplify > converting the V4L code that uses this i2c client list.) Agreed, I'll split things up as needed so that we have a clean incremental patch set. > (...) > static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj) > { > - struct device * const dev = container_of(kobj, struct device, kobj); > - return to_i2c_client(dev); > + return i2c_verify_client(container_of(kobj, struct device, kobj)); > } Unless you have a reason to think that this is really needed, I think I'll back this change out as explained in my previous post. All the rest looks just fine to me, thanks! -- Jean Delvare ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <200712291905.15160.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2008-01-04 22:16 ` Jean Delvare 2008-01-06 11:23 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare @ 2008-01-17 22:24 ` David Brownell 2 siblings, 0 replies; 43+ messages in thread From: David Brownell @ 2008-01-17 22:24 UTC (permalink / raw) To: Byron Bradley; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA On Saturday 29 December 2007, David Brownell wrote: > I still don't know why you get lockdep warnings and I don't ... Theory: my test systems were turning lockdep off because of a lockdep (usage) deficiency that triggers while booting: enable_irq_wake(GPIO_irq) holds irq_desc[GPIO_irq].lock and calls enable_irq_wake(parent_of(GPIO_irq)) which grabs irq_desc[parent_of(GPIO_irq))] Lockdep falsely detects that as a potential recursion, and then turns off all further lockdep calls. I think a genirq patch to make set_irq_chained_handler() put the parent into a different locking class may help resolve that issue. - Dave _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility
@ 2007-12-22 17:31 Jean Delvare
[not found] ` <kOXVGr9s.1198344701.9162110.khali-IO4AeUl/lkuWVfeAwA7xHQ@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Jean Delvare @ 2007-12-22 17:31 UTC (permalink / raw)
To: david-b-yBeKhBN/0LDR7s880joybQ; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA
Hi David,
Sorry for the non-threaded reply, I do not have access to the original
post at the moment.
David Brownell wrote:
> This adds a i2c_new_dummy() primitive to help work with devices
> that consume multiple addresses, which include many I2C eeproms
> and at least one RTC.
>
> Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
> ---
> [ Apologies for the duplicate message some of you may have seen. ]
>
> Tested with a 24c00 EEPROM ... that's the 16-byte one, which
> ignores a0/a1/a2 and thus consumes 8 addresses.
>
> drivers/i2c/i2c-core.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++-
> include/linux/i2c.h | 6 ++++
> 2 files changed, 65 insertions(+), 1 deletion(-)
>
> --- a/drivers/i2c/i2c-core.c 2007-12-15 20:57:54.000000000 -0800
> +++ b/drivers/i2c/i2c-core.c 2007-12-15 21:01:22.000000000 -0800
> @@ -276,6 +276,51 @@ void i2c_unregister_device(struct i2c_cl
> EXPORT_SYMBOL_GPL(i2c_unregister_device);
>
>
> +static int dummy_nop(struct i2c_client *client)
> +{
> + return 0;
> +}
> +
> +static struct i2c_driver dummy_driver = {
> + .driver.name = "dummy",
> + .probe = dummy_nop,
> + .remove = dummy_nop,
> +};
> +
> +
> +/**
> + * i2c_new_dummy - return a new i2c device bound to a dummy driver
> + * @adapter: the adapter managing the device
> + * @address: seven bit address to be used
> + * @type: optional label used for i2c_client.name
Do you have a use case in mind for this feature?
> + * Context: can sleep
> + *
> + * This returns an I2C client bound to the "dummy" driver, intended for use
> + * with devices that consume multiple addresses. Examples of such chips
> + * include various EEPROMS (like 24c04 and 24c08 models).
> + *
> + * These dummy devices have two main uses. First, most I2C and SMBus calls
> + * except i2c_transfer() need a client handle; the dummy will be that handle.
> + * And second, this prevents the specified address from being bound to a
> + * different driver.
> + *
> + * This returns the new i2c client, which may be saved for later use with
> + * i2c_unregister_device(); or NULL to indicate an error.
I'd say it _should_ be saved. Calling i2c_unregister_device() is pretty
much mandatory, unless the driver can't be built as a module.
> + */
> +struct i2c_client *
> +i2c_new_dummy(struct i2c_adapter *adapter, unsigned address, const char *type)
The rest of i2c-core uses an unsigned short for addresses, maybe do the
same here for consistency?
> +{
> + struct i2c_board_info info = {
> + .driver_name = "dummy",
> + .addr = address,
> + };
> +
> + if (type)
> + strncpy(info.type, type, sizeof info.type);
Please use strlcpy() instead, strncpy() is error-prone.
> + return i2c_new_device(adapter, &info);
> +}
> +EXPORT_SYMBOL_GPL(i2c_new_dummy);
> +
> /* ------------------------------------------------------------------------- */
>
> /* I2C bus adapters -- one roots each I2C or SMBUS segment */
> @@ -848,11 +893,24 @@ static int __init i2c_init(void)
> retval = bus_register(&i2c_bus_type);
> if (retval)
> return retval;
> - return class_register(&i2c_adapter_class);
> + retval = class_register(&i2c_adapter_class);
> + if (retval)
> + goto bus_err;
> + retval = i2c_add_driver(&dummy_driver);
> + if (retval)
> + goto class_err;
> + return 0;
> +
> +class_err:
> + class_unregister(&i2c_adapter_class);
> +bus_err:
> + bus_unregister(&i2c_bus_type);
> + return retval;
> }
Thanks for fixing a broken error path...
>
> static void __exit i2c_exit(void)
> {
> + i2c_del_driver(&dummy_driver);
> class_unregister(&i2c_adapter_class);
> bus_unregister(&i2c_bus_type);
> }
> --- a/include/linux/i2c.h 2007-12-15 20:57:54.000000000 -0800
> +++ b/include/linux/i2c.h 2007-12-15 21:01:22.000000000 -0800
> @@ -261,6 +261,12 @@ i2c_new_probed_device(struct i2c_adapter
> struct i2c_board_info *info,
> unsigned short const *addr_list);
>
> +/* For devices that use several addresses, use i2c_new_dummy() to make
> + * client handles for the exta addresses.
Typo: extra.
> + */
> +extern struct i2c_client *
> +i2c_new_dummy(struct i2c_adapter *adap, unsigned address, const char *type);
> +
> extern void i2c_unregister_device(struct i2c_client *);
>
> /* Mainboard arch_initcall() code should register all its I2C devices.
>
Other than that the patch looks just fine. Please respin it and I'll
apply it.
Thanks,
--
Jean Delvare
^ permalink raw reply [flat|nested] 43+ messages in thread[parent not found: <kOXVGr9s.1198344701.9162110.khali-IO4AeUl/lkuWVfeAwA7xHQ@public.gmane.org>]
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <kOXVGr9s.1198344701.9162110.khali-IO4AeUl/lkuWVfeAwA7xHQ@public.gmane.org> @ 2007-12-23 5:08 ` David Brownell [not found] ` <200712222108.51292.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: David Brownell @ 2007-12-23 5:08 UTC (permalink / raw) To: Jean Delvare; +Cc: timtimred-f/KTTADhmRsdnm+yROfE0A, i2c-GZX6beZjE8VD60Wz+7aTrA On Saturday 22 December 2007, Jean Delvare wrote: > > +/** > > + * i2c_new_dummy - return a new i2c device bound to a dummy driver > > + * @adapter: the adapter managing the device > > + * @address: seven bit address to be used > > + * @type: optional label used for i2c_client.name > > Do you have a use case in mind for this feature? You mean the "type" field? In the at24.c driver I posted, it's the same name used with the "real" i2c_client node. That helps make sense of just what the "dummy" is for; sysfs can show it. Being tied to a "dummy" driver is not very explanatory. > > + * This returns the new i2c client, which may be saved for later use with > > + * i2c_unregister_device(); or NULL to indicate an error. > > I'd say it _should_ be saved. Calling i2c_unregister_device() is pretty > much mandatory, unless the driver can't be built as a module. OK by me, "which should be saved". > > + */ > > +struct i2c_client * > > +i2c_new_dummy(struct i2c_adapter *adapter, unsigned address, const char *type) > > The rest of i2c-core uses an unsigned short for addresses, maybe do the > same here for consistency? It's promoted by C! But no problem. I'll make it u16 to match the SMBus calls and struct i2c_msg ... and be more concise, still fitting on one line. > > +{ > > + struct i2c_board_info info = { > > + .driver_name = "dummy", > > + .addr = address, > > + }; > > + > > + if (type) > > + strncpy(info.type, type, sizeof info.type); > > Please use strlcpy() instead, strncpy() is error-prone. OK. > > @@ -848,11 +893,24 @@ static int __init i2c_init(void) > > retval = bus_register(&i2c_bus_type); > > if (retval) > > return retval; > > - return class_register(&i2c_adapter_class); > > + retval = class_register(&i2c_adapter_class); > > + if (retval) > > + goto bus_err; > > + retval = i2c_add_driver(&dummy_driver); > > + if (retval) > > + goto class_err; > > + return 0; > > + > > +class_err: > > + class_unregister(&i2c_adapter_class); > > +bus_err: > > + bus_unregister(&i2c_bus_type); > > + return retval; > > } > > Thanks for fixing a broken error path... I could hardly avoid it! :) > > --- a/include/linux/i2c.h 2007-12-15 20:57:54.000000000 -0800 > > +++ b/include/linux/i2c.h 2007-12-15 21:01:22.000000000 -0800 > > @@ -261,6 +261,12 @@ i2c_new_probed_device(struct i2c_adapter > > struct i2c_board_info *info, > > unsigned short const *addr_list); > > > > +/* For devices that use several addresses, use i2c_new_dummy() to make > > + * client handles for the exta addresses. > > Typo: extra. Glitchey keyboard. :( > > + */ > > +extern struct i2c_client * > > +i2c_new_dummy(struct i2c_adapter *adap, unsigned address, const char *type); > > + > > extern void i2c_unregister_device(struct i2c_client *); > > > > /* Mainboard arch_initcall() code should register all its I2C devices. > > > > Other than that the patch looks just fine. Please respin it and I'll > apply it. Thanks. Update to follow. - Dave ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200712222108.51292.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <200712222108.51292.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-12-23 5:11 ` David Brownell [not found] ` <200712222111.09471.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 43+ messages in thread From: David Brownell @ 2007-12-23 5:11 UTC (permalink / raw) To: Jean Delvare; +Cc: timtimred-f/KTTADhmRsdnm+yROfE0A, i2c-GZX6beZjE8VD60Wz+7aTrA This adds a i2c_new_dummy() primitive to help work with devices that consume multiple addresses, which include many I2C eeproms and at least one RTC. Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> --- Updated to match Jean's feedback. Tested with 24c00 EEPROM, which takes eight addresses (but stores only 16 bytes total). drivers/i2c/i2c-core.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++- include/linux/i2c.h | 6 ++++ 2 files changed, 65 insertions(+), 1 deletion(-) --- a/drivers/i2c/i2c-core.c 2007-12-22 13:54:04.000000000 -0800 +++ b/drivers/i2c/i2c-core.c 2007-12-22 13:57:15.000000000 -0800 @@ -276,6 +276,51 @@ void i2c_unregister_device(struct i2c_cl EXPORT_SYMBOL_GPL(i2c_unregister_device); +static int dummy_nop(struct i2c_client *client) +{ + return 0; +} + +static struct i2c_driver dummy_driver = { + .driver.name = "dummy", + .probe = dummy_nop, + .remove = dummy_nop, +}; + + +/** + * i2c_new_dummy - return a new i2c device bound to a dummy driver + * @adapter: the adapter managing the device + * @address: seven bit address to be used + * @type: optional label used for i2c_client.name + * Context: can sleep + * + * This returns an I2C client bound to the "dummy" driver, intended for use + * with devices that consume multiple addresses. Examples of such chips + * include various EEPROMS (like 24c04 and 24c08 models). + * + * These dummy devices have two main uses. First, most I2C and SMBus calls + * except i2c_transfer() need a client handle; the dummy will be that handle. + * And second, this prevents the specified address from being bound to a + * different driver. + * + * This returns the new i2c client, which should be saved for later use with + * i2c_unregister_device(); or NULL to indicate an error. + */ +struct i2c_client * +i2c_new_dummy(struct i2c_adapter *adapter, u16 address, const char *type) +{ + struct i2c_board_info info = { + .driver_name = "dummy", + .addr = address, + }; + + if (type) + strlcpy(info.type, type, sizeof info.type); + return i2c_new_device(adapter, &info); +} +EXPORT_SYMBOL_GPL(i2c_new_dummy); + /* ------------------------------------------------------------------------- */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */ @@ -848,11 +893,24 @@ static int __init i2c_init(void) retval = bus_register(&i2c_bus_type); if (retval) return retval; - return class_register(&i2c_adapter_class); + retval = class_register(&i2c_adapter_class); + if (retval) + goto bus_err; + retval = i2c_add_driver(&dummy_driver); + if (retval) + goto class_err; + return 0; + +class_err: + class_unregister(&i2c_adapter_class); +bus_err: + bus_unregister(&i2c_bus_type); + return retval; } static void __exit i2c_exit(void) { + i2c_del_driver(&dummy_driver); class_unregister(&i2c_adapter_class); bus_unregister(&i2c_bus_type); } --- a/include/linux/i2c.h 2007-12-22 13:54:04.000000000 -0800 +++ b/include/linux/i2c.h 2007-12-22 13:57:15.000000000 -0800 @@ -261,6 +261,12 @@ i2c_new_probed_device(struct i2c_adapter struct i2c_board_info *info, unsigned short const *addr_list); +/* For devices that use several addresses, use i2c_new_dummy() to make + * client handles for the extra addresses. + */ +extern struct i2c_client * +i2c_new_dummy(struct i2c_adapter *adap, u16 address, const char *type); + extern void i2c_unregister_device(struct i2c_client *); /* Mainboard arch_initcall() code should register all its I2C devices. ^ permalink raw reply [flat|nested] 43+ messages in thread
[parent not found: <200712222111.09471.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.24-rc5-git] add i2c_new_dummy() utility [not found] ` <200712222111.09471.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-12-23 9:03 ` Jean Delvare 0 siblings, 0 replies; 43+ messages in thread From: Jean Delvare @ 2007-12-23 9:03 UTC (permalink / raw) To: david-b-yBeKhBN/0LDR7s880joybQ Cc: timtimred-f/KTTADhmRsdnm+yROfE0A, i2c-GZX6beZjE8VD60Wz+7aTrA HI David, Le 23/12/2007, David Brownell a écrit: >This adds a i2c_new_dummy() primitive to help work with devices >that consume multiple addresses, which include many I2C eeproms >and at least one RTC. > >Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> >--- >Updated to match Jean's feedback. Tested with 24c00 EEPROM, >which takes eight addresses (but stores only 16 bytes total). Applied, thanks. -- Jean Delvare ^ permalink raw reply [flat|nested] 43+ messages in thread
end of thread, other threads:[~2008-01-18 12:10 UTC | newest]
Thread overview: 43+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20071216052308.A0FB11668D7@adsl-69-226-248-13.dsl.pltn13.pacbell.net>
[not found] ` <20071216052308.A0FB11668D7-ZcXrCSuhvln6VZ3dlLfH/g4gEjPzgfUyLrfjE7I9kuVHxeISYlDBzl6hYfS7NtTn@public.gmane.org>
2007-12-27 20:58 ` [patch 2.6.24-rc5-git] add i2c_new_dummy() utility Byron Bradley
[not found] ` <57e2b00712271258l6ea661ai2bfd6b9e099c71be-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-12-27 21:53 ` David Brownell
[not found] ` <200712271353.05857.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-12-27 22:09 ` Byron Bradley
[not found] ` <57e2b00712271409n6c98f76o45116cd92b01f396-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-12-27 23:06 ` David Brownell
[not found] ` <200712271506.43069.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-12-27 23:37 ` Byron Bradley
2007-12-27 23:59 ` David Brownell
[not found] ` <200712281230.17840.david-b@pacbell.net>
[not found] ` <57e2b00712281645y70f6ec74s57945dc53f113ec8@mail.gmail.com>
[not found] ` <57e2b00712281645y70f6ec74s57945dc53f113ec8-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-12-30 3:05 ` David Brownell
[not found] ` <200712291905.15160.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-01-04 22:16 ` Jean Delvare
[not found] ` <20080104231633.135f2875-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-01-04 23:48 ` David Brownell
[not found] ` <200801041548.54825.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-01-06 9:57 ` Jean Delvare
2008-01-06 11:23 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
[not found] ` <20080106122356.78556b8a-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-01-06 19:30 ` i2c-remove-redundant-i2c_client-list.patch David Brownell
[not found] ` <200801061130.31774.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-01-08 14:18 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
[not found] ` <20080108151817.35e05c6c-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-01-08 16:20 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
[not found] ` <20080108172001.33de6afc-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-01-08 19:12 ` i2c-remove-redundant-i2c_client-list.patch David Brownell
[not found] ` <200801081112.46972.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-01-08 20:50 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
[not found] ` <20080108215042.534e32fa-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-01-08 21:44 ` i2c-remove-redundant-i2c_client-list.patch David Brownell
[not found] ` <200801081344.45544.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-01-08 22:04 ` i2c-remove-redundant-i2c_client-list.patch Greg KH
[not found] ` <20080108220445.GB3873-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
2008-01-08 22:27 ` i2c-remove-redundant-i2c_client-list.patch David Brownell
2008-01-09 13:29 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
[not found] ` <20080109142906.23a55f5f-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-01-09 16:19 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
[not found] ` <20080109171934.4f894bdc-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-01-09 21:21 ` i2c-remove-redundant-i2c_client-list.patch David Brownell
[not found] ` <200801091321.29212.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-01-10 13:31 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
[not found] ` <20080110143105.456ddaf0-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-01-14 22:20 ` i2c-remove-redundant-i2c_client-list.patch David Brownell
[not found] ` <200801141420.49274.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-01-17 22:02 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
2008-01-18 10:14 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
[not found] ` <20080118111401.7ffdccc5-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-01-18 10:30 ` i2c-remove-redundant-i2c_client-list.patch David Brownell
2008-01-14 22:42 ` i2c-remove-redundant-i2c_client-list.patch David Brownell
2008-01-17 19:35 ` i2c-remove-redundant-i2c_client-list.patch David Brownell
[not found] ` <200801171135.45797.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-01-17 19:59 ` i2c-remove-redundant-i2c_client-list.patch David Brownell
[not found] ` <200801171159.00291.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-01-18 9:32 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
[not found] ` <20080118103209.4b92ac76-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-01-18 10:16 ` i2c-remove-redundant-i2c_client-list.patch David Brownell
[not found] ` <200801180216.22363.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-01-18 12:10 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
2008-01-08 18:52 ` i2c-remove-redundant-i2c_client-list.patch David Brownell
[not found] ` <200801081052.31413.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-01-08 19:57 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
2008-01-09 16:09 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
2008-01-06 19:43 ` i2c-remove-redundant-i2c_client-list.patch David Brownell
[not found] ` <200801061143.34020.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-01-08 14:21 ` i2c-remove-redundant-i2c_client-list.patch Jean Delvare
2008-01-17 22:24 ` [patch 2.6.24-rc5-git] add i2c_new_dummy() utility David Brownell
2007-12-22 17:31 Jean Delvare
[not found] ` <kOXVGr9s.1198344701.9162110.khali-IO4AeUl/lkuWVfeAwA7xHQ@public.gmane.org>
2007-12-23 5:08 ` David Brownell
[not found] ` <200712222108.51292.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-12-23 5:11 ` David Brownell
[not found] ` <200712222111.09471.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-12-23 9:03 ` Jean Delvare
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox