From: Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
To: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Subject: Re: [PATCH 2/5] mips: PMC MSP71xx mips common
Date: Fri, 16 Mar 2007 15:53:15 -0800 [thread overview]
Message-ID: <45FB2DEB.70204@pmc-sierra.com> (raw)
Ralf Baechle wrote:
> 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.
[...]
> > + */
> > +
> > +#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.
Thanks, will do.
> > +#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 ...
OK.
> > +/*
> > + * 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.
I have been searching for information on this in various 34k manuals as
well as Dominic's See MIPS Run 2nd Ed. and have not found this limitation
stated anywhere.
Programming the MIPS32 34K Core Family (MD00427) Section 3.5 states:
"The MIPS MT ASE requires that ll/sc also work between concurrent threads
on an MT CPU. Each TC is equipped with a CP0 register called LLAddr, which
remembers the physical address (at least to the enclosing 32-byte block) of
the target location of any ll/sc sequence. The 34K core detects possible
non-atomicity by checking every write made by any thread against the LLAddr
of all other TCs."
Doesn't the fact that a physical address is being compared imply any logical
address type can be used?
> 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.
I don't believe we can use a linux lock as the code running on the other TCs
is not necessarily a linux driver/thread/process. It does not share linux's
lock implementation.
> > +/* 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:
MIPS32 34K Processor Core Family Software User's Manual (MD00534)
Store Conditional Word instruction states:
"If either of the following events occurs between the execution of LL and
SC, the SC may succeed or it may fail; the success or failure is not
predictable. Portable programs should not cause one of these events.
-A memory access instruction (load, store, or prefetch) is executed on
the processor executing the LL/SC.
-The instructions executed starting with the LL and ending with the SC
do not lie in a 2048-byte contiguous region of virtual memory. (The
region does not have to be aligned, other than the alignment required
for instruction words.)"
For the first of these points, if a failure occurs because of activity
on another TC, the loop should repeat until success.
For the second point, the code between custom_reg32_read and
custom_reg32_write is meant to be very simple. We can live with a
2k limit.
> + 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
We've been using this for a year with different versions of gcc and
have not encountered any problems. We could declare tmpdata as
"register" and increase the odds of it being allocated into a register.
Marc
next reply other threads:[~2007-03-16 23:54 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-03-16 23:53 Marc St-Jean [this message]
2007-03-17 0:46 ` [PATCH 2/5] mips: PMC MSP71xx mips common Ralf Baechle
-- strict thread matches above, loose matches on Subject: below --
2007-03-07 18:01 Marc St-Jean
2007-03-16 1:58 ` 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=45FB2DEB.70204@pmc-sierra.com \
--to=marc_st-jean@pmc-sierra.com \
--cc=linux-mips@linux-mips.org \
--cc=ralf@linux-mips.org \
/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.