Re: OMAP4430 SDP with KS8851: very slow networking

2018-12-07 Thread Russell King - ARM Linux
On Fri, Dec 07, 2018 at 11:03:12AM -0800, Tony Lindgren wrote:
> * Tony Lindgren  [181207 18:14]:
> > Hi,
> > 
> > * Russell King - ARM Linux  [181207 18:01]:
> > > Hi Tony,
> > > 
> > > You know most of what's been going on from IRC, but here's the patch
> > > which gets me:
> > > 
> > > 1) working interrupts for networking
> > > 2) solves the stuck-wakeup problem
> > > 
> > > It also contains some of the debug bits I added.
> > 
> > This is excellent news :) Will test today.
> 
> Yes your patch seems to work great based on brief testing :)
> 
> > > I think what this means is that we should strip out ec0daae685b2
> > > ("gpio: omap: Add level wakeup handling for omap4 based SoCs").
> > 
> > Yes the only reason for the wakeup quirk was the stuck wakeup
> > state seen on omap4, it can be just dropped if this works.
> > Adding Grygorii to Cc too.
> 
> I'll post a partial revert for commit ec0daae685b2 ("gpio: omap:
> Add level wakeup handling for omap4 based SoCs") shortly.

Hi,

You mentioned that edge mode didn't work as well as level mode on
duovero smsc controller, I think this may help to solve the same
issue but for edge IRQs - we need a mask_ack_irq function to avoid
acking while the edge interrupt is masked.  Let me know if that
lowers the smsc ping latency while in edge mode.

Thanks.

diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 3d021f648c5d..b1ad6098e894 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -11,7 +11,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define DEBUG
 #include 
 #include 
 #include 
@@ -366,10 +366,14 @@ static inline void omap_set_gpio_trigger(struct gpio_bank 
*bank, int gpio,
  trigger & IRQ_TYPE_LEVEL_LOW);
omap_gpio_rmw(base, bank->regs->leveldetect1, gpio_bit,
  trigger & IRQ_TYPE_LEVEL_HIGH);
+   /*
+* We need the edge detect enabled for the idle mode detection
+* to function on OMAP4430.
+*/
omap_gpio_rmw(base, bank->regs->risingdetect, gpio_bit,
- trigger & IRQ_TYPE_EDGE_RISING);
+ trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH));
omap_gpio_rmw(base, bank->regs->fallingdetect, gpio_bit,
- trigger & IRQ_TYPE_EDGE_FALLING);
+ trigger & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW));
 
bank->context.leveldetect0 =
readl_relaxed(bank->base + bank->regs->leveldetect0);
@@ -899,6 +903,19 @@ static void omap_gpio_mask_irq(struct irq_data *d)
raw_spin_unlock_irqrestore(>lock, flags);
 }
 
+static void omap_gpio_mask_ack_irq(struct irq_data *d)
+{
+   struct gpio_bank *bank = omap_irq_data_get_bank(d);
+   unsigned offset = d->hwirq;
+   unsigned long flags;
+
+   raw_spin_lock_irqsave(>lock, flags);
+   omap_clear_gpio_irqstatus(bank, offset);
+   omap_set_gpio_irqenable(bank, offset, 0);
+   omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+   raw_spin_unlock_irqrestore(>lock, flags);
+}
+
 static void omap_gpio_unmask_irq(struct irq_data *d)
 {
struct gpio_bank *bank = omap_irq_data_get_bank(d);
@@ -910,14 +927,16 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
if (trigger)
omap_set_gpio_triggering(bank, offset, trigger);
 
+   omap_set_gpio_irqenable(bank, offset, 1);
+
/* For level-triggered GPIOs, the clearing must be done after
-* the HW source is cleared, thus after the handler has run */
-   if (bank->level_mask & BIT(offset)) {
-   omap_set_gpio_irqenable(bank, offset, 0);
+* the HW source is cleared, thus after the handler has run.
+* OMAP4 needs this done _after_ enabing the interrupt to clear
+* the wakeup status.
+*/
+   if (bank->level_mask & BIT(offset))
omap_clear_gpio_irqstatus(bank, offset);
-   }
 
-   omap_set_gpio_irqenable(bank, offset, 1);
raw_spin_unlock_irqrestore(>lock, flags);
 }
 
@@ -1377,6 +1396,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
 
irqc->irq_startup = omap_gpio_irq_startup,
irqc->irq_shutdown = omap_gpio_irq_shutdown,
+   irqc->irq_mask_ack = omap_gpio_mask_ack_irq,
irqc->irq_ack = omap_gpio_ack_irq,
irqc->irq_mask = omap_gpio_mask_irq,
irqc->irq_unmask = omap_gpio_unmask_irq,
@@ -1520,6 +1540,10 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool 
may_lose_context)
struct device *dev = bank->chip.parent;
u32 l1 = 0, l2 = 0;
 
+

Re: OMAP4430 SDP with KS8851: very slow networking

2018-12-07 Thread Russell King - ARM Linux
Hi Tony,

You know most of what's been going on from IRC, but here's the patch
which gets me:

1) working interrupts for networking
2) solves the stuck-wakeup problem

It also contains some of the debug bits I added.

I think what this means is that we should strip out ec0daae685b2
("gpio: omap: Add level wakeup handling for omap4 based SoCs").

diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 3d021f648c5d..528ffd1b9832 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -11,7 +11,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define DEBUG
 #include 
 #include 
 #include 
@@ -366,10 +366,14 @@ static inline void omap_set_gpio_trigger(struct gpio_bank 
*bank, int gpio,
  trigger & IRQ_TYPE_LEVEL_LOW);
omap_gpio_rmw(base, bank->regs->leveldetect1, gpio_bit,
  trigger & IRQ_TYPE_LEVEL_HIGH);
+   /*
+* We need the edge detect enabled for the idle mode detection
+* to function on OMAP4430.
+*/
omap_gpio_rmw(base, bank->regs->risingdetect, gpio_bit,
- trigger & IRQ_TYPE_EDGE_RISING);
+ trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH));
omap_gpio_rmw(base, bank->regs->fallingdetect, gpio_bit,
- trigger & IRQ_TYPE_EDGE_FALLING);
+ trigger & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW));
 
bank->context.leveldetect0 =
readl_relaxed(bank->base + bank->regs->leveldetect0);
@@ -910,14 +914,16 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
if (trigger)
omap_set_gpio_triggering(bank, offset, trigger);
 
+   omap_set_gpio_irqenable(bank, offset, 1);
+
/* For level-triggered GPIOs, the clearing must be done after
-* the HW source is cleared, thus after the handler has run */
-   if (bank->level_mask & BIT(offset)) {
-   omap_set_gpio_irqenable(bank, offset, 0);
+* the HW source is cleared, thus after the handler has run.
+* OMAP4 needs this done _after_ enabing the interrupt to clear
+* the wakeup status.
+*/
+   if (bank->level_mask & BIT(offset))
omap_clear_gpio_irqstatus(bank, offset);
-   }
 
-   omap_set_gpio_irqenable(bank, offset, 1);
raw_spin_unlock_irqrestore(>lock, flags);
 }
 
@@ -1520,6 +1526,10 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool 
may_lose_context)
struct device *dev = bank->chip.parent;
u32 l1 = 0, l2 = 0;
 
+   dev_dbg(dev, "%s(): ld 0x%08x 0x%08x we 0x%08x\n", __func__,
+   bank->context.leveldetect0, bank->context.leveldetect1,
+   bank->context.wake_en);
+
if (bank->funcs.idle_enable_level_quirk)
bank->funcs.idle_enable_level_quirk(bank);
 
@@ -1553,6 +1563,10 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool 
may_lose_context)
bank->get_context_loss_count(dev);
 
omap_gpio_dbck_disable(bank);
+
+   dev_dbg(dev, "%s(): ld 0x%08x 0x%08x we 0x%08x\n", __func__,
+   bank->context.leveldetect0, bank->context.leveldetect1,
+   bank->context.wake_en);
 }
 
 static void omap_gpio_init_context(struct gpio_bank *p);
@@ -1563,6 +1577,10 @@ static void omap_gpio_unidle(struct gpio_bank *bank)
u32 l = 0, gen, gen0, gen1;
int c;
 
+   dev_dbg(dev, "%s(): ld 0x%08x 0x%08x we 0x%08x\n", __func__,
+   bank->context.leveldetect0, bank->context.leveldetect1,
+   bank->context.wake_en);
+
/*
 * On the first resume during the probe, the context has not
 * been initialised and so initialise it now. Also initialise
@@ -1648,6 +1666,10 @@ static void omap_gpio_unidle(struct gpio_bank *bank)
}
 
bank->workaround_enabled = false;
+
+   dev_dbg(dev, "%s(): ld 0x%08x 0x%08x we 0x%08x\n", __func__,
+   bank->context.leveldetect0, bank->context.leveldetect1,
+   bank->context.wake_en);
 }
 
 static void omap_gpio_init_context(struct gpio_bank *p)
@@ -1720,6 +1742,7 @@ static int __maybe_unused 
omap_gpio_runtime_suspend(struct device *dev)
error = -EBUSY;
goto unlock;
}
+   dev_dbg(dev, "%s()\n", __func__);
omap_gpio_idle(bank, true);
bank->is_suspended = true;
 unlock:
@@ -1741,6 +1764,7 @@ static int __maybe_unused omap_gpio_runtime_resume(struct 
device *dev)
error = -EBUSY;
goto unlock;
}
+   dev_dbg(dev, "%s()\n", __func__);
omap_gpio_unidle(bank);
bank->is_suspended = false;
 unlock:
@@ -1827,8 +1851,8 @@ static const struct omap_gpio_platform_data omap4_pdata = 
{
.regs = _gpio_regs,
.bank_width = 32,
.dbck_flag = true,
-   .quirks = 

Re: [RFC PATCH 4/6] dt-bindings: update mvneta binding document

2018-12-07 Thread Russell King - ARM Linux
On Fri, Dec 07, 2018 at 05:30:52PM +0530, Kishon Vijay Abraham I wrote:
> Hi,
> 
> On 07/12/18 5:03 PM, Russell King - ARM Linux wrote:
> > On Fri, Dec 07, 2018 at 04:43:27PM +0530, Kishon Vijay Abraham I wrote:
> >> Russell,
> >>
> >> No, I haven't merged patches from this series. That would have failed
> >> compilation since Grygorii modified enum phy_mode which is used in this 
> >> series.
> >> You have also noted this in your cover letter.
> > 
> > Ok, but in any case, given the complexities of modifying the patch
> > and properly testing it, I think I'll wait until those changes have
> > hit mainline before re-spinning this series.  Alternatively, if
> > you're happy to take just build-tested version, I could re-spin
> > with that so at least we can get the phy bits queued for the merge
> > window.
> 
> I'd prefer we test it before merging.

Okay, expect it sometime after Christmas.  In any case, waiting for
the upheaval in the phy API to hit mainline will need to happen to
that netdev is in sync with the revised phy API.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [RFC PATCH 4/6] dt-bindings: update mvneta binding document

2018-12-07 Thread Russell King - ARM Linux
On Fri, Dec 07, 2018 at 04:43:27PM +0530, Kishon Vijay Abraham I wrote:
> Russell,
> 
> No, I haven't merged patches from this series. That would have failed
> compilation since Grygorii modified enum phy_mode which is used in this 
> series.
> You have also noted this in your cover letter.

Ok, but in any case, given the complexities of modifying the patch
and properly testing it, I think I'll wait until those changes have
hit mainline before re-spinning this series.  Alternatively, if
you're happy to take just build-tested version, I could re-spin
with that so at least we can get the phy bits queued for the merge
window.

In any case, I'm busy trying to get to the bottom of several OMAP4
bugs while ill, so this isn't something I want to do at the moment.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [RFC PATCH 4/6] dt-bindings: update mvneta binding document

2018-12-07 Thread Russell King - ARM Linux
On Fri, Dec 07, 2018 at 09:37:54AM +0530, Kishon Vijay Abraham I wrote:
> Hi Russell,
> 
> On 05/12/18 9:00 PM, Rob Herring wrote:
> > On Wed, Dec 5, 2018 at 5:00 AM Russell King - ARM Linux
> >  wrote:
> >>
> >> On Mon, Dec 03, 2018 at 05:54:55PM -0600, Rob Herring wrote:
> >>> On Mon, Nov 12, 2018 at 12:31:02PM +, Russell King wrote:
> >>>> Signed-off-by: Russell King 
> >>>
> >>> Needs a better subject and a commit msg.
> >>
> >> Hmm, not sure why it didn't contain:
> >>
> >> "dt-bindings: net: mvneta: add phys property
> >>
> >> Add an optional phys property to the mvneta binding documentation for
> >> the common phy.
> >>
> >> Signed-off-by: Russell King "
> >>
> >> as the commit message.  With the correct commit message, are you happy
> >> with it?
> > 
> > Yes.
> > 
> > Reviewed-by: Rob Herring 
> 
> Are you planning to resend this series?

I'm not - you said previously that you had merged the first three
patches into the phy tree, which are fine.  The next two could be
merged via netdev.  However, we must avoid merging the last patch
with patch 5 if the patches are going via different trees or
mvneta will break.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: OMAP4430 SDP with KS8851: very slow networking

2018-12-06 Thread Russell King - ARM Linux
On Thu, Dec 06, 2018 at 08:31:54AM -0800, Tony Lindgren wrote:
> Hi,
> 
> * Russell King - ARM Linux  [181206 13:23]:
> > It looks very much like a receive problem - in that the board is not
> > always aware of a packet having been received until it attempts to
> > transmit (eg, in the case of TFTP, when it re-sends the ACK after a
> > receive timeout, it _then_ notices that there's a packet waiting.)
> > 
> > I'm not quite sure when this cropped up as I no longer regularly
> > update and run my nightly boot tests, but I think 4.18 was fine.
> 
> Sounds like it's some gpio or PM related issue. If it's not caused
> by commit b764a5863fd8 ("gpio: omap: Remove custom PM calls and
> use cpu_pm instead"), then maybe the changes to probe devices
> with ti-sysc interconnect target module driver caused it. Below
> is a revert for mcspi that would help in that case.

In the interests of keeping the mailing list record up to date, with
the following:

850d434ea37b ("gpio: omap: Remove set but not used variable 'dev'")
c4791bc6e3a6 ("gpio: omap: drop omap_gpio_list")
467480738d0b ("gpio: omap: get rid of the conditional PM runtime calls")
5284521a290e ("gpio: omap: Get rid of pm_runtime_irq_safe()")
b764a5863fd8 ("gpio: omap: Remove custom PM calls and use cpu_pm instead")

reverted, the problem is still there.  Revert:

ec0daae685b2 ("gpio: omap: Add level wakeup handling for omap4 based SoCs")

on top, and networking returns to normal.  So it appears to be this
last commit causing the issue.

With that and b764a5863fd8 applied, it still misbehaves.  Then, poking
at the OMAP4_GPIO_IRQWAKEN0 register, changing it from 0 to 4 with
devmem2 restores normal behaviour - ping times are normal and NFS is
happy.

# devmem2 0x48055044 w 4

(slightly more complex for me as its via NFS and needs different C
libraries from the ones on the rootfs.)

Given that this GPIO device is not runtime suspended, and is
permanently active (which is what I think we expect, given that it
has an IRQ claimed against it) does the hardware still attempt to
idle the GPIO block - if so, could that be why we need to program
the wakeup register, so the GPIO block signals that it's active?

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


OMAP4430 SDP with KS8851: very slow networking

2018-12-06 Thread Russell King - ARM Linux
Hi,

I'm experiencing very slow networking on my OMAP4430 SDP board, which
uses the SPI ethernet chip KS8851.

The initial symptom I noticed is that tftping the 3MB kernel image
inside Linux takes more than 5 minutes.  Running tcpdump on the tftp
server shows:

13:13:29.018377 IP 192.168.1.189.45542 > 192.168.0.4.40620: UDP, length 4
13:13:29.020683 IP 192.168.1.189.45542 > 192.168.0.4.40620: UDP, length 4
13:13:29.022280 IP 192.168.0.4.40620 > 192.168.1.189.45542: UDP, length 516
13:13:29.078391 IP 192.168.1.189.45542 > 192.168.0.4.40620: UDP, length 4
13:13:29.080696 IP 192.168.1.189.45542 > 192.168.0.4.40620: UDP, length 4
13:13:29.082291 IP 192.168.0.4.40620 > 192.168.1.189.45542: UDP, length 516
13:13:29.138377 IP 192.168.1.189.45542 > 192.168.0.4.40620: UDP, length 4
13:13:29.140563 IP 192.168.1.189.45542 > 192.168.0.4.40620: UDP, length 4
13:13:29.142205 IP 192.168.0.4.40620 > 192.168.1.189.45542: UDP, length 516
13:13:29.198365 IP 192.168.1.189.45542 > 192.168.0.4.40620: UDP, length 4
13:13:29.200709 IP 192.168.1.189.45542 > 192.168.0.4.40620: UDP, length 4
13:13:29.202292 IP 192.168.0.4.40620 > 192.168.1.189.45542: UDP, length 516
13:13:29.258375 IP 192.168.1.189.45542 > 192.168.0.4.40620: UDP, length 4
13:13:29.260708 IP 192.168.1.189.45542 > 192.168.0.4.40620: UDP, length 4
13:13:29.262292 IP 192.168.0.4.40620 > 192.168.1.189.45542: UDP, length 516

which is about 512 bytes every 60ms.  The two length 4 UDPs are the
ACK packets - one of which is a repeated transmission for each
packet.

I also see NFS timing out.

pings also have weirdness:

root@omap-4430sdp:~# ping -c 10 192.168.0.4
PING 192.168.0.4 (192.168.0.4): 56 data bytes
64 bytes from 192.168.0.4: seq=0 ttl=64 time=107.635 ms
64 bytes from 192.168.0.4: seq=1 ttl=64 time=1011.689 ms
64 bytes from 192.168.0.4: seq=2 ttl=64 time=5.157 ms
64 bytes from 192.168.0.4: seq=3 ttl=64 time=1021.820 ms
64 bytes from 192.168.0.4: seq=4 ttl=64 time=4.395 ms
64 bytes from 192.168.0.4: seq=5 ttl=64 time=4.669 ms
64 bytes from 192.168.0.4: seq=6 ttl=64 time=371.735 ms
64 bytes from 192.168.0.4: seq=7 ttl=64 time=882.598 ms
64 bytes from 192.168.0.4: seq=8 ttl=64 time=31.372 ms
64 bytes from 192.168.0.4: seq=9 ttl=64 time=2010.772 ms

--- 192.168.0.4 ping statistics ---
10 packets transmitted, 10 packets received, 0% packet loss
round-trip min/avg/max = 4.395/545.184/2010.772 ms

If I ping the board remotely:

$ ping -i .2 192.168.1.189
PING 192.168.1.189 (192.168.1.189) 56(84) bytes of data.
64 bytes from 192.168.1.189: icmp_req=1 ttl=64 time=2033 ms
64 bytes from 192.168.1.189: icmp_req=2 ttl=64 time=1825 ms
64 bytes from 192.168.1.189: icmp_req=3 ttl=64 time=1616 ms
64 bytes from 192.168.1.189: icmp_req=4 ttl=64 time=1417 ms
64 bytes from 192.168.1.189: icmp_req=5 ttl=64 time=1218 ms
64 bytes from 192.168.1.189: icmp_req=6 ttl=64 time=1018 ms
64 bytes from 192.168.1.189: icmp_req=7 ttl=64 time=819 ms
64 bytes from 192.168.1.189: icmp_req=8 ttl=64 time=610 ms
64 bytes from 192.168.1.189: icmp_req=9 ttl=64 time=411 ms
64 bytes from 192.168.1.189: icmp_req=10 ttl=64 time=202 ms
64 bytes from 192.168.1.189: icmp_req=11 ttl=64 time=4.46 ms
64 bytes from 192.168.1.189: icmp_req=12 ttl=64 time=263 ms
64 bytes from 192.168.1.189: icmp_req=13 ttl=64 time=54.5 ms
64 bytes from 192.168.1.189: icmp_req=14 ttl=64 time=1399 ms
64 bytes from 192.168.1.189: icmp_req=15 ttl=64 time=1199 ms
64 bytes from 192.168.1.189: icmp_req=16 ttl=64 time=990 ms
64 bytes from 192.168.1.189: icmp_req=17 ttl=64 time=781 ms
64 bytes from 192.168.1.189: icmp_req=18 ttl=64 time=572 ms
64 bytes from 192.168.1.189: icmp_req=19 ttl=64 time=372 ms
64 bytes from 192.168.1.189: icmp_req=20 ttl=64 time=163 ms
^C
--- 192.168.1.189 ping statistics ---
22 packets transmitted, 20 received, 9% packet loss, time 4302ms
rtt min/avg/max/mdev = 4.468/848.854/2033.873/592.100 ms, pipe 10

It looks very much like a receive problem - in that the board is not
always aware of a packet having been received until it attempts to
transmit (eg, in the case of TFTP, when it re-sends the ACK after a
receive timeout, it _then_ notices that there's a packet waiting.)

I'm not quite sure when this cropped up as I no longer regularly
update and run my nightly boot tests, but I think 4.18 was fine.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [RFC PATCH 4/6] dt-bindings: update mvneta binding document

2018-12-05 Thread Russell King - ARM Linux
On Mon, Dec 03, 2018 at 05:54:55PM -0600, Rob Herring wrote:
> On Mon, Nov 12, 2018 at 12:31:02PM +0000, Russell King wrote:
> > Signed-off-by: Russell King 
> 
> Needs a better subject and a commit msg.

Hmm, not sure why it didn't contain:

"dt-bindings: net: mvneta: add phys property

Add an optional phys property to the mvneta binding documentation for
the common phy.

Signed-off-by: Russell King "

as the commit message.  With the correct commit message, are you happy
with it?

> 
> > ---
> >  Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git 
> > a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt 
> > b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
> > index bedcfd5a52cd..691f886cfc4a 100644
> > --- a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
> > +++ b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
> > @@ -19,7 +19,7 @@
> >"marvell,armada-370-neta" and 9800B for others.
> >  - clock-names: List of names corresponding to clocks property; shall be
> >"core" for core clock and "bus" for the optional bus clock.
> > -
> > +- phys: comphy for the ethernet port, see ../phy/phy-bindings.txt
> >  
> >  Optional properties (valid only for Armada XP/38x):
> >  
> > -- 
> > 2.7.4
> > 

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [RFC PATCH] net: mvpp2: fix detection of 10G SFP modules

2018-12-04 Thread Russell King - ARM Linux
On Tue, Dec 04, 2018 at 12:19:54PM +0200, Baruch Siach wrote:
> Hi Russell,
> 
> On Thu, Nov 29, 2018 at 10:00:43PM +, Russell King - ARM Linux wrote:
> > On Thu, Nov 29, 2018 at 11:31:23AM -0800, Florian Fainelli wrote:
> > > On 11/29/2018 4:49 AM, Baruch Siach wrote:
> > > > The mvpp2_phylink_validate() relies on the interface field of
> > > > phylink_link_state to determine valid link modes. However, when called
> > > > from phylink_sfp_module_insert() this field in not initialized. The
> > > > default switch case then excludes 10G link modes. This allows 10G SFP
> > > > modules that are detected correctly to be configured at max rate of
> > > > 2.5G.
> > > > 
> > > > Catch the uninitialized PHY mode case, and allow 10G rates.
> > > > 
> > > > Cc: Maxime Chevallier 
> > > > Cc: Antoine Tenart 
> > > > Signed-off-by: Baruch Siach 
> > > > ---
> > > > Is that the right fix?
> > > 
> > > It would be a bit surprising that this is the right fix, you would
> > > expect validate to be called once everything has been parsed
> > > successfully from the SFP, is not that the case here? If not, can you
> > > find out what happens?
> > 
> > Two calls are made - the first with PHY_INTERFACE_MODE_NA to
> > determine what the advertising link mode may be, and then again
> > once the interface mode has been selected from the advertising mask.
> > 
> > Why?
> > 
> > Consider a 4.3Mbps fiberchannel SFP plugged into a 1G-only MAC.
> > If we did it as a single pass, we would end up passing an
> > interface mode of 2500BASEX first time around which is illogical.
> 
> So you consider this to be the right fix, right?

Yes, but there is another bug lurking here - the handling of invalid
interface modes is not correct.  Please see mvneta.c as an example -
interface modes that are not supported by the MAC (apart from the NA
mode) end up with the supported mask completely cleared.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [RFC PATCH] net: mvpp2: fix detection of 10G SFP modules

2018-11-29 Thread Russell King - ARM Linux
On Thu, Nov 29, 2018 at 11:31:23AM -0800, Florian Fainelli wrote:
> 
> 
> On 11/29/2018 4:49 AM, Baruch Siach wrote:
> > The mvpp2_phylink_validate() relies on the interface field of
> > phylink_link_state to determine valid link modes. However, when called
> > from phylink_sfp_module_insert() this field in not initialized. The
> > default switch case then excludes 10G link modes. This allows 10G SFP
> > modules that are detected correctly to be configured at max rate of
> > 2.5G.
> > 
> > Catch the uninitialized PHY mode case, and allow 10G rates.
> > 
> > Cc: Maxime Chevallier 
> > Cc: Antoine Tenart 
> > Signed-off-by: Baruch Siach 
> > ---
> > Is that the right fix?
> 
> It would be a bit surprising that this is the right fix, you would
> expect validate to be called once everything has been parsed
> successfully from the SFP, is not that the case here? If not, can you
> find out what happens?

Two calls are made - the first with PHY_INTERFACE_MODE_NA to
determine what the advertising link mode may be, and then again
once the interface mode has been selected from the advertising mask.

Why?

Consider a 4.3Mbps fiberchannel SFP plugged into a 1G-only MAC.
If we did it as a single pass, we would end up passing an
interface mode of 2500BASEX first time around which is illogical.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [PATCH] net: phy: sfp: correct store of detected link modes

2018-11-29 Thread Russell King - ARM Linux
On Thu, Nov 29, 2018 at 02:30:53PM +0200, Baruch Siach wrote:
> Hi Russell,
> 
> Russell King - ARM Linux writes:
> > On Thu, Nov 29, 2018 at 12:40:11PM +0200, Baruch Siach wrote:
> >> The link modes that sfp_parse_support() detects are stored in the
> >> 'modes' bitmap. There is no reason to make an exception for 1000Base-PX
> >> or 1000Base-BX10.
> >
> > I think you may be carrying some local patch, have an incorrect merge,
> > or maybe there's a patch in -next which changed this.
> >
> > Mainline has:
> >
> > if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS)) {
> > /* If the encoding and bit rate allows 1000baseX */
> > if (id->base.encoding == SFP_ENCODING_8B10B && br_nom &&
> > br_min <= 1300 && br_max >= 1200)
> > phylink_set(modes, 1000baseX_Full);
> > }
> >
> > but your patch changes that phylink_set() from:
> >
> > phylink_set(support, 1000baseX_Full);
> >
> > to:
> >
> > phylink_set(modes, 1000baseX_Full);
> >
> > which in the context of what's in mainline doesn't make sense.
> 
> The code that this patch touches is at line 165 in current mainline as
> of commit 60b548237fe:
> 
> 162 /* 1000Base-PX or 1000Base-BX10 */
> 163 if ((id->base.e_base_px || id->base.e_base_bx10) &&
> 164 br_min <= 1300 && br_max >= 1200)
> 165 phylink_set(support, 1000baseX_Full);
> 
> net-next as of e561bb29b6 carries no change in this file, as far as I
> can see.

Ah, sorry, I was looking further down.  Yes, your change is correct -
it was missed in 03145864bd0fcac29e33442f39d67d4f28b0777c, so it needs
a fixes tag for that commit.  Probably missed by having patches hanging
around for soo long.

Fixes: 03145864bd0f ("sfp: support 1G BiDi (eg, FiberStore SFP-GE-BX) modules")
Acked-by: Russell King 

Thanks!

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [PATCH] net: phy: sfp: correct store of detected link modes

2018-11-29 Thread Russell King - ARM Linux
On Thu, Nov 29, 2018 at 12:40:11PM +0200, Baruch Siach wrote:
> The link modes that sfp_parse_support() detects are stored in the
> 'modes' bitmap. There is no reason to make an exception for 1000Base-PX
> or 1000Base-BX10.

I think you may be carrying some local patch, have an incorrect merge,
or maybe there's a patch in -next which changed this.

Mainline has:

if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS)) {
/* If the encoding and bit rate allows 1000baseX */
if (id->base.encoding == SFP_ENCODING_8B10B && br_nom &&
br_min <= 1300 && br_max >= 1200)
phylink_set(modes, 1000baseX_Full);
}

but your patch changes that phylink_set() from:

phylink_set(support, 1000baseX_Full);

to:

phylink_set(modes, 1000baseX_Full);

which in the context of what's in mainline doesn't make sense.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [RFC PATCH 5/6] net: marvell: neta: add support for 2500base-X

