[PATCH linux] mtd: spi-nor: aspeed-smc: Use io string accessors to fifo

Andrew Jeffery andrew at aj.id.au
Fri Feb 19 11:35:09 AEDT 2016


On Thu, 2016-02-18 at 22:50 +0000, Milton Miller II wrote:
> Around 02/11/2016 08:59PM in some timezone,  Andrew Jeffery wrote:
> > Hi Milton,
> > 
> > Excuse the unnecessary quote markers that might appear through the
> > patch, my mail client (Evolution) seems to have a mind of its own
> > sometimes. Starting to shave that yak. Anyway.
> 
> It can't be worse than me manually quoting in smart cloud notes client.
> 
> > 
> > As an aside I've tested an earlier version of the code and confirmed
> > the approach works (i.e. no JFFS2 corruption on re-mount).
> 
> Yea.
> 
> 
> > On Wed, 2016-02-10 at 21:50 -0600, OpenBMC Patches wrote:
> > > From: "Milton D. Miller II" <miltonm at us.ibm.com>
> > > 
> > > Make and use new routines to access the fifo when in user mode.
> > > Instead of using memcpy_fromio, base the new routines on the io
> > >  port string accessors.
> > > 
> ...
> > typo: unsigned
> fixed
> 
> 
> > > +static void *ins_align(unsigned long io, void *buf, size_t len)
> > > +{
> > > +> > > > 	> > > > BUILD_BUG_ON(0 & len & ~3);
> > 
> > Should just be BUG_ON()? Given that you disabled it with '0 &', do we
> > want it at all?
> 
> It should definitively not be a driver BUG that crashes the whole system.  If 
> you need I can search for Linus' quote about the use of BUG in drivers.

Sure - but if we needed to use a bug macro then it needs to be one that
triggers at runtime, as you've used a formal parameter whose value
won't be known at compile time right? That's what I was (poorly) trying
to express.

Unless the optimiser gets involved and reasons about actual parameters
from callers? Anyway, this is largely a distraction.

> 
> It can be killed.

SGTM

> 
> > > + */
> > > +
> > > +static void aspeed_smc_from_fifo(void *buf, const void __iomem *iop, size_t len)
> > > +{
> > > +> > > > 	> > > > unsigned long io = (__force unsigned long)iop;
> > > +
> ...
> > > +> > > > 	> > > > > > > 	> > > > buf = ins_align(io, buf, len & 1);
> > > +> > > > 	> > > > } else {
> > > +> > > > 	> > > > > > > 	> > > > size_t l = (4 - (unsigned long)buf) & 3;
> > > +
> > > +> > > > 	> > > > > > > 	> > > > l = min(l, len);
> > > +> > > > 	> > > > > > > 	> > > > buf = ins_align(io, buf, l);
> > > +> > > > 	> > > > > > > 	> > > > len -= l;
> > > +
> > > +> > > > 	> > > > > > > 	> > > > if (len >= 4) {
> > > +> > > > 	> > > > > > > 	> > > > > > > 	> > > > insl(io, buf, len >> 2);
> > > +> > > > 	> > > > > > > 	> > > > > > > 	> > > > buf += len & ~3;
> > > +> > > > 	> > > > > > > 	> > > > }
> > > +> > > > 	> > > > > > > 	> > > > buf = ins_align(io, buf, len & 3);
> > > +> > > > 	> > > > }
> > 
> > So I've tried deduplicating this function - the code in the latter two
> > cases is largely the same bar the magic numbers and insw vs insl. I've
> > come up with the code below (note that I haven't actually probed the
> > modifications), but I'm not convinced it's much of a win in terms of
> > clarity:
> > 
> > /* Is this available somewhere else? Rusty doesn't think so.
> >  * Probably needs a better name (first set value) */
> > #define FS_VAL(x) ((x) & ~((x) - 1))
> 
> That is a horrible name!  What is this magic file system value about?

Yes, I admitted that in the comment!

> 
> > 
> > static void aspeed_smc_from_fifo(void *buf, const void __iomem *iop, size_t len)
> > {
> > 	> > unsigned long io = (__force unsigned long)iop;
> >         u8 align = FS_VAL((io & 7) | 4); /* align is one of 1, 2 or 4 */
> 
> I see masking & 7 and comment about being 1, 2, or 4 and think:
> 
> That's not true, the port bit doesn't always have bit 4 on when
> the others are off.
> 
> Only after a long pause coming back do I see the | 4, and then I have
> to go back to a macro above to figure out is it before or after the
> fancy math.

Yeah, adding further magic to what was there already was a dicey idea.
The code was more something to spark discussion of alternatives than a
genuine proposal.

> 
> 
> >         u8 mask = align - 1;
> >         size_t to_align = align - ((unsigned long)buf) & mask);
> > 
> > 	> > if (align == 1) {
> > 	> > 	> > insb(io, buf, len);
> >                 return;
> > 	> > }
> >         to_align = min(to_align, len);
> >         buf = ins_align(io, buf, to_align);
> >         len -= to_align;
> > 	> > if (len >= align) {
> > 	> > 	> > size_t nr_blocks = len / align;
> > 	> > 	> > if (align == 2) {
> > 	> > 	> > 	> > insw(io, buf, nr_blocks);
> > 	> > 	> > } else {
> > 	> > 	> > 	> > insl(io, buf, nr_blocks);
> > 	> > 	> > }
> > 	> > 	> > buf += (nr_blocks * align);
> > 	> > }
> >         buf = ins_align(io, buf, len & mask);
> > 
> > Is it worth it? A similar approach can be taken for
> > aspeed_smc_to_fifo() if so.
> 
> So I think this approach hides what is supposed to happen
> in the case we are actually using.
> 
> I decided on a different approach to the remove the duplication:

Cool, as mentioned above I mainly posted my hack to trigger thoughts
about alternatives, so I'm happy it's done that :)

