diff options
author | Arnd Bergmann <arnd@arndb.de> | 2013-06-21 21:55:35 +0200 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2015-08-07 00:32:19 +0100 |
commit | cee9e1e861382df144a3a880f8e2c89285197a3e (patch) | |
tree | c3d5326bb40ae77ce345dfcd5d459fb135f6d3f4 | |
parent | 53774d1d22885f5bf14645baf551a3c4b6a6efba (diff) |
staging: line6: avoid __sync_fetch_and_{and,or}
commit 9f613601482c56e05884f21565e3d218fac427ae upstream.
__sync_fetch_and_and and __sync_fetch_and_or are functions that are provided
by gcc and depending on the target architecture may be implemented in libgcc,
which is not always available in the kernel. This leads to a build failure
on ARMv5:
drivers/built-in.o: In function `line6_pcm_release':
:(.text+0x3bfe80): undefined reference to `__sync_fetch_and_and_4'
drivers/built-in.o: In function `line6_pcm_acquire':
:(.text+0x3bff30): undefined reference to `__sync_fetch_and_or_4'
To work around this, we can use the kernel-provided cmpxchg macro.
Build-tested only.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Markus Grabner <grabner@icg.tugraz.at>
Acked-by: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[bwh: Backported to 3.2:
- Adjust context
- Fix up two more instances of __sync_fetch_and_and() that were removed
separately upstream]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r-- | drivers/staging/line6/pcm.c | 40 |
1 files changed, 25 insertions, 15 deletions
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c index 2d3a420d6038..955c6dee6adb 100644 --- a/drivers/staging/line6/pcm.c +++ b/drivers/staging/line6/pcm.c @@ -88,10 +88,13 @@ static DEVICE_ATTR(impulse_period, S_IWUSR | S_IRUGO, pcm_get_impulse_period, int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels) { - unsigned long flags_old = - __sync_fetch_and_or(&line6pcm->flags, channels); - unsigned long flags_new = flags_old | channels; - int err = 0; + unsigned long flags_old, flags_new; + int err; + + do { + flags_old = ACCESS_ONCE(line6pcm->flags); + flags_new = flags_old | channels; + } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); #if LINE6_BACKUP_MONITOR_SIGNAL if (!(line6pcm->line6->properties->capabilities & LINE6_BIT_HWMON)) { @@ -133,10 +136,8 @@ int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels) line6pcm->prev_fsize = 0; err = line6_submit_audio_in_all_urbs(line6pcm); - if (err < 0) { - __sync_fetch_and_and(&line6pcm->flags, ~channels); - return err; - } + if (err < 0) + goto fail; } if (((flags_old & MASK_PLAYBACK) == 0) && @@ -160,20 +161,29 @@ int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels) line6pcm->count_out = 0; err = line6_submit_audio_out_all_urbs(line6pcm); - if (err < 0) { - __sync_fetch_and_and(&line6pcm->flags, ~channels); - return err; - } + if (err < 0) + goto fail; } return 0; + +fail: + do { + flags_old = ACCESS_ONCE(line6pcm->flags); + flags_new = flags_old & ~channels; + } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); + + return err; } int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels) { - unsigned long flags_old = - __sync_fetch_and_and(&line6pcm->flags, ~channels); - unsigned long flags_new = flags_old & ~channels; + unsigned long flags_old, flags_new; + + do { + flags_old = ACCESS_ONCE(line6pcm->flags); + flags_new = flags_old & ~channels; + } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); if (((flags_old & MASK_CAPTURE) != 0) && ((flags_new & MASK_CAPTURE) == 0)) { |