2018-11-14 Thread Russell King - ARM Linux
On Wed, Nov 14, 2018 at 02:18:14PM +0530, Kishon Vijay Abraham I wrote:
> Hi,
> 
> On 12/11/18 6:01 PM, Russell King wrote:
> > Signed-off-by: Russell King 
> > ---
> >  drivers/net/ethernet/marvell/mvneta.c | 58 
> > ++-
> >  1 file changed, 51 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/net/ethernet/marvell/mvneta.c 
> > b/drivers/net/ethernet/marvell/mvneta.c
> > index 5bfd349bf41a..7305d4cc0630 100644
> > --- a/drivers/net/ethernet/marvell/mvneta.c
> > +++ b/drivers/net/ethernet/marvell/mvneta.c
> > @@ -27,6 +27,7 @@
> >  #include 
> >  #include 
> >  #include 
> > +#include 
> >  #include 
> >  #include 
> >  #include 
> > @@ -437,6 +438,7 @@ struct mvneta_port {
> > struct device_node *dn;
> > unsigned int tx_csum_limit;
> > struct phylink *phylink;
> > +   struct phy *comphy;
> >  
> > struct mvneta_bm *bm_priv;
> > struct mvneta_bm_pool *pool_long;
> > @@ -3150,6 +3152,8 @@ static void mvneta_start_dev(struct mvneta_port *pp)
> >  {
> > int cpu;
> >  
> > +   WARN_ON(phy_power_on(pp->comphy));
> > +
> > mvneta_max_rx_size_set(pp, pp->pkt_size);
> > mvneta_txq_max_tx_size_set(pp, pp->pkt_size);
> >  
> > @@ -3212,6 +3216,8 @@ static void mvneta_stop_dev(struct mvneta_port *pp)
> >  
> > mvneta_tx_reset(pp);
> > mvneta_rx_reset(pp);
> > +
> > +   WARN_ON(phy_power_off(pp->comphy));
> >  }
> >  
> >  static void mvneta_percpu_enable(void *arg)
> > @@ -3337,6 +3343,7 @@ static int mvneta_set_mac_addr(struct net_device 
> > *dev, void *addr)
> >  static void mvneta_validate(struct net_device *ndev, unsigned long 
> > *supported,
> > struct phylink_link_state *state)
> >  {
> > +   struct mvneta_port *pp = netdev_priv(ndev);
> > __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
> >  
> > /* We only support QSGMII, SGMII, 802.3z and RGMII modes */
> > @@ -3357,14 +3364,14 @@ static void mvneta_validate(struct net_device 
> > *ndev, unsigned long *supported,
> > /* Asymmetric pause is unsupported */
> > phylink_set(mask, Pause);
> >  
> > -   /* We cannot use 1Gbps when using the 2.5G interface. */
> > -   if (state->interface == PHY_INTERFACE_MODE_2500BASEX) {
> > -   phylink_set(mask, 2500baseT_Full);
> > -   phylink_set(mask, 2500baseX_Full);
> > -   } else {
> > +   /* Half-duplex at speeds higher than 100Mbit is unsupported */
> > +   if (pp->comphy || state->interface != PHY_INTERFACE_MODE_2500BASEX) {
> > phylink_set(mask, 1000baseT_Full);
> > phylink_set(mask, 1000baseX_Full);
> > }
> > +   if (pp->comphy || state->interface == PHY_INTERFACE_MODE_2500BASEX) {
> > +   phylink_set(mask, 2500baseX_Full);
> > +   }
> >  
> > if (!phy_interface_mode_is_8023z(state->interface)) {
> > /* 10M and 100M are only supported in non-802.3z mode */
> > @@ -3378,6 +3385,11 @@ static void mvneta_validate(struct net_device *ndev, 
> > unsigned long *supported,
> >__ETHTOOL_LINK_MODE_MASK_NBITS);
> > bitmap_and(state->advertising, state->advertising, mask,
> >__ETHTOOL_LINK_MODE_MASK_NBITS);
> > +
> > +   /* We can only operate at 2500BaseX or 1000BaseX.  If requested
> > +* to advertise both, only report advertising at 2500BaseX.
> > +*/
> > +   phylink_helper_basex_speed(state);
> >  }
> >  
> >  static int mvneta_mac_link_state(struct net_device *ndev,
> > @@ -3389,7 +3401,9 @@ static int mvneta_mac_link_state(struct net_device 
> > *ndev,
> > gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS);
> >  
> > if (gmac_stat & MVNETA_GMAC_SPEED_1000)
> > -   state->speed = SPEED_1000;
> > +   state->speed =
> > +   state->interface == PHY_INTERFACE_MODE_2500BASEX ?
> > +   SPEED_2500 : SPEED_1000;
> > else if (gmac_stat & MVNETA_GMAC_SPEED_100)
> > state->speed = SPEED_100;
> > else
> > @@ -3504,12 +3518,32 @@ static void mvneta_mac_config(struct net_device 
> > *ndev, unsigned int mode,
> > MVNETA_GMAC_FORCE_LINK_DOWN);
> > }
> >  
> > +
> > /* When at 2.5G, the link partner can send frames with shortened
> >  * preambles.
> >  */
> >

Re: [RFC PATCH 0/6] Armada 38x comphy driver to support 2.5Gbps networking

2018-11-14 Thread Russell King - ARM Linux
On Wed, Nov 14, 2018 at 01:39:29PM +0530, Kishon Vijay Abraham I wrote:
> Hi,
> 
> On 12/11/18 5:59 PM, Russell King - ARM Linux wrote:
> > Hi,
> > 
> > This series adds support for dynamically switching between 1Gbps
> > and 2.5Gbps networking for the Marvell Armada 38x SoCs, tested on
> > Armada 388 on the Clearfog platform.
> > 
> > This is necessary to be able to connect (eg) a Clearfog platform
> > with a Macchiatobin platform via the SFP sockets, as Clearfog
> > currently only supports 1Gbps networking via the SFP socket and
> > Macchiatobin defaults to 2.5Gbps when using Fiberchannel SFPs.
> > 
> > In order to allow dynamic switching, we need to implement a common
> > phy driver to switch the ethernet serdes lane speed - 2.5Gbps is
> > just 1Gbps up-clocked by 2.5x.  We implement a simple comphy
> > driver to achieve this, which only supports networking.
> > 
> > With this, we are able to support both Fiberchannel SFPs operating
> > at 2.5Gbps or 1Gbps, and 1G ethernet SFPs plugged into the Clearfog
> > platform, dynamically selecting according to the SFPs abilities.
> > 
> > I'm aware of the proposed changes to the PHY layer, changing
> > phy_set_mode() to take the ethernet phy interface type, hence why
> > this is RFC - there's also the question about how this will be
> > merged.  This series is currently based on 4.20-rc1, but will
> > likely need to be rebased when the PHY layer changes hit.
> 
> For this case, I'd prefer the phy_set_mode series and the phy and net changes
> here (after rebasing) go via linux-phy tree.

Please let me know when they've hit, thanks.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


[RFC PATCH 6/6] ARM: dts: clearfog: add comphy settings for Ethernet interfaces

2018-11-12 Thread Russell King
Add the comphy settings for the Ethernet interfaces.

Signed-off-by: Russell King 
---
 arch/arm/boot/dts/armada-388-clearfog.dtsi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/armada-388-clearfog.dtsi 
b/arch/arm/boot/dts/armada-388-clearfog.dtsi
index 1b0d0680c8b6..0d81600ca247 100644
--- a/arch/arm/boot/dts/armada-388-clearfog.dtsi
+++ b/arch/arm/boot/dts/armada-388-clearfog.dtsi
@@ -93,6 +93,7 @@
bm,pool-long = <2>;
bm,pool-short = <1>;
buffer-manager = <>;
+   phys = < 1>;
phy-mode = "sgmii";
status = "okay";
 };
@@ -103,6 +104,7 @@
bm,pool-short = <1>;
buffer-manager = <>;
managed = "in-band-status";
+   phys = < 2>;
phy-mode = "sgmii";
sfp = <>;
status = "okay";
-- 
2.7.4



[RFC PATCH 3/6] ARM: dts: add description for Armada 38x common phy

2018-11-12 Thread Russell King
Add the DT description for the Armada 38x common phy.

Signed-off-by: Russell King 
---
 arch/arm/boot/dts/armada-38x.dtsi | 37 +
 1 file changed, 37 insertions(+)

diff --git a/arch/arm/boot/dts/armada-38x.dtsi 
b/arch/arm/boot/dts/armada-38x.dtsi
index 929459c42760..7b2e2bd6479b 100644
--- a/arch/arm/boot/dts/armada-38x.dtsi
+++ b/arch/arm/boot/dts/armada-38x.dtsi
@@ -335,6 +335,43 @@
#clock-cells = <1>;
};
 
+   comphy: phy@18300 {
+   compatible = "marvell,armada-380-comphy";
+   reg = <0x18300 0x100>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   comphy0: phy@0 {
+   reg = <0>;
+   #phy-cells = <1>;
+   };
+
+   comphy1: phy@1 {
+   reg = <1>;
+   #phy-cells = <1>;
+   };
+
+   comphy2: phy@2 {
+   reg = <2>;
+   #phy-cells = <1>;
+   };
+
+   comphy3: phy@3 {
+   reg = <3>;
+   #phy-cells = <1>;
+   };
+
+   comphy4: phy@4 {
+   reg = <4>;
+   #phy-cells = <1>;
+   };
+
+   comphy5: phy@5 {
+   reg = <5>;
+   #phy-cells = <1>;
+   };
+   };
+
coreclk: mvebu-sar@18600 {
compatible = "marvell,armada-380-core-clock";
reg = <0x18600 0x04>;
-- 
2.7.4



[RFC PATCH 5/6] net: marvell: neta: add support for 2500base-X

2018-11-12 Thread Russell King
Signed-off-by: Russell King 
---
 drivers/net/ethernet/marvell/mvneta.c | 58 ++-
 1 file changed, 51 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/marvell/mvneta.c 
b/drivers/net/ethernet/marvell/mvneta.c
index 5bfd349bf41a..7305d4cc0630 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -27,6 +27,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -437,6 +438,7 @@ struct mvneta_port {
struct device_node *dn;
unsigned int tx_csum_limit;
struct phylink *phylink;
+   struct phy *comphy;
 
struct mvneta_bm *bm_priv;
struct mvneta_bm_pool *pool_long;
@@ -3150,6 +3152,8 @@ static void mvneta_start_dev(struct mvneta_port *pp)
 {
int cpu;
 
+   WARN_ON(phy_power_on(pp->comphy));
+
mvneta_max_rx_size_set(pp, pp->pkt_size);
mvneta_txq_max_tx_size_set(pp, pp->pkt_size);
 
@@ -3212,6 +3216,8 @@ static void mvneta_stop_dev(struct mvneta_port *pp)
 
mvneta_tx_reset(pp);
mvneta_rx_reset(pp);
+
+   WARN_ON(phy_power_off(pp->comphy));
 }
 
 static void mvneta_percpu_enable(void *arg)
@@ -3337,6 +3343,7 @@ static int mvneta_set_mac_addr(struct net_device *dev, 
void *addr)
 static void mvneta_validate(struct net_device *ndev, unsigned long *supported,
struct phylink_link_state *state)
 {
+   struct mvneta_port *pp = netdev_priv(ndev);
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
 
/* We only support QSGMII, SGMII, 802.3z and RGMII modes */
@@ -3357,14 +3364,14 @@ static void mvneta_validate(struct net_device *ndev, 
unsigned long *supported,
/* Asymmetric pause is unsupported */
phylink_set(mask, Pause);
 
-   /* We cannot use 1Gbps when using the 2.5G interface. */
-   if (state->interface == PHY_INTERFACE_MODE_2500BASEX) {
-   phylink_set(mask, 2500baseT_Full);
-   phylink_set(mask, 2500baseX_Full);
-   } else {
+   /* Half-duplex at speeds higher than 100Mbit is unsupported */
+   if (pp->comphy || state->interface != PHY_INTERFACE_MODE_2500BASEX) {
phylink_set(mask, 1000baseT_Full);
phylink_set(mask, 1000baseX_Full);
}
+   if (pp->comphy || state->interface == PHY_INTERFACE_MODE_2500BASEX) {
+   phylink_set(mask, 2500baseX_Full);
+   }
 
if (!phy_interface_mode_is_8023z(state->interface)) {
/* 10M and 100M are only supported in non-802.3z mode */
@@ -3378,6 +3385,11 @@ static void mvneta_validate(struct net_device *ndev, 
unsigned long *supported,
   __ETHTOOL_LINK_MODE_MASK_NBITS);
bitmap_and(state->advertising, state->advertising, mask,
   __ETHTOOL_LINK_MODE_MASK_NBITS);
+
+   /* We can only operate at 2500BaseX or 1000BaseX.  If requested
+* to advertise both, only report advertising at 2500BaseX.
+*/
+   phylink_helper_basex_speed(state);
 }
 
 static int mvneta_mac_link_state(struct net_device *ndev,
@@ -3389,7 +3401,9 @@ static int mvneta_mac_link_state(struct net_device *ndev,
gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS);
 
if (gmac_stat & MVNETA_GMAC_SPEED_1000)
-   state->speed = SPEED_1000;
+   state->speed =
+   state->interface == PHY_INTERFACE_MODE_2500BASEX ?
+   SPEED_2500 : SPEED_1000;
else if (gmac_stat & MVNETA_GMAC_SPEED_100)
state->speed = SPEED_100;
else
@@ -3504,12 +3518,32 @@ static void mvneta_mac_config(struct net_device *ndev, 
unsigned int mode,
MVNETA_GMAC_FORCE_LINK_DOWN);
}
 
+
/* When at 2.5G, the link partner can send frames with shortened
 * preambles.
 */
if (state->speed == SPEED_2500)
new_ctrl4 |= MVNETA_GMAC4_SHORT_PREAMBLE_ENABLE;
 
+   if (pp->comphy) {
+   enum phy_mode mode = PHY_MODE_INVALID;
+
+   switch (state->interface) {
+   case PHY_INTERFACE_MODE_SGMII:
+   case PHY_INTERFACE_MODE_1000BASEX:
+   mode = PHY_MODE_SGMII;
+   break;
+   case PHY_INTERFACE_MODE_2500BASEX:
+   mode = PHY_MODE_2500SGMII;
+   break;
+   default:
+   break;
+   }
+
+   if (mode != PHY_MODE_INVALID)
+   WARN_ON(phy_set_mode(pp->comphy, mode));
+   }
+
if (new_ctrl0 != gmac_ctrl0)
mvreg_write(pp, MVNETA_GMAC_CTRL_0, new_ctrl0);
if (new_ctrl2 != gmac_ctrl2)
@@ -4411,7 +4445,7 @@ static int mvneta_port_power_up(struct mvneta_port *pp, 
int phy_mode)
if (phy_mode == PHY_INTERFACE_MODE_QSGMII)
 

[RFC PATCH 4/6] dt-bindings: update mvneta binding document

2018-11-12 Thread Russell King
Signed-off-by: Russell King 
---
 Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt 
b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
index bedcfd5a52cd..691f886cfc4a 100644
--- a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
+++ b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
@@ -19,7 +19,7 @@
   "marvell,armada-370-neta" and 9800B for others.
 - clock-names: List of names corresponding to clocks property; shall be
   "core" for core clock and "bus" for the optional bus clock.
-
+- phys: comphy for the ethernet port, see ../phy/phy-bindings.txt
 
 Optional properties (valid only for Armada XP/38x):
 
-- 
2.7.4



[RFC PATCH 2/6] phy: armada38x: add common phy support

2018-11-12 Thread Russell King
Add support for the Armada 38x common phy to allow us to change the
speed of the Ethernet serdes lane.  This driver only supports
manipulation of the speed, it does not support configuration of the
common phy.

Signed-off-by: Russell King 
---
 drivers/phy/marvell/Kconfig|  10 ++
 drivers/phy/marvell/Makefile   |   1 +
 drivers/phy/marvell/phy-armada38x-comphy.c | 236 +
 3 files changed, 247 insertions(+)
 create mode 100644 drivers/phy/marvell/phy-armada38x-comphy.c

diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig
index 6fb4b56e4c14..224ea4e6a46d 100644
--- a/drivers/phy/marvell/Kconfig
+++ b/drivers/phy/marvell/Kconfig
@@ -21,6 +21,16 @@ config PHY_BERLIN_USB
help
  Enable this to support the USB PHY on Marvell Berlin SoCs.
 
+config PHY_MVEBU_A38X_COMPHY
+   tristate "Marvell Armada 38x comphy driver"
+   depends on ARCH_MVEBU || COMPILE_TEST
+   depends on OF
+   select GENERIC_PHY
+   help
+ This driver allows to control the comphy, an hardware block providing
+ shared serdes PHYs on Marvell Armada 38x. Its serdes lanes can be
+ used by various controllers (Ethernet, sata, usb, PCIe...).
+
 config PHY_MVEBU_CP110_COMPHY
tristate "Marvell CP110 comphy driver"
depends on ARCH_MVEBU || COMPILE_TEST
diff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile
index 3975b144f8ec..59b6c03ef756 100644
--- a/drivers/phy/marvell/Makefile
+++ b/drivers/phy/marvell/Makefile
@@ -2,6 +2,7 @@
 obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o
 obj-$(CONFIG_PHY_BERLIN_SATA)  += phy-berlin-sata.o
 obj-$(CONFIG_PHY_BERLIN_USB)   += phy-berlin-usb.o
+obj-$(CONFIG_PHY_MVEBU_A38X_COMPHY)+= phy-armada38x-comphy.o
 obj-$(CONFIG_PHY_MVEBU_CP110_COMPHY)   += phy-mvebu-cp110-comphy.o
 obj-$(CONFIG_PHY_MVEBU_SATA)   += phy-mvebu-sata.o
 obj-$(CONFIG_PHY_PXA_28NM_HSIC)+= phy-pxa-28nm-hsic.o
diff --git a/drivers/phy/marvell/phy-armada38x-comphy.c 
b/drivers/phy/marvell/phy-armada38x-comphy.c
new file mode 100644
index ..61d1965e1cf6
--- /dev/null
+++ b/drivers/phy/marvell/phy-armada38x-comphy.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Russell King, Deep Blue Solutions Ltd.
+ *
+ * Partly derived from CP110 comphy driver by Antoine Tenart
+ * 
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define MAX_A38X_COMPHY6
+#define MAX_A38X_PORTS 3
+
+#define COMPHY_CFG10x00
+#define  COMPHY_CFG1_GEN_TX(x) ((x) << 26)
+#define  COMPHY_CFG1_GEN_TX_MSKCOMPHY_CFG1_GEN_TX(15)
+#define  COMPHY_CFG1_GEN_RX(x) ((x) << 22)
+#define  COMPHY_CFG1_GEN_RX_MSKCOMPHY_CFG1_GEN_RX(15)
+#define  GEN_SGMII_1_25GBPS6
+#define  GEN_SGMII_3_125GBPS   8
+
+#define COMPHY_STAT1   0x18
+#define  COMPHY_STAT1_PLL_RDY_TX   BIT(3)
+#define  COMPHY_STAT1_PLL_RDY_RX   BIT(2)
+
+#define COMPHY_SELECTOR0xfc
+
+struct a38x_comphy;
+
+struct a38x_comphy_lane {
+   void __iomem *base;
+   struct a38x_comphy *priv;
+   unsigned int n;
+
+   int port;
+};
+
+struct a38x_comphy {
+   void __iomem *base;
+   struct device *dev;
+   struct a38x_comphy_lane lane[MAX_A38X_COMPHY];
+};
+
+static const u8 gbe_mux[MAX_A38X_COMPHY][MAX_A38X_PORTS] = {
+   { 0, 0, 0 },
+   { 4, 5, 0 },
+   { 0, 4, 0 },
+   { 0, 0, 4 },
+   { 0, 3, 0 },
+   { 0, 0, 3 },
+};
+
+static void a38x_comphy_set_reg(struct a38x_comphy_lane *lane,
+   unsigned int offset, u32 mask, u32 value)
+{
+   u32 val;
+
+   val = readl_relaxed(lane->base + offset) & ~mask;
+   writel(val | value, lane->base + offset);
+}
+
+static void a38x_comphy_set_speed(struct a38x_comphy_lane *lane,
+ unsigned int gen_tx, unsigned int gen_rx)
+{
+   a38x_comphy_set_reg(lane, COMPHY_CFG1,
+   COMPHY_CFG1_GEN_TX_MSK | COMPHY_CFG1_GEN_RX_MSK,
+   COMPHY_CFG1_GEN_TX(gen_tx) |
+   COMPHY_CFG1_GEN_RX(gen_rx));
+}
+
+static int a38x_comphy_poll(struct a38x_comphy_lane *lane,
+   unsigned int offset, u32 mask, u32 value)
+{
+   unsigned int timeout = 10;
+   u32 val;
+
+   while (1) {
+   val = readl_relaxed(lane->base + offset);
+   if ((val & mask) == value)
+   return 0;
+   if (!timeout--)
+   break;
+   udelay(10);
+   }
+
+   dev_err(lane->priv->dev, "comphy%u: timed out waiting for status\n",
+   lane->n);
+
+   return -ETIMEDOUT;
+}
+
+/*
+ * We only support changing the speed for comphys configured for GBE.
+ * Sinc

[RFC PATCH 1/6] dt-bindings: phy: Armada 38x common phy bindings

2018-11-12 Thread Russell King
Add the Marvell Armada 38x common phy bindings.

Signed-off-by: Russell King 
---
 .../bindings/phy/phy-armada38x-comphy.txt  | 40 ++
 1 file changed, 40 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/phy/phy-armada38x-comphy.txt

diff --git a/Documentation/devicetree/bindings/phy/phy-armada38x-comphy.txt 
b/Documentation/devicetree/bindings/phy/phy-armada38x-comphy.txt
new file mode 100644
index ..ad49e5c01334
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-armada38x-comphy.txt
@@ -0,0 +1,40 @@
+mvebu armada 38x comphy driver
+--
+
+This comphy controller can be found on Marvell Armada 38x. It provides a
+number of shared PHYs used by various interfaces (network, sata, usb,
+PCIe...).
+
+Required properties:
+
+- compatible: should be "marvell,armada-380-comphy"
+- reg: should contain the comphy register location and length.
+- #address-cells: should be 1.
+- #size-cells: should be 0.
+
+A sub-node is required for each comphy lane provided by the comphy.
+
+Required properties (child nodes):
+
+- reg: comphy lane number.
+- #phy-cells : from the generic phy bindings, must be 1. Defines the
+   input port to use for a given comphy lane.
+
+Example:
+
+   comphy: phy@18300 {
+   compatible = "marvell,armada-380-comphy";
+   reg = <0x18300 0x100>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   cpm_comphy0: phy@0 {
+   reg = <0>;
+   #phy-cells = <1>;
+   };
+
+   cpm_comphy1: phy@1 {
+   reg = <1>;
+   #phy-cells = <1>;
+   };
+   };
-- 
2.7.4



[RFC PATCH 0/6] Armada 38x comphy driver to support 2.5Gbps networking

2018-11-12 Thread Russell King - ARM Linux
Hi,

This series adds support for dynamically switching between 1Gbps
and 2.5Gbps networking for the Marvell Armada 38x SoCs, tested on
Armada 388 on the Clearfog platform.

This is necessary to be able to connect (eg) a Clearfog platform
with a Macchiatobin platform via the SFP sockets, as Clearfog
currently only supports 1Gbps networking via the SFP socket and
Macchiatobin defaults to 2.5Gbps when using Fiberchannel SFPs.

In order to allow dynamic switching, we need to implement a common
phy driver to switch the ethernet serdes lane speed - 2.5Gbps is
just 1Gbps up-clocked by 2.5x.  We implement a simple comphy
driver to achieve this, which only supports networking.

With this, we are able to support both Fiberchannel SFPs operating
at 2.5Gbps or 1Gbps, and 1G ethernet SFPs plugged into the Clearfog
platform, dynamically selecting according to the SFPs abilities.

I'm aware of the proposed changes to the PHY layer, changing
phy_set_mode() to take the ethernet phy interface type, hence why
this is RFC - there's also the question about how this will be
merged.  This series is currently based on 4.20-rc1, but will
likely need to be rebased when the PHY layer changes hit.

 .../bindings/net/marvell-armada-370-neta.txt   |   2 +-
 .../bindings/phy/phy-armada38x-comphy.txt  |  40 
 arch/arm/boot/dts/armada-388-clearfog.dtsi |   2 +
 arch/arm/boot/dts/armada-38x.dtsi  |  37 
 drivers/net/ethernet/marvell/mvneta.c  |  58 -
 drivers/phy/marvell/Kconfig|  10 +
 drivers/phy/marvell/Makefile   |   1 +
 drivers/phy/marvell/phy-armada38x-comphy.c | 236 +
 8 files changed, 378 insertions(+), 8 deletions(-)
 create mode 100644 
Documentation/devicetree/bindings/phy/phy-armada38x-comphy.txt
 create mode 100644 drivers/phy/marvell/phy-armada38x-comphy.c


-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [PATCH RFC net-next 0/3] net: phy: sfp: Warn when using generic PHY driver

2018-11-06 Thread Russell King - ARM Linux
On Tue, Nov 06, 2018 at 04:09:35PM -0800, Florian Fainelli wrote:
> On 11/6/18 4:03 PM, Russell King - ARM Linux wrote:
> > On Tue, Nov 06, 2018 at 03:38:44PM -0800, David Miller wrote:
> >> From: Florian Fainelli 
> >> Date: Tue,  6 Nov 2018 15:29:10 -0800
> >>
> >>> This patch series allows warning an user that the generic PHY driver(s)
> >>> are used when a SFP incorporates a PHY (e.g: 1000BaseT SFP) which is
> >>> likely not going to work at all.
> >>>
> >>> Let me know if you would want to do that differently.
> >>
> >> Is there ever a possibility that the generic PHY driver could work
> >> in an SFP situation?
> > 
> > I don't yet see the reason for Florian's patch series - all the Marvell
> > 88e based modules I have, or have come across in information from
> > manufacturers self-configure themselves and don't really need the
> > Marvell 1G PHY driver.
> > 
> > For example, the Source Photonics were offering a range of 1GbaseT
> > modules with the 88e programmed in different modes, but published
> > instructions for the register accesses to configure them differently
> > (eg, SGMII vs 1000base-X interface facing the MAC).  Depending on
> > the module part number determines which mode the PHY has been
> > programmed to come up in.
> > 
> > So in theory, you don't need any PHY driver for these modules - but
> > it's useful to have a functional PHY driver to be able to read out
> > the negotiated flow control results.
> > 
> > I'd like more information from Florian about the reasoning behind
> > this patch series before it's merged.
> > 
> 
> The module that I am using [1] would not work, as in , no link up being
> reported without turning on the Marvell PHY driver:
> 
> https://www.amazon.com/dp/B01LW2P72V/ref=twister_B07F3WQJQX?_encoding=UTF8=1
> 
> this module uses a 88E PHY as well (OUI: 0x01410cc2).

>From the above URL:

 * This is 1000M SFP-T Transceiver, not 10/100/1000M Multi-Rate SFP-T. If
   you want to buy 10/100/1000M Multi-Rate SFP-T, pls contact us.10Gtek
   offer more compatible options, if your brands not listed above, pls
   contact us.

I wonder if this is like the Source Photonics situation, where the
1000base-T only variant of their module uses 1000base-X on the MAC
side, whereas their 10/100/1000base-T variant uses SGMII.  The only
difference between these are the part numbers and the programming
of the 88E to tell it which mode to default to for the host
side.  (There's no true way to know from the EEPROM whether a module
wants SGMII or 1000base-X.)

What I also gather is that this is a 10Gtek-manufactured version of
the Ubiquiti UF-RJ45-1G - the original Ubiquiti version supports
10/100/1G speeds which would require the 88e to configure for
a SGMII host interface by default.

Now, the reason that modules with an 88E configured to default to
1000base-X will work when the marvell PHY driver is present, but not
with the generic driver is that the marvell PHY driver will see that
SFP/phylink is wanting to use SGMII mode, and the Marvell PHY driver
reprograms the PHY to use SGMII.  This is only a problem for these
modules.

So, in so far as your patch 3 goes to give a hint that the Marvell
driver should be selected, that's correct.

However, where the 88e is configured for SGMII by default, the
Marvell driver shouldn't be required, and I wonder whether we ought
to be issuing a warning in that case.  The problem, however, is there
is no way to know for certain.

We could have modules that do not use the Marvell PHY, and if we don't
have a PHY driver for their particular PHY, do we want a warning to be
issued?

The whole 1000base-X vs SGMII with SFP modules is all very icky. :(

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [PATCH RFC net-next 0/3] net: phy: sfp: Warn when using generic PHY driver

2018-11-06 Thread Russell King - ARM Linux
On Tue, Nov 06, 2018 at 03:38:44PM -0800, David Miller wrote:
> From: Florian Fainelli 
> Date: Tue,  6 Nov 2018 15:29:10 -0800
> 
> > This patch series allows warning an user that the generic PHY driver(s)
> > are used when a SFP incorporates a PHY (e.g: 1000BaseT SFP) which is
> > likely not going to work at all.
> > 
> > Let me know if you would want to do that differently.
> 
> Is there ever a possibility that the generic PHY driver could work
> in an SFP situation?

I don't yet see the reason for Florian's patch series - all the Marvell
88e based modules I have, or have come across in information from
manufacturers self-configure themselves and don't really need the
Marvell 1G PHY driver.

For example, the Source Photonics were offering a range of 1GbaseT
modules with the 88e programmed in different modes, but published
instructions for the register accesses to configure them differently
(eg, SGMII vs 1000base-X interface facing the MAC).  Depending on
the module part number determines which mode the PHY has been
programmed to come up in.

So in theory, you don't need any PHY driver for these modules - but
it's useful to have a functional PHY driver to be able to read out
the negotiated flow control results.

I'd like more information from Florian about the reasoning behind
this patch series before it's merged.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [PATCH net-next 3/4] net: phy-c45: Implement reset/suspend/resume callbacks

2018-10-23 Thread Russell King - ARM Linux
On Tue, Oct 23, 2018 at 11:28:09AM +0100, Jose Abreu wrote:
> On 23-10-2018 11:20, Russell King - ARM Linux wrote:
> > I have no idea what you're proposing there - your patches weren't copied
> > to me.
> 
> They just set / unset  MDIO_CTRL1_LPOWER bit in PCS. I find that
> without this remote end doesn't detect link is down ...
> 
> If it's okay for Generic 10G driver I can submit only this and
> manually reset PHY in stmmac driver so that I don't need to
> implement custom PHY driver ...



> BTW, I just found out currently Generic 10G Driver is broken
> without patch 4/4 of this series [1]
> 
> [1] https://patchwork.ozlabs.org/patch/987570/

How is it broken - what are the symptoms?

The generic 10G driver is bound not via the normal bus matching and
phy_bus_match(), but via a manual bind in phy_attach_direct().  This
calls the probe function, which is phy_probe(), which initialises
the supported/advertising to the driver's features (which as you note
are zero.)

However, phy_attach_direct() goes on to call phy_init_hw(), which
calls the config_init() method.  The config_init() method initialises
the supported/advertising masks to 10GbaseT.  This is (partly) what
I refer to when I say that the generic 10G support is crippled - it
only supports this single speed and media.

So the supported/advertising masks should be forced to only 10GbaseT
at the completion of phy_attach_direct().

The "generic 10G" support doesn't do autonegotiation, configuration
or link mode forcing.  It only assumes 10GbaseT is supported, and
only checks for the "link up" bits.

It isn't like the non-10G generic PHY support due to history - it
was added in 2014 by Andy Fleming (see 124059fd53af).

BTW, your patch 1 is wrong as well (introducing phy_update_link()).
You don't take account that a 10G phy may have alternative ways of
reading the link (like 88x3310 does, because it has multiple
instances of AN/PCS/PHYXS at 1k offsets.)  All the gen10g_*
functions are legacy functions for the crippled "generic" 10G
support.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [PATCH net-next 3/4] net: phy-c45: Implement reset/suspend/resume callbacks

2018-10-23 Thread Russell King - ARM Linux
On Tue, Oct 23, 2018 at 11:17:50AM +0100, Jose Abreu wrote:
> On 22-10-2018 18:13, Florian Fainelli wrote:
> > On 10/22/18 8:48 AM, Russell King - ARM Linux wrote:
> >> On Mon, Oct 22, 2018 at 01:47:48PM +0100, Jose Abreu wrote:
> >>> Hello,
> >>>
> >>> On 22-10-2018 13:28, Andrew Lunn wrote:
> >>>>>  EXPORT_SYMBOL_GPL(gen10g_resume);
> >>>>> @@ -327,7 +381,7 @@ struct phy_driver genphy_10g_driver = {
> >>>>> .phy_id = 0x,
> >>>>> .phy_id_mask= 0x,
> >>>>> .name   = "Generic 10G PHY",
> >>>>> -   .soft_reset = gen10g_no_soft_reset,
> >>>>> +   .soft_reset = gen10g_soft_reset,
> >>>>> .config_init= gen10g_config_init,
> >>>>> .features   = 0,
> >>>>> .aneg_done  = genphy_c45_aneg_done,
> >>>> Hi Jose
> >>>>
> >>>> You need to be careful here. There is a reason this is called
> >>>> gen10g_no_soft_reset, rather than having an empty
> >>>> gen10g_soft_reset. Some PHYs break when you do a reset.  So adding a
> >>>> gen10g_soft_reset is fine, but don't change this here, without first
> >>>> understanding the history, and talking to Russell King.
> >>> Hmm, the reset function only interacts with standard PCS
> >>> registers, which should always be available ...
> >>>
> >>> >From my tests I need to do at least 1 reset during power-up so in
> >>> ultimate case I can add a feature quirk or similar.
> >>>
> >>> Russell, can you please comment ?
> >> Setting the reset bit on 88x3310 causes the entire device to become
> >> completely inaccessible until hardware reset.  Therefore, this bit
> >> must _never_ be set for these devices.  That said, we have a separate
> >> driver for these PHYs, but that will only be used for them if it's
> >> present in the kernel.  If we accidentally fall back to the generic
> >> driver, then we'll screw the 88x3310 until a full hardware reset.
> >>
> >> We also have a bunch of net devices that make use of this crippled
> >> "generic" 10G support - we don't know whether resetting the PHY
> >> for those systems will cause a regression - maybe board firmware
> >> already configured the PHY?  I can't say either way on that, except
> >> that we've had crippled 10G support in PHYLIB for a number of years
> >> now _with_ users, and adding reset support drastically changes the
> >> subsystem's behaviour for these users.
> >>
> >> I would recommend not touching the generic 10G driver, but instead
> >> implement your own driver for your PHY to avoid causing regressions.
> >>
> > Agreed.
> 
> What about .suspend / .resume ?

I have no idea what you're proposing there - your patches weren't copied
to me.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [PATCH net-next 3/4] net: phy-c45: Implement reset/suspend/resume callbacks

2018-10-22 Thread Russell King - ARM Linux
On Mon, Oct 22, 2018 at 01:47:48PM +0100, Jose Abreu wrote:
> Hello,
> 
> On 22-10-2018 13:28, Andrew Lunn wrote:
> >>  EXPORT_SYMBOL_GPL(gen10g_resume);
> >> @@ -327,7 +381,7 @@ struct phy_driver genphy_10g_driver = {
> >>.phy_id = 0x,
> >>.phy_id_mask= 0x,
> >>.name   = "Generic 10G PHY",
> >> -  .soft_reset = gen10g_no_soft_reset,
> >> +  .soft_reset = gen10g_soft_reset,
> >>.config_init= gen10g_config_init,
> >>.features   = 0,
> >>.aneg_done  = genphy_c45_aneg_done,
> > Hi Jose
> >
> > You need to be careful here. There is a reason this is called
> > gen10g_no_soft_reset, rather than having an empty
> > gen10g_soft_reset. Some PHYs break when you do a reset.  So adding a
> > gen10g_soft_reset is fine, but don't change this here, without first
> > understanding the history, and talking to Russell King.
> 
> Hmm, the reset function only interacts with standard PCS
> registers, which should always be available ...
> 
> >From my tests I need to do at least 1 reset during power-up so in
> ultimate case I can add a feature quirk or similar.
> 
> Russell, can you please comment ?

Setting the reset bit on 88x3310 causes the entire device to become
completely inaccessible until hardware reset.  Therefore, this bit
must _never_ be set for these devices.  That said, we have a separate
driver for these PHYs, but that will only be used for them if it's
present in the kernel.  If we accidentally fall back to the generic
driver, then we'll screw the 88x3310 until a full hardware reset.

We also have a bunch of net devices that make use of this crippled
"generic" 10G support - we don't know whether resetting the PHY
for those systems will cause a regression - maybe board firmware
already configured the PHY?  I can't say either way on that, except
that we've had crippled 10G support in PHYLIB for a number of years
now _with_ users, and adding reset support drastically changes the
subsystem's behaviour for these users.

I would recommend not touching the generic 10G driver, but instead
implement your own driver for your PHY to avoid causing regressions.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [RFC PATCH] skb: Define NET_IP_ALIGN based on CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS

2018-10-04 Thread Russell King - ARM Linux
On Thu, Oct 04, 2018 at 07:43:59PM +0200, Ard Biesheuvel wrote:
> (+ Arnd, Russell, Catalin, Will)
> 
> On 4 October 2018 at 19:36, Ben Hutchings  
> wrote:
> > NET_IP_ALIGN is supposed to be defined as 0 if DMA writes to an
> > unaligned buffer would be more expensive than CPU access to unaligned
> > header fields, and otherwise defined as 2.
> >
> > Currently only ppc64 and x86 configurations define it to be 0.
> > However several other architectures (conditionally) define
> > CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS, which seems to imply that
> > NET_IP_ALIGN should be 0.
> >
> > Remove the overriding definitions for ppc64 and x86 and define
> > NET_IP_ALIGN solely based on CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS.
> >
> > Signed-off-by: Ben Hutchings 
> 
> While this makes sense for arm64, I don't think it is appropriate for
> ARM per se.
> 
> The unusual thing about ARM is that some instructions require 32-bit
> alignment even when CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is set,
> (i.e., load/store multiple, load/store double), and we rely on
> alignment fixups done by the kernel to deal with the fallout if such
> instructions happen to be used on unaligned quantities (Russell,
> please correct me if this is inaccurate)

Correct, and we do have some assembly that use ldmia in the net code
(eg, for checksum calculation.)  Having NET_IP_ALIGN be 0 on ARM
coupled with a network adapter that doesn't do its own checksumming
would mean every non-hw-checksummed IP packet hitting the alignment
fixup - and not just once per packet.

So it's likely that this change could provoke reports of performance
regressions for ARM.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up


Re: [PATCH] net: phy: phylink: fix SFP interface autodetection

2018-09-22 Thread Russell King - ARM Linux
On Sat, Sep 22, 2018 at 10:09:44PM +0300, Baruch Siach wrote:
> When connecting a PHY to phylink use the detected interface. Otherwise,
> the link fails to come up when the configured 'phy-mode' differs from
> the SFP detected mode.
> 
> This fixes 1GB SFP module link up on eth3 of the Macchiatobin board that
> is configured in the DT to "2500base-x" phy-mode.

What I actually meant is that a PHY attached from a SFP interface
should use link_config.interface.  A PHY attached as not part of
a SFP interface should continue using the DT-parsed link_interface.

What I envisaged seeing is phylink_connect_phy() being renamed to
__phylink_connect_phy(), and taking the phy interface,
phylink_sfp_connect_phy() calling __phylink_connect_phy() with
link_config.interface, and a replacement phylink_connect_phy() which
called __phylink_connect_phy() with link_interface.

Sorry I wasn't explicit enough last time around.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


[PATCH net] sfp: fix oops with ethtool -m

2018-09-18 Thread Russell King
If a network interface is created prior to the SFP socket being
available, ethtool can request module information.  This unfortunately
leads to an oops:

Unable to handle kernel NULL pointer dereference at virtual address 0008
pgd = (ptrval)
[0008] *pgd=7c400831, *pte=, *ppte=
Internal error: Oops: 17 [#1] SMP ARM
Modules linked in:
CPU: 0 PID: 1480 Comm: ethtool Not tainted 4.19.0-rc3 #138
Hardware name: Broadcom Northstar Plus SoC
PC is at sfp_get_module_info+0x8/0x10
LR is at dev_ethtool+0x218c/0x2afc

Fix this by not filling in the network device's SFP bus pointer until
SFP is fully bound, thereby avoiding the core calling into the SFP bus
code.

Fixes: ce0aa27ff3f6 ("sfp: add sfp-bus to bridge between network devices and 
sfp cages")
Reported-by: Florian Fainelli 
Tested-by: Florian Fainelli 
Signed-off-by: Russell King 
---
 drivers/net/phy/sfp-bus.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
index 740655261e5b..83060fb349f4 100644
--- a/drivers/net/phy/sfp-bus.c
+++ b/drivers/net/phy/sfp-bus.c
@@ -349,6 +349,7 @@ static int sfp_register_bus(struct sfp_bus *bus)
}
if (bus->started)
bus->socket_ops->start(bus->sfp);
+   bus->netdev->sfp_bus = bus;
bus->registered = true;
return 0;
 }
@@ -357,6 +358,7 @@ static void sfp_unregister_bus(struct sfp_bus *bus)
 {
const struct sfp_upstream_ops *ops = bus->upstream_ops;
 
+   bus->netdev->sfp_bus = NULL;
if (bus->registered) {
if (bus->started)
bus->socket_ops->stop(bus->sfp);
@@ -438,7 +440,6 @@ static void sfp_upstream_clear(struct sfp_bus *bus)
 {
bus->upstream_ops = NULL;
bus->upstream = NULL;
-   bus->netdev->sfp_bus = NULL;
bus->netdev = NULL;
 }
 
@@ -467,7 +468,6 @@ struct sfp_bus *sfp_register_upstream(struct fwnode_handle 
*fwnode,
bus->upstream_ops = ops;
bus->upstream = upstream;
bus->netdev = ndev;
-   ndev->sfp_bus = bus;
 
if (bus->sfp) {
ret = sfp_register_bus(bus);
-- 
2.7.4



Re: [PATCH] net: phy: phylink: fix SFP interface autodetection

2018-09-17 Thread Russell King - ARM Linux
On Mon, Sep 17, 2018 at 05:19:57PM +0300, Baruch Siach wrote:
> When the switching to the SFP detected link mode update the main
> link_interface field as well. Otherwise, the link fails to come up when
> the configured 'phy-mode' defers from the SFP detected mode.
> 
> This fixes 1GB SFP module link up on eth3 of the Macchiatobin board that
> is configured in the DT to "2500base-x" phy-mode.

link_interface isn't supposed to track the SFP link mode.  In any case,
this is only used when a PHY is attached.  For a PHY on a SFP,
phylink_connect_phy() should be using link_config.interface and not
link_interface there.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


Re: [offlist] Re: Crash in netlink/sk_filter_trim_cap on ARMv7 on 4.18rc1

2018-08-17 Thread Russell King - ARM Linux
On Fri, Aug 17, 2018 at 02:40:19PM +0200, Daniel Borkmann wrote:
> I'd have one potential bug suspicion, for the 4.18 one you were trying,
> could you run with the below patch to see whether it would help?

I think this is almost certainly the problem - looking at the history,
it seems that the "-4" was assumed to be part of the scratch stuff in
commit 38ca93060163 ("bpf, arm32: save 4 bytes of unneeded stack space")
but it isn't - it's because "off" of zero refers to the top word in the
stack (iow at STACK_SIZE-4).

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


Re: [offlist] Re: Crash in netlink/sk_filter_trim_cap on ARMv7 on 4.18rc1

2018-08-16 Thread Russell King - ARM Linux
On Thu, Aug 16, 2018 at 10:35:16PM +0200, Marc Haber wrote:
> On Mon, Jun 25, 2018 at 05:41:27PM +0100, Peter Robinson wrote:
> > So with that and the other fix there was no improvement, with those
> > and the BPF JIT disabled it works, I'm not sure if the two patches
> > have any effect with the JIT disabled though.
> 
> I can confirm the crash with the released 4.18.1 on Banana Pi, and I can
> also confirm that disabling BPF JIT makes the Banana Pi work again.,

Hi,

I'm afraid that the information in the crash dumps is insufficient
to be able to work very much out about these crashes.

We need a recipe (kernel configuration and what userspace is doing)
so that it's possible to recreate the crash, or we need responses
to requests for information - I requested the disassembly of
sk_filter_trim_cap and the BPF code dump via setting a sysctl back
in early July.  Without this, as I say, I don't see how this problem
can be progressed.

If the problem is at boot, one way to set the sysctl would be to
hack the kernel and explicitly initialise the sysctl to '2', or
boot with init=/bin/sh, then manually mount /proc, set the sysctl,
and then "exec /sbin/init" from that shell.  (Remember there's no
job control in that shell, so ^z, ^c, etc do not work.)

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


Re: [PATCH] net: phy: sftp: print debug message with text, not numbers

2018-08-08 Thread Russell King - ARM Linux
You might want to fix the subject line.

On Wed, Aug 08, 2018 at 08:54:12PM +0200, Andrew Lunn wrote:
> Convert the state numbers, device state, etc from numbers to strings
> when printing debug messages.
> 
> Signed-off-by: Andrew Lunn 
> ---
>  drivers/net/phy/sfp.c | 76 ---
>  1 file changed, 72 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
> index 5661226cf75b..4637d980310e 100644
> --- a/drivers/net/phy/sfp.c
> +++ b/drivers/net/phy/sfp.c
> @@ -60,6 +60,69 @@ enum {
>   SFP_S_TX_DISABLE,
>  };
>  
> +static const char  * const mod_state_strings[] = {
> + [SFP_MOD_EMPTY] = "empty",
> + [SFP_MOD_PROBE] = "probe",
> + [SFP_MOD_HPOWER] = "hpower",
> + [SFP_MOD_PRESENT] = "present",
> + [SFP_MOD_ERROR] = "error",
> +};
> +
> +static const char *mod_state_to_str(unsigned short mod_state)
> +{
> + if (mod_state >= ARRAY_SIZE(mod_state_strings))
> + return "Unknown module state";
> + return mod_state_strings[mod_state];
> +}
> +
> +static const char * const dev_state_strings[] = {
> + [SFP_DEV_DOWN] = "down",
> + [SFP_DEV_UP] = "up",
> +};
> +
> +static const char *dev_state_to_str(unsigned short dev_state)
> +{
> + if (dev_state >= ARRAY_SIZE(dev_state_strings))
> + return "Unknown device state";
> + return dev_state_strings[dev_state];
> +}
> +
> +static const char * const event_strings[] = {
> + [SFP_E_INSERT] = "insert",
> + [SFP_E_REMOVE] = "remove",
> + [SFP_E_DEV_DOWN] = "dev_down",
> + [SFP_E_DEV_UP] = "dev_up",
> + [SFP_E_TX_FAULT] = "tx_fault",
> + [SFP_E_TX_CLEAR] = "tx_clear",
> + [SFP_E_LOS_HIGH] = "los_high",
> + [SFP_E_LOS_LOW] = "los_low",
> + [SFP_E_TIMEOUT] = "timeout",
> +};
> +
> +static const char *event_to_str(unsigned short event)
> +{
> + if (event >= ARRAY_SIZE(event_strings))
> + return "Unknown event";
> + return event_strings[event];
> +}
> +
> +static const char * const sm_state_strings[] = {
> + [SFP_S_DOWN] = "down",
> + [SFP_S_INIT] = "init",
> + [SFP_S_WAIT_LOS] = "wait_los",
> + [SFP_S_LINK_UP] = "link_up",
> + [SFP_S_TX_FAULT] = "tx_fault",
> + [SFP_S_REINIT] = "reinit",
> + [SFP_S_TX_DISABLE] = "rx_disable",
> +};
> +
> +static const char *sm_state_to_str(unsigned short sm_state)
> +{
> + if (sm_state >= ARRAY_SIZE(sm_state_strings))
> + return "Unknown state";
> + return sm_state_strings[sm_state];
> +}
> +
>  static const char *gpio_of_names[] = {
>   "mod-def0",
>   "los",
> @@ -1388,8 +1451,11 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int 
> event)
>  {
>   mutex_lock(>sm_mutex);
>  
> - dev_dbg(sfp->dev, "SM: enter %u:%u:%u event %u\n",
> - sfp->sm_mod_state, sfp->sm_dev_state, sfp->sm_state, event);
> + dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n",
> + mod_state_to_str(sfp->sm_mod_state),
> + dev_state_to_str(sfp->sm_dev_state),
> + sm_state_to_str(sfp->sm_state),
> + event_to_str(event));
>  
>   /* This state machine tracks the insert/remove state of
>* the module, and handles probing the on-board EEPROM.
> @@ -1520,8 +1586,10 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int 
> event)
>   break;
>   }
>  
> - dev_dbg(sfp->dev, "SM: exit %u:%u:%u\n",
> - sfp->sm_mod_state, sfp->sm_dev_state, sfp->sm_state);
> + dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n",
> + mod_state_to_str(sfp->sm_mod_state),
> + dev_state_to_str(sfp->sm_dev_state),
> + sm_state_to_str(sfp->sm_state));
>  
>   mutex_unlock(>sm_mutex);
>  }
> -- 
> 2.18.0
> 

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


Re: Is it currently possible to connect SFP to dsa port?

2018-08-08 Thread Russell King - ARM Linux
On Wed, Aug 08, 2018 at 03:00:13PM +0200, Marek Behún wrote:
> Btw: some SFP modules can operate in 2500BASE-X mode. Currently the SFP
> driver does not support this, and there even isn't code in the
> mainline kernel for mvneta to switch to 2500BASEX. On Armada 3720 this
> has to be done by configuring comphy, which is currently done in
> u-boot. As a side project I am working on supporting Armada 3720 comphy
> in the kernel, so that it will be possible to set 2500BASE-X mode.

With mvneta, it works the same way as other Marvell stuff - the comphy
needs to be told to up-clock the 1000base-X to 2500base-X.  That's all
that 2500base-X is - an up-clocked 1000base-X.

With Armada 388, it's just a matter of poking one register to configure
the comphy to 2500base-X.

As mvneta has no support for comphys, and I don't have the full details
for the comphy stuff, I've not bothered implementing anything for mvneta
other than some bare bones support in my repository to support the mode,
and resorting to poking the comphy register with devmem2 as required.

However, I can assure you that SFP definitely does support 2500base-X.
As 2500base-X is rather unofficial (there's no 802.3 standard for it)
there's no bits in SFP module eeprom that identify a module as
supporting this mode.

Consequently, the only way I'm aware of is to detect a Fibrechannel
SFP which supports the range of bitrates that would allow this mode
to work.  Currently, the code does this:

/* For fibre channel SFP, derive possible BaseX modes */
if (id->base.fc_speed_100 ||
id->base.fc_speed_200 ||
id->base.fc_speed_400) {
if (id->base.br_nominal >= 31)
phylink_set(modes, 2500baseX_Full);
if (id->base.br_nominal >= 12)
phylink_set(modes, 1000baseX_Full);
}

So, the SFP core supports it.  What's expected from network drivers is
that they say they support 2500base-X, and then things get rather icky.
There is no way to autonegotiate between 2500base-X and 1000base-X.

What results is ultimately up to the driver implementation, but how I
have it locally via a local "phylink: add helper for configuring
2500BaseX modes" commit is:

- report 2500baseX_Full and 1000baseX_Full as supported to userspace.
- if both 2500baseX_Full and 1000baseX_Full are attempted to be set
   as advertised modes, clear 1000baseX_Full.
- select PHY_INTERFACE_MODE_2500BASEX or PHY_INTERFACE_MODE_1000BASEX
   depending whether the resulting advertising mask wants 2500baseX_Full
   or 1000baseX_Full.  If manual speed configuration, select between
   the PHY interface modes according to the requested speed.

With the exception of this commit (which is probably going to provoke
discussion about exactly what semantics we want) the SFP and phylink
code is all in place to support 2500base-X - I've proved it out using
a Macchiatobin (with the Marvell mvpp2x driver) and a Clearfog.

Without this patch, we detect in sfp_parse_support() that the module
is capable of 2500base-X, and, provided the network interface supports
2500base-X, sfp_select_interface() will select the 2500base-X PHY
interface mode, otherwise it'll select 1000base-X mode.

> The mv88e6190/6390 can configure ports 9 and 10 to either
> 1000BASE-X/SGMII od 2500BASE-X, but this has to be done by setting a
> pin and reseting the switch. Our board is able to configure this pin,
> and the plan is to do this in u-boot when SFP board is detected to be
> connected to the switch board. In this case the port is configured to
> 1000BASE-X.

It's really not that simple, unfortunately.  If you are talking about
pluggable SFPs (btw, SFP itself means the hot-pluggable modules, not
the soldered down modules, although we support both), SFP modules can
require *either* 1000base-X or SGMII.  There are some copper modules
with a PHY on board that want 1000base-X, but the vast majority of
copper modules want SGMII.  Conversely, gigabit fiber modules want
1000base-X.

Even more annoying, there is nothing that definitively tells you which
mode you should be using - and if you use the wrong mode, it may or
may not work, and you may or may not end up with a mismatched config
at either end of the link.

So, merely detecting a SFP modules presence doesn't tell you which
mode you should be in - and the annoying part is, if you hotplug the
module, you might need to change the port mode.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


Re: [PATCH 00/14] ARM BPF jit compiler improvements

2018-07-12 Thread Russell King - ARM Linux
On Thu, Jul 12, 2018 at 11:12:45PM +0200, Daniel Borkmann wrote:
> On 07/12/2018 11:02 PM, Russell King - ARM Linux wrote:
> > On Thu, Jul 12, 2018 at 09:02:41PM +0200, Daniel Borkmann wrote:
> >> Applied to bpf-next, thanks a lot Russell!
> > 
> > Thanks, I've just sent four more patches, which is the sum total of
> > what I'm intending to send for BPF improvements for the next merge
> > window.
> 
> Great, thanks a lot for the batch of improvements, Russell!
> 
> Did you manage to get the BPF kselftest suite working on arm32 under
> tools/testing/selftests/bpf/? In particular the test_verfier with
> bpf_jit_enabled set to 1 and test_kmod.sh has a bigger number of
> runtime tests that would stress it.

I have a big issue with almost all of the tools/ subdirectory, and
that is that it isn't "portable".

It seems that cross-build environments just weren't considered when
the tools subdirectory was created - it appears to require the entire
kernel tree and build tree to be accessible on the target in order
to build almost everything there.  (I also exclusively do split-object
builds, I never do an in-source-tree build.)

At least perf has the ability to ask Kbuild to package it up as a
tar.* file.  That can be easily transported to the target as a
self-contained buildable tree, and then be able to built from that.

My cross-build environment for the kernel is just for building
kernels, it does not have the facilities to build for userspace - I
have a wide range of userspaces across targets, with a multitude of
different glibc versions, and even when they're compatible versions,
they're built differently.

As far as I can see, basically, most tools/ stuff requires too much
effort to work around this to be of any use to me.  Even if I did
unpick it from the kernel source tree by hand, that would be wasted
effort, because I'd need to repeat that same process whenever
anything there gets updated.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


Re: [PATCH 00/14] ARM BPF jit compiler improvements

2018-07-12 Thread Russell King - ARM Linux
On Thu, Jul 12, 2018 at 09:02:41PM +0200, Daniel Borkmann wrote:
> Applied to bpf-next, thanks a lot Russell!

Thanks, I've just sent four more patches, which is the sum total of
what I'm intending to send for BPF improvements for the next merge
window.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


[PATCH net-next 3/4] ARM: net: bpf: improve 64-bit store implementation

2018-07-12 Thread Russell King
Improve the 64-bit store implementation from:

  ldr r6, [fp, #-8]
  str r8, [r6]
  ldr r6, [fp, #-8]
  mov r7, #4
  add r7, r6, r7
  str r9, [r7]

to:

  ldr r6, [fp, #-8]
  str r8, [r6]
  str r9, [r6, #4]

We leave the store as two separate STR instructions rather than using
STRD as the store may not be aligned, and STR can handle misalignment.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 52 +++
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 3a182e618441..026612ee8151 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -975,29 +975,42 @@ static inline void emit_a32_mul_r64(const s8 dst[], const 
s8 src[],
 }
 
 /* *(size *)(dst + off) = src */
-static inline void emit_str_r(const s8 dst, const s8 src,
- const s32 off, struct jit_ctx *ctx, const u8 sz){
+static inline void emit_str_r(const s8 dst, const s8 src[],
+ s32 off, struct jit_ctx *ctx, const u8 sz){
const s8 *tmp = bpf2a32[TMP_REG_1];
+   s32 off_max;
s8 rd;
 
rd = arm_bpf_get_reg32(dst, tmp[1], ctx);
-   if (off) {
+
+   if (sz == BPF_H)
+   off_max = 0xff;
+   else
+   off_max = 0xfff;
+
+   if (off < 0 || off > off_max) {
emit_a32_mov_i(tmp[0], off, ctx);
-   emit(ARM_ADD_R(tmp[0], rd, tmp[0]), ctx);
+   emit(ARM_ADD_R(tmp[0], tmp[0], rd), ctx);
rd = tmp[0];
+   off = 0;
}
switch (sz) {
-   case BPF_W:
-   /* Store a Word */
-   emit(ARM_STR_I(src, rd, 0), ctx);
+   case BPF_B:
+   /* Store a Byte */
+   emit(ARM_STRB_I(src_lo, rd, off), ctx);
break;
case BPF_H:
/* Store a HalfWord */
-   emit(ARM_STRH_I(src, rd, 0), ctx);
+   emit(ARM_STRH_I(src_lo, rd, off), ctx);
break;
-   case BPF_B:
-   /* Store a Byte */
-   emit(ARM_STRB_I(src, rd, 0), ctx);
+   case BPF_W:
+   /* Store a Word */
+   emit(ARM_STR_I(src_lo, rd, off), ctx);
+   break;
+   case BPF_DW:
+   /* Store a Double Word */
+   emit(ARM_STR_I(src_lo, rd, off), ctx);
+   emit(ARM_STR_I(src_hi, rd, off + 4), ctx);
break;
}
 }
@@ -1539,16 +1552,14 @@ static int build_insn(const struct bpf_insn *insn, 
struct jit_ctx *ctx)
case BPF_DW:
/* Sign-extend immediate value into temp reg */
emit_a32_mov_se_i64(true, tmp2, imm, ctx);
-   emit_str_r(dst_lo, tmp2[1], off, ctx, BPF_W);
-   emit_str_r(dst_lo, tmp2[0], off+4, ctx, BPF_W);
break;
case BPF_W:
case BPF_H:
case BPF_B:
emit_a32_mov_i(tmp2[1], imm, ctx);
-   emit_str_r(dst_lo, tmp2[1], off, ctx, BPF_SIZE(code));
break;
}
+   emit_str_r(dst_lo, tmp2, off, ctx, BPF_SIZE(code));
break;
/* STX XADD: lock *(u32 *)(dst + off) += src */
case BPF_STX | BPF_XADD | BPF_W:
@@ -1560,20 +1571,9 @@ static int build_insn(const struct bpf_insn *insn, 
struct jit_ctx *ctx)
case BPF_STX | BPF_MEM | BPF_H:
case BPF_STX | BPF_MEM | BPF_B:
case BPF_STX | BPF_MEM | BPF_DW:
-   {
-   u8 sz = BPF_SIZE(code);
-
rs = arm_bpf_get_reg64(src, tmp2, ctx);
-
-   /* Store the value */
-   if (BPF_SIZE(code) == BPF_DW) {
-   emit_str_r(dst_lo, rs[1], off, ctx, BPF_W);
-   emit_str_r(dst_lo, rs[0], off+4, ctx, BPF_W);
-   } else {
-   emit_str_r(dst_lo, rs[1], off, ctx, sz);
-   }
+   emit_str_r(dst_lo, rs, off, ctx, BPF_SIZE(code));
break;
-   }
/* PC += off if dst == src */
/* PC += off if dst > src */
/* PC += off if dst >= src */
-- 
2.7.4



[PATCH net-next 4/4] ARM: net: bpf: improve 64-bit ALU implementation

2018-07-12 Thread Russell King
Improbe the 64-bit ALU implementation from:

  movwr8, #65532
  movtr8, #65535
  movwr9, #65535
  movtr9, #65535
  ldr r7, [fp, #-44]
  addsr7, r7, r8
  str r7, [fp, #-44]
  ldr r7, [fp, #-40]
  adc r7, r7, r9
  str r7, [fp, #-40]

to:

  movwr8, #65532
  movtr8, #65535
  movwr9, #65535
  movtr9, #65535
  ldrdr6, [fp, #-44]
  addsr6, r6, r8
  adc r7, r7, r9
  strdr6, [fp, #-44]

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 29 -
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 026612ee8151..25b3ee85066e 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -716,11 +716,30 @@ static inline void emit_a32_alu_r(const s8 dst, const s8 
src,
 static inline void emit_a32_alu_r64(const bool is64, const s8 dst[],
  const s8 src[], struct jit_ctx *ctx,
  const u8 op) {
-   emit_a32_alu_r(dst_lo, src_lo, ctx, is64, false, op);
-   if (is64)
-   emit_a32_alu_r(dst_hi, src_hi, ctx, is64, true, op);
-   else
-   emit_a32_mov_i(dst_hi, 0, ctx);
+   const s8 *tmp = bpf2a32[TMP_REG_1];
+   const s8 *tmp2 = bpf2a32[TMP_REG_2];
+   const s8 *rd;
+
+   rd = arm_bpf_get_reg64(dst, tmp, ctx);
+   if (is64) {
+   const s8 *rs;
+
+   rs = arm_bpf_get_reg64(src, tmp2, ctx);
+
+   /* ALU operation */
+   emit_alu_r(rd[1], rs[1], true, false, op, ctx);
+   emit_alu_r(rd[0], rs[0], true, true, op, ctx);
+   } else {
+   s8 rs;
+
+   rs = arm_bpf_get_reg32(src_lo, tmp2[1], ctx);
+
+   /* ALU operation */
+   emit_alu_r(rd[1], rs, true, false, op, ctx);
+   emit_a32_mov_i(rd[0], 0, ctx);
+   }
+
+   arm_bpf_put_reg64(dst, rd, ctx);
 }
 
 /* dst = src (4 bytes)*/
-- 
2.7.4



[PATCH net-next 2/4] ARM: net: bpf: improve 64-bit sign-extended immediate load

2018-07-12 Thread Russell King
Improve the 64-bit sign-extended immediate from:

  mov r6, #1
  str r6, [fp, #-52]  ; 0xffcc
  mov r6, #0
  str r6, [fp, #-48]  ; 0xffd0

to:

  mov r6, #1
  mov r7, #0
  strdr6, [fp, #-52]  ; 0xffcc

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 7 +++
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 6558bd73bbb9..3a182e618441 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -613,12 +613,11 @@ static void emit_a32_mov_i64(const s8 dst[], u64 val, 
struct jit_ctx *ctx)
 /* Sign extended move */
 static inline void emit_a32_mov_se_i64(const bool is64, const s8 dst[],
   const u32 val, struct jit_ctx *ctx) {
-   u32 hi = 0;
+   u64 val64 = val;
 
if (is64 && (val & (1<<31)))
-   hi = (u32)~0;
-   emit_a32_mov_i(dst_lo, val, ctx);
-   emit_a32_mov_i(dst_hi, hi, ctx);
+   val64 |= 0xULL;
+   emit_a32_mov_i64(dst, val64, ctx);
 }
 
 static inline void emit_a32_add_r(const u8 dst, const u8 src,
-- 
2.7.4



[PATCH net-next 1/4] ARM: net: bpf: improve 64-bit load immediate implementation

2018-07-12 Thread Russell King
Rather than writing each 32-bit half of the 64-bit immediate value
separately when the register is on the stack:

  movwr6, #45056  ; 0xb000
  movtr6, #60979  ; 0xee33
  str r6, [fp, #-44]  ; 0xffd4
  mov r6, #0
  str r6, [fp, #-40]  ; 0xffd8

arrange to use the double-word store when available instead:

  movwr6, #45056  ; 0xb000
  movtr6, #60979  ; 0xee33
  mov r7, #0
  strdr6, [fp, #-44]  ; 0xffd4

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 32 
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index a9f68a924800..6558bd73bbb9 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -599,9 +599,20 @@ static inline void emit_a32_mov_i(const s8 dst, const u32 
val,
}
 }
 
+static void emit_a32_mov_i64(const s8 dst[], u64 val, struct jit_ctx *ctx)
+{
+   const s8 *tmp = bpf2a32[TMP_REG_1];
+   const s8 *rd = is_stacked(dst_lo) ? tmp : dst;
+
+   emit_mov_i(rd[1], (u32)val, ctx);
+   emit_mov_i(rd[0], val >> 32, ctx);
+
+   arm_bpf_put_reg64(dst, rd, ctx);
+}
+
 /* Sign extended move */
-static inline void emit_a32_mov_i64(const bool is64, const s8 dst[],
- const u32 val, struct jit_ctx *ctx) {
+static inline void emit_a32_mov_se_i64(const bool is64, const s8 dst[],
+  const u32 val, struct jit_ctx *ctx) {
u32 hi = 0;
 
if (is64 && (val & (1<<31)))
@@ -1309,7 +1320,7 @@ static int build_insn(const struct bpf_insn *insn, struct 
jit_ctx *ctx)
break;
case BPF_K:
/* Sign-extend immediate value to destination reg */
-   emit_a32_mov_i64(is64, dst, imm, ctx);
+   emit_a32_mov_se_i64(is64, dst, imm, ctx);
break;
}
break;
@@ -1358,7 +1369,7 @@ static int build_insn(const struct bpf_insn *insn, struct 
jit_ctx *ctx)
 * value into temporary reg and then it would be
 * safe to do the operation on it.
 */
-   emit_a32_mov_i64(is64, tmp2, imm, ctx);
+   emit_a32_mov_se_i64(is64, tmp2, imm, ctx);
emit_a32_alu_r64(is64, dst, tmp2, ctx, BPF_OP(code));
break;
}
@@ -1454,7 +1465,7 @@ static int build_insn(const struct bpf_insn *insn, struct 
jit_ctx *ctx)
 * reg then it would be safe to do the operation
 * on it.
 */
-   emit_a32_mov_i64(is64, tmp2, imm, ctx);
+   emit_a32_mov_se_i64(is64, tmp2, imm, ctx);
emit_a32_mul_r64(dst, tmp2, ctx);
break;
}
@@ -1506,12 +1517,9 @@ static int build_insn(const struct bpf_insn *insn, 
struct jit_ctx *ctx)
/* dst = imm64 */
case BPF_LD | BPF_IMM | BPF_DW:
{
-   const struct bpf_insn insn1 = insn[1];
-   u32 hi, lo = imm;
+   u64 val = (u32)imm | (u64)insn[1].imm << 32;
 
-   hi = insn1.imm;
-   emit_a32_mov_i(dst_lo, lo, ctx);
-   emit_a32_mov_i(dst_hi, hi, ctx);
+   emit_a32_mov_i64(dst, val, ctx);
 
return 1;
}
@@ -1531,7 +1539,7 @@ static int build_insn(const struct bpf_insn *insn, struct 
jit_ctx *ctx)
switch (BPF_SIZE(code)) {
case BPF_DW:
/* Sign-extend immediate value into temp reg */
-   emit_a32_mov_i64(true, tmp2, imm, ctx);
+   emit_a32_mov_se_i64(true, tmp2, imm, ctx);
emit_str_r(dst_lo, tmp2[1], off, ctx, BPF_W);
emit_str_r(dst_lo, tmp2[0], off+4, ctx, BPF_W);
break;
@@ -1620,7 +1628,7 @@ static int build_insn(const struct bpf_insn *insn, struct 
jit_ctx *ctx)
rm = tmp2[0];
rn = tmp2[1];
/* Sign-extend immediate value */
-   emit_a32_mov_i64(true, tmp2, imm, ctx);
+   emit_a32_mov_se_i64(true, tmp2, imm, ctx);
 go_jmp:
/* Setup destination register */
rd = arm_bpf_get_reg64(dst, tmp, ctx);
-- 
2.7.4



[PATCH net-next 0/4] Further ARM BPF jit compiler improvements

2018-07-12 Thread Russell King - ARM Linux
Four further jit compiler improves for 32-bit ARM.

 arch/arm/net/bpf_jit_32.c | 120 --
 1 file changed, 73 insertions(+), 47 deletions(-)

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


[PATCH net-next v2 14/14] ARM: net: bpf: use double-word load/stores where available

2018-07-11 Thread Russell King
Use double-word load and stores where support for this instruction is
supported by the CPU architecture.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 55 ---
 arch/arm/net/bpf_jit_32.h |  2 ++
 2 files changed, 45 insertions(+), 12 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 006ff9615850..a9f68a924800 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -22,6 +22,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "bpf_jit_32.h"
 
@@ -192,6 +193,7 @@ struct jit_ctx {
unsigned int idx;
unsigned int prologue_bytes;
unsigned int epilogue_offset;
+   unsigned int cpu_architecture;
u32 flags;
u32 *offsets;
u32 *target;
@@ -319,10 +321,12 @@ static u32 arm_bpf_ldst_imm8(u32 op, u8 rt, u8 rn, s16 
imm8)
 
 #define ARM_LDR_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_LDR_I, rt, rn, off)
 #define ARM_LDRB_I(rt, rn, off)arm_bpf_ldst_imm12(ARM_INST_LDRB_I, rt, 
rn, off)
+#define ARM_LDRD_I(rt, rn, off)arm_bpf_ldst_imm8(ARM_INST_LDRD_I, rt, 
rn, off)
 #define ARM_LDRH_I(rt, rn, off)arm_bpf_ldst_imm8(ARM_INST_LDRH_I, rt, 
rn, off)
 
 #define ARM_STR_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_STR_I, rt, rn, off)
 #define ARM_STRB_I(rt, rn, off)arm_bpf_ldst_imm12(ARM_INST_STRB_I, rt, 
rn, off)
+#define ARM_STRD_I(rt, rn, off)arm_bpf_ldst_imm8(ARM_INST_STRD_I, rt, 
rn, off)
 #define ARM_STRH_I(rt, rn, off)arm_bpf_ldst_imm8(ARM_INST_STRH_I, rt, 
rn, off)
 
 /*
@@ -533,10 +537,16 @@ static const s8 *arm_bpf_get_reg64(const s8 *reg, const 
s8 *tmp,
   struct jit_ctx *ctx)
 {
if (is_stacked(reg[1])) {
-   emit(ARM_LDR_I(tmp[1], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[1])),
-ctx);
-   emit(ARM_LDR_I(tmp[0], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[0])),
-ctx);
+   if (__LINUX_ARM_ARCH__ >= 6 ||
+   ctx->cpu_architecture >= CPU_ARCH_ARMv5TE) {
+   emit(ARM_LDRD_I(tmp[1], ARM_FP,
+   EBPF_SCRATCH_TO_ARM_FP(reg[1])), ctx);
+   } else {
+   emit(ARM_LDR_I(tmp[1], ARM_FP,
+  EBPF_SCRATCH_TO_ARM_FP(reg[1])), ctx);
+   emit(ARM_LDR_I(tmp[0], ARM_FP,
+  EBPF_SCRATCH_TO_ARM_FP(reg[0])), ctx);
+   }
reg = tmp;
}
return reg;
@@ -558,10 +568,16 @@ static void arm_bpf_put_reg64(const s8 *reg, const s8 
*src,
  struct jit_ctx *ctx)
 {
if (is_stacked(reg[1])) {
-   emit(ARM_STR_I(src[1], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[1])),
-ctx);
-   emit(ARM_STR_I(src[0], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[0])),
-ctx);
+   if (__LINUX_ARM_ARCH__ >= 6 ||
+   ctx->cpu_architecture >= CPU_ARCH_ARMv5TE) {
+   emit(ARM_STRD_I(src[1], ARM_FP,
+  EBPF_SCRATCH_TO_ARM_FP(reg[1])), ctx);
+   } else {
+   emit(ARM_STR_I(src[1], ARM_FP,
+  EBPF_SCRATCH_TO_ARM_FP(reg[1])), ctx);
+   emit(ARM_STR_I(src[0], ARM_FP,
+  EBPF_SCRATCH_TO_ARM_FP(reg[0])), ctx);
+   }
} else {
if (reg[1] != src[1])
emit(ARM_MOV_R(reg[1], src[1]), ctx);
@@ -711,13 +727,27 @@ static inline void emit_a32_mov_r(const s8 dst, const s8 
src,
 static inline void emit_a32_mov_r64(const bool is64, const s8 dst[],
  const s8 src[],
  struct jit_ctx *ctx) {
-   emit_a32_mov_r(dst_lo, src_lo, ctx);
-   if (is64) {
+   if (!is64) {
+   emit_a32_mov_r(dst_lo, src_lo, ctx);
+   /* Zero out high 4 bytes */
+   emit_a32_mov_i(dst_hi, 0, ctx);
+   } else if (__LINUX_ARM_ARCH__ < 6 &&
+  ctx->cpu_architecture < CPU_ARCH_ARMv5TE) {
/* complete 8 byte move */
+   emit_a32_mov_r(dst_lo, src_lo, ctx);
emit_a32_mov_r(dst_hi, src_hi, ctx);
+   } else if (is_stacked(src_lo) && is_stacked(dst_lo)) {
+   const u8 *tmp = bpf2a32[TMP_REG_1];
+
+   emit(ARM_LDRD_I(tmp[1], ARM_FP, 
EBPF_SCRATCH_TO_ARM_FP(src_lo)), ctx);
+   emit(ARM_STRD_I(tmp[1], ARM_FP, 
EBPF_SCRATCH_TO_ARM_FP(dst_lo)), ctx);
+   } else if (is_stacked(src_lo)) {
+   emit(ARM_LDRD_I(dst[1], ARM_FP, 
EBPF_SCRATCH_TO_ARM_FP(src_lo)), ctx);
+   } else if (is_stacked(dst_lo)) {
+   emit(ARM_STRD_I(src[1], ARM_FP, 

[PATCH net-next v2 12/14] ARM: net: bpf: avoid reloading 'array'

2018-07-11 Thread Russell King
Rearranging the order of the initial tail call code a little allows is
to avoid reloading the 'array' pointer.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 9 -
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 0a8b3d0903c4..f0cad9692952 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -1064,16 +1064,16 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
BUILD_BUG_ON(offsetof(struct bpf_array, map.max_entries) >
 ARM_INST_LDST__IMM12);
off = offsetof(struct bpf_array, map.max_entries);
-   /* array->map.max_entries */
-   r_array = arm_bpf_get_reg32(r2[1], tmp2[1], ctx);
-   emit(ARM_LDR_I(tmp[1], r_array, off), ctx);
+   r_array = arm_bpf_get_reg32(r2[1], tmp2[0], ctx);
/* index is 32-bit for arrays */
r_index = arm_bpf_get_reg32(r3[1], tmp2[1], ctx);
+   /* array->map.max_entries */
+   emit(ARM_LDR_I(tmp[1], r_array, off), ctx);
/* index >= array->map.max_entries */
emit(ARM_CMP_R(r_index, tmp[1]), ctx);
_emit(ARM_COND_CS, ARM_B(jmp_offset), ctx);
 
-   /* tmp2[1] = index */
+   /* tmp2[0] = array, tmp2[1] = index */
 
/* if (tail_call_cnt > MAX_TAIL_CALL_CNT)
 *  goto out;
@@ -1095,7 +1095,6 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
 */
BUILD_BUG_ON(imm8m(offsetof(struct bpf_array, ptrs)) < 0);
off = imm8m(offsetof(struct bpf_array, ptrs));
-   r_array = arm_bpf_get_reg32(r2[1], tmp2[0], ctx);
emit(ARM_ADD_I(tmp[1], r_array, off), ctx);
emit(ARM_LDR_R_SI(tmp[1], tmp[1], r_index, SRTYPE_ASL, 2), ctx);
emit(ARM_CMP_I(tmp[1], 0), ctx);
-- 
2.7.4



[PATCH net-next v2 13/14] ARM: net: bpf: always use odd/even register pair

2018-07-11 Thread Russell King
Always use an odd/even register pair for our 64-bit registers, so that
we're able to use the double-word load/store instructions in the future.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 28 ++--
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index f0cad9692952..006ff9615850 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -47,27 +47,27 @@
  * The callee saved registers depends on whether frame pointers are enabled.
  * With frame pointers (to be compliant with the ABI):
  *
- *high
- * original ARM_SP => +--+ \
- *|pc| |
- * current ARM_FP =>  +--+ } callee saved registers
- *|r4-r8,r10,fp,ip,lr| |
- *+--+ /
- *low
+ *  high
+ * original ARM_SP => +--+ \
+ *|  pc  | |
+ * current ARM_FP =>  +--+ } callee saved registers
+ *|r4-r9,fp,ip,lr| |
+ *+--+ /
+ *  low
  *
  * Without frame pointers:
  *
- *high
- * original ARM_SP => +--+
- *| r4-r8,r10,fp,lr  | callee saved registers
- * current ARM_FP =>  +--+
- *low
+ *  high
+ * original ARM_SP => +--+
+ *|  r4-r9,fp,lr | callee saved registers
+ * current ARM_FP =>  +--+
+ *  low
  *
  * When popping registers off the stack at the end of a BPF function, we
  * reference them via the current ARM_FP register.
  */
 #define CALLEE_MASK(1 << ARM_R4 | 1 << ARM_R5 | 1 << ARM_R6 | \
-1 << ARM_R7 | 1 << ARM_R8 | 1 << ARM_R10 | \
+1 << ARM_R7 | 1 << ARM_R8 | 1 << ARM_R9 | \
 1 << ARM_FP)
 #define CALLEE_PUSH_MASK (CALLEE_MASK | 1 << ARM_LR)
 #define CALLEE_POP_MASK  (CALLEE_MASK | 1 << ARM_PC)
@@ -157,7 +157,7 @@ static const s8 bpf2a32[][2] = {
 * for constant blindings and others.
 */
[TMP_REG_1] = {ARM_R7, ARM_R6},
-   [TMP_REG_2] = {ARM_R10, ARM_R8},
+   [TMP_REG_2] = {ARM_R9, ARM_R8},
/* Tail call count. Stored on stack scratch space. */
[TCALL_CNT] = {STACK_OFFSET(BPF_TC_HI), STACK_OFFSET(BPF_TC_LO)},
/* temporary register for blinding constants.
-- 
2.7.4



[PATCH net-next v2 04/14] ARM: net: bpf: remove is_on_stack() and sstk/dstk

2018-07-11 Thread Russell King
The decision about whether a BPF register is on the stack or in a CPU
register is detected at the top BPF insn processing level, and then
percolated throughout the remainder of the code.  Since we now use
negative register values to represent stacked registers, we can detect
where a BPF register is stored without restoring to carrying this
additional metadata through all code paths.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 336 ++
 1 file changed, 160 insertions(+), 176 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 69bf7ab18bf9..e81401aca2df 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -459,27 +459,18 @@ static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, 
struct jit_ctx *ctx, u8 op)
emit(ARM_MOV_R(ARM_R0, tmp[1]), ctx);
 }
 
-/* Checks whether BPF register is on scratch stack space or not. */
-static inline bool is_on_stack(u8 bpf_reg)
+/* Is the translated BPF register on stack? */
+static bool is_stacked(s8 reg)
 {
-   static u8 stack_regs[] = {BPF_REG_AX, BPF_REG_3, BPF_REG_4, BPF_REG_5,
-   BPF_REG_7, BPF_REG_8, BPF_REG_9, TCALL_CNT,
-   BPF_REG_2, BPF_REG_FP};
-   int i, reg_len = sizeof(stack_regs);
-
-   for (i = 0 ; i < reg_len ; i++) {
-   if (bpf_reg == stack_regs[i])
-   return true;
-   }
-   return false;
+   return reg < 0;
 }
 
 static inline void emit_a32_mov_i(const s8 dst, const u32 val,
- bool dstk, struct jit_ctx *ctx)
+ struct jit_ctx *ctx)
 {
const s8 *tmp = bpf2a32[TMP_REG_1];
 
-   if (dstk) {
+   if (is_stacked(dst)) {
emit_mov_i(tmp[1], val, ctx);
emit(ARM_STR_I(tmp[1], ARM_SP, STACK_VAR(dst)), ctx);
} else {
@@ -489,14 +480,13 @@ static inline void emit_a32_mov_i(const s8 dst, const u32 
val,
 
 /* Sign extended move */
 static inline void emit_a32_mov_i64(const bool is64, const s8 dst[],
- const u32 val, bool dstk,
- struct jit_ctx *ctx) {
+ const u32 val, struct jit_ctx *ctx) {
u32 hi = 0;
 
if (is64 && (val & (1<<31)))
hi = (u32)~0;
-   emit_a32_mov_i(dst_lo, val, dstk, ctx);
-   emit_a32_mov_i(dst_hi, hi, dstk, ctx);
+   emit_a32_mov_i(dst_lo, val, ctx);
+   emit_a32_mov_i(dst_hi, hi, ctx);
 }
 
 static inline void emit_a32_add_r(const u8 dst, const u8 src,
@@ -579,17 +569,16 @@ static inline void emit_alu_r(const u8 dst, const u8 src, 
const bool is64,
  * dst = dst (op) src
  */
 static inline void emit_a32_alu_r(const s8 dst, const s8 src,
- bool dstk, bool sstk,
  struct jit_ctx *ctx, const bool is64,
  const bool hi, const u8 op) {
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rn = sstk ? tmp[1] : src;
+   s8 rn = is_stacked(src) ? tmp[1] : src;
 
-   if (sstk)
+   if (is_stacked(src))
emit(ARM_LDR_I(rn, ARM_SP, STACK_VAR(src)), ctx);
 
/* ALU operation */
-   if (dstk) {
+   if (is_stacked(dst)) {
emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(dst)), ctx);
emit_alu_r(tmp[0], rn, is64, hi, op, ctx);
emit(ARM_STR_I(tmp[0], ARM_SP, STACK_VAR(dst)), ctx);
@@ -600,26 +589,24 @@ static inline void emit_a32_alu_r(const s8 dst, const s8 
src,
 
 /* ALU operation (64 bit) */
 static inline void emit_a32_alu_r64(const bool is64, const s8 dst[],
- const s8 src[], bool dstk,
- bool sstk, struct jit_ctx *ctx,
+ const s8 src[], struct jit_ctx *ctx,
  const u8 op) {
-   emit_a32_alu_r(dst_lo, src_lo, dstk, sstk, ctx, is64, false, op);
+   emit_a32_alu_r(dst_lo, src_lo, ctx, is64, false, op);
if (is64)
-   emit_a32_alu_r(dst_hi, src_hi, dstk, sstk, ctx, is64, true, op);
+   emit_a32_alu_r(dst_hi, src_hi, ctx, is64, true, op);
else
-   emit_a32_mov_i(dst_hi, 0, dstk, ctx);
+   emit_a32_mov_i(dst_hi, 0, ctx);
 }
 
 /* dst = imm (4 bytes)*/
 static inline void emit_a32_mov_r(const s8 dst, const s8 src,
- bool dstk, bool sstk,
  struct jit_ctx *ctx) {
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rt = sstk ? tmp[0] : src;
+   s8 rt = is_stacked(src) ? tmp[0] : src;
 
-   if (sstk)
+   if (is_stacked(src))
emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(src)), ctx);
-   if (dstk)
+   if (is_stacked(dst))
emit(ARM_STR_I(rt, ARM_SP, STACK_VAR(d

[PATCH net-next v2 07/14] ARM: net: bpf: access eBPF scratch space using ARM FP register

2018-07-11 Thread Russell King
Access the eBPF scratch space using the frame pointer rather than our
stack pointer, as the offsets from the ARM frame pointer are constant
across all eBPF programs.

Since we no longer reference the scratch space registers from the stack
pointer, this simplifies emit_push_r64() as it no longer needs to know
how many words are pushed onto the stack.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 44 +---
 1 file changed, 25 insertions(+), 19 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 45a3599e94a4..753b5b2b2e3d 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -108,6 +108,12 @@ enum {
 #define STACK_OFFSET(k)(-4 - (k) * 4)
 #define SCRATCH_SIZE   (BPF_JIT_SCRATCH_REGS * 4)
 
+#ifdef CONFIG_FRAME_POINTER
+#define EBPF_SCRATCH_TO_ARM_FP(x) ((x) - 4 * hweight16(CALLEE_PUSH_MASK) - 4)
+#else
+#define EBPF_SCRATCH_TO_ARM_FP(x) (x)
+#endif
+
 #define TMP_REG_1  (MAX_BPF_JIT_REG + 0)   /* TEMP Register 1 */
 #define TMP_REG_2  (MAX_BPF_JIT_REG + 1)   /* TEMP Register 2 */
 #define TCALL_CNT  (MAX_BPF_JIT_REG + 2)   /* Tail Call Count */
@@ -294,9 +300,6 @@ static void jit_fill_hole(void *area, unsigned int size)
 #define _STACK_SIZE(ctx->prog->aux->stack_depth + SCRATCH_SIZE)
 #define STACK_SIZE ALIGN(_STACK_SIZE, STACK_ALIGNMENT)
 
-/* Get the offset of eBPF REGISTERs stored on scratch space. */
-#define STACK_VAR(off) (STACK_SIZE + (off))
-
 #if __LINUX_ARM_ARCH__ < 7
 
 static u16 imm_offset(u32 k, struct jit_ctx *ctx)
@@ -472,7 +475,7 @@ static bool is_stacked(s8 reg)
 static s8 arm_bpf_get_reg32(s8 reg, s8 tmp, struct jit_ctx *ctx)
 {
if (is_stacked(reg)) {
-   emit(ARM_LDR_I(tmp, ARM_SP, STACK_VAR(reg)), ctx);
+   emit(ARM_LDR_I(tmp, ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg)), ctx);
reg = tmp;
}
return reg;
@@ -482,8 +485,10 @@ static const s8 *arm_bpf_get_reg64(const s8 *reg, const s8 
*tmp,
   struct jit_ctx *ctx)
 {
if (is_stacked(reg[1])) {
-   emit(ARM_LDR_I(tmp[1], ARM_SP, STACK_VAR(reg[1])), ctx);
-   emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(reg[0])), ctx);
+   emit(ARM_LDR_I(tmp[1], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[1])),
+ctx);
+   emit(ARM_LDR_I(tmp[0], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[0])),
+ctx);
reg = tmp;
}
return reg;
@@ -496,7 +501,7 @@ static const s8 *arm_bpf_get_reg64(const s8 *reg, const s8 
*tmp,
 static void arm_bpf_put_reg32(s8 reg, s8 src, struct jit_ctx *ctx)
 {
if (is_stacked(reg))
-   emit(ARM_STR_I(src, ARM_SP, STACK_VAR(reg)), ctx);
+   emit(ARM_STR_I(src, ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg)), ctx);
else if (reg != src)
emit(ARM_MOV_R(reg, src), ctx);
 }
@@ -505,8 +510,10 @@ static void arm_bpf_put_reg64(const s8 *reg, const s8 *src,
  struct jit_ctx *ctx)
 {
if (is_stacked(reg[1])) {
-   emit(ARM_STR_I(src[1], ARM_SP, STACK_VAR(reg[1])), ctx);
-   emit(ARM_STR_I(src[0], ARM_SP, STACK_VAR(reg[0])), ctx);
+   emit(ARM_STR_I(src[1], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[1])),
+ctx);
+   emit(ARM_STR_I(src[0], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[0])),
+ctx);
} else {
if (reg[1] != src[1])
emit(ARM_MOV_R(reg[1], src[1]), ctx);
@@ -1103,16 +1110,15 @@ static inline void emit_rev32(const u8 rd, const u8 rn, 
struct jit_ctx *ctx)
 }
 
 // push the scratch stack register on top of the stack
-static inline void emit_push_r64(const s8 src[], const u8 shift,
-   struct jit_ctx *ctx)
+static inline void emit_push_r64(const s8 src[], struct jit_ctx *ctx)
 {
const s8 *tmp2 = bpf2a32[TMP_REG_2];
+   const s8 *rt;
u16 reg_set = 0;
 
-   emit(ARM_LDR_I(tmp2[1], ARM_SP, STACK_VAR(src[1]+shift)), ctx);
-   emit(ARM_LDR_I(tmp2[0], ARM_SP, STACK_VAR(src[0]+shift)), ctx);
+   rt = arm_bpf_get_reg64(src, tmp2, ctx);
 
-   reg_set = (1 << tmp2[1]) | (1 << tmp2[0]);
+   reg_set = (1 << rt[1]) | (1 << rt[0]);
emit(ARM_PUSH(reg_set), ctx);
 }
 
@@ -1155,8 +1161,8 @@ static void build_prologue(struct jit_ctx *ctx)
emit(ARM_MOV_R(r3, r4), ctx);
emit(ARM_MOV_R(r2, r0), ctx);
/* Initialize Tail Count */
-   emit(ARM_STR_I(r4, ARM_SP, STACK_VAR(tcc[0])), ctx);
-   emit(ARM_STR_I(r4, ARM_SP, STACK_VAR(tcc[1])), ctx);
+   emit(ARM_STR_I(r4, ARM_FP, EBPF_SCRATCH_TO_ARM_FP(tcc[0])), ctx);
+   emit(ARM_STR_I(r4, ARM_FP, EBPF_SCRATCH_TO_ARM_FP(tcc[1])), ctx);
/* end of prologue */
 }
 
@@ -1606,9 +1612,9 @@ static int build_insn(const struct bpf_insn *insn, struct 
jit_ctx *ctx)
 
 

[PATCH net-next v2 08/14] ARM: net: bpf: imm12 constant conversion

2018-07-11 Thread Russell King
Provide a version of the imm8m() function that the compiler can optimise
when used with a constant expression.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 50 ++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 753b5b2b2e3d..2cc66aa44dfe 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -237,9 +237,55 @@ static inline void emit(u32 inst, struct jit_ctx *ctx)
 }
 
 /*
+ * This is rather horrid, but necessary to convert an integer constant
+ * to an immediate operand for the opcodes, and be able to detect at
+ * build time whether the constant can't be converted (iow, usable in
+ * BUILD_BUG_ON()).
+ */
+#define imm12val(v, s) (rol32(v, (s)) | (s) << 7)
+#define const_imm8m(x) \
+   ({ int r;   \
+  u32 v = (x); \
+  if (!(v & ~0x00ff))  \
+   r = imm12val(v, 0); \
+  else if (!(v & ~0xc03f)) \
+   r = imm12val(v, 2); \
+  else if (!(v & ~0xf00f)) \
+   r = imm12val(v, 4); \
+  else if (!(v & ~0xfc03)) \
+   r = imm12val(v, 6); \
+  else if (!(v & ~0xff00)) \
+   r = imm12val(v, 8); \
+  else if (!(v & ~0x3fc0)) \
+   r = imm12val(v, 10);\
+  else if (!(v & ~0x0ff0)) \
+   r = imm12val(v, 12);\
+  else if (!(v & ~0x03fc)) \
+   r = imm12val(v, 14);\
+  else if (!(v & ~0x00ff)) \
+   r = imm12val(v, 16);\
+  else if (!(v & ~0x003fc000)) \
+   r = imm12val(v, 18);\
+  else if (!(v & ~0x000ff000)) \
+   r = imm12val(v, 20);\
+  else if (!(v & ~0x0003fc00)) \
+   r = imm12val(v, 22);\
+  else if (!(v & ~0xff00)) \
+   r = imm12val(v, 24);\
+  else if (!(v & ~0x3fc0)) \
+   r = imm12val(v, 26);\
+  else if (!(v & ~0x0ff0)) \
+   r = imm12val(v, 28);\
+  else if (!(v & ~0x03fc)) \
+   r = imm12val(v, 30);\
+  else \
+   r = -1; \
+  r; })
+
+/*
  * Checks if immediate value can be converted to imm12(12 bits) value.
  */
-static int16_t imm8m(u32 x)
+static int imm8m(u32 x)
 {
u32 rot;
 
@@ -249,6 +295,8 @@ static int16_t imm8m(u32 x)
return -1;
 }
 
+#define imm8m(x) (__builtin_constant_p(x) ? const_imm8m(x) : imm8m(x))
+
 static u32 arm_bpf_ldst_imm12(u32 op, u8 rt, u8 rn, s16 imm12)
 {
op |= rt << 12 | rn << 16;
-- 
2.7.4



[PATCH net-next v2 05/14] ARM: net: bpf: provide accessor functions for BPF registers

2018-07-11 Thread Russell King
Many of the code paths need to have knowledge about whether a register
is stacked or in a CPU register.  Move this decision making to a pair
of helper functions instead of having it scattered throughout the
code.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 329 ++
 1 file changed, 128 insertions(+), 201 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index e81401aca2df..08fb4eb285a2 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -465,6 +465,31 @@ static bool is_stacked(s8 reg)
return reg < 0;
 }
 
+/* If a BPF register is on the stack (stk is true), load it to the
+ * supplied temporary register and return the temporary register
+ * for subsequent operations, otherwise just use the CPU register.
+ */
+static s8 arm_bpf_get_reg32(s8 reg, s8 tmp, struct jit_ctx *ctx)
+{
+   if (is_stacked(reg)) {
+   emit(ARM_LDR_I(tmp, ARM_SP, STACK_VAR(reg)), ctx);
+   reg = tmp;
+   }
+   return reg;
+}
+
+/* If a BPF register is on the stack (stk is true), save the register
+ * back to the stack.  If the source register is not the same, then
+ * move it into the correct register.
+ */
+static void arm_bpf_put_reg32(s8 reg, s8 src, struct jit_ctx *ctx)
+{
+   if (is_stacked(reg))
+   emit(ARM_STR_I(src, ARM_SP, STACK_VAR(reg)), ctx);
+   else if (reg != src)
+   emit(ARM_MOV_R(reg, src), ctx);
+}
+
 static inline void emit_a32_mov_i(const s8 dst, const u32 val,
  struct jit_ctx *ctx)
 {
@@ -472,7 +497,7 @@ static inline void emit_a32_mov_i(const s8 dst, const u32 
val,
 
if (is_stacked(dst)) {
emit_mov_i(tmp[1], val, ctx);
-   emit(ARM_STR_I(tmp[1], ARM_SP, STACK_VAR(dst)), ctx);
+   arm_bpf_put_reg32(dst, tmp[1], ctx);
} else {
emit_mov_i(dst, val, ctx);
}
@@ -572,19 +597,13 @@ static inline void emit_a32_alu_r(const s8 dst, const s8 
src,
  struct jit_ctx *ctx, const bool is64,
  const bool hi, const u8 op) {
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rn = is_stacked(src) ? tmp[1] : src;
-
-   if (is_stacked(src))
-   emit(ARM_LDR_I(rn, ARM_SP, STACK_VAR(src)), ctx);
+   s8 rn, rd;
 
+   rn = arm_bpf_get_reg32(src, tmp[1], ctx);
+   rd = arm_bpf_get_reg32(dst, tmp[0], ctx);
/* ALU operation */
-   if (is_stacked(dst)) {
-   emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(dst)), ctx);
-   emit_alu_r(tmp[0], rn, is64, hi, op, ctx);
-   emit(ARM_STR_I(tmp[0], ARM_SP, STACK_VAR(dst)), ctx);
-   } else {
-   emit_alu_r(dst, rn, is64, hi, op, ctx);
-   }
+   emit_alu_r(rd, rn, is64, hi, op, ctx);
+   arm_bpf_put_reg32(dst, rd, ctx);
 }
 
 /* ALU operation (64 bit) */
@@ -598,18 +617,14 @@ static inline void emit_a32_alu_r64(const bool is64, 
const s8 dst[],
emit_a32_mov_i(dst_hi, 0, ctx);
 }
 
-/* dst = imm (4 bytes)*/
+/* dst = src (4 bytes)*/
 static inline void emit_a32_mov_r(const s8 dst, const s8 src,
  struct jit_ctx *ctx) {
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rt = is_stacked(src) ? tmp[0] : src;
+   s8 rt;
 
-   if (is_stacked(src))
-   emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(src)), ctx);
-   if (is_stacked(dst))
-   emit(ARM_STR_I(rt, ARM_SP, STACK_VAR(dst)), ctx);
-   else
-   emit(ARM_MOV_R(dst, rt), ctx);
+   rt = arm_bpf_get_reg32(src, tmp[0], ctx);
+   arm_bpf_put_reg32(dst, rt, ctx);
 }
 
 /* dst = src */
@@ -630,10 +645,9 @@ static inline void emit_a32_mov_r64(const bool is64, const 
s8 dst[],
 static inline void emit_a32_alu_i(const s8 dst, const u32 val,
struct jit_ctx *ctx, const u8 op) {
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rd = is_stacked(dst) ? tmp[0] : dst;
+   s8 rd;
 
-   if (is_stacked(dst))
-   emit(ARM_LDR_I(rd, ARM_SP, STACK_VAR(dst)), ctx);
+   rd = arm_bpf_get_reg32(dst, tmp[0], ctx);
 
/* Do shift operation */
switch (op) {
@@ -648,31 +662,25 @@ static inline void emit_a32_alu_i(const s8 dst, const u32 
val,
break;
}
 
-   if (is_stacked(dst))
-   emit(ARM_STR_I(rd, ARM_SP, STACK_VAR(dst)), ctx);
+   arm_bpf_put_reg32(dst, rd, ctx);
 }
 
 /* dst = ~dst (64 bit) */
 static inline void emit_a32_neg64(const s8 dst[],
struct jit_ctx *ctx){
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rd = is_stacked(dst_lo) ? tmp[1] : dst[1];
-   s8 rm = is_stacked(dst_lo) ? tmp[0] : dst[0];
+   s8 rd, rm;
 
/* Setup Operand */
-   if (is_stacked(dst_lo)) {
-   emit(ARM_LDR_I(rd, ARM_SP, STACK_VAR(dst_lo)), 

[PATCH net-next v2 06/14] ARM: net: bpf: 64-bit accessor functions for BPF registers

2018-07-11 Thread Russell King
Provide a couple of 64-bit register accessors, and use them where
appropriate

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 235 --
 1 file changed, 122 insertions(+), 113 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 08fb4eb285a2..45a3599e94a4 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -478,6 +478,17 @@ static s8 arm_bpf_get_reg32(s8 reg, s8 tmp, struct jit_ctx 
*ctx)
return reg;
 }
 
+static const s8 *arm_bpf_get_reg64(const s8 *reg, const s8 *tmp,
+  struct jit_ctx *ctx)
+{
+   if (is_stacked(reg[1])) {
+   emit(ARM_LDR_I(tmp[1], ARM_SP, STACK_VAR(reg[1])), ctx);
+   emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(reg[0])), ctx);
+   reg = tmp;
+   }
+   return reg;
+}
+
 /* If a BPF register is on the stack (stk is true), save the register
  * back to the stack.  If the source register is not the same, then
  * move it into the correct register.
@@ -490,6 +501,20 @@ static void arm_bpf_put_reg32(s8 reg, s8 src, struct 
jit_ctx *ctx)
emit(ARM_MOV_R(reg, src), ctx);
 }
 
+static void arm_bpf_put_reg64(const s8 *reg, const s8 *src,
+ struct jit_ctx *ctx)
+{
+   if (is_stacked(reg[1])) {
+   emit(ARM_STR_I(src[1], ARM_SP, STACK_VAR(reg[1])), ctx);
+   emit(ARM_STR_I(src[0], ARM_SP, STACK_VAR(reg[0])), ctx);
+   } else {
+   if (reg[1] != src[1])
+   emit(ARM_MOV_R(reg[1], src[1]), ctx);
+   if (reg[0] != src[0])
+   emit(ARM_MOV_R(reg[0], src[0]), ctx);
+   }
+}
+
 static inline void emit_a32_mov_i(const s8 dst, const u32 val,
  struct jit_ctx *ctx)
 {
@@ -669,18 +694,16 @@ static inline void emit_a32_alu_i(const s8 dst, const u32 
val,
 static inline void emit_a32_neg64(const s8 dst[],
struct jit_ctx *ctx){
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rd, rm;
+   const s8 *rd;
 
/* Setup Operand */
-   rd = arm_bpf_get_reg32(dst_lo, tmp[1], ctx);
-   rm = arm_bpf_get_reg32(dst_hi, tmp[0], ctx);
+   rd = arm_bpf_get_reg64(dst, tmp, ctx);
 
/* Do Negate Operation */
-   emit(ARM_RSBS_I(rd, rd, 0), ctx);
-   emit(ARM_RSC_I(rm, rm, 0), ctx);
+   emit(ARM_RSBS_I(rd[1], rd[1], 0), ctx);
+   emit(ARM_RSC_I(rd[0], rd[0], 0), ctx);
 
-   arm_bpf_put_reg32(dst_lo, rd, ctx);
-   arm_bpf_put_reg32(dst_hi, rm, ctx);
+   arm_bpf_put_reg64(dst, rd, ctx);
 }
 
 /* dst = dst << src */
@@ -688,20 +711,20 @@ static inline void emit_a32_lsh_r64(const s8 dst[], const 
s8 src[],
struct jit_ctx *ctx) {
const s8 *tmp = bpf2a32[TMP_REG_1];
const s8 *tmp2 = bpf2a32[TMP_REG_2];
-   s8 rt, rd, rm;
+   const s8 *rd;
+   s8 rt;
 
/* Setup Operands */
rt = arm_bpf_get_reg32(src_lo, tmp2[1], ctx);
-   rd = arm_bpf_get_reg32(dst_lo, tmp[1], ctx);
-   rm = arm_bpf_get_reg32(dst_hi, tmp[0], ctx);
+   rd = arm_bpf_get_reg64(dst, tmp, ctx);
 
/* Do LSH operation */
emit(ARM_SUB_I(ARM_IP, rt, 32), ctx);
emit(ARM_RSB_I(tmp2[0], rt, 32), ctx);
-   emit(ARM_MOV_SR(ARM_LR, rm, SRTYPE_ASL, rt), ctx);
-   emit(ARM_ORR_SR(ARM_LR, ARM_LR, rd, SRTYPE_ASL, ARM_IP), ctx);
-   emit(ARM_ORR_SR(ARM_IP, ARM_LR, rd, SRTYPE_LSR, tmp2[0]), ctx);
-   emit(ARM_MOV_SR(ARM_LR, rd, SRTYPE_ASL, rt), ctx);
+   emit(ARM_MOV_SR(ARM_LR, rd[0], SRTYPE_ASL, rt), ctx);
+   emit(ARM_ORR_SR(ARM_LR, ARM_LR, rd[1], SRTYPE_ASL, ARM_IP), ctx);
+   emit(ARM_ORR_SR(ARM_IP, ARM_LR, rd[1], SRTYPE_LSR, tmp2[0]), ctx);
+   emit(ARM_MOV_SR(ARM_LR, rd[1], SRTYPE_ASL, rt), ctx);
 
arm_bpf_put_reg32(dst_lo, ARM_LR, ctx);
arm_bpf_put_reg32(dst_hi, ARM_IP, ctx);
@@ -712,21 +735,21 @@ static inline void emit_a32_arsh_r64(const s8 dst[], 
const s8 src[],
 struct jit_ctx *ctx) {
const s8 *tmp = bpf2a32[TMP_REG_1];
const s8 *tmp2 = bpf2a32[TMP_REG_2];
-   s8 rt, rd, rm;
+   const s8 *rd;
+   s8 rt;
 
/* Setup Operands */
rt = arm_bpf_get_reg32(src_lo, tmp2[1], ctx);
-   rd = arm_bpf_get_reg32(dst_lo, tmp[1], ctx);
-   rm = arm_bpf_get_reg32(dst_hi, tmp[0], ctx);
+   rd = arm_bpf_get_reg64(dst, tmp, ctx);
 
/* Do the ARSH operation */
emit(ARM_RSB_I(ARM_IP, rt, 32), ctx);
emit(ARM_SUBS_I(tmp2[0], rt, 32), ctx);
-   emit(ARM_MOV_SR(ARM_LR, rd, SRTYPE_LSR, rt), ctx);
-   emit(ARM_ORR_SR(ARM_LR, ARM_LR, rm, SRTYPE_ASL, ARM_IP), ctx);
+   emit(ARM_MOV_SR(ARM_LR, rd[1], SRTYPE_LSR, rt), ctx);
+   emit(ARM_ORR_SR(ARM_LR, ARM_LR, rd[0], SRTYPE_ASL, ARM_IP), ctx);
_emit(ARM_COND_MI, ARM_B(0), ctx);
-   emit(ARM_

[PATCH net-next v2 11/14] ARM: net: bpf: avoid reloading 'index'

2018-07-11 Thread Russell King
Avoid reloading 'index' after we have validated it - it remains in
tmp2[1] up to the point that we begin the code to index the pointer
array, so with a little rearrangement of the registers, we can use
the already loaded value.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index e22dc828420c..0a8b3d0903c4 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -1073,6 +1073,8 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
emit(ARM_CMP_R(r_index, tmp[1]), ctx);
_emit(ARM_COND_CS, ARM_B(jmp_offset), ctx);
 
+   /* tmp2[1] = index */
+
/* if (tail_call_cnt > MAX_TAIL_CALL_CNT)
 *  goto out;
 * tail_call_cnt++;
@@ -1093,9 +1095,8 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
 */
BUILD_BUG_ON(imm8m(offsetof(struct bpf_array, ptrs)) < 0);
off = imm8m(offsetof(struct bpf_array, ptrs));
-   r_array = arm_bpf_get_reg32(r2[1], tmp2[1], ctx);
+   r_array = arm_bpf_get_reg32(r2[1], tmp2[0], ctx);
emit(ARM_ADD_I(tmp[1], r_array, off), ctx);
-   r_index = arm_bpf_get_reg32(r3[1], tmp2[1], ctx);
emit(ARM_LDR_R_SI(tmp[1], tmp[1], r_index, SRTYPE_ASL, 2), ctx);
emit(ARM_CMP_I(tmp[1], 0), ctx);
_emit(ARM_COND_EQ, ARM_B(jmp_offset), ctx);
-- 
2.7.4



[PATCH net-next v2 10/14] ARM: net: bpf: use ldr instructions with shifted rm register

2018-07-11 Thread Russell King
Rather than pre-shifting the rm register for the ldr in the tail call,
shift it in the load instruction.  This eliminates one unnecessary
instruction.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 3 +--
 arch/arm/net/bpf_jit_32.h | 4 
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 645653e1931e..e22dc828420c 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -1096,8 +1096,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
r_array = arm_bpf_get_reg32(r2[1], tmp2[1], ctx);
emit(ARM_ADD_I(tmp[1], r_array, off), ctx);
r_index = arm_bpf_get_reg32(r3[1], tmp2[1], ctx);
-   emit(ARM_MOV_SI(tmp[0], r_index, SRTYPE_ASL, 2), ctx);
-   emit(ARM_LDR_R(tmp[1], tmp[1], tmp[0]), ctx);
+   emit(ARM_LDR_R_SI(tmp[1], tmp[1], r_index, SRTYPE_ASL, 2), ctx);
emit(ARM_CMP_I(tmp[1], 0), ctx);
_emit(ARM_COND_EQ, ARM_B(jmp_offset), ctx);
 
diff --git a/arch/arm/net/bpf_jit_32.h b/arch/arm/net/bpf_jit_32.h
index dee8a76fb0bc..e541a7a6139a 100644
--- a/arch/arm/net/bpf_jit_32.h
+++ b/arch/arm/net/bpf_jit_32.h
@@ -188,6 +188,10 @@
 #define ARM_LDR_R(rt, rn, rm)  (ARM_INST_LDR_R | ARM_INST_LDST__U \
 | (rt) << 12 | (rn) << 16 \
 | (rm))
+#define ARM_LDR_R_SI(rt, rn, rm, type, imm) \
+   (ARM_INST_LDR_R | ARM_INST_LDST__U \
+| (rt) << 12 | (rn) << 16 \
+| (imm) << 7 | (type) << 5 | (rm))
 #define ARM_LDRB_R(rt, rn, rm) (ARM_INST_LDRB_R | ARM_INST_LDST__U \
 | (rt) << 12 | (rn) << 16 \
 | (rm))
-- 
2.7.4



[PATCH net-next v2 09/14] ARM: net: bpf: use immediate forms of instructions where possible

2018-07-11 Thread Russell King
Rather than moving constants to a register and then using them in a
subsequent instruction, use them directly in the desired instruction
cutting out the "middle" register.  This removes two instructions from
the tail call code path.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 21 -
 arch/arm/net/bpf_jit_32.h |  1 +
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 2cc66aa44dfe..645653e1931e 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -304,7 +304,7 @@ static u32 arm_bpf_ldst_imm12(u32 op, u8 rt, u8 rn, s16 
imm12)
op |= ARM_INST_LDST__U;
else
imm12 = -imm12;
-   return op | (imm12 & 0xfff);
+   return op | (imm12 & ARM_INST_LDST__IMM12);
 }
 
 static u32 arm_bpf_ldst_imm8(u32 op, u8 rt, u8 rn, s16 imm8)
@@ -1054,17 +1054,19 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
const int idx0 = ctx->idx;
 #define cur_offset (ctx->idx - idx0)
 #define jmp_offset (out_offset - (cur_offset) - 2)
-   u32 off, lo, hi;
+   u32 lo, hi;
s8 r_array, r_index;
+   int off;
 
/* if (index >= array->map.max_entries)
 *  goto out;
 */
+   BUILD_BUG_ON(offsetof(struct bpf_array, map.max_entries) >
+ARM_INST_LDST__IMM12);
off = offsetof(struct bpf_array, map.max_entries);
/* array->map.max_entries */
-   emit_a32_mov_i(tmp[1], off, ctx);
r_array = arm_bpf_get_reg32(r2[1], tmp2[1], ctx);
-   emit(ARM_LDR_R(tmp[1], r_array, tmp[1]), ctx);
+   emit(ARM_LDR_I(tmp[1], r_array, off), ctx);
/* index is 32-bit for arrays */
r_index = arm_bpf_get_reg32(r3[1], tmp2[1], ctx);
/* index >= array->map.max_entries */
@@ -1089,10 +1091,10 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
 * if (prog == NULL)
 *  goto out;
 */
-   off = offsetof(struct bpf_array, ptrs);
-   emit_a32_mov_i(tmp[1], off, ctx);
+   BUILD_BUG_ON(imm8m(offsetof(struct bpf_array, ptrs)) < 0);
+   off = imm8m(offsetof(struct bpf_array, ptrs));
r_array = arm_bpf_get_reg32(r2[1], tmp2[1], ctx);
-   emit(ARM_ADD_R(tmp[1], r_array, tmp[1]), ctx);
+   emit(ARM_ADD_I(tmp[1], r_array, off), ctx);
r_index = arm_bpf_get_reg32(r3[1], tmp2[1], ctx);
emit(ARM_MOV_SI(tmp[0], r_index, SRTYPE_ASL, 2), ctx);
emit(ARM_LDR_R(tmp[1], tmp[1], tmp[0]), ctx);
@@ -1100,9 +1102,10 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
_emit(ARM_COND_EQ, ARM_B(jmp_offset), ctx);
 
/* goto *(prog->bpf_func + prologue_size); */
+   BUILD_BUG_ON(offsetof(struct bpf_prog, bpf_func) >
+ARM_INST_LDST__IMM12);
off = offsetof(struct bpf_prog, bpf_func);
-   emit_a32_mov_i(tmp2[1], off, ctx);
-   emit(ARM_LDR_R(tmp[1], tmp[1], tmp2[1]), ctx);
+   emit(ARM_LDR_I(tmp[1], tmp[1], off), ctx);
emit(ARM_ADD_I(tmp[1], tmp[1], ctx->prologue_bytes), ctx);
emit_bx_r(tmp[1], ctx);
 
diff --git a/arch/arm/net/bpf_jit_32.h b/arch/arm/net/bpf_jit_32.h
index c55bc39d3e22..dee8a76fb0bc 100644
--- a/arch/arm/net/bpf_jit_32.h
+++ b/arch/arm/net/bpf_jit_32.h
@@ -78,6 +78,7 @@
 #define ARM_INST_EOR_I 0x0220
 
 #define ARM_INST_LDST__U   0x0080
+#define ARM_INST_LDST__IMM12   0x0fff
 #define ARM_INST_LDRB_I0x0550
 #define ARM_INST_LDRB_R0x07d0
 #define ARM_INST_LDRH_I0x015000b0
-- 
2.7.4



[PATCH net-next v2 01/14] ARM: net: bpf: enumerate the JIT scratch stack layout

2018-07-11 Thread Russell King
Enumerate the contents of the JIT scratch stack layout used for storing
some of the JITs 64-bit registers, tail call counter and AX register.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 59 +--
 1 file changed, 42 insertions(+), 17 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index f6a62ae44a65..f2e6ffe57788 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -72,7 +72,38 @@
 #define CALLEE_PUSH_MASK (CALLEE_MASK | 1 << ARM_LR)
 #define CALLEE_POP_MASK  (CALLEE_MASK | 1 << ARM_PC)
 
-#define STACK_OFFSET(k)(k)
+enum {
+   /* Stack layout - these are offsets from (top of stack - 4) */
+   BPF_R2_HI,
+   BPF_R2_LO,
+   BPF_R3_HI,
+   BPF_R3_LO,
+   BPF_R4_HI,
+   BPF_R4_LO,
+   BPF_R5_HI,
+   BPF_R5_LO,
+   BPF_R7_HI,
+   BPF_R7_LO,
+   BPF_R8_HI,
+   BPF_R8_LO,
+   BPF_R9_HI,
+   BPF_R9_LO,
+   BPF_FP_HI,
+   BPF_FP_LO,
+   BPF_TC_HI,
+   BPF_TC_LO,
+   BPF_AX_HI,
+   BPF_AX_LO,
+   /* Stack space for BPF_REG_2, BPF_REG_3, BPF_REG_4,
+* BPF_REG_5, BPF_REG_7, BPF_REG_8, BPF_REG_9,
+* BPF_REG_FP and Tail call counts.
+*/
+   BPF_JIT_SCRATCH_REGS,
+};
+
+#define STACK_OFFSET(k)((k) * 4)
+#define SCRATCH_SIZE   (BPF_JIT_SCRATCH_REGS * 4)
+
 #define TMP_REG_1  (MAX_BPF_JIT_REG + 0)   /* TEMP Register 1 */
 #define TMP_REG_2  (MAX_BPF_JIT_REG + 1)   /* TEMP Register 2 */
 #define TCALL_CNT  (MAX_BPF_JIT_REG + 2)   /* Tail Call Count */
@@ -100,29 +131,29 @@ static const u8 bpf2a32[][2] = {
/* arguments from eBPF program to in-kernel function */
[BPF_REG_1] = {ARM_R3, ARM_R2},
/* Stored on stack scratch space */
-   [BPF_REG_2] = {STACK_OFFSET(0), STACK_OFFSET(4)},
-   [BPF_REG_3] = {STACK_OFFSET(8), STACK_OFFSET(12)},
-   [BPF_REG_4] = {STACK_OFFSET(16), STACK_OFFSET(20)},
-   [BPF_REG_5] = {STACK_OFFSET(24), STACK_OFFSET(28)},
+   [BPF_REG_2] = {STACK_OFFSET(BPF_R2_HI), STACK_OFFSET(BPF_R2_LO)},
+   [BPF_REG_3] = {STACK_OFFSET(BPF_R3_HI), STACK_OFFSET(BPF_R3_LO)},
+   [BPF_REG_4] = {STACK_OFFSET(BPF_R4_HI), STACK_OFFSET(BPF_R4_LO)},
+   [BPF_REG_5] = {STACK_OFFSET(BPF_R5_HI), STACK_OFFSET(BPF_R5_LO)},
/* callee saved registers that in-kernel function will preserve */
[BPF_REG_6] = {ARM_R5, ARM_R4},
/* Stored on stack scratch space */
-   [BPF_REG_7] = {STACK_OFFSET(32), STACK_OFFSET(36)},
-   [BPF_REG_8] = {STACK_OFFSET(40), STACK_OFFSET(44)},
-   [BPF_REG_9] = {STACK_OFFSET(48), STACK_OFFSET(52)},
+   [BPF_REG_7] = {STACK_OFFSET(BPF_R7_HI), STACK_OFFSET(BPF_R7_LO)},
+   [BPF_REG_8] = {STACK_OFFSET(BPF_R8_HI), STACK_OFFSET(BPF_R8_LO)},
+   [BPF_REG_9] = {STACK_OFFSET(BPF_R9_HI), STACK_OFFSET(BPF_R9_LO)},
/* Read only Frame Pointer to access Stack */
-   [BPF_REG_FP] = {STACK_OFFSET(56), STACK_OFFSET(60)},
+   [BPF_REG_FP] = {STACK_OFFSET(BPF_FP_HI), STACK_OFFSET(BPF_FP_LO)},
/* Temporary Register for internal BPF JIT, can be used
 * for constant blindings and others.
 */
[TMP_REG_1] = {ARM_R7, ARM_R6},
[TMP_REG_2] = {ARM_R10, ARM_R8},
/* Tail call count. Stored on stack scratch space. */
-   [TCALL_CNT] = {STACK_OFFSET(64), STACK_OFFSET(68)},
+   [TCALL_CNT] = {STACK_OFFSET(BPF_TC_HI), STACK_OFFSET(BPF_TC_LO)},
/* temporary register for blinding constants.
 * Stored on stack scratch space.
 */
-   [BPF_REG_AX] = {STACK_OFFSET(72), STACK_OFFSET(76)},
+   [BPF_REG_AX] = {STACK_OFFSET(BPF_AX_HI), STACK_OFFSET(BPF_AX_LO)},
 };
 
 #definedst_lo  dst[1]
@@ -227,12 +258,6 @@ static void jit_fill_hole(void *area, unsigned int size)
 #define STACK_ALIGNMENT4
 #endif
 
-/* Stack space for BPF_REG_2, BPF_REG_3, BPF_REG_4,
- * BPF_REG_5, BPF_REG_7, BPF_REG_8, BPF_REG_9,
- * BPF_REG_FP and Tail call counts.
- */
-#define SCRATCH_SIZE 80
-
 /* total stack size used in JITed code */
 #define _STACK_SIZE(ctx->prog->aux->stack_depth + SCRATCH_SIZE)
 #define STACK_SIZE ALIGN(_STACK_SIZE, STACK_ALIGNMENT)
-- 
2.7.4



[PATCH net-next v2 03/14] ARM: net: bpf: use negative numbers for stacked registers

2018-07-11 Thread Russell King
Use negative numbers for eBPF registers that live on the stack.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 200 +++---
 1 file changed, 102 insertions(+), 98 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index c81da1a50834..69bf7ab18bf9 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -101,7 +101,11 @@ enum {
BPF_JIT_SCRATCH_REGS,
 };
 
-#define STACK_OFFSET(k)((k) * 4)
+/*
+ * Negative "register" values indicate the register is stored on the stack
+ * and are the offset from the top of the eBPF JIT scratch space.
+ */
+#define STACK_OFFSET(k)(-4 - (k) * 4)
 #define SCRATCH_SIZE   (BPF_JIT_SCRATCH_REGS * 4)
 
 #define TMP_REG_1  (MAX_BPF_JIT_REG + 0)   /* TEMP Register 1 */
@@ -125,7 +129,7 @@ enum {
  * scratch memory space and we have to build eBPF 64 bit register from those.
  *
  */
-static const u8 bpf2a32[][2] = {
+static const s8 bpf2a32[][2] = {
/* return value from in-kernel function, and exit value from eBPF */
[BPF_REG_0] = {ARM_R1, ARM_R0},
/* arguments from eBPF program to in-kernel function */
@@ -291,7 +295,7 @@ static void jit_fill_hole(void *area, unsigned int size)
 #define STACK_SIZE ALIGN(_STACK_SIZE, STACK_ALIGNMENT)
 
 /* Get the offset of eBPF REGISTERs stored on scratch space. */
-#define STACK_VAR(off) (STACK_SIZE - off)
+#define STACK_VAR(off) (STACK_SIZE + (off))
 
 #if __LINUX_ARM_ARCH__ < 7
 
@@ -408,7 +412,7 @@ static inline int epilogue_offset(const struct jit_ctx *ctx)
 
 static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 
op)
 {
-   const u8 *tmp = bpf2a32[TMP_REG_1];
+   const s8 *tmp = bpf2a32[TMP_REG_1];
 
 #if __LINUX_ARM_ARCH__ == 7
if (elf_hwcap & HWCAP_IDIVA) {
@@ -470,10 +474,10 @@ static inline bool is_on_stack(u8 bpf_reg)
return false;
 }
 
-static inline void emit_a32_mov_i(const u8 dst, const u32 val,
+static inline void emit_a32_mov_i(const s8 dst, const u32 val,
  bool dstk, struct jit_ctx *ctx)
 {
-   const u8 *tmp = bpf2a32[TMP_REG_1];
+   const s8 *tmp = bpf2a32[TMP_REG_1];
 
if (dstk) {
emit_mov_i(tmp[1], val, ctx);
@@ -484,7 +488,7 @@ static inline void emit_a32_mov_i(const u8 dst, const u32 
val,
 }
 
 /* Sign extended move */
-static inline void emit_a32_mov_i64(const bool is64, const u8 dst[],
+static inline void emit_a32_mov_i64(const bool is64, const s8 dst[],
  const u32 val, bool dstk,
  struct jit_ctx *ctx) {
u32 hi = 0;
@@ -574,12 +578,12 @@ static inline void emit_alu_r(const u8 dst, const u8 src, 
const bool is64,
 /* ALU operation (32 bit)
  * dst = dst (op) src
  */
-static inline void emit_a32_alu_r(const u8 dst, const u8 src,
+static inline void emit_a32_alu_r(const s8 dst, const s8 src,
  bool dstk, bool sstk,
  struct jit_ctx *ctx, const bool is64,
  const bool hi, const u8 op) {
-   const u8 *tmp = bpf2a32[TMP_REG_1];
-   u8 rn = sstk ? tmp[1] : src;
+   const s8 *tmp = bpf2a32[TMP_REG_1];
+   s8 rn = sstk ? tmp[1] : src;
 
if (sstk)
emit(ARM_LDR_I(rn, ARM_SP, STACK_VAR(src)), ctx);
@@ -595,8 +599,8 @@ static inline void emit_a32_alu_r(const u8 dst, const u8 
src,
 }
 
 /* ALU operation (64 bit) */
-static inline void emit_a32_alu_r64(const bool is64, const u8 dst[],
- const u8 src[], bool dstk,
+static inline void emit_a32_alu_r64(const bool is64, const s8 dst[],
+ const s8 src[], bool dstk,
  bool sstk, struct jit_ctx *ctx,
  const u8 op) {
emit_a32_alu_r(dst_lo, src_lo, dstk, sstk, ctx, is64, false, op);
@@ -607,11 +611,11 @@ static inline void emit_a32_alu_r64(const bool is64, 
const u8 dst[],
 }
 
 /* dst = imm (4 bytes)*/
-static inline void emit_a32_mov_r(const u8 dst, const u8 src,
+static inline void emit_a32_mov_r(const s8 dst, const s8 src,
  bool dstk, bool sstk,
  struct jit_ctx *ctx) {
-   const u8 *tmp = bpf2a32[TMP_REG_1];
-   u8 rt = sstk ? tmp[0] : src;
+   const s8 *tmp = bpf2a32[TMP_REG_1];
+   s8 rt = sstk ? tmp[0] : src;
 
if (sstk)
emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(src)), ctx);
@@ -622,8 +626,8 @@ static inline void emit_a32_mov_r(const u8 dst, const u8 
src,
 }
 
 /* dst = src */
-static inline void emit_a32_mov_r64(const bool is64, const u8 dst[],
- const u8 src[], bool dstk,
+static inline void emit_a32_mov_r64(const bool is64, const s8 dst[],
+ const s8 src[], bool dstk,
  

[PATCH net-next v2 02/14] ARM: net: bpf: provide load/store ops with negative immediates

2018-07-11 Thread Russell King
Provide a set of load/store opcode generators that work with negative
immediates as well as positive ones.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 28 
 arch/arm/net/bpf_jit_32.h | 35 +--
 2 files changed, 41 insertions(+), 22 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index f2e6ffe57788..c81da1a50834 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -239,6 +239,34 @@ static int16_t imm8m(u32 x)
return -1;
 }
 
+static u32 arm_bpf_ldst_imm12(u32 op, u8 rt, u8 rn, s16 imm12)
+{
+   op |= rt << 12 | rn << 16;
+   if (imm12 >= 0)
+   op |= ARM_INST_LDST__U;
+   else
+   imm12 = -imm12;
+   return op | (imm12 & 0xfff);
+}
+
+static u32 arm_bpf_ldst_imm8(u32 op, u8 rt, u8 rn, s16 imm8)
+{
+   op |= rt << 12 | rn << 16;
+   if (imm8 >= 0)
+   op |= ARM_INST_LDST__U;
+   else
+   imm8 = -imm8;
+   return op | (imm8 & 0xf0) << 4 | (imm8 & 0x0f);
+}
+
+#define ARM_LDR_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_LDR_I, rt, rn, off)
+#define ARM_LDRB_I(rt, rn, off)arm_bpf_ldst_imm12(ARM_INST_LDRB_I, rt, 
rn, off)
+#define ARM_LDRH_I(rt, rn, off)arm_bpf_ldst_imm8(ARM_INST_LDRH_I, rt, 
rn, off)
+
+#define ARM_STR_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_STR_I, rt, rn, off)
+#define ARM_STRB_I(rt, rn, off)arm_bpf_ldst_imm12(ARM_INST_STRB_I, rt, 
rn, off)
+#define ARM_STRH_I(rt, rn, off)arm_bpf_ldst_imm8(ARM_INST_STRH_I, rt, 
rn, off)
+
 /*
  * Initializes the JIT space with undefined instructions.
  */
diff --git a/arch/arm/net/bpf_jit_32.h b/arch/arm/net/bpf_jit_32.h
index d5cf5f6208aa..c55bc39d3e22 100644
--- a/arch/arm/net/bpf_jit_32.h
+++ b/arch/arm/net/bpf_jit_32.h
@@ -77,11 +77,12 @@
 #define ARM_INST_EOR_R 0x0020
 #define ARM_INST_EOR_I 0x0220
 
-#define ARM_INST_LDRB_I0x05d0
+#define ARM_INST_LDST__U   0x0080
+#define ARM_INST_LDRB_I0x0550
 #define ARM_INST_LDRB_R0x07d0
-#define ARM_INST_LDRH_I0x01d000b0
+#define ARM_INST_LDRH_I0x015000b0
 #define ARM_INST_LDRH_R0x019000b0
-#define ARM_INST_LDR_I 0x0590
+#define ARM_INST_LDR_I 0x0510
 #define ARM_INST_LDR_R 0x0790
 
 #define ARM_INST_LDM   0x0890
@@ -124,9 +125,9 @@
 #define ARM_INST_SBC_R 0x00c0
 #define ARM_INST_SBCS_R0x00d0
 
-#define ARM_INST_STR_I 0x0580
-#define ARM_INST_STRB_I0x05c0
-#define ARM_INST_STRH_I0x01c000b0
+#define ARM_INST_STR_I 0x0500
+#define ARM_INST_STRB_I0x0540
+#define ARM_INST_STRH_I0x014000b0
 
 #define ARM_INST_TST_R 0x0110
 #define ARM_INST_TST_I 0x0310
@@ -183,17 +184,14 @@
 #define ARM_EOR_R(rd, rn, rm)  _AL3_R(ARM_INST_EOR, rd, rn, rm)
 #define ARM_EOR_I(rd, rn, imm) _AL3_I(ARM_INST_EOR, rd, rn, imm)
 
-#define ARM_LDR_I(rt, rn, off) (ARM_INST_LDR_I | (rt) << 12 | (rn) << 16 \
-| ((off) & 0xfff))
-#define ARM_LDR_R(rt, rn, rm)  (ARM_INST_LDR_R | (rt) << 12 | (rn) << 16 \
+#define ARM_LDR_R(rt, rn, rm)  (ARM_INST_LDR_R | ARM_INST_LDST__U \
+| (rt) << 12 | (rn) << 16 \
 | (rm))
-#define ARM_LDRB_I(rt, rn, off)(ARM_INST_LDRB_I | (rt) << 12 | (rn) << 
16 \
-| (off))
-#define ARM_LDRB_R(rt, rn, rm) (ARM_INST_LDRB_R | (rt) << 12 | (rn) << 16 \
+#define ARM_LDRB_R(rt, rn, rm) (ARM_INST_LDRB_R | ARM_INST_LDST__U \
+| (rt) << 12 | (rn) << 16 \
 | (rm))
-#define ARM_LDRH_I(rt, rn, off)(ARM_INST_LDRH_I | (rt) << 12 | (rn) << 
16 \
-| (((off) & 0xf0) << 4) | ((off) & 0xf))
-#define ARM_LDRH_R(rt, rn, rm) (ARM_INST_LDRH_R | (rt) << 12 | (rn) << 16 \
+#define ARM_LDRH_R(rt, rn, rm) (ARM_INST_LDRH_R | ARM_INST_LDST__U \
+| (rt) << 12 | (rn) << 16 \
 | (rm))
 
 #define ARM_LDM(rn, regs)  (ARM_INST_LDM | (rn) << 16 | (regs))
@@ -254,13 +252,6 @@
 #define ARM_SUBS_I(rd, rn, imm)_AL3_I(ARM_INST_SUBS, rd, rn, imm)
 #define ARM_SBC_I(rd, rn, imm) _AL3_I(ARM_INST_SBC, rd, rn, imm)
 
-#define ARM_STR_I(rt, rn, off) (ARM_INST_STR_I | (rt) << 12 | (rn) << 16 \
-| ((off) & 0xfff))
-#define ARM_STRH_I(rt, rn, off)(ARM_INST_STRH_I | (rt) << 12 | (rn) << 
16 \
-| (((off) & 

[PATCH 00/14] ARM BPF jit compiler improvements

2018-07-11 Thread Russell King - ARM Linux
Hi,

This series improves the ARM BPF JIT compiler by:
- enumerating the stack layout rather than using constants that happen
  to be multiples of four
- rejig the BPF "register" accesses to use negative numbers instead of
  positive, which could be confused with register numbers in the bpf2a32
  array.
- since we maintain the ARM FP register as a pointer to the top of our
  scratch space (or, with frame pointers enabled, a valid ARM frame
  pointer register), we can access our scratch space using FP, which is
  constant across all BPF programs, including tail-called programs.
- use immediate forms of ARM instructions where possible, rather than
  first loading the immediate into an ARM register.
- use load-with-shift instruction rather than seperate shift instruction
  followed by load
- avoid reloading index and array in the tail-call code
- use double-word load/store instructions where available

Version 2:
- Fix ARMv5 test pointed out by Olof
- Fix build error found by 0-day (adding an additional patch)

 arch/arm/net/bpf_jit_32.c | 982 --
 arch/arm/net/bpf_jit_32.h |  42 +-
 2 files changed, 543 insertions(+), 481 deletions(-)

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


Re: [PATCH net-next 01/13] ARM: net: bpf: enumerate the JIT scratch stack layout

2018-07-10 Thread Russell King - ARM Linux
On Tue, Jul 10, 2018 at 08:30:04PM +0200, Daniel Borkmann wrote:
> Hi Russell,
> 
> thanks a lot for your work on the arm32 JIT!
> 
> On 07/10/2018 02:36 PM, Russell King wrote:
> > Enumerate the contents of the JIT scratch stack layout used for storing
> > some of the JITs 64-bit registers, tail call counter and AX register.
> > 
> > XXX: what about the skb_copy_bits buffer - this appears to overlap with
> > the first word of the JITs accessible stack.
> 
> Could you elaborate on that case? Unless I'm missing something there should
> be no use of the skb_copy_bits buffer anymore (aka former SKB_BUFFER at
> STACK_VAR(SCRATCH_SIZE) offset), but aside from that it's not supposed to
> overlap either.

Probably an old comment - these were originally developed back in
January timeframe when there was the SKB_BUFFER stuff, but that was
removed during the 4.18 merge window.  I'll kill the comment.

Thanks.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


Re: [PATCH net-next 13/13] ARM: net: bpf: use double-word load/stores where available

2018-07-10 Thread Russell King - ARM Linux
On Tue, Jul 10, 2018 at 10:03:33AM -0700, Olof Johansson wrote:
> Hi Russell,
> > @@ -663,13 +679,27 @@ static inline void emit_a32_mov_r(const s8 dst, const 
> > s8 src,
> >  static inline void emit_a32_mov_r64(const bool is64, const s8 dst[],
> >   const s8 src[],
> >   struct jit_ctx *ctx) {
> > -   emit_a32_mov_r(dst_lo, src_lo, ctx);
> > -   if (is64) {
> > +   if (!is64) {
> > +   emit_a32_mov_r(dst_lo, src_lo, ctx);
> > +   /* Zero out high 4 bytes */
> > +   emit_a32_mov_i(dst_hi, 0, ctx);
> > +   } else if (__LINUX_ARM_ARCH__ < 6 &&
> > +  ctx->cpu_architecture < CPU_ARCH_ARMv5) {
> > /* complete 8 byte move */
> > +   emit_a32_mov_r(dst_lo, src_lo, ctx);
> > emit_a32_mov_r(dst_hi, src_hi, ctx);
> 
> 
> Tiny nit: Looks like you compare for >= ARMv5TE above and  I'm not aware of any vanilla v5 implementations (all I can find are
> v5TE or <=v4T), so it doesn't seem like something actually causing
> problems. Mostly pointing it out for consistency's sake.

They're rare - I think the only one is an ARM1020 (ARMv5T) as opposed
to the ARM1020E (ARMv5TE).  Whether any are in the wild or not is
another matter.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


[PATCH net-next 11/13] ARM: net: bpf: avoid reloading 'array'

2018-07-10 Thread Russell King
Rearranging the order of the initial tail call code a little allows is
to avoid reloading the 'array' pointer.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 9 -
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 8264cac1322c..926e81c15505 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -1015,16 +1015,16 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
BUILD_BUG_ON(offsetof(struct bpf_array, map.max_entries) >
 ARM_INST_LDST__IMM12);
off = offsetof(struct bpf_array, map.max_entries);
-   /* array->map.max_entries */
-   r_array = arm_bpf_get_reg32(r2[1], tmp2[1], ctx);
-   emit(ARM_LDR_I(tmp[1], r_array, off), ctx);
+   r_array = arm_bpf_get_reg32(r2[1], tmp2[0], ctx);
/* index is 32-bit for arrays */
r_index = arm_bpf_get_reg32(r3[1], tmp2[1], ctx);
+   /* array->map.max_entries */
+   emit(ARM_LDR_I(tmp[1], r_array, off), ctx);
/* index >= array->map.max_entries */
emit(ARM_CMP_R(r_index, tmp[1]), ctx);
_emit(ARM_COND_CS, ARM_B(jmp_offset), ctx);
 
-   /* tmp2[1] = index */
+   /* tmp2[0] = array, tmp2[1] = index */
 
/* if (tail_call_cnt > MAX_TAIL_CALL_CNT)
 *  goto out;
@@ -1046,7 +1046,6 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
 */
BUILD_BUG_ON(offsetof(struct bpf_array, ptrs) > ARM_ALU_IMM);
off = offsetof(struct bpf_array, ptrs);
-   r_array = arm_bpf_get_reg32(r2[1], tmp2[0], ctx);
emit(ARM_ADD_I(tmp[1], r_array, off), ctx);
emit(ARM_LDR_R_SI(tmp[1], tmp[1], r_index, SRTYPE_ASL, 2), ctx);
emit(ARM_CMP_I(tmp[1], 0), ctx);
-- 
2.7.4



[PATCH net-next 12/13] ARM: net: bpf: always use odd/even register pair

2018-07-10 Thread Russell King
Always use an odd/even register pair for our 64-bit registers, so that
we're able to use the double-word load/store instructions in the future.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 28 ++--
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 926e81c15505..ca6534cabfa9 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -47,27 +47,27 @@
  * The callee saved registers depends on whether frame pointers are enabled.
  * With frame pointers (to be compliant with the ABI):
  *
- *high
- * original ARM_SP => +--+ \
- *|pc| |
- * current ARM_FP =>  +--+ } callee saved registers
- *|r4-r8,r10,fp,ip,lr| |
- *+--+ /
- *low
+ *  high
+ * original ARM_SP => +--+ \
+ *|  pc  | |
+ * current ARM_FP =>  +--+ } callee saved registers
+ *|r4-r9,fp,ip,lr| |
+ *+--+ /
+ *  low
  *
  * Without frame pointers:
  *
- *high
- * original ARM_SP => +--+
- *| r4-r8,r10,fp,lr  | callee saved registers
- * current ARM_FP =>  +--+
- *low
+ *  high
+ * original ARM_SP => +--+
+ *|  r4-r9,fp,lr | callee saved registers
+ * current ARM_FP =>  +--+
+ *  low
  *
  * When popping registers off the stack at the end of a BPF function, we
  * reference them via the current ARM_FP register.
  */
 #define CALLEE_MASK(1 << ARM_R4 | 1 << ARM_R5 | 1 << ARM_R6 | \
-1 << ARM_R7 | 1 << ARM_R8 | 1 << ARM_R10 | \
+1 << ARM_R7 | 1 << ARM_R8 | 1 << ARM_R9 | \
 1 << ARM_FP)
 #define CALLEE_PUSH_MASK (CALLEE_MASK | 1 << ARM_LR)
 #define CALLEE_POP_MASK  (CALLEE_MASK | 1 << ARM_PC)
@@ -157,7 +157,7 @@ static const s8 bpf2a32[][2] = {
 * for constant blindings and others.
 */
[TMP_REG_1] = {ARM_R7, ARM_R6},
-   [TMP_REG_2] = {ARM_R10, ARM_R8},
+   [TMP_REG_2] = {ARM_R9, ARM_R8},
/* Tail call count. Stored on stack scratch space. */
[TCALL_CNT] = {STACK_OFFSET(BPF_TC_HI), STACK_OFFSET(BPF_TC_LO)},
/* temporary register for blinding constants.
-- 
2.7.4



[PATCH net-next 13/13] ARM: net: bpf: use double-word load/stores where available

2018-07-10 Thread Russell King
Use double-word load and stores where support for this instruction is
supported by the CPU architecture.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 55 ---
 arch/arm/net/bpf_jit_32.h |  2 ++
 2 files changed, 45 insertions(+), 12 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index ca6534cabfa9..7e1d1635c65b 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -22,6 +22,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "bpf_jit_32.h"
 
@@ -192,6 +193,7 @@ struct jit_ctx {
unsigned int idx;
unsigned int prologue_bytes;
unsigned int epilogue_offset;
+   unsigned int cpu_architecture;
u32 flags;
u32 *offsets;
u32 *target;
@@ -271,10 +273,12 @@ static u32 arm_bpf_ldst_imm8(u32 op, u8 rt, u8 rn, s16 
imm8)
 
 #define ARM_LDR_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_LDR_I, rt, rn, off)
 #define ARM_LDRB_I(rt, rn, off)arm_bpf_ldst_imm12(ARM_INST_LDRB_I, rt, 
rn, off)
+#define ARM_LDRD_I(rt, rn, off)arm_bpf_ldst_imm8(ARM_INST_LDRD_I, rt, 
rn, off)
 #define ARM_LDRH_I(rt, rn, off)arm_bpf_ldst_imm8(ARM_INST_LDRH_I, rt, 
rn, off)
 
 #define ARM_STR_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_STR_I, rt, rn, off)
 #define ARM_STRB_I(rt, rn, off)arm_bpf_ldst_imm12(ARM_INST_STRB_I, rt, 
rn, off)
+#define ARM_STRD_I(rt, rn, off)arm_bpf_ldst_imm8(ARM_INST_STRD_I, rt, 
rn, off)
 #define ARM_STRH_I(rt, rn, off)arm_bpf_ldst_imm8(ARM_INST_STRH_I, rt, 
rn, off)
 
 /*
@@ -485,10 +489,16 @@ static const s8 *arm_bpf_get_reg64(const s8 *reg, const 
s8 *tmp,
   struct jit_ctx *ctx)
 {
if (is_stacked(reg[1])) {
-   emit(ARM_LDR_I(tmp[1], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[1])),
-ctx);
-   emit(ARM_LDR_I(tmp[0], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[0])),
-ctx);
+   if (__LINUX_ARM_ARCH__ >= 6 ||
+   ctx->cpu_architecture >= CPU_ARCH_ARMv5TE) {
+   emit(ARM_LDRD_I(tmp[1], ARM_FP,
+   EBPF_SCRATCH_TO_ARM_FP(reg[1])), ctx);
+   } else {
+   emit(ARM_LDR_I(tmp[1], ARM_FP,
+  EBPF_SCRATCH_TO_ARM_FP(reg[1])), ctx);
+   emit(ARM_LDR_I(tmp[0], ARM_FP,
+  EBPF_SCRATCH_TO_ARM_FP(reg[0])), ctx);
+   }
reg = tmp;
}
return reg;
@@ -510,10 +520,16 @@ static void arm_bpf_put_reg64(const s8 *reg, const s8 
*src,
  struct jit_ctx *ctx)
 {
if (is_stacked(reg[1])) {
-   emit(ARM_STR_I(src[1], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[1])),
-ctx);
-   emit(ARM_STR_I(src[0], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[0])),
-ctx);
+   if (__LINUX_ARM_ARCH__ >= 6 ||
+   ctx->cpu_architecture >= CPU_ARCH_ARMv5TE) {
+   emit(ARM_STRD_I(src[1], ARM_FP,
+  EBPF_SCRATCH_TO_ARM_FP(reg[1])), ctx);
+   } else {
+   emit(ARM_STR_I(src[1], ARM_FP,
+  EBPF_SCRATCH_TO_ARM_FP(reg[1])), ctx);
+   emit(ARM_STR_I(src[0], ARM_FP,
+  EBPF_SCRATCH_TO_ARM_FP(reg[0])), ctx);
+   }
} else {
if (reg[1] != src[1])
emit(ARM_MOV_R(reg[1], src[1]), ctx);
@@ -663,13 +679,27 @@ static inline void emit_a32_mov_r(const s8 dst, const s8 
src,
 static inline void emit_a32_mov_r64(const bool is64, const s8 dst[],
  const s8 src[],
  struct jit_ctx *ctx) {
-   emit_a32_mov_r(dst_lo, src_lo, ctx);
-   if (is64) {
+   if (!is64) {
+   emit_a32_mov_r(dst_lo, src_lo, ctx);
+   /* Zero out high 4 bytes */
+   emit_a32_mov_i(dst_hi, 0, ctx);
+   } else if (__LINUX_ARM_ARCH__ < 6 &&
+  ctx->cpu_architecture < CPU_ARCH_ARMv5) {
/* complete 8 byte move */
+   emit_a32_mov_r(dst_lo, src_lo, ctx);
emit_a32_mov_r(dst_hi, src_hi, ctx);
+   } else if (is_stacked(src_lo) && is_stacked(dst_lo)) {
+   const u8 *tmp = bpf2a32[TMP_REG_1];
+
+   emit(ARM_LDRD_I(tmp[1], ARM_FP, 
EBPF_SCRATCH_TO_ARM_FP(src_lo)), ctx);
+   emit(ARM_STRD_I(tmp[1], ARM_FP, 
EBPF_SCRATCH_TO_ARM_FP(dst_lo)), ctx);
+   } else if (is_stacked(src_lo)) {
+   emit(ARM_LDRD_I(dst[1], ARM_FP, 
EBPF_SCRATCH_TO_ARM_FP(src_lo)), ctx);
+   } else if (is_stacked(dst_lo)) {
+   emit(ARM_STRD_I(src[1], ARM_FP, 

[PATCH net-next 08/13] ARM: net: bpf: use immediate forms of instructions where possible

2018-07-10 Thread Russell King
Rather than moving constants to a register and then using them in a
subsequent instruction, use them directly in the desired instruction
cutting out the "middle" register.  This removes two instructions from
the tail call code path.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 16 +---
 arch/arm/net/bpf_jit_32.h |  3 +++
 2 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 753b5b2b2e3d..c7591877c350 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -256,7 +256,7 @@ static u32 arm_bpf_ldst_imm12(u32 op, u8 rt, u8 rn, s16 
imm12)
op |= ARM_INST_LDST__U;
else
imm12 = -imm12;
-   return op | (imm12 & 0xfff);
+   return op | (imm12 & ARM_INST_LDST__IMM12);
 }
 
 static u32 arm_bpf_ldst_imm8(u32 op, u8 rt, u8 rn, s16 imm8)
@@ -1012,11 +1012,12 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
/* if (index >= array->map.max_entries)
 *  goto out;
 */
+   BUILD_BUG_ON(offsetof(struct bpf_array, map.max_entries) >
+ARM_INST_LDST__IMM12);
off = offsetof(struct bpf_array, map.max_entries);
/* array->map.max_entries */
-   emit_a32_mov_i(tmp[1], off, ctx);
r_array = arm_bpf_get_reg32(r2[1], tmp2[1], ctx);
-   emit(ARM_LDR_R(tmp[1], r_array, tmp[1]), ctx);
+   emit(ARM_LDR_I(tmp[1], r_array, off), ctx);
/* index is 32-bit for arrays */
r_index = arm_bpf_get_reg32(r3[1], tmp2[1], ctx);
/* index >= array->map.max_entries */
@@ -1041,10 +1042,10 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
 * if (prog == NULL)
 *  goto out;
 */
+   BUILD_BUG_ON(offsetof(struct bpf_array, ptrs) > ARM_ALU_IMM);
off = offsetof(struct bpf_array, ptrs);
-   emit_a32_mov_i(tmp[1], off, ctx);
r_array = arm_bpf_get_reg32(r2[1], tmp2[1], ctx);
-   emit(ARM_ADD_R(tmp[1], r_array, tmp[1]), ctx);
+   emit(ARM_ADD_I(tmp[1], r_array, off), ctx);
r_index = arm_bpf_get_reg32(r3[1], tmp2[1], ctx);
emit(ARM_MOV_SI(tmp[0], r_index, SRTYPE_ASL, 2), ctx);
emit(ARM_LDR_R(tmp[1], tmp[1], tmp[0]), ctx);
@@ -1052,9 +1053,10 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
_emit(ARM_COND_EQ, ARM_B(jmp_offset), ctx);
 
/* goto *(prog->bpf_func + prologue_size); */
+   BUILD_BUG_ON(offsetof(struct bpf_prog, bpf_func) >
+ARM_INST_LDST__IMM12);
off = offsetof(struct bpf_prog, bpf_func);
-   emit_a32_mov_i(tmp2[1], off, ctx);
-   emit(ARM_LDR_R(tmp[1], tmp[1], tmp2[1]), ctx);
+   emit(ARM_LDR_I(tmp[1], tmp[1], off), ctx);
emit(ARM_ADD_I(tmp[1], tmp[1], ctx->prologue_bytes), ctx);
emit_bx_r(tmp[1], ctx);
 
diff --git a/arch/arm/net/bpf_jit_32.h b/arch/arm/net/bpf_jit_32.h
index c55bc39d3e22..ca9f1f5589f4 100644
--- a/arch/arm/net/bpf_jit_32.h
+++ b/arch/arm/net/bpf_jit_32.h
@@ -78,6 +78,7 @@
 #define ARM_INST_EOR_I 0x0220
 
 #define ARM_INST_LDST__U   0x0080
+#define ARM_INST_LDST__IMM12   0x0fff
 #define ARM_INST_LDRB_I0x0550
 #define ARM_INST_LDRB_R0x07d0
 #define ARM_INST_LDRH_I0x015000b0
@@ -154,6 +155,8 @@
  */
 #define ARM_INST_UDF   0xe7fddef1
 
+#define ARM_ALU_IMM0xff
+
 /* register */
 #define _AL3_R(op, rd, rn, rm) ((op ## _R) | (rd) << 12 | (rn) << 16 | (rm))
 /* immediate */
-- 
2.7.4



[PATCH net-next 10/13] ARM: net: bpf: avoid reloading 'index'

2018-07-10 Thread Russell King
Avoid reloading 'index' after we have validated it - it remains in
tmp2[1] up to the point that we begin the code to index the pointer
array, so with a little rearrangement of the registers, we can use
the already loaded value.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index a375eb33ac69..8264cac1322c 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -1024,6 +1024,8 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
emit(ARM_CMP_R(r_index, tmp[1]), ctx);
_emit(ARM_COND_CS, ARM_B(jmp_offset), ctx);
 
+   /* tmp2[1] = index */
+
/* if (tail_call_cnt > MAX_TAIL_CALL_CNT)
 *  goto out;
 * tail_call_cnt++;
@@ -1044,9 +1046,8 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
 */
BUILD_BUG_ON(offsetof(struct bpf_array, ptrs) > ARM_ALU_IMM);
off = offsetof(struct bpf_array, ptrs);
-   r_array = arm_bpf_get_reg32(r2[1], tmp2[1], ctx);
+   r_array = arm_bpf_get_reg32(r2[1], tmp2[0], ctx);
emit(ARM_ADD_I(tmp[1], r_array, off), ctx);
-   r_index = arm_bpf_get_reg32(r3[1], tmp2[1], ctx);
emit(ARM_LDR_R_SI(tmp[1], tmp[1], r_index, SRTYPE_ASL, 2), ctx);
emit(ARM_CMP_I(tmp[1], 0), ctx);
_emit(ARM_COND_EQ, ARM_B(jmp_offset), ctx);
-- 
2.7.4



[PATCH net-next 07/13] ARM: net: bpf: access eBPF scratch space using ARM FP register

2018-07-10 Thread Russell King
Access the eBPF scratch space using the frame pointer rather than our
stack pointer, as the offsets from the ARM frame pointer are constant
across all eBPF programs.

Since we no longer reference the scratch space registers from the stack
pointer, this simplifies emit_push_r64() as it no longer needs to know
how many words are pushed onto the stack.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 44 +---
 1 file changed, 25 insertions(+), 19 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 45a3599e94a4..753b5b2b2e3d 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -108,6 +108,12 @@ enum {
 #define STACK_OFFSET(k)(-4 - (k) * 4)
 #define SCRATCH_SIZE   (BPF_JIT_SCRATCH_REGS * 4)
 
+#ifdef CONFIG_FRAME_POINTER
+#define EBPF_SCRATCH_TO_ARM_FP(x) ((x) - 4 * hweight16(CALLEE_PUSH_MASK) - 4)
+#else
+#define EBPF_SCRATCH_TO_ARM_FP(x) (x)
+#endif
+
 #define TMP_REG_1  (MAX_BPF_JIT_REG + 0)   /* TEMP Register 1 */
 #define TMP_REG_2  (MAX_BPF_JIT_REG + 1)   /* TEMP Register 2 */
 #define TCALL_CNT  (MAX_BPF_JIT_REG + 2)   /* Tail Call Count */
@@ -294,9 +300,6 @@ static void jit_fill_hole(void *area, unsigned int size)
 #define _STACK_SIZE(ctx->prog->aux->stack_depth + SCRATCH_SIZE)
 #define STACK_SIZE ALIGN(_STACK_SIZE, STACK_ALIGNMENT)
 
-/* Get the offset of eBPF REGISTERs stored on scratch space. */
-#define STACK_VAR(off) (STACK_SIZE + (off))
-
 #if __LINUX_ARM_ARCH__ < 7
 
 static u16 imm_offset(u32 k, struct jit_ctx *ctx)
@@ -472,7 +475,7 @@ static bool is_stacked(s8 reg)
 static s8 arm_bpf_get_reg32(s8 reg, s8 tmp, struct jit_ctx *ctx)
 {
if (is_stacked(reg)) {
-   emit(ARM_LDR_I(tmp, ARM_SP, STACK_VAR(reg)), ctx);
+   emit(ARM_LDR_I(tmp, ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg)), ctx);
reg = tmp;
}
return reg;
@@ -482,8 +485,10 @@ static const s8 *arm_bpf_get_reg64(const s8 *reg, const s8 
*tmp,
   struct jit_ctx *ctx)
 {
if (is_stacked(reg[1])) {
-   emit(ARM_LDR_I(tmp[1], ARM_SP, STACK_VAR(reg[1])), ctx);
-   emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(reg[0])), ctx);
+   emit(ARM_LDR_I(tmp[1], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[1])),
+ctx);
+   emit(ARM_LDR_I(tmp[0], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[0])),
+ctx);
reg = tmp;
}
return reg;
@@ -496,7 +501,7 @@ static const s8 *arm_bpf_get_reg64(const s8 *reg, const s8 
*tmp,
 static void arm_bpf_put_reg32(s8 reg, s8 src, struct jit_ctx *ctx)
 {
if (is_stacked(reg))
-   emit(ARM_STR_I(src, ARM_SP, STACK_VAR(reg)), ctx);
+   emit(ARM_STR_I(src, ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg)), ctx);
else if (reg != src)
emit(ARM_MOV_R(reg, src), ctx);
 }
@@ -505,8 +510,10 @@ static void arm_bpf_put_reg64(const s8 *reg, const s8 *src,
  struct jit_ctx *ctx)
 {
if (is_stacked(reg[1])) {
-   emit(ARM_STR_I(src[1], ARM_SP, STACK_VAR(reg[1])), ctx);
-   emit(ARM_STR_I(src[0], ARM_SP, STACK_VAR(reg[0])), ctx);
+   emit(ARM_STR_I(src[1], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[1])),
+ctx);
+   emit(ARM_STR_I(src[0], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg[0])),
+ctx);
} else {
if (reg[1] != src[1])
emit(ARM_MOV_R(reg[1], src[1]), ctx);
@@ -1103,16 +1110,15 @@ static inline void emit_rev32(const u8 rd, const u8 rn, 
struct jit_ctx *ctx)
 }
 
 // push the scratch stack register on top of the stack
-static inline void emit_push_r64(const s8 src[], const u8 shift,
-   struct jit_ctx *ctx)
+static inline void emit_push_r64(const s8 src[], struct jit_ctx *ctx)
 {
const s8 *tmp2 = bpf2a32[TMP_REG_2];
+   const s8 *rt;
u16 reg_set = 0;
 
-   emit(ARM_LDR_I(tmp2[1], ARM_SP, STACK_VAR(src[1]+shift)), ctx);
-   emit(ARM_LDR_I(tmp2[0], ARM_SP, STACK_VAR(src[0]+shift)), ctx);
+   rt = arm_bpf_get_reg64(src, tmp2, ctx);
 
-   reg_set = (1 << tmp2[1]) | (1 << tmp2[0]);
+   reg_set = (1 << rt[1]) | (1 << rt[0]);
emit(ARM_PUSH(reg_set), ctx);
 }
 
@@ -1155,8 +1161,8 @@ static void build_prologue(struct jit_ctx *ctx)
emit(ARM_MOV_R(r3, r4), ctx);
emit(ARM_MOV_R(r2, r0), ctx);
/* Initialize Tail Count */
-   emit(ARM_STR_I(r4, ARM_SP, STACK_VAR(tcc[0])), ctx);
-   emit(ARM_STR_I(r4, ARM_SP, STACK_VAR(tcc[1])), ctx);
+   emit(ARM_STR_I(r4, ARM_FP, EBPF_SCRATCH_TO_ARM_FP(tcc[0])), ctx);
+   emit(ARM_STR_I(r4, ARM_FP, EBPF_SCRATCH_TO_ARM_FP(tcc[1])), ctx);
/* end of prologue */
 }
 
@@ -1606,9 +1612,9 @@ static int build_insn(const struct bpf_insn *insn, struct 
jit_ctx *ctx)
 
 

[PATCH net-next 01/13] ARM: net: bpf: enumerate the JIT scratch stack layout

2018-07-10 Thread Russell King
Enumerate the contents of the JIT scratch stack layout used for storing
some of the JITs 64-bit registers, tail call counter and AX register.

XXX: what about the skb_copy_bits buffer - this appears to overlap with
the first word of the JITs accessible stack.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 59 +--
 1 file changed, 42 insertions(+), 17 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index f6a62ae44a65..f2e6ffe57788 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -72,7 +72,38 @@
 #define CALLEE_PUSH_MASK (CALLEE_MASK | 1 << ARM_LR)
 #define CALLEE_POP_MASK  (CALLEE_MASK | 1 << ARM_PC)
 
-#define STACK_OFFSET(k)(k)
+enum {
+   /* Stack layout - these are offsets from (top of stack - 4) */
+   BPF_R2_HI,
+   BPF_R2_LO,
+   BPF_R3_HI,
+   BPF_R3_LO,
+   BPF_R4_HI,
+   BPF_R4_LO,
+   BPF_R5_HI,
+   BPF_R5_LO,
+   BPF_R7_HI,
+   BPF_R7_LO,
+   BPF_R8_HI,
+   BPF_R8_LO,
+   BPF_R9_HI,
+   BPF_R9_LO,
+   BPF_FP_HI,
+   BPF_FP_LO,
+   BPF_TC_HI,
+   BPF_TC_LO,
+   BPF_AX_HI,
+   BPF_AX_LO,
+   /* Stack space for BPF_REG_2, BPF_REG_3, BPF_REG_4,
+* BPF_REG_5, BPF_REG_7, BPF_REG_8, BPF_REG_9,
+* BPF_REG_FP and Tail call counts.
+*/
+   BPF_JIT_SCRATCH_REGS,
+};
+
+#define STACK_OFFSET(k)((k) * 4)
+#define SCRATCH_SIZE   (BPF_JIT_SCRATCH_REGS * 4)
+
 #define TMP_REG_1  (MAX_BPF_JIT_REG + 0)   /* TEMP Register 1 */
 #define TMP_REG_2  (MAX_BPF_JIT_REG + 1)   /* TEMP Register 2 */
 #define TCALL_CNT  (MAX_BPF_JIT_REG + 2)   /* Tail Call Count */
@@ -100,29 +131,29 @@ static const u8 bpf2a32[][2] = {
/* arguments from eBPF program to in-kernel function */
[BPF_REG_1] = {ARM_R3, ARM_R2},
/* Stored on stack scratch space */
-   [BPF_REG_2] = {STACK_OFFSET(0), STACK_OFFSET(4)},
-   [BPF_REG_3] = {STACK_OFFSET(8), STACK_OFFSET(12)},
-   [BPF_REG_4] = {STACK_OFFSET(16), STACK_OFFSET(20)},
-   [BPF_REG_5] = {STACK_OFFSET(24), STACK_OFFSET(28)},
+   [BPF_REG_2] = {STACK_OFFSET(BPF_R2_HI), STACK_OFFSET(BPF_R2_LO)},
+   [BPF_REG_3] = {STACK_OFFSET(BPF_R3_HI), STACK_OFFSET(BPF_R3_LO)},
+   [BPF_REG_4] = {STACK_OFFSET(BPF_R4_HI), STACK_OFFSET(BPF_R4_LO)},
+   [BPF_REG_5] = {STACK_OFFSET(BPF_R5_HI), STACK_OFFSET(BPF_R5_LO)},
/* callee saved registers that in-kernel function will preserve */
[BPF_REG_6] = {ARM_R5, ARM_R4},
/* Stored on stack scratch space */
-   [BPF_REG_7] = {STACK_OFFSET(32), STACK_OFFSET(36)},
-   [BPF_REG_8] = {STACK_OFFSET(40), STACK_OFFSET(44)},
-   [BPF_REG_9] = {STACK_OFFSET(48), STACK_OFFSET(52)},
+   [BPF_REG_7] = {STACK_OFFSET(BPF_R7_HI), STACK_OFFSET(BPF_R7_LO)},
+   [BPF_REG_8] = {STACK_OFFSET(BPF_R8_HI), STACK_OFFSET(BPF_R8_LO)},
+   [BPF_REG_9] = {STACK_OFFSET(BPF_R9_HI), STACK_OFFSET(BPF_R9_LO)},
/* Read only Frame Pointer to access Stack */
-   [BPF_REG_FP] = {STACK_OFFSET(56), STACK_OFFSET(60)},
+   [BPF_REG_FP] = {STACK_OFFSET(BPF_FP_HI), STACK_OFFSET(BPF_FP_LO)},
/* Temporary Register for internal BPF JIT, can be used
 * for constant blindings and others.
 */
[TMP_REG_1] = {ARM_R7, ARM_R6},
[TMP_REG_2] = {ARM_R10, ARM_R8},
/* Tail call count. Stored on stack scratch space. */
-   [TCALL_CNT] = {STACK_OFFSET(64), STACK_OFFSET(68)},
+   [TCALL_CNT] = {STACK_OFFSET(BPF_TC_HI), STACK_OFFSET(BPF_TC_LO)},
/* temporary register for blinding constants.
 * Stored on stack scratch space.
 */
-   [BPF_REG_AX] = {STACK_OFFSET(72), STACK_OFFSET(76)},
+   [BPF_REG_AX] = {STACK_OFFSET(BPF_AX_HI), STACK_OFFSET(BPF_AX_LO)},
 };
 
 #definedst_lo  dst[1]
@@ -227,12 +258,6 @@ static void jit_fill_hole(void *area, unsigned int size)
 #define STACK_ALIGNMENT4
 #endif
 
-/* Stack space for BPF_REG_2, BPF_REG_3, BPF_REG_4,
- * BPF_REG_5, BPF_REG_7, BPF_REG_8, BPF_REG_9,
- * BPF_REG_FP and Tail call counts.
- */
-#define SCRATCH_SIZE 80
-
 /* total stack size used in JITed code */
 #define _STACK_SIZE(ctx->prog->aux->stack_depth + SCRATCH_SIZE)
 #define STACK_SIZE ALIGN(_STACK_SIZE, STACK_ALIGNMENT)
-- 
2.7.4



[PATCH net-next 06/13] ARM: net: bpf: 64-bit accessor functions for BPF registers

2018-07-10 Thread Russell King
Provide a couple of 64-bit register accessors, and use them where
appropriate

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 235 --
 1 file changed, 122 insertions(+), 113 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 08fb4eb285a2..45a3599e94a4 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -478,6 +478,17 @@ static s8 arm_bpf_get_reg32(s8 reg, s8 tmp, struct jit_ctx 
*ctx)
return reg;
 }
 
+static const s8 *arm_bpf_get_reg64(const s8 *reg, const s8 *tmp,
+  struct jit_ctx *ctx)
+{
+   if (is_stacked(reg[1])) {
+   emit(ARM_LDR_I(tmp[1], ARM_SP, STACK_VAR(reg[1])), ctx);
+   emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(reg[0])), ctx);
+   reg = tmp;
+   }
+   return reg;
+}
+
 /* If a BPF register is on the stack (stk is true), save the register
  * back to the stack.  If the source register is not the same, then
  * move it into the correct register.
@@ -490,6 +501,20 @@ static void arm_bpf_put_reg32(s8 reg, s8 src, struct 
jit_ctx *ctx)
emit(ARM_MOV_R(reg, src), ctx);
 }
 
+static void arm_bpf_put_reg64(const s8 *reg, const s8 *src,
+ struct jit_ctx *ctx)
+{
+   if (is_stacked(reg[1])) {
+   emit(ARM_STR_I(src[1], ARM_SP, STACK_VAR(reg[1])), ctx);
+   emit(ARM_STR_I(src[0], ARM_SP, STACK_VAR(reg[0])), ctx);
+   } else {
+   if (reg[1] != src[1])
+   emit(ARM_MOV_R(reg[1], src[1]), ctx);
+   if (reg[0] != src[0])
+   emit(ARM_MOV_R(reg[0], src[0]), ctx);
+   }
+}
+
 static inline void emit_a32_mov_i(const s8 dst, const u32 val,
  struct jit_ctx *ctx)
 {
@@ -669,18 +694,16 @@ static inline void emit_a32_alu_i(const s8 dst, const u32 
val,
 static inline void emit_a32_neg64(const s8 dst[],
struct jit_ctx *ctx){
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rd, rm;
+   const s8 *rd;
 
/* Setup Operand */
-   rd = arm_bpf_get_reg32(dst_lo, tmp[1], ctx);
-   rm = arm_bpf_get_reg32(dst_hi, tmp[0], ctx);
+   rd = arm_bpf_get_reg64(dst, tmp, ctx);
 
/* Do Negate Operation */
-   emit(ARM_RSBS_I(rd, rd, 0), ctx);
-   emit(ARM_RSC_I(rm, rm, 0), ctx);
+   emit(ARM_RSBS_I(rd[1], rd[1], 0), ctx);
+   emit(ARM_RSC_I(rd[0], rd[0], 0), ctx);
 
-   arm_bpf_put_reg32(dst_lo, rd, ctx);
-   arm_bpf_put_reg32(dst_hi, rm, ctx);
+   arm_bpf_put_reg64(dst, rd, ctx);
 }
 
 /* dst = dst << src */
@@ -688,20 +711,20 @@ static inline void emit_a32_lsh_r64(const s8 dst[], const 
s8 src[],
struct jit_ctx *ctx) {
const s8 *tmp = bpf2a32[TMP_REG_1];
const s8 *tmp2 = bpf2a32[TMP_REG_2];
-   s8 rt, rd, rm;
+   const s8 *rd;
+   s8 rt;
 
/* Setup Operands */
rt = arm_bpf_get_reg32(src_lo, tmp2[1], ctx);
-   rd = arm_bpf_get_reg32(dst_lo, tmp[1], ctx);
-   rm = arm_bpf_get_reg32(dst_hi, tmp[0], ctx);
+   rd = arm_bpf_get_reg64(dst, tmp, ctx);
 
/* Do LSH operation */
emit(ARM_SUB_I(ARM_IP, rt, 32), ctx);
emit(ARM_RSB_I(tmp2[0], rt, 32), ctx);
-   emit(ARM_MOV_SR(ARM_LR, rm, SRTYPE_ASL, rt), ctx);
-   emit(ARM_ORR_SR(ARM_LR, ARM_LR, rd, SRTYPE_ASL, ARM_IP), ctx);
-   emit(ARM_ORR_SR(ARM_IP, ARM_LR, rd, SRTYPE_LSR, tmp2[0]), ctx);
-   emit(ARM_MOV_SR(ARM_LR, rd, SRTYPE_ASL, rt), ctx);
+   emit(ARM_MOV_SR(ARM_LR, rd[0], SRTYPE_ASL, rt), ctx);
+   emit(ARM_ORR_SR(ARM_LR, ARM_LR, rd[1], SRTYPE_ASL, ARM_IP), ctx);
+   emit(ARM_ORR_SR(ARM_IP, ARM_LR, rd[1], SRTYPE_LSR, tmp2[0]), ctx);
+   emit(ARM_MOV_SR(ARM_LR, rd[1], SRTYPE_ASL, rt), ctx);
 
arm_bpf_put_reg32(dst_lo, ARM_LR, ctx);
arm_bpf_put_reg32(dst_hi, ARM_IP, ctx);
@@ -712,21 +735,21 @@ static inline void emit_a32_arsh_r64(const s8 dst[], 
const s8 src[],
 struct jit_ctx *ctx) {
const s8 *tmp = bpf2a32[TMP_REG_1];
const s8 *tmp2 = bpf2a32[TMP_REG_2];
-   s8 rt, rd, rm;
+   const s8 *rd;
+   s8 rt;
 
/* Setup Operands */
rt = arm_bpf_get_reg32(src_lo, tmp2[1], ctx);
-   rd = arm_bpf_get_reg32(dst_lo, tmp[1], ctx);
-   rm = arm_bpf_get_reg32(dst_hi, tmp[0], ctx);
+   rd = arm_bpf_get_reg64(dst, tmp, ctx);
 
/* Do the ARSH operation */
emit(ARM_RSB_I(ARM_IP, rt, 32), ctx);
emit(ARM_SUBS_I(tmp2[0], rt, 32), ctx);
-   emit(ARM_MOV_SR(ARM_LR, rd, SRTYPE_LSR, rt), ctx);
-   emit(ARM_ORR_SR(ARM_LR, ARM_LR, rm, SRTYPE_ASL, ARM_IP), ctx);
+   emit(ARM_MOV_SR(ARM_LR, rd[1], SRTYPE_LSR, rt), ctx);
+   emit(ARM_ORR_SR(ARM_LR, ARM_LR, rd[0], SRTYPE_ASL, ARM_IP), ctx);
_emit(ARM_COND_MI, ARM_B(0), ctx);
-   emit(ARM_

[PATCH net-next 09/13] ARM: net: bpf: use ldr instructions with shifted rm register

2018-07-10 Thread Russell King
Rather than pre-shifting the rm register for the ldr in the tail call,
shift it in the load instruction.  This eliminates one unnecessary
instruction.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 3 +--
 arch/arm/net/bpf_jit_32.h | 4 
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index c7591877c350..a375eb33ac69 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -1047,8 +1047,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
r_array = arm_bpf_get_reg32(r2[1], tmp2[1], ctx);
emit(ARM_ADD_I(tmp[1], r_array, off), ctx);
r_index = arm_bpf_get_reg32(r3[1], tmp2[1], ctx);
-   emit(ARM_MOV_SI(tmp[0], r_index, SRTYPE_ASL, 2), ctx);
-   emit(ARM_LDR_R(tmp[1], tmp[1], tmp[0]), ctx);
+   emit(ARM_LDR_R_SI(tmp[1], tmp[1], r_index, SRTYPE_ASL, 2), ctx);
emit(ARM_CMP_I(tmp[1], 0), ctx);
_emit(ARM_COND_EQ, ARM_B(jmp_offset), ctx);
 
diff --git a/arch/arm/net/bpf_jit_32.h b/arch/arm/net/bpf_jit_32.h
index ca9f1f5589f4..9d605e7a8309 100644
--- a/arch/arm/net/bpf_jit_32.h
+++ b/arch/arm/net/bpf_jit_32.h
@@ -190,6 +190,10 @@
 #define ARM_LDR_R(rt, rn, rm)  (ARM_INST_LDR_R | ARM_INST_LDST__U \
 | (rt) << 12 | (rn) << 16 \
 | (rm))
+#define ARM_LDR_R_SI(rt, rn, rm, type, imm) \
+   (ARM_INST_LDR_R | ARM_INST_LDST__U \
+| (rt) << 12 | (rn) << 16 \
+| (imm) << 7 | (type) << 5 | (rm))
 #define ARM_LDRB_R(rt, rn, rm) (ARM_INST_LDRB_R | ARM_INST_LDST__U \
 | (rt) << 12 | (rn) << 16 \
 | (rm))
-- 
2.7.4



[PATCH net-next 02/13] ARM: net: bpf: provide load/store ops with negative immediates

2018-07-10 Thread Russell King
Provide a set of load/store opcode generators that work with negative
immediates as well as positive ones.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 28 
 arch/arm/net/bpf_jit_32.h | 35 +--
 2 files changed, 41 insertions(+), 22 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index f2e6ffe57788..c81da1a50834 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -239,6 +239,34 @@ static int16_t imm8m(u32 x)
return -1;
 }
 
+static u32 arm_bpf_ldst_imm12(u32 op, u8 rt, u8 rn, s16 imm12)
+{
+   op |= rt << 12 | rn << 16;
+   if (imm12 >= 0)
+   op |= ARM_INST_LDST__U;
+   else
+   imm12 = -imm12;
+   return op | (imm12 & 0xfff);
+}
+
+static u32 arm_bpf_ldst_imm8(u32 op, u8 rt, u8 rn, s16 imm8)
+{
+   op |= rt << 12 | rn << 16;
+   if (imm8 >= 0)
+   op |= ARM_INST_LDST__U;
+   else
+   imm8 = -imm8;
+   return op | (imm8 & 0xf0) << 4 | (imm8 & 0x0f);
+}
+
+#define ARM_LDR_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_LDR_I, rt, rn, off)
+#define ARM_LDRB_I(rt, rn, off)arm_bpf_ldst_imm12(ARM_INST_LDRB_I, rt, 
rn, off)
+#define ARM_LDRH_I(rt, rn, off)arm_bpf_ldst_imm8(ARM_INST_LDRH_I, rt, 
rn, off)
+
+#define ARM_STR_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_STR_I, rt, rn, off)
+#define ARM_STRB_I(rt, rn, off)arm_bpf_ldst_imm12(ARM_INST_STRB_I, rt, 
rn, off)
+#define ARM_STRH_I(rt, rn, off)arm_bpf_ldst_imm8(ARM_INST_STRH_I, rt, 
rn, off)
+
 /*
  * Initializes the JIT space with undefined instructions.
  */
diff --git a/arch/arm/net/bpf_jit_32.h b/arch/arm/net/bpf_jit_32.h
index d5cf5f6208aa..c55bc39d3e22 100644
--- a/arch/arm/net/bpf_jit_32.h
+++ b/arch/arm/net/bpf_jit_32.h
@@ -77,11 +77,12 @@
 #define ARM_INST_EOR_R 0x0020
 #define ARM_INST_EOR_I 0x0220
 
-#define ARM_INST_LDRB_I0x05d0
+#define ARM_INST_LDST__U   0x0080
+#define ARM_INST_LDRB_I0x0550
 #define ARM_INST_LDRB_R0x07d0
-#define ARM_INST_LDRH_I0x01d000b0
+#define ARM_INST_LDRH_I0x015000b0
 #define ARM_INST_LDRH_R0x019000b0
-#define ARM_INST_LDR_I 0x0590
+#define ARM_INST_LDR_I 0x0510
 #define ARM_INST_LDR_R 0x0790
 
 #define ARM_INST_LDM   0x0890
@@ -124,9 +125,9 @@
 #define ARM_INST_SBC_R 0x00c0
 #define ARM_INST_SBCS_R0x00d0
 
-#define ARM_INST_STR_I 0x0580
-#define ARM_INST_STRB_I0x05c0
-#define ARM_INST_STRH_I0x01c000b0
+#define ARM_INST_STR_I 0x0500
+#define ARM_INST_STRB_I0x0540
+#define ARM_INST_STRH_I0x014000b0
 
 #define ARM_INST_TST_R 0x0110
 #define ARM_INST_TST_I 0x0310
@@ -183,17 +184,14 @@
 #define ARM_EOR_R(rd, rn, rm)  _AL3_R(ARM_INST_EOR, rd, rn, rm)
 #define ARM_EOR_I(rd, rn, imm) _AL3_I(ARM_INST_EOR, rd, rn, imm)
 
-#define ARM_LDR_I(rt, rn, off) (ARM_INST_LDR_I | (rt) << 12 | (rn) << 16 \
-| ((off) & 0xfff))
-#define ARM_LDR_R(rt, rn, rm)  (ARM_INST_LDR_R | (rt) << 12 | (rn) << 16 \
+#define ARM_LDR_R(rt, rn, rm)  (ARM_INST_LDR_R | ARM_INST_LDST__U \
+| (rt) << 12 | (rn) << 16 \
 | (rm))
-#define ARM_LDRB_I(rt, rn, off)(ARM_INST_LDRB_I | (rt) << 12 | (rn) << 
16 \
-| (off))
-#define ARM_LDRB_R(rt, rn, rm) (ARM_INST_LDRB_R | (rt) << 12 | (rn) << 16 \
+#define ARM_LDRB_R(rt, rn, rm) (ARM_INST_LDRB_R | ARM_INST_LDST__U \
+| (rt) << 12 | (rn) << 16 \
 | (rm))
-#define ARM_LDRH_I(rt, rn, off)(ARM_INST_LDRH_I | (rt) << 12 | (rn) << 
16 \
-| (((off) & 0xf0) << 4) | ((off) & 0xf))
-#define ARM_LDRH_R(rt, rn, rm) (ARM_INST_LDRH_R | (rt) << 12 | (rn) << 16 \
+#define ARM_LDRH_R(rt, rn, rm) (ARM_INST_LDRH_R | ARM_INST_LDST__U \
+| (rt) << 12 | (rn) << 16 \
 | (rm))
 
 #define ARM_LDM(rn, regs)  (ARM_INST_LDM | (rn) << 16 | (regs))
@@ -254,13 +252,6 @@
 #define ARM_SUBS_I(rd, rn, imm)_AL3_I(ARM_INST_SUBS, rd, rn, imm)
 #define ARM_SBC_I(rd, rn, imm) _AL3_I(ARM_INST_SBC, rd, rn, imm)
 
-#define ARM_STR_I(rt, rn, off) (ARM_INST_STR_I | (rt) << 12 | (rn) << 16 \
-| ((off) & 0xfff))
-#define ARM_STRH_I(rt, rn, off)(ARM_INST_STRH_I | (rt) << 12 | (rn) << 
16 \
-| (((off) & 

[PATCH net-next 05/13] ARM: net: bpf: provide accessor functions for BPF registers

2018-07-10 Thread Russell King
Many of the code paths need to have knowledge about whether a register
is stacked or in a CPU register.  Move this decision making to a pair
of helper functions instead of having it scattered throughout the
code.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 329 ++
 1 file changed, 128 insertions(+), 201 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index e81401aca2df..08fb4eb285a2 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -465,6 +465,31 @@ static bool is_stacked(s8 reg)
return reg < 0;
 }
 
+/* If a BPF register is on the stack (stk is true), load it to the
+ * supplied temporary register and return the temporary register
+ * for subsequent operations, otherwise just use the CPU register.
+ */
+static s8 arm_bpf_get_reg32(s8 reg, s8 tmp, struct jit_ctx *ctx)
+{
+   if (is_stacked(reg)) {
+   emit(ARM_LDR_I(tmp, ARM_SP, STACK_VAR(reg)), ctx);
+   reg = tmp;
+   }
+   return reg;
+}
+
+/* If a BPF register is on the stack (stk is true), save the register
+ * back to the stack.  If the source register is not the same, then
+ * move it into the correct register.
+ */
+static void arm_bpf_put_reg32(s8 reg, s8 src, struct jit_ctx *ctx)
+{
+   if (is_stacked(reg))
+   emit(ARM_STR_I(src, ARM_SP, STACK_VAR(reg)), ctx);
+   else if (reg != src)
+   emit(ARM_MOV_R(reg, src), ctx);
+}
+
 static inline void emit_a32_mov_i(const s8 dst, const u32 val,
  struct jit_ctx *ctx)
 {
@@ -472,7 +497,7 @@ static inline void emit_a32_mov_i(const s8 dst, const u32 
val,
 
if (is_stacked(dst)) {
emit_mov_i(tmp[1], val, ctx);
-   emit(ARM_STR_I(tmp[1], ARM_SP, STACK_VAR(dst)), ctx);
+   arm_bpf_put_reg32(dst, tmp[1], ctx);
} else {
emit_mov_i(dst, val, ctx);
}
@@ -572,19 +597,13 @@ static inline void emit_a32_alu_r(const s8 dst, const s8 
src,
  struct jit_ctx *ctx, const bool is64,
  const bool hi, const u8 op) {
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rn = is_stacked(src) ? tmp[1] : src;
-
-   if (is_stacked(src))
-   emit(ARM_LDR_I(rn, ARM_SP, STACK_VAR(src)), ctx);
+   s8 rn, rd;
 
+   rn = arm_bpf_get_reg32(src, tmp[1], ctx);
+   rd = arm_bpf_get_reg32(dst, tmp[0], ctx);
/* ALU operation */
-   if (is_stacked(dst)) {
-   emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(dst)), ctx);
-   emit_alu_r(tmp[0], rn, is64, hi, op, ctx);
-   emit(ARM_STR_I(tmp[0], ARM_SP, STACK_VAR(dst)), ctx);
-   } else {
-   emit_alu_r(dst, rn, is64, hi, op, ctx);
-   }
+   emit_alu_r(rd, rn, is64, hi, op, ctx);
+   arm_bpf_put_reg32(dst, rd, ctx);
 }
 
 /* ALU operation (64 bit) */
@@ -598,18 +617,14 @@ static inline void emit_a32_alu_r64(const bool is64, 
const s8 dst[],
emit_a32_mov_i(dst_hi, 0, ctx);
 }
 
-/* dst = imm (4 bytes)*/
+/* dst = src (4 bytes)*/
 static inline void emit_a32_mov_r(const s8 dst, const s8 src,
  struct jit_ctx *ctx) {
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rt = is_stacked(src) ? tmp[0] : src;
+   s8 rt;
 
-   if (is_stacked(src))
-   emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(src)), ctx);
-   if (is_stacked(dst))
-   emit(ARM_STR_I(rt, ARM_SP, STACK_VAR(dst)), ctx);
-   else
-   emit(ARM_MOV_R(dst, rt), ctx);
+   rt = arm_bpf_get_reg32(src, tmp[0], ctx);
+   arm_bpf_put_reg32(dst, rt, ctx);
 }
 
 /* dst = src */
@@ -630,10 +645,9 @@ static inline void emit_a32_mov_r64(const bool is64, const 
s8 dst[],
 static inline void emit_a32_alu_i(const s8 dst, const u32 val,
struct jit_ctx *ctx, const u8 op) {
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rd = is_stacked(dst) ? tmp[0] : dst;
+   s8 rd;
 
-   if (is_stacked(dst))
-   emit(ARM_LDR_I(rd, ARM_SP, STACK_VAR(dst)), ctx);
+   rd = arm_bpf_get_reg32(dst, tmp[0], ctx);
 
/* Do shift operation */
switch (op) {
@@ -648,31 +662,25 @@ static inline void emit_a32_alu_i(const s8 dst, const u32 
val,
break;
}
 
-   if (is_stacked(dst))
-   emit(ARM_STR_I(rd, ARM_SP, STACK_VAR(dst)), ctx);
+   arm_bpf_put_reg32(dst, rd, ctx);
 }
 
 /* dst = ~dst (64 bit) */
 static inline void emit_a32_neg64(const s8 dst[],
struct jit_ctx *ctx){
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rd = is_stacked(dst_lo) ? tmp[1] : dst[1];
-   s8 rm = is_stacked(dst_lo) ? tmp[0] : dst[0];
+   s8 rd, rm;
 
/* Setup Operand */
-   if (is_stacked(dst_lo)) {
-   emit(ARM_LDR_I(rd, ARM_SP, STACK_VAR(dst_lo)), 

[PATCH net-next 04/13] ARM: net: bpf: remove is_on_stack() and sstk/dstk

2018-07-10 Thread Russell King
The decision about whether a BPF register is on the stack or in a CPU
register is detected at the top BPF insn processing level, and then
percolated throughout the remainder of the code.  Since we now use
negative register values to represent stacked registers, we can detect
where a BPF register is stored without restoring to carrying this
additional metadata through all code paths.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 336 ++
 1 file changed, 160 insertions(+), 176 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 69bf7ab18bf9..e81401aca2df 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -459,27 +459,18 @@ static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, 
struct jit_ctx *ctx, u8 op)
emit(ARM_MOV_R(ARM_R0, tmp[1]), ctx);
 }
 
-/* Checks whether BPF register is on scratch stack space or not. */
-static inline bool is_on_stack(u8 bpf_reg)
+/* Is the translated BPF register on stack? */
+static bool is_stacked(s8 reg)
 {
-   static u8 stack_regs[] = {BPF_REG_AX, BPF_REG_3, BPF_REG_4, BPF_REG_5,
-   BPF_REG_7, BPF_REG_8, BPF_REG_9, TCALL_CNT,
-   BPF_REG_2, BPF_REG_FP};
-   int i, reg_len = sizeof(stack_regs);
-
-   for (i = 0 ; i < reg_len ; i++) {
-   if (bpf_reg == stack_regs[i])
-   return true;
-   }
-   return false;
+   return reg < 0;
 }
 
 static inline void emit_a32_mov_i(const s8 dst, const u32 val,
- bool dstk, struct jit_ctx *ctx)
+ struct jit_ctx *ctx)
 {
const s8 *tmp = bpf2a32[TMP_REG_1];
 
-   if (dstk) {
+   if (is_stacked(dst)) {
emit_mov_i(tmp[1], val, ctx);
emit(ARM_STR_I(tmp[1], ARM_SP, STACK_VAR(dst)), ctx);
} else {
@@ -489,14 +480,13 @@ static inline void emit_a32_mov_i(const s8 dst, const u32 
val,
 
 /* Sign extended move */
 static inline void emit_a32_mov_i64(const bool is64, const s8 dst[],
- const u32 val, bool dstk,
- struct jit_ctx *ctx) {
+ const u32 val, struct jit_ctx *ctx) {
u32 hi = 0;
 
if (is64 && (val & (1<<31)))
hi = (u32)~0;
-   emit_a32_mov_i(dst_lo, val, dstk, ctx);
-   emit_a32_mov_i(dst_hi, hi, dstk, ctx);
+   emit_a32_mov_i(dst_lo, val, ctx);
+   emit_a32_mov_i(dst_hi, hi, ctx);
 }
 
 static inline void emit_a32_add_r(const u8 dst, const u8 src,
@@ -579,17 +569,16 @@ static inline void emit_alu_r(const u8 dst, const u8 src, 
const bool is64,
  * dst = dst (op) src
  */
 static inline void emit_a32_alu_r(const s8 dst, const s8 src,
- bool dstk, bool sstk,
  struct jit_ctx *ctx, const bool is64,
  const bool hi, const u8 op) {
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rn = sstk ? tmp[1] : src;
+   s8 rn = is_stacked(src) ? tmp[1] : src;
 
-   if (sstk)
+   if (is_stacked(src))
emit(ARM_LDR_I(rn, ARM_SP, STACK_VAR(src)), ctx);
 
/* ALU operation */
-   if (dstk) {
+   if (is_stacked(dst)) {
emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(dst)), ctx);
emit_alu_r(tmp[0], rn, is64, hi, op, ctx);
emit(ARM_STR_I(tmp[0], ARM_SP, STACK_VAR(dst)), ctx);
@@ -600,26 +589,24 @@ static inline void emit_a32_alu_r(const s8 dst, const s8 
src,
 
 /* ALU operation (64 bit) */
 static inline void emit_a32_alu_r64(const bool is64, const s8 dst[],
- const s8 src[], bool dstk,
- bool sstk, struct jit_ctx *ctx,
+ const s8 src[], struct jit_ctx *ctx,
  const u8 op) {
-   emit_a32_alu_r(dst_lo, src_lo, dstk, sstk, ctx, is64, false, op);
+   emit_a32_alu_r(dst_lo, src_lo, ctx, is64, false, op);
if (is64)
-   emit_a32_alu_r(dst_hi, src_hi, dstk, sstk, ctx, is64, true, op);
+   emit_a32_alu_r(dst_hi, src_hi, ctx, is64, true, op);
else
-   emit_a32_mov_i(dst_hi, 0, dstk, ctx);
+   emit_a32_mov_i(dst_hi, 0, ctx);
 }
 
 /* dst = imm (4 bytes)*/
 static inline void emit_a32_mov_r(const s8 dst, const s8 src,
- bool dstk, bool sstk,
  struct jit_ctx *ctx) {
const s8 *tmp = bpf2a32[TMP_REG_1];
-   s8 rt = sstk ? tmp[0] : src;
+   s8 rt = is_stacked(src) ? tmp[0] : src;
 
-   if (sstk)
+   if (is_stacked(src))
emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(src)), ctx);
-   if (dstk)
+   if (is_stacked(dst))
emit(ARM_STR_I(rt, ARM_SP, STACK_VAR(d

[PATCH net-next 03/13] ARM: net: bpf: use negative numbers for stacked registers

2018-07-10 Thread Russell King
Use negative numbers for eBPF registers that live on the stack.

Signed-off-by: Russell King 
---
 arch/arm/net/bpf_jit_32.c | 200 +++---
 1 file changed, 102 insertions(+), 98 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index c81da1a50834..69bf7ab18bf9 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -101,7 +101,11 @@ enum {
BPF_JIT_SCRATCH_REGS,
 };
 
-#define STACK_OFFSET(k)((k) * 4)
+/*
+ * Negative "register" values indicate the register is stored on the stack
+ * and are the offset from the top of the eBPF JIT scratch space.
+ */
+#define STACK_OFFSET(k)(-4 - (k) * 4)
 #define SCRATCH_SIZE   (BPF_JIT_SCRATCH_REGS * 4)
 
 #define TMP_REG_1  (MAX_BPF_JIT_REG + 0)   /* TEMP Register 1 */
@@ -125,7 +129,7 @@ enum {
  * scratch memory space and we have to build eBPF 64 bit register from those.
  *
  */
-static const u8 bpf2a32[][2] = {
+static const s8 bpf2a32[][2] = {
/* return value from in-kernel function, and exit value from eBPF */
[BPF_REG_0] = {ARM_R1, ARM_R0},
/* arguments from eBPF program to in-kernel function */
@@ -291,7 +295,7 @@ static void jit_fill_hole(void *area, unsigned int size)
 #define STACK_SIZE ALIGN(_STACK_SIZE, STACK_ALIGNMENT)
 
 /* Get the offset of eBPF REGISTERs stored on scratch space. */
-#define STACK_VAR(off) (STACK_SIZE - off)
+#define STACK_VAR(off) (STACK_SIZE + (off))
 
 #if __LINUX_ARM_ARCH__ < 7
 
@@ -408,7 +412,7 @@ static inline int epilogue_offset(const struct jit_ctx *ctx)
 
 static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 
op)
 {
-   const u8 *tmp = bpf2a32[TMP_REG_1];
+   const s8 *tmp = bpf2a32[TMP_REG_1];
 
 #if __LINUX_ARM_ARCH__ == 7
if (elf_hwcap & HWCAP_IDIVA) {
@@ -470,10 +474,10 @@ static inline bool is_on_stack(u8 bpf_reg)
return false;
 }
 
-static inline void emit_a32_mov_i(const u8 dst, const u32 val,
+static inline void emit_a32_mov_i(const s8 dst, const u32 val,
  bool dstk, struct jit_ctx *ctx)
 {
-   const u8 *tmp = bpf2a32[TMP_REG_1];
+   const s8 *tmp = bpf2a32[TMP_REG_1];
 
if (dstk) {
emit_mov_i(tmp[1], val, ctx);
@@ -484,7 +488,7 @@ static inline void emit_a32_mov_i(const u8 dst, const u32 
val,
 }
 
 /* Sign extended move */
-static inline void emit_a32_mov_i64(const bool is64, const u8 dst[],
+static inline void emit_a32_mov_i64(const bool is64, const s8 dst[],
  const u32 val, bool dstk,
  struct jit_ctx *ctx) {
u32 hi = 0;
@@ -574,12 +578,12 @@ static inline void emit_alu_r(const u8 dst, const u8 src, 
const bool is64,
 /* ALU operation (32 bit)
  * dst = dst (op) src
  */
-static inline void emit_a32_alu_r(const u8 dst, const u8 src,
+static inline void emit_a32_alu_r(const s8 dst, const s8 src,
  bool dstk, bool sstk,
  struct jit_ctx *ctx, const bool is64,
  const bool hi, const u8 op) {
-   const u8 *tmp = bpf2a32[TMP_REG_1];
-   u8 rn = sstk ? tmp[1] : src;
+   const s8 *tmp = bpf2a32[TMP_REG_1];
+   s8 rn = sstk ? tmp[1] : src;
 
if (sstk)
emit(ARM_LDR_I(rn, ARM_SP, STACK_VAR(src)), ctx);
@@ -595,8 +599,8 @@ static inline void emit_a32_alu_r(const u8 dst, const u8 
src,
 }
 
 /* ALU operation (64 bit) */
-static inline void emit_a32_alu_r64(const bool is64, const u8 dst[],
- const u8 src[], bool dstk,
+static inline void emit_a32_alu_r64(const bool is64, const s8 dst[],
+ const s8 src[], bool dstk,
  bool sstk, struct jit_ctx *ctx,
  const u8 op) {
emit_a32_alu_r(dst_lo, src_lo, dstk, sstk, ctx, is64, false, op);
@@ -607,11 +611,11 @@ static inline void emit_a32_alu_r64(const bool is64, 
const u8 dst[],
 }
 
 /* dst = imm (4 bytes)*/
-static inline void emit_a32_mov_r(const u8 dst, const u8 src,
+static inline void emit_a32_mov_r(const s8 dst, const s8 src,
  bool dstk, bool sstk,
  struct jit_ctx *ctx) {
-   const u8 *tmp = bpf2a32[TMP_REG_1];
-   u8 rt = sstk ? tmp[0] : src;
+   const s8 *tmp = bpf2a32[TMP_REG_1];
+   s8 rt = sstk ? tmp[0] : src;
 
if (sstk)
emit(ARM_LDR_I(tmp[0], ARM_SP, STACK_VAR(src)), ctx);
@@ -622,8 +626,8 @@ static inline void emit_a32_mov_r(const u8 dst, const u8 
src,
 }
 
 /* dst = src */
-static inline void emit_a32_mov_r64(const bool is64, const u8 dst[],
- const u8 src[], bool dstk,
+static inline void emit_a32_mov_r64(const bool is64, const s8 dst[],
+ const s8 src[], bool dstk,
  

[PATCH 00/13] ARM BPF jit compiler improvements

2018-07-10 Thread Russell King - ARM Linux
Hi,

This series improves the ARM BPF JIT compiler by:
- enumerating the stack layout rather than using constants that happen
  to be multiples of four
- rejig the BPF "register" accesses to use negative numbers instead of
  positive, which could be confused with register numbers in the bpf2a32
  array.
- since we maintain the ARM FP register as a pointer to the top of our
  scratch space (or, with frame pointers enabled, a valid ARM frame
  pointer register), we can access our scratch space using FP, which is
  constant across all BPF programs, including tail-called programs.
- use immediate forms of ARM instructions where possible, rather than
  first loading the immediate into an ARM register.
- use load-with-shift instruction rather than seperate shift instruction
  followed by load
- avoid reloading index and array in the tail-call code
- use double-word load/store instructions where available

 arch/arm/net/bpf_jit_32.c | 927 +++---
 arch/arm/net/bpf_jit_32.h |  44 +--
 2 files changed, 493 insertions(+), 478 deletions(-)

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


[PATCH net 1/2] sfp: ensure we clean up properly on bus registration failure

2018-07-10 Thread Russell King
We fail to correctly clean up after a bus registration failure, which
can lead to an incorrect assumption about the registration state of
the upstream or sfp cage.

Signed-off-by: Russell King 
---
 drivers/net/phy/sfp-bus.c | 31 ---
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
index fd6c23f69c2f..e355e7db54a7 100644
--- a/drivers/net/phy/sfp-bus.c
+++ b/drivers/net/phy/sfp-bus.c
@@ -429,6 +429,13 @@ void sfp_upstream_stop(struct sfp_bus *bus)
 }
 EXPORT_SYMBOL_GPL(sfp_upstream_stop);
 
+static void sfp_upstream_clear(struct sfp_bus *bus)
+{
+   bus->upstream_ops = NULL;
+   bus->upstream = NULL;
+   bus->netdev = NULL;
+}
+
 /**
  * sfp_register_upstream() - Register the neighbouring device
  * @fwnode: firmware node for the SFP bus
@@ -455,8 +462,11 @@ struct sfp_bus *sfp_register_upstream(struct fwnode_handle 
*fwnode,
bus->upstream = upstream;
bus->netdev = ndev;
 
-   if (bus->sfp)
+   if (bus->sfp) {
ret = sfp_register_bus(bus);
+   if (ret)
+   sfp_upstream_clear(bus);
+   }
rtnl_unlock();
}
 
@@ -481,8 +491,7 @@ void sfp_unregister_upstream(struct sfp_bus *bus)
rtnl_lock();
if (bus->sfp)
sfp_unregister_bus(bus);
-   bus->upstream = NULL;
-   bus->netdev = NULL;
+   sfp_upstream_clear(bus);
rtnl_unlock();
 
sfp_bus_put(bus);
@@ -554,6 +563,13 @@ void sfp_module_remove(struct sfp_bus *bus)
 }
 EXPORT_SYMBOL_GPL(sfp_module_remove);
 
+static void sfp_socket_clear(struct sfp_bus *bus)
+{
+   bus->sfp_dev = NULL;
+   bus->sfp = NULL;
+   bus->socket_ops = NULL;
+}
+
 struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp,
const struct sfp_socket_ops *ops)
 {
@@ -566,8 +582,11 @@ struct sfp_bus *sfp_register_socket(struct device *dev, 
struct sfp *sfp,
bus->sfp = sfp;
bus->socket_ops = ops;
 
-   if (bus->netdev)
+   if (bus->netdev) {
ret = sfp_register_bus(bus);
+   if (ret)
+   sfp_socket_clear(bus);
+   }
rtnl_unlock();
}
 
@@ -585,9 +604,7 @@ void sfp_unregister_socket(struct sfp_bus *bus)
rtnl_lock();
if (bus->netdev)
sfp_unregister_bus(bus);
-   bus->sfp_dev = NULL;
-   bus->sfp = NULL;
-   bus->socket_ops = NULL;
+   sfp_socket_clear(bus);
rtnl_unlock();
 
sfp_bus_put(bus);
-- 
2.7.4



[PATCH net 2/2] sfp: fix module initialisation with netdev already up

2018-07-10 Thread Russell King
It was been observed that with a particular order of initialisation,
the netdev can be up, but the SFP module still has its TX_DISABLE
signal asserted.  This occurs when the network device brought up before
the SFP kernel module has been inserted by userspace.

This occurs because sfp-bus layer does not hear about the change in
network device state, and so assumes that it is still down.  Set
netdev->sfp when the upstream is registered to work around this problem.

Signed-off-by: Russell King 
---
 drivers/net/phy/sfp-bus.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
index e355e7db54a7..5e5fcc33421e 100644
--- a/drivers/net/phy/sfp-bus.c
+++ b/drivers/net/phy/sfp-bus.c
@@ -342,7 +342,6 @@ static int sfp_register_bus(struct sfp_bus *bus)
}
if (bus->started)
bus->socket_ops->start(bus->sfp);
-   bus->netdev->sfp_bus = bus;
bus->registered = true;
return 0;
 }
@@ -357,7 +356,6 @@ static void sfp_unregister_bus(struct sfp_bus *bus)
if (bus->phydev && ops && ops->disconnect_phy)
ops->disconnect_phy(bus->upstream);
}
-   bus->netdev->sfp_bus = NULL;
bus->registered = false;
 }
 
@@ -433,6 +431,7 @@ static void sfp_upstream_clear(struct sfp_bus *bus)
 {
bus->upstream_ops = NULL;
bus->upstream = NULL;
+   bus->netdev->sfp_bus = NULL;
bus->netdev = NULL;
 }
 
@@ -461,6 +460,7 @@ struct sfp_bus *sfp_register_upstream(struct fwnode_handle 
*fwnode,
bus->upstream_ops = ops;
bus->upstream = upstream;
bus->netdev = ndev;
+   ndev->sfp_bus = bus;
 
if (bus->sfp) {
ret = sfp_register_bus(bus);
-- 
2.7.4



Re: [offlist] Re: Crash in netlink/sk_filter_trim_cap on ARMv7 on 4.18rc1

2018-07-05 Thread Russell King - ARM Linux
On Thu, Jul 05, 2018 at 12:41:54AM +0100, Russell King - ARM Linux wrote:
> Subject says offlist, but this isn't...
> 
> On Wed, Jul 04, 2018 at 08:33:20AM +0100, Peter Robinson wrote:
> > Sorry for the delay on this from my end. I noticed there was some bpf
> > bits land in the last net fixes pull request landed Monday so I built
> > a kernel with the JIT reenabled. It seems it's improved in that the
> > completely dead no output boot has gone but the original problem that
> > arrived in the merge window still persists:
> > 
> > [   17.564142] note: systemd-udevd[194] exited with preempt_count 1
> > [   17.592739] Unable to handle kernel NULL pointer dereference at
> > virtual address 000c
> > [   17.601002] pgd = (ptrval)
> > [   17.603819] [000c] *pgd=
> > [   17.607487] Internal error: Oops: 805 [#10] SMP ARM
> > [   17.612396] Modules linked in:
> > [   17.615484] CPU: 0 PID: 195 Comm: systemd-udevd Tainted: G  D
> > 4.18.0-0.rc3.git1.1.bpf1.fc29.armv7hl #1
> > [   17.626056] Hardware name: Generic AM33XX (Flattened Device Tree)
> > [   17.632198] PC is at sk_filter_trim_cap+0x218/0x2fc
> > [   17.637102] LR is at   (null)
> > [   17.640086] pc : []lr : [<>]psr: 6013
> > [   17.646384] sp : cfe1dd48  ip :   fp : 
> > [   17.651635] r10: d837e000  r9 : d833be00  r8 : 
> > [   17.656887] r7 : 0001  r6 : e003d000  r5 :   r4 : 
> > [   17.663447] r3 : 0007  r2 :   r1 :   r0 : 
> > [   17.670009] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment 
> > none
> > [   17.677180] Control: 10c5387d  Table: 8fe20019  DAC: 0051
> > [   17.682956] Process systemd-udevd (pid: 195, stack limit = 0x(ptrval))
> > [   17.689518] Stack: (0xcfe1dd48 to 0xcfe1e000)
> 
> Can you provide a full disassembly of sk_filter_trim_cap from vmlinux
> (iow, annotated with its linked address) for the above dump please -
> alternatively a new dump with matching disassembly.  Thanks.

Also probably a good idea to have bpf_jit_enable set to 2 to get a
dump of the bpf program being run, which I think for your problem,
you'll have to hack the kernel source to do that.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


Re: [offlist] Re: Crash in netlink/sk_filter_trim_cap on ARMv7 on 4.18rc1

2018-07-04 Thread Russell King - ARM Linux
Subject says offlist, but this isn't...

On Wed, Jul 04, 2018 at 08:33:20AM +0100, Peter Robinson wrote:
> Sorry for the delay on this from my end. I noticed there was some bpf
> bits land in the last net fixes pull request landed Monday so I built
> a kernel with the JIT reenabled. It seems it's improved in that the
> completely dead no output boot has gone but the original problem that
> arrived in the merge window still persists:
> 
> [   17.564142] note: systemd-udevd[194] exited with preempt_count 1
> [   17.592739] Unable to handle kernel NULL pointer dereference at
> virtual address 000c
> [   17.601002] pgd = (ptrval)
> [   17.603819] [000c] *pgd=
> [   17.607487] Internal error: Oops: 805 [#10] SMP ARM
> [   17.612396] Modules linked in:
> [   17.615484] CPU: 0 PID: 195 Comm: systemd-udevd Tainted: G  D
> 4.18.0-0.rc3.git1.1.bpf1.fc29.armv7hl #1
> [   17.626056] Hardware name: Generic AM33XX (Flattened Device Tree)
> [   17.632198] PC is at sk_filter_trim_cap+0x218/0x2fc
> [   17.637102] LR is at   (null)
> [   17.640086] pc : []lr : [<>]psr: 6013
> [   17.646384] sp : cfe1dd48  ip :   fp : 
> [   17.651635] r10: d837e000  r9 : d833be00  r8 : 
> [   17.656887] r7 : 0001  r6 : e003d000  r5 :   r4 : 
> [   17.663447] r3 : 0007  r2 :   r1 :   r0 : 
> [   17.670009] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment 
> none
> [   17.677180] Control: 10c5387d  Table: 8fe20019  DAC: 0051
> [   17.682956] Process systemd-udevd (pid: 195, stack limit = 0x(ptrval))
> [   17.689518] Stack: (0xcfe1dd48 to 0xcfe1e000)

Can you provide a full disassembly of sk_filter_trim_cap from vmlinux
(iow, annotated with its linked address) for the above dump please -
alternatively a new dump with matching disassembly.  Thanks.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 13.8Mbps down 630kbps up
According to speedtest.net: 13Mbps down 490kbps up


Re: [PATCH net-next 1/2] net: phy: sfp: make the i2c-bus property really optional

2018-05-17 Thread Russell King - ARM Linux
On Thu, May 17, 2018 at 03:04:06PM +0200, Andrew Lunn wrote:
> On Thu, May 17, 2018 at 02:56:48PM +0200, Antoine Tenart wrote:
> > Hi Andrew,
> > 
> > On Thu, May 17, 2018 at 02:41:28PM +0200, Andrew Lunn wrote:
> > > On Thu, May 17, 2018 at 10:29:06AM +0200, Antoine Tenart wrote:
> > > > The SFF,SFP documentation is clear about making all the DT properties,
> > > > with the exception of the compatible, optional. In practice this is not
> > > > the case and without an i2c-bus property provided the SFP code will
> > > > throw NULL pointer exceptions.
> > > > 
> > > > This patch is an attempt to fix this.
> > > 
> > > How usable is an SFF/SFP module without access to the i2c EEPROM? I
> > > guess this comes down to link speed. Can it be manually configured?
> > >
> > > I'm just wondering if we want to make this mandatory? Fail the probe
> > > if it is not listed?
> > 
> > Yes, the other option would be to fail when probing a cage missing the
> > i2c description. I'd say a passive module can work without the i2c
> > EEPROM accessible as it does not need to be configured. I don't know
> > what would happen with active ones.
> 
> Hi Antoine
> 
> I was thinking about how it reads the bit rate from the EEPROM. From
> that it determines what mode the MAC could use, 1000-Base-X,
> 2500-Base-X, etc. Can you still configure this correctly via ethtool,
> if you don't have the bitrate information?

Determining the protocol is kind of guess work even with the EEPROM
available - see comments above sfp_parse_interface().

Without knowing the contents of the EEPROM, you can't even guess what
protocol should be used for a particular module.

For example, there are 10/100/1000 modules from one vendor that use an
88e, which are configured for SGMII on the MAC side.  There is
another variant of that module which has the same hardware, but the
88e is programmed for 1G only mode, and uses 1000base-X on the MAC
side.  For both modules, the 88e is accessible, the host side
protocol can be reconfigured and the manufacturer includes the 88e
register access instructions for doing so.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [PATCH net-next 1/2] net: phy: sfp: make the i2c-bus property really optional

2018-05-17 Thread Russell King - ARM Linux
On Thu, May 17, 2018 at 02:41:28PM +0200, Andrew Lunn wrote:
> On Thu, May 17, 2018 at 10:29:06AM +0200, Antoine Tenart wrote:
> > The SFF,SFP documentation is clear about making all the DT properties,
> > with the exception of the compatible, optional. In practice this is not
> > the case and without an i2c-bus property provided the SFP code will
> > throw NULL pointer exceptions.
> > 
> > This patch is an attempt to fix this.
> 
> Hi Antoine, Russell
> 
> How usable is an SFF/SFP module without access to the i2c EEPROM? I
> guess this comes down to link speed. Can it be manually configured?

While we can support forcing the speed/duplex through ethtool, there
is no obvious facility via ethtool to set the protocol currently (eg,
SGMII vs 1000base-X).  There is, however, the possibility to use the
advertise mask to determine which mode we should be using, but that's
awkward to deal with via ethtool as ethtool wants a hex mask, which
really isn't user friendly.

The protocol matters - for example, a copper SFP module will typically
want to use SGMII, and if it encounters 1000base-X on the other side,
the PHY won't pass data because it will believe that the link to the
MAC is down.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [PATCH net-next v3 00/10] net: mvpp2: phylink conversion

2018-05-17 Thread Russell King - ARM Linux
On Thu, May 17, 2018 at 10:29:29AM +0200, Antoine Tenart wrote:
> Since v2:
>   - Removed the SFP description from the DB boards, as their SFP cages
> are wired properly. We now use fixed-link.

I think you mean "improperly" here.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [PATCH net-next v2 3/9] net: phy: phylink: Poll link GPIOs

2018-05-10 Thread Russell King - ARM Linux
On Thu, May 10, 2018 at 01:17:31PM -0700, Florian Fainelli wrote:
> From: Russell King <rmk+ker...@armlinux.org.uk>
> 
> When using a fixed link with a link GPIO, we need to poll that GPIO to
> determine link state changes. This is consistent with what fixed_phy.c does.
> 
> Signed-off-by: Florian Fainelli <f.faine...@gmail.com>

I'd like this to use the GPIO interrupt where available, only falling back
to the timer approach when there's no interrupt.  Unfortunately, I don't
have much time to devote to this at the moment, having recently been away
on vacation, and now having to work on ARM specific issues for probably
all of the remainder of this kernel cycle.

That means I won't have time to test your series on any of the boards
I have available to me.

> ---
>  drivers/net/phy/phylink.c | 16 
>  1 file changed, 16 insertions(+)
> 
> diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
> index 6392b5248cf5..581ce93ecaf9 100644
> --- a/drivers/net/phy/phylink.c
> +++ b/drivers/net/phy/phylink.c
> @@ -19,6 +19,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  
>  #include "sfp.h"
> @@ -54,6 +55,7 @@ struct phylink {
>   /* The link configuration settings */
>   struct phylink_link_state link_config;
>   struct gpio_desc *link_gpio;
> + struct timer_list link_poll;
>   void (*get_fixed_state)(struct net_device *dev,
>   struct phylink_link_state *s);
>  
> @@ -500,6 +502,15 @@ static void phylink_run_resolve(struct phylink *pl)
>   queue_work(system_power_efficient_wq, >resolve);
>  }
>  
> +static void phylink_fixed_poll(struct timer_list *t)
> +{
> + struct phylink *pl = container_of(t, struct phylink, link_poll);
> +
> + mod_timer(t, jiffies + HZ);
> +
> + phylink_run_resolve(pl);
> +}
> +
>  static const struct sfp_upstream_ops sfp_phylink_ops;
>  
>  static int phylink_register_sfp(struct phylink *pl,
> @@ -572,6 +583,7 @@ struct phylink *phylink_create(struct net_device *ndev,
>   pl->link_config.an_enabled = true;
>   pl->ops = ops;
>   __set_bit(PHYLINK_DISABLE_STOPPED, >phylink_disable_state);
> + timer_setup(>link_poll, phylink_fixed_poll, 0);
>  
>   bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
>   linkmode_copy(pl->link_config.advertising, pl->supported);
> @@ -905,6 +917,8 @@ void phylink_start(struct phylink *pl)
>   clear_bit(PHYLINK_DISABLE_STOPPED, >phylink_disable_state);
>   phylink_run_resolve(pl);
>  
> + if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio))
> + mod_timer(>link_poll, jiffies + HZ);
>   if (pl->sfp_bus)
>   sfp_upstream_start(pl->sfp_bus);
>   if (pl->phydev)
> @@ -929,6 +943,8 @@ void phylink_stop(struct phylink *pl)
>   phy_stop(pl->phydev);
>   if (pl->sfp_bus)
>   sfp_upstream_stop(pl->sfp_bus);
> + if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio))
> + del_timer_sync(>link_poll);
>  
>   set_bit(PHYLINK_DISABLE_STOPPED, >phylink_disable_state);
>   queue_work(system_power_efficient_wq, >resolve);
> -- 
> 2.14.1
> 

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [PATCH net-next v2 03/13] net: phy: sfp: warn the user when no tx_disable pin is available

2018-05-08 Thread Russell King - ARM Linux
On Sat, May 05, 2018 at 10:52:42PM +0200, Andrew Lunn wrote:
> On Sat, May 05, 2018 at 01:38:31PM -0700, Florian Fainelli wrote:
> > On May 4, 2018 10:14:25 AM PDT, Andrew Lunn  wrote:
> > >On Fri, May 04, 2018 at 10:07:53AM -0700, Florian Fainelli wrote:
> > >> On 05/04/2018 06:56 AM, Antoine Tenart wrote:
> > >> > In case no Tx disable pin is available the SFP modules will always
> > >be
> > >> > emitting. This could be an issue when using modules using laser as
> > >their
> > >> > light source as we would have no way to disable it when the fiber
> > >is
> > >> > removed. This patch adds a warning when registering an SFP cage
> > >which do
> > >> > not have its tx_disable pin wired or available.
> > >> 
> > >> Is this something that was done in a possibly earlier revision of a
> > >> given board design and which was finally fixed? Nothing wrong with
> > >the
> > >> patch, but this seems like a pretty serious board design mistake,
> > >that
> > >> needs to be addressed.
> > >
> > >Hi Florian
> > >
> > >Zii Devel B is like this. Only the "Signal Detect" pin is wired to a
> > >GPIO.
> > 
> 
> > Good point, indeed. BTW what do you think about exposing the SFF's
> > EEPROM and diagnostics through the standard ethtool operations even
> > if we have to keep the description of the SFF as a fixed link in
> > Device Tree because of the unfortunate wiring?
> 
> I believe in Antoine case, all the control plane is broken. He cannot
> read the EEPROM, nor any of the modules pins via GPIOs.

Correct.

> For Zii Devel B, the EEPROM is accessible, and so is the SD pin. What
> is missing is transmit disable. So i would expose it as an SFF module.

Agreed.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [PATCH net-next] net: phy: sfp: handle cases where neither BR,min nor BR,max is given

2018-05-08 Thread Russell King - ARM Linux
On Sat, May 05, 2018 at 01:35:34PM -0700, Florian Fainelli wrote:
> On May 4, 2018 8:21:03 AM PDT, Antoine Tenart  
> wrote:
> >When computing the bitrate using values read from an SFP module EEPROM,
> >we use the nominal BR plus BR,min and BR,max to determine the
> >boundaries. But in some cases BR,min and BR,max aren't provided, which
> >led the SFP code to end up having the nominal value for both the
> >minimum
> >and maximum bitrate values. When using a passive cable, the nominal
> >value should be used as the maximum one, and there is no minimum one
> >so we should use 0.
> >
> >Signed-off-by: Antoine Tenart 
> >---
> >
> >Hi Russell,
> >
> >I'm not completely sure about this patch as this case is not really
> >specified in the specification. But the issue is there, and I've
> >discuss
> >this with others. It seemed logical (at least to us :)) to use the
> >BR,nominal values as br_max and 0 as br_min when using a passive cable
> >which only provides BR,nominal as this would be the highest rate at
> >which the cable could work. And because it's passive, there should be
> >no
> >issues using it at a lower rate.
> >
> >I've tested this with one passive cable which only reports its
> >BR,nominal (which was 10300) while it could be used when using
> >1000baseX
> >or 2500baseX modes.
> 
> Which SFP modules (vendor and model) exposed this out of curiosity?
> Russell and I already saw the Cotsworks modules having so e issues
> with checksums, so building a table of quirks would help. Thanks!

I think this is just manufacturers being lazy with their EEPROM
contents - looking around, most passive cables are specified to be
"up to" some figure, and that's definitely what's specified by the
SFP+ specification by way of the high-pass pole requirement of the
coupling capacitors.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [PATCH net-next v2 06/13] phy: add 2.5G SGMII mode to the phy_mode enum

2018-05-08 Thread Russell King - ARM Linux
On Fri, May 04, 2018 at 03:56:36PM +0200, Antoine Tenart wrote:
> This patch adds one more generic PHY mode to the phy_mode enum, to allow
> configuring generic PHYs to the 2.5G SGMII mode by using the set_mode
> callback.
> 
> Signed-off-by: Antoine Tenart 
> Acked-by: Kishon Vijay Abraham I 

Hi,

Would it be possible to get the 2.5G SGMII comphy support merged
ahead of the rest of this series please - I don't think there's been
any objections to it, and having it in mainline would then mean I can
drop the Marvell Comphy code from my tree and transition to the bootlin
Comphy code instead.

Of course, the perfect solution would be to get the whole series merged,
but I'm just thinking about the situation where we're still discussing
points when the next merge window opens.

Thanks.

> ---
>  include/linux/phy/phy.h | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
> index c9d147f5..9713aebdd348 100644
> --- a/include/linux/phy/phy.h
> +++ b/include/linux/phy/phy.h
> @@ -36,6 +36,7 @@ enum phy_mode {
>   PHY_MODE_USB_DEVICE_SS,
>   PHY_MODE_USB_OTG,
>   PHY_MODE_SGMII,
> + PHY_MODE_2500SGMII,
>   PHY_MODE_10GKR,
>   PHY_MODE_UFS_HS_A,
>   PHY_MODE_UFS_HS_B,
> -- 
> 2.17.0
> 

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [PATCH net-next] net: phy: sfp: handle cases where neither BR,min nor BR,max is given

2018-05-08 Thread Russell King - ARM Linux
On Fri, May 04, 2018 at 05:21:03PM +0200, Antoine Tenart wrote:
> When computing the bitrate using values read from an SFP module EEPROM,
> we use the nominal BR plus BR,min and BR,max to determine the
> boundaries. But in some cases BR,min and BR,max aren't provided, which
> led the SFP code to end up having the nominal value for both the minimum
> and maximum bitrate values. When using a passive cable, the nominal
> value should be used as the maximum one, and there is no minimum one
> so we should use 0.
> 
> Signed-off-by: Antoine Tenart <antoine.ten...@bootlin.com>
> ---
> 
> Hi Russell,
> 
> I'm not completely sure about this patch as this case is not really
> specified in the specification. But the issue is there, and I've discuss
> this with others. It seemed logical (at least to us :)) to use the
> BR,nominal values as br_max and 0 as br_min when using a passive cable
> which only provides BR,nominal as this would be the highest rate at
> which the cable could work. And because it's passive, there should be no
> issues using it at a lower rate.
> 
> I've tested this with one passive cable which only reports its
> BR,nominal (which was 10300) while it could be used when using 1000baseX
> or 2500baseX modes.

The electronic engineer in me says that using zero isn't really valid
because there are coupling capacitors in the SFP module that block DC.
These blocking capacitors are required by the SFP+ specs to have a high
pass pole of between 20kHz and 100kHz - in other words, frequencies
below this are attenuated by the coupling capacitors.  The relationship
between this and the bit rate will be a function of the encoding, so we
can't come to a definitive figure without some math (and I want to be
lazy about that!)

Practically, we're talking about SerDes Ethernet, where the bit rate is
no lower than 100Mbps [*], which will always have a frequency well above
this cut-off.  So, I don't have any problem with your approach to
setting the minimum to zero.  Therefore,

Acked-by: Russell King <rmk+ker...@armlinux.org.uk>

Please send me the EEPROM dump using:

ethtool -m  raw on > foo.bin

so I can add it to my database for future testing and validation.

Thanks.

* - 10Mbps SGMII is 1Gbps SGMII with each bit repeated 100 times.
100Mbps SGMII is 1Gbps SGMII with each bit repeated 10 times.
There is a capability bits for transceivers supporting
100base-FX/LX but no one has tested those yet.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [PATCH net] net: phy: sfp: fix the BR,min computation

2018-05-08 Thread Russell King - ARM Linux
On Fri, May 04, 2018 at 05:10:54PM +0200, Antoine Tenart wrote:
> In an SFP EEPROM values can be read to get information about a given SFP
> module. One of those is the bitrate, which can be determined using a
> nominal bitrate in addition with min and max values (in %). The SFP code
> currently compute both BR,min and BR,max values thanks to this nominal
> and min,max values.
> 
> This patch fixes the BR,min computation as the min value should be
> subtracted to the nominal one, not added.
> 
> Fixes: 9962acf7fb8c ("sfp: add support for 1000Base-PX and 1000Base-BX10")
> Signed-off-by: Antoine Tenart 

I know David has already applied it, but for the record, your fix looks
correct, thanks.

> ---
>  drivers/net/phy/sfp-bus.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
> index 0381da78d228..fd6c23f69c2f 100644
> --- a/drivers/net/phy/sfp-bus.c
> +++ b/drivers/net/phy/sfp-bus.c
> @@ -125,7 +125,7 @@ void sfp_parse_support(struct sfp_bus *bus, const struct 
> sfp_eeprom_id *id,
>   if (id->base.br_nominal) {
>   if (id->base.br_nominal != 255) {
>   br_nom = id->base.br_nominal * 100;
> - br_min = br_nom + id->base.br_nominal * id->ext.br_min;
> + br_min = br_nom - id->base.br_nominal * id->ext.br_min;
>   br_max = br_nom + id->base.br_nominal * id->ext.br_max;
>   } else if (id->ext.br_max) {
>   br_nom = 250 * id->ext.br_max;
> -- 
> 2.17.0
> 

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [PATCH net-next v2 03/13] net: phy: sfp: warn the user when no tx_disable pin is available

2018-05-08 Thread Russell King - ARM Linux
On Fri, May 04, 2018 at 03:56:33PM +0200, Antoine Tenart wrote:
> In case no Tx disable pin is available the SFP modules will always be
> emitting. This could be an issue when using modules using laser as their
> light source as we would have no way to disable it when the fiber is
> removed. This patch adds a warning when registering an SFP cage which do
> not have its tx_disable pin wired or available.
> 
> Signed-off-by: Antoine Tenart <antoine.ten...@bootlin.com>

Looks fine, thanks.

Acked-by: Russell King <rmk+ker...@armlinux.org.uk>

> ---
>  drivers/net/phy/sfp.c | 9 +
>  1 file changed, 9 insertions(+)
> 
> diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
> index 8e323a4b70da..d4f503b2e3e2 100644
> --- a/drivers/net/phy/sfp.c
> +++ b/drivers/net/phy/sfp.c
> @@ -1093,6 +1093,15 @@ static int sfp_probe(struct platform_device *pdev)
>   if (!sfp->gpio[GPIO_MODDEF0] && !sfp->gpio[GPIO_LOS])
>   sfp->sm_dev_state = SFP_DEV_UNKNOWN;
>  
> + /* We could have an issue in cases no Tx disable pin is available or
> +  * wired as modules using a laser as their light source will continue to
> +  * be active when the fiber is removed. This could be a safety issue and
> +  * we should at least warn the user about that.
> +  */
> + if (!sfp->gpio[GPIO_TX_DISABLE])
> + dev_warn(sfp->dev,
> +  "No tx_disable pin: SFP modules will always be 
> emitting.\n");
> +
>   return 0;
>  }
>  
> -- 
> 2.17.0
> 

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [PATCH net-next v2 02/13] net: phy: sfp: handle non-wired SFP connectors

2018-05-08 Thread Russell King - ARM Linux
On Fri, May 04, 2018 at 03:56:32PM +0200, Antoine Tenart wrote:
> SFP connectors can be solder on a board without having any of their pins
> (LOS, i2c...) wired. In such cases the SFP link state cannot be guessed,
> and the overall link status reporting is left to other layers.
> 
> In order to achieve this, a new SFP_DEV status is added, named UNKNOWN.
> This mode is set when it is not possible for the SFP code to get the
> link status and as a result the link status is reported to be always UP
> from the SFP point of view.

This looks weird to me.  SFP_DEV_* states track the netdevice up/down
state and have little to do with whether LOS or MODDEF0 are implemented.

I think it would be better to have a new SFP_MOD_* and to force
sm_mod_state to that in this circumstance.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


BUG: DSA blocks (some?) multicast traffic

2018-04-16 Thread Russell King - ARM Linux
Hi,

Yesterday, I noticed that one of my platforms had become unreachable
over IPv6.  This platform is connected to a Clearfog, which uses
the Marvell 88e6176 switch.

The setup is:

   (rest of network)
 | | | | | | |
Source  Netgear switch  Clearfog switch  Target
^ ^  ^
   lan1  lan5   eth2
  port 4port 0

Both the source and target could ping the IPv6 link-local address on
the clearfog, and IPv4 traffic was fine.

The source was attempting to ping the target, and the target had been
attempting to mount a NFS share over IPv6 (and failing.)

Statistics from the Clearfog switch - port 0 is the target, port 4 is
the netgear switch, port 5 is the CPU port:

 Statistic   Port  0  Port  1  Port  2  Port  3  Port  4  Port  5  Port  6
 in_multicasts:27670001455278196 16740
out_multicasts:  4390  331  332  331   114860  334

As you can see, very few multicast packets have been sent out any of
the ports.

Running tcpdump on the source machine:

21:31:48.805654 xx:xx:xx:15:37:dd > 33:33:ff:00:00:05,
ethertype IPv6 (0x86dd), length 86:
fd8f::::222:68ff:fe15:37dd > ff02::1:ff00:5:
ICMP6, neighbor solicitation, who has
fd8f::::200:ff:fe00:5, length 32

tcpdump on the clearfog for port 4:

21:31:48.807640 xx:xx:xx:15:37:dd > 33:33:ff:00:00:05,
ethertype IPv6 (0x86dd), length 86:
fd8f::::222:68ff:fe15:37dd > ff02::1:ff00:5:
ICMP6, neighbor solicitation, who has
fd8f::::200:ff:fe00:5, length 32

The port connected to the target doesn't see these multicast messages
which are intended for it.  However, I am able to see messages
multicasted from the target, which is trying to solicit a different
machine on my network:

21:33:22.394653 00:00:00:00:00:05 > 33:33:ff:10:1b:e6,
ethertype IPv6 (0x86dd), length 86:
fd8f::::200:ff:fe00:5 > ff02::1:ff10:1be6:
ICMP6, neighbor solicitation, who has
fd8f::::214:fdff:fe10:1be6, length 32

but these neighbour solicitations are also not forwarded to through
the switch to the rest of the network.

Tweaking the DSA switch port register 4 (which had a value of 0x0433)
to 0x043b resolved the issue - multicast traffic started to egress
these ports, and the neighbour solicitations then worked.

I thought maybe this was a 4.16 regression, but it seems my other
clearfog has a similar register setup, so I'm not sure.  I'm pretty
sure that it used to work at some point, as I'm a heavy user of IPv6
internally, and I'm quite certain that I would have noticed a failure
such as this.

The setup on the target is eth2 is part of a Linux bridge device.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


[PATCH v2] net: phy: marvell10g: add thermal hwmon device

2018-04-03 Thread Russell King
Add a thermal monitoring device for the Marvell 88x3310, which updates
once a second.  We also need to hook into the suspend/resume mechanism
to ensure that the thermal monitoring is reconfigured when we resume.

Suggested-by: Andrew Lunn <and...@lunn.ch>
Signed-off-by: Russell King <rmk+ker...@armlinux.org.uk>
---
v2: update to apply to net-next

 drivers/net/phy/marvell10g.c | 184 ++-
 1 file changed, 182 insertions(+), 2 deletions(-)

diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 8a0bd98fdec7..db9d66781da6 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -21,8 +21,10 @@
  * If both the fiber and copper ports are connected, the first to gain
  * link takes priority and the other port is completely locked out.
  */
-#include 
+#include 
+#include 
 #include 
+#include 
 
 enum {
MV_PCS_BASE_T   = 0x,
@@ -40,6 +42,19 @@ enum {
 */
MV_AN_CTRL1000  = 0x8000, /* 1000base-T control register */
MV_AN_STAT1000  = 0x8001, /* 1000base-T status register */
+
+   /* Vendor2 MMD registers */
+   MV_V2_TEMP_CTRL = 0xf08a,
+   MV_V2_TEMP_CTRL_MASK= 0xc000,
+   MV_V2_TEMP_CTRL_SAMPLE  = 0x,
+   MV_V2_TEMP_CTRL_DISABLE = 0xc000,
+   MV_V2_TEMP  = 0xf08c,
+   MV_V2_TEMP_UNKNOWN  = 0x9600, /* unknown function */
+};
+
+struct mv3310_priv {
+   struct device *hwmon_dev;
+   char *hwmon_name;
 };
 
 static int mv3310_modify(struct phy_device *phydev, int devad, u16 reg,
@@ -60,17 +75,180 @@ static int mv3310_modify(struct phy_device *phydev, int 
devad, u16 reg,
return ret < 0 ? ret : 1;
 }
 
+#ifdef CONFIG_HWMON
+static umode_t mv3310_hwmon_is_visible(const void *data,
+  enum hwmon_sensor_types type,
+  u32 attr, int channel)
+{
+   if (type == hwmon_chip && attr == hwmon_chip_update_interval)
+   return 0444;
+   if (type == hwmon_temp && attr == hwmon_temp_input)
+   return 0444;
+   return 0;
+}
+
+static int mv3310_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+u32 attr, int channel, long *value)
+{
+   struct phy_device *phydev = dev_get_drvdata(dev);
+   int temp;
+
+   if (type == hwmon_chip && attr == hwmon_chip_update_interval) {
+   *value = MSEC_PER_SEC;
+   return 0;
+   }
+
+   if (type == hwmon_temp && attr == hwmon_temp_input) {
+   temp = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_TEMP);
+   if (temp < 0)
+   return temp;
+
+   *value = ((temp & 0xff) - 75) * 1000;
+
+   return 0;
+   }
+
+   return -EOPNOTSUPP;
+}
+
+static const struct hwmon_ops mv3310_hwmon_ops = {
+   .is_visible = mv3310_hwmon_is_visible,
+   .read = mv3310_hwmon_read,
+};
+
+static u32 mv3310_hwmon_chip_config[] = {
+   HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL,
+   0,
+};
+
+static const struct hwmon_channel_info mv3310_hwmon_chip = {
+   .type = hwmon_chip,
+   .config = mv3310_hwmon_chip_config,
+};
+
+static u32 mv3310_hwmon_temp_config[] = {
+   HWMON_T_INPUT,
+   0,
+};
+
+static const struct hwmon_channel_info mv3310_hwmon_temp = {
+   .type = hwmon_temp,
+   .config = mv3310_hwmon_temp_config,
+};
+
+static const struct hwmon_channel_info *mv3310_hwmon_info[] = {
+   _hwmon_chip,
+   _hwmon_temp,
+   NULL,
+};
+
+static const struct hwmon_chip_info mv3310_hwmon_chip_info = {
+   .ops = _hwmon_ops,
+   .info = mv3310_hwmon_info,
+};
+
+static int mv3310_hwmon_config(struct phy_device *phydev, bool enable)
+{
+   u16 val;
+   int ret;
+
+   ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_TEMP,
+   MV_V2_TEMP_UNKNOWN);
+   if (ret < 0)
+   return ret;
+
+   val = enable ? MV_V2_TEMP_CTRL_SAMPLE : MV_V2_TEMP_CTRL_DISABLE;
+   ret = mv3310_modify(phydev, MDIO_MMD_VEND2, MV_V2_TEMP_CTRL,
+   MV_V2_TEMP_CTRL_MASK, val);
+
+   return ret < 0 ? ret : 0;
+}
+
+static void mv3310_hwmon_disable(void *data)
+{
+   struct phy_device *phydev = data;
+
+   mv3310_hwmon_config(phydev, false);
+}
+
+static int mv3310_hwmon_probe(struct phy_device *phydev)
+{
+   struct device *dev = >mdio.dev;
+   struct mv3310_priv *priv = dev_get_drvdata(>mdio.dev);
+   int i, j, ret;
+
+   priv->hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
+   if (!priv->hwmon_name)
+   return -ENODEV;
+
+   for (i = j = 0; priv->hwmon_name[i]; i++) {
+   if (isalnum(priv->hwmon_name[i])) {
+   if (i != j)
+ 

Re: [PATCH v2 2/2] net: mvneta: improve suspend/resume

2018-03-30 Thread Russell King - ARM Linux
On Fri, Mar 30, 2018 at 06:36:15PM +0800, Jisheng Zhang wrote:
> Current suspend/resume implementation reuses the mvneta_open() and
> mvneta_close(), but it could be optimized to take only necessary
> actions during suspend/resume.
> 
> One obvious problem of current implementation is: after hundreds of
> system suspend/resume cycles, the resume of mvneta could fail due to
> fragmented dma coherent memory. After this patch, the non-necessary
> memory alloc/free is optimized out.

I don't think you've properly tested this.  Please ensure that you test
patches with the appropriate debug options enabled.

> @@ -4586,16 +4586,43 @@ static int mvneta_remove(struct platform_device *pdev)
>  #ifdef CONFIG_PM_SLEEP
>  static int mvneta_suspend(struct device *device)
>  {
> + int queue;
>   struct net_device *dev = dev_get_drvdata(device);
>   struct mvneta_port *pp = netdev_priv(dev);
>  
> - rtnl_lock();
> - if (netif_running(dev))
> - mvneta_stop(dev);
> - rtnl_unlock();
...
> + mvneta_stop_dev(pp);

You're removing the rtnl_lock() that I introduced in 3b8bc67413de
("net: mvneta: ensure PM paths take the rtnl lock") which is necessary
to provide phylink with consistent locking.  mvneta_stop_dev() calls
phylink_stop() which will check that the rtnl lock is held, and will
print a warning if it isn't.

Your patch will cause a regression here.

> +
> + for (queue = 0; queue < rxq_number; queue++) {
> + struct mvneta_rx_queue *rxq = >rxqs[queue];
> +
> + mvneta_rxq_drop_pkts(pp, rxq);
> + }
> +
> + for (queue = 0; queue < txq_number; queue++) {
> + struct mvneta_tx_queue *txq = >txqs[queue];
> +
> + mvneta_txq_hw_deinit(pp, txq);
> + }
> +
> +clean_exit:
>   netif_device_detach(dev);
>   clk_disable_unprepare(pp->clk_bus);
>   clk_disable_unprepare(pp->clk);
> +
>   return 0;
>  }
>  
> @@ -4604,7 +4631,7 @@ static int mvneta_resume(struct device *device)
>   struct platform_device *pdev = to_platform_device(device);
>   struct net_device *dev = dev_get_drvdata(device);
>   struct mvneta_port *pp = netdev_priv(dev);
> - int err;
> + int err, queue;
>  
>   clk_prepare_enable(pp->clk);
>   if (!IS_ERR(pp->clk_bus))
> @@ -4626,12 +4653,36 @@ static int mvneta_resume(struct device *device)
>   }
>  
>   netif_device_attach(dev);
> - rtnl_lock();
> - if (netif_running(dev)) {
> - mvneta_open(dev);
> - mvneta_set_rx_mode(dev);
...
>   }
> - rtnl_unlock();
...
> + mvneta_start_dev(pp);

Same applies here.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [EXT] [PATCH net-next v2 0/2] phylink: API changes

2018-03-29 Thread Russell King - ARM Linux
On Thu, Mar 29, 2018 at 05:58:43AM +, Yan Markman wrote:
> Hi Florian
> Please keep CCYelena Krivosheev <yel...@marvell.com>
> for changes with  drivers/net/ethernet/marvell/mvneta.c
> Thanks

We have a way to ensure such things happen - it's the MAINTAINERS
file.  Please use the established community methods rather than
sending emails asking for people to remember such quirks.  Thanks.

> Yan Markman
> Tel. 05-44732819
> 
> 
> -Original Message-
> From: Florian Fainelli [mailto:f.faine...@gmail.com] 
> Sent: Thursday, March 29, 2018 1:44 AM
> To: netdev@vger.kernel.org
> Cc: Florian Fainelli <f.faine...@gmail.com>; Thomas Petazzoni 
> <thomas.petazz...@free-electrons.com>; Andrew Lunn <and...@lunn.ch>; David S. 
> Miller <da...@davemloft.net>; Russell King <rmk+ker...@armlinux.org.uk>; open 
> list <linux-ker...@vger.kernel.org>; Antoine Tenart 
> <antoine.ten...@bootlin.com>; Yan Markman <ymark...@marvell.com>; Stefan 
> Chulski <stef...@marvell.com>; Maxime Chevallier 
> <maxime.chevall...@bootlin.com>; Miquel Raynal 
> <miquel.ray...@free-electrons.com>; Marcin Wojtas <m...@semihalf.com>
> Subject: [EXT] [PATCH net-next v2 0/2] phylink: API changes
> 
> External Email
> 
> --
> Hi all,
> 
> This patch series contains two API changes to PHYLINK which will later be 
> used by DSA to migrate to PHYLINK. Because these are API changes that impact 
> other outstanding work (e.g: MVPP2) I would rather get them included sooner 
> to minimize conflicts.
> 
> Thank you!
> 
> Changes in v2:
> 
> - added missing documentation to mac_link_{up,down} that the interface
>   must be configured in mac_config()
> 
> - added Russell's, Andrew's and my tags
> 
> Florian Fainelli (1):
>   net: phy: phylink: Provide PHY interface to mac_link_{up,down}
> 
> Russell King (1):
>   sfp/phylink: move module EEPROM ethtool access into netdev core
> ethtool
> 
>  drivers/net/ethernet/marvell/mvneta.c | 22 +++---
>  drivers/net/phy/phylink.c | 32 +++-
>  drivers/net/phy/sfp-bus.c |  6 ++
>  include/linux/netdevice.h |  3 +++
>  include/linux/phylink.h   | 17 +++--
>  net/core/ethtool.c|  7 +++
>  6 files changed, 29 insertions(+), 58 deletions(-)
> 
> --
> 2.14.1
> 

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [PATCH net-next 2/2] sfp/phylink: move module EEPROM ethtool access into netdev core ethtool

2018-03-28 Thread Russell King - ARM Linux
On Wed, Mar 28, 2018 at 12:03:39PM -0700, Florian Fainelli wrote:
> From: Russell King <rmk+ker...@armlinux.org.uk>
> 
> Provide a pointer to the SFP bus in struct net_device, so that the
> ethtool module EEPROM methods can access the SFP directly, rather
> than needing every user to provide a hook for it.
> 
> Signed-off-by: Russell King <rmk+ker...@armlinux.org.uk>

This probably ought to have your sign-off too as you're passing the
patch along rather than me submitting it directly.  DCO v1.1 (c)
seems to apply to this situation.

> ---
>  drivers/net/ethernet/marvell/mvneta.c | 18 --
>  drivers/net/phy/phylink.c | 28 
>  drivers/net/phy/sfp-bus.c |  6 ++
>  include/linux/netdevice.h |  3 +++
>  include/linux/phylink.h   |  3 ---
>  net/core/ethtool.c|  7 +++
>  6 files changed, 12 insertions(+), 53 deletions(-)
> 
> diff --git a/drivers/net/ethernet/marvell/mvneta.c 
> b/drivers/net/ethernet/marvell/mvneta.c
> index cd09bde55596..25ced96750bf 100644
> --- a/drivers/net/ethernet/marvell/mvneta.c
> +++ b/drivers/net/ethernet/marvell/mvneta.c
> @@ -4075,22 +4075,6 @@ static int mvneta_ethtool_set_wol(struct net_device 
> *dev,
>   return ret;
>  }
>  
> -static int mvneta_ethtool_get_module_info(struct net_device *dev,
> -   struct ethtool_modinfo *modinfo)
> -{
> - struct mvneta_port *pp = netdev_priv(dev);
> -
> - return phylink_ethtool_get_module_info(pp->phylink, modinfo);
> -}
> -
> -static int mvneta_ethtool_get_module_eeprom(struct net_device *dev,
> - struct ethtool_eeprom *ee, u8 *buf)
> -{
> - struct mvneta_port *pp = netdev_priv(dev);
> -
> - return phylink_ethtool_get_module_eeprom(pp->phylink, ee, buf);
> -}
> -
>  static int mvneta_ethtool_get_eee(struct net_device *dev,
> struct ethtool_eee *eee)
>  {
> @@ -4165,8 +4149,6 @@ static const struct ethtool_ops mvneta_eth_tool_ops = {
>   .set_link_ksettings = mvneta_ethtool_set_link_ksettings,
>   .get_wol= mvneta_ethtool_get_wol,
>   .set_wol= mvneta_ethtool_set_wol,
> - .get_module_info = mvneta_ethtool_get_module_info,
> - .get_module_eeprom = mvneta_ethtool_get_module_eeprom,
>   .get_eee= mvneta_ethtool_get_eee,
>   .set_eee= mvneta_ethtool_set_eee,
>  };
> diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
> index 9b1e4721ea3a..c582b2d7546c 100644
> --- a/drivers/net/phy/phylink.c
> +++ b/drivers/net/phy/phylink.c
> @@ -1250,34 +1250,6 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl,
>  }
>  EXPORT_SYMBOL_GPL(phylink_ethtool_set_pauseparam);
>  
> -int phylink_ethtool_get_module_info(struct phylink *pl,
> - struct ethtool_modinfo *modinfo)
> -{
> - int ret = -EOPNOTSUPP;
> -
> - WARN_ON(!lockdep_rtnl_is_held());
> -
> - if (pl->sfp_bus)
> - ret = sfp_get_module_info(pl->sfp_bus, modinfo);
> -
> - return ret;
> -}
> -EXPORT_SYMBOL_GPL(phylink_ethtool_get_module_info);
> -
> -int phylink_ethtool_get_module_eeprom(struct phylink *pl,
> -   struct ethtool_eeprom *ee, u8 *buf)
> -{
> - int ret = -EOPNOTSUPP;
> -
> - WARN_ON(!lockdep_rtnl_is_held());
> -
> - if (pl->sfp_bus)
> - ret = sfp_get_module_eeprom(pl->sfp_bus, ee, buf);
> -
> - return ret;
> -}
> -EXPORT_SYMBOL_GPL(phylink_ethtool_get_module_eeprom);
> -
>  /**
>   * phylink_ethtool_get_eee_err() - read the energy efficient ethernet error
>   *   counter
> diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
> index 3d4ff5d0d2a6..0381da78d228 100644
> --- a/drivers/net/phy/sfp-bus.c
> +++ b/drivers/net/phy/sfp-bus.c
> @@ -342,6 +342,7 @@ static int sfp_register_bus(struct sfp_bus *bus)
>   }
>   if (bus->started)
>   bus->socket_ops->start(bus->sfp);
> + bus->netdev->sfp_bus = bus;
>   bus->registered = true;
>   return 0;
>  }
> @@ -356,6 +357,7 @@ static void sfp_unregister_bus(struct sfp_bus *bus)
>   if (bus->phydev && ops && ops->disconnect_phy)
>   ops->disconnect_phy(bus->upstream);
>   }
> + bus->netdev->sfp_bus = NULL;
>   bus->registered = false;
>  }
>  
> @@ -371,8 +373,6 @@ static void sfp_unregister_bus(struct sfp_bus *bus)
>   */
>  int sfp_get_module_info(struct sfp_bus *bus, struct ethtool_modinfo *mo

Re: [PATCH net-next 1/2] net: phy: phylink: Provide PHY interface to mac_link_{up,down}

2018-03-28 Thread Russell King - ARM Linux
On Wed, Mar 28, 2018 at 12:03:38PM -0700, Florian Fainelli wrote:
> In preparation for having DSA transition entirely to PHYLINK, we need to pass 
> a
> PHY interface type to the mac_link_{up,down} callbacks because we may have to
> make decisions on that (e.g: turn on/off RGMII interfaces etc.). We do not 
> pass
> an entire phylink_link_state because not all parameters (pause, duplex etc.) 
> are
> defined when the link is down, only link and interface are.
> 
> Update mvneta accordingly since it currently implements phylink_mac_ops.
> 
> Signed-off-by: Florian Fainelli <f.faine...@gmail.com>

Similar comments to previous version wrt documentation, but...

Acked-by: Russell King <rmk+ker...@armlinux.org.uk>

> ---
>  drivers/net/ethernet/marvell/mvneta.c |  4 +++-
>  drivers/net/phy/phylink.c |  4 +++-
>  include/linux/phylink.h   | 10 --
>  3 files changed, 14 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/ethernet/marvell/mvneta.c 
> b/drivers/net/ethernet/marvell/mvneta.c
> index eaa4bb80f1c9..cd09bde55596 100644
> --- a/drivers/net/ethernet/marvell/mvneta.c
> +++ b/drivers/net/ethernet/marvell/mvneta.c
> @@ -3396,7 +3396,8 @@ static void mvneta_set_eee(struct mvneta_port *pp, bool 
> enable)
>   mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi_ctl1);
>  }
>  
> -static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode)
> +static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode,
> +  phy_interface_t interface)
>  {
>   struct mvneta_port *pp = netdev_priv(ndev);
>   u32 val;
> @@ -3415,6 +3416,7 @@ static void mvneta_mac_link_down(struct net_device 
> *ndev, unsigned int mode)
>  }
>  
>  static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode,
> +phy_interface_t interface,
>  struct phy_device *phy)
>  {
>   struct mvneta_port *pp = netdev_priv(ndev);
> diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
> index 51a011a349fe..9b1e4721ea3a 100644
> --- a/drivers/net/phy/phylink.c
> +++ b/drivers/net/phy/phylink.c
> @@ -470,10 +470,12 @@ static void phylink_resolve(struct work_struct *w)
>   if (link_state.link != netif_carrier_ok(ndev)) {
>   if (!link_state.link) {
>   netif_carrier_off(ndev);
> - pl->ops->mac_link_down(ndev, pl->link_an_mode);
> + pl->ops->mac_link_down(ndev, pl->link_an_mode,
> +pl->phy_state.interface);
>   netdev_info(ndev, "Link is Down\n");
>   } else {
>   pl->ops->mac_link_up(ndev, pl->link_an_mode,
> +  pl->phy_state.interface,
>pl->phydev);
>  
>   netif_carrier_on(ndev);
> diff --git a/include/linux/phylink.h b/include/linux/phylink.h
> index bd137c273d38..f29a40947de9 100644
> --- a/include/linux/phylink.h
> +++ b/include/linux/phylink.h
> @@ -73,8 +73,10 @@ struct phylink_mac_ops {
>   void (*mac_config)(struct net_device *ndev, unsigned int mode,
>  const struct phylink_link_state *state);
>   void (*mac_an_restart)(struct net_device *ndev);
> - void (*mac_link_down)(struct net_device *ndev, unsigned int mode);
> + void (*mac_link_down)(struct net_device *ndev, unsigned int mode,
> +   phy_interface_t interface);
>   void (*mac_link_up)(struct net_device *ndev, unsigned int mode,
> + phy_interface_t interface,
>   struct phy_device *phy);
>  };
>  
> @@ -161,17 +163,20 @@ void mac_an_restart(struct net_device *ndev);
>   * mac_link_down() - take the link down
>   * @ndev: a pointer to a  net_device for the MAC.
>   * @mode: link autonegotiation mode
> + * @interface: link  phy_interface_t mode
>   *
>   * If @mode is not an in-band negotiation mode (as defined by
>   * phylink_autoneg_inband()), force the link down and disable any
>   * Energy Efficient Ethernet MAC configuration.
>   */
> -void mac_link_down(struct net_device *ndev, unsigned int mode);
> +void mac_link_down(struct net_device *ndev, unsigned int mode,
> +phy_interface_t interface);
>  
>  /**
>   * mac_link_up() - allow the link to come up
>   * @ndev: a pointer to a  net_device for the MAC.
>   * @mode: link autonegotiation mode
> + * @interface: link  phy_interface_t mode
>   * @phy: any attached phy
>   *
>   * If @mode is not an in-band nego

Re: [PATCH] sfp: allow cotsworks modules

2018-03-28 Thread Russell King - ARM Linux
On Wed, Mar 28, 2018 at 09:19:01AM -0700, Joe Perches wrote:
> On Wed, 2018-03-28 at 11:41 +0100, Russell King - ARM Linux wrote:
> > On Wed, Mar 28, 2018 at 03:33:57AM -0700, Joe Perches wrote:
> > > On Wed, 2018-03-28 at 11:18 +0100, Russell King wrote:
> > > > Cotsworks modules fail the checksums - it appears that Cotsworks
> > > > reprograms the EEPROM at the end of production with the final product
> > > > information (serial, date code, and exact part number for module
> > > > options) and fails to update the checksum.
> > > 
> > > trivia:
> > > 
> > > > diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
> > > 
> > > []
> > > > @@ -574,23 +575,43 @@ static int sfp_sm_mod_probe(struct sfp *sfp)
> > > 
> > > []
> > > > +   if (cotsworks) {
> > > > +   dev_warn(sfp->dev,
> > > > +"EEPROM base structure checksum 
> > > > failure (0x%02x != 0x%02x)\n",
> > > > +check, id.base.cc_base);
> > > > +   } else {
> > > > +   dev_err(sfp->dev,
> > > > +   "EEPROM base structure checksum 
> > > > failure: 0x%02x != 0x%02x\n",
> > > 
> > > It'd be better to move this above the if and
> > > use only a single format string instead of
> > > using 2 slightly different formats.
> > 
> > No.  I think you've missed the fact that one is a _warning_ the other is
> > an _error_ and they are emitted at the appropriate severity.  It's not
> > just that the format strings are slightly different.
> 
> Right.  Still nicer to use the same formats.

I'll stick a "Warning:" and "Error:" tag before them if you really
want the rest of the message to be identically formatted - otherwise,
when seeing reports from people's dmesg, there will be nothing to
indicate which message was printed.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [PATCH] sfp: allow cotsworks modules

2018-03-28 Thread Russell King - ARM Linux
On Wed, Mar 28, 2018 at 03:33:57AM -0700, Joe Perches wrote:
> On Wed, 2018-03-28 at 11:18 +0100, Russell King wrote:
> > Cotsworks modules fail the checksums - it appears that Cotsworks
> > reprograms the EEPROM at the end of production with the final product
> > information (serial, date code, and exact part number for module
> > options) and fails to update the checksum.
> 
> trivia:
> 
> > diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
> []
> > @@ -574,23 +575,43 @@ static int sfp_sm_mod_probe(struct sfp *sfp)
> []
> > +   if (cotsworks) {
> > +   dev_warn(sfp->dev,
> > +"EEPROM base structure checksum failure 
> > (0x%02x != 0x%02x)\n",
> > +check, id.base.cc_base);
> > +   } else {
> > +   dev_err(sfp->dev,
> > +   "EEPROM base structure checksum failure: 0x%02x 
> > != 0x%02x\n",
> 
> It'd be better to move this above the if and
> use only a single format string instead of
> using 2 slightly different formats.

No.  I think you've missed the fact that one is a _warning_ the other is
an _error_ and they are emitted at the appropriate severity.  It's not
just that the format strings are slightly different.

> 
> > +   check, id.base.cc_base);
> > +   print_hex_dump(KERN_ERR, "sfp EE: ", DUMP_PREFIX_OFFSET,
> > +  16, 1, , sizeof(id), true);
> > +   return -EINVAL;
> > +   }
> > }
> >  
> > check = sfp_check(, sizeof(id.ext) - 1);
> > if (check != id.ext.cc_ext) {
> > -   dev_err(sfp->dev,
> > -   "EEPROM extended structure checksum failure: 0x%02x\n",
> > -   check);
> > -   memset(, 0, sizeof(id.ext));
> > +   if (cotsworks) {
> > +   dev_warn(sfp->dev,
> > +"EEPROM extended structure checksum failure 
> > (0x%02x != 0x%02x)\n",
> > +check, id.ext.cc_ext);
> > +   } else {
> > +   dev_err(sfp->dev,
> > +   "EEPROM extended structure checksum failure: 
> > 0x%02x != 0x%02x\n",
> > +   check, id.ext.cc_ext);
> 
> 
> here too

Same applies.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


[PATCH] net: phy: marvell10g: add thermal hwmon device

2018-03-28 Thread Russell King
Add a thermal monitoring device for the Marvell 88x3310, which updates
once a second.  We also need to hook into the suspend/resume mechanism
to ensure that the thermal monitoring is reconfigured when we resume.

Suggested-by: Andrew Lunn <and...@lunn.ch>
Signed-off-by: Russell King <rmk+ker...@armlinux.org.uk>
---
 drivers/net/phy/marvell10g.c | 184 ++-
 1 file changed, 182 insertions(+), 2 deletions(-)

diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 8a0bd98fdec7..db9d66781da6 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -21,8 +21,10 @@
  * If both the fiber and copper ports are connected, the first to gain
  * link takes priority and the other port is completely locked out.
  */
-#include 
+#include 
+#include 
 #include 
+#include 
 
 enum {
MV_PCS_BASE_T   = 0x,
@@ -40,6 +42,19 @@ enum {
 */
MV_AN_CTRL1000  = 0x8000, /* 1000base-T control register */
MV_AN_STAT1000  = 0x8001, /* 1000base-T status register */
+
+   /* Vendor2 MMD registers */
+   MV_V2_TEMP_CTRL = 0xf08a,
+   MV_V2_TEMP_CTRL_MASK= 0xc000,
+   MV_V2_TEMP_CTRL_SAMPLE  = 0x,
+   MV_V2_TEMP_CTRL_DISABLE = 0xc000,
+   MV_V2_TEMP  = 0xf08c,
+   MV_V2_TEMP_UNKNOWN  = 0x9600, /* unknown function */
+};
+
+struct mv3310_priv {
+   struct device *hwmon_dev;
+   char *hwmon_name;
 };
 
 static int mv3310_modify(struct phy_device *phydev, int devad, u16 reg,
@@ -60,17 +75,180 @@ static int mv3310_modify(struct phy_device *phydev, int 
devad, u16 reg,
return ret < 0 ? ret : 1;
 }
 
+#ifdef CONFIG_HWMON
+static umode_t mv3310_hwmon_is_visible(const void *data,
+  enum hwmon_sensor_types type,
+  u32 attr, int channel)
+{
+   if (type == hwmon_chip && attr == hwmon_chip_update_interval)
+   return 0444;
+   if (type == hwmon_temp && attr == hwmon_temp_input)
+   return 0444;
+   return 0;
+}
+
+static int mv3310_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+u32 attr, int channel, long *value)
+{
+   struct phy_device *phydev = dev_get_drvdata(dev);
+   int temp;
+
+   if (type == hwmon_chip && attr == hwmon_chip_update_interval) {
+   *value = MSEC_PER_SEC;
+   return 0;
+   }
+
+   if (type == hwmon_temp && attr == hwmon_temp_input) {
+   temp = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_TEMP);
+   if (temp < 0)
+   return temp;
+
+   *value = ((temp & 0xff) - 75) * 1000;
+
+   return 0;
+   }
+
+   return -EOPNOTSUPP;
+}
+
+static const struct hwmon_ops mv3310_hwmon_ops = {
+   .is_visible = mv3310_hwmon_is_visible,
+   .read = mv3310_hwmon_read,
+};
+
+static u32 mv3310_hwmon_chip_config[] = {
+   HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL,
+   0,
+};
+
+static const struct hwmon_channel_info mv3310_hwmon_chip = {
+   .type = hwmon_chip,
+   .config = mv3310_hwmon_chip_config,
+};
+
+static u32 mv3310_hwmon_temp_config[] = {
+   HWMON_T_INPUT,
+   0,
+};
+
+static const struct hwmon_channel_info mv3310_hwmon_temp = {
+   .type = hwmon_temp,
+   .config = mv3310_hwmon_temp_config,
+};
+
+static const struct hwmon_channel_info *mv3310_hwmon_info[] = {
+   _hwmon_chip,
+   _hwmon_temp,
+   NULL,
+};
+
+static const struct hwmon_chip_info mv3310_hwmon_chip_info = {
+   .ops = _hwmon_ops,
+   .info = mv3310_hwmon_info,
+};
+
+static int mv3310_hwmon_config(struct phy_device *phydev, bool enable)
+{
+   u16 val;
+   int ret;
+
+   ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_TEMP,
+   MV_V2_TEMP_UNKNOWN);
+   if (ret < 0)
+   return ret;
+
+   val = enable ? MV_V2_TEMP_CTRL_SAMPLE : MV_V2_TEMP_CTRL_DISABLE;
+   ret = mv3310_modify(phydev, MDIO_MMD_VEND2, MV_V2_TEMP_CTRL,
+   MV_V2_TEMP_CTRL_MASK, val);
+
+   return ret < 0 ? ret : 0;
+}
+
+static void mv3310_hwmon_disable(void *data)
+{
+   struct phy_device *phydev = data;
+
+   mv3310_hwmon_config(phydev, false);
+}
+
+static int mv3310_hwmon_probe(struct phy_device *phydev)
+{
+   struct device *dev = >mdio.dev;
+   struct mv3310_priv *priv = dev_get_drvdata(>mdio.dev);
+   int i, j, ret;
+
+   priv->hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
+   if (!priv->hwmon_name)
+   return -ENODEV;
+
+   for (i = j = 0; priv->hwmon_name[i]; i++) {
+   if (isalnum(priv->hwmon_name[i])) {
+   if (i != j)
+   priv->hwmon_name[j] = priv->hwmon_name[i];

[PATCH] sfp: allow cotsworks modules

2018-03-28 Thread Russell King
Cotsworks modules fail the checksums - it appears that Cotsworks
reprograms the EEPROM at the end of production with the final product
information (serial, date code, and exact part number for module
options) and fails to update the checksum.

Work around this by detecting the Cotsworks name in the manufacturer
field, and reducing the checksum failures to warnings rather than a
hard error.

Signed-off-by: Russell King <rmk+ker...@armlinux.org.uk>
---
 drivers/net/phy/sfp.c | 41 +++--
 1 file changed, 31 insertions(+), 10 deletions(-)

diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index 83bf4959b043..4ab6e9a50bbe 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -560,6 +560,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp)
 {
/* SFP module inserted - read I2C data */
struct sfp_eeprom_id id;
+   bool cotsworks;
u8 check;
int ret;
 
@@ -574,23 +575,43 @@ static int sfp_sm_mod_probe(struct sfp *sfp)
return -EAGAIN;
}
 
+   /* Cotsworks do not seem to update the checksums when they
+* do the final programming with the final module part number,
+* serial number and date code.
+*/
+   cotsworks = !memcmp(id.base.vendor_name, "COTSWORKS   ", 16);
+
/* Validate the checksum over the base structure */
check = sfp_check(, sizeof(id.base) - 1);
if (check != id.base.cc_base) {
-   dev_err(sfp->dev,
-   "EEPROM base structure checksum failure: 0x%02x\n",
-   check);
-   print_hex_dump(KERN_ERR, "sfp EE: ", DUMP_PREFIX_OFFSET,
-  16, 1, , sizeof(id.base) - 1, true);
-   return -EINVAL;
+   if (cotsworks) {
+   dev_warn(sfp->dev,
+"EEPROM base structure checksum failure 
(0x%02x != 0x%02x)\n",
+check, id.base.cc_base);
+   } else {
+   dev_err(sfp->dev,
+   "EEPROM base structure checksum failure: 0x%02x 
!= 0x%02x\n",
+   check, id.base.cc_base);
+   print_hex_dump(KERN_ERR, "sfp EE: ", DUMP_PREFIX_OFFSET,
+  16, 1, , sizeof(id), true);
+   return -EINVAL;
+   }
}
 
check = sfp_check(, sizeof(id.ext) - 1);
if (check != id.ext.cc_ext) {
-   dev_err(sfp->dev,
-   "EEPROM extended structure checksum failure: 0x%02x\n",
-   check);
-   memset(, 0, sizeof(id.ext));
+   if (cotsworks) {
+   dev_warn(sfp->dev,
+"EEPROM extended structure checksum failure 
(0x%02x != 0x%02x)\n",
+check, id.ext.cc_ext);
+   } else {
+   dev_err(sfp->dev,
+   "EEPROM extended structure checksum failure: 
0x%02x != 0x%02x\n",
+   check, id.ext.cc_ext);
+   print_hex_dump(KERN_ERR, "sfp EE: ", DUMP_PREFIX_OFFSET,
+  16, 1, , sizeof(id), true);
+   memset(, 0, sizeof(id.ext));
+   }
}
 
sfp->id = id;
-- 
2.7.4



Re: [PATCH net-next 2/4] net: phy: phylink: Provide PHY interface to mac_link_{up,down}

2018-03-28 Thread Russell King - ARM Linux
On Sun, Mar 18, 2018 at 11:52:44AM -0700, Florian Fainelli wrote:
> In preparation for having DSA transition entirely to PHYLINK, we need to pass 
> a
> PHY interface type to the mac_link_{up,down} callbacks because we may have to
> make decisions on that (e.g: turn on/off RGMII interfaces etc.). We do not 
> pass
> an entire phylink_link_state because not all parameters (pause, duplex etc.) 
> are
> defined when the link is down, only link and interface are.

If we're going to make this change, we ought to decide whether David
should pick this up for the coming merge window or not independently
of the remaining patches - there are other users of phylink in the
pipeline (bootlin are working on mvpp2 support, so this will be a
minor source of build error pain for folk.)

To that end,

Acked-by: Russell King <rmk+ker...@armlinux.org.uk>

However, the documentation probably ought to make it clear that the
configuration of the interface mode of the MAC should always happen
in the mac_config() callback, not in the mac_link_*() functions.

Thanks.

> Update mvneta accordingly since it currently implements phylink_mac_ops.
> 
> Signed-off-by: Florian Fainelli <f.faine...@gmail.com>
> ---
>  drivers/net/ethernet/marvell/mvneta.c |  4 +++-
>  drivers/net/phy/phylink.c |  6 +-
>  include/linux/phylink.h   | 10 --
>  3 files changed, 16 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/ethernet/marvell/mvneta.c 
> b/drivers/net/ethernet/marvell/mvneta.c
> index 25e9a551cc8c..60de9b8d62c2 100644
> --- a/drivers/net/ethernet/marvell/mvneta.c
> +++ b/drivers/net/ethernet/marvell/mvneta.c
> @@ -3396,7 +3396,8 @@ static void mvneta_set_eee(struct mvneta_port *pp, bool 
> enable)
>   mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi_ctl1);
>  }
>  
> -static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode)
> +static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode,
> +  phy_interface_t interface)
>  {
>   struct mvneta_port *pp = netdev_priv(ndev);
>   u32 val;
> @@ -3415,6 +3416,7 @@ static void mvneta_mac_link_down(struct net_device 
> *ndev, unsigned int mode)
>  }
>  
>  static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode,
> +phy_interface_t interface,
>  struct phy_device *phy)
>  {
>   struct mvneta_port *pp = netdev_priv(ndev);
> diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
> index 51a011a349fe..cef3c1356a8c 100644
> --- a/drivers/net/phy/phylink.c
> +++ b/drivers/net/phy/phylink.c
> @@ -423,8 +423,10 @@ static void phylink_resolve(struct work_struct *w)
>   if (pl->phylink_disable_state) {
>   pl->mac_link_dropped = false;
>   link_state.link = false;
> + link_state.interface = pl->phy_state.interface;
>   } else if (pl->mac_link_dropped) {
>   link_state.link = false;
> + link_state.interface = pl->phy_state.interface;
>   } else {
>   switch (pl->link_an_mode) {
>   case MLO_AN_PHY:
> @@ -470,10 +472,12 @@ static void phylink_resolve(struct work_struct *w)
>   if (link_state.link != netif_carrier_ok(ndev)) {
>   if (!link_state.link) {
>   netif_carrier_off(ndev);
> - pl->ops->mac_link_down(ndev, pl->link_an_mode);
> + pl->ops->mac_link_down(ndev, pl->link_an_mode,
> +pl->phy_state.interface);
>   netdev_info(ndev, "Link is Down\n");
>   } else {
>   pl->ops->mac_link_up(ndev, pl->link_an_mode,
> +  pl->phy_state.interface,
>pl->phydev);
>  
>   netif_carrier_on(ndev);
> diff --git a/include/linux/phylink.h b/include/linux/phylink.h
> index bd137c273d38..f29a40947de9 100644
> --- a/include/linux/phylink.h
> +++ b/include/linux/phylink.h
> @@ -73,8 +73,10 @@ struct phylink_mac_ops {
>   void (*mac_config)(struct net_device *ndev, unsigned int mode,
>  const struct phylink_link_state *state);
>   void (*mac_an_restart)(struct net_device *ndev);
> - void (*mac_link_down)(struct net_device *ndev, unsigned int mode);
> + void (*mac_link_down)(struct net_device *ndev, unsigned int mode,
> +   phy_interface_t interface);
>   void (*mac_link_up)(struct net_device *ndev, unsigned int mode,
> + phy_interface_t interface,
> 

Re: [PATCH net-next 3/4] net: dsa: Plug in PHYLINK support

2018-03-19 Thread Russell King - ARM Linux
On Mon, Mar 19, 2018 at 10:59:55AM -0700, Florian Fainelli wrote:
> Hi Andrew,
> 
> On 03/18/2018 12:19 PM, Andrew Lunn wrote:
> >> +static int dsa_slave_nway_reset(struct net_device *dev)
> >> +{
> >> +  struct dsa_port *dp = dsa_slave_to_port(dev);
> >> +
> >> +  return phylink_ethtool_nway_reset(dp->pl);
> >> +}
> > 
> > Hi Florian
> > 
> > I've seen in one of Russells trees a patch to put a phylink into
> > net_device. That would make a generic slave_nway_reset() possible, and
> > a few others as well. Maybe it makes sense to pull in that patch?
> 
> To make this generic, we would have to have net_device carry a reference
> to a phylink instance, which I would rather not do. Were you possibly
> referring to this patch set:
> 
> http://git.armlinux.org.uk/cgit/linux-arm.git/commit/?h=phy=4eda3b76573473d811bc80a6f0e5a2e06dd76bf6
> 
> in which case I think it was discussed and rejected (that was my
> recollection).

Unfortunately, that rejection kind'a prevents SFP support on a PHY,
which is why I'm not pushing the 3310 patches (I don't have any other
solution to this problem at the moment as PHYLIB gets in the way of
knowing what state the network interface is in.)

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


Re: [EXT] Re: [PATCH net-next 02/10] net: phy: phylink: allow 10GKR interface to use in-band negotiation

2018-03-19 Thread Russell King - ARM Linux
On Mon, Mar 19, 2018 at 01:19:24PM +, Stefan Chulski wrote:
> 
> 
> > -Original Message-
> > From: Andrew Lunn [mailto:and...@lunn.ch]
> > Sent: Monday, March 19, 2018 3:08 PM
> > To: Stefan Chulski <stef...@marvell.com>
> > Cc: Antoine Tenart <antoine.ten...@bootlin.com>; Russell King - ARM Linux
> > <li...@armlinux.org.uk>; da...@davemloft.net; kis...@ti.com;
> > gregory.clem...@bootlin.com; ja...@lakedaemon.net;
> > sebastian.hesselba...@gmail.com; netdev@vger.kernel.org; linux-
> > ker...@vger.kernel.org; thomas.petazz...@bootlin.com;
> > maxime.chevall...@bootlin.com; miquel.ray...@bootlin.com; Nadav Haklai
> > <nad...@marvell.com>; Yan Markman <ymark...@marvell.com>;
> > m...@semihalf.com; linux-arm-ker...@lists.infradead.org
> > Subject: Re: [EXT] Re: [PATCH net-next 02/10] net: phy: phylink: allow 10GKR
> > interface to use in-band negotiation
> > 
> > > > If they don't have PHYs, how are the connected to the outside world?
> > > >
> > > >Andrew
> > >
> > > By external SFP or direct attached cable.
> > 
> > Maybe i'm missing something, but don't you just need to add an SFP device
> > in the device tree. The SFP code and PHYLINK will work together, query what
> > the SFP module is, use the GPIOs to determine link up/down and module
> > present, and tell the MAC how to configure the MAC-SFP link?
> > 
> >  Andrew
> 
> phylink pool SFP loss signal to determine link up/down?

No.  Phylink was merged along with SFP cage support, which includes a DT
description for SFP cages, including the various signals for the cage.

The SFP layer will take care of monitoring the cage and conveying state
information to Phylink.

Phylink's job is to work out how any SFP module, PHY and MAC should be
configured and to determine the link state based on information supplied
by or requested from each depending on the configured state.

Please do not try and support SFP cages as fixed links.  They aren't,
and such an approach will always have sub-standard link state monitoring.

In an optical setup, the SFP LOS signal just indicates whether there is
sufficient optical power present at the receiver.  It doesn't indicate
whether there is a valid signal there, or whether the chip at the other
end of the serdes link can decode the signal.  That has to come from the
upstream chip, whether it be a PHY or a MAC.

SFP optical modules do not perform protocol validation - they merely
convert the serdes electrical signal into a light signal and back again,
with varying amounts of monitoring on board.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


  1   2   3   4   5   6   7   >