* Re: [PATCH 2/2] at803x: double check SGMII side autoneg
From: Matthias May @ 2017-05-24 7:18 UTC (permalink / raw)
To: Timur Tabi, Andrew Lunn
Cc: Zefir Kurtisi, netdev, f.fainelli, David Miller, Manoj Iyer,
jhugo
In-Reply-To: <3dc4f9cf-3172-0227-f03c-1ccfdad3e15e@codeaurora.org>
On 23/05/17 18:33, Timur Tabi wrote:
> On 05/23/2017 11:07 AM, Andrew Lunn wrote:
>>>> I will test that to see what happens, but I believe the real problem is that
>>>> the at803x driver is lying when it says that the link is not okay. I think
>>>> the link is okay, and that's why I'm not getting any more interrupts. I
>>>> don't think I should have to drop interrupt support in my MAC driver because
>>>> one specific PHY driver is broken.
>> If it turns out the PHY hardware is broken, the phy driver itself can
>> force it back to polling by setting phydev->irq to PHY_POLL in its
>> probe() function.
>
> I don't think the hardware is broken, I think the driver is broken. The
> patch that sets aneg_done to 0 should be reverted or restricted somehow.
>
> Even the developer of the patch admits that if the warning message is
> displayed, the link will appear to be up, but no packets will go through.
> Perhaps that's because the driver is returning 0 instead of BMSR_ANEGCOMPLETE?
>
> Would it be okay for the PHY driver to query a property from the device tree
> directly (e.g. "qca,check-sgmii-link"), and if present, only then implement
> the sgmii link check? So in at803x_probe(), I would do something like this:
>
> if (device_property_read_bool(&phydev->mdio.dev,
> "qca,check-sgmii-link")
> priv->check_sgmii_link = true;
>
Zefir is currently on holiday and will probably get these emails when he gets back around 1. June
I think you missunderstand what "the link appears up but no packets go through means".
There are 2 pages which each reflect a side of the PHY:
* copper side
* SGMII side
Until the patch only the copper side was ever considered when reporting the state of the link.
This lead to the situation that the copper side was up (and the link reported up), but the SGMII side didn't come up.
It could well be a bad combination of CPU and the AR8031/33.
We know of at least 1 CPU (Freescale P1010) which has erratas for certain revisions regarding this.
If the SGMII side doesn't come, well no packets can go through.
With the patch: When the copper side is seen as up, it also checks if aneg of the SGMII link is done.
As far as i know SGMII can not be run without aneg, since it is always Gbit with aneg mandatory.
If SGMII aneg is not done, then, well aneg is not done and thus 0 is returned.
Internally we have this patch extended so we don't only report that aneg is not done but also reset the link.
Eventually aneg on the SGMII side can be completed and the link comes up.
Why do you think that frames are able to go through when aneg is reported as not done by the PHY?
Since aneg is mandatory for SGMII this can as well be seen as "link not up", not?
BR
Matthias
^ permalink raw reply
* [PATCH net-next] net: rps: Add the rfs_needed check when record flow hash
From: gfree.wind @ 2017-05-24 7:35 UTC (permalink / raw)
To: davem, netdev; +Cc: Gao Feng
From: Gao Feng <gfree.wind@vip.163.com>
There are two spots which invoke the sock_rps_record_flow_hash, one is
sock_rps_record_flow which has already checked rfs_needed. But the other
is tun_flow_update which doesn't check if the rfs is enabled.
Now rename the original function sock_rps_record_flow_hash to
_sock_rps_record_flow_hash, and add one helper func which checks the
rfs_needed.
The perf result of two functions is following.
When rfs is disabled, it could enhance 58% performance with checking
rfs_needed.
When rfs is enabled, the performanc is lower than current about 29%.
Because the RFS is disabled by default. I think it is useful to tun
driver.
The follow is test statistics.
test_rfs_check_rfs_key invokes _sock_rps_record_flow_hash 10000000 times.
test_rfs_no_check_rfs_key invokes sock_rps_record_flow_hash 10000000 times
too.
The test function is running with bh disabled, and the cycles is measured
by rdtscll.
[ 1716.374630] rfs_needed:1
[ 1716.388961] test_rfs_check_rfs_key costs 37119844 cycles
[ 1716.404495] test_rfs_check_rfs_key costs 40229886 cycles
[ 1716.419033] test_rfs_check_rfs_key costs 37668179 cycles
[ 1716.432618] test_rfs_no_check_rfs_key costs 35181759 cycles
[ 1716.443151] test_rfs_no_check_rfs_key costs 27290206 cycles
[ 1716.453496] test_rfs_no_check_rfs_key costs 26797500 cycles
[ 2635.215760] rfs_needed:0
[ 2635.219079] test_rfs_check_rfs_key costs 8455450 cycles
[ 2635.222381] test_rfs_check_rfs_key costs 8556322 cycles
[ 2635.225761] test_rfs_check_rfs_key costs 8758388 cycles
[ 2635.232230] test_rfs_no_check_rfs_key costs 16762130 cycles
[ 2635.239942] test_rfs_no_check_rfs_key costs 19982679 cycles
[ 2635.249172] test_rfs_no_check_rfs_key costs 23894840 cycles
Signed-off-by: Gao Feng <gfree.wind@vip.163.com>
---
include/net/sock.h | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/include/net/sock.h b/include/net/sock.h
index 3467d9e..584bb9a 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -910,7 +910,7 @@ static inline void sk_incoming_cpu_update(struct sock *sk)
sk->sk_incoming_cpu = raw_smp_processor_id();
}
-static inline void sock_rps_record_flow_hash(__u32 hash)
+static inline void _sock_rps_record_flow_hash(__u32 hash)
{
#ifdef CONFIG_RPS
struct rps_sock_flow_table *sock_flow_table;
@@ -922,6 +922,14 @@ static inline void sock_rps_record_flow_hash(__u32 hash)
#endif
}
+static inline void sock_rps_record_flow_hash(__u32 hash)
+{
+#ifdef CONFIG_RPS
+ if (static_key_false(&rfs_needed))
+ _sock_rps_record_flow_hash(hash);
+#endif
+}
+
static inline void sock_rps_record_flow(const struct sock *sk)
{
#ifdef CONFIG_RPS
@@ -937,7 +945,7 @@ static inline void sock_rps_record_flow(const struct sock *sk)
* [1] : sk_state and sk_prot are in the same cache line.
*/
if (sk->sk_state == TCP_ESTABLISHED)
- sock_rps_record_flow_hash(sk->sk_rxhash);
+ _sock_rps_record_flow_hash(sk->sk_rxhash);
}
#endif
}
--
1.9.1
^ permalink raw reply related
* [PATCH v2] net: move somaxconn init from sysctl code
From: Roman Kapl @ 2017-05-24 8:22 UTC (permalink / raw)
To: netdev, davem; +Cc: Roman Kapl
The default value for somaxconn is set in sysctl_core_net_init(), but this
function is not called when kernel is configured without CONFIG_SYSCTL.
This results in the kernel not being able to accept TCP connections,
because the backlog has zero size. Usually, the user ends up with:
"TCP: request_sock_TCP: Possible SYN flooding on port 7. Dropping request. Check SNMP counters."
If SYN cookies are not enabled the connection is rejected.
Before ef547f2ac16 (tcp: remove max_qlen_log), the effects were less
severe, because the backlog was always at least eight slots long.
Signed-off-by: Roman Kapl <roman.kapl@sysgo.com>
---
net/core/net_namespace.c | 19 +++++++++++++++++++
net/core/sysctl_net_core.c | 2 --
2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 1934efd..26bbfab 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -315,6 +315,25 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
goto out;
}
+static int __net_init net_defaults_init_net(struct net *net)
+{
+ net->core.sysctl_somaxconn = SOMAXCONN;
+ return 0;
+}
+
+static struct pernet_operations net_defaults_ops = {
+ .init = net_defaults_init_net,
+};
+
+static __init int net_defaults_init(void)
+{
+ if (register_pernet_subsys(&net_defaults_ops))
+ panic("Cannot initialize net default settings");
+
+ return 0;
+}
+
+core_initcall(net_defaults_init);
#ifdef CONFIG_NET_NS
static struct ucounts *inc_net_namespaces(struct user_namespace *ns)
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index ea23254..b7cd9aa 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -479,8 +479,6 @@ static __net_init int sysctl_core_net_init(struct net *net)
{
struct ctl_table *tbl;
- net->core.sysctl_somaxconn = SOMAXCONN;
-
tbl = netns_core_table;
if (!net_eq(net, &init_net)) {
tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL);
--
2.10.1
^ permalink raw reply related
* Process phantom ECN event in TCP without CWR response
From: Lars Erik Storbukås @ 2017-05-24 8:45 UTC (permalink / raw)
To: Netdev
I'm trying to generate phantom ECN events to (manually) decrease the
transmission rate/throughput.
The signals is meant to be generated and received on a single host. I
don't want the ECN event to generate a CWR (Congestion Window Reduced)
response to the sender. I'm trying to think of ways to avoid the TCP
code from entering the part of an ECN event, where the response to the
sender is generated.
I have thought of two (possible) solutions:
1. Before the phantom ECN signal is generated, a FLAG is set,
indicating that a phantom ECN event is coming. Before entering the
part where the CWR response is generated, perform a check on whether
the FLAG is set or not (if set - do not enter CWR part).
2. Instead of generating ECN signals (modify incoming packets), use a
flag to indicate that the next incoming ACK is processed as if it were
an ECN signal (except entering the CWR part).
Any input on how to implement, or pointers for where to look for
similar solutions is greatly appreciated.
...
For those who are interested in why I'm trying to achieve this:
I'm working on the implementation of a Deadline Aware, Less than Best
Effort framework. A framework for adding both LBE behaviour and
awareness of “soft” delivery deadlines to any congestion control (CC)
algorithm, whether loss-based, delay- based or explicit
signaling-based. This effectively allows it to turn an arbitrary CC
protocol into a scavenger protocol that dynamically adapts its sending
rate to network conditions and remaining time before the deadline, to
balance timeliness and transmission aggressiveness.
/ Lars Erik Storbukås (storbukas.dev@gmail.com)
^ permalink raw reply
* Re: [PATCH net] netfilter: do not hold dev in ipt_CLUSTERIP
From: Xin Long @ 2017-05-24 8:53 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: network dev, netfilter-devel, davem, fw
In-Reply-To: <20170523212607.GA8936@salvia>
On Wed, May 24, 2017 at 5:26 AM, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Sat, May 20, 2017 at 05:08:06PM +0800, Xin Long wrote:
>> It's a terrible thing to hold dev in iptables target. When the dev is
>> being removed, unregister_netdevice has to wait for the dev to become
>> free. dmesg will keep logging the err:
>>
>> kernel:unregister_netdevice: waiting for veth0_in to become free. \
>> Usage count = 1
>>
>> until iptables rules with this target are removed manually.
>>
>> The worse thing is when deleting a netns, a virtual nic will be deleted
>> instead of reset to init_net in default_device_ops exit/exit_batch. As
>> it is earlier than to flush the iptables rules in iptable_filter_net_ops
>> exit, unregister_netdevice will block to wait for the nic to become free.
>>
>> As unregister_netdevice is actually waiting for iptables rules flushing
>> while iptables rules have to be flushed after unregister_netdevice. This
>> 'dead lock' will cause unregister_netdevice to block there forever. As
>> the netns is not available to operate at that moment, iptables rules can
>> not even be flushed manually either.
>>
>> The reproducer can be:
>>
>> # ip netns add test
>> # ip link add veth0_in type veth peer name veth0_out
>> # ip link set veth0_in netns test
>> # ip netns exec test ip link set lo up
>> # ip netns exec test ip link set veth0_in up
>> # ip netns exec test iptables -I INPUT -d 1.2.3.4 -i veth0_in -j \
>> CLUSTERIP --new --clustermac 89:d4:47:eb:9a:fa --total-nodes 3 \
>> --local-node 1 --hashmode sourceip-sourceport
>> # ip netns del test
>>
>> This issue can be triggered by all virtual nics with ipt_CLUSTERIP.
>>
>> This patch is to fix it by not holding dev in ipt_CLUSTERIP, but only
>> save dev->ifindex instead of dev. When removing the mc from the dev,
>> it will get dev by c->ifindex through dev_get_by_index.
>>
>> Note that it doesn't save dev->name but dev->ifindex, as a dev->name
>> can be changed, it will confuse ipt_CLUSTERIP.
>>
>> Reported-by: Jianlin Shi <jishi@redhat.com>
>> Signed-off-by: Xin Long <lucien.xin@gmail.com>
>
> OK. Let's fix this finally... One comment below.
>
>> net/ipv4/netfilter/ipt_CLUSTERIP.c | 31 ++++++++++++++++++-------------
>> 1 file changed, 18 insertions(+), 13 deletions(-)
>>
>> diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
>> index 038f293..d1adb2f 100644
>> --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
>> +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
>> @@ -47,7 +47,7 @@ struct clusterip_config {
>>
>> __be32 clusterip; /* the IP address */
>> u_int8_t clustermac[ETH_ALEN]; /* the MAC address */
>> - struct net_device *dev; /* device */
>> + int ifindex; /* device ifindex */
>> u_int16_t num_total_nodes; /* total number of nodes */
>> unsigned long local_nodes; /* node number array */
>>
>> @@ -98,19 +98,23 @@ clusterip_config_put(struct clusterip_config *c)
>> * entry(rule) is removed, remove the config from lists, but don't free it
>> * yet, since proc-files could still be holding references */
>> static inline void
>> -clusterip_config_entry_put(struct clusterip_config *c)
>> +clusterip_config_entry_put(struct net *net, struct clusterip_config *c)
>> {
>> - struct net *net = dev_net(c->dev);
>> struct clusterip_net *cn = net_generic(net, clusterip_net_id);
>>
>> local_bh_disable();
>> if (refcount_dec_and_lock(&c->entries, &cn->lock)) {
>> + struct net_device *dev;
>> +
>> list_del_rcu(&c->list);
>> spin_unlock(&cn->lock);
>> local_bh_enable();
>>
>> - dev_mc_del(c->dev, c->clustermac);
>> - dev_put(c->dev);
>> + dev = dev_get_by_index(net, c->ifindex);
>> + if (dev) {
>> + dev_mc_del(dev, c->clustermac);
>> + dev_put(dev);
>> + }
>>
>> /* In case anyone still accesses the file, the open/close
>> * functions are also incrementing the refcount on their own,
>> @@ -182,7 +186,7 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip,
>> if (!c)
>> return ERR_PTR(-ENOMEM);
>>
>> - c->dev = dev;
>> + c->ifindex = dev->ifindex;
>> c->clusterip = ip;
>> memcpy(&c->clustermac, &i->clustermac, ETH_ALEN);
>> c->num_total_nodes = i->num_total_nodes;
>> @@ -427,12 +431,14 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
>> }
>>
>> config = clusterip_config_init(cipinfo,
>> - e->ip.dst.s_addr, dev);
>> + e->ip.dst.s_addr, dev);
>> if (IS_ERR(config)) {
>> dev_put(dev);
>> return PTR_ERR(config);
>> }
>> - dev_mc_add(config->dev, config->clustermac);
>> +
>> + dev_mc_add(dev, config->clustermac);
>> + dev_put(dev);
>> }
>> }
>> cipinfo->config = config;
>> @@ -458,7 +464,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
>>
>> /* if no more entries are referencing the config, remove it
>> * from the list and destroy the proc entry */
>> - clusterip_config_entry_put(cipinfo->config);
>> + clusterip_config_entry_put(par->net, cipinfo->config);
>>
>> clusterip_config_put(cipinfo->config);
>>
>> @@ -558,10 +564,9 @@ arp_mangle(void *priv,
>> * addresses on different interfacs. However, in the CLUSTERIP case
>> * this wouldn't work, since we didn't subscribe the mcast group on
>> * other interfaces */
>> - if (c->dev != state->out) {
>> - pr_debug("not mangling arp reply on different "
>> - "interface: cip'%s'-skb'%s'\n",
>> - c->dev->name, state->out->name);
>> + if (c->ifindex != state->out->ifindex) {
>
> I'm missing the code to register_netdevice_notifier() so we can
> refresh c->ifindex.
>
> Just like we do in net/netfilter/xt_TEE.c
Yep, but clusterip would be more complicated, As config
can be shared by more than one targets, a config has
to have it's own notifier, and save the dev's name as well.
I didn't do it and just wanted to keep clusterip simple.
But after checking xt_TEE, notifier seems necessary, will
check more, and post v2 if it's doable for clusterip. thanks.
^ permalink raw reply
* Re: [PATCH v6 net-next 17/17] net: qualcomm: add QCA7000 UART driver
From: Stefan Wahren @ 2017-05-24 9:06 UTC (permalink / raw)
To: Lino Sanfilippo, Rob Herring, Mark Rutland, David S. Miller
Cc: linux-serial, Jiri Slaby, Greg Kroah-Hartman, netdev,
linux-kernel, Jakub Kicinski, devicetree
In-Reply-To: <41c7302e-b25c-9f57-470a-dd95200a060f@gmx.de>
Am 23.05.2017 um 23:01 schrieb Lino Sanfilippo:
> On 23.05.2017 21:38, Stefan Wahren wrote:
>>> Lino Sanfilippo <LinoSanfilippo@gmx.de> hat am 23. Mai 2017 um 20:16 geschrieben:
>>>
>>> I suggest to avoid this possible race by first unregistering the netdevice and then
>>> calling cancel_work_sync().
>> What makes you sure that's safe to unregister the netdev while the tx work queue is possibly active?
> unregister_netdevice() calls netdev_close() if the interface is still up. netdev_close() calls flush_work()
> so the unregistration is delayed until the tx work function is finished. Furthermore both close() and
> tx work are synchronized by means of the qca->lock which also guarantees that unregister_netdevice() wont
> be finished until the tx work is done.
>
Thanks for the explanation. I suspect there could be the same race
between serdev_device_close() and the tx work queue.
So i would propose a variant of your original suggestion:
unregister_netdev(qca->net_dev);
/* Flush any pending characters in the driver. */
serdev_device_close(serdev);
cancel_work_sync(&qca->tx_work);
Since we have the same pattern in the error path of the probe function,
the same applies there.
Stefan
^ permalink raw reply
* [PATCH v2] drivers: phy: Add Cortina CS4340 driver
From: Bogdan Purcareata @ 2017-05-24 9:25 UTC (permalink / raw)
To: andrew, f.fainelli, netdev, linux-kernel
Add basic support for Cortina PHY drivers. Support only CS4340 for now.
The phys are not compatible with IEEE 802.3 clause 45 registers. Implement
proper read_status support, so that phy polling does not cause bus
register access errors.
The driver should be described using the "ethernet-phy-id" device tree
compatible.
Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
---
v1 -> v2:
- Rename "mdio-cortina.c" to "cortina.c" since it's a phy driver.
- Test probing based on the "ethernet-phy-id" compatible. In the previous
version, getting the phy_id via get_phy_c45_ids() involved an additional
hack. Drop that approach and document probing in the commit message.
drivers/net/phy/Kconfig | 5 +++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/cortina.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 96 insertions(+)
create mode 100644 drivers/net/phy/cortina.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 22dea7f..ad09e2d 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -240,6 +240,11 @@ config CICADA_PHY
---help---
Currently supports the cis8204
+config CORTINA_PHY
+ tristate "Cortina quad-10G Ethernet PHY"
+ ---help---
+ Currently supports the CS4340 phy.
+
config DAVICOM_PHY
tristate "Davicom PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 79365be..0de3e20 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o
obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_CICADA_PHY) += cicada.o
+obj-$(CONFIG_CORTINA_PHY) += cortina.o
obj-$(CONFIG_DAVICOM_PHY) += davicom.o
obj-$(CONFIG_DP83640_PHY) += dp83640.o
obj-$(CONFIG_DP83848_PHY) += dp83848.o
diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c
new file mode 100644
index 0000000..6f054ed
--- /dev/null
+++ b/drivers/net/phy/cortina.c
@@ -0,0 +1,90 @@
+/*
+ * Based on code from Cortina Systems, Inc.
+ *
+ * Copyright 2011 Cortina Systems, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ */
+#include <linux/module.h>
+#include <linux/phy.h>
+
+#define PHY_ID_CS4340 0x13e51002
+
+#define CORTINA_GPIO_GPIO_INTS 0x16D
+
+static int cortina_read_x(struct phy_device *phydev, int off, u16 regnum)
+{
+ return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr + off,
+ MII_ADDR_C45 | regnum);
+}
+
+static int cortina_read(struct phy_device *phydev, u16 regnum)
+{
+ return cortina_read_x(phydev, 0, regnum);
+}
+
+static int cortina_config_aneg(struct phy_device *phydev)
+{
+ phydev->supported = SUPPORTED_10000baseT_Full;
+ phydev->advertising = SUPPORTED_10000baseT_Full;
+
+ return 0;
+}
+
+static int cortina_read_status(struct phy_device *phydev)
+{
+ int gpio_int_status;
+ int ret = 0;
+
+ gpio_int_status = cortina_read(phydev, CORTINA_GPIO_GPIO_INTS);
+ if (gpio_int_status < 0) {
+ ret = gpio_int_status;
+ goto err;
+ }
+
+ if (gpio_int_status & 0x8) {
+ phydev->speed = SPEED_10000;
+ phydev->duplex = DUPLEX_FULL;
+ phydev->link = 1;
+ } else {
+ phydev->link = 0;
+ }
+
+err:
+ return ret;
+}
+
+static int cortina_soft_reset(struct phy_device *phydev)
+{
+ return 0;
+}
+
+static struct phy_driver cortina_driver[] = {
+{
+ .phy_id = PHY_ID_CS4340,
+ .phy_id_mask = 0xffffffff,
+ .name = "Cortina CS4340",
+ .config_aneg = cortina_config_aneg,
+ .read_status = cortina_read_status,
+ .soft_reset = cortina_soft_reset,
+},
+};
+
+module_phy_driver(cortina_driver);
+
+static struct mdio_device_id __maybe_unused cortina_tbl[] = {
+ { PHY_ID_CS4340, 0xffffffff},
+ {},
+};
+
+MODULE_DEVICE_TABLE(mdio, cortina_tbl);
--
1.9.1
^ permalink raw reply related
* Re: [PATCH] net: fix potential null pointer dereference
From: Pablo Neira Ayuso @ 2017-05-24 9:29 UTC (permalink / raw)
To: Gustavo A. R. Silva; +Cc: Harald Welte, osmocom-net-gprs, netdev, linux-kernel
In-Reply-To: <20170523231837.GA9364@embeddedgus>
On Tue, May 23, 2017 at 06:18:37PM -0500, Gustavo A. R. Silva wrote:
> Add null check to avoid a potential null pointer dereference.
>
> Addresses-Coverity-ID: 1408831
> Signed-off-by: Gustavo A. R. Silva <garsilva@embeddedor.com>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
This is a fix for the net.git tree BTW.
^ permalink raw reply
* [PATCH v7 net-next 17/17] net: qualcomm: add QCA7000 UART driver
From: Stefan Wahren @ 2017-05-24 9:29 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, David S. Miller
Cc: Greg Kroah-Hartman, Jiri Slaby, Lino Sanfilippo, Jakub Kicinski,
devicetree-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-serial-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Stefan Wahren
In-Reply-To: <50e5a442-777f-1516-4e94-16db7fa28f8b-eS4NqCHxEME@public.gmane.org>
This patch adds the Ethernet over UART driver for the
Qualcomm QCA7000 HomePlug GreenPHY.
Signed-off-by: Stefan Wahren <stefan.wahren-eS4NqCHxEME@public.gmane.org>
---
drivers/net/ethernet/qualcomm/Kconfig | 16 +
drivers/net/ethernet/qualcomm/Makefile | 2 +
drivers/net/ethernet/qualcomm/qca_7k_common.h | 6 +
drivers/net/ethernet/qualcomm/qca_uart.c | 423 ++++++++++++++++++++++++++
4 files changed, 447 insertions(+)
create mode 100644 drivers/net/ethernet/qualcomm/qca_uart.c
diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig
index b4c369d..877675a 100644
--- a/drivers/net/ethernet/qualcomm/Kconfig
+++ b/drivers/net/ethernet/qualcomm/Kconfig
@@ -30,6 +30,22 @@ config QCA7000_SPI
To compile this driver as a module, choose M here. The module
will be called qcaspi.
+config QCA7000_UART
+ tristate "Qualcomm Atheros QCA7000 UART support"
+ select QCA7000
+ depends on SERIAL_DEV_BUS && OF
+ ---help---
+ This UART protocol driver supports the Qualcomm Atheros QCA7000.
+
+ Currently the driver assumes these device UART settings:
+ Data bits: 8
+ Parity: None
+ Stop bits: 1
+ Flow control: None
+
+ To compile this driver as a module, choose M here. The module
+ will be called qcauart.
+
config QCOM_EMAC
tristate "Qualcomm Technologies, Inc. EMAC Gigabit Ethernet support"
depends on HAS_DMA && HAS_IOMEM
diff --git a/drivers/net/ethernet/qualcomm/Makefile b/drivers/net/ethernet/qualcomm/Makefile
index 65556ca..92fa7c4 100644
--- a/drivers/net/ethernet/qualcomm/Makefile
+++ b/drivers/net/ethernet/qualcomm/Makefile
@@ -5,5 +5,7 @@
obj-$(CONFIG_QCA7000) += qca_7k_common.o
obj-$(CONFIG_QCA7000_SPI) += qcaspi.o
qcaspi-objs := qca_7k.o qca_debug.o qca_spi.o
+obj-$(CONFIG_QCA7000_UART) += qcauart.o
+qcauart-objs := qca_uart.o
obj-y += emac/
diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.h b/drivers/net/ethernet/qualcomm/qca_7k_common.h
index 07bdd6c..928554f 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k_common.h
+++ b/drivers/net/ethernet/qualcomm/qca_7k_common.h
@@ -122,6 +122,12 @@ static inline void qcafrm_fsm_init_spi(struct qcafrm_handle *handle)
handle->state = handle->init;
}
+static inline void qcafrm_fsm_init_uart(struct qcafrm_handle *handle)
+{
+ handle->init = QCAFRM_WAIT_AA1;
+ handle->state = handle->init;
+}
+
/* Gather received bytes and try to extract a full Ethernet frame
* by following a simple state machine.
*
diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c
new file mode 100644
index 0000000..db6068c
--- /dev/null
+++ b/drivers/net/ethernet/qualcomm/qca_uart.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc.
+ * Copyright (c) 2017, I2SE GmbH
+ *
+ * Permission to use, copy, modify, and/or distribute this software
+ * for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear
+ * in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* This module implements the Qualcomm Atheros UART protocol for
+ * kernel-based UART device; it is essentially an Ethernet-to-UART
+ * serial converter;
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_net.h>
+#include <linux/sched.h>
+#include <linux/serdev.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+
+#include "qca_7k_common.h"
+
+#define QCAUART_DRV_VERSION "0.1.0"
+#define QCAUART_DRV_NAME "qcauart"
+#define QCAUART_TX_TIMEOUT (1 * HZ)
+
+struct qcauart {
+ struct net_device *net_dev;
+ spinlock_t lock; /* transmit lock */
+ struct work_struct tx_work; /* Flushes transmit buffer */
+
+ struct serdev_device *serdev;
+ struct qcafrm_handle frm_handle;
+ struct sk_buff *rx_skb;
+
+ unsigned char *tx_head; /* pointer to next XMIT byte */
+ int tx_left; /* bytes left in XMIT queue */
+ unsigned char *tx_buffer;
+};
+
+static int
+qca_tty_receive(struct serdev_device *serdev, const unsigned char *data,
+ size_t count)
+{
+ struct qcauart *qca = serdev_device_get_drvdata(serdev);
+ struct net_device *netdev = qca->net_dev;
+ struct net_device_stats *n_stats = &netdev->stats;
+ size_t i;
+
+ if (!qca->rx_skb) {
+ qca->rx_skb = netdev_alloc_skb_ip_align(netdev,
+ netdev->mtu +
+ VLAN_ETH_HLEN);
+ if (!qca->rx_skb) {
+ n_stats->rx_errors++;
+ n_stats->rx_dropped++;
+ return 0;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ s32 retcode;
+
+ retcode = qcafrm_fsm_decode(&qca->frm_handle,
+ qca->rx_skb->data,
+ skb_tailroom(qca->rx_skb),
+ data[i]);
+
+ switch (retcode) {
+ case QCAFRM_GATHER:
+ case QCAFRM_NOHEAD:
+ break;
+ case QCAFRM_NOTAIL:
+ netdev_dbg(netdev, "recv: no RX tail\n");
+ n_stats->rx_errors++;
+ n_stats->rx_dropped++;
+ break;
+ case QCAFRM_INVLEN:
+ netdev_dbg(netdev, "recv: invalid RX length\n");
+ n_stats->rx_errors++;
+ n_stats->rx_dropped++;
+ break;
+ default:
+ n_stats->rx_packets++;
+ n_stats->rx_bytes += retcode;
+ skb_put(qca->rx_skb, retcode);
+ qca->rx_skb->protocol = eth_type_trans(
+ qca->rx_skb, qca->rx_skb->dev);
+ qca->rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
+ netif_rx_ni(qca->rx_skb);
+ qca->rx_skb = netdev_alloc_skb_ip_align(netdev,
+ netdev->mtu +
+ VLAN_ETH_HLEN);
+ if (!qca->rx_skb) {
+ netdev_dbg(netdev, "recv: out of RX resources\n");
+ n_stats->rx_errors++;
+ return i;
+ }
+ }
+ }
+
+ return i;
+}
+
+/* Write out any remaining transmit buffer. Scheduled when tty is writable */
+static void qcauart_transmit(struct work_struct *work)
+{
+ struct qcauart *qca = container_of(work, struct qcauart, tx_work);
+ struct net_device_stats *n_stats = &qca->net_dev->stats;
+ int written;
+
+ spin_lock_bh(&qca->lock);
+
+ /* First make sure we're connected. */
+ if (!netif_running(qca->net_dev)) {
+ spin_unlock_bh(&qca->lock);
+ return;
+ }
+
+ if (qca->tx_left <= 0) {
+ /* Now serial buffer is almost free & we can start
+ * transmission of another packet
+ */
+ n_stats->tx_packets++;
+ spin_unlock_bh(&qca->lock);
+ netif_wake_queue(qca->net_dev);
+ return;
+ }
+
+ written = serdev_device_write_buf(qca->serdev, qca->tx_head,
+ qca->tx_left);
+ if (written > 0) {
+ qca->tx_left -= written;
+ qca->tx_head += written;
+ }
+ spin_unlock_bh(&qca->lock);
+}
+
+/* Called by the driver when there's room for more data.
+ * Schedule the transmit.
+ */
+static void qca_tty_wakeup(struct serdev_device *serdev)
+{
+ struct qcauart *qca = serdev_device_get_drvdata(serdev);
+
+ schedule_work(&qca->tx_work);
+}
+
+static struct serdev_device_ops qca_serdev_ops = {
+ .receive_buf = qca_tty_receive,
+ .write_wakeup = qca_tty_wakeup,
+};
+
+static int qcauart_netdev_open(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+
+ netif_start_queue(qca->net_dev);
+
+ return 0;
+}
+
+static int qcauart_netdev_close(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+ flush_work(&qca->tx_work);
+
+ spin_lock_bh(&qca->lock);
+ qca->tx_left = 0;
+ spin_unlock_bh(&qca->lock);
+
+ return 0;
+}
+
+static netdev_tx_t
+qcauart_netdev_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_device_stats *n_stats = &dev->stats;
+ struct qcauart *qca = netdev_priv(dev);
+ u8 pad_len = 0;
+ int written;
+ u8 *pos;
+
+ spin_lock(&qca->lock);
+
+ WARN_ON(qca->tx_left);
+
+ if (!netif_running(dev)) {
+ spin_unlock(&qca->lock);
+ netdev_warn(qca->net_dev, "xmit: iface is down\n");
+ goto out;
+ }
+
+ pos = qca->tx_buffer;
+
+ if (skb->len < QCAFRM_MIN_LEN)
+ pad_len = QCAFRM_MIN_LEN - skb->len;
+
+ pos += qcafrm_create_header(pos, skb->len + pad_len);
+
+ memcpy(pos, skb->data, skb->len);
+ pos += skb->len;
+
+ if (pad_len) {
+ memset(pos, 0, pad_len);
+ pos += pad_len;
+ }
+
+ pos += qcafrm_create_footer(pos);
+
+ netif_stop_queue(qca->net_dev);
+
+ written = serdev_device_write_buf(qca->serdev, qca->tx_buffer,
+ pos - qca->tx_buffer);
+ if (written > 0) {
+ qca->tx_left = (pos - qca->tx_buffer) - written;
+ qca->tx_head = qca->tx_buffer + written;
+ n_stats->tx_bytes += written;
+ }
+ spin_unlock(&qca->lock);
+
+ netif_trans_update(dev);
+out:
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+}
+
+static void qcauart_netdev_tx_timeout(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+
+ netdev_info(qca->net_dev, "Transmit timeout at %ld, latency %ld\n",
+ jiffies, dev_trans_start(dev));
+ dev->stats.tx_errors++;
+ dev->stats.tx_dropped++;
+}
+
+static int qcauart_netdev_init(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+ size_t len;
+
+ /* Finish setting up the device info. */
+ dev->mtu = QCAFRM_MAX_MTU;
+ dev->type = ARPHRD_ETHER;
+
+ len = QCAFRM_HEADER_LEN + QCAFRM_MAX_LEN + QCAFRM_FOOTER_LEN;
+ qca->tx_buffer = devm_kmalloc(&qca->serdev->dev, len, GFP_KERNEL);
+ if (!qca->tx_buffer)
+ return -ENOMEM;
+
+ qca->rx_skb = netdev_alloc_skb_ip_align(qca->net_dev,
+ qca->net_dev->mtu +
+ VLAN_ETH_HLEN);
+ if (!qca->rx_skb)
+ return -ENOBUFS;
+
+ return 0;
+}
+
+static void qcauart_netdev_uninit(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+
+ if (qca->rx_skb)
+ dev_kfree_skb(qca->rx_skb);
+}
+
+static const struct net_device_ops qcauart_netdev_ops = {
+ .ndo_init = qcauart_netdev_init,
+ .ndo_uninit = qcauart_netdev_uninit,
+ .ndo_open = qcauart_netdev_open,
+ .ndo_stop = qcauart_netdev_close,
+ .ndo_start_xmit = qcauart_netdev_xmit,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_tx_timeout = qcauart_netdev_tx_timeout,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+static void qcauart_netdev_setup(struct net_device *dev)
+{
+ dev->netdev_ops = &qcauart_netdev_ops;
+ dev->watchdog_timeo = QCAUART_TX_TIMEOUT;
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+ dev->tx_queue_len = 100;
+
+ /* MTU range: 46 - 1500 */
+ dev->min_mtu = QCAFRM_MIN_MTU;
+ dev->max_mtu = QCAFRM_MAX_MTU;
+}
+
+static const struct of_device_id qca_uart_of_match[] = {
+ {
+ .compatible = "qca,qca7000",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qca_uart_of_match);
+
+static int qca_uart_probe(struct serdev_device *serdev)
+{
+ struct net_device *qcauart_dev = alloc_etherdev(sizeof(struct qcauart));
+ struct qcauart *qca;
+ const char *mac;
+ u32 speed = 115200;
+ int ret;
+
+ if (!qcauart_dev)
+ return -ENOMEM;
+
+ qcauart_netdev_setup(qcauart_dev);
+ SET_NETDEV_DEV(qcauart_dev, &serdev->dev);
+
+ qca = netdev_priv(qcauart_dev);
+ if (!qca) {
+ pr_err("qca_uart: Fail to retrieve private structure\n");
+ ret = -ENOMEM;
+ goto free;
+ }
+ qca->net_dev = qcauart_dev;
+ qca->serdev = serdev;
+ qcafrm_fsm_init_uart(&qca->frm_handle);
+
+ spin_lock_init(&qca->lock);
+ INIT_WORK(&qca->tx_work, qcauart_transmit);
+
+ of_property_read_u32(serdev->dev.of_node, "current-speed", &speed);
+
+ mac = of_get_mac_address(serdev->dev.of_node);
+
+ if (mac)
+ ether_addr_copy(qca->net_dev->dev_addr, mac);
+
+ if (!is_valid_ether_addr(qca->net_dev->dev_addr)) {
+ eth_hw_addr_random(qca->net_dev);
+ dev_info(&serdev->dev, "Using random MAC address: %pM\n",
+ qca->net_dev->dev_addr);
+ }
+
+ netif_carrier_on(qca->net_dev);
+ serdev_device_set_drvdata(serdev, qca);
+ serdev_device_set_client_ops(serdev, &qca_serdev_ops);
+
+ ret = serdev_device_open(serdev);
+ if (ret) {
+ dev_err(&serdev->dev, "Unable to open device %s\n",
+ qcauart_dev->name);
+ goto free;
+ }
+
+ speed = serdev_device_set_baudrate(serdev, speed);
+ dev_info(&serdev->dev, "Using baudrate: %u\n", speed);
+
+ serdev_device_set_flow_control(serdev, false);
+
+ ret = register_netdev(qcauart_dev);
+ if (ret) {
+ dev_err(&serdev->dev, "Unable to register net device %s\n",
+ qcauart_dev->name);
+ serdev_device_close(serdev);
+ cancel_work_sync(&qca->tx_work);
+ goto free;
+ }
+
+ return 0;
+
+free:
+ free_netdev(qcauart_dev);
+ return ret;
+}
+
+static void qca_uart_remove(struct serdev_device *serdev)
+{
+ struct qcauart *qca = serdev_device_get_drvdata(serdev);
+
+ unregister_netdev(qca->net_dev);
+
+ /* Flush any pending characters in the driver. */
+ serdev_device_close(serdev);
+ cancel_work_sync(&qca->tx_work);
+
+ free_netdev(qca->net_dev);
+}
+
+static struct serdev_device_driver qca_uart_driver = {
+ .probe = qca_uart_probe,
+ .remove = qca_uart_remove,
+ .driver = {
+ .name = QCAUART_DRV_NAME,
+ .of_match_table = of_match_ptr(qca_uart_of_match),
+ },
+};
+
+module_serdev_device_driver(qca_uart_driver);
+
+MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 UART Driver");
+MODULE_AUTHOR("Qualcomm Atheros Communications");
+MODULE_AUTHOR("Stefan Wahren <stefan.wahren-eS4NqCHxEME@public.gmane.org>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(QCAUART_DRV_VERSION);
--
2.1.4
--
To unsubscribe from this list: send the line "unsubscribe devicetree" 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 related
* [PATCH RESEND v7 net-next 17/17] net: qualcomm: add QCA7000 UART driver
From: Stefan Wahren @ 2017-05-24 9:32 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, David S. Miller
Cc: Greg Kroah-Hartman, Jiri Slaby, Lino Sanfilippo, Jakub Kicinski,
devicetree, netdev, linux-serial, linux-kernel, Stefan Wahren
In-Reply-To: <50e5a442-777f-1516-4e94-16db7fa28f8b@i2se.com>
This patch adds the Ethernet over UART driver for the
Qualcomm QCA7000 HomePlug GreenPHY.
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
drivers/net/ethernet/qualcomm/Kconfig | 16 +
drivers/net/ethernet/qualcomm/Makefile | 2 +
drivers/net/ethernet/qualcomm/qca_7k_common.h | 6 +
drivers/net/ethernet/qualcomm/qca_uart.c | 423 ++++++++++++++++++++++++++
4 files changed, 447 insertions(+)
create mode 100644 drivers/net/ethernet/qualcomm/qca_uart.c
Changes in v7:
* fix race between tx workqueue and device deregistration (reported by Lino)
diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig
index b4c369d..877675a 100644
--- a/drivers/net/ethernet/qualcomm/Kconfig
+++ b/drivers/net/ethernet/qualcomm/Kconfig
@@ -30,6 +30,22 @@ config QCA7000_SPI
To compile this driver as a module, choose M here. The module
will be called qcaspi.
+config QCA7000_UART
+ tristate "Qualcomm Atheros QCA7000 UART support"
+ select QCA7000
+ depends on SERIAL_DEV_BUS && OF
+ ---help---
+ This UART protocol driver supports the Qualcomm Atheros QCA7000.
+
+ Currently the driver assumes these device UART settings:
+ Data bits: 8
+ Parity: None
+ Stop bits: 1
+ Flow control: None
+
+ To compile this driver as a module, choose M here. The module
+ will be called qcauart.
+
config QCOM_EMAC
tristate "Qualcomm Technologies, Inc. EMAC Gigabit Ethernet support"
depends on HAS_DMA && HAS_IOMEM
diff --git a/drivers/net/ethernet/qualcomm/Makefile b/drivers/net/ethernet/qualcomm/Makefile
index 65556ca..92fa7c4 100644
--- a/drivers/net/ethernet/qualcomm/Makefile
+++ b/drivers/net/ethernet/qualcomm/Makefile
@@ -5,5 +5,7 @@
obj-$(CONFIG_QCA7000) += qca_7k_common.o
obj-$(CONFIG_QCA7000_SPI) += qcaspi.o
qcaspi-objs := qca_7k.o qca_debug.o qca_spi.o
+obj-$(CONFIG_QCA7000_UART) += qcauart.o
+qcauart-objs := qca_uart.o
obj-y += emac/
diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.h b/drivers/net/ethernet/qualcomm/qca_7k_common.h
index 07bdd6c..928554f 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k_common.h
+++ b/drivers/net/ethernet/qualcomm/qca_7k_common.h
@@ -122,6 +122,12 @@ static inline void qcafrm_fsm_init_spi(struct qcafrm_handle *handle)
handle->state = handle->init;
}
+static inline void qcafrm_fsm_init_uart(struct qcafrm_handle *handle)
+{
+ handle->init = QCAFRM_WAIT_AA1;
+ handle->state = handle->init;
+}
+
/* Gather received bytes and try to extract a full Ethernet frame
* by following a simple state machine.
*
diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c
new file mode 100644
index 0000000..db6068c
--- /dev/null
+++ b/drivers/net/ethernet/qualcomm/qca_uart.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc.
+ * Copyright (c) 2017, I2SE GmbH
+ *
+ * Permission to use, copy, modify, and/or distribute this software
+ * for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear
+ * in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* This module implements the Qualcomm Atheros UART protocol for
+ * kernel-based UART device; it is essentially an Ethernet-to-UART
+ * serial converter;
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_net.h>
+#include <linux/sched.h>
+#include <linux/serdev.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+
+#include "qca_7k_common.h"
+
+#define QCAUART_DRV_VERSION "0.1.0"
+#define QCAUART_DRV_NAME "qcauart"
+#define QCAUART_TX_TIMEOUT (1 * HZ)
+
+struct qcauart {
+ struct net_device *net_dev;
+ spinlock_t lock; /* transmit lock */
+ struct work_struct tx_work; /* Flushes transmit buffer */
+
+ struct serdev_device *serdev;
+ struct qcafrm_handle frm_handle;
+ struct sk_buff *rx_skb;
+
+ unsigned char *tx_head; /* pointer to next XMIT byte */
+ int tx_left; /* bytes left in XMIT queue */
+ unsigned char *tx_buffer;
+};
+
+static int
+qca_tty_receive(struct serdev_device *serdev, const unsigned char *data,
+ size_t count)
+{
+ struct qcauart *qca = serdev_device_get_drvdata(serdev);
+ struct net_device *netdev = qca->net_dev;
+ struct net_device_stats *n_stats = &netdev->stats;
+ size_t i;
+
+ if (!qca->rx_skb) {
+ qca->rx_skb = netdev_alloc_skb_ip_align(netdev,
+ netdev->mtu +
+ VLAN_ETH_HLEN);
+ if (!qca->rx_skb) {
+ n_stats->rx_errors++;
+ n_stats->rx_dropped++;
+ return 0;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ s32 retcode;
+
+ retcode = qcafrm_fsm_decode(&qca->frm_handle,
+ qca->rx_skb->data,
+ skb_tailroom(qca->rx_skb),
+ data[i]);
+
+ switch (retcode) {
+ case QCAFRM_GATHER:
+ case QCAFRM_NOHEAD:
+ break;
+ case QCAFRM_NOTAIL:
+ netdev_dbg(netdev, "recv: no RX tail\n");
+ n_stats->rx_errors++;
+ n_stats->rx_dropped++;
+ break;
+ case QCAFRM_INVLEN:
+ netdev_dbg(netdev, "recv: invalid RX length\n");
+ n_stats->rx_errors++;
+ n_stats->rx_dropped++;
+ break;
+ default:
+ n_stats->rx_packets++;
+ n_stats->rx_bytes += retcode;
+ skb_put(qca->rx_skb, retcode);
+ qca->rx_skb->protocol = eth_type_trans(
+ qca->rx_skb, qca->rx_skb->dev);
+ qca->rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
+ netif_rx_ni(qca->rx_skb);
+ qca->rx_skb = netdev_alloc_skb_ip_align(netdev,
+ netdev->mtu +
+ VLAN_ETH_HLEN);
+ if (!qca->rx_skb) {
+ netdev_dbg(netdev, "recv: out of RX resources\n");
+ n_stats->rx_errors++;
+ return i;
+ }
+ }
+ }
+
+ return i;
+}
+
+/* Write out any remaining transmit buffer. Scheduled when tty is writable */
+static void qcauart_transmit(struct work_struct *work)
+{
+ struct qcauart *qca = container_of(work, struct qcauart, tx_work);
+ struct net_device_stats *n_stats = &qca->net_dev->stats;
+ int written;
+
+ spin_lock_bh(&qca->lock);
+
+ /* First make sure we're connected. */
+ if (!netif_running(qca->net_dev)) {
+ spin_unlock_bh(&qca->lock);
+ return;
+ }
+
+ if (qca->tx_left <= 0) {
+ /* Now serial buffer is almost free & we can start
+ * transmission of another packet
+ */
+ n_stats->tx_packets++;
+ spin_unlock_bh(&qca->lock);
+ netif_wake_queue(qca->net_dev);
+ return;
+ }
+
+ written = serdev_device_write_buf(qca->serdev, qca->tx_head,
+ qca->tx_left);
+ if (written > 0) {
+ qca->tx_left -= written;
+ qca->tx_head += written;
+ }
+ spin_unlock_bh(&qca->lock);
+}
+
+/* Called by the driver when there's room for more data.
+ * Schedule the transmit.
+ */
+static void qca_tty_wakeup(struct serdev_device *serdev)
+{
+ struct qcauart *qca = serdev_device_get_drvdata(serdev);
+
+ schedule_work(&qca->tx_work);
+}
+
+static struct serdev_device_ops qca_serdev_ops = {
+ .receive_buf = qca_tty_receive,
+ .write_wakeup = qca_tty_wakeup,
+};
+
+static int qcauart_netdev_open(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+
+ netif_start_queue(qca->net_dev);
+
+ return 0;
+}
+
+static int qcauart_netdev_close(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+ flush_work(&qca->tx_work);
+
+ spin_lock_bh(&qca->lock);
+ qca->tx_left = 0;
+ spin_unlock_bh(&qca->lock);
+
+ return 0;
+}
+
+static netdev_tx_t
+qcauart_netdev_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_device_stats *n_stats = &dev->stats;
+ struct qcauart *qca = netdev_priv(dev);
+ u8 pad_len = 0;
+ int written;
+ u8 *pos;
+
+ spin_lock(&qca->lock);
+
+ WARN_ON(qca->tx_left);
+
+ if (!netif_running(dev)) {
+ spin_unlock(&qca->lock);
+ netdev_warn(qca->net_dev, "xmit: iface is down\n");
+ goto out;
+ }
+
+ pos = qca->tx_buffer;
+
+ if (skb->len < QCAFRM_MIN_LEN)
+ pad_len = QCAFRM_MIN_LEN - skb->len;
+
+ pos += qcafrm_create_header(pos, skb->len + pad_len);
+
+ memcpy(pos, skb->data, skb->len);
+ pos += skb->len;
+
+ if (pad_len) {
+ memset(pos, 0, pad_len);
+ pos += pad_len;
+ }
+
+ pos += qcafrm_create_footer(pos);
+
+ netif_stop_queue(qca->net_dev);
+
+ written = serdev_device_write_buf(qca->serdev, qca->tx_buffer,
+ pos - qca->tx_buffer);
+ if (written > 0) {
+ qca->tx_left = (pos - qca->tx_buffer) - written;
+ qca->tx_head = qca->tx_buffer + written;
+ n_stats->tx_bytes += written;
+ }
+ spin_unlock(&qca->lock);
+
+ netif_trans_update(dev);
+out:
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+}
+
+static void qcauart_netdev_tx_timeout(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+
+ netdev_info(qca->net_dev, "Transmit timeout at %ld, latency %ld\n",
+ jiffies, dev_trans_start(dev));
+ dev->stats.tx_errors++;
+ dev->stats.tx_dropped++;
+}
+
+static int qcauart_netdev_init(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+ size_t len;
+
+ /* Finish setting up the device info. */
+ dev->mtu = QCAFRM_MAX_MTU;
+ dev->type = ARPHRD_ETHER;
+
+ len = QCAFRM_HEADER_LEN + QCAFRM_MAX_LEN + QCAFRM_FOOTER_LEN;
+ qca->tx_buffer = devm_kmalloc(&qca->serdev->dev, len, GFP_KERNEL);
+ if (!qca->tx_buffer)
+ return -ENOMEM;
+
+ qca->rx_skb = netdev_alloc_skb_ip_align(qca->net_dev,
+ qca->net_dev->mtu +
+ VLAN_ETH_HLEN);
+ if (!qca->rx_skb)
+ return -ENOBUFS;
+
+ return 0;
+}
+
+static void qcauart_netdev_uninit(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+
+ if (qca->rx_skb)
+ dev_kfree_skb(qca->rx_skb);
+}
+
+static const struct net_device_ops qcauart_netdev_ops = {
+ .ndo_init = qcauart_netdev_init,
+ .ndo_uninit = qcauart_netdev_uninit,
+ .ndo_open = qcauart_netdev_open,
+ .ndo_stop = qcauart_netdev_close,
+ .ndo_start_xmit = qcauart_netdev_xmit,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_tx_timeout = qcauart_netdev_tx_timeout,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+static void qcauart_netdev_setup(struct net_device *dev)
+{
+ dev->netdev_ops = &qcauart_netdev_ops;
+ dev->watchdog_timeo = QCAUART_TX_TIMEOUT;
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+ dev->tx_queue_len = 100;
+
+ /* MTU range: 46 - 1500 */
+ dev->min_mtu = QCAFRM_MIN_MTU;
+ dev->max_mtu = QCAFRM_MAX_MTU;
+}
+
+static const struct of_device_id qca_uart_of_match[] = {
+ {
+ .compatible = "qca,qca7000",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qca_uart_of_match);
+
+static int qca_uart_probe(struct serdev_device *serdev)
+{
+ struct net_device *qcauart_dev = alloc_etherdev(sizeof(struct qcauart));
+ struct qcauart *qca;
+ const char *mac;
+ u32 speed = 115200;
+ int ret;
+
+ if (!qcauart_dev)
+ return -ENOMEM;
+
+ qcauart_netdev_setup(qcauart_dev);
+ SET_NETDEV_DEV(qcauart_dev, &serdev->dev);
+
+ qca = netdev_priv(qcauart_dev);
+ if (!qca) {
+ pr_err("qca_uart: Fail to retrieve private structure\n");
+ ret = -ENOMEM;
+ goto free;
+ }
+ qca->net_dev = qcauart_dev;
+ qca->serdev = serdev;
+ qcafrm_fsm_init_uart(&qca->frm_handle);
+
+ spin_lock_init(&qca->lock);
+ INIT_WORK(&qca->tx_work, qcauart_transmit);
+
+ of_property_read_u32(serdev->dev.of_node, "current-speed", &speed);
+
+ mac = of_get_mac_address(serdev->dev.of_node);
+
+ if (mac)
+ ether_addr_copy(qca->net_dev->dev_addr, mac);
+
+ if (!is_valid_ether_addr(qca->net_dev->dev_addr)) {
+ eth_hw_addr_random(qca->net_dev);
+ dev_info(&serdev->dev, "Using random MAC address: %pM\n",
+ qca->net_dev->dev_addr);
+ }
+
+ netif_carrier_on(qca->net_dev);
+ serdev_device_set_drvdata(serdev, qca);
+ serdev_device_set_client_ops(serdev, &qca_serdev_ops);
+
+ ret = serdev_device_open(serdev);
+ if (ret) {
+ dev_err(&serdev->dev, "Unable to open device %s\n",
+ qcauart_dev->name);
+ goto free;
+ }
+
+ speed = serdev_device_set_baudrate(serdev, speed);
+ dev_info(&serdev->dev, "Using baudrate: %u\n", speed);
+
+ serdev_device_set_flow_control(serdev, false);
+
+ ret = register_netdev(qcauart_dev);
+ if (ret) {
+ dev_err(&serdev->dev, "Unable to register net device %s\n",
+ qcauart_dev->name);
+ serdev_device_close(serdev);
+ cancel_work_sync(&qca->tx_work);
+ goto free;
+ }
+
+ return 0;
+
+free:
+ free_netdev(qcauart_dev);
+ return ret;
+}
+
+static void qca_uart_remove(struct serdev_device *serdev)
+{
+ struct qcauart *qca = serdev_device_get_drvdata(serdev);
+
+ unregister_netdev(qca->net_dev);
+
+ /* Flush any pending characters in the driver. */
+ serdev_device_close(serdev);
+ cancel_work_sync(&qca->tx_work);
+
+ free_netdev(qca->net_dev);
+}
+
+static struct serdev_device_driver qca_uart_driver = {
+ .probe = qca_uart_probe,
+ .remove = qca_uart_remove,
+ .driver = {
+ .name = QCAUART_DRV_NAME,
+ .of_match_table = of_match_ptr(qca_uart_of_match),
+ },
+};
+
+module_serdev_device_driver(qca_uart_driver);
+
+MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 UART Driver");
+MODULE_AUTHOR("Qualcomm Atheros Communications");
+MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(QCAUART_DRV_VERSION);
--
2.1.4
^ permalink raw reply related
* Re: [PATCH net-next v9 5/5] virtio_net: check return value of skb_to_sgvec always
From: Sergei Shtylyov @ 2017-05-24 9:41 UTC (permalink / raw)
To: Jason A. Donenfeld, netdev, linux-kernel, davem
Cc: Michael S. Tsirkin, Jason Wang
In-Reply-To: <20170523160550.5203-6-Jason@zx2c4.com>
Hello!
On 5/23/2017 7:05 PM, Jason A. Donenfeld wrote:
> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Jason Wang <jasowang@redhat.com>
> ---
> drivers/net/virtio_net.c | 9 +++++++--
> 1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 9320d96a1632..13fbe4b349c2 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -1150,7 +1150,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
> struct virtio_net_hdr_mrg_rxbuf *hdr;
> const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
> struct virtnet_info *vi = sq->vq->vdev->priv;
> - unsigned num_sg;
> + int num_sg;
> unsigned hdr_len = vi->hdr_len;
> bool can_push;
>
> @@ -1177,11 +1177,16 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
> if (can_push) {
> __skb_push(skb, hdr_len);
> num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len);
> + if (unlikely(num_sg < 0))
Please indent with tabs, like above and below.
> + return num_sg;
> /* Pull header back to avoid skew in tx bytes calculations. */
> __skb_pull(skb, hdr_len);
[...]
MBR, Sergei
^ permalink raw reply
* [PATCH] nfc: Fix the sockaddr length sanitization in llcp_sock_connect
From: Mateusz Jurczyk @ 2017-05-24 10:26 UTC (permalink / raw)
To: Samuel Ortiz, David S. Miller
Cc: linux-wireless, netdev, linux-kernel, security
Fix the sockaddr length verification in the connect() handler of NFC/LLCP
sockets, to compare against the size of the actual structure expected on
input (sockaddr_nfc_llcp) instead of its shorter version (sockaddr_nfc).
Both structures are defined in include/uapi/linux/nfc.h. The fields
specific to the _llcp extended struct are as follows:
276 __u8 dsap; /* Destination SAP, if known */
277 __u8 ssap; /* Source SAP to be bound to */
278 char service_name[NFC_LLCP_MAX_SERVICE_NAME]; /* Service name URI */;
279 size_t service_name_len;
If the caller doesn't provide a sufficiently long sockaddr buffer, these
fields remain uninitialized (and they currently originate from the stack
frame of the top-level sys_connect handler). They are then copied by
llcp_sock_connect() into internal storage (nfc_llcp_sock structure), and
could be subsequently read back through the user-mode getsockname()
function (handled by llcp_sock_getname()). This would result in the
disclosure of up to ~70 uninitialized bytes from the kernel stack to
user-mode clients capable of creating AFC_NFC sockets.
Signed-off-by: Mateusz Jurczyk <mjurczyk@google.com>
---
net/nfc/llcp_sock.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c
index 2ffb18e73df6..d0d12bea65cb 100644
--- a/net/nfc/llcp_sock.c
+++ b/net/nfc/llcp_sock.c
@@ -662,8 +662,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
pr_debug("sock %p sk %p flags 0x%x\n", sock, sk, flags);
- if (!addr || len < sizeof(struct sockaddr_nfc) ||
- addr->sa_family != AF_NFC)
+ if (!addr || len < sizeof(*addr) || addr->sa_family != AF_NFC)
return -EINVAL;
if (addr->service_name_len == 0 && addr->dsap == 0)
--
2.13.0.219.gdb65acc882-goog
^ permalink raw reply related
* [PATCH] nfc: Ensure presence of required attributes in the activate_target netlink handler
From: Mateusz Jurczyk @ 2017-05-24 10:42 UTC (permalink / raw)
To: Samuel Ortiz, David S. Miller
Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
security-DgEjT+Ai2ygdnm+yROfE0A
Check that the NFC_ATTR_TARGET_INDEX and NFC_ATTR_PROTOCOLS attributes (in
addition to NFC_ATTR_DEVICE_INDEX) are provided by the netlink client
prior to accessing them. This prevents potential unhandled NULL pointer
dereference exceptions which can be triggered by malicious user-mode
programs, if they omit one or both of these attributes.
Signed-off-by: Mateusz Jurczyk <mjurczyk-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
---
net/nfc/netlink.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index 6b0850e63e09..b251fb936a27 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -907,7 +907,9 @@ static int nfc_genl_activate_target(struct sk_buff *skb, struct genl_info *info)
u32 device_idx, target_idx, protocol;
int rc;
- if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
+ if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
+ !info->attrs[NFC_ATTR_TARGET_INDEX] ||
+ !info->attrs[NFC_ATTR_PROTOCOLS])
return -EINVAL;
device_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
--
2.13.0.219.gdb65acc882-goog
^ permalink raw reply related
* Re: [PATCH net-next v3 5/5] net-next: dsa: add dsa support for Mediatek MT7530 switch
From: Andrey Jr. Melnikov @ 2017-05-24 11:17 UTC (permalink / raw)
To: netdev; +Cc: devicetree, linux-kernel, linux-mediatek
In-Reply-To: <1490780303-18598-6-git-send-email-sean.wang@mediatek.com>
In gmane.linux.kernel sean.wang@mediatek.com wrote:
> From: Sean Wang <sean.wang@mediatek.com>
> MT7530 is a 7-ports Gigabit Ethernet Switch that could be found on
> Mediatek router platforms such as MT7623A or MT7623N platform which
> includes 7-port Gigabit Ethernet MAC and 5-port Gigabit Ethernet PHY.
> Among these ports, The port from 0 to 4 are the user ports connecting
> with the remote devices while the port 5 and 6 are the CPU ports
> connecting into Mediatek Ethernet GMAC.
> For port 6, it can communicate with the CPU via Mediatek Ethernet GMAC
> through either the TRGMII or RGMII which could be controlled by phy-mode
> in the dt-bindings to specify which mode is preferred to use. And for
> port 5, only RGMII can be specified. However, currently, only port 6 is
> being supported in this DSA driver.
> The driver is made with the reference to qca8k and other existing DSA
> driver. The most of the essential callbacks of the DSA are already
> support in the driver, including tag insert for user port distinguishing,
> port control, bridge offloading, STP setup and ethtool operation to allow
> DSA to model each user port into a standalone netdevice as the other DSA
> driver had done.
What about JUMBO frames and large MTU support? devlink support?
^ permalink raw reply
* Re: [PATCH net-next v9 5/5] virtio_net: check return value of skb_to_sgvec always
From: Jason A. Donenfeld @ 2017-05-24 11:34 UTC (permalink / raw)
To: Sergei Shtylyov
Cc: Netdev, LKML, David Miller, Michael S. Tsirkin, Jason Wang
In-Reply-To: <911d6dda-85de-ba8d-0c84-6a37e91523de@cogentembedded.com>
I'm shocked this somehow made it into the commit. I wonder how that happened?
Anyway, fixed in my git repo, and will be part of the next series.
(Unless DaveM wants to fix it up trivially when/if he merges this v9,
which would be faster.)
Barring that, does this look good to you? Could I have your signed-off-by?
Regards,
Jason
^ permalink raw reply
* Re: [PATCH net-next 2/4] nfp: register ports as devlink ports
From: Jiri Pirko @ 2017-05-24 12:35 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: netdev, oss-drivers
In-Reply-To: <20170523151247.8535-3-jakub.kicinski@netronome.com>
Tue, May 23, 2017 at 05:12:45PM CEST, jakub.kicinski@netronome.com wrote:
>Extend nfp_port to contain devlink_port structures. Register the
>ports to allow users inspecting device ports.
>
>Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
>Reviewed-by: Simon Horman <simon.horman@netronome.com>
>---
[...]
>+void nfp_devlink_port_unregister(struct nfp_port *port)
>+{
>+ /* Due to unpleasant lock ordering we may see the port go away before
>+ * we have fully probed.
Could you elaborate on this a bit more please?
>+ */
>+ if (port->dl_port.registered)
>+ devlink_port_unregister(&port->dl_port);
>+}
^ permalink raw reply
* Re: [PATCH v2] drivers: phy: Add Cortina CS4340 driver
From: Andrew Lunn @ 2017-05-24 12:58 UTC (permalink / raw)
To: Bogdan Purcareata; +Cc: f.fainelli, netdev, linux-kernel
In-Reply-To: <1495617948-13435-1-git-send-email-bogdan.purcareata@nxp.com>
On Wed, May 24, 2017 at 09:25:48AM +0000, Bogdan Purcareata wrote:
> Add basic support for Cortina PHY drivers. Support only CS4340 for now.
> The phys are not compatible with IEEE 802.3 clause 45 registers. Implement
> proper read_status support, so that phy polling does not cause bus
> register access errors.
>
> The driver should be described using the "ethernet-phy-id" device tree
> compatible.
Hi Bogdan
Thanks for testing that ethernet-phy-id works.
I suggest you write a
Documentation/devicetree/binding/net/phy/cortina.txt giving an example
device tree node.
>
> Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
> ---
> v1 -> v2:
> - Rename "mdio-cortina.c" to "cortina.c" since it's a phy driver.
> - Test probing based on the "ethernet-phy-id" compatible. In the previous
> version, getting the phy_id via get_phy_c45_ids() involved an additional
> hack. Drop that approach and document probing in the commit message.
>
> drivers/net/phy/Kconfig | 5 +++
> drivers/net/phy/Makefile | 1 +
> drivers/net/phy/cortina.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 96 insertions(+)
> create mode 100644 drivers/net/phy/cortina.c
>
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> index 22dea7f..ad09e2d 100644
> --- a/drivers/net/phy/Kconfig
> +++ b/drivers/net/phy/Kconfig
> @@ -240,6 +240,11 @@ config CICADA_PHY
> ---help---
> Currently supports the cis8204
>
> +config CORTINA_PHY
> + tristate "Cortina quad-10G Ethernet PHY"
> + ---help---
> + Currently supports the CS4340 phy.
> +
> config DAVICOM_PHY
> tristate "Davicom PHYs"
> ---help---
> diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
> index 79365be..0de3e20 100644
> --- a/drivers/net/phy/Makefile
> +++ b/drivers/net/phy/Makefile
> @@ -47,6 +47,7 @@ obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o
> obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o
> obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
> obj-$(CONFIG_CICADA_PHY) += cicada.o
> +obj-$(CONFIG_CORTINA_PHY) += cortina.o
> obj-$(CONFIG_DAVICOM_PHY) += davicom.o
> obj-$(CONFIG_DP83640_PHY) += dp83640.o
> obj-$(CONFIG_DP83848_PHY) += dp83848.o
> diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c
> new file mode 100644
> index 0000000..6f054ed
> --- /dev/null
> +++ b/drivers/net/phy/cortina.c
> @@ -0,0 +1,90 @@
> +/*
> + * Based on code from Cortina Systems, Inc.
> + *
> + * Copyright 2011 Cortina Systems, Inc.
> + * Copyright 2017 NXP
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program 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.
> + *
> + */
> +#include <linux/module.h>
> +#include <linux/phy.h>
> +
> +#define PHY_ID_CS4340 0x13e51002
> +
> +#define CORTINA_GPIO_GPIO_INTS 0x16D
> +
> +static int cortina_read_x(struct phy_device *phydev, int off, u16 regnum)
> +{
> + return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr + off,
> + MII_ADDR_C45 | regnum);
> +}
> +
> +static int cortina_read(struct phy_device *phydev, u16 regnum)
> +{
> + return cortina_read_x(phydev, 0, regnum);
> +}
> +
> +static int cortina_config_aneg(struct phy_device *phydev)
> +{
> + phydev->supported = SUPPORTED_10000baseT_Full;
> + phydev->advertising = SUPPORTED_10000baseT_Full;
> +
> + return 0;
> +}
> +
> +static int cortina_read_status(struct phy_device *phydev)
> +{
> + int gpio_int_status;
> + int ret = 0;
I think there needs to be some explanation here. What exactly are you
using to indicate link up? What does CORTINA_GPIO_GPIO_INTS mean?
> + gpio_int_status = cortina_read(phydev, CORTINA_GPIO_GPIO_INTS);
> + if (gpio_int_status < 0) {
> + ret = gpio_int_status;
> + goto err;
> + }
> +
> + if (gpio_int_status & 0x8) {
> + phydev->speed = SPEED_10000;
> + phydev->duplex = DUPLEX_FULL;
> + phydev->link = 1;
> + } else {
> + phydev->link = 0;
> + }
> +
> +err:
> + return ret;
> +}
> +
> +static int cortina_soft_reset(struct phy_device *phydev)
> +{
> + return 0;
> +}
> +
> +static struct phy_driver cortina_driver[] = {
> +{
> + .phy_id = PHY_ID_CS4340,
> + .phy_id_mask = 0xffffffff,
> + .name = "Cortina CS4340",
> + .config_aneg = cortina_config_aneg,
> + .read_status = cortina_read_status,
> + .soft_reset = cortina_soft_reset,
> +},
> +};
Having two } at the same indentation level seems odd. Please can you
fix this.
Thanks
Andrew
> +
> +module_phy_driver(cortina_driver);
> +
> +static struct mdio_device_id __maybe_unused cortina_tbl[] = {
> + { PHY_ID_CS4340, 0xffffffff},
> + {},
> +};
> +
> +MODULE_DEVICE_TABLE(mdio, cortina_tbl);
> --
> 1.9.1
>
^ permalink raw reply
* Re: [PATCH net-next v3 5/5] net-next: dsa: add dsa support for Mediatek MT7530 switch
From: Andrew Lunn @ 2017-05-24 13:20 UTC (permalink / raw)
To: Andrey Jr. Melnikov; +Cc: netdev, devicetree, linux-kernel, linux-mediatek
In-Reply-To: <hn6gvd-qp1.ln1@banana.localnet>
> What about JUMBO frames and large MTU support? devlink support?
To get the driver merged, it is better to start small, a minimal set
of features. Other features can be added later. If these features are
important to you, please feel free to submit patches.
Andrew
^ permalink raw reply
* [PATCHv2 net] netfilter: do not hold dev in ipt_CLUSTERIP
From: Xin Long @ 2017-05-24 13:24 UTC (permalink / raw)
To: network dev, netfilter-devel; +Cc: davem, pablo, fw
It's a terrible thing to hold dev in iptables target. When the dev is
being removed, unregister_netdevice has to wait for the dev to become
free. dmesg will keep logging the err:
kernel:unregister_netdevice: waiting for veth0_in to become free. \
Usage count = 1
until iptables rules with this target are removed manually.
The worse thing is when deleting a netns, a virtual nic will be deleted
instead of reset to init_net in default_device_ops exit/exit_batch. As
it is earlier than to flush the iptables rules in iptable_filter_net_ops
exit, unregister_netdevice will block to wait for the nic to become free.
As unregister_netdevice is actually waiting for iptables rules flushing
while iptables rules have to be flushed after unregister_netdevice. This
'dead lock' will cause unregister_netdevice to block there forever. As
the netns is not available to operate at that moment, iptables rules can
not even be flushed manually either.
The reproducer can be:
# ip netns add test
# ip link add veth0_in type veth peer name veth0_out
# ip link set veth0_in netns test
# ip netns exec test ip link set lo up
# ip netns exec test ip link set veth0_in up
# ip netns exec test iptables -I INPUT -d 1.2.3.4 -i veth0_in -j \
CLUSTERIP --new --clustermac 89:d4:47:eb:9a:fa --total-nodes 3 \
--local-node 1 --hashmode sourceip-sourceport
# ip netns del test
This issue can be triggered by all virtual nics with ipt_CLUSTERIP.
This patch is to fix it by not holding dev in ipt_CLUSTERIP, but saving
the dev->ifindex instead of the dev.
As Pablo Neira Ayuso's suggestion, it will refresh c->ifindex and dev's
mc by registering a netdevice notifier, just as what xt_TEE does. So it
removes the old codes updating dev's mc, and also no need to initialize
c->ifindex with dev->ifindex.
But as one config can be shared by more than one targets, and the netdev
notifier is per config, not per target. It couldn't get e->ip.iniface
in the notifier handler. So e->ip.iniface has to be saved into config.
Note that for backwards compatibility, this patch doesn't remove the
codes checking if the dev exists before creating a config.
v1->v2:
- As Pablo Neira Ayuso's suggestion, register a netdevice notifier to
manage c->ifindex and dev's mc.
Reported-by: Jianlin Shi <jishi@redhat.com>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/ipv4/netfilter/ipt_CLUSTERIP.c | 101 +++++++++++++++++++++++++++----------
1 file changed, 73 insertions(+), 28 deletions(-)
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 038f293..b2eef2a 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -47,7 +47,7 @@ struct clusterip_config {
__be32 clusterip; /* the IP address */
u_int8_t clustermac[ETH_ALEN]; /* the MAC address */
- struct net_device *dev; /* device */
+ int ifindex; /* device ifindex */
u_int16_t num_total_nodes; /* total number of nodes */
unsigned long local_nodes; /* node number array */
@@ -57,6 +57,9 @@ struct clusterip_config {
enum clusterip_hashmode hash_mode; /* which hashing mode */
u_int32_t hash_initval; /* hash initialization */
struct rcu_head rcu;
+
+ char ifname[IFNAMSIZ]; /* device ifname */
+ struct notifier_block notifier; /* refresh c->ifindex in it */
};
#ifdef CONFIG_PROC_FS
@@ -98,9 +101,8 @@ clusterip_config_put(struct clusterip_config *c)
* entry(rule) is removed, remove the config from lists, but don't free it
* yet, since proc-files could still be holding references */
static inline void
-clusterip_config_entry_put(struct clusterip_config *c)
+clusterip_config_entry_put(struct net *net, struct clusterip_config *c)
{
- struct net *net = dev_net(c->dev);
struct clusterip_net *cn = net_generic(net, clusterip_net_id);
local_bh_disable();
@@ -109,8 +111,7 @@ clusterip_config_entry_put(struct clusterip_config *c)
spin_unlock(&cn->lock);
local_bh_enable();
- dev_mc_del(c->dev, c->clustermac);
- dev_put(c->dev);
+ unregister_netdevice_notifier(&c->notifier);
/* In case anyone still accesses the file, the open/close
* functions are also incrementing the refcount on their own,
@@ -170,19 +171,55 @@ clusterip_config_init_nodelist(struct clusterip_config *c,
set_bit(i->local_nodes[n] - 1, &c->local_nodes);
}
-static struct clusterip_config *
-clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip,
- struct net_device *dev)
+static int
+clusterip_netdev_event(struct notifier_block *this, unsigned long event,
+ void *ptr)
{
- struct net *net = dev_net(dev);
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct clusterip_config *c;
+
+ c = container_of(this, struct clusterip_config, notifier);
+ switch (event) {
+ case NETDEV_REGISTER:
+ if (!strcmp(dev->name, c->ifname)) {
+ c->ifindex = dev->ifindex;
+ dev_mc_add(dev, c->clustermac);
+ }
+ break;
+ case NETDEV_UNREGISTER:
+ if (dev->ifindex == c->ifindex) {
+ dev_mc_del(dev, c->clustermac);
+ c->ifindex = -1;
+ }
+ break;
+ case NETDEV_CHANGENAME:
+ if (!strcmp(dev->name, c->ifname)) {
+ c->ifindex = dev->ifindex;
+ dev_mc_add(dev, c->clustermac);
+ } else if (dev->ifindex == c->ifindex) {
+ dev_mc_del(dev, c->clustermac);
+ c->ifindex = -1;
+ }
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct clusterip_config *
+clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i,
+ __be32 ip, const char *iniface)
+{
struct clusterip_net *cn = net_generic(net, clusterip_net_id);
+ struct clusterip_config *c;
+ int err;
c = kzalloc(sizeof(*c), GFP_ATOMIC);
if (!c)
return ERR_PTR(-ENOMEM);
- c->dev = dev;
+ strcpy(c->ifname, iniface);
+ c->ifindex = -1;
c->clusterip = ip;
memcpy(&c->clustermac, &i->clustermac, ETH_ALEN);
c->num_total_nodes = i->num_total_nodes;
@@ -213,17 +250,27 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip,
cn->procdir,
&clusterip_proc_fops, c);
if (!c->pde) {
- spin_lock_bh(&cn->lock);
- list_del_rcu(&c->list);
- spin_unlock_bh(&cn->lock);
- kfree(c);
-
- return ERR_PTR(-ENOMEM);
+ err = -ENOMEM;
+ goto err;
}
}
#endif
- return c;
+ c->notifier.notifier_call = clusterip_netdev_event;
+ err = register_netdevice_notifier(&c->notifier);
+ if (!err)
+ return c;
+
+#ifdef CONFIG_PROC_FS
+ proc_remove(c->pde);
+err:
+#endif
+ spin_lock_bh(&cn->lock);
+ list_del_rcu(&c->list);
+ spin_unlock_bh(&cn->lock);
+ kfree(c);
+
+ return ERR_PTR(err);
}
#ifdef CONFIG_PROC_FS
@@ -425,14 +472,13 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
e->ip.iniface);
return -ENOENT;
}
+ dev_put(dev);
- config = clusterip_config_init(cipinfo,
- e->ip.dst.s_addr, dev);
- if (IS_ERR(config)) {
- dev_put(dev);
+ config = clusterip_config_init(par->net, cipinfo,
+ e->ip.dst.s_addr,
+ e->ip.iniface);
+ if (IS_ERR(config))
return PTR_ERR(config);
- }
- dev_mc_add(config->dev, config->clustermac);
}
}
cipinfo->config = config;
@@ -458,7 +504,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
/* if no more entries are referencing the config, remove it
* from the list and destroy the proc entry */
- clusterip_config_entry_put(cipinfo->config);
+ clusterip_config_entry_put(par->net, cipinfo->config);
clusterip_config_put(cipinfo->config);
@@ -558,10 +604,9 @@ arp_mangle(void *priv,
* addresses on different interfacs. However, in the CLUSTERIP case
* this wouldn't work, since we didn't subscribe the mcast group on
* other interfaces */
- if (c->dev != state->out) {
- pr_debug("not mangling arp reply on different "
- "interface: cip'%s'-skb'%s'\n",
- c->dev->name, state->out->name);
+ if (c->ifindex != state->out->ifindex) {
+ pr_debug("not mangling arp reply on different interface: cip'%d'-skb'%d'\n",
+ c->ifindex, state->out->ifindex);
clusterip_config_put(c);
return NF_ACCEPT;
}
--
2.1.0
^ permalink raw reply related
* Re: [PATCH 2/2] at803x: double check SGMII side autoneg
From: Timur Tabi @ 2017-05-24 13:29 UTC (permalink / raw)
To: Matthias May, Andrew Lunn
Cc: Zefir Kurtisi, netdev, f.fainelli, David Miller, Manoj Iyer,
jhugo
In-Reply-To: <a87a7309-e15e-286f-08d0-83535c094358@neratec.com>
On 5/24/17 2:18 AM, Matthias May wrote:
> With the patch: When the copper side is seen as up, it also checks if aneg of the SGMII link is done.
> As far as i know SGMII can not be run without aneg, since it is always Gbit with aneg mandatory.
> If SGMII aneg is not done, then, well aneg is not done and thus 0 is returned.
>
> Internally we have this patch extended so we don't only report that aneg is not done but also reset the link.
> Eventually aneg on the SGMII side can be completed and the link comes up.
I would really like to test this patch.
> Why do you think that frames are able to go through when aneg is reported as not done by the PHY?
I have two theories:
1. The warning message is bogus. The link actually is okay, but the
driver thinks that it isn't.
2. The link is not okay, but it automatically fixes itself soon after
the at803x_aneg_done() finishes.
> Since aneg is mandatory for SGMII this can as well be seen as "link not up", not?
The problem is that even though the link is up, the driver has returned
"0", so the kernel thinks that autonegotiation has not finished.
at803x_aneg_done() is never called again, and so I think the kernel is
disabling the interface is some secret way.
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, hosted by The Linux Foundation.
^ permalink raw reply
* Re: rsi: rsi_91x_core: Use time_after time comparison
From: Kalle Valo @ 2017-05-24 13:40 UTC (permalink / raw)
To: Karim Eshapa; +Cc: linux-wireless, netdev, linux-kernel, Karim Eshapa
In-Reply-To: <1494282850-13782-1-git-send-email-karim.eshapa@gmail.com>
Karim Eshapa <karim.eshapa@gmail.com> wrote:
> Use time_after kernel macro for time comparison.
>
> Signed-off-by: Karim Eshapa <karim.eshapa@gmail.com>
Patch applied to wireless-drivers-next.git, thanks.
c07036f18d93 rsi: rsi_91x_core: Use time_after time comparison
--
https://patchwork.kernel.org/patch/9716843/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: [PATCH 2/2] at803x: double check SGMII side autoneg
From: Andrew Lunn @ 2017-05-24 13:40 UTC (permalink / raw)
To: Timur Tabi
Cc: Matthias May, Zefir Kurtisi, netdev, f.fainelli, David Miller,
Manoj Iyer, jhugo
In-Reply-To: <a88a111d-5e3a-0999-14ef-0ada06febb3f@codeaurora.org>
> >Since aneg is mandatory for SGMII this can as well be seen as "link not up", not?
>
> The problem is that even though the link is up, the driver has
> returned "0", so the kernel thinks that autonegotiation has not
> finished.
You need to prove this, that the link is not up. Any by link, we mean
both the copper and the SGMII link.
> at803x_aneg_done() is never called again, and so I think
> the kernel is disabling the interface is some secret way.
Well, the driver has told the core that the link is not up. So the
kernel is waiting for another interrupt indicating the link has gone
up. And probably, this second interrupt never happens.
And it is not disabling the interface. Since the PHY is still down,
the core has not called netif_carrier_on().
Andrew
^ permalink raw reply
* Re: [PATCHv4] wlcore: add wl1285 compatible
From: Kalle Valo @ 2017-05-24 13:42 UTC (permalink / raw)
To: Sebastian Reichel
Cc: David S. Miller, Sebastian Reichel, Tony Lindgren,
Marcel Holtmann, Rob Herring, linux-wireless, linux-omap,
linux-kernel, netdev, Sebastian Reichel
In-Reply-To: <20170505141553.2605-1-sebastian.reichel@collabora.co.uk>
Sebastian Reichel <sebastian.reichel@collabora.co.uk> wrote:
> Motorola Droid 4 uses a WL1285C. With differences between the
> chips not being public let's add explicit binding for wl1285
> instead of relying on wl1283 being very similar.
>
> Reviewed-by: Rob Herring <robh@kernel.org>
> Acked-by: Kalle Valo <kvalo@codeaurora.org>
> Acked-by: Tony Lindgren <tony@atomide.com>
> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
My understanding is that there will be a new version. Please let me know
if I misunderstood.
Patch set to Changes Requested.
--
https://patchwork.kernel.org/patch/9713645/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: wlcore: fix 64K page support
From: Kalle Valo @ 2017-05-24 13:42 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Arnd Bergmann, stable, Reizer, Eyal, Tony Lindgren, Wei Yongjun,
linux-wireless, netdev, linux-kernel
In-Reply-To: <20170511115307.3060650-1-arnd@arndb.de>
Arnd Bergmann <arnd@arndb.de> wrote:
> In the stable linux-3.16 branch, I ran into a warning in the
> wlcore driver:
>
> drivers/net/wireless/ti/wlcore/spi.c: In function 'wl12xx_spi_raw_write':
> drivers/net/wireless/ti/wlcore/spi.c:315:1: error: the frame size of 12848 bytes is larger than 2048 bytes [-Werror=frame-larger-than=]
>
> Newer kernels no longer show the warning, but the bug is still there,
> as the allocation is based on the CPU page size rather than the
> actual capabilities of the hardware.
>
> This replaces the PAGE_SIZE macro with the SZ_4K macro, i.e. 4096 bytes
> per buffer.
>
> Cc: stable@vger.kernel.org
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Patch applied to wireless-drivers-next.git, thanks.
4a4274bf2dbb wlcore: fix 64K page support
--
https://patchwork.kernel.org/patch/9721269/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: [v3] libertas: Avoid reading past end of buffer
From: Kalle Valo @ 2017-05-24 13:44 UTC (permalink / raw)
To: Kees Cook
Cc: netdev, Joe Perches, libertas-dev, linux-wireless, netdev,
Daniel Micay, linux-kernel
In-Reply-To: <20170515212640.GA45443@beast>
Kees Cook <keescook@chromium.org> wrote:
> Using memcpy() from a string that is shorter than the length copied means
> the destination buffer is being filled with arbitrary data from the kernel
> rodata segment. Instead, redefine the stat strings to be ETH_GSTRING_LEN
> sizes, like other drivers. This lets us use a single memcpy that does not
> leak rodata contents. Additionally adjust indentation to keep checkpatch.pl
> happy.
>
> This was found with the future CONFIG_FORTIFY_SOURCE feature.
>
> Cc: Daniel Micay <danielmicay@gmail.com>
> Signed-off-by: Kees Cook <keescook@chromium.org>
Patch applied to wireless-drivers-next.git, thanks.
12e3c0433e8a libertas: Avoid reading past end of buffer
--
https://patchwork.kernel.org/patch/9727997/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ 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