> 
> Don't add code that will not be used.
> 
> We always pass a 4 byte aligned port.  Rather than bug, 
> just call insb if the io port is not aligned.  
> 
> Then remove the ins_align and outs_align function and 
> bring them inline, but expand top and bottom call sites 
> to order the byte vs (half)word transfers to remove
> the get/put_unaligned pessimisation since we are testing 
> the alignemnt and can choose the order by context.
> 
> I then removed the updates to buf and len that were dead
> in the tail code.
> 
> With 2 one-line comments and no white space it fits in 
> 80x25 which means you can see all the code after the 
> preliminary 0 length and unaligned checks on one screen.
> 
> 
> > 
> > As for whether there's a better approach short of fixing mmiocpy(), I
> > don't know, so no further suggestions really (i.e. I guess we just live
> > with the IO_SPACE_LIMIT jiggery-pokery).
> > 
> 
> When I started to go back and comment the assembly I figured out the
> memcpy has 2 places it can stutter:
> 
> It first aligns source to a word boundary with byte copies.  After that 
> it works on aligning the destination.  It will do an extra load at this
> point if the destination is not aligned to the source.  Then it sometimes 
> aligns to cache lines (depends on core if it helps), then transfers
> blocks, back to words, then if there are upto 3 bytes it backs up and
> switches back to bytes (reading bytes a second time here).
> 
> So there are two places to fix, one stutters output and one input.
> 
> I thought about switching read/write to engine mode.  I probably still
> will sometime.  The stutters will cause it to stop and resend the 
> address slowing down the access.  Hmm, that might cause double write 
> attempt at the stutter...

Ugh

> 
> Anyways, see what you think of the current code.

Will do, thanks for the detailed response!

Andrew

> 
> Thanks,
> milton
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.ozlabs.org/pipermail/openbmc/attachments/20160219/4bb43bb3/attachment.sig>


More information about the openbmc mailing list