From: Ralf Baechle <ralf@linux-mips.org>
To: Marc St-Jean <stjeanma@pmc-sierra.com>
Cc: linux-mips@linux-mips.org
Subject: Re: [PATCH 2/5] mips: PMC MSP71xx mips common
Date: Fri, 16 Mar 2007 01:58:47 +0000 [thread overview]
Message-ID: <20070316015847.GB14865@linux-mips.org> (raw)
In-Reply-To: <200703071801.l27I1Yfs012803@pasqua.pmc-sierra.bc.ca>
On Wed, Mar 07, 2007 at 12:01:34PM -0600, Marc St-Jean wrote:
Looks fine ... except this one:
> diff --git a/include/asm-mips/regops.h b/include/asm-mips/regops.h
> new file mode 100644
> index 0000000..375c667
> --- /dev/null
> +++ b/include/asm-mips/regops.h
> @@ -0,0 +1,166 @@
> +/*
> + * VPE/SMP-safe functions to access registers. They use ll/sc instructions, so
> + * it is your responsibility to ensure these are available on your platform
> + * before including this file.
> + *
> + * In addition, there is a bug on the R10000 chips which has a workaround. If
> + * you are affected by this bug, make sure to define the symbol
> + * 'R10000_LLSC_WAR' to be non-zero. If you are using this header from within
> + * linux, you may include <asm/war.h> before including this file to have this
> + * defined appropriately for you.
> + *
> + * Copyright 2005 PMC-Sierra, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
> + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc., 675
> + * Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifndef __ASM_REGOPS_H__
> +#define __ASM_REGOPS_H__
> +
> +#ifndef R10000_LLSC_WAR
> +#define R10000_LLSC_WAR 0
> +#endif
Better include <asm/war.h> or R10000_LLSC_WAR might have an unexpected value.
> +#if R10000_LLSC_WAR == 1
> +#define __beqz "beqzl "
> +#else
> +#define __beqz "beqz "
> +#endif
> +
> +#ifndef _LINUX_TYPES_H
> +typedef unsigned int uint32_t;
> +#endif
Again, include <linux/types.h>. Including this file first then <linux/types.h>
will result in a duplicate definition ...
> +/*
> + * Sets all the masked bits to the corresponding value bits
> + */
> +static inline void set_value_reg32( volatile uint32_t * const addr,
> + uint32_t const mask,
> + uint32_t const value )
> +{
> + uint32_t temp;
> +
> + __asm__ __volatile__(
> + " .set mips3 \n"
> + "1: ll %0, %1 # set_value_reg32 \n"
> + " and %0, %2 \n"
> + " or %0, %3 \n"
> + " sc %0, %1 \n"
> + " "__beqz"%0, 1b \n"
> + " .set mips0 \n"
> + : "=&r" (temp), "=m" (*addr)
> + : "ir" (~mask), "ir" (value), "m" (*addr) );
> +}
> +
> +/*
> + * Sets all the masked bits to '1'
> + */
> +static inline void set_reg32( volatile uint32_t * const addr,
> + uint32_t const mask )
> +{
> + uint32_t temp;
> +
> + __asm__ __volatile__(
> + " .set mips3 \n"
> + "1: ll %0, %1 # set_reg32 \n"
> + " or %0, %2 \n"
> + " sc %0, %1 \n"
> + " "__beqz"%0, 1b \n"
> + " .set mips0 \n"
> + : "=&r" (temp), "=m" (*addr)
> + : "ir" (mask), "m" (*addr) );
> +}
> +
> +/*
> + * Sets all the masked bits to '0'
> + */
> +static inline void clear_reg32( volatile uint32_t * const addr,
> + uint32_t const mask )
> +{
> + uint32_t temp;
> +
> + __asm__ __volatile__(
> + " .set mips3 \n"
> + "1: ll %0, %1 # clear_reg32 \n"
> + " and %0, %2 \n"
> + " sc %0, %1 \n"
> + " "__beqz"%0, 1b \n"
> + " .set mips0 \n"
> + : "=&r" (temp), "=m" (*addr)
> + : "ir" (~mask), "m" (*addr) );
> +}
> +
> +/*
> + * Toggles all masked bits from '0' to '1' and '1' to '0'
> + */
> +static inline void toggle_reg32( volatile uint32_t * const addr,
> + uint32_t const mask )
> +{
> + uint32_t temp;
> +
> + __asm__ __volatile__(
> + " .set mips3 \n"
> + "1: ll %0, %1 # toggle_reg32 \n"
> + " xor %0, %2 \n"
> + " sc %0, %1 \n"
> + " "__beqz"%0, 1b \n"
> + " .set mips0 \n"
> + : "=&r" (temp), "=m" (*addr)
> + : "ir" (mask), "m" (*addr) );
> +}
As I understand you're using the preceeding 4 functions with the address
pointing to device registers, that is uncached memory? The operation of
ll/sc on uncached memory is undefined.
So to fix this you'd have to use something like this:
unsigned long flags;
spinlock_t lock;
spin_lock_irqsave(&lock, flags);
writel(readl(addr) | mask);
spin_unlock_restore(&lock, flags);
Which of course is considerably slower and heavier weight.
> +/* For special strange cases only:
> + *
> + * If you need custom processing within a ll/sc loop, use the following macros
> + * VERY CAREFULLY:
> + *
> + * uint32_t tmp; <-- Define a variable to hold the data
> + *
> + * custom_reg32_start(address, tmp); <-- Reads the address and puts the value
> + * in the 'tmp' variable given
> + *
> + * < From here on out, you are (basicly) atomic, so don't do anything too
> + * < fancy!
> + * < Also, this code may loop if the end of this block fails to write
> + * < everything back safely due do the other CPU, so do NOT do anything
> + * < with side-effects!
> + *
> + * custom_reg32_stop(address, tmp); <-- Writes back 'tmp' safely.
> + *
> + */
> +#define custom_reg32_read(address, tmp) \
> + __asm__ __volatile__( \
> + " .set mips3 \n" \
> + "1: ll %0, %1 #custom_reg32_read \n" \
> + " .set mips0 \n" \
> + : "=r" (tmp), "=m" (*address) \
> + : "m" (*address) )
> +
> +#define custom_reg32_write(address, tmp) \
> + __asm__ __volatile__( \
> + " .set mips3 \n" \
> + " sc %0, %1 #custom_reg32_write \n" \
> + " "__beqz"%0, 1b \n" \
> + " .set mips0 \n" \
> + : "=&r" (tmp), "=m" (*address) \
> + : "0" (tmp), "m" (*address) )
> +
> +#endif /* __ASM_REGOPS_H__ */
Same comment as above applies for uncached accesses.
I used to have functions that expand into ll/sc in the kernel ages ago -
gcc did generate interesting (for some definition of interesting) but not
terribly useful code from it. The chance that something like this is
happening has grown even further thanks to the more agressive optimizer
of modern gcc.
A valid ll/sc sequence also requires that there may not be another
load or store in between these two instructions. So for example:
+ custom_reg32_read(MSP_GPIO_DATA_REGISTER[gpio],
+ tmpdata);
+ if (tmpdata & EXTENDED_CLR(gpio))
+ tmpdata = EXTENDED_CLR(gpio);
+ else
+ tmpdata = EXTENDED_SET(gpio);
+ custom_reg32_write(MSP_GPIO_DATA_REGISTER[gpio],
+ tmpdata);
What if gcc just because it feels like it puts tmpdata or gpio into the
stackframe? In this particular case there is little register pressure
so it's unlikely but be afraid, be very afraid ...
Ralf
next prev parent reply other threads:[~2007-03-16 2:01 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-03-07 18:01 [PATCH 2/5] mips: PMC MSP71xx mips common Marc St-Jean
2007-03-16 1:58 ` Ralf Baechle [this message]
-- strict thread matches above, loose matches on Subject: below --
2007-03-16 23:53 Marc St-Jean
2007-03-17 0:46 ` Ralf Baechle
2007-03-01 20:41 Marc St-Jean
2007-02-28 22:35 Marc St-Jean
2007-02-28 21:35 Marc St-Jean
2007-02-28 21:43 ` Uhler, Mike
2007-02-28 21:43 ` Uhler, Mike
2007-02-28 22:18 ` Ralf Baechle
2007-02-28 0:04 Marc St-Jean
2007-02-27 21:27 Marc St-Jean
2007-02-28 19:52 ` Ralf Baechle
2007-02-27 17:59 Marc St-Jean
2007-02-27 20:03 ` Thiemo Seufer
2007-02-27 17:09 Marc St-Jean
2007-02-27 17:38 ` Thiemo Seufer
2007-02-28 19:32 ` Ralf Baechle
2007-02-27 18:46 ` Andrew Sharp
2007-02-28 19:42 ` Ralf Baechle
2007-02-27 0:12 Marc St-Jean
2007-02-27 0:43 ` Andrew Sharp
2007-02-23 21:27 Marc St-Jean
2007-02-23 21:15 Marc St-Jean
2007-02-23 20:53 Marc St-Jean
2007-02-23 21:02 ` Sergei Shtylyov
2007-02-23 21:02 ` David Daney
2007-02-23 19:56 Marc St-Jean
2007-02-23 20:35 ` Sergei Shtylyov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070316015847.GB14865@linux-mips.org \
--to=ralf@linux-mips.org \
--cc=linux-mips@linux-mips.org \
--cc=stjeanma@pmc-sierra.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.