* [PATCH net-next 1/2] net: dsa: lan9303: phy_addr_sel_strap rename and retype
From: Egil Hjelmeland @ 2017-12-29 12:38 UTC (permalink / raw)
To: andrew, vivien.didelot, f.fainelli, netdev, linux-kernel; +Cc: Egil Hjelmeland
In-Reply-To: <20171229123824.28452-1-privat@egil-hjelmeland.no>
chip->phy_addr_sel_strap is declared as a bool, but is also used as an
integer address base.
Rename 'phy_addr_sel_strap' to 'phy_addr_base', and change type to int.
Signed-off-by: Egil Hjelmeland <privat@egil-hjelmeland.no>
---
drivers/net/dsa/lan9303-core.c | 20 ++++++++++----------
include/linux/dsa/lan9303.h | 2 +-
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c
index 944901f03f8b..3088cdc5d205 100644
--- a/drivers/net/dsa/lan9303-core.c
+++ b/drivers/net/dsa/lan9303-core.c
@@ -479,7 +479,8 @@ static int lan9303_detect_phy_setup(struct lan9303 *chip)
{
int reg;
- /* depending on the 'phy_addr_sel_strap' setting, the three phys are
+ /* Calculate chip->phy_addr_base:
+ * Depending on the 'phy_addr_sel_strap' setting, the three phys are
* using IDs 0-1-2 or IDs 1-2-3. We cannot read back the
* 'phy_addr_sel_strap' setting directly, so we need a test, which
* configuration is active:
@@ -495,12 +496,12 @@ static int lan9303_detect_phy_setup(struct lan9303 *chip)
}
if ((reg != 0) && (reg != 0xffff))
- chip->phy_addr_sel_strap = 1;
+ chip->phy_addr_base = 1;
else
- chip->phy_addr_sel_strap = 0;
+ chip->phy_addr_base = 0;
dev_dbg(chip->dev, "Phy setup '%s' detected\n",
- chip->phy_addr_sel_strap ? "1-2-3" : "0-1-2");
+ chip->phy_addr_base ? "1-2-3" : "0-1-2");
return 0;
}
@@ -1019,7 +1020,7 @@ static int lan9303_get_sset_count(struct dsa_switch *ds)
static int lan9303_phy_read(struct dsa_switch *ds, int phy, int regnum)
{
struct lan9303 *chip = ds->priv;
- int phy_base = chip->phy_addr_sel_strap;
+ int phy_base = chip->phy_addr_base;
if (phy == phy_base)
return lan9303_virt_phy_reg_read(chip, regnum);
@@ -1033,7 +1034,7 @@ static int lan9303_phy_write(struct dsa_switch *ds, int phy, int regnum,
u16 val)
{
struct lan9303 *chip = ds->priv;
- int phy_base = chip->phy_addr_sel_strap;
+ int phy_base = chip->phy_addr_base;
if (phy == phy_base)
return lan9303_virt_phy_reg_write(chip, regnum, val);
@@ -1070,7 +1071,7 @@ static void lan9303_adjust_link(struct dsa_switch *ds, int port,
res = lan9303_phy_write(ds, port, MII_BMCR, ctl);
- if (port == chip->phy_addr_sel_strap) {
+ if (port == chip->phy_addr_base) {
/* Virtual Phy: Remove Turbo 200Mbit mode */
lan9303_read(chip->regmap, LAN9303_VIRT_SPECIAL_CTRL, &ctl);
@@ -1094,8 +1095,7 @@ static void lan9303_port_disable(struct dsa_switch *ds, int port,
struct lan9303 *chip = ds->priv;
lan9303_disable_processing_port(chip, port);
- lan9303_phy_write(ds, chip->phy_addr_sel_strap + port,
- MII_BMCR, BMCR_PDOWN);
+ lan9303_phy_write(ds, chip->phy_addr_base + port, MII_BMCR, BMCR_PDOWN);
}
static int lan9303_port_bridge_join(struct dsa_switch *ds, int port,
@@ -1289,7 +1289,7 @@ static int lan9303_register_switch(struct lan9303 *chip)
chip->ds->priv = chip;
chip->ds->ops = &lan9303_switch_ops;
- chip->ds->phys_mii_mask = chip->phy_addr_sel_strap ? 0xe : 0x7;
+ chip->ds->phys_mii_mask = chip->phy_addr_base ? 0xe : 0x7;
return dsa_register_switch(chip->ds);
}
diff --git a/include/linux/dsa/lan9303.h b/include/linux/dsa/lan9303.h
index b6514c29563f..b4f22112ba75 100644
--- a/include/linux/dsa/lan9303.h
+++ b/include/linux/dsa/lan9303.h
@@ -23,7 +23,7 @@ struct lan9303 {
struct regmap_irq_chip_data *irq_data;
struct gpio_desc *reset_gpio;
u32 reset_duration; /* in [ms] */
- bool phy_addr_sel_strap;
+ int phy_addr_base;
struct dsa_switch *ds;
struct mutex indirect_mutex; /* protect indexed register access */
struct mutex alr_mutex; /* protect ALR access */
--
2.14.1
^ permalink raw reply related
* [PATCH net-next 0/2] net: dsa: lan9303: phy_addr_sel_strap rename and retype
From: Egil Hjelmeland @ 2017-12-29 12:38 UTC (permalink / raw)
To: andrew, vivien.didelot, f.fainelli, netdev, linux-kernel; +Cc: Egil Hjelmeland
Non functional cleanups involving chip->phy_addr_sel_strap.
As promised in https://lkml.org/lkml/2017/11/6/273
Egil Hjelmeland (2):
net: dsa: lan9303: phy_addr_sel_strap rename and retype
net: dsa: lan9303: Adjust phy_addr_base expressions
drivers/net/dsa/lan9303-core.c | 24 ++++++++++++------------
include/linux/dsa/lan9303.h | 2 +-
2 files changed, 13 insertions(+), 13 deletions(-)
--
2.14.1
^ permalink raw reply
* Re: [PATCH bpf-next v3 3/3] libbpf: add missing SPDX-License-Identifier
From: Philippe Ombredanne @ 2017-12-29 12:35 UTC (permalink / raw)
To: Eric Leblond; +Cc: daniel, Alexei Starovoitov, netdev, LKML
In-Reply-To: <20171228080437.16933-4-eric@regit.org>
Eric,
On Thu, Dec 28, 2017 at 9:04 AM, Eric Leblond <eric@regit.org> wrote:
> Signed-off-by: Eric Leblond <eric@regit.org>
> Acked-by: Alexei Starovoitov <ast@kernel.org>
> ---
> tools/lib/bpf/bpf.c | 2 ++
> tools/lib/bpf/bpf.h | 2 ++
> tools/lib/bpf/libbpf.c | 2 ++
> tools/lib/bpf/libbpf.h | 2 ++
> 4 files changed, 8 insertions(+)
>
> diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> index cdfabbe118cc..9e53dbbca2bd 100644
> --- a/tools/lib/bpf/bpf.c
> +++ b/tools/lib/bpf/bpf.c
> @@ -1,3 +1,5 @@
> +/* SPDX-License-Identifier: LGPL-2.1 */
In a .c file these should using C++-style comments as in //.
As requested by Linus, discussed on list and documented in Thomas doc patches.
> +
> /*
> * common eBPF ELF operations.
> *
> diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
> index 9f44c196931e..8d18fb73d7fb 100644
> --- a/tools/lib/bpf/bpf.h
> +++ b/tools/lib/bpf/bpf.h
> @@ -1,3 +1,5 @@
> +/* SPDX-License-Identifier: LGPL-2.1 */
And this is correct for a .h
> +
> /*
> * common eBPF ELF operations.
> *
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 5fe8aaa2123e..878e240a681b 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -1,3 +1,5 @@
> +/* SPDX-License-Identifier: LGPL-2.1 */
Use // here.
> +
> /*
> * Common eBPF ELF object loading operations.
> *
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index e42f96900318..f85906533cdd 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -1,3 +1,5 @@
> +/* SPDX-License-Identifier: LGPL-2.1 */
> +
> /*
> * Common eBPF ELF object loading operations.
> *
> --
> 2.15.1
>
--
Cordially
Philippe Ombredanne
^ permalink raw reply
* Re: [PATCH net-next 2/2] tuntap: XDP transmission
From: Jesper Dangaard Brouer @ 2017-12-29 12:32 UTC (permalink / raw)
To: Jason Wang; +Cc: brouer, netdev, linux-kernel, mst
In-Reply-To: <1514541604-12728-3-git-send-email-jasowang@redhat.com>
On Fri, 29 Dec 2017 18:00:04 +0800
Jason Wang <jasowang@redhat.com> wrote:
> This patch implements XDP transmission for TAP. Since we can't create
> new queues for TAP during XDP set, exist ptr_ring was reused for
> queuing XDP buffers. To differ xdp_buff from sk_buff, TUN_XDP_FLAG
> (0x1ULL) was encoded into lowest bit of xpd_buff pointer during
> ptr_ring_produce, and was decoded during consuming. XDP metadata was
> stored in the headroom of the packet which should work in most of
> cases since driver usually reserve enough headroom. Very minor changes
> were done for vhost_net: it just need to peek the length depends on
> the type of pointer.
>
> Tests was done on two Intel E5-2630 2.40GHz machines connected back to
> back through two 82599ES. Traffic were generated through MoonGen and
> testpmd(rxonly) in guest reports 2.97Mpps when xdp_redirect_map is
> doing redirection from ixgbe to TAP.
IMHO a performance measurement without something to compare against is
useless. What was the performance before?
> Cc: Jesper Dangaard Brouer <brouer@redhat.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/net/tun.c | 205 ++++++++++++++++++++++++++++++++++++++++---------
> drivers/vhost/net.c | 13 +++-
> include/linux/if_tun.h | 17 ++++
> 3 files changed, 197 insertions(+), 38 deletions(-)
>
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index 2c89efe..be6d993 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -240,6 +240,24 @@ struct tun_struct {
> struct tun_steering_prog __rcu *steering_prog;
> };
>
> +bool tun_is_xdp_buff(void *ptr)
> +{
> + return (unsigned long)ptr & TUN_XDP_FLAG;
> +}
> +EXPORT_SYMBOL(tun_is_xdp_buff);
> +
> +void *tun_xdp_to_ptr(void *ptr)
> +{
> + return (void *)((unsigned long)ptr | TUN_XDP_FLAG);
> +}
> +EXPORT_SYMBOL(tun_xdp_to_ptr);
> +
> +void *tun_ptr_to_xdp(void *ptr)
> +{
> + return (void *)((unsigned long)ptr & ~TUN_XDP_FLAG);
> +}
> +EXPORT_SYMBOL(tun_ptr_to_xdp);
> +
> static int tun_napi_receive(struct napi_struct *napi, int budget)
> {
> struct tun_file *tfile = container_of(napi, struct tun_file, napi);
> @@ -630,12 +648,25 @@ static struct tun_struct *tun_enable_queue(struct tun_file *tfile)
> return tun;
> }
>
> +static void tun_ptr_free(void *ptr)
> +{
> + if (!ptr)
> + return;
> + if (tun_is_xdp_buff(ptr)) {
> + struct xdp_buff *xdp = tun_ptr_to_xdp(ptr);
> +
> + put_page(virt_to_head_page(xdp->data));
(Yet another XDP-free call point, I need to convert to use an accessor
later to transition driver into an xdp_buff return API)
> + } else {
> + __skb_array_destroy_skb(ptr);
> + }
> +}
> +
> static void tun_queue_purge(struct tun_file *tfile)
> {
> - struct sk_buff *skb;
> + void *ptr;
>
> - while ((skb = ptr_ring_consume(&tfile->tx_ring)) != NULL)
> - kfree_skb(skb);
> + while ((ptr = ptr_ring_consume(&tfile->tx_ring)) != NULL)
> + tun_ptr_free(ptr);
>
> skb_queue_purge(&tfile->sk.sk_write_queue);
> skb_queue_purge(&tfile->sk.sk_error_queue);
> @@ -688,8 +719,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
> unregister_netdevice(tun->dev);
> }
> if (tun)
> - ptr_ring_cleanup(&tfile->tx_ring,
> - __skb_array_destroy_skb);
> + ptr_ring_cleanup(&tfile->tx_ring, tun_ptr_free);
> sock_put(&tfile->sk);
> }
> }
> @@ -1201,6 +1231,54 @@ static const struct net_device_ops tun_netdev_ops = {
> .ndo_get_stats64 = tun_net_get_stats64,
> };
>
> +static int tun_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp)
> +{
> + struct tun_struct *tun = netdev_priv(dev);
> + struct xdp_buff *buff = xdp->data_hard_start;
> + int headroom = xdp->data - xdp->data_hard_start;
> + struct tun_file *tfile;
> + u32 numqueues;
> + int ret = 0;
> +
> + /* Assure headroom is available and buff is properly aligned */
> + if (unlikely(headroom < sizeof(*xdp) || tun_is_xdp_buff(xdp)))
> + return -ENOSPC;
> +
> + *buff = *xdp;
> +
> + rcu_read_lock();
> +
> + numqueues = READ_ONCE(tun->numqueues);
> + if (!numqueues) {
> + ret = -ENOSPC;
> + goto out;
> + }
> + tfile = rcu_dereference(tun->tfiles[smp_processor_id() %
> + numqueues]);
Several concurrent CPUs can get the same 'tfile'.
> + /* Encode the XDP flag into lowest bit for consumer to differ
> + * XDP buffer from sk_buff.
> + */
> + if (ptr_ring_produce(&tfile->tx_ring, tun_xdp_to_ptr(buff))) {
> + this_cpu_inc(tun->pcpu_stats->tx_dropped);
> + ret = -ENOSPC;
> + }
The ptr_ring_produce() will take a lock per packet, limiting the
performance. (Again a case where I would have liked a bulk API for
ndo_xdp_xmit()).
> +
> +out:
> + rcu_read_unlock();
> + return ret;
> +}
> +
> +static void tun_xdp_flush(struct net_device *dev)
> +{
> + struct tun_struct *tun = netdev_priv(dev);
> + struct tun_file *tfile = tun->tfiles[0];
> +
> + /* Notify and wake up reader process */
> + if (tfile->flags & TUN_FASYNC)
> + kill_fasync(&tfile->fasync, SIGIO, POLL_IN);
> + tfile->socket.sk->sk_data_ready(tfile->socket.sk);
> +}
> +
> static const struct net_device_ops tap_netdev_ops = {
> .ndo_uninit = tun_net_uninit,
> .ndo_open = tun_net_open,
> @@ -1218,6 +1296,8 @@ static const struct net_device_ops tap_netdev_ops = {
> .ndo_set_rx_headroom = tun_set_headroom,
> .ndo_get_stats64 = tun_net_get_stats64,
> .ndo_bpf = tun_xdp,
> + .ndo_xdp_xmit = tun_xdp_xmit,
> + .ndo_xdp_flush = tun_xdp_flush,
> };
>
> static void tun_flow_init(struct tun_struct *tun)
> @@ -1841,6 +1921,40 @@ static ssize_t tun_chr_write_iter(struct kiocb *iocb, struct iov_iter *from)
> return result;
> }
>
> +static ssize_t tun_put_user_xdp(struct tun_struct *tun,
> + struct tun_file *tfile,
> + struct xdp_buff *xdp,
> + struct iov_iter *iter)
> +{
> + int vnet_hdr_sz = 0;
> + size_t size = xdp->data_end - xdp->data;
> + struct tun_pcpu_stats *stats;
> + size_t ret;
> +
> + if (tun->flags & IFF_VNET_HDR) {
> + struct virtio_net_hdr gso = { 0 };
> +
> + vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz);
> + if (unlikely(iov_iter_count(iter) < vnet_hdr_sz))
> + return -EINVAL;
> + if (unlikely(copy_to_iter(&gso, sizeof(gso), iter) !=
> + sizeof(gso)))
> + return -EFAULT;
> + iov_iter_advance(iter, vnet_hdr_sz - sizeof(gso));
> + }
> +
> + ret = copy_to_iter(xdp->data, size, iter) + vnet_hdr_sz;
> +
> + stats = get_cpu_ptr(tun->pcpu_stats);
> + u64_stats_update_begin(&stats->syncp);
> + stats->tx_packets++;
> + stats->tx_bytes += ret;
> + u64_stats_update_end(&stats->syncp);
> + put_cpu_ptr(tun->pcpu_stats);
> +
> + return ret;
> +}
> +
> /* Put packet to the user space buffer */
> static ssize_t tun_put_user(struct tun_struct *tun,
> struct tun_file *tfile,
[...]
> error = -ERESTARTSYS;
> @@ -1977,36 +2090,42 @@ static struct sk_buff *tun_ring_recv(struct tun_file *tfile, int noblock,
>
> out:
> *err = error;
> - return skb;
> + return ptr;
> }
>
> static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
> struct iov_iter *to,
> - int noblock, struct sk_buff *skb)
> + int noblock, void *ptr)
> {
> ssize_t ret;
> int err;
>
> tun_debug(KERN_INFO, tun, "tun_do_read\n");
>
> - if (!iov_iter_count(to)) {
> - if (skb)
> - kfree_skb(skb);
> - return 0;
> - }
> + if (!iov_iter_count(to))
> + tun_ptr_free(ptr);
>
> - if (!skb) {
> + if (!ptr) {
> /* Read frames from ring */
> - skb = tun_ring_recv(tfile, noblock, &err);
> - if (!skb)
> + ptr = tun_ring_recv(tfile, noblock, &err);
> + if (!ptr)
> return err;
> }
>
> - ret = tun_put_user(tun, tfile, skb, to);
> - if (unlikely(ret < 0))
> - kfree_skb(skb);
> - else
> - consume_skb(skb);
> + if (tun_is_xdp_buff(ptr)) {
> + struct xdp_buff *xdp = tun_ptr_to_xdp(ptr);
> +
> + ret = tun_put_user_xdp(tun, tfile, xdp, to);
> + put_page(virt_to_head_page(xdp->data));
This again tie us info a page-refcnt based XDP scheme.
> + } else {
> + struct sk_buff *skb = ptr;
> +
> + ret = tun_put_user(tun, tfile, skb, to);
> + if (unlikely(ret < 0))
> + kfree_skb(skb);
> + else
> + consume_skb(skb);
> + }
>
> return ret;
> }
[...]
> @@ -3191,8 +3323,7 @@ struct socket *tun_get_socket(struct file *file)
> struct tun_file *tfile;
> if (file->f_op != &tun_fops)
> return ERR_PTR(-EINVAL);
> - tfile = file->private_data;
> - if (!tfile)
> + tfile = file->private_data; if (!tfile)
This change looks like a typo...
> return ERR_PTR(-EBADFD);
> return &tfile->socket;
> }
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Principal Kernel Engineer at Red Hat
LinkedIn: http://www.linkedin.com/in/brouer
^ permalink raw reply
* [PATCH net-next 7/7] net: phy: convert read-modify-write to phy_modify()
From: Russell King @ 2017-12-29 12:31 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
In-Reply-To: <20171229123024.GZ10595@n2100.armlinux.org.uk>
Convert read-modify-write sequences in at803x, Marvell and core phylib
to use phy_modify() to ensure safety.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/at803x.c | 20 +++--------
drivers/net/phy/marvell.c | 82 ++++++++++++++++----------------------------
drivers/net/phy/phy_device.c | 50 +++++----------------------
3 files changed, 43 insertions(+), 109 deletions(-)
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index e911e4990b20..e86c1b8b1b51 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -216,34 +216,22 @@ static int at803x_suspend(struct phy_device *phydev)
int value;
int wol_enabled;
- mutex_lock(&phydev->lock);
-
value = phy_read(phydev, AT803X_INTR_ENABLE);
wol_enabled = value & AT803X_INTR_ENABLE_WOL;
- value = phy_read(phydev, MII_BMCR);
-
if (wol_enabled)
- value |= BMCR_ISOLATE;
+ value = BMCR_ISOLATE;
else
- value |= BMCR_PDOWN;
+ value = BMCR_PDOWN;
- phy_write(phydev, MII_BMCR, value);
-
- mutex_unlock(&phydev->lock);
+ phy_modify(phydev, MII_BMCR, 0, value);
return 0;
}
static int at803x_resume(struct phy_device *phydev)
{
- int value;
-
- value = phy_read(phydev, MII_BMCR);
- value &= ~(BMCR_PDOWN | BMCR_ISOLATE);
- phy_write(phydev, MII_BMCR, value);
-
- return 0;
+ return phy_modify(phydev, MII_BMCR, ~(BMCR_PDOWN | BMCR_ISOLATE), 0);
}
static int at803x_probe(struct phy_device *phydev)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 1cb84064d658..6129ab1000f9 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -664,19 +664,14 @@ static int m88e1116r_config_init(struct phy_device *phydev)
static int m88e3016_config_init(struct phy_device *phydev)
{
- int reg;
+ int ret;
/* Enable Scrambler and Auto-Crossover */
- reg = phy_read(phydev, MII_88E3016_PHY_SPEC_CTRL);
- if (reg < 0)
- return reg;
-
- reg &= ~MII_88E3016_DISABLE_SCRAMBLER;
- reg |= MII_88E3016_AUTO_MDIX_CROSSOVER;
-
- reg = phy_write(phydev, MII_88E3016_PHY_SPEC_CTRL, reg);
- if (reg < 0)
- return reg;
+ ret = phy_modify(phydev, MII_88E3016_PHY_SPEC_CTRL,
+ ~MII_88E3016_DISABLE_SCRAMBLER,
+ MII_88E3016_AUTO_MDIX_CROSSOVER);
+ if (ret < 0)
+ return ret;
return marvell_config_init(phydev);
}
@@ -685,42 +680,34 @@ static int m88e1111_config_init_hwcfg_mode(struct phy_device *phydev,
u16 mode,
int fibre_copper_auto)
{
- int temp;
-
- temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
- if (temp < 0)
- return temp;
-
- temp &= ~(MII_M1111_HWCFG_MODE_MASK |
- MII_M1111_HWCFG_FIBER_COPPER_AUTO |
- MII_M1111_HWCFG_FIBER_COPPER_RES);
- temp |= mode;
-
if (fibre_copper_auto)
- temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
+ mode |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
- return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+ return phy_modify(phydev, MII_M1111_PHY_EXT_SR,
+ (u16)~(MII_M1111_HWCFG_MODE_MASK |
+ MII_M1111_HWCFG_FIBER_COPPER_AUTO |
+ MII_M1111_HWCFG_FIBER_COPPER_RES),
+ mode);
}
static int m88e1111_config_init_rgmii_delays(struct phy_device *phydev)
{
- int temp;
-
- temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
- if (temp < 0)
- return temp;
+ int delay;
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
- temp |= (MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY);
+ delay = MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY;
} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
- temp &= ~MII_M1111_RGMII_TX_DELAY;
- temp |= MII_M1111_RGMII_RX_DELAY;
+ delay = MII_M1111_RGMII_RX_DELAY;
} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
- temp &= ~MII_M1111_RGMII_RX_DELAY;
- temp |= MII_M1111_RGMII_TX_DELAY;
+ delay = MII_M1111_RGMII_TX_DELAY;
+ } else {
+ delay = 0;
}
- return phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
+ return phy_modify(phydev, MII_M1111_PHY_EXT_CR,
+ (u16)~(MII_M1111_RGMII_RX_DELAY |
+ MII_M1111_RGMII_TX_DELAY),
+ delay);
}
static int m88e1111_config_init_rgmii(struct phy_device *phydev)
@@ -834,7 +821,6 @@ static int m88e1121_config_init(struct phy_device *phydev)
static int m88e1510_config_init(struct phy_device *phydev)
{
int err;
- int temp;
/* SGMII-to-Copper mode initialization */
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
@@ -846,16 +832,15 @@ static int m88e1510_config_init(struct phy_device *phydev)
return err;
/* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
- temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1);
- temp &= ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK;
- temp |= MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII;
- err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
+ err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1,
+ ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK,
+ MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII);
if (err < 0)
return err;
/* PHY reset is necessary after changing MODE[2:0] */
- temp |= MII_88E1510_GEN_CTRL_REG_1_RESET;
- err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
+ err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 0,
+ MII_88E1510_GEN_CTRL_REG_1_RESET);
if (err < 0)
return err;
@@ -961,7 +946,6 @@ static int m88e1149_config_init(struct phy_device *phydev)
static int m88e1145_config_init_rgmii(struct phy_device *phydev)
{
- int temp;
int err;
err = m88e1111_config_init_rgmii_delays(phydev);
@@ -973,15 +957,9 @@ static int m88e1145_config_init_rgmii(struct phy_device *phydev)
if (err < 0)
return err;
- temp = phy_read(phydev, 0x1e);
- if (temp < 0)
- return temp;
-
- temp &= 0xf03f;
- temp |= 2 << 9; /* 36 ohm */
- temp |= 2 << 6; /* 39 ohm */
-
- err = phy_write(phydev, 0x1e, temp);
+ err = phy_modify(phydev, 0x1e, 0xf03f,
+ 2 << 9 | /* 36 ohm */
+ 2 << 6); /* 39 ohm */
if (err < 0)
return err;
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index b15b31ca2618..e5ddc5ae56d1 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1328,9 +1328,8 @@ static int genphy_config_eee_advert(struct phy_device *phydev)
*/
int genphy_setup_forced(struct phy_device *phydev)
{
- int ctl = phy_read(phydev, MII_BMCR);
+ u16 ctl = 0;
- ctl &= BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN;
phydev->pause = 0;
phydev->asym_pause = 0;
@@ -1342,7 +1341,8 @@ int genphy_setup_forced(struct phy_device *phydev)
if (DUPLEX_FULL == phydev->duplex)
ctl |= BMCR_FULLDPLX;
- return phy_write(phydev, MII_BMCR, ctl);
+ return phy_modify(phydev, MII_BMCR,
+ BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN, ctl);
}
EXPORT_SYMBOL(genphy_setup_forced);
@@ -1352,17 +1352,9 @@ EXPORT_SYMBOL(genphy_setup_forced);
*/
int genphy_restart_aneg(struct phy_device *phydev)
{
- int ctl = phy_read(phydev, MII_BMCR);
-
- if (ctl < 0)
- return ctl;
-
- ctl |= BMCR_ANENABLE | BMCR_ANRESTART;
-
/* Don't isolate the PHY if we're negotiating */
- ctl &= ~BMCR_ISOLATE;
-
- return phy_write(phydev, MII_BMCR, ctl);
+ return phy_modify(phydev, MII_BMCR, ~BMCR_ISOLATE,
+ BMCR_ANENABLE | BMCR_ANRESTART);
}
EXPORT_SYMBOL(genphy_restart_aneg);
@@ -1628,44 +1620,20 @@ EXPORT_SYMBOL(genphy_config_init);
int genphy_suspend(struct phy_device *phydev)
{
- int value;
-
- mutex_lock(&phydev->lock);
-
- value = phy_read(phydev, MII_BMCR);
- phy_write(phydev, MII_BMCR, value | BMCR_PDOWN);
-
- mutex_unlock(&phydev->lock);
-
- return 0;
+ return phy_modify(phydev, MII_BMCR, 0, BMCR_PDOWN);
}
EXPORT_SYMBOL(genphy_suspend);
int genphy_resume(struct phy_device *phydev)
{
- int value;
-
- value = phy_read(phydev, MII_BMCR);
- phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
-
- return 0;
+ return phy_modify(phydev, MII_BMCR, ~BMCR_PDOWN, 0);
}
EXPORT_SYMBOL(genphy_resume);
int genphy_loopback(struct phy_device *phydev, bool enable)
{
- int value;
-
- value = phy_read(phydev, MII_BMCR);
- if (value < 0)
- return value;
-
- if (enable)
- value |= BMCR_LOOPBACK;
- else
- value &= ~BMCR_LOOPBACK;
-
- return phy_write(phydev, MII_BMCR, value);
+ return phy_modify(phydev, MII_BMCR, ~BMCR_LOOPBACK,
+ enable ? BMCR_LOOPBACK : 0);
}
EXPORT_SYMBOL(genphy_loopback);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 6/7] net: phy: add phy_modify() accessor
From: Russell King @ 2017-12-29 12:31 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
In-Reply-To: <20171229123024.GZ10595@n2100.armlinux.org.uk>
Add phy_modify() convenience accessor to complement the mdiobus
counterpart.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/phy-core.c | 23 +++++++++++++++++++++++
include/linux/phy.h | 1 +
2 files changed, 24 insertions(+)
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index df39e6711b76..9c08850eed16 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -306,6 +306,29 @@ int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
}
EXPORT_SYMBOL_GPL(__phy_modify);
+/**
+ * phy_modify - Convenience function for modifying a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to write
+ * @mask: bit mask of bits to clear
+ * @set: new value of bits set in mask to write to @regnum
+ *
+ * NOTE: MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation.
+ */
+int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
+{
+ int ret;
+
+ mutex_lock(&phydev->mdio.bus->mdio_lock);
+ ret = __phy_modify(phydev, regnum, mask, set);
+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(phy_modify);
+
static int __phy_read_page(struct phy_device *phydev)
{
return phydev->drv->read_page(phydev);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index f408220d95ec..0ee4ece312da 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -760,6 +760,7 @@ static inline int __phy_write(struct phy_device *phydev, u32 regnum, u16 val)
}
int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set);
+int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set);
/**
* phy_interrupt_is_valid - Convenience function for testing a given PHY irq
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 5/7] net: phy: marvell: fix paged access races
From: Russell King @ 2017-12-29 12:31 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
In-Reply-To: <20171229123024.GZ10595@n2100.armlinux.org.uk>
For paged accesses to be truely safe, we need to hold the bus lock to
prevent anyone else gaining access to the registers while we modify
them.
The phydev->lock mutex does not do this: userspace via the MII ioctl
can still sneak in and read or write any register while we are on a
different page, and the suspend/resume methods can be called by a
thread different to the thread polling the phy status.
Races have been observed with mvneta on SolidRun Clearfog with phylink,
particularly between the phylib worker reading the PHYs status, and
the thread resuming mvneta, calling phy_start() which then calls
through to m88e1121_config_aneg_rgmii_delays(), which tries to
read-modify-write the MSCR register:
CPU0 CPU1
marvell_read_status_page()
marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE)
...
m88e1121_config_aneg_rgmii_delays()
set_page(MII_MARVELL_MSCR_PAGE)
phy_read(phydev, MII_88E1121_PHY_MSCR_REG)
marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
...
phy_write(phydev, MII_88E1121_PHY_MSCR_REG)
The result of this is we end up writing the copper page register 21,
which causes the copper PHY to be disabled, and the link partner sees
the link immediately go down.
Solve this by taking the bus lock instead of the PHY lock, thereby
preventing other accesses to the PHY while we are accessing other PHY
pages.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/marvell.c | 354 ++++++++++++++++++----------------------------
1 file changed, 137 insertions(+), 217 deletions(-)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 82104edca393..1cb84064d658 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -83,7 +83,7 @@
#define MII_88E1121_PHY_MSCR_REG 21
#define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5)
#define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4)
-#define MII_88E1121_PHY_MSCR_DELAY_MASK (~(BIT(5) | BIT(4)))
+#define MII_88E1121_PHY_MSCR_DELAY_MASK (BIT(5) | BIT(4))
#define MII_88E1121_MISC_TEST 0x1a
#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00
@@ -177,27 +177,19 @@ struct marvell_priv {
struct device *hwmon_dev;
};
-static int marvell_get_page(struct phy_device *phydev)
+static int marvell_read_page(struct phy_device *phydev)
{
- return phy_read(phydev, MII_MARVELL_PHY_PAGE);
+ return __phy_read(phydev, MII_MARVELL_PHY_PAGE);
}
-static int marvell_set_page(struct phy_device *phydev, int page)
+static int marvell_write_page(struct phy_device *phydev, int page)
{
- return phy_write(phydev, MII_MARVELL_PHY_PAGE, page);
+ return __phy_write(phydev, MII_MARVELL_PHY_PAGE, page);
}
-static int marvell_get_set_page(struct phy_device *phydev, int page)
+static int marvell_set_page(struct phy_device *phydev, int page)
{
- int oldpage = marvell_get_page(phydev);
-
- if (oldpage < 0)
- return oldpage;
-
- if (page != oldpage)
- return marvell_set_page(phydev, page);
-
- return 0;
+ return phy_write(phydev, MII_MARVELL_PHY_PAGE, page);
}
static int marvell_ack_interrupt(struct phy_device *phydev)
@@ -399,7 +391,7 @@ static int m88e1111_config_aneg(struct phy_device *phydev)
static int marvell_of_reg_init(struct phy_device *phydev)
{
const __be32 *paddr;
- int len, i, saved_page, current_page, ret;
+ int len, i, saved_page, current_page, ret = 0;
if (!phydev->mdio.dev.of_node)
return 0;
@@ -409,12 +401,11 @@ static int marvell_of_reg_init(struct phy_device *phydev)
if (!paddr || len < (4 * sizeof(*paddr)))
return 0;
- saved_page = marvell_get_page(phydev);
+ saved_page = phy_save_page(phydev);
if (saved_page < 0)
- return saved_page;
+ goto err;
current_page = saved_page;
- ret = 0;
len /= sizeof(*paddr);
for (i = 0; i < len - 3; i += 4) {
u16 page = be32_to_cpup(paddr + i);
@@ -425,14 +416,14 @@ static int marvell_of_reg_init(struct phy_device *phydev)
if (page != current_page) {
current_page = page;
- ret = marvell_set_page(phydev, page);
+ ret = marvell_write_page(phydev, page);
if (ret < 0)
goto err;
}
val = 0;
if (mask) {
- val = phy_read(phydev, reg);
+ val = __phy_read(phydev, reg);
if (val < 0) {
ret = val;
goto err;
@@ -441,17 +432,12 @@ static int marvell_of_reg_init(struct phy_device *phydev)
}
val |= val_bits;
- ret = phy_write(phydev, reg, val);
+ ret = __phy_write(phydev, reg, val);
if (ret < 0)
goto err;
}
err:
- if (current_page != saved_page) {
- i = marvell_set_page(phydev, saved_page);
- if (ret == 0)
- ret = i;
- }
- return ret;
+ return phy_restore_page(phydev, saved_page, ret);
}
#else
static int marvell_of_reg_init(struct phy_device *phydev)
@@ -462,34 +448,21 @@ static int marvell_of_reg_init(struct phy_device *phydev)
static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev)
{
- int err, oldpage, mscr;
-
- oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE);
- if (oldpage < 0)
- return oldpage;
-
- mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG);
- if (mscr < 0) {
- err = mscr;
- goto out;
- }
-
- mscr &= MII_88E1121_PHY_MSCR_DELAY_MASK;
+ int mscr;
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
- mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
- MII_88E1121_PHY_MSCR_TX_DELAY);
+ mscr = MII_88E1121_PHY_MSCR_RX_DELAY |
+ MII_88E1121_PHY_MSCR_TX_DELAY;
else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
- mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
+ mscr = MII_88E1121_PHY_MSCR_RX_DELAY;
else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
- mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
-
- err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
-
-out:
- marvell_set_page(phydev, oldpage);
+ mscr = MII_88E1121_PHY_MSCR_TX_DELAY;
+ else
+ mscr = 0;
- return err;
+ return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
+ MII_88E1121_PHY_MSCR_REG,
+ MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
}
static int m88e1121_config_aneg(struct phy_device *phydev)
@@ -515,20 +488,11 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
static int m88e1318_config_aneg(struct phy_device *phydev)
{
- int err, oldpage, mscr;
-
- oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE);
- if (oldpage < 0)
- return oldpage;
-
- mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG);
- mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD;
-
- err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr);
- if (err < 0)
- return err;
+ int err;
- err = marvell_set_page(phydev, oldpage);
+ err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
+ MII_88E1318S_PHY_MSCR1_REG,
+ 0, MII_88E1318S_PHY_MSCR1_PAD_ODD);
if (err < 0)
return err;
@@ -854,20 +818,15 @@ static int m88e1111_config_init(struct phy_device *phydev)
static int m88e1121_config_init(struct phy_device *phydev)
{
- int err, oldpage;
-
- oldpage = marvell_get_set_page(phydev, MII_MARVELL_LED_PAGE);
- if (oldpage < 0)
- return oldpage;
+ int err;
/* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */
- err = phy_write(phydev, MII_88E1121_PHY_LED_CTRL,
- MII_88E1121_PHY_LED_DEF);
+ err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE,
+ MII_88E1121_PHY_LED_CTRL,
+ MII_88E1121_PHY_LED_DEF);
if (err < 0)
return err;
- marvell_set_page(phydev, oldpage);
-
/* Set marvell,reg-init configuration from device tree */
return marvell_config_init(phydev);
}
@@ -1398,100 +1357,98 @@ static int m88e1121_did_interrupt(struct phy_device *phydev)
static void m88e1318_get_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol)
{
+ int oldpage, ret = 0;
+
wol->supported = WAKE_MAGIC;
wol->wolopts = 0;
- if (marvell_set_page(phydev, MII_MARVELL_WOL_PAGE) < 0)
- return;
+ oldpage = phy_select_page(phydev, MII_MARVELL_WOL_PAGE);
+ if (oldpage < 0)
+ goto error;
- if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) &
- MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)
+ ret = __phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
+ if (ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)
wol->wolopts |= WAKE_MAGIC;
- if (marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE) < 0)
- return;
+error:
+ phy_restore_page(phydev, oldpage, ret);
}
static int m88e1318_set_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol)
{
- int err, oldpage, temp;
+ int err = 0, oldpage;
- oldpage = marvell_get_page(phydev);
+ oldpage = phy_save_page(phydev);
+ if (oldpage < 0)
+ goto error;
if (wol->wolopts & WAKE_MAGIC) {
/* Explicitly switch to page 0x00, just to be sure */
- err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
+ err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE);
if (err < 0)
- return err;
+ goto error;
/* Enable the WOL interrupt */
- temp = phy_read(phydev, MII_88E1318S_PHY_CSIER);
- temp |= MII_88E1318S_PHY_CSIER_WOL_EIE;
- err = phy_write(phydev, MII_88E1318S_PHY_CSIER, temp);
+ err = __phy_modify(phydev, MII_88E1318S_PHY_CSIER, 0,
+ MII_88E1318S_PHY_CSIER_WOL_EIE);
if (err < 0)
- return err;
+ goto error;
- err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE);
+ err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE);
if (err < 0)
- return err;
+ goto error;
/* Setup LED[2] as interrupt pin (active low) */
- temp = phy_read(phydev, MII_88E1318S_PHY_LED_TCR);
- temp &= ~MII_88E1318S_PHY_LED_TCR_FORCE_INT;
- temp |= MII_88E1318S_PHY_LED_TCR_INTn_ENABLE;
- temp |= MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW;
- err = phy_write(phydev, MII_88E1318S_PHY_LED_TCR, temp);
+ err = __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR,
+ (u16)~MII_88E1318S_PHY_LED_TCR_FORCE_INT,
+ MII_88E1318S_PHY_LED_TCR_INTn_ENABLE |
+ MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW);
if (err < 0)
- return err;
+ goto error;
- err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE);
+ err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);
if (err < 0)
- return err;
+ goto error;
/* Store the device address for the magic packet */
- err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2,
+ err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2,
((phydev->attached_dev->dev_addr[5] << 8) |
phydev->attached_dev->dev_addr[4]));
if (err < 0)
- return err;
- err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1,
+ goto error;
+ err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1,
((phydev->attached_dev->dev_addr[3] << 8) |
phydev->attached_dev->dev_addr[2]));
if (err < 0)
- return err;
- err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0,
+ goto error;
+ err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0,
((phydev->attached_dev->dev_addr[1] << 8) |
phydev->attached_dev->dev_addr[0]));
if (err < 0)
- return err;
+ goto error;
/* Clear WOL status and enable magic packet matching */
- temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
- temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS;
- temp |= MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE;
- err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp);
+ err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 0,
+ MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS |
+ MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE);
if (err < 0)
- return err;
+ goto error;
} else {
- err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE);
+ err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);
if (err < 0)
- return err;
+ goto error;
/* Clear WOL status and disable magic packet matching */
- temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
- temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS;
- temp &= ~MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE;
- err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp);
+ err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL,
+ (u16)~MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE,
+ MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS);
if (err < 0)
- return err;
+ goto error;
}
- err = marvell_set_page(phydev, oldpage);
- if (err < 0)
- return err;
-
- return 0;
+error:
+ return phy_restore_page(phydev, oldpage, err);
}
static int marvell_get_sset_count(struct phy_device *phydev)
@@ -1519,14 +1476,10 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i)
{
struct marvell_hw_stat stat = marvell_hw_stats[i];
struct marvell_priv *priv = phydev->priv;
- int oldpage, val;
+ int val;
u64 ret;
- oldpage = marvell_get_set_page(phydev, stat.page);
- if (oldpage < 0)
- return UINT64_MAX;
-
- val = phy_read(phydev, stat.reg);
+ val = phy_read_paged(phydev, stat.page, stat.reg);
if (val < 0) {
ret = UINT64_MAX;
} else {
@@ -1535,8 +1488,6 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i)
ret = priv->stats[i];
}
- marvell_set_page(phydev, oldpage);
-
return ret;
}
@@ -1553,51 +1504,44 @@ static void marvell_get_stats(struct phy_device *phydev,
static int m88e1121_get_temp(struct phy_device *phydev, long *temp)
{
int oldpage;
- int ret;
+ int ret = 0;
int val;
*temp = 0;
- mutex_lock(&phydev->lock);
-
- oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
- if (oldpage < 0) {
- mutex_unlock(&phydev->lock);
- return oldpage;
- }
+ oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
+ if (oldpage < 0)
+ goto error;
/* Enable temperature sensor */
- ret = phy_read(phydev, MII_88E1121_MISC_TEST);
+ ret = __phy_read(phydev, MII_88E1121_MISC_TEST);
if (ret < 0)
goto error;
- ret = phy_write(phydev, MII_88E1121_MISC_TEST,
- ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);
+ ret = __phy_write(phydev, MII_88E1121_MISC_TEST,
+ ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);
if (ret < 0)
goto error;
/* Wait for temperature to stabilize */
usleep_range(10000, 12000);
- val = phy_read(phydev, MII_88E1121_MISC_TEST);
+ val = __phy_read(phydev, MII_88E1121_MISC_TEST);
if (val < 0) {
ret = val;
goto error;
}
/* Disable temperature sensor */
- ret = phy_write(phydev, MII_88E1121_MISC_TEST,
- ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);
+ ret = __phy_write(phydev, MII_88E1121_MISC_TEST,
+ ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);
if (ret < 0)
goto error;
*temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000;
error:
- marvell_set_page(phydev, oldpage);
- mutex_unlock(&phydev->lock);
-
- return ret;
+ return phy_restore_page(phydev, oldpage, ret);
}
static int m88e1121_hwmon_read(struct device *dev,
@@ -1671,118 +1615,64 @@ static const struct hwmon_chip_info m88e1121_hwmon_chip_info = {
static int m88e1510_get_temp(struct phy_device *phydev, long *temp)
{
- int oldpage;
int ret;
*temp = 0;
- mutex_lock(&phydev->lock);
-
- oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
- if (oldpage < 0) {
- mutex_unlock(&phydev->lock);
- return oldpage;
- }
-
- ret = phy_read(phydev, MII_88E1510_TEMP_SENSOR);
+ ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
+ MII_88E1510_TEMP_SENSOR);
if (ret < 0)
- goto error;
+ return ret;
*temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000;
-error:
- marvell_set_page(phydev, oldpage);
- mutex_unlock(&phydev->lock);
-
- return ret;
+ return 0;
}
static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp)
{
- int oldpage;
int ret;
*temp = 0;
- mutex_lock(&phydev->lock);
-
- oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
- if (oldpage < 0) {
- mutex_unlock(&phydev->lock);
- return oldpage;
- }
-
- ret = phy_read(phydev, MII_88E1121_MISC_TEST);
+ ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
+ MII_88E1121_MISC_TEST);
if (ret < 0)
- goto error;
+ return ret;
*temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >>
MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25;
/* convert to mC */
*temp *= 1000;
-error:
- marvell_set_page(phydev, oldpage);
- mutex_unlock(&phydev->lock);
-
- return ret;
+ return 0;
}
static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp)
{
- int oldpage;
- int ret;
-
- mutex_lock(&phydev->lock);
-
- oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
- if (oldpage < 0) {
- mutex_unlock(&phydev->lock);
- return oldpage;
- }
-
- ret = phy_read(phydev, MII_88E1121_MISC_TEST);
- if (ret < 0)
- goto error;
-
temp = temp / 1000;
temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f);
- ret = phy_write(phydev, MII_88E1121_MISC_TEST,
- (ret & ~MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) |
- (temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT));
-
-error:
- marvell_set_page(phydev, oldpage);
- mutex_unlock(&phydev->lock);
- return ret;
+ return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
+ MII_88E1121_MISC_TEST,
+ MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK,
+ temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT);
}
static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm)
{
- int oldpage;
int ret;
*alarm = false;
- mutex_lock(&phydev->lock);
-
- oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
- if (oldpage < 0) {
- mutex_unlock(&phydev->lock);
- return oldpage;
- }
-
- ret = phy_read(phydev, MII_88E1121_MISC_TEST);
+ ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
+ MII_88E1121_MISC_TEST);
if (ret < 0)
- goto error;
- *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ);
+ return ret;
-error:
- marvell_set_page(phydev, oldpage);
- mutex_unlock(&phydev->lock);
+ *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ);
- return ret;
+ return 0;
}
static int m88e1510_hwmon_read(struct device *dev,
@@ -1979,6 +1869,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -1997,6 +1889,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2015,6 +1909,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2033,6 +1929,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2052,6 +1950,8 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2073,6 +1973,8 @@ static struct phy_driver marvell_drivers[] = {
.set_wol = &m88e1318_set_wol,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2091,6 +1993,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2109,6 +2013,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2127,6 +2033,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2145,6 +2053,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2166,6 +2076,8 @@ static struct phy_driver marvell_drivers[] = {
.set_wol = &m88e1318_set_wol,
.resume = &marvell_resume,
.suspend = &marvell_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2186,6 +2098,8 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2205,6 +2119,8 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2225,6 +2141,8 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2244,6 +2162,8 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 4/7] net: phy: add paged phy register accessors
From: Russell King @ 2017-12-29 12:31 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
In-Reply-To: <20171229123024.GZ10595@n2100.armlinux.org.uk>
Add a set of paged phy register accessors which are inherently safe in
their design against other accesses interfering with the paged access.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/phy-core.c | 157 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/phy.h | 11 ++++
2 files changed, 168 insertions(+)
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 37c039da0c16..df39e6711b76 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -305,3 +305,160 @@ int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
return ret;
}
EXPORT_SYMBOL_GPL(__phy_modify);
+
+static int __phy_read_page(struct phy_device *phydev)
+{
+ return phydev->drv->read_page(phydev);
+}
+
+static int __phy_write_page(struct phy_device *phydev, int page)
+{
+ return phydev->drv->write_page(phydev, page);
+}
+
+/**
+ * phy_save_page() - take the bus lock and save the current page
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * Take the MDIO bus lock, and return the current page number. On error,
+ * returns a negative errno. phy_restore_page() must be called after this
+ * to release the lock even on failure.
+ */
+int phy_save_page(struct phy_device *phydev)
+{
+ mutex_lock(&phydev->mdio.bus->mdio_lock);
+ return __phy_read_page(phydev);
+}
+EXPORT_SYMBOL_GPL(phy_save_page);
+
+/**
+ * phy_select_page() - take the bus lock, save the current page, and set a page
+ * @phydev: a pointer to a &struct phy_device
+ * @page: desired page
+ *
+ * Take the MDIO bus lock to protect against concurrent access, save the
+ * current PHY page, and set the current page. On error, returns a
+ * negative errno, otherwise returns the previous page number.
+ * phy_restore_page() must be called after this to restore the page
+ * number (if this call was successful) and release the lock.
+ */
+int phy_select_page(struct phy_device *phydev, int page)
+{
+ int ret, oldpage;
+
+ oldpage = ret = phy_save_page(phydev);
+ if (ret < 0)
+ return ret;
+
+ if (oldpage != page) {
+ ret = __phy_write_page(phydev, page);
+ if (ret < 0)
+ return ret;
+ }
+
+ return oldpage;
+}
+EXPORT_SYMBOL_GPL(phy_select_page);
+
+/**
+ * phy_restore_page() - restore the page register and release the bus lock
+ * @phydev: a pointer to a &struct phy_device
+ * @oldpage: the old page, return value from phy_save_page() or phy_select_page()
+ * @ret: operation's return code
+ *
+ * Release the MDIO bus lock, restoring @oldpage if it is a valid page.
+ * This function propagates the earliest error code from the group of
+ * operations.
+ *
+ * Returns:
+ * @oldpage if it was a negative value, otherwise
+ * @ret if it was a negative errno value, otherwise
+ * phy_write_page()'s negative value if it were in error, otherwise
+ * @ret.
+ */
+int phy_restore_page(struct phy_device *phydev, int oldpage, int ret)
+{
+ int r;
+
+ if (oldpage >= 0) {
+ r = __phy_write_page(phydev, oldpage);
+
+ /* Propagate the operation return code if the page write
+ * was successful.
+ */
+ if (ret >= 0 && r < 0)
+ ret = r;
+ } else {
+ /* Propagate the phy page selection error code */
+ ret = oldpage;
+ }
+
+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(phy_restore_page);
+
+/**
+ * phy_read_paged() - Convenience function for reading a paged register
+ * @phydev: a pointer to a &struct phy_device
+ * @page: the page for the phy
+ * @regnum: register number
+ *
+ * Same rules as for phy_read();
+ */
+int phy_read_paged(struct phy_device *phydev, int page, u32 regnum)
+{
+ int ret = 0, oldpage;
+
+ oldpage = phy_select_page(phydev, page);
+ if (oldpage >= 0)
+ ret = __phy_read(phydev, regnum);
+
+ return phy_restore_page(phydev, oldpage, ret);
+}
+EXPORT_SYMBOL(phy_read_paged);
+
+/**
+ * phy_write_paged() - Convenience function for writing a paged register
+ * @phydev: a pointer to a &struct phy_device
+ * @page: the page for the phy
+ * @regnum: register number
+ * @val: value to write
+ *
+ * Same rules as for phy_write();
+ */
+int phy_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val)
+{
+ int ret = 0, oldpage;
+
+ oldpage = phy_select_page(phydev, page);
+ if (oldpage >= 0)
+ ret = __phy_write(phydev, regnum, val);
+
+ return phy_restore_page(phydev, oldpage, ret);
+}
+EXPORT_SYMBOL(phy_write_paged);
+
+/**
+ * phy_modify_paged() - Convenience function for modifying a paged register
+ * @phydev: a pointer to a &struct phy_device
+ * @page: the page for the phy
+ * @regnum: register number
+ * @mask: bit mask of bits to clear
+ * @set: bit mask of bits to set
+ *
+ * Same rules as for phy_read() and phy_write();
+ */
+int phy_modify_paged(struct phy_device *phydev, int page, u32 regnum,
+ u16 mask, u16 set)
+{
+ int ret = 0, oldpage;
+
+ oldpage = phy_select_page(phydev, page);
+ if (oldpage >= 0)
+ ret = __phy_modify(phydev, regnum, mask, set);
+
+ return phy_restore_page(phydev, oldpage, ret);
+}
+EXPORT_SYMBOL(phy_modify_paged);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 3dae5b7408b4..f408220d95ec 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -634,6 +634,9 @@ struct phy_driver {
int (*write_mmd)(struct phy_device *dev, int devnum, u16 regnum,
u16 val);
+ int (*read_page)(struct phy_device *dev);
+ int (*write_page)(struct phy_device *dev, int page);
+
/* Get the size and type of the eeprom contained within a plug-in
* module */
int (*module_info)(struct phy_device *dev,
@@ -836,6 +839,14 @@ static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev)
*/
int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val);
+int phy_save_page(struct phy_device *phydev);
+int phy_select_page(struct phy_device *phydev, int page);
+int phy_restore_page(struct phy_device *phydev, int oldpage, int ret);
+int phy_read_paged(struct phy_device *phydev, int page, u32 regnum);
+int phy_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val);
+int phy_modify_paged(struct phy_device *phydev, int page, u32 regnum,
+ u16 mask, u16 set);
+
struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
bool is_c45,
struct phy_c45_device_ids *c45_ids);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 3/7] net: phy: add unlocked accessors
From: Russell King @ 2017-12-29 12:30 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
In-Reply-To: <20171229123024.GZ10595@n2100.armlinux.org.uk>
Add unlocked versions of the bus accessors, which allows access to the
bus with all the tracing. These accessors validate that the bus mutex
is held, which is a basic requirement for all mii bus accesses.
Also added is a read-modify-write unlocked accessor with the same
locking requirements.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/phy-core.c | 25 +++++++++++++++++++++++++
include/linux/phy.h | 28 ++++++++++++++++++++++++++++
2 files changed, 53 insertions(+)
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 83d32644cb4d..37c039da0c16 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -280,3 +280,28 @@ int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
return ret;
}
EXPORT_SYMBOL(phy_write_mmd);
+
+/**
+ * __phy_modify() - Convenience function for modifying a PHY register
+ * @phydev: a pointer to a &struct phy_device
+ * @regnum: register number
+ * @mask: bit mask of bits to clear
+ * @set: bit mask of bits to set
+ *
+ * Unlocked helper function which allows a PHY register to be modified as
+ * new register value = (old register value & mask) | set
+ */
+int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
+{
+ int ret, res;
+
+ ret = __phy_read(phydev, regnum);
+ if (ret >= 0) {
+ res = __phy_write(phydev, regnum, (ret & ~mask) | set);
+ if (res < 0)
+ ret = res;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__phy_modify);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 71d777fe6c3d..3dae5b7408b4 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -716,6 +716,18 @@ static inline int phy_read(struct phy_device *phydev, u32 regnum)
}
/**
+ * __phy_read - convenience function for reading a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to read
+ *
+ * The caller must have taken the MDIO bus lock.
+ */
+static inline int __phy_read(struct phy_device *phydev, u32 regnum)
+{
+ return __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, regnum);
+}
+
+/**
* phy_write - Convenience function for writing a given PHY register
* @phydev: the phy_device struct
* @regnum: register number to write
@@ -731,6 +743,22 @@ static inline int phy_write(struct phy_device *phydev, u32 regnum, u16 val)
}
/**
+ * __phy_write - Convenience function for writing a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ *
+ * The caller must have taken the MDIO bus lock.
+ */
+static inline int __phy_write(struct phy_device *phydev, u32 regnum, u16 val)
+{
+ return __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr, regnum,
+ val);
+}
+
+int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set);
+
+/**
* phy_interrupt_is_valid - Convenience function for testing a given PHY irq
* @phydev: the phy_device struct
*
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 2/7] net: phy: use unlocked accessors for indirect MMD accesses
From: Russell King @ 2017-12-29 12:30 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
In-Reply-To: <20171229123024.GZ10595@n2100.armlinux.org.uk>
Use unlocked accessors for indirect MMD accesses to clause 22 PHYs.
This permits tracing of these accesses.
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/phy-core.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 21f75ae244b3..83d32644cb4d 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -193,13 +193,14 @@ static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
u16 regnum)
{
/* Write the desired MMD Devad */
- bus->write(bus, phy_addr, MII_MMD_CTRL, devad);
+ __mdiobus_write(bus, phy_addr, MII_MMD_CTRL, devad);
/* Write the desired MMD register address */
- bus->write(bus, phy_addr, MII_MMD_DATA, regnum);
+ __mdiobus_write(bus, phy_addr, MII_MMD_DATA, regnum);
/* Select the Function : DATA with no post increment */
- bus->write(bus, phy_addr, MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
+ __mdiobus_write(bus, phy_addr, MII_MMD_CTRL,
+ devad | MII_MMD_CTRL_NOINCR);
}
/**
@@ -232,7 +233,7 @@ int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
mmd_phy_indirect(bus, phy_addr, devad, regnum);
/* Read the content of the MMD's selected register */
- val = bus->read(bus, phy_addr, MII_MMD_DATA);
+ val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
mutex_unlock(&bus->mdio_lock);
}
return val;
@@ -271,7 +272,7 @@ int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
mmd_phy_indirect(bus, phy_addr, devad, regnum);
/* Write the data into MMD's selected register */
- bus->write(bus, phy_addr, MII_MMD_DATA, val);
+ __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
mutex_unlock(&bus->mdio_lock);
ret = 0;
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 1/7] net: mdiobus: add unlocked accessors
From: Russell King @ 2017-12-29 12:30 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
In-Reply-To: <20171229123024.GZ10595@n2100.armlinux.org.uk>
Add unlocked versions of the bus accessors, which allows access to the
bus with all the tracing. These accessors validate that the bus mutex
is held, which is a basic requirement for all mii bus accesses.
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/mdio_bus.c | 65 +++++++++++++++++++++++++++++++++++++---------
include/linux/mdio.h | 3 +++
2 files changed, 56 insertions(+), 12 deletions(-)
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 54d00a1d2bef..75be8be0d169 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -494,6 +494,55 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
EXPORT_SYMBOL(mdiobus_scan);
/**
+ * __mdiobus_read - Unlocked version of the mdiobus_read function
+ * @bus: the mii_bus struct
+ * @addr: the phy address
+ * @regnum: register number to read
+ *
+ * Read a MDIO bus register. Caller must hold the mdio bus lock.
+ *
+ * NOTE: MUST NOT be called from interrupt context.
+ */
+int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
+{
+ int retval;
+
+ WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock));
+
+ retval = bus->read(bus, addr, regnum);
+
+ trace_mdio_access(bus, 1, addr, regnum, retval, retval);
+
+ return retval;
+}
+EXPORT_SYMBOL(__mdiobus_read);
+
+/**
+ * __mdiobus_write - Unlocked version of the mdiobus_write function
+ * @bus: the mii_bus struct
+ * @addr: the phy address
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ *
+ * Write a MDIO bus register. Caller must hold the mdio bus lock.
+ *
+ * NOTE: MUST NOT be called from interrupt context.
+ */
+int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
+{
+ int err;
+
+ WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock));
+
+ err = bus->write(bus, addr, regnum, val);
+
+ trace_mdio_access(bus, 0, addr, regnum, val, err);
+
+ return err;
+}
+EXPORT_SYMBOL(__mdiobus_write);
+
+/**
* mdiobus_read_nested - Nested version of the mdiobus_read function
* @bus: the mii_bus struct
* @addr: the phy address
@@ -513,11 +562,9 @@ int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum)
BUG_ON(in_interrupt());
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
- retval = bus->read(bus, addr, regnum);
+ retval = __mdiobus_read(bus, addr, regnum);
mutex_unlock(&bus->mdio_lock);
- trace_mdio_access(bus, 1, addr, regnum, retval, retval);
-
return retval;
}
EXPORT_SYMBOL(mdiobus_read_nested);
@@ -539,11 +586,9 @@ int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
BUG_ON(in_interrupt());
mutex_lock(&bus->mdio_lock);
- retval = bus->read(bus, addr, regnum);
+ retval = __mdiobus_read(bus, addr, regnum);
mutex_unlock(&bus->mdio_lock);
- trace_mdio_access(bus, 1, addr, regnum, retval, retval);
-
return retval;
}
EXPORT_SYMBOL(mdiobus_read);
@@ -569,11 +614,9 @@ int mdiobus_write_nested(struct mii_bus *bus, int addr, u32 regnum, u16 val)
BUG_ON(in_interrupt());
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
- err = bus->write(bus, addr, regnum, val);
+ err = __mdiobus_write(bus, addr, regnum, val);
mutex_unlock(&bus->mdio_lock);
- trace_mdio_access(bus, 0, addr, regnum, val, err);
-
return err;
}
EXPORT_SYMBOL(mdiobus_write_nested);
@@ -596,11 +639,9 @@ int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
BUG_ON(in_interrupt());
mutex_lock(&bus->mdio_lock);
- err = bus->write(bus, addr, regnum, val);
+ err = __mdiobus_write(bus, addr, regnum, val);
mutex_unlock(&bus->mdio_lock);
- trace_mdio_access(bus, 0, addr, regnum, val, err);
-
return err;
}
EXPORT_SYMBOL(mdiobus_write);
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index ca08ab16ecdc..34796e29c90c 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -257,6 +257,9 @@ static inline u16 ethtool_adv_to_mmd_eee_adv_t(u32 adv)
return reg;
}
+int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
+int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
+
int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum);
int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 0/7] Resolve races in phy accessors
From: Russell King - ARM Linux @ 2017-12-29 12:30 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
Hi,
This series resolves races with various accesses to PHY registers.
The first five patches are necessary before we add phylink support
to mvneta, the remaining three are merely cleanups for unobserved
races, and hence are less critical.
There are two possible classes of races that can occur: where we
write to a page register that changes the meaning of a group of
other registers, and where we read-modify-write a register.
Resolve these races by performing the accesses under the mdio bus
lock, ensuring that no other user can access the bus while the
series of atomic operations are being performed.
These patches have been posted before, and have been modified
along the lines of previous feedback:
- The third patch was originally reviewed by Florian, but as I've
added __phy_modify() to it, I've removed that attributation.
- Included generic page-based accessors as suggested last time
around.
- Since we have the unlocked __phy_modify() in this patch series,
it is sensible to include the changes for this to marvell.c -
these accessors have to change anyway to avoid deadlocks on the
mdio bus lock.
I haven't been able to test the at803x.c changes yet beyond compile
testing - although I do have systems with an ar8035 PHY. However,
they should be straight forward to review.
This is targetted for net-next because the races have not been
found in existing drivers, but have been observed with phylink
integrated into mvneta - that's not to say that the races do not
exist today, they are just unobserved (probably through lack of
rigorous enough testing.) The race provoking condition is detailed
in patch 5.
drivers/net/phy/at803x.c | 20 +-
drivers/net/phy/marvell.c | 436 +++++++++++++++++--------------------------
drivers/net/phy/mdio_bus.c | 65 +++++--
drivers/net/phy/phy-core.c | 216 ++++++++++++++++++++-
drivers/net/phy/phy_device.c | 50 +----
include/linux/mdio.h | 3 +
include/linux/phy.h | 40 ++++
7 files changed, 487 insertions(+), 343 deletions(-)
--
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
^ permalink raw reply
* [PATCH net-next A 5/5] phylink: remove 'mode' variable from phylink_sfp_module_insert()
From: Russell King @ 2017-12-29 12:15 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
In-Reply-To: <20171229121451.GY10595@n2100.armlinux.org.uk>
'mode' is actually constant through phylink_sfp_module_insert(), so
remove it and replace it with the enumerated constant.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/phylink.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 073530949677..4e8c459bf062 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -1578,7 +1578,7 @@ static int phylink_sfp_module_insert(void *upstream,
__ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
struct phylink_link_state config;
phy_interface_t iface;
- int mode, ret = 0;
+ int ret = 0;
bool changed;
u8 port;
@@ -1593,7 +1593,6 @@ static int phylink_sfp_module_insert(void *upstream,
case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_2500BASEX:
case PHY_INTERFACE_MODE_10GKR:
- mode = MLO_AN_INBAND;
break;
default:
return -EINVAL;
@@ -1611,13 +1610,15 @@ static int phylink_sfp_module_insert(void *upstream,
ret = phylink_validate(pl, support, &config);
if (ret) {
netdev_err(pl->netdev, "validation of %s/%s with support %*pb failed: %d\n",
- phylink_an_mode_str(mode), phy_modes(config.interface),
+ phylink_an_mode_str(MLO_AN_INBAND),
+ phy_modes(config.interface),
__ETHTOOL_LINK_MODE_MASK_NBITS, support, ret);
return ret;
}
netdev_dbg(pl->netdev, "requesting link mode %s/%s with support %*pb\n",
- phylink_an_mode_str(mode), phy_modes(config.interface),
+ phylink_an_mode_str(MLO_AN_INBAND),
+ phy_modes(config.interface),
__ETHTOOL_LINK_MODE_MASK_NBITS, support);
if (phy_interface_mode_is_8023z(iface) && pl->phydev)
@@ -1630,15 +1631,15 @@ static int phylink_sfp_module_insert(void *upstream,
linkmode_copy(pl->link_config.advertising, config.advertising);
}
- if (pl->link_an_mode != mode ||
+ if (pl->link_an_mode != MLO_AN_INBAND ||
pl->link_config.interface != config.interface) {
pl->link_config.interface = config.interface;
- pl->link_an_mode = mode;
+ pl->link_an_mode = MLO_AN_INBAND;
changed = true;
netdev_info(pl->netdev, "switched to %s/%s link mode\n",
- phylink_an_mode_str(mode),
+ phylink_an_mode_str(MLO_AN_INBAND),
phy_modes(config.interface));
}
--
2.7.4
^ permalink raw reply related
* [PATCH net-next A 4/5] sfp: improve support for direct-attach copper cables
From: Russell King @ 2017-12-29 12:15 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
In-Reply-To: <20171229121451.GY10595@n2100.armlinux.org.uk>
Improve the support for direct-attach copper so that we avoid kernel
warning messages, and report the appropriate PORT_DA type to userspace.
Direct Attach cables can use a number of protocols depending on their
range of speeds.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/sfp-bus.c | 51 ++++++++++++++++++++++++++++++++++++++++-------
include/linux/sfp.h | 36 ++++++++++++++++++++++++++++++++-
2 files changed, 79 insertions(+), 8 deletions(-)
diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
index 6c05acd5b1d4..bdc4bb3c8288 100644
--- a/drivers/net/phy/sfp-bus.c
+++ b/drivers/net/phy/sfp-bus.c
@@ -57,21 +57,19 @@ int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
case SFP_CONNECTOR_MT_RJ:
case SFP_CONNECTOR_MU:
case SFP_CONNECTOR_OPTICAL_PIGTAIL:
- if (support)
- phylink_set(support, FIBRE);
port = PORT_FIBRE;
break;
case SFP_CONNECTOR_RJ45:
- if (support)
- phylink_set(support, TP);
port = PORT_TP;
break;
+ case SFP_CONNECTOR_COPPER_PIGTAIL:
+ port = PORT_DA;
+ break;
+
case SFP_CONNECTOR_UNSPEC:
if (id->base.e1000_base_t) {
- if (support)
- phylink_set(support, TP);
port = PORT_TP;
break;
}
@@ -80,7 +78,6 @@ int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
case SFP_CONNECTOR_MPO_1X12:
case SFP_CONNECTOR_MPO_2X16:
case SFP_CONNECTOR_HSSDC_II:
- case SFP_CONNECTOR_COPPER_PIGTAIL:
case SFP_CONNECTOR_NOSEPARATE:
case SFP_CONNECTOR_MXC_2X16:
port = PORT_OTHER;
@@ -92,6 +89,18 @@ int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
break;
}
+ if (support) {
+ switch (port) {
+ case PORT_FIBRE:
+ phylink_set(support, FIBRE);
+ break;
+
+ case PORT_TP:
+ phylink_set(support, TP);
+ break;
+ }
+ }
+
return port;
}
EXPORT_SYMBOL_GPL(sfp_parse_port);
@@ -143,6 +152,11 @@ phy_interface_t sfp_parse_interface(struct sfp_bus *bus,
break;
default:
+ if (id->base.e1000_base_cx) {
+ iface = PHY_INTERFACE_MODE_1000BASEX;
+ break;
+ }
+
iface = PHY_INTERFACE_MODE_NA;
dev_err(bus->sfp_dev,
"SFP module encoding does not support 8b10b nor 64b66b\n");
@@ -208,6 +222,29 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
br_min <= 1300 && br_max >= 1200)
phylink_set(support, 1000baseX_Full);
+ /* For active or passive cables, select the link modes
+ * based on the bit rates and the cable compliance bytes.
+ */
+ if ((id->base.sfp_ct_passive || id->base.sfp_ct_active) && br_nom) {
+ /* This may look odd, but some manufacturers use 12000MBd */
+ if (br_min <= 12000 && br_max >= 10300)
+ phylink_set(support, 10000baseCR_Full);
+ if (br_min <= 3200 && br_max >= 3100)
+ phylink_set(support, 2500baseX_Full);
+ if (br_min <= 1300 && br_max >= 1200)
+ phylink_set(support, 1000baseX_Full);
+ }
+ if (id->base.sfp_ct_passive) {
+ if (id->base.passive.sff8431_app_e)
+ phylink_set(support, 10000baseCR_Full);
+ }
+ if (id->base.sfp_ct_active) {
+ if (id->base.active.sff8431_app_e ||
+ id->base.active.sff8431_lim) {
+ phylink_set(support, 10000baseCR_Full);
+ }
+ }
+
switch (id->base.extended_cc) {
case 0x00: /* Unspecified */
break;
diff --git a/include/linux/sfp.h b/include/linux/sfp.h
index 0c5c5f6ae1ec..e724d5a3dd80 100644
--- a/include/linux/sfp.h
+++ b/include/linux/sfp.h
@@ -165,7 +165,41 @@ struct sfp_eeprom_base {
char vendor_rev[4];
union {
__be16 optical_wavelength;
- u8 cable_spec;
+ __be16 cable_compliance;
+ struct {
+#if defined __BIG_ENDIAN_BITFIELD
+ u8 reserved60_2:6;
+ u8 fc_pi_4_app_h:1;
+ u8 sff8431_app_e:1;
+ u8 reserved61:8;
+#elif defined __LITTLE_ENDIAN_BITFIELD
+ u8 sff8431_app_e:1;
+ u8 fc_pi_4_app_h:1;
+ u8 reserved60_2:6;
+ u8 reserved61:8;
+#else
+#error Unknown Endian
+#endif
+ } __packed passive;
+ struct {
+#if defined __BIG_ENDIAN_BITFIELD
+ u8 reserved60_4:4;
+ u8 fc_pi_4_lim:1;
+ u8 sff8431_lim:1;
+ u8 fc_pi_4_app_h:1;
+ u8 sff8431_app_e:1;
+ u8 reserved61:8;
+#elif defined __LITTLE_ENDIAN_BITFIELD
+ u8 sff8431_app_e:1;
+ u8 fc_pi_4_app_h:1;
+ u8 sff8431_lim:1;
+ u8 fc_pi_4_lim:1;
+ u8 reserved60_4:4;
+ u8 reserved61:8;
+#else
+#error Unknown Endian
+#endif
+ } __packed active;
} __packed;
u8 reserved62;
u8 cc_base;
--
2.7.4
^ permalink raw reply related
* [PATCH net-next A 3/5] sfp: add support for 1000Base-PX and 1000Base-BX10
From: Russell King @ 2017-12-29 12:15 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
In-Reply-To: <20171229121451.GY10595@n2100.armlinux.org.uk>
Add support for decoding the transceiver information for 1000Base-PX and
1000Base-BX10. These use 1000BASE-X protocol.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/sfp-bus.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
index a668a67c7eef..6c05acd5b1d4 100644
--- a/drivers/net/phy/sfp-bus.c
+++ b/drivers/net/phy/sfp-bus.c
@@ -165,10 +165,26 @@ EXPORT_SYMBOL_GPL(sfp_parse_interface);
void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
unsigned long *support)
{
+ unsigned int br_min, br_nom, br_max;
+
phylink_set(support, Autoneg);
phylink_set(support, Pause);
phylink_set(support, Asym_Pause);
+ /* Decode the bitrate information to MBd */
+ br_min = br_nom = br_max = 0;
+ 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_max = br_nom + id->base.br_nominal * id->ext.br_max;
+ } else if (id->ext.br_max) {
+ br_nom = 250 * id->ext.br_max;
+ br_max = br_nom + br_nom * id->ext.br_min / 100;
+ br_min = br_nom - br_nom * id->ext.br_min / 100;
+ }
+ }
+
/* Set ethtool support from the compliance fields. */
if (id->base.e10g_base_sr)
phylink_set(support, 10000baseSR_Full);
@@ -187,6 +203,11 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
phylink_set(support, 1000baseT_Full);
}
+ /* 1000Base-PX or 1000Base-BX10 */
+ if ((id->base.e_base_px || id->base.e_base_bx10) &&
+ br_min <= 1300 && br_max >= 1200)
+ phylink_set(support, 1000baseX_Full);
+
switch (id->base.extended_cc) {
case 0x00: /* Unspecified */
break;
--
2.7.4
^ permalink raw reply related
* [PATCH net-next A 2/5] sfp: don't guess support from connector type
From: Russell King @ 2017-12-29 12:15 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
In-Reply-To: <20171229121451.GY10595@n2100.armlinux.org.uk>
Don't try to guess the support mask from the connector type - this is
mostly irrelevant to the speeds that the transceiver supports.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/sfp-bus.c | 29 -----------------------------
1 file changed, 29 deletions(-)
diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
index bebc9391ac3d..a668a67c7eef 100644
--- a/drivers/net/phy/sfp-bus.c
+++ b/drivers/net/phy/sfp-bus.c
@@ -220,35 +220,6 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
if (id->base.br_nominal >= 12)
phylink_set(support, 1000baseX_Full);
}
-
- switch (id->base.connector) {
- case SFP_CONNECTOR_SC:
- case SFP_CONNECTOR_FIBERJACK:
- case SFP_CONNECTOR_LC:
- case SFP_CONNECTOR_MT_RJ:
- case SFP_CONNECTOR_MU:
- case SFP_CONNECTOR_OPTICAL_PIGTAIL:
- break;
-
- case SFP_CONNECTOR_UNSPEC:
- if (id->base.e1000_base_t)
- break;
-
- case SFP_CONNECTOR_SG: /* guess */
- case SFP_CONNECTOR_MPO_1X12:
- case SFP_CONNECTOR_MPO_2X16:
- case SFP_CONNECTOR_HSSDC_II:
- case SFP_CONNECTOR_COPPER_PIGTAIL:
- case SFP_CONNECTOR_NOSEPARATE:
- case SFP_CONNECTOR_MXC_2X16:
- default:
- /* a guess at the supported link modes */
- dev_warn(bus->sfp_dev,
- "Guessing link modes, please report...\n");
- phylink_set(support, 1000baseT_Half);
- phylink_set(support, 1000baseT_Full);
- break;
- }
}
EXPORT_SYMBOL_GPL(sfp_parse_support);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next A 1/5] sfp: use precision to print non-null terminated strings
From: Russell King @ 2017-12-29 12:15 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
In-Reply-To: <20171229121451.GY10595@n2100.armlinux.org.uk>
Rather than memcpy()'ing the strings and null terminate them, printf
allows non-NULL terminated strings provided the precision is not more
than the size of the buffer. Use this form to print the basic module
information rather than copying and terminating the strings.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/sfp.c | 24 ++++++------------------
1 file changed, 6 insertions(+), 18 deletions(-)
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index ee6b2e041171..6c7d9289078d 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -466,11 +466,6 @@ static int sfp_sm_mod_probe(struct sfp *sfp)
{
/* SFP module inserted - read I2C data */
struct sfp_eeprom_id id;
- char vendor[17];
- char part[17];
- char sn[17];
- char date[9];
- char rev[5];
u8 check;
int err;
@@ -506,19 +501,12 @@ static int sfp_sm_mod_probe(struct sfp *sfp)
sfp->id = id;
- memcpy(vendor, sfp->id.base.vendor_name, 16);
- vendor[16] = '\0';
- memcpy(part, sfp->id.base.vendor_pn, 16);
- part[16] = '\0';
- memcpy(rev, sfp->id.base.vendor_rev, 4);
- rev[4] = '\0';
- memcpy(sn, sfp->id.ext.vendor_sn, 16);
- sn[16] = '\0';
- memcpy(date, sfp->id.ext.datecode, 8);
- date[8] = '\0';
-
- dev_info(sfp->dev, "module %s %s rev %s sn %s dc %s\n",
- vendor, part, rev, sn, date);
+ dev_info(sfp->dev, "module %.*s %.*s rev %.*s sn %.*s dc %.*s\n",
+ (int)sizeof(id.base.vendor_name), id.base.vendor_name,
+ (int)sizeof(id.base.vendor_pn), id.base.vendor_pn,
+ (int)sizeof(id.base.vendor_rev), id.base.vendor_rev,
+ (int)sizeof(id.ext.vendor_sn), id.ext.vendor_sn,
+ (int)sizeof(id.ext.datecode), id.ext.datecode);
/* Check whether we support this module */
if (!sfp->type->module_supported(&sfp->id)) {
--
2.7.4
^ permalink raw reply related
* [PATCH net-next A 0/5] further sfp/phylink updates
From: Russell King - ARM Linux @ 2017-12-29 12:14 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli; +Cc: netdev
Hi,
This series:
- cleans up printing of module information
- improves the transceiver capability decoding, getting rid of the
guessing by connector type, improves direct-attach cable support
and adds support for 1G Base-PX and Base-BX10 modules.
- cleans up phylink_sfp_module_insert()
drivers/net/phy/phylink.c | 15 +++----
drivers/net/phy/sfp-bus.c | 101 +++++++++++++++++++++++++++++-----------------
drivers/net/phy/sfp.c | 24 +++--------
include/linux/sfp.h | 36 ++++++++++++++++-
4 files changed, 114 insertions(+), 62 deletions(-)
--
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
^ permalink raw reply
* Re: [RFT net-next v3 0/5] dwmac-meson8b: RGMII clock fixes for Meson8b
From: Emiliano Ingrassia @ 2017-12-29 12:04 UTC (permalink / raw)
To: Martin Blumenstingl
Cc: linus.luessing, Neil Armstrong, netdev, peppe.cavallaro,
alexandre.torgue, khilman, linux-amlogic, jbrunet
In-Reply-To: <CAFBinCDVRNKBTG0CHcmV9iJ9gb2VeODCfU6BO+dyRU6bVwkffg@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 8645 bytes --]
Hi Martin,
On Fri, Dec 29, 2017 at 08:48:54AM +0100, Martin Blumenstingl wrote:
> Hi Emiliano,
>
> On Fri, Dec 29, 2017 at 2:31 AM, Emiliano Ingrassia
> <ingrassia@epigenesys.com> wrote:
> > Hi Martin, Hi Dave,
> >
> > On Thu, Dec 28, 2017 at 11:21:23PM +0100, Martin Blumenstingl wrote:
> >> Hi Dave,
> >>
> >> please do not apply this series until it got a Tested-by from Emiliano.
> >>
> >>
> >> Hi Emiliano,
> >>
> >> you reported [0] that you couldn't get dwmac-meson8b to work on your
> >> Odroid-C1. With your findings (register dumps, clk_summary output, etc.)
> >> I think I was able to find a fix: it consists of two patches (which you
> >> find in this series)
> >>
> >> Unfortunately I don't have any Meson8b boards with RGMII PHY so I could
> >> only partially test this (I could only check if the clocks were
> >> calculated correctly when using a dummy 500002394Hz input clock instead
> >> of MPLL2).
> >>
> >> Could you please give this series a try and let me know about the
> >> results?
> >> You obviously still need your two "ARM: dts: meson8b" patches which
> >> - add the amlogic,meson8b-dwmac" compatible to meson8b.dtsi
> >> - enable Ethernet on the Odroid-C1
> >>
> >> When testing on Meson8b this also needs a fix for the MPLL clock driver:
> >> "clk: meson: mpll: use 64-bit maths in params_from_rate", see:
> >> https://patchwork.kernel.org/patch/10131677/
> >>
> >>
> >> I have tested this myself on a Khadas VIM (GXL SoC, internal RMII PHY)
> >> and a Khadas VIM2 (GXM SoC, external RGMII PHY). Both are still working
> >> fine (so let's hope that this also fixes your Meson8b issue :)).
> >>
> >>
> >> changes since v1 at [1]:
> >> - changed the subject of the cover-letter to indicate that this is all
> >> about the RGMII clock
> >> - added PATCH #1 which ensures that we don't unnecessarily change the
> >> parent clocks in RMII mode (and also makes the code easier to
> >> understand)
> >> - changed subject of PATCH #2 (formerly PATCH #1) to state that this
> >> is about the RGMII clock
> >> - added Jerome's Reviewed-by to PATCH #2 (formerly PATCH #1)
> >> - replaced PATCH #3 (formerly PATCH #2) with one that sets
> >> CLK_SET_RATE_PARENT on the mux and thus re-configures the MPLL2 clock
> >> on Meson8b correctly
> >>
> >> changes since v2 at [2]:
> >> - added PATCH #2 to make the following patch easier
> >> - Emiliano reported that there's currently another bug in the
> >> dwmac-meson8b driver which prevents it from working with RGMII PHYs on
> >> Meson8b: bit 10 of the PRG_ETH0 register is configures a clock gate
> >> (instead of a divide by 5 or divide by 10 clock divider). This has not
> >> been visible on GXBB and later due to the input clock which always led
> >> to a selection of "divide by 10" (which is done internally in the IP
> >> block, but the bit actually means "enable RGMII clock output").
> >> PATCH #3 was added to address this issue.
> >> - the commit message of PATCH #4 and #5 (formerly PATCH #2 and #3) were
> >> updated and the patch itself rebased because the m25_div clock was
> >> removed with the new PATCH #3 (so some of the statements were not
> >> valid anymore)
> >>
> >
> > Here is the clk_summary relative to ethernet on Odroid-C1+
> > with this new series applied:
> >
> > xtal 1 1 24000000 0 0
> > sys_pll 0 0 1200000000 0 0
> > cpu_clk 0 0 1200000000 0 0
> > vid_pll 0 0 732000000 0 0
> > fixed_pll 2 2 2550000000 0 0
> > mpll2 1 1 249999701 0 0
> > c9410000.ethernet#m250_sel 1 1 249999701 0 0
> > c9410000.ethernet#m250_div 1 1 249999701 0 0
> > c9410000.ethernet#fixed_div10 1 1 24999970 0 0
> > c9410000.ethernet#m25_en 1 1 24999970 0 0
> >
> > The ethernet prg0 register is set to 0x74A1 which should be correct with
> > respect to the information contained in the S805 SoC manual.
> > Actually, the ethernet is not yet fully functional.
> > Trying to ping the board, I can see ARP request from host to board using
> > tcpdump. However, the host can't see any response.
> great - we're getting closer!
>
> > Following the U-Boot value for prg0 register, which is 0x7d21, I also
> > tried to set bit 11. As expected, this did not have any influence.
> it *may* be something outside the PRG_ETH0 register than
> to confirm that: could you temporarily revert the last patch from this
> series ("net: stmmac: dwmac-meson8b: propagate rate changes to the
> parent clock")? this way MPLL2 will stay at ~500MHz and PRG_ETH0
> should be identical to what u-boot sets (apart from bit 11, but that
> is only relevant in RMII mode according to the datasheet)
>
Here is the clk_summary after your suggestion:
xtal 1 1 24000000 0 0
sys_pll 0 0 1200000000 0 0
cpu_clk 0 0 1200000000 0 0
vid_pll 0 0 732000000 0 0
fixed_pll 2 2 2550000000 0 0
mpll2 1 1 500002394 0 0
c9410000.ethernet#m250_sel 1 1 500002394 0 0
c9410000.ethernet#m250_div 1 1 166667465 0 0
c9410000.ethernet#fixed_div10 1 1 16666746 0 0
c9410000.ethernet#m25_en 1 1 16666746 0 0
which seems worse. Pinging the board, I still see ARP request/reply via
tcpdump. The host, however, can't see any.
> > Another thing that we should check is the "Ethernet Memory PD" (see S805
> > manual - sec. 5.4) register which bits 3-2 enable/disable ethernet
> > normal operation. However, those bits are already cleared by U-Boot.
> if the peripheral registers itself are configured correctly it's
> typically one of these issues:
> - gate clock not being enabled (can you confirm that you hav the
> "stmmaceth" with CLKID_ETH in the ethmac node?)
- yes, I have;
> - incorrect pinmux settings (as a hack I would remove all ethernet
> pinctrl properties/nodes from meson8b.dtsi and meson8b-odroidc1.dts.
> before booting the mainline kernel you'll need to use Ethernet from
> within u-boot once)
- tried; nothing changed;
> - incorrect TX delay (amlogic,tx-delay-ns = <2> should be defined in
> meson8b-odroidc1.dts, but the driver should auto-select that value if
> it's missing)
- defined as in odroid-c2 dts;
> - IP block being in some undefined state which can be brought back
> into a working state by adding the reset line (RESET_ETHERNET)
- I have it;
> - Ethernet PHY being in some undefined state can be brought back into
> a working state by adding the reset line (GPIOH_4, see
> meson-gxbb-odroidc2.dts how to use that)
- have it.
> - I have not seen that the power-domains ("Ethernet Memory PD") were a
> problem yet, but you already checked that
>
> maybe you can share your current .dts patch and a boot-log so others
> can have a look as well?
>
OK, no problem.
> > Thank you for the support.
> thank you for your patience as well, most people would have given up by now
>
> > Best regards,
> >
> > Emiliano
> >
> >>
> >> [0] http://lists.infradead.org/pipermail/linux-amlogic/2017-December/005596.html
> >> [1] http://lists.infradead.org/pipermail/linux-amlogic/2017-December/005848.html
> >> [2] http://lists.infradead.org/pipermail/linux-amlogic/2017-December/005861.html
> >>
> >>
> >> Martin Blumenstingl (5):
> >> net: stmmac: dwmac-meson8b: only configure the clocks in RGMII mode
> >> net: stmmac: dwmac-meson8b: simplify generating the clock names
> >> net: stmmac: dwmac-meson8b: fix internal RGMII clock configuration
> >> net: stmmac: dwmac-meson8b: fix setting the RGMII clock on Meson8b
> >> net: stmmac: dwmac-meson8b: propagate rate changes to the parent clock
> >>
> >> .../net/ethernet/stmicro/stmmac/dwmac-meson8b.c | 119 +++++++++++----------
> >> 1 file changed, 63 insertions(+), 56 deletions(-)
> >>
> >> --
> >> 2.15.1
> >>
>
>
> Regards
> Martin
>
Regards,
Emiliano
> _______________________________________________
> linux-amlogic mailing list
> linux-amlogic@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-amlogic
[-- Attachment #2: meson8b.dtsi --]
[-- Type: text/plain, Size: 7728 bytes --]
/*
* Copyright 2015 Endless Mobile, Inc.
* Author: Carlo Caione <carlo@endlessm.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
* licensing only applies to this file, and not this project as a
* whole.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Or, alternatively,
*
* b) Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <dt-bindings/clock/meson8b-clkc.h>
#include <dt-bindings/gpio/meson8b-gpio.h>
#include <dt-bindings/reset/amlogic,meson8b-reset.h>
#include <dt-bindings/reset/amlogic,meson8b-clkc-reset.h>
#include "meson.dtsi"
/ {
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@200 {
device_type = "cpu";
compatible = "arm,cortex-a5";
next-level-cache = <&L2>;
reg = <0x200>;
enable-method = "amlogic,meson8b-smp";
resets = <&clkc CLKC_RESET_CPU0_SOFT_RESET>;
};
cpu@201 {
device_type = "cpu";
compatible = "arm,cortex-a5";
next-level-cache = <&L2>;
reg = <0x201>;
enable-method = "amlogic,meson8b-smp";
resets = <&clkc CLKC_RESET_CPU1_SOFT_RESET>;
};
cpu@202 {
device_type = "cpu";
compatible = "arm,cortex-a5";
next-level-cache = <&L2>;
reg = <0x202>;
enable-method = "amlogic,meson8b-smp";
resets = <&clkc CLKC_RESET_CPU2_SOFT_RESET>;
};
cpu@203 {
device_type = "cpu";
compatible = "arm,cortex-a5";
next-level-cache = <&L2>;
reg = <0x203>;
enable-method = "amlogic,meson8b-smp";
resets = <&clkc CLKC_RESET_CPU3_SOFT_RESET>;
};
};
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
/* 2 MiB reserved for Hardware ROM Firmware? */
hwrom@0 {
reg = <0x0 0x200000>;
no-map;
};
};
scu@c4300000 {
compatible = "arm,cortex-a5-scu";
reg = <0xc4300000 0x100>;
};
}; /* end of / */
&aobus {
pmu: pmu@e0 {
compatible = "amlogic,meson8b-pmu", "syscon";
reg = <0xe0 0x18>;
};
pinctrl_aobus: pinctrl@84 {
compatible = "amlogic,meson8b-aobus-pinctrl";
reg = <0x84 0xc>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
gpio_ao: ao-bank@14 {
reg = <0x14 0x4>,
<0x2c 0x4>,
<0x24 0x8>;
reg-names = "mux", "pull", "gpio";
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl_aobus 0 0 16>;
};
uart_ao_a_pins: uart_ao_a {
mux {
groups = "uart_tx_ao_a", "uart_rx_ao_a";
function = "uart_ao";
};
};
};
};
&cbus {
clkc: clock-controller@4000 {
#clock-cells = <1>;
#reset-cells = <1>;
compatible = "amlogic,meson8b-clkc";
reg = <0x8000 0x4>, <0x4000 0x460>;
};
reset: reset-controller@4404 {
compatible = "amlogic,meson8b-reset";
reg = <0x4404 0x20>;
#reset-cells = <1>;
};
analog_top: analog-top@81a8 {
compatible = "amlogic,meson8b-analog-top", "syscon";
reg = <0x81a8 0x14>;
};
pwm_ef: pwm@86c0 {
compatible = "amlogic,meson8b-pwm";
reg = <0x86c0 0x10>;
#pwm-cells = <3>;
status = "disabled";
};
pinctrl_cbus: pinctrl@9880 {
compatible = "amlogic,meson8b-cbus-pinctrl";
reg = <0x9880 0x10>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
gpio: banks@80b0 {
reg = <0x80b0 0x28>,
<0x80e8 0x18>,
<0x8120 0x18>,
<0x8030 0x38>;
reg-names = "mux", "pull", "pull-enable", "gpio";
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl_cbus 0 0 130>;
};
eth_rgmii_pins: eth-rgmii {
mux {
groups = "eth_tx_clk",
"eth_tx_en",
"eth_txd1_0",
"eth_txd1_1",
"eth_txd0_0",
"eth_txd0_1",
"eth_rx_clk",
"eth_rx_dv",
"eth_rxd1",
"eth_rxd0",
"eth_mdio_en",
"eth_mdc",
"eth_ref_clk",
"eth_txd2",
"eth_txd3";
function = "ethernet";
};
};
};
};
&ahb_sram {
smp-sram@1ff80 {
compatible = "amlogic,meson8b-smp-sram";
reg = <0x1ff80 0x8>;
};
};
&efuse {
compatible = "amlogic,meson8b-efuse";
clocks = <&clkc CLKID_EFUSE>;
clock-names = "core";
};
ðmac {
compatible = "amlogic,meson8b-dwmac", "snps,dwmac-3.70a", "snps,dwmac";
reg = <0xc9410000 0x10000
0xc1108140 0x4>;
clocks = <&clkc CLKID_ETH>,
<&clkc CLKID_MPLL2>,
<&clkc CLKID_MPLL2>;
clock-names = "stmmaceth", "clkin0", "clkin1";
resets = <&reset RESET_ETHERNET>;
reset-names = "stmmaceth";
};
&gpio_intc {
compatible = "amlogic,meson-gpio-intc",
"amlogic,meson8b-gpio-intc";
status = "okay";
};
&hwrng {
compatible = "amlogic,meson8b-rng", "amlogic,meson-rng";
clocks = <&clkc CLKID_RNG0>;
clock-names = "core";
};
&L2 {
arm,data-latency = <3 3 3>;
arm,tag-latency = <2 2 2>;
arm,filter-ranges = <0x100000 0xc0000000>;
};
&pwm_ab {
compatible = "amlogic,meson8b-pwm";
};
&pwm_cd {
compatible = "amlogic,meson8b-pwm";
};
&saradc {
compatible = "amlogic,meson8b-saradc", "amlogic,meson-saradc";
clocks = <&clkc CLKID_XTAL>,
<&clkc CLKID_SAR_ADC>,
<&clkc CLKID_SANA>;
clock-names = "clkin", "core", "sana";
};
&sdio {
compatible = "amlogic,meson8b-sdio", "amlogic,meson-mx-sdio";
clocks = <&clkc CLKID_SDIO>, <&clkc CLKID_CLK81>;
clock-names = "core", "clkin";
};
&uart_AO {
clocks = <&clkc CLKID_CLK81>;
};
&uart_A {
clocks = <&clkc CLKID_CLK81>;
};
&uart_B {
clocks = <&clkc CLKID_CLK81>;
};
&uart_C {
clocks = <&clkc CLKID_CLK81>;
};
&usb0 {
compatible = "amlogic,meson8b-usb", "snps,dwc2";
clocks = <&clkc CLKID_USB0_DDR_BRIDGE>;
clock-names = "otg";
};
&usb1 {
compatible = "amlogic,meson8b-usb", "snps,dwc2";
clocks = <&clkc CLKID_USB1_DDR_BRIDGE>;
clock-names = "otg";
};
&usb0_phy {
compatible = "amlogic,meson8b-usb2-phy", "amlogic,meson-mx-usb2-phy";
clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB0>;
clock-names = "usb_general", "usb";
resets = <&reset RESET_USB_OTG>;
};
&usb1_phy {
compatible = "amlogic,meson8b-usb2-phy", "amlogic,meson-mx-usb2-phy";
clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB1>;
clock-names = "usb_general", "usb";
resets = <&reset RESET_USB_OTG>;
};
&wdt {
compatible = "amlogic,meson8b-wdt";
};
[-- Attachment #3: meson8b-odroidc1.dts --]
[-- Type: text/plain, Size: 3850 bytes --]
/*
* Copyright 2015 Endless Mobile, Inc.
* Author: Carlo Caione <carlo@endlessm.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
* licensing only applies to this file, and not this project as a
* whole.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Or, alternatively,
*
* b) Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
#include "meson8b.dtsi"
#include <dt-bindings/gpio/gpio.h>
/ {
model = "Hardkernel ODROID-C1";
compatible = "hardkernel,odroid-c1", "amlogic,meson8b";
aliases {
serial0 = &uart_AO;
};
memory {
reg = <0x40000000 0x40000000>;
};
leds {
compatible = "gpio-leds";
blue {
label = "c1:blue:alive";
gpios = <&gpio_ao GPIOAO_13 GPIO_ACTIVE_LOW>;
linux,default-trigger = "heartbeat";
default-state = "off";
};
};
};
&uart_AO {
status = "okay";
pinctrl-0 = <&uart_ao_a_pins>;
pinctrl-names = "default";
};
&gpio_ao {
/*
* WARNING: The USB Hub on the Odroid-C1/C1+ needs a reset signal
* to be turned high in order to be detected by the USB Controller.
* This signal should be handled by a USB specific power sequence
* in order to reset the Hub when USB bus is powered down.
*/
usb-hub {
gpio-hog;
gpios = <GPIOAO_4 GPIO_ACTIVE_HIGH>;
output-high;
line-name = "usb-hub-reset";
};
};
&usb1_phy {
status = "okay";
};
&usb1 {
status = "okay";
};
ðmac {
status = "okay";
snps,reset-gpio = <&gpio GPIOH_4 GPIO_ACTIVE_HIGH>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 30000>;
pinctrl-0 = <ð_rgmii_pins>;
pinctrl-names = "default";
phy-mode = "rgmii";
phy-handle = <ð_phy>;
amlogic,tx-delay-ns = <2>;
mdio {
compatible = "snps,dwmac-mdio";
#address-cells = <1>;
#size-cells = <0>;
eth_phy: ethernet-phy@0 {
/* ethernet PHY RTL8211F */
compatible = "ethernet-phy-id001c.c916",
"ethernet-phy-ieee802.3-c22";
reg = <0>;
max-speed = <1000>;
eee-broken-1000t;
interrupt-parent = <&gpio_intc>;
interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
};
};
};
^ permalink raw reply
* Re: [PATCH] NET: usb: qmi_wwan: add support for YUGA CLM920-NC5 PID 0x9625
From: Bjørn Mork @ 2017-12-29 11:45 UTC (permalink / raw)
To: SZ Lin (林上智)
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20171229090217.6933-1-sz.lin-D4fb9hXD9d4@public.gmane.org>
"SZ Lin (林上智)" <sz.lin-D4fb9hXD9d4@public.gmane.org> writes:
> This patch adds support for PID 0x9625 of YUGA CLM920-NC5.
>
> YUGA CLM920-NC5 needs to enable QMI_WWAN_QUIRK_DTR before QMI operation.
>
> qmicli -d /dev/cdc-wdm0 -p --dms-get-revision
> [/dev/cdc-wdm0] Device revision retrieved:
> Revision: 'CLM920_NC5-V1 1 [Oct 23 2016 19:00:00]'
>
> Signed-off-by: SZ Lin (林上智) <sz.lin-D4fb9hXD9d4@public.gmane.org>
> ---
> drivers/net/usb/qmi_wwan.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
> index 3000ddd1c7e2..728819feab44 100644
> --- a/drivers/net/usb/qmi_wwan.c
> +++ b/drivers/net/usb/qmi_wwan.c
> @@ -1100,6 +1100,7 @@ static const struct usb_device_id products[] = {
> {QMI_FIXED_INTF(0x05c6, 0x9084, 4)},
> {QMI_FIXED_INTF(0x05c6, 0x920d, 0)},
> {QMI_FIXED_INTF(0x05c6, 0x920d, 5)},
> + {QMI_QUIRK_SET_DTR(0x05c6, 0x9625, 4)}, /* YUGA CLM920-NC5 */
> {QMI_FIXED_INTF(0x0846, 0x68a2, 8)},
> {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */
> {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)}, /* Huawei E1820 */
Perfect. Thanks
Acked-by: Bjørn Mork <bjorn-yOkvZcmFvRU@public.gmane.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH net-next 5/6] arm64: dts: marvell: mcbin: enable the fourth network interface
From: Russell King - ARM Linux @ 2017-12-29 11:38 UTC (permalink / raw)
To: Marcin Wojtas
Cc: Thomas Petazzoni, Andrew Lunn, Florian Fainelli, Yan Markman,
Jason Cooper, netdev, Antoine Tenart, linux-kernel, kishon,
nadavh, Miquèl Raynal, Gregory Clément, Stefan Chulski,
David S. Miller, linux-arm-kernel, Sebastian Hesselbarth
In-Reply-To: <CAPv3WKdNCOB=1BqGXw7gXZNX+bBhOXVfheYPjC4CFZjfiOXyHQ@mail.gmail.com>
On Fri, Dec 29, 2017 at 12:12:15PM +0100, Marcin Wojtas wrote:
> Hi Russell,
>
> I see that I misspelled your email address, hence the series remained unnoticed:
> https://lkml.org/lkml/2017/12/18/216
>
> In terms of the phylink support, I think the most important are:
> * 3/8
> https://lkml.org/lkml/2017/12/18/211
> * 7/8
> https://lkml.org/lkml/2017/12/18/207
>
> I think the way of obtaining PHY fwnode and connecting it from the
> latter patch could be incorporated to the phylink code. Although I
> didn't get much feedback, the whole ACPI-handling of MDIO bus and the
> PHYs touch ACPI specification and I expect it a slower to get merged.
> Hence my idea is following:
> * Send v2 with ACPI supporting link-irq only in mvpp2.c
> * Extract MDIO bus handling for ACPI and propose PHY handling
> modifications in phylink.
>
> This way we may push the two things forwards in more efficient way.
> I'm looking forward to your opinion.
Agreed - as we have very few users of phylink at the moment (they're
mostly all in external trees) we can easily change the phylink
interfaces. The first step is solving the ACPI representation of the
MDIO bus and attached devices, and until that is settled, not much can
be done.
However, it seems to me that the issues of adding ACPI to mvpp2 vs
adding phylink to mvpp2 are two entirely separate problems that don't
really conflict with each other - since the "phy" problem afflicts
both.
However, I'm not sure what this "link-irq" thing is that you talk
about (and I suspect it's one of the things that I've been trying for
months to find out about from Antoine when he says that there's stuff
that mvpp2 supports that phylink doesn't.) So, I'm left to guess, and
I guess it's the mvpp2-variant of mvneta's in-band autonegotiation.
Continuing to guess from the mvpp2 phylink conversion patch, this mvpp2
variant is selected by not providing a phy handle in DT, whereas
mvneta's variant is selected using the ethernet-standard property
'managed = "in-band-status"'.
If my guessing is correct, I have to wonder why mvpp2 invented a
different way to represent this from mvneta? This makes it much more
difficult to convert mvpp2 to phylink, and it also makes it difficult
to add SFP support ignoring the phylink issue (since there is no phy
handle there either.)
--
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
^ permalink raw reply
* Re: [PATCH net-next 5/6] arm64: dts: marvell: mcbin: enable the fourth network interface
From: Marcin Wojtas @ 2017-12-29 11:12 UTC (permalink / raw)
To: Russell King - ARM Linux
Cc: Antoine Tenart, Florian Fainelli, Andrew Lunn, Thomas Petazzoni,
Yan Markman, Jason Cooper, netdev, linux-kernel, kishon, nadavh,
Miquèl Raynal, Gregory Clément, Stefan Chulski,
David S. Miller, linux-arm-kernel, Sebastian Hesselbarth
In-Reply-To: <20171228184642.GV10595@n2100.armlinux.org.uk>
Hi Russell,
2017-12-28 19:46 GMT+01:00 Russell King - ARM Linux <linux@armlinux.org.uk>:
> On Thu, Dec 28, 2017 at 07:27:39PM +0100, Antoine Tenart wrote:
>> Hi Florian,
>>
>> On Thu, Dec 28, 2017 at 07:02:09AM -0800, Florian Fainelli wrote:
>> > On 12/28/2017 02:05 AM, Antoine Tenart wrote:
>> > > On Thu, Dec 28, 2017 at 08:46:23AM +0100, Andrew Lunn wrote:
>> > >> On Wed, Dec 27, 2017 at 10:24:01PM +0000, Russell King - ARM Linux wrote:
>> > >>> On Wed, Dec 27, 2017 at 11:14:45PM +0100, Antoine Tenart wrote:
>> > >>>>
>> > >>>> +&cps_eth2 {
>> > >>>> + /* CPS Lane 5 */
>> > >>>> + status = "okay";
>> > >>>> + phy-mode = "2500base-x";
>> > >>>> + /* Generic PHY, providing serdes lanes */
>> > >>>> + phys = <&cps_comphy5 2>;
>> > >>>> +};
>> > >>>> +
>> > >>>
>> > >>> This is wrong. This lane is connected to a SFP cage which can support
>> > >>> more than just 2500base-X. Tying it in this way to 2500base-X means
>> > >>> that this port does not support conenctions at 1000base-X, despite
>> > >>> that's one of the most popular and more standardised speeds.
>> > >>>
>> > >>
>> > >> I agree with Russell here. SFP modules are hot pluggable, and support
>> > >> a range of interface modes. You need to query what the SFP module is
>> > >> in order to know how to configure the SERDES interface. The phylink
>> > >> infrastructure does that for you.
>> > >
>> > > Sure, I understand. We'll be able to support such interfaces only when
>> > > the phylink PPv2 support lands in.
>> >
>> > Should we expect PHYLINK support to make it as the first patch in your
>> > v2 of this patch series, or is someone else doing that?
>>
>> No, the phylink patch conflicts with Marcin's ACPI series and we agreed
>> to let him get his series merged first. And I will probably work on a
>> few other topics before having the chance to work on it. So it'll
>> probably be me doing that, but not right now.
>
> ACPI is going to be a problem with phylink for a while. There's patches
> queued in net-next which convert phylink and SFP mostly to the fwnode
> and property based systems, but phylib and i2c do not seem to have the
> necessary bits to be able to deal with those.
>
> Specifically, in DT we have "of_find_i2c_adapter_by_node()" but afaics
> there is no equivalent in ACPI - which means in an ACPI based system
> we have no way to determine the I2C bus associated with a SFP socket,
> which is a rather fundamental issue for SFP modules.
>
> For phylib side, there's "of_phy_attach()" but again there is no
> equivalent in ACPI. This should not be that much of a problem, because
> network drivers using the DT phylib calls (eg, "of_phy_connect()") are
> already restricted by this. That may have been solved by Marcin's
> series, but I've not seen it to know.
>
I see that I misspelled your email address, hence the series remained unnoticed:
https://lkml.org/lkml/2017/12/18/216
In terms of the phylink support, I think the most important are:
* 3/8
https://lkml.org/lkml/2017/12/18/211
* 7/8
https://lkml.org/lkml/2017/12/18/207
I think the way of obtaining PHY fwnode and connecting it from the
latter patch could be incorporated to the phylink code. Although I
didn't get much feedback, the whole ACPI-handling of MDIO bus and the
PHYs touch ACPI specification and I expect it a slower to get merged.
Hence my idea is following:
* Send v2 with ACPI supporting link-irq only in mvpp2.c
* Extract MDIO bus handling for ACPI and propose PHY handling
modifications in phylink.
This way we may push the two things forwards in more efficient way.
I'm looking forward to your opinion.
Best regards,
Marcin
^ permalink raw reply
* [iptables] extensions: add support for 'srh' match
From: Ahmed Abdelsalam @ 2017-12-29 11:08 UTC (permalink / raw)
To: pablo, kadlec, fw, davem, kuznet, yoshfuji
Cc: linux-kernel, netfilter-devel, coreteam, netdev, amsalam20
This patch adds a new exetension to iptables to supprt 'srh' match
The implementation considers revision 7 of the SRH draft.
https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-07
Signed-off-by: Ahmed Abdelsalam <amsalam20@gmail.com>
---
extensions/libip6t_srh.c | 283 ++++++++++++++++++++++++++++++++
include/linux/netfilter_ipv6/ip6t_srh.h | 63 +++++++
2 files changed, 346 insertions(+)
create mode 100644 extensions/libip6t_srh.c
create mode 100644 include/linux/netfilter_ipv6/ip6t_srh.h
diff --git a/extensions/libip6t_srh.c b/extensions/libip6t_srh.c
new file mode 100644
index 0000000..fd92ba1
--- /dev/null
+++ b/extensions/libip6t_srh.c
@@ -0,0 +1,283 @@
+/**
+ * Segment Routing Header 'srh' match extension
+ *
+ * Author:
+ * Ahmed Abdelsalam <amsalam20@gmail.com>
+ */
+
+#include <stdio.h>
+#include <xtables.h>
+#include <linux/netfilter_ipv6/ip6t_srh.h>
+#include <string.h>
+
+/* srh command-line options */
+enum {
+ O_SRH_NEXTHDR,
+ O_SRH_LEN_EQ,
+ O_SRH_LEN_GT,
+ O_SRH_LEN_LT,
+ O_SRH_SEGS_EQ,
+ O_SRH_SEGS_GT,
+ O_SRH_SEGS_LT,
+ O_SRH_LAST_EQ,
+ O_SRH_LAST_GT,
+ O_SRH_LAST_LT,
+ O_SRH_TAG,
+};
+
+static void srh_help(void)
+{
+ printf(
+"srh match options:\n"
+"[!] --srh-next-hdr next-hdr Next Header value of SRH\n"
+"[!] --srh-len-eq hdr_len Hdr Ext Len value of SRH\n"
+"[!] --srh-len-gt hdr_len Hdr Ext Len value of SRH\n"
+"[!] --srh-len-lt hdr_len Hdr Ext Len value of SRH\n"
+"[!] --srh-segs-eq segs_left Segments Left value of SRH\n"
+"[!] --srh-segs-gt segs_left Segments Left value of SRH\n"
+"[!] --srh-segs-lt segs_left Segments Left value of SRH\n"
+"[!] --srh-last-eq last_entry Last Entry value of SRH\n"
+"[!] --srh-last-gt last_entry Last Entry value of SRH\n"
+"[!] --srh-last-lt last_entry Last Entry value of SRH\n"
+"[!] --srh-tag tag Tag value of SRH\n");
+}
+
+#define s struct ip6t_srh
+static const struct xt_option_entry srh_opts[] = {
+ { .name = "srh-next-hdr", .id = O_SRH_NEXTHDR, .type = XTTYPE_UINT8,
+ .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, next_hdr)},
+ { .name = "srh-len-eq", .id = O_SRH_LEN_EQ, .type = XTTYPE_UINT8,
+ .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdr_len)},
+ { .name = "srh-len-gt", .id = O_SRH_LEN_GT, .type = XTTYPE_UINT8,
+ .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdr_len)},
+ { .name = "srh-len-lt", .id = O_SRH_LEN_LT, .type = XTTYPE_UINT8,
+ .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdr_len)},
+ { .name = "srh-segs-eq", .id = O_SRH_SEGS_EQ, .type = XTTYPE_UINT8,
+ .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segs_left)},
+ { .name = "srh-segs-gt", .id = O_SRH_SEGS_GT, .type = XTTYPE_UINT8,
+ .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segs_left)},
+ { .name = "srh-segs-lt", .id = O_SRH_SEGS_LT, .type = XTTYPE_UINT8,
+ .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segs_left)},
+ { .name = "srh-last-eq", .id = O_SRH_LAST_EQ, .type = XTTYPE_UINT8,
+ .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, last_entry)},
+ { .name = "srh-last-gt", .id = O_SRH_LAST_GT, .type = XTTYPE_UINT8,
+ flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, last_entry)},
+ { .name = "srh-last-lt", .id = O_SRH_LAST_LT, .type = XTTYPE_UINT8,
+ .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, last_entry)},
+ { .name = "srh-tag", .id = O_SRH_TAG, .type = XTTYPE_UINT16,
+ .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, tag)},
+ { }
+};
+#undef s
+
+static void srh_init(struct xt_entry_match *m)
+{
+ struct ip6t_srh *srhinfo = (void *)m->data;
+
+ srhinfo->mt_flags = 0;
+ srhinfo->mt_invflags = 0;
+}
+
+static void srh_parse(struct xt_option_call *cb)
+{
+ struct ip6t_srh *srhinfo = cb->data;
+
+ xtables_option_parse(cb);
+ switch (cb->entry->id) {
+ case O_SRH_NEXTHDR:
+ srhinfo->mt_flags |= IP6T_SRH_NEXTHDR;
+ if (cb->invert)
+ srhinfo->mt_invflags |= IP6T_SRH_INV_NEXTHDR;
+ break;
+ case O_SRH_LEN_EQ:
+ srhinfo->mt_flags |= IP6T_SRH_LEN_EQ;
+ if (cb->invert)
+ srhinfo->mt_invflags |= IP6T_SRH_INV_LEN_EQ;
+ break;
+ case O_SRH_LEN_GT:
+ srhinfo->mt_flags |= IP6T_SRH_LEN_GT;
+ if (cb->invert)
+ srhinfo->mt_invflags |= IP6T_SRH_INV_LEN_GT;
+ break;
+ case O_SRH_LEN_LT:
+ srhinfo->mt_flags |= IP6T_SRH_LEN_LT;
+ if (cb->invert)
+ srhinfo->mt_invflags |= IP6T_SRH_INV_LEN_LT;
+ break;
+ case O_SRH_SEGS_EQ:
+ srhinfo->mt_flags |= IP6T_SRH_SEGS_EQ;
+ if (cb->invert)
+ srhinfo->mt_invflags |= IP6T_SRH_INV_SEGS_EQ;
+ break;
+ case O_SRH_SEGS_GT:
+ srhinfo->mt_flags |= IP6T_SRH_SEGS_GT;
+ if (cb->invert)
+ srhinfo->mt_invflags |= IP6T_SRH_INV_SEGS_GT;
+ break;
+ case O_SRH_SEGS_LT:
+ srhinfo->mt_flags |= IP6T_SRH_SEGS_LT;
+ if (cb->invert)
+ srhinfo->mt_invflags |= IP6T_SRH_INV_SEGS_LT;
+ break;
+ case O_SRH_LAST_EQ:
+ srhinfo->mt_flags |= IP6T_SRH_LAST_EQ;
+ if (cb->invert)
+ srhinfo->mt_invflags |= IP6T_SRH_INV_LAST_EQ;
+ break;
+ case O_SRH_LAST_GT:
+ srhinfo->mt_flags |= IP6T_SRH_LAST_GT;
+ if (cb->invert)
+ srhinfo->mt_invflags |= IP6T_SRH_INV_LAST_GT;
+ break;
+ case O_SRH_LAST_LT:
+ srhinfo->mt_flags |= IP6T_SRH_LAST_LT;
+ if (cb->invert)
+ srhinfo->mt_invflags |= IP6T_SRH_INV_LAST_LT;
+ break;
+ case O_SRH_TAG:
+ srhinfo->mt_flags |= IP6T_SRH_TAG;
+ if (cb->invert)
+ srhinfo->mt_invflags |= IP6T_SRH_INV_TAG;
+ break;
+ }
+}
+
+static const char *pinv(bool invert)
+{
+ const char *inv = invert ? "!" : " ";
+ return inv;
+}
+
+static void srh_print(const void *ip, const struct xt_entry_match *match,
+ int numeric)
+{
+ const struct ip6t_srh *srhinfo = (struct ip6t_srh *)match->data;
+
+ printf(" srh ");
+
+ if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR)
+ printf("next-hdr %s=%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_NEXTHDR),
+ srhinfo->next_hdr);
+
+ if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ)
+ printf("hdr-len %s=%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_LEN_EQ),
+ srhinfo->hdr_len);
+ if (srhinfo->mt_flags & IP6T_SRH_LEN_GT)
+ printf("hdr-len %s>%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_LEN_GT),
+ srhinfo->hdr_len);
+ if (srhinfo->mt_flags & IP6T_SRH_LEN_LT)
+ printf("hdr-len %s<%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_LEN_LT),
+ srhinfo->hdr_len);
+
+ if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ)
+ printf("segs-left %s=%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_EQ),
+ srhinfo->segs_left);
+ if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT)
+ printf("segs-left %s>%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_GT),
+ srhinfo->segs_left);
+ if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT)
+ printf("segs-left %s<%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_LT),
+ srhinfo->segs_left);
+
+ if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ)
+ printf("last-entry %s=%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_LAST_EQ),
+ srhinfo->last_entry);
+ if (srhinfo->mt_flags & IP6T_SRH_LAST_GT)
+ printf("last-entry %s>%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_LAST_GT),
+ srhinfo->last_entry);
+ if (srhinfo->mt_flags & IP6T_SRH_LAST_LT)
+ printf("last-entry %s<%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_LAST_LT),
+ srhinfo->last_entry);
+
+ if (srhinfo->mt_flags & IP6T_SRH_TAG)
+ printf("tag %s=%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_TAG),
+ srhinfo->tag);
+
+}
+
+static void srh_save(const void *ip, const struct xt_entry_match *match)
+{
+ const struct ip6t_srh *srhinfo = (struct ip6t_srh *)match->data;
+
+ printf(" srh ");
+
+ if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR)
+ printf("next-hdr %s=%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_NEXTHDR),
+ srhinfo->next_hdr);
+
+ if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ)
+ printf("hdr-len %s=%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_LEN_EQ),
+ srhinfo->hdr_len);
+ if (srhinfo->mt_flags & IP6T_SRH_LEN_GT)
+ printf("hdr-len %s>%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_LEN_GT),
+ srhinfo->hdr_len);
+ if (srhinfo->mt_flags & IP6T_SRH_LEN_LT)
+ printf("hdr-len %s<%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_LEN_LT),
+ srhinfo->hdr_len);
+
+ if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ)
+ printf("segs-left %s=%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_EQ),
+ srhinfo->segs_left);
+ if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT)
+ printf("segs-left %s>%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_GT),
+ srhinfo->segs_left);
+ if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT)
+ printf("segs-left %s<%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_LT),
+ srhinfo->segs_left);
+
+ if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ)
+ printf("last-entry %s=%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_LAST_EQ),
+ srhinfo->last_entry);
+ if (srhinfo->mt_flags & IP6T_SRH_LAST_GT)
+ printf("last-entry %s>%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_LAST_GT),
+ srhinfo->last_entry);
+ if (srhinfo->mt_flags & IP6T_SRH_LAST_LT)
+ printf("last-entry %s<%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_LAST_LT),
+ srhinfo->last_entry);
+
+ if (srhinfo->mt_flags & IP6T_SRH_TAG)
+ printf("tag %s=%d ",
+ pinv(srhinfo->mt_invflags & IP6T_SRH_INV_TAG),
+ srhinfo->tag);
+}
+
+static struct xtables_match srh_mt6_reg = {
+ .name = "srh",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV6,
+ .size = XT_ALIGN(sizeof(struct ip6t_srh)),
+ .userspacesize = XT_ALIGN(sizeof(struct ip6t_srh)),
+ .help = srh_help,
+ .init = srh_init,
+ .print = srh_print,
+ .save = srh_save,
+ .x6_parse = srh_parse,
+ .x6_options = srh_opts,
+};
+
+void
+_init(void)
+{
+ xtables_register_match(&srh_mt6_reg);
+}
diff --git a/include/linux/netfilter_ipv6/ip6t_srh.h b/include/linux/netfilter_ipv6/ip6t_srh.h
new file mode 100644
index 0000000..bc27197
--- /dev/null
+++ b/include/linux/netfilter_ipv6/ip6t_srh.h
@@ -0,0 +1,63 @@
+/**
+ * Definitions for Segment Routing Header 'srh' match
+ *
+ * Author:
+ * Ahmed Abdelsalam <amsalam20@gmail.com>
+ */
+
+#ifndef _IP6T_SRH_H
+#define _IP6T_SRH_H
+
+#include <linux/types.h>
+#include <linux/netfilter.h>
+
+/* Values for "mt_flags" field in struct ip6t_srh */
+#define IP6T_SRH_NEXTHDR 0x0001
+#define IP6T_SRH_LEN_EQ 0x0002
+#define IP6T_SRH_LEN_GT 0x0004
+#define IP6T_SRH_LEN_LT 0x0008
+#define IP6T_SRH_SEGS_EQ 0x0010
+#define IP6T_SRH_SEGS_GT 0x0020
+#define IP6T_SRH_SEGS_LT 0x0040
+#define IP6T_SRH_LAST_EQ 0x0080
+#define IP6T_SRH_LAST_GT 0x0100
+#define IP6T_SRH_LAST_LT 0x0200
+#define IP6T_SRH_TAG 0x0400
+#define IP6T_SRH_MASK 0x07FF
+
+/* Values for "mt_invflags" field in struct ip6t_srh */
+#define IP6T_SRH_INV_NEXTHDR 0x0001
+#define IP6T_SRH_INV_LEN_EQ 0x0002
+#define IP6T_SRH_INV_LEN_GT 0x0004
+#define IP6T_SRH_INV_LEN_LT 0x0008
+#define IP6T_SRH_INV_SEGS_EQ 0x0010
+#define IP6T_SRH_INV_SEGS_GT 0x0020
+#define IP6T_SRH_INV_SEGS_LT 0x0040
+#define IP6T_SRH_INV_LAST_EQ 0x0080
+#define IP6T_SRH_INV_LAST_GT 0x0100
+#define IP6T_SRH_INV_LAST_LT 0x0200
+#define IP6T_SRH_INV_TAG 0x0400
+#define IP6T_SRH_INV_MASK 0x07FF
+
+/**
+ * struct ip6t_srh - SRH match options
+ * @ next_hdr: Next header field of SRH
+ * @ hdr_len: Extension header length field of SRH
+ * @ segs_left: Segments left field of SRH
+ * @ last_entry: Last entry field of SRH
+ * @ tag: Tag field of SRH
+ * @ mt_flags: match options
+ * @ mt_invflags: Invert the sense of match options
+ */
+
+struct ip6t_srh {
+ __u8 next_hdr;
+ __u8 hdr_len;
+ __u8 segs_left;
+ __u8 last_entry;
+ __u16 tag;
+ __u16 mt_flags;
+ __u16 mt_invflags;
+};
+
+#endif /*_IP6T_SRH_H*/
--
2.1.4
^ permalink raw reply related
* [net-next] netfilter: add segment routing header 'srh' match
From: Ahmed Abdelsalam @ 2017-12-29 11:07 UTC (permalink / raw)
To: pablo, kadlec, fw, davem, kuznet, yoshfuji
Cc: linux-kernel, netfilter-devel, coreteam, netdev, amsalam20
It allows matching packets based on Segment Routing Header
(SRH) information.
The implementation considers revision 7 of the SRH draft.
https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-07
Currently supported match options include:
(1) Next Header
(2) Hdr Ext Len
(3) Segments Left
(4) Last Entry
(5) Tag value of SRH
Signed-off-by: Ahmed Abdelsalam <amsalam20@gmail.com>
---
include/uapi/linux/netfilter_ipv6/ip6t_srh.h | 63 ++++++++++
net/ipv6/netfilter/Kconfig | 9 ++
net/ipv6/netfilter/Makefile | 1 +
net/ipv6/netfilter/ip6t_srh.c | 165 +++++++++++++++++++++++++++
4 files changed, 238 insertions(+)
create mode 100644 include/uapi/linux/netfilter_ipv6/ip6t_srh.h
create mode 100644 net/ipv6/netfilter/ip6t_srh.c
diff --git a/include/uapi/linux/netfilter_ipv6/ip6t_srh.h b/include/uapi/linux/netfilter_ipv6/ip6t_srh.h
new file mode 100644
index 0000000..1b5dbd8
--- /dev/null
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_srh.h
@@ -0,0 +1,63 @@
+/**
+ * Definitions for Segment Routing Header 'srh' match
+ *
+ * Author:
+ * Ahmed Abdelsalam <amsalam20@gmail.com>
+ */
+
+#ifndef _IP6T_SRH_H
+#define _IP6T_SRH_H
+
+#include <linux/types.h>
+#include <linux/netfilter.h>
+
+/* Values for "mt_flags" field in struct ip6t_srh */
+#define IP6T_SRH_NEXTHDR 0x0001
+#define IP6T_SRH_LEN_EQ 0x0002
+#define IP6T_SRH_LEN_GT 0x0004
+#define IP6T_SRH_LEN_LT 0x0008
+#define IP6T_SRH_SEGS_EQ 0x0010
+#define IP6T_SRH_SEGS_GT 0x0020
+#define IP6T_SRH_SEGS_LT 0x0040
+#define IP6T_SRH_LAST_EQ 0x0080
+#define IP6T_SRH_LAST_GT 0x0100
+#define IP6T_SRH_LAST_LT 0x0200
+#define IP6T_SRH_TAG 0x0400
+#define IP6T_SRH_MASK 0x07FF
+
+/* Values for "mt_invflags" field in struct ip6t_srh */
+#define IP6T_SRH_INV_NEXTHDR 0x0001
+#define IP6T_SRH_INV_LEN_EQ 0x0002
+#define IP6T_SRH_INV_LEN_GT 0x0004
+#define IP6T_SRH_INV_LEN_LT 0x0008
+#define IP6T_SRH_INV_SEGS_EQ 0x0010
+#define IP6T_SRH_INV_SEGS_GT 0x0020
+#define IP6T_SRH_INV_SEGS_LT 0x0040
+#define IP6T_SRH_INV_LAST_EQ 0x0080
+#define IP6T_SRH_INV_LAST_GT 0x0100
+#define IP6T_SRH_INV_LAST_LT 0x0200
+#define IP6T_SRH_INV_TAG 0x0400
+#define IP6T_SRH_INV_MASK 0x07FF
+
+/**
+ * struct ip6t_srh - SRH match options
+ * @ next_hdr: Next header field of SRH
+ * @ hdr_len: Extension header length field of SRH
+ * @ segs_left: Segments left field of SRH
+ * @ last_entry: Last entry field of SRH
+ * @ tag: Tag field of SRH
+ * @ mt_flags: match options
+ * @ mt_invflags: Invert the sense of match options
+ */
+
+struct ip6t_srh {
+ __u8 next_hdr;
+ __u8 hdr_len;
+ __u8 segs_left;
+ __u8 last_entry;
+ __u16 tag;
+ __u16 mt_flags;
+ __u16 mt_invflags;
+};
+
+#endif /*_IP6T_SRH_H*/
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 6acb2ee..e1818eb 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -232,6 +232,15 @@ config IP6_NF_MATCH_RT
To compile it as a module, choose M here. If unsure, say N.
+config IP6_NF_MATCH_SRH
+ tristate '"srh" Segment Routing header match support'
+ depends on NETFILTER_ADVANCED
+ help
+ srh matching allows you to match packets based on the segment
+ routing header of the packet.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
# The targets
config IP6_NF_TARGET_HL
tristate '"HL" hoplimit target support'
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index c6ee0cd..e0d51a9 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o
obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o
obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o
obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
+obj-$(CONFIG_IP6_NF_MATCH_SRH) += ip6t_srh.o
# targets
obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
diff --git a/net/ipv6/netfilter/ip6t_srh.c b/net/ipv6/netfilter/ip6t_srh.c
new file mode 100644
index 0000000..75e41dc9
--- /dev/null
+++ b/net/ipv6/netfilter/ip6t_srh.c
@@ -0,0 +1,165 @@
+/*
+ * Kernel module to match Segment Routing Header (SRH) parameters.
+ *
+ * Author:
+ * Ahmed Abdelsalam <amsalam20@gmail.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/ipv6.h>
+#include <net/seg6.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_ipv6/ip6t_srh.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Xtables: IPv6 Segment Routing Header match");
+MODULE_AUTHOR("Ahmed Abdelsalam <amsalam20@gmail.com>");
+
+/* Test a struct->mt_invflags and a boolean for inequality */
+#define NF_SRH_INVF(ptr, flag, boolean) \
+ ((boolean) ^ !!((ptr)->mt_invflags & (flag)))
+
+static bool srh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct ip6t_srh *srhinfo = par->matchinfo;
+ struct ipv6_sr_hdr *srh;
+ struct ipv6_sr_hdr _srh;
+ int hdrlen, srhoff = 0;
+
+ if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
+ return false;
+
+ srh = skb_header_pointer(skb, srhoff, sizeof(_srh), &_srh);
+
+ if (!srh)
+ return false;
+
+ hdrlen = ipv6_optlen(srh);
+ if (skb->len - srhoff < hdrlen)
+ return false;
+
+ if (srh->type != IPV6_SRCRT_TYPE_4)
+ return false;
+
+ if (srh->segments_left > srh->first_segment)
+ return false;
+
+ /* Next Header matching */
+ if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR)
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_NEXTHDR,
+ !(srh->nexthdr == srhinfo->next_hdr)))
+ return false;
+
+ /* Header Extension Length matching */
+ if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ)
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_EQ,
+ !(srh->hdrlen == srhinfo->hdr_len)))
+ return false;
+
+ if (srhinfo->mt_flags & IP6T_SRH_LEN_GT)
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_GT,
+ !(srh->hdrlen > srhinfo->hdr_len)))
+ return false;
+
+ if (srhinfo->mt_flags & IP6T_SRH_LEN_LT)
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_LT,
+ !(srh->hdrlen < srhinfo->hdr_len)))
+ return false;
+
+ /* Segments Left matching */
+ if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ)
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_EQ,
+ !(srh->segments_left == srhinfo->segs_left)))
+ return false;
+
+ if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT)
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_GT,
+ !(srh->segments_left > srhinfo->segs_left)))
+ return false;
+
+ if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT)
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_LT,
+ !(srh->segments_left < srhinfo->segs_left)))
+ return false;
+
+ /**
+ * Last Entry matching
+ * Last_Entry field was introduced in revision 6 of the SRH draft.
+ * It was called First_Segment in the previous revision
+ */
+ if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ)
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_EQ,
+ !(srh->first_segment == srhinfo->last_entry)))
+ return false;
+
+ if (srhinfo->mt_flags & IP6T_SRH_LAST_GT)
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_GT,
+ !(srh->first_segment > srhinfo->last_entry)))
+ return false;
+
+ if (srhinfo->mt_flags & IP6T_SRH_LAST_LT)
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_LT,
+ !(srh->first_segment < srhinfo->last_entry)))
+ return false;
+
+ /**
+ * Tag matchig
+ * Tag field was introduced in revision 6 of the SRH draft.
+ */
+ if (srhinfo->mt_flags & IP6T_SRH_TAG)
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_TAG,
+ !(srh->tag == srhinfo->tag)))
+ return false;
+ return true;
+}
+
+static int srh_mt6_check(const struct xt_mtchk_param *par)
+{
+ const struct ip6t_srh *srhinfo = par->matchinfo;
+
+ if (srhinfo->mt_flags & ~IP6T_SRH_MASK) {
+ pr_debug("unknown srh match flags %X\n", srhinfo->mt_flags);
+ return -EINVAL;
+ }
+
+ if (srhinfo->mt_invflags & ~IP6T_SRH_INV_MASK) {
+ pr_debug("unknown srh invflags %X\n", srhinfo->mt_invflags);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct xt_match srh_mt6_reg __read_mostly = {
+ .name = "srh",
+ .family = NFPROTO_IPV6,
+ .match = srh_mt6,
+ .matchsize = sizeof(struct ip6t_srh),
+ .checkentry = srh_mt6_check,
+ .me = THIS_MODULE,
+};
+
+static int __init srh_mt6_init(void)
+{
+ return xt_register_match(&srh_mt6_reg);
+}
+
+static void __exit srh_mt6_exit(void)
+{
+ xt_unregister_match(&srh_mt6_reg);
+}
+
+module_init(srh_mt6_init);
+module_exit(srh_mt6_exit);
--
2.1.4
^ permalink raw reply related
* Re: [PATCH][next] wcn36xx: remove redundant assignment to msg_body.min_ch_time
From: Colin Ian King @ 2017-12-29 10:52 UTC (permalink / raw)
To: Loic Poulain, Bjorn Andersson
Cc: Eugene Krasnikov, Kalle Valo, wcn36xx, linux-wireless, netdev,
kernel-janitors, linux-kernel
In-Reply-To: <CAMZdPi8hYToYoPSMggPY-tVpsJNL2W57uzB+d0nSLdfNtPK6Cg@mail.gmail.com>
On 29/12/17 07:44, Loic Poulain wrote:
> Hi Colin, Bjorn,
>
> On 26 December 2017 at 21:13, Bjorn Andersson
> <bjorn.andersson@linaro.org> wrote:
>> On Tue 19 Dec 09:04 PST 2017, Colin King wrote:
>>
>>> From: Colin Ian King <colin.king@canonical.com>
>>>
>>> msg_body.min_ch_time is being assigned twice; remove the redundant
>>> first assignment.
>>>
>>> Detected by CoverityScan, CID#1463042 ("Unused Value")
>>>
>>
>> Happy to see Coverity working for us :)
>>
>>
>> This should have had a:
>>
>> Fixes: 2f3bef4b247e ("wcn36xx: Add hardware scan offload support")
>>
>>> Signed-off-by: Colin Ian King <colin.king@canonical.com>
>>> ---
>>> drivers/net/wireless/ath/wcn36xx/smd.c | 1 -
>>> 1 file changed, 1 deletion(-)
>>>
>>> diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
>>> index 2914618a0335..bab2eca5fcac 100644
>>> --- a/drivers/net/wireless/ath/wcn36xx/smd.c
>>> +++ b/drivers/net/wireless/ath/wcn36xx/smd.c
>>> @@ -625,7 +625,6 @@ int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif,
>>> INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_OFFLOAD_REQ);
>>>
>>> msg_body.scan_type = WCN36XX_HAL_SCAN_TYPE_ACTIVE;
>>> - msg_body.min_ch_time = 30;
>>> msg_body.min_ch_time = 100;
>>
>> But I strongly suspect the second line is supposed to be max_ch_time.
>>
>> @Loic, do you agree?
>
> You're absolutely right.
> Colin could you please update your patch accordingly?
Resent as "wcn36xx: fix incorrect assignment to msg_body.min_ch_time"
>
> Regards,
> Loic
> --
> To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox