* Re: [PATCH rdma-rc] RDMA/mlx5: Fix missed RST2INIT and INIT2INIT steps during ECE handshake
From: Jason Gunthorpe @ 2020-06-18 13:01 UTC (permalink / raw)
To: Leon Romanovsky
Cc: Doug Ledford, Leon Romanovsky, linux-rdma, Mark Zhang, netdev,
Saeed Mahameed
In-Reply-To: <20200616104536.2426384-1-leon@kernel.org>
On Tue, Jun 16, 2020 at 01:45:36PM +0300, Leon Romanovsky wrote:
> From: Leon Romanovsky <leonro@mellanox.com>
>
> Missed step during ECE handshake left userspace application with less
> options for the ECE handshake with a need to do workarounds.
>
> Fixes: 50aec2c3135e ("RDMA/mlx5: Return ECE data after modify QP")
> Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
> ---
> drivers/infiniband/hw/mlx5/qpc.c | 8 ++++++++
> include/linux/mlx5/mlx5_ifc.h | 10 ++++++----
> 2 files changed, 14 insertions(+), 4 deletions(-)
Applied to for-rc, thanks
Jason
^ permalink raw reply
* Re: [PATCH net] net: dsa: bcm_sf2: Fix node reference count
From: Andrew Lunn @ 2020-06-18 12:56 UTC (permalink / raw)
To: Florian Fainelli
Cc: netdev, Vivien Didelot, David S. Miller, Jakub Kicinski,
open list
In-Reply-To: <20200618034245.29928-1-f.fainelli@gmail.com>
On Wed, Jun 17, 2020 at 08:42:44PM -0700, Florian Fainelli wrote:
> of_find_node_by_name() will do an of_node_put() on the "from" argument.
> Fixes: afa3b592953b ("net: dsa: bcm_sf2: Ensure correct sub-node is parsed")
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
> drivers/net/dsa/bcm_sf2.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
> index c1bd21e4b15c..9f62ba3e4345 100644
> --- a/drivers/net/dsa/bcm_sf2.c
> +++ b/drivers/net/dsa/bcm_sf2.c
> @@ -1154,6 +1154,8 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev)
> set_bit(0, priv->cfp.used);
> set_bit(0, priv->cfp.unique);
>
> + /* Balance of_node_put() done by of_find_node_by_name() */
> + of_node_get(dn);
> ports = of_find_node_by_name(dn, "ports");
That if_find_node_by_name() does a put is not very intuitive.
Maybe document that as well in the kerneldocs?
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
* [PATCH net v5 1/4] flow_offload: add flow_indr_block_cb_alloc/remove function
From: wenxu @ 2020-06-18 12:49 UTC (permalink / raw)
To: netdev; +Cc: davem, pablo, vladbu, simon.horman
In-Reply-To: <1592484551-16188-1-git-send-email-wenxu@ucloud.cn>
From: wenxu <wenxu@ucloud.cn>
Add flow_indr_block_cb_alloc/remove function for next fix patch.
Signed-off-by: wenxu <wenxu@ucloud.cn>
---
include/net/flow_offload.h | 13 +++++++++++++
net/core/flow_offload.c | 21 +++++++++++++++++++++
2 files changed, 34 insertions(+)
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index f2c8311..bf43430 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -467,6 +467,12 @@ struct flow_block_cb {
struct flow_block_cb *flow_block_cb_alloc(flow_setup_cb_t *cb,
void *cb_ident, void *cb_priv,
void (*release)(void *cb_priv));
+struct flow_block_cb *flow_indr_block_cb_alloc(flow_setup_cb_t *cb,
+ void *cb_ident, void *cb_priv,
+ void (*release)(void *cb_priv),
+ struct flow_block_offload *bo,
+ struct net_device *dev, void *data,
+ void (*cleanup)(struct flow_block_cb *block_cb));
void flow_block_cb_free(struct flow_block_cb *block_cb);
struct flow_block_cb *flow_block_cb_lookup(struct flow_block *block,
@@ -488,6 +494,13 @@ static inline void flow_block_cb_remove(struct flow_block_cb *block_cb,
list_move(&block_cb->list, &offload->cb_list);
}
+static inline void flow_indr_block_cb_remove(struct flow_block_cb *block_cb,
+ struct flow_block_offload *offload)
+{
+ list_del(&block_cb->indr.list);
+ list_move(&block_cb->list, &offload->cb_list);
+}
+
bool flow_block_cb_is_busy(flow_setup_cb_t *cb, void *cb_ident,
struct list_head *driver_block_list);
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index 0cfc35e..1fd781d 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -437,6 +437,27 @@ static void flow_block_indr_init(struct flow_block_cb *flow_block,
flow_block->indr.cleanup = cleanup;
}
+struct flow_block_cb *flow_indr_block_cb_alloc(flow_setup_cb_t *cb,
+ void *cb_ident, void *cb_priv,
+ void (*release)(void *cb_priv),
+ struct flow_block_offload *bo,
+ struct net_device *dev, void *data,
+ void (*cleanup)(struct flow_block_cb *block_cb))
+{
+ struct flow_block_cb *block_cb;
+
+ block_cb = flow_block_cb_alloc(cb, cb_ident, cb_priv, release);
+ if (IS_ERR(block_cb))
+ goto out;
+
+ flow_block_indr_init(block_cb, bo, dev, data, cleanup);
+ list_add(&block_cb->indr.list, &flow_block_indr_list);
+
+out:
+ return block_cb;
+}
+EXPORT_SYMBOL(flow_indr_block_cb_alloc);
+
static void __flow_block_indr_binding(struct flow_block_offload *bo,
struct net_device *dev, void *data,
void (*cleanup)(struct flow_block_cb *block_cb))
--
1.8.3.1
^ permalink raw reply related
* [PATCH net v5 2/4] flow_offload: use flow_indr_block_cb_alloc/remove function
From: wenxu @ 2020-06-18 12:49 UTC (permalink / raw)
To: netdev; +Cc: davem, pablo, vladbu, simon.horman
In-Reply-To: <1592484551-16188-1-git-send-email-wenxu@ucloud.cn>
From: wenxu <wenxu@ucloud.cn>
Prepare fix the bug in the next patch. use flow_indr_block_cb_alloc/remove
function and remove the __flow_block_indr_binding.
Signed-off-by: wenxu <wenxu@ucloud.cn>
---
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c | 19 ++++++++++++-------
.../net/ethernet/mellanox/mlx5/core/en/rep/tc.c | 21 ++++++++++++++-------
drivers/net/ethernet/netronome/nfp/flower/main.h | 4 +++-
.../net/ethernet/netronome/nfp/flower/offload.c | 18 +++++++++++-------
include/net/flow_offload.h | 4 +++-
net/core/flow_offload.c | 22 +---------------------
6 files changed, 44 insertions(+), 44 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
index 0eef4f5..3e3a884 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
@@ -1889,7 +1889,8 @@ static void bnxt_tc_setup_indr_rel(void *cb_priv)
}
static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct bnxt *bp,
- struct flow_block_offload *f)
+ struct flow_block_offload *f, void *data,
+ void (*cleanup)(struct flow_block_cb *block_cb))
{
struct bnxt_flower_indr_block_cb_priv *cb_priv;
struct flow_block_cb *block_cb;
@@ -1907,9 +1908,10 @@ static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct bnxt *bp,
cb_priv->bp = bp;
list_add(&cb_priv->list, &bp->tc_indr_block_list);
- block_cb = flow_block_cb_alloc(bnxt_tc_setup_indr_block_cb,
- cb_priv, cb_priv,
- bnxt_tc_setup_indr_rel);
+ block_cb = flow_indr_block_cb_alloc(bnxt_tc_setup_indr_block_cb,
+ cb_priv, cb_priv,
+ bnxt_tc_setup_indr_rel, f,
+ netdev, data, cleanup);
if (IS_ERR(block_cb)) {
list_del(&cb_priv->list);
kfree(cb_priv);
@@ -1930,7 +1932,7 @@ static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct bnxt *bp,
if (!block_cb)
return -ENOENT;
- flow_block_cb_remove(block_cb, f);
+ flow_indr_block_cb_remove(block_cb, f);
list_del(&block_cb->driver_list);
break;
default:
@@ -1945,14 +1947,17 @@ static bool bnxt_is_netdev_indr_offload(struct net_device *netdev)
}
static int bnxt_tc_setup_indr_cb(struct net_device *netdev, void *cb_priv,
- enum tc_setup_type type, void *type_data)
+ enum tc_setup_type type, void *type_data,
+ void *data,
+ void (*cleanup)(struct flow_block_cb *block_cb))
{
if (!bnxt_is_netdev_indr_offload(netdev))
return -EOPNOTSUPP;
switch (type) {
case TC_SETUP_BLOCK:
- return bnxt_tc_setup_indr_block(netdev, cb_priv, type_data);
+ return bnxt_tc_setup_indr_block(netdev, cb_priv, type_data, data,
+ cleanup);
default:
break;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
index 80713123..d629864 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
@@ -407,7 +407,9 @@ static void mlx5e_rep_indr_block_unbind(void *cb_priv)
mlx5e_rep_indr_setup_block(struct net_device *netdev,
struct mlx5e_rep_priv *rpriv,
struct flow_block_offload *f,
- flow_setup_cb_t *setup_cb)
+ flow_setup_cb_t *setup_cb,
+ void *data,
+ void (*cleanup)(struct flow_block_cb *block_cb))
{
struct mlx5e_priv *priv = netdev_priv(rpriv->netdev);
struct mlx5e_rep_indr_block_priv *indr_priv;
@@ -438,8 +440,9 @@ static void mlx5e_rep_indr_block_unbind(void *cb_priv)
list_add(&indr_priv->list,
&rpriv->uplink_priv.tc_indr_block_priv_list);
- block_cb = flow_block_cb_alloc(setup_cb, indr_priv, indr_priv,
- mlx5e_rep_indr_block_unbind);
+ block_cb = flow_indr_block_cb_alloc(setup_cb, indr_priv, indr_priv,
+ mlx5e_rep_indr_block_unbind,
+ f, netdev, data, cleanup);
if (IS_ERR(block_cb)) {
list_del(&indr_priv->list);
kfree(indr_priv);
@@ -458,7 +461,7 @@ static void mlx5e_rep_indr_block_unbind(void *cb_priv)
if (!block_cb)
return -ENOENT;
- flow_block_cb_remove(block_cb, f);
+ flow_indr_block_cb_remove(block_cb, f);
list_del(&block_cb->driver_list);
return 0;
default:
@@ -469,15 +472,19 @@ static void mlx5e_rep_indr_block_unbind(void *cb_priv)
static
int mlx5e_rep_indr_setup_cb(struct net_device *netdev, void *cb_priv,
- enum tc_setup_type type, void *type_data)
+ enum tc_setup_type type, void *type_data,
+ void *data,
+ void (*cleanup)(struct flow_block_cb *block_cb))
{
switch (type) {
case TC_SETUP_BLOCK:
return mlx5e_rep_indr_setup_block(netdev, cb_priv, type_data,
- mlx5e_rep_indr_setup_tc_cb);
+ mlx5e_rep_indr_setup_tc_cb,
+ data, cleanup);
case TC_SETUP_FT:
return mlx5e_rep_indr_setup_block(netdev, cb_priv, type_data,
- mlx5e_rep_indr_setup_ft_cb);
+ mlx5e_rep_indr_setup_ft_cb,
+ data, cleanup);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h
index 6c3dc3b..56b3b68 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.h
@@ -459,7 +459,9 @@ int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev,
struct tc_cls_matchall_offload *flow);
void nfp_flower_stats_rlim_reply(struct nfp_app *app, struct sk_buff *skb);
int nfp_flower_indr_setup_tc_cb(struct net_device *netdev, void *cb_priv,
- enum tc_setup_type type, void *type_data);
+ enum tc_setup_type type, void *type_data,
+ void *data,
+ void (*cleanup)(struct flow_block_cb *block_cb));
int nfp_flower_setup_indr_block_cb(enum tc_setup_type type, void *type_data,
void *cb_priv);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 695d24b9..95c7525 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1647,7 +1647,8 @@ static void nfp_flower_setup_indr_tc_release(void *cb_priv)
static int
nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
- struct flow_block_offload *f)
+ struct flow_block_offload *f, void *data,
+ void (*cleanup)(struct flow_block_cb *block_cb))
{
struct nfp_flower_indr_block_cb_priv *cb_priv;
struct nfp_flower_priv *priv = app->priv;
@@ -1676,9 +1677,10 @@ static void nfp_flower_setup_indr_tc_release(void *cb_priv)
cb_priv->app = app;
list_add(&cb_priv->list, &priv->indr_block_cb_priv);
- block_cb = flow_block_cb_alloc(nfp_flower_setup_indr_block_cb,
- cb_priv, cb_priv,
- nfp_flower_setup_indr_tc_release);
+ block_cb = flow_indr_block_cb_alloc(nfp_flower_setup_indr_block_cb,
+ cb_priv, cb_priv,
+ nfp_flower_setup_indr_tc_release,
+ f, netdev, data, cleanup);
if (IS_ERR(block_cb)) {
list_del(&cb_priv->list);
kfree(cb_priv);
@@ -1699,7 +1701,7 @@ static void nfp_flower_setup_indr_tc_release(void *cb_priv)
if (!block_cb)
return -ENOENT;
- flow_block_cb_remove(block_cb, f);
+ flow_indr_block_cb_remove(block_cb, f);
list_del(&block_cb->driver_list);
return 0;
default:
@@ -1710,7 +1712,9 @@ static void nfp_flower_setup_indr_tc_release(void *cb_priv)
int
nfp_flower_indr_setup_tc_cb(struct net_device *netdev, void *cb_priv,
- enum tc_setup_type type, void *type_data)
+ enum tc_setup_type type, void *type_data,
+ void *data,
+ void (*cleanup)(struct flow_block_cb *block_cb))
{
if (!nfp_fl_is_netdev_to_offload(netdev))
return -EOPNOTSUPP;
@@ -1718,7 +1722,7 @@ static void nfp_flower_setup_indr_tc_release(void *cb_priv)
switch (type) {
case TC_SETUP_BLOCK:
return nfp_flower_setup_indr_tc_block(netdev, cb_priv,
- type_data);
+ type_data, data, cleanup);
default:
return -EOPNOTSUPP;
}
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index bf43430..1961c79 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -545,7 +545,9 @@ static inline void flow_block_init(struct flow_block *flow_block)
}
typedef int flow_indr_block_bind_cb_t(struct net_device *dev, void *cb_priv,
- enum tc_setup_type type, void *type_data);
+ enum tc_setup_type type, void *type_data,
+ void *data,
+ void (*cleanup)(struct flow_block_cb *block_cb));
int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv);
void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index 1fd781d..ddd958c 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -458,25 +458,6 @@ struct flow_block_cb *flow_indr_block_cb_alloc(flow_setup_cb_t *cb,
}
EXPORT_SYMBOL(flow_indr_block_cb_alloc);
-static void __flow_block_indr_binding(struct flow_block_offload *bo,
- struct net_device *dev, void *data,
- void (*cleanup)(struct flow_block_cb *block_cb))
-{
- struct flow_block_cb *block_cb;
-
- list_for_each_entry(block_cb, &bo->cb_list, list) {
- switch (bo->command) {
- case FLOW_BLOCK_BIND:
- flow_block_indr_init(block_cb, bo, dev, data, cleanup);
- list_add(&block_cb->indr.list, &flow_block_indr_list);
- break;
- case FLOW_BLOCK_UNBIND:
- list_del(&block_cb->indr.list);
- break;
- }
- }
-}
-
int flow_indr_dev_setup_offload(struct net_device *dev,
enum tc_setup_type type, void *data,
struct flow_block_offload *bo,
@@ -486,9 +467,8 @@ int flow_indr_dev_setup_offload(struct net_device *dev,
mutex_lock(&flow_indr_block_lock);
list_for_each_entry(this, &flow_block_indr_dev_list, list)
- this->cb(dev, this->cb_priv, type, bo);
+ this->cb(dev, this->cb_priv, type, bo, data, cleanup);
- __flow_block_indr_binding(bo, dev, data, cleanup);
mutex_unlock(&flow_indr_block_lock);
return list_empty(&bo->cb_list) ? -EOPNOTSUPP : 0;
--
1.8.3.1
^ permalink raw reply related
* [PATCH net v5 4/4] net/sched: cls_api: fix nooffloaddevcnt warning dmesg log
From: wenxu @ 2020-06-18 12:49 UTC (permalink / raw)
To: netdev; +Cc: davem, pablo, vladbu, simon.horman
In-Reply-To: <1592484551-16188-1-git-send-email-wenxu@ucloud.cn>
From: wenxu <wenxu@ucloud.cn>
The block->nooffloaddevcnt should always count for indr block.
even the indr block offload successful. The representor maybe
gone away and the ingress qdisc can work in software mode.
block->nooffloaddevcnt warning with following dmesg log:
[ 760.667058] #####################################################
[ 760.668186] ## TEST test-ecmp-add-vxlan-encap-disable-sriov.sh ##
[ 760.669179] #####################################################
[ 761.780655] :test: Fedora 30 (Thirty)
[ 761.783794] :test: Linux reg-r-vrt-018-180 5.7.0+
[ 761.822890] :test: NIC ens1f0 FW 16.26.6000 PCI 0000:81:00.0 DEVICE 0x1019 ConnectX-5 Ex
[ 761.860244] mlx5_core 0000:81:00.0 ens1f0: Link up
[ 761.880693] IPv6: ADDRCONF(NETDEV_CHANGE): ens1f0: link becomes ready
[ 762.059732] mlx5_core 0000:81:00.1 ens1f1: Link up
[ 762.234341] :test: unbind vfs of ens1f0
[ 762.257825] :test: Change ens1f0 eswitch (0000:81:00.0) mode to switchdev
[ 762.291363] :test: unbind vfs of ens1f1
[ 762.306914] :test: Change ens1f1 eswitch (0000:81:00.1) mode to switchdev
[ 762.309237] mlx5_core 0000:81:00.1: E-Switch: Disable: mode(LEGACY), nvfs(2), active vports(3)
[ 763.282598] mlx5_core 0000:81:00.1: E-Switch: Supported tc offload range - chains: 4294967294, prios: 4294967295
[ 763.362825] mlx5_core 0000:81:00.1: MLX5E: StrdRq(1) RqSz(8) StrdSz(2048) RxCqeCmprss(0)
[ 763.444465] mlx5_core 0000:81:00.1 ens1f1: renamed from eth0
[ 763.460088] mlx5_core 0000:81:00.1: MLX5E: StrdRq(1) RqSz(8) StrdSz(2048) RxCqeCmprss(0)
[ 763.502586] mlx5_core 0000:81:00.1: MLX5E: StrdRq(1) RqSz(8) StrdSz(2048) RxCqeCmprss(0)
[ 763.552429] ens1f1_0: renamed from eth0
[ 763.569569] mlx5_core 0000:81:00.1: E-Switch: Enable: mode(OFFLOADS), nvfs(2), active vports(3)
[ 763.629694] ens1f1_1: renamed from eth1
[ 764.631552] IPv6: ADDRCONF(NETDEV_CHANGE): ens1f1_0: link becomes ready
[ 764.670841] :test: unbind vfs of ens1f0
[ 764.681966] :test: unbind vfs of ens1f1
[ 764.726762] mlx5_core 0000:81:00.0 ens1f0: Link up
[ 764.766511] mlx5_core 0000:81:00.1 ens1f1: Link up
[ 764.797325] :test: Add multipath vxlan encap rule and disable sriov
[ 764.798544] :test: config multipath route
[ 764.812732] mlx5_core 0000:81:00.0: lag map port 1:2 port 2:2
[ 764.874556] mlx5_core 0000:81:00.0: modify lag map port 1:1 port 2:2
[ 765.603681] :test: OK
[ 765.659048] IPv6: ADDRCONF(NETDEV_CHANGE): ens1f1_1: link becomes ready
[ 765.675085] :test: verify rule in hw
[ 765.694237] IPv6: ADDRCONF(NETDEV_CHANGE): ens1f0: link becomes ready
[ 765.711892] IPv6: ADDRCONF(NETDEV_CHANGE): ens1f1: link becomes ready
[ 766.979230] :test: OK
[ 768.125419] :test: OK
[ 768.127519] :test: - disable sriov ens1f1
[ 768.131160] pci 0000:81:02.2: Removing from iommu group 75
[ 768.132646] pci 0000:81:02.3: Removing from iommu group 76
[ 769.179749] mlx5_core 0000:81:00.1: E-Switch: Disable: mode(OFFLOADS), nvfs(2), active vports(3)
[ 769.455627] mlx5_core 0000:81:00.0: modify lag map port 1:1 port 2:1
[ 769.703990] mlx5_core 0000:81:00.1: MLX5E: StrdRq(1) RqSz(8) StrdSz(2048) RxCqeCmprss(0)
[ 769.988637] mlx5_core 0000:81:00.1 ens1f1: renamed from eth0
[ 769.990022] :test: - disable sriov ens1f0
[ 769.994922] pci 0000:81:00.2: Removing from iommu group 73
[ 769.997048] pci 0000:81:00.3: Removing from iommu group 74
[ 771.035813] mlx5_core 0000:81:00.0: E-Switch: Disable: mode(OFFLOADS), nvfs(2), active vports(3)
[ 771.339091] ------------[ cut here ]------------
[ 771.340812] WARNING: CPU: 6 PID: 3448 at net/sched/cls_api.c:749 tcf_block_offload_unbind.isra.0+0x5c/0x60
[ 771.341728] Modules linked in: act_mirred act_tunnel_key cls_flower dummy vxlan ip6_udp_tunnel udp_tunnel sch_ingress nfsv3 nfs_acl nfs lockd grace fscache tun bridge stp llc sunrpc rdma_ucm rdma_cm iw_cm ib_cm mlx5_ib ib_uverbs ib_core mlx5_core intel_rapl_msr intel_rapl_common sb_edac x86_pkg_temp_thermal intel_powerclamp coretemp mlxfw act_ct nf_flow_table kvm_intel nf_nat kvm nf_conntrack irqbypass crct10dif_pclmul igb crc32_pclmul nf_defrag_ipv6 libcrc32c nf_defrag_ipv4 crc32c_intel ghash_clmulni_intel ptp ipmi_ssif intel_cstate pps_c
ore ses intel_uncore mei_me iTCO_wdt joydev ipmi_si iTCO_vendor_support i2c_i801 enclosure mei ioatdma dca lpc_ich wmi ipmi_devintf pcspkr acpi_power_meter ipmi_msghandler acpi_pad ast i2c_algo_bit drm_vram_helper drm_kms_helper drm_ttm_helper ttm drm mpt3sas raid_class scsi_transport_sas
[ 771.347818] CPU: 6 PID: 3448 Comm: test-ecmp-add-v Not tainted 5.7.0+ #1146
[ 771.348727] Hardware name: Supermicro SYS-2028TP-DECR/X10DRT-P, BIOS 2.0b 03/30/2017
[ 771.349646] RIP: 0010:tcf_block_offload_unbind.isra.0+0x5c/0x60
[ 771.350553] Code: 4a fd ff ff 83 f8 a1 74 0e 5b 4c 89 e7 5d 41 5c 41 5d e9 07 93 89 ff 8b 83 a0 00 00 00 8d 50 ff 89 93 a0 00 00 00 85 c0 75 df <0f> 0b eb db 0f 1f 44 00 00 41 57 41 56 41 55 41 89 cd 41 54 49 89
[ 771.352420] RSP: 0018:ffffb33144cd3b00 EFLAGS: 00010246
[ 771.353353] RAX: 0000000000000000 RBX: ffff8b37cf4b2800 RCX: 0000000000000000
[ 771.354294] RDX: 00000000ffffffff RSI: ffff8b3b9aad0000 RDI: ffffffff8d5c6e20
[ 771.355245] RBP: ffff8b37eb546948 R08: ffffffffc0b7a348 R09: ffff8b3b9aad0000
[ 771.356189] R10: 0000000000000001 R11: ffff8b3ba7a0a1c0 R12: ffff8b37cf4b2850
[ 771.357123] R13: ffff8b3b9aad0000 R14: ffff8b37cf4b2820 R15: ffff8b37cf4b2820
[ 771.358039] FS: 00007f8a19b6e740(0000) GS:ffff8b3befa00000(0000) knlGS:0000000000000000
[ 771.358965] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 771.359885] CR2: 00007f3afb91c1a0 CR3: 000000045133c004 CR4: 00000000001606e0
[ 771.360825] Call Trace:
[ 771.361764] __tcf_block_put+0x84/0x150
[ 771.362712] ingress_destroy+0x1b/0x20 [sch_ingress]
[ 771.363658] qdisc_destroy+0x3e/0xc0
[ 771.364594] dev_shutdown+0x7a/0xa5
[ 771.365522] rollback_registered_many+0x20d/0x530
[ 771.366458] ? netdev_upper_dev_unlink+0x15d/0x1c0
[ 771.367387] unregister_netdevice_many.part.0+0xf/0x70
[ 771.368310] vxlan_netdevice_event+0xa4/0x110 [vxlan]
[ 771.369454] notifier_call_chain+0x4c/0x70
[ 771.370579] rollback_registered_many+0x2f5/0x530
[ 771.371719] rollback_registered+0x56/0x90
[ 771.372843] unregister_netdevice_queue+0x73/0xb0
[ 771.373982] unregister_netdev+0x18/0x20
[ 771.375168] mlx5e_vport_rep_unload+0x56/0xc0 [mlx5_core]
[ 771.376327] esw_offloads_disable+0x81/0x90 [mlx5_core]
[ 771.377512] mlx5_eswitch_disable_locked.cold+0xcb/0x1af [mlx5_core]
[ 771.378679] mlx5_eswitch_disable+0x44/0x60 [mlx5_core]
[ 771.379822] mlx5_device_disable_sriov+0xad/0xb0 [mlx5_core]
[ 771.380968] mlx5_core_sriov_configure+0xc1/0xe0 [mlx5_core]
[ 771.382087] sriov_numvfs_store+0xfc/0x130
[ 771.383195] kernfs_fop_write+0xce/0x1b0
[ 771.384302] vfs_write+0xb6/0x1a0
[ 771.385410] ksys_write+0x5f/0xe0
[ 771.386500] do_syscall_64+0x5b/0x1d0
[ 771.387569] entry_SYSCALL_64_after_hwframe+0x44/0xa9
Fixes: 0fdcf78d5973 ("net: use flow_indr_dev_setup_offload()")
Signed-off-by: wenxu <wenxu@ucloud.cn>
---
net/sched/cls_api.c | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index f8028d7..faa78b7 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -672,25 +672,29 @@ static int tcf_block_offload_cmd(struct tcf_block *block,
struct netlink_ext_ack *extack)
{
struct flow_block_offload bo = {};
- int err;
tcf_block_offload_init(&bo, dev, command, ei->binder_type,
&block->flow_block, tcf_block_shared(block),
extack);
- if (dev->netdev_ops->ndo_setup_tc)
+ if (dev->netdev_ops->ndo_setup_tc) {
+ int err;
+
err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_BLOCK, &bo);
- else
- err = flow_indr_dev_setup_offload(dev, TC_SETUP_BLOCK, block,
- &bo, tc_block_indr_cleanup);
+ if (err < 0) {
+ if (err != -EOPNOTSUPP)
+ NL_SET_ERR_MSG(extack, "Driver ndo_setup_tc failed");
+ return err;
+ }
- if (err < 0) {
- if (err != -EOPNOTSUPP)
- NL_SET_ERR_MSG(extack, "Driver ndo_setup_tc failed");
- return err;
+ return tcf_block_setup(block, &bo);
}
- return tcf_block_setup(block, &bo);
+ flow_indr_dev_setup_offload(dev, TC_SETUP_BLOCK, block, &bo,
+ tc_block_indr_cleanup);
+ tcf_block_setup(block, &bo);
+
+ return -EOPNOTSUPP;
}
static int tcf_block_offload_bind(struct tcf_block *block, struct Qdisc *q,
--
1.8.3.1
^ permalink raw reply related
* [PATCH net v5 3/4] net: flow_offload: fix flow_indr_dev_unregister path
From: wenxu @ 2020-06-18 12:49 UTC (permalink / raw)
To: netdev; +Cc: davem, pablo, vladbu, simon.horman
In-Reply-To: <1592484551-16188-1-git-send-email-wenxu@ucloud.cn>
From: wenxu <wenxu@ucloud.cn>
If the representor is removed, then identify the indirect flow_blocks
that need to be removed by the release callback and the port representor
structure. To identify the port representor structure, a new
indr.cb_priv field needs to be introduced. The flow_block also needs to
be removed from the driver list from the cleanup path.
Fixes: 1fac52da5942 ("net: flow_offload: consolidate indirect flow_block infrastructure")
Signed-off-by: wenxu <wenxu@ucloud.cn>
---
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c | 4 ++--
drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c | 5 +++--
drivers/net/ethernet/netronome/nfp/flower/main.c | 2 +-
drivers/net/ethernet/netronome/nfp/flower/main.h | 3 +--
drivers/net/ethernet/netronome/nfp/flower/offload.c | 8 ++++----
include/net/flow_offload.h | 4 +++-
net/core/flow_offload.c | 16 ++++++++++------
net/netfilter/nf_flow_table_offload.c | 1 +
net/netfilter/nf_tables_offload.c | 1 +
net/sched/cls_api.c | 1 +
10 files changed, 27 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
index 3e3a884..4a11c1e 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
@@ -1911,7 +1911,7 @@ static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct bnxt *bp,
block_cb = flow_indr_block_cb_alloc(bnxt_tc_setup_indr_block_cb,
cb_priv, cb_priv,
bnxt_tc_setup_indr_rel, f,
- netdev, data, cleanup);
+ netdev, data, bp, cleanup);
if (IS_ERR(block_cb)) {
list_del(&cb_priv->list);
kfree(cb_priv);
@@ -2079,7 +2079,7 @@ void bnxt_shutdown_tc(struct bnxt *bp)
return;
flow_indr_dev_unregister(bnxt_tc_setup_indr_cb, bp,
- bnxt_tc_setup_indr_block_cb);
+ bnxt_tc_setup_indr_rel);
rhashtable_destroy(&tc_info->flow_table);
rhashtable_destroy(&tc_info->l2_table);
rhashtable_destroy(&tc_info->decap_l2_table);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
index d629864..eefeb1c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
@@ -442,7 +442,8 @@ static void mlx5e_rep_indr_block_unbind(void *cb_priv)
block_cb = flow_indr_block_cb_alloc(setup_cb, indr_priv, indr_priv,
mlx5e_rep_indr_block_unbind,
- f, netdev, data, cleanup);
+ f, netdev, data, rpriv,
+ cleanup);
if (IS_ERR(block_cb)) {
list_del(&indr_priv->list);
kfree(indr_priv);
@@ -503,7 +504,7 @@ int mlx5e_rep_tc_netdevice_event_register(struct mlx5e_rep_priv *rpriv)
void mlx5e_rep_tc_netdevice_event_unregister(struct mlx5e_rep_priv *rpriv)
{
flow_indr_dev_unregister(mlx5e_rep_indr_setup_cb, rpriv,
- mlx5e_rep_indr_setup_tc_cb);
+ mlx5e_rep_indr_block_unbind);
}
#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c
index c393276..bb448c8 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.c
@@ -861,7 +861,7 @@ static void nfp_flower_clean(struct nfp_app *app)
flush_work(&app_priv->cmsg_work);
flow_indr_dev_unregister(nfp_flower_indr_setup_tc_cb, app,
- nfp_flower_setup_indr_block_cb);
+ nfp_flower_setup_indr_tc_release);
if (app_priv->flower_ext_feats & NFP_FL_FEATS_VF_RLIM)
nfp_flower_qos_cleanup(app);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h
index 56b3b68..7f54a62 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.h
@@ -462,8 +462,7 @@ int nfp_flower_indr_setup_tc_cb(struct net_device *netdev, void *cb_priv,
enum tc_setup_type type, void *type_data,
void *data,
void (*cleanup)(struct flow_block_cb *block_cb));
-int nfp_flower_setup_indr_block_cb(enum tc_setup_type type, void *type_data,
- void *cb_priv);
+void nfp_flower_setup_indr_tc_release(void *cb_priv);
void
__nfp_flower_non_repr_priv_get(struct nfp_flower_non_repr_priv *non_repr_priv);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 95c7525..d7340dc 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1619,8 +1619,8 @@ struct nfp_flower_indr_block_cb_priv {
return NULL;
}
-int nfp_flower_setup_indr_block_cb(enum tc_setup_type type,
- void *type_data, void *cb_priv)
+static int nfp_flower_setup_indr_block_cb(enum tc_setup_type type,
+ void *type_data, void *cb_priv)
{
struct nfp_flower_indr_block_cb_priv *priv = cb_priv;
struct flow_cls_offload *flower = type_data;
@@ -1637,7 +1637,7 @@ int nfp_flower_setup_indr_block_cb(enum tc_setup_type type,
}
}
-static void nfp_flower_setup_indr_tc_release(void *cb_priv)
+void nfp_flower_setup_indr_tc_release(void *cb_priv)
{
struct nfp_flower_indr_block_cb_priv *priv = cb_priv;
@@ -1680,7 +1680,7 @@ static void nfp_flower_setup_indr_tc_release(void *cb_priv)
block_cb = flow_indr_block_cb_alloc(nfp_flower_setup_indr_block_cb,
cb_priv, cb_priv,
nfp_flower_setup_indr_tc_release,
- f, netdev, data, cleanup);
+ f, netdev, data, app, cleanup);
if (IS_ERR(block_cb)) {
list_del(&cb_priv->list);
kfree(cb_priv);
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 1961c79..6315324 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -450,6 +450,7 @@ struct flow_block_indr {
struct net_device *dev;
enum flow_block_binder_type binder_type;
void *data;
+ void *cb_priv;
void (*cleanup)(struct flow_block_cb *block_cb);
};
@@ -472,6 +473,7 @@ struct flow_block_cb *flow_indr_block_cb_alloc(flow_setup_cb_t *cb,
void (*release)(void *cb_priv),
struct flow_block_offload *bo,
struct net_device *dev, void *data,
+ void *indr_cb_priv,
void (*cleanup)(struct flow_block_cb *block_cb));
void flow_block_cb_free(struct flow_block_cb *block_cb);
@@ -551,7 +553,7 @@ typedef int flow_indr_block_bind_cb_t(struct net_device *dev, void *cb_priv,
int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv);
void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
- flow_setup_cb_t *setup_cb);
+ void (*release)(void *cb_priv));
int flow_indr_dev_setup_offload(struct net_device *dev,
enum tc_setup_type type, void *data,
struct flow_block_offload *bo,
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index ddd958c..b739cfa 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -372,14 +372,15 @@ int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv)
}
EXPORT_SYMBOL(flow_indr_dev_register);
-static void __flow_block_indr_cleanup(flow_setup_cb_t *setup_cb, void *cb_priv,
+static void __flow_block_indr_cleanup(void (*release)(void *cb_priv),
+ void *cb_priv,
struct list_head *cleanup_list)
{
struct flow_block_cb *this, *next;
list_for_each_entry_safe(this, next, &flow_block_indr_list, indr.list) {
- if (this->cb == setup_cb &&
- this->cb_priv == cb_priv) {
+ if (this->release == release &&
+ this->indr.cb_priv == cb_priv) {
list_move(&this->indr.list, cleanup_list);
return;
}
@@ -397,7 +398,7 @@ static void flow_block_indr_notify(struct list_head *cleanup_list)
}
void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
- flow_setup_cb_t *setup_cb)
+ void (*release)(void *cb_priv))
{
struct flow_indr_dev *this, *next, *indr_dev = NULL;
LIST_HEAD(cleanup_list);
@@ -418,7 +419,7 @@ void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
return;
}
- __flow_block_indr_cleanup(setup_cb, cb_priv, &cleanup_list);
+ __flow_block_indr_cleanup(release, cb_priv, &cleanup_list);
mutex_unlock(&flow_indr_block_lock);
flow_block_indr_notify(&cleanup_list);
@@ -429,10 +430,12 @@ void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
static void flow_block_indr_init(struct flow_block_cb *flow_block,
struct flow_block_offload *bo,
struct net_device *dev, void *data,
+ void *cb_priv,
void (*cleanup)(struct flow_block_cb *block_cb))
{
flow_block->indr.binder_type = bo->binder_type;
flow_block->indr.data = data;
+ flow_block->indr.cb_priv = cb_priv;
flow_block->indr.dev = dev;
flow_block->indr.cleanup = cleanup;
}
@@ -442,6 +445,7 @@ struct flow_block_cb *flow_indr_block_cb_alloc(flow_setup_cb_t *cb,
void (*release)(void *cb_priv),
struct flow_block_offload *bo,
struct net_device *dev, void *data,
+ void *indr_cb_priv,
void (*cleanup)(struct flow_block_cb *block_cb))
{
struct flow_block_cb *block_cb;
@@ -450,7 +454,7 @@ struct flow_block_cb *flow_indr_block_cb_alloc(flow_setup_cb_t *cb,
if (IS_ERR(block_cb))
goto out;
- flow_block_indr_init(block_cb, bo, dev, data, cleanup);
+ flow_block_indr_init(block_cb, bo, dev, data, indr_cb_priv, cleanup);
list_add(&block_cb->indr.list, &flow_block_indr_list);
out:
diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
index 62651e6..5fff1e0 100644
--- a/net/netfilter/nf_flow_table_offload.c
+++ b/net/netfilter/nf_flow_table_offload.c
@@ -950,6 +950,7 @@ static void nf_flow_table_indr_cleanup(struct flow_block_cb *block_cb)
nf_flow_table_gc_cleanup(flowtable, dev);
down_write(&flowtable->flow_block_lock);
list_del(&block_cb->list);
+ list_del(&block_cb->driver_list);
flow_block_cb_free(block_cb);
up_write(&flowtable->flow_block_lock);
}
diff --git a/net/netfilter/nf_tables_offload.c b/net/netfilter/nf_tables_offload.c
index 185fc82..c7cf1cd 100644
--- a/net/netfilter/nf_tables_offload.c
+++ b/net/netfilter/nf_tables_offload.c
@@ -296,6 +296,7 @@ static void nft_indr_block_cleanup(struct flow_block_cb *block_cb)
nft_flow_block_offload_init(&bo, dev_net(dev), FLOW_BLOCK_UNBIND,
basechain, &extack);
mutex_lock(&net->nft.commit_mutex);
+ list_del(&block_cb->driver_list);
list_move(&block_cb->list, &bo.cb_list);
nft_flow_offload_unbind(&bo, basechain);
mutex_unlock(&net->nft.commit_mutex);
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index a00a203..f8028d7 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -652,6 +652,7 @@ static void tc_block_indr_cleanup(struct flow_block_cb *block_cb)
&block->flow_block, tcf_block_shared(block),
&extack);
down_write(&block->cb_lock);
+ list_del(&block_cb->driver_list);
list_move(&block_cb->list, &bo.cb_list);
up_write(&block->cb_lock);
rtnl_lock();
--
1.8.3.1
^ permalink raw reply related
* [PATCH net v5 0/4] several fixes for indirect flow_blocks offload
From: wenxu @ 2020-06-18 12:49 UTC (permalink / raw)
To: netdev; +Cc: davem, pablo, vladbu, simon.horman
From: wenxu <wenxu@ucloud.cn>
v2:
patch2: store the cb_priv of representor to the flow_block_cb->indr.cb_priv
in the driver. And make the correct check with the statments
this->indr.cb_priv == cb_priv
patch4: del the driver list only in the indriect cleanup callbacks
v3:
add the cover letter and changlogs.
v4:
collapsed 1/4, 2/4, 4/4 in v3 to one fix
Add the prepare patch 1 and 2
v5:
patch1: place flow_indr_block_cb_alloc() right before
flow_indr_dev_setup_offload() to avoid moving flow_block_indr_init()
This series fixes commit 1fac52da5942 ("net: flow_offload: consolidate
indirect flow_block infrastructure") that revists the flow_block
infrastructure.
patch #1 #2: prepare for fix patch #3
add and use flow_indr_block_cb_alloc/remove function
patch #3: fix flow_indr_dev_unregister path
If the representor is removed, then identify the indirect flow_blocks
that need to be removed by the release callback and the port representor
structure. To identify the port representor structure, a new
indr.cb_priv field needs to be introduced. The flow_block also needs to
be removed from the driver list from the cleanup path
patch#4 fix block->nooffloaddevcnt warning dmesg log.
When a indr device add in offload success. The block->nooffloaddevcnt
should be 0. After the representor go away. When the dir device go away
the flow_block UNBIND operation with -EOPNOTSUPP which lead the warning
demesg log.
The block->nooffloaddevcnt should always count for indr block.
even the indr block offload successful. The representor maybe
gone away and the ingress qdisc can work in software mode.
wenxu (4):
flow_offload: add flow_indr_block_cb_alloc/remove function
flow_offload: use flow_indr_block_cb_alloc/remove function
net: flow_offload: fix flow_indr_dev_unregister path
net/sched: cls_api: fix nooffloaddevcnt warning dmesg log
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c | 21 +++---
.../net/ethernet/mellanox/mlx5/core/en/rep/tc.c | 24 ++++---
drivers/net/ethernet/netronome/nfp/flower/main.c | 2 +-
drivers/net/ethernet/netronome/nfp/flower/main.h | 7 +-
.../net/ethernet/netronome/nfp/flower/offload.c | 24 ++++---
include/net/flow_offload.h | 21 +++++-
net/core/flow_offload.c | 79 ++++++++++++----------
net/netfilter/nf_flow_table_offload.c | 1 +
net/netfilter/nf_tables_offload.c | 1 +
net/sched/cls_api.c | 25 ++++---
10 files changed, 126 insertions(+), 79 deletions(-)
--
1.8.3.1
^ permalink raw reply
* Re: [PATCH] lan743x: allow mac address to come from dt
From: Andrew Lunn @ 2020-06-18 12:44 UTC (permalink / raw)
To: Tim Harvey
Cc: Bryan Whitehead, Microchip Linux Driver Support, David S . Miller,
Jakub Kicinski, netdev, linux-kernel
In-Reply-To: <1592434750-8940-1-git-send-email-tharvey@gateworks.com>
On Wed, Jun 17, 2020 at 03:59:10PM -0700, Tim Harvey wrote:
> If a valid mac address is present in dt, use that before using
> CSR's or a random mac address.
>
> Signed-off-by: Tim Harvey <tharvey@gateworks.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
* Re: [PATCH 0/6] Add Microchip MCP25XXFD CAN driver
From: Marc Kleine-Budde @ 2020-06-18 12:35 UTC (permalink / raw)
To: Manivannan Sadhasivam, wg, kernel, linux-can, netdev,
linux-kernel
In-Reply-To: <20200618123055.GA17496@x1.vandijck-laurijssen.be>
On 6/18/20 2:30 PM, Kurt Van Dijck wrote:
> On do, 18 jun 2020 00:36:29 +0200, Marc Kleine-Budde wrote:
>> On 6/17/20 6:59 PM, Kurt Van Dijck wrote:
>>> I'm in the process of getting a Variscite imx8m mini SOM online, with
>>
>> Have your heard about the imx8m plus? It has CAN cores! We have a board in the
>> office to play with. :)
>>
>>> MCP2517FD. The 4.19 kernel that comes with it, has a driver that is
>>
>> You shall not start projects with 1,5 years old kernel.
>> And you probably shall not use vendor kernel for new projects.
>> :D
>
> your rpi kernel starts of v4.19.119 (or so), where the variscite starts
> of v4.19.35.
You're missing some stable backports for the kernel then.
> The result was quite some list of merge conflicts, on top of a vendor
> kernel, so I took your advise and switched to the latest and greatest
> 5.7.3.
\o/
> Luckily, we need no sound (yet) and no video. :-)
regards,
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Embedded Linux | https://www.pengutronix.de |
Vertretung West/Dortmund | Phone: +49-231-2826-924 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* bpf-next test error: KASAN: use-after-free Write in afs_wake_up_async_call
From: syzbot @ 2020-06-18 12:34 UTC (permalink / raw)
To: ast, daniel, dhowells, linux-afs, linux-kernel, netdev,
syzkaller-bugs
Hello,
syzbot found the following crash on:
HEAD commit: 7bd3a33a libbpf: Bump version to 0.1.0
git tree: bpf-next
console output: https://syzkaller.appspot.com/x/log.txt?x=16bc8c35100000
kernel config: https://syzkaller.appspot.com/x/.config?x=b8ad29058cb749bc
dashboard link: https://syzkaller.appspot.com/bug?extid=39eaecb9eee28d41da93
compiler: gcc (GCC) 9.0.0 20181231 (experimental)
IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: syzbot+39eaecb9eee28d41da93@syzkaller.appspotmail.com
tipc: TX() has been purged, node left!
==================================================================
BUG: KASAN: use-after-free in afs_wake_up_async_call+0x6aa/0x770 fs/afs/rxrpc.c:707
Write of size 1 at addr ffff88809154b9e4 by task kworker/u4:0/7
CPU: 1 PID: 7 Comm: kworker/u4:0 Not tainted 5.8.0-rc1-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Workqueue: netns cleanup_net
Call Trace:
__dump_stack lib/dump_stack.c:77 [inline]
dump_stack+0x18f/0x20d lib/dump_stack.c:118
print_address_description.constprop.0.cold+0xd3/0x413 mm/kasan/report.c:383
__kasan_report mm/kasan/report.c:513 [inline]
kasan_report.cold+0x1f/0x37 mm/kasan/report.c:530
afs_wake_up_async_call+0x6aa/0x770 fs/afs/rxrpc.c:707
rxrpc_notify_socket+0x1db/0x5d0 net/rxrpc/recvmsg.c:40
__rxrpc_set_call_completion.part.0+0x172/0x410 net/rxrpc/recvmsg.c:76
__rxrpc_call_completed net/rxrpc/recvmsg.c:112 [inline]
rxrpc_call_completed+0xca/0xf0 net/rxrpc/recvmsg.c:111
rxrpc_discard_prealloc+0x781/0xab0 net/rxrpc/call_accept.c:233
rxrpc_listen+0x147/0x360 net/rxrpc/af_rxrpc.c:245
afs_close_socket+0x95/0x320 fs/afs/rxrpc.c:110
afs_net_exit+0x1bc/0x310 fs/afs/main.c:155
ops_exit_list.isra.0+0xa8/0x150 net/core/net_namespace.c:186
cleanup_net+0x511/0xa50 net/core/net_namespace.c:603
process_one_work+0x965/0x1690 kernel/workqueue.c:2269
worker_thread+0x96/0xe10 kernel/workqueue.c:2415
kthread+0x3b5/0x4a0 kernel/kthread.c:291
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:293
Allocated by task 6811:
save_stack+0x1b/0x40 mm/kasan/common.c:48
set_track mm/kasan/common.c:56 [inline]
__kasan_kmalloc mm/kasan/common.c:494 [inline]
__kasan_kmalloc.constprop.0+0xbf/0xd0 mm/kasan/common.c:467
kmem_cache_alloc_trace+0x153/0x7d0 mm/slab.c:3551
kmalloc include/linux/slab.h:555 [inline]
kzalloc include/linux/slab.h:669 [inline]
afs_alloc_call+0x55/0x630 fs/afs/rxrpc.c:141
afs_charge_preallocation+0xe9/0x2d0 fs/afs/rxrpc.c:757
afs_open_socket+0x292/0x360 fs/afs/rxrpc.c:92
afs_net_init+0xa6c/0xe30 fs/afs/main.c:125
ops_init+0xaf/0x420 net/core/net_namespace.c:151
setup_net+0x2de/0x860 net/core/net_namespace.c:341
copy_net_ns+0x293/0x590 net/core/net_namespace.c:482
create_new_namespaces+0x3fb/0xb30 kernel/nsproxy.c:110
unshare_nsproxy_namespaces+0xbd/0x1f0 kernel/nsproxy.c:231
ksys_unshare+0x43d/0x8e0 kernel/fork.c:2983
__do_sys_unshare kernel/fork.c:3051 [inline]
__se_sys_unshare kernel/fork.c:3049 [inline]
__x64_sys_unshare+0x2d/0x40 kernel/fork.c:3049
do_syscall_64+0x60/0xe0 arch/x86/entry/common.c:359
entry_SYSCALL_64_after_hwframe+0x44/0xa9
Freed by task 7:
save_stack+0x1b/0x40 mm/kasan/common.c:48
set_track mm/kasan/common.c:56 [inline]
kasan_set_free_info mm/kasan/common.c:316 [inline]
__kasan_slab_free+0xf7/0x140 mm/kasan/common.c:455
__cache_free mm/slab.c:3426 [inline]
kfree+0x109/0x2b0 mm/slab.c:3757
afs_put_call+0x585/0xa40 fs/afs/rxrpc.c:190
rxrpc_discard_prealloc+0x764/0xab0 net/rxrpc/call_accept.c:230
rxrpc_listen+0x147/0x360 net/rxrpc/af_rxrpc.c:245
afs_close_socket+0x95/0x320 fs/afs/rxrpc.c:110
afs_net_exit+0x1bc/0x310 fs/afs/main.c:155
ops_exit_list.isra.0+0xa8/0x150 net/core/net_namespace.c:186
cleanup_net+0x511/0xa50 net/core/net_namespace.c:603
process_one_work+0x965/0x1690 kernel/workqueue.c:2269
worker_thread+0x96/0xe10 kernel/workqueue.c:2415
kthread+0x3b5/0x4a0 kernel/kthread.c:291
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:293
The buggy address belongs to the object at ffff88809154b800
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 484 bytes inside of
1024-byte region [ffff88809154b800, ffff88809154bc00)
The buggy address belongs to the page:
page:ffffea00024552c0 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0
flags: 0xfffe0000000200(slab)
raw: 00fffe0000000200 ffffea00028cf188 ffffea000248e5c8 ffff8880aa000c40
raw: 0000000000000000 ffff88809154b000 0000000100000002 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff88809154b880: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88809154b900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88809154b980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff88809154ba00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88809154ba80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
---
This bug is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this bug report. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
^ permalink raw reply
* Re: [PATCH 0/6] Add Microchip MCP25XXFD CAN driver
From: Kurt Van Dijck @ 2020-06-18 12:30 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: Manivannan Sadhasivam, wg, kernel, linux-can, netdev,
linux-kernel
In-Reply-To: <2e80e2ed-d63d-5cc6-e1c6-e0c9e75c218e@pengutronix.de>
On do, 18 jun 2020 00:36:29 +0200, Marc Kleine-Budde wrote:
> On 6/17/20 6:59 PM, Kurt Van Dijck wrote:
> > I'm in the process of getting a Variscite imx8m mini SOM online, with
>
> Have your heard about the imx8m plus? It has CAN cores! We have a board in the
> office to play with. :)
>
> > MCP2517FD. The 4.19 kernel that comes with it, has a driver that is
>
> You shall not start projects with 1,5 years old kernel.
> And you probably shall not use vendor kernel for new projects.
> :D
your rpi kernel starts of v4.19.119 (or so), where the variscite starts
of v4.19.35.
The result was quite some list of merge conflicts, on top of a vendor
kernel, so I took your advise and switched to the latest and greatest
5.7.3.
Luckily, we need no sound (yet) and no video. :-)
>
> Not much, some bus off cleanups, however I've backported all changes to
> v4.19-rpi/mcp25xxfd-20200429-41 (debug and log is still included).
>
> When you port this to your mx8 take all from (including)
>
> 097701d1ea4f can: dev: avoid long lines
> to
> v4.19-rpi/mcp25xxfd-20200429-41
>
I'll merge one of your latest ...
Kurt
^ permalink raw reply
* [PATCH v5 1/3] net: phy: mscc: move shared probe code into a helper
From: Heiko Stuebner @ 2020-06-18 12:11 UTC (permalink / raw)
To: davem, kuba
Cc: robh+dt, andrew, f.fainelli, hkallweit1, linux, netdev,
devicetree, linux-kernel, heiko, christoph.muellner,
Heiko Stuebner
In-Reply-To: <20200618121139.1703762-1-heiko@sntech.de>
From: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
The different probe functions share a lot of code, so move the
common parts into a helper to reduce duplication.
This moves the devm_phy_package_join below the general allocation
but as all components just allocate things, this should be ok.
Suggested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/phy/mscc/mscc_main.c | 124 +++++++++++++++----------------
1 file changed, 61 insertions(+), 63 deletions(-)
diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c
index 5ddc44f87eaf..5d2777522fb4 100644
--- a/drivers/net/phy/mscc/mscc_main.c
+++ b/drivers/net/phy/mscc/mscc_main.c
@@ -1935,12 +1935,11 @@ static int vsc85xx_read_status(struct phy_device *phydev)
return genphy_read_status(phydev);
}
-static int vsc8514_probe(struct phy_device *phydev)
+static int vsc85xx_probe_helper(struct phy_device *phydev,
+ u32 *leds, int num_leds, u16 led_modes,
+ const struct vsc85xx_hw_stat *stats, int nstats)
{
struct vsc8531_private *vsc8531;
- u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
- VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
- VSC8531_DUPLEX_COLLISION};
vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
if (!vsc8531)
@@ -1948,54 +1947,66 @@ static int vsc8514_probe(struct phy_device *phydev)
phydev->priv = vsc8531;
- vsc8584_get_base_addr(phydev);
- devm_phy_package_join(&phydev->mdio.dev, phydev,
- vsc8531->base_addr, 0);
-
- vsc8531->nleds = 4;
- vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
- vsc8531->hw_stats = vsc85xx_hw_stats;
- vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);
+ vsc8531->nleds = num_leds;
+ vsc8531->supp_led_modes = led_modes;
+ vsc8531->hw_stats = stats;
+ vsc8531->nstats = nstats;
vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
sizeof(u64), GFP_KERNEL);
if (!vsc8531->stats)
return -ENOMEM;
- return vsc85xx_dt_led_modes_get(phydev, default_mode);
+ return vsc85xx_dt_led_modes_get(phydev, leds);
}
-static int vsc8574_probe(struct phy_device *phydev)
+static int vsc8514_probe(struct phy_device *phydev)
{
struct vsc8531_private *vsc8531;
+ int rc;
u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
VSC8531_DUPLEX_COLLISION};
- vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
- if (!vsc8531)
- return -ENOMEM;
-
- phydev->priv = vsc8531;
+ rc = vsc85xx_probe_helper(phydev, default_mode,
+ ARRAY_SIZE(default_mode),
+ VSC85XX_SUPP_LED_MODES,
+ vsc85xx_hw_stats,
+ ARRAY_SIZE(vsc85xx_hw_stats));
+ if (rc < 0)
+ return rc;
+ vsc8531 = phydev->priv;
vsc8584_get_base_addr(phydev);
- devm_phy_package_join(&phydev->mdio.dev, phydev,
- vsc8531->base_addr, 0);
+ return devm_phy_package_join(&phydev->mdio.dev, phydev,
+ vsc8531->base_addr, 0);
+}
- vsc8531->nleds = 4;
- vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
- vsc8531->hw_stats = vsc8584_hw_stats;
- vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
- vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
- sizeof(u64), GFP_KERNEL);
- if (!vsc8531->stats)
- return -ENOMEM;
+static int vsc8574_probe(struct phy_device *phydev)
+{
+ struct vsc8531_private *vsc8531;
+ int rc;
+ u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
+ VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
+ VSC8531_DUPLEX_COLLISION};
+
+ rc = vsc85xx_probe_helper(phydev, default_mode,
+ ARRAY_SIZE(default_mode),
+ VSC8584_SUPP_LED_MODES,
+ vsc8584_hw_stats,
+ ARRAY_SIZE(vsc8584_hw_stats));
+ if (rc < 0)
+ return rc;
- return vsc85xx_dt_led_modes_get(phydev, default_mode);
+ vsc8531 = phydev->priv;
+ vsc8584_get_base_addr(phydev);
+ return devm_phy_package_join(&phydev->mdio.dev, phydev,
+ vsc8531->base_addr, 0);
}
static int vsc8584_probe(struct phy_device *phydev)
{
struct vsc8531_private *vsc8531;
+ int rc;
u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
VSC8531_DUPLEX_COLLISION};
@@ -2005,32 +2016,24 @@ static int vsc8584_probe(struct phy_device *phydev)
return -ENOTSUPP;
}
- vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
- if (!vsc8531)
- return -ENOMEM;
-
- phydev->priv = vsc8531;
+ rc = vsc85xx_probe_helper(phydev, default_mode,
+ ARRAY_SIZE(default_mode),
+ VSC8584_SUPP_LED_MODES,
+ vsc8584_hw_stats,
+ ARRAY_SIZE(vsc8584_hw_stats));
+ if (rc < 0)
+ return rc;
+ vsc8531 = phydev->priv;
vsc8584_get_base_addr(phydev);
- devm_phy_package_join(&phydev->mdio.dev, phydev,
- vsc8531->base_addr, 0);
-
- vsc8531->nleds = 4;
- vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
- vsc8531->hw_stats = vsc8584_hw_stats;
- vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
- vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
- sizeof(u64), GFP_KERNEL);
- if (!vsc8531->stats)
- return -ENOMEM;
-
- return vsc85xx_dt_led_modes_get(phydev, default_mode);
+ return devm_phy_package_join(&phydev->mdio.dev, phydev,
+ vsc8531->base_addr, 0);
}
static int vsc85xx_probe(struct phy_device *phydev)
{
struct vsc8531_private *vsc8531;
- int rate_magic;
+ int rate_magic, rc;
u32 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY,
VSC8531_LINK_100_ACTIVITY};
@@ -2038,23 +2041,18 @@ static int vsc85xx_probe(struct phy_device *phydev)
if (rate_magic < 0)
return rate_magic;
- vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
- if (!vsc8531)
- return -ENOMEM;
-
- phydev->priv = vsc8531;
+ rc = vsc85xx_probe_helper(phydev, default_mode,
+ ARRAY_SIZE(default_mode),
+ VSC85XX_SUPP_LED_MODES,
+ vsc85xx_hw_stats,
+ ARRAY_SIZE(vsc85xx_hw_stats));
+ if (rc < 0)
+ return rc;
+ vsc8531 = phydev->priv;
vsc8531->rate_magic = rate_magic;
- vsc8531->nleds = 2;
- vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
- vsc8531->hw_stats = vsc85xx_hw_stats;
- vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);
- vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
- sizeof(u64), GFP_KERNEL);
- if (!vsc8531->stats)
- return -ENOMEM;
- return vsc85xx_dt_led_modes_get(phydev, default_mode);
+ return 0;
}
/* Microsemi VSC85xx PHYs */
--
2.26.2
^ permalink raw reply related
* [PATCH v5 2/3] dt-bindings: net: mscc-vsc8531: add optional clock properties
From: Heiko Stuebner @ 2020-06-18 12:11 UTC (permalink / raw)
To: davem, kuba
Cc: robh+dt, andrew, f.fainelli, hkallweit1, linux, netdev,
devicetree, linux-kernel, heiko, christoph.muellner,
Heiko Stuebner
In-Reply-To: <20200618121139.1703762-1-heiko@sntech.de>
From: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
Some mscc ethernet phys have a configurable clock output, so describe the
generic properties to access them in devicetrees.
Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
---
Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
index 5ff37c68c941..67625ba27f53 100644
--- a/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
+++ b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
@@ -1,6 +1,8 @@
* Microsemi - vsc8531 Giga bit ethernet phy
Optional properties:
+- clock-output-names : Name for the exposed clock output
+- #clock-cells : should be 0
- vsc8531,vddmac : The vddmac in mV. Allowed values is listed
in the first row of Table 1 (below).
This property is only used in combination
--
2.26.2
^ permalink raw reply related
* [PATCH v5 3/3] net: phy: mscc: handle the clkout control on some phy variants
From: Heiko Stuebner @ 2020-06-18 12:11 UTC (permalink / raw)
To: davem, kuba
Cc: robh+dt, andrew, f.fainelli, hkallweit1, linux, netdev,
devicetree, linux-kernel, heiko, christoph.muellner,
Heiko Stuebner
In-Reply-To: <20200618121139.1703762-1-heiko@sntech.de>
From: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
At least VSC8530/8531/8540/8541 contain a clock output that can emit
a predefined rate of 25, 50 or 125MHz.
This may then feed back into the network interface as source clock.
So expose a clock-provider from the phy using the common clock framework
to allow setting the rate.
Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
---
drivers/net/phy/mscc/mscc.h | 13 +++
drivers/net/phy/mscc/mscc_main.c | 182 +++++++++++++++++++++++++++++--
2 files changed, 187 insertions(+), 8 deletions(-)
diff --git a/drivers/net/phy/mscc/mscc.h b/drivers/net/phy/mscc/mscc.h
index fbcee5fce7b2..94883dab5cc1 100644
--- a/drivers/net/phy/mscc/mscc.h
+++ b/drivers/net/phy/mscc/mscc.h
@@ -218,6 +218,13 @@ enum rgmii_clock_delay {
#define INT_MEM_DATA_M 0x00ff
#define INT_MEM_DATA(x) (INT_MEM_DATA_M & (x))
+#define MSCC_CLKOUT_CNTL 13
+#define CLKOUT_ENABLE BIT(15)
+#define CLKOUT_FREQ_MASK GENMASK(14, 13)
+#define CLKOUT_FREQ_25M (0x0 << 13)
+#define CLKOUT_FREQ_50M (0x1 << 13)
+#define CLKOUT_FREQ_125M (0x2 << 13)
+
#define MSCC_PHY_PROC_CMD 18
#define PROC_CMD_NCOMPLETED 0x8000
#define PROC_CMD_FAILED 0x4000
@@ -360,6 +367,12 @@ struct vsc8531_private {
*/
unsigned int base_addr;
+#ifdef CONFIG_COMMON_CLK
+ struct clk_hw clkout_hw;
+#endif
+ u32 clkout_rate;
+ int clkout_enabled;
+
#if IS_ENABLED(CONFIG_MACSEC)
/* MACsec fields:
* - One SecY per device (enforced at the s/w implementation level)
diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c
index 5d2777522fb4..727a9dd58403 100644
--- a/drivers/net/phy/mscc/mscc_main.c
+++ b/drivers/net/phy/mscc/mscc_main.c
@@ -7,6 +7,7 @@
* Copyright (c) 2016 Microsemi Corporation
*/
+#include <linux/clk-provider.h>
#include <linux/firmware.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
@@ -431,7 +432,6 @@ static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
return led_mode;
}
-
#else
static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
{
@@ -1508,6 +1508,43 @@ static int vsc85xx_config_init(struct phy_device *phydev)
return 0;
}
+static int vsc8531_config_init(struct phy_device *phydev)
+{
+ struct vsc8531_private *vsc8531 = phydev->priv;
+ u16 val;
+ int rc;
+
+ rc = vsc85xx_config_init(phydev);
+ if (rc)
+ return rc;
+
+#ifdef CONFIG_COMMON_CLK
+ switch (vsc8531->clkout_rate) {
+ case 25000000:
+ val = CLKOUT_FREQ_25M;
+ break;
+ case 50000000:
+ val = CLKOUT_FREQ_50M;
+ break;
+ case 125000000:
+ val = CLKOUT_FREQ_125M;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (vsc8531->clkout_enabled)
+ val |= CLKOUT_ENABLE;
+
+ rc = phy_write_paged(phydev, MSCC_PHY_PAGE_EXTENDED_GPIO,
+ MSCC_CLKOUT_CNTL, val);
+ if (rc)
+ return rc;
+#endif
+
+ return 0;
+}
+
static int vsc8584_did_interrupt(struct phy_device *phydev)
{
int rc = 0;
@@ -1935,6 +1972,107 @@ static int vsc85xx_read_status(struct phy_device *phydev)
return genphy_read_status(phydev);
}
+#ifdef CONFIG_COMMON_CLK
+#define clkout_hw_to_vsc8531(_hw) container_of(_hw, struct vsc8531_private, clkout_hw)
+
+static int clkout_rates[] = {
+ 125000000,
+ 50000000,
+ 25000000,
+};
+
+static unsigned long vsc8531_clkout_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct vsc8531_private *vsc8531 = clkout_hw_to_vsc8531(hw);
+
+ return vsc8531->clkout_rate;
+}
+
+static long vsc8531_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
+ if (clkout_rates[i] <= rate)
+ return clkout_rates[i];
+ return 0;
+}
+
+static int vsc8531_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct vsc8531_private *vsc8531 = clkout_hw_to_vsc8531(hw);
+
+ vsc8531->clkout_rate = rate;
+ return 0;
+}
+
+static int vsc8531_clkout_prepare(struct clk_hw *hw)
+{
+ struct vsc8531_private *vsc8531 = clkout_hw_to_vsc8531(hw);
+
+ vsc8531->clkout_enabled = true;
+ return 0;
+}
+
+static void vsc8531_clkout_unprepare(struct clk_hw *hw)
+{
+ struct vsc8531_private *vsc8531 = clkout_hw_to_vsc8531(hw);
+
+ vsc8531->clkout_enabled = false;
+}
+
+static int vsc8531_clkout_is_prepared(struct clk_hw *hw)
+{
+ struct vsc8531_private *vsc8531 = clkout_hw_to_vsc8531(hw);
+
+ return vsc8531->clkout_enabled;
+}
+
+static const struct clk_ops vsc8531_clkout_ops = {
+ .prepare = vsc8531_clkout_prepare,
+ .unprepare = vsc8531_clkout_unprepare,
+ .is_prepared = vsc8531_clkout_is_prepared,
+ .recalc_rate = vsc8531_clkout_recalc_rate,
+ .round_rate = vsc8531_clkout_round_rate,
+ .set_rate = vsc8531_clkout_set_rate,
+};
+
+static int vsc8531_register_clkout(struct phy_device *phydev)
+{
+ struct vsc8531_private *vsc8531 = phydev->priv;
+ struct device *dev = &phydev->mdio.dev;
+ struct device_node *of_node = dev->of_node;
+ struct clk_init_data init;
+ int ret;
+
+ init.name = "vsc8531-clkout";
+ init.ops = &vsc8531_clkout_ops;
+ init.flags = 0;
+ init.parent_names = NULL;
+ init.num_parents = 0;
+ vsc8531->clkout_hw.init = &init;
+
+ /* optional override of the clockname */
+ of_property_read_string(of_node, "clock-output-names", &init.name);
+
+ /* register the clock */
+ ret = devm_clk_hw_register(dev, &vsc8531->clkout_hw);
+ if (!ret)
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ &vsc8531->clkout_hw);
+
+ return ret;
+}
+#else
+static int vsc8531_register_clkout(struct phy_device *phydev)
+{
+ return 0;
+}
+#endif
+
static int vsc85xx_probe_helper(struct phy_device *phydev,
u32 *leds, int num_leds, u16 led_modes,
const struct vsc85xx_hw_stat *stats, int nstats)
@@ -1981,6 +2119,34 @@ static int vsc8514_probe(struct phy_device *phydev)
vsc8531->base_addr, 0);
}
+static int vsc8531_probe(struct phy_device *phydev)
+{
+ struct vsc8531_private *vsc8531;
+ int rate_magic, rc;
+ u32 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY,
+ VSC8531_LINK_100_ACTIVITY};
+
+ rate_magic = vsc85xx_edge_rate_magic_get(phydev);
+ if (rate_magic < 0)
+ return rate_magic;
+
+ rc = vsc85xx_probe_helper(phydev, default_mode,
+ ARRAY_SIZE(default_mode),
+ VSC85XX_SUPP_LED_MODES,
+ vsc85xx_hw_stats,
+ ARRAY_SIZE(vsc85xx_hw_stats));
+ if (rc < 0)
+ return rc;
+
+ vsc8531 = phydev->priv;
+ vsc8531->rate_magic = rate_magic;
+ rc = vsc8531_register_clkout(phydev);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
static int vsc8574_probe(struct phy_device *phydev)
{
struct vsc8531_private *vsc8531;
@@ -2136,14 +2302,14 @@ static struct phy_driver vsc85xx_driver[] = {
.phy_id_mask = 0xfffffff0,
/* PHY_BASIC_FEATURES */
.soft_reset = &genphy_soft_reset,
- .config_init = &vsc85xx_config_init,
+ .config_init = &vsc8531_config_init,
.config_aneg = &vsc85xx_config_aneg,
.read_status = &vsc85xx_read_status,
.ack_interrupt = &vsc85xx_ack_interrupt,
.config_intr = &vsc85xx_config_intr,
.suspend = &genphy_suspend,
.resume = &genphy_resume,
- .probe = &vsc85xx_probe,
+ .probe = &vsc8531_probe,
.set_wol = &vsc85xx_wol_set,
.get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
@@ -2160,14 +2326,14 @@ static struct phy_driver vsc85xx_driver[] = {
.phy_id_mask = 0xfffffff0,
/* PHY_GBIT_FEATURES */
.soft_reset = &genphy_soft_reset,
- .config_init = &vsc85xx_config_init,
+ .config_init = &vsc8531_config_init,
.config_aneg = &vsc85xx_config_aneg,
.read_status = &vsc85xx_read_status,
.ack_interrupt = &vsc85xx_ack_interrupt,
.config_intr = &vsc85xx_config_intr,
.suspend = &genphy_suspend,
.resume = &genphy_resume,
- .probe = &vsc85xx_probe,
+ .probe = &vsc8531_probe,
.set_wol = &vsc85xx_wol_set,
.get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
@@ -2184,14 +2350,14 @@ static struct phy_driver vsc85xx_driver[] = {
.phy_id_mask = 0xfffffff0,
/* PHY_BASIC_FEATURES */
.soft_reset = &genphy_soft_reset,
- .config_init = &vsc85xx_config_init,
+ .config_init = &vsc8531_config_init,
.config_aneg = &vsc85xx_config_aneg,
.read_status = &vsc85xx_read_status,
.ack_interrupt = &vsc85xx_ack_interrupt,
.config_intr = &vsc85xx_config_intr,
.suspend = &genphy_suspend,
.resume = &genphy_resume,
- .probe = &vsc85xx_probe,
+ .probe = &vsc8531_probe,
.set_wol = &vsc85xx_wol_set,
.get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
@@ -2208,7 +2374,7 @@ static struct phy_driver vsc85xx_driver[] = {
.phy_id_mask = 0xfffffff0,
/* PHY_GBIT_FEATURES */
.soft_reset = &genphy_soft_reset,
- .config_init = &vsc85xx_config_init,
+ .config_init = &vsc8531_config_init,
.config_aneg = &vsc85xx_config_aneg,
.read_status = &vsc85xx_read_status,
.ack_interrupt = &vsc85xx_ack_interrupt,
--
2.26.2
^ permalink raw reply related
* [PATCH v5 0/3] add clkout support to mscc phys
From: Heiko Stuebner @ 2020-06-18 12:11 UTC (permalink / raw)
To: davem, kuba
Cc: robh+dt, andrew, f.fainelli, hkallweit1, linux, netdev,
devicetree, linux-kernel, heiko, christoph.muellner
The main part of this series is adding handling of the clkout
controls some of the mscc phys have and while at it Andrew
asked for some of the duplicated probe functionality to be
factored out into a common function.
A working config on rockchip/rk3368-lion for example now looks like:
&gmac {
status = "okay";
mdio {
compatible = "snps,dwmac-mdio";
#address-cells = <1>;
#size-cells = <0>;
phy0: phy@0 {
compatible = "ethernet-phy-id0007.0570";
reg = <0>;
assigned-clocks = <&phy0>, <&cru SCLK_MAC>;
assigned-clock-rates = <125000000>, <125000000>;
assigned-clock-parents = <0>, <&phy0>;
clock-output-names = "ext_gmac";
#clock-cells = <0>;
vsc8531,edge-slowdown = <7>;
vsc8531,led-0-mode = <1>;
vsc8531,led-1-mode = <2>;
};
};
};
changes in v5:
- added Andrew's Rb for patch 1
- modified clkout handling to be a clock-provider
to fit into the existing clock structures
changes in v4:
- fix missing variable initialization in one probe function
changes in v3:
- adapt to 5.8 merge-window results
- introduce a more generic enet-phy-property instead of
using a vsc8531,* one - suggested by Andrew
changes in v2:
- new probe factoring patch as suggested by Andrew
Heiko Stuebner (3):
net: phy: mscc: move shared probe code into a helper
dt-bindings: net: mscc-vsc8531: add optional clock properties
net: phy: mscc: handle the clkout control on some phy variants
.../bindings/net/mscc-phy-vsc8531.txt | 2 +
drivers/net/phy/mscc/mscc.h | 13 +
drivers/net/phy/mscc/mscc_main.c | 306 ++++++++++++++----
3 files changed, 250 insertions(+), 71 deletions(-)
--
2.26.2
^ permalink raw reply
* [PATCH net-next 5/5] net: dsa: felix: use the Lynx PCS helpers
From: Ioana Ciornei @ 2020-06-18 12:08 UTC (permalink / raw)
To: netdev, davem
Cc: vladimir.oltean, claudiu.manoil, alexandru.marginean, michael,
andrew, linux, f.fainelli, Ioana Ciornei
In-Reply-To: <20200618120837.27089-1-ioana.ciornei@nxp.com>
Use the helper functions introduced by the newly added
Lynx PCS MDIO module.
Instead of representing the PCS as a phy_device, a mdio_device structure
will be passed to the Lynx module which is now actually implementing all
the PCS configuration and status reporting.
All code previously used for PCS momnitoring and runtime configuration
is removed and replaced will calls to the Lynx PCS operations.
Tested on the following SERDES protocols of LS1028A: 0x7777
(2500Base-X), 0x85bb (QSGMII), 0x9999 (SGMII) and 0x13bb (USXGMII).
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/net/dsa/ocelot/Kconfig | 1 +
drivers/net/dsa/ocelot/felix.c | 5 +
drivers/net/dsa/ocelot/felix.h | 7 +-
drivers/net/dsa/ocelot/felix_vsc9959.c | 385 +++----------------------
include/linux/fsl/enetc_mdio.h | 21 --
5 files changed, 52 insertions(+), 367 deletions(-)
diff --git a/drivers/net/dsa/ocelot/Kconfig b/drivers/net/dsa/ocelot/Kconfig
index a5b7cca03d09..d6bdb511aac5 100644
--- a/drivers/net/dsa/ocelot/Kconfig
+++ b/drivers/net/dsa/ocelot/Kconfig
@@ -7,6 +7,7 @@ config NET_DSA_MSCC_FELIX
select MSCC_OCELOT_SWITCH
select NET_DSA_TAG_OCELOT
select FSL_ENETC_MDIO
+ select MDIO_LYNX_PCS
help
This driver supports the VSC9959 network switch, which is a member of
the Vitesse / Microsemi / Microchip Ocelot family of switching cores.
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 66648986e6e3..7995695fae0a 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -277,6 +277,7 @@ static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
{
struct ocelot *ocelot = ds->priv;
struct ocelot_port *ocelot_port = ocelot->ports[port];
+ struct felix *felix = ocelot_to_felix(ocelot);
/* Enable MAC module */
ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA |
@@ -295,6 +296,10 @@ static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) |
QSYS_SWITCH_PORT_MODE_PORT_ENA,
QSYS_SWITCH_PORT_MODE, port);
+
+ if (felix->info->pcs_link_up)
+ felix->info->pcs_link_up(ocelot, port, link_an_mode, interface,
+ speed, duplex);
}
static void felix_port_qos_map_init(struct ocelot *ocelot, int port)
diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h
index a891736ca006..81d93bfee23b 100644
--- a/drivers/net/dsa/ocelot/felix.h
+++ b/drivers/net/dsa/ocelot/felix.h
@@ -4,6 +4,8 @@
#ifndef _MSCC_FELIX_H
#define _MSCC_FELIX_H
+#include <linux/mdio-lynx-pcs.h>
+
#define ocelot_to_felix(o) container_of((o), struct felix, ocelot)
#define FELIX_NUM_TC 8
@@ -34,6 +36,9 @@ struct felix_info {
void (*pcs_an_restart)(struct ocelot *ocelot, int port);
void (*pcs_link_state)(struct ocelot *ocelot, int port,
struct phylink_link_state *state);
+ void (*pcs_link_up)(struct ocelot *ocelot, int port,
+ unsigned int mode, phy_interface_t interface,
+ int speed, int duplex);
int (*prevalidate_phy_mode)(struct ocelot *ocelot, int port,
phy_interface_t phy_mode);
int (*port_setup_tc)(struct dsa_switch *ds, int port,
@@ -55,7 +60,7 @@ struct felix {
struct felix_info *info;
struct ocelot ocelot;
struct mii_bus *imdio;
- struct phy_device **pcs;
+ struct mdio_lynx_pcs **pcs;
};
#endif
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index 1dd9e348152d..6f18fd4ea44a 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -17,19 +17,6 @@
#define VSC9959_VCAP_IS2_ENTRY_WIDTH 376
#define VSC9959_VCAP_PORT_CNT 6
-/* TODO: should find a better place for these */
-#define USXGMII_BMCR_RESET BIT(15)
-#define USXGMII_BMCR_AN_EN BIT(12)
-#define USXGMII_BMCR_RST_AN BIT(9)
-#define USXGMII_BMSR_LNKS(status) (((status) & GENMASK(2, 2)) >> 2)
-#define USXGMII_BMSR_AN_CMPL(status) (((status) & GENMASK(5, 5)) >> 5)
-#define USXGMII_ADVERTISE_LNKS(x) (((x) << 15) & BIT(15))
-#define USXGMII_ADVERTISE_FDX BIT(12)
-#define USXGMII_ADVERTISE_SPEED(x) (((x) << 9) & GENMASK(11, 9))
-#define USXGMII_LPA_LNKS(lpa) ((lpa) >> 15)
-#define USXGMII_LPA_DUPLEX(lpa) (((lpa) & GENMASK(12, 12)) >> 12)
-#define USXGMII_LPA_SPEED(lpa) (((lpa) & GENMASK(11, 9)) >> 9)
-
#define VSC9959_TAS_GCL_ENTRY_MAX 63
enum usxgmii_speed {
@@ -728,181 +715,15 @@ static int vsc9959_reset(struct ocelot *ocelot)
return 0;
}
-static void vsc9959_pcs_an_restart_sgmii(struct phy_device *pcs)
-{
- phy_set_bits(pcs, MII_BMCR, BMCR_ANRESTART);
-}
-
-static void vsc9959_pcs_an_restart_usxgmii(struct phy_device *pcs)
-{
- phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_BMCR,
- USXGMII_BMCR_RESET |
- USXGMII_BMCR_AN_EN |
- USXGMII_BMCR_RST_AN);
-}
-
static void vsc9959_pcs_an_restart(struct ocelot *ocelot, int port)
{
struct felix *felix = ocelot_to_felix(ocelot);
- struct phy_device *pcs = felix->pcs[port];
+ struct mdio_lynx_pcs *pcs = felix->pcs[port];
if (!pcs)
return;
- switch (pcs->interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_QSGMII:
- vsc9959_pcs_an_restart_sgmii(pcs);
- break;
- case PHY_INTERFACE_MODE_USXGMII:
- vsc9959_pcs_an_restart_usxgmii(pcs);
- break;
- default:
- dev_err(ocelot->dev, "Invalid PCS interface type %s\n",
- phy_modes(pcs->interface));
- break;
- }
-}
-
-/* We enable SGMII AN only when the PHY has managed = "in-band-status" in the
- * device tree. If we are in MLO_AN_PHY mode, we program directly state->speed
- * into the PCS, which is retrieved out-of-band over MDIO. This also has the
- * benefit of working with SGMII fixed-links, like downstream switches, where
- * both link partners attempt to operate as AN slaves and therefore AN never
- * completes. But it also has the disadvantage that some PHY chips don't pass
- * traffic if SGMII AN is enabled but not completed (acknowledged by us), so
- * setting MLO_AN_INBAND is actually required for those.
- */
-static void vsc9959_pcs_init_sgmii(struct phy_device *pcs,
- unsigned int link_an_mode,
- const struct phylink_link_state *state)
-{
- if (link_an_mode == MLO_AN_INBAND) {
- int bmsr, bmcr;
-
- /* Some PHYs like VSC8234 don't like it when AN restarts on
- * their system side and they restart line side AN too, going
- * into an endless link up/down loop. Don't restart PCS AN if
- * link is up already.
- * We do check that AN is enabled just in case this is the 1st
- * call, PCS detects a carrier but AN is disabled from power on
- * or by boot loader.
- */
- bmcr = phy_read(pcs, MII_BMCR);
- if (bmcr < 0)
- return;
-
- bmsr = phy_read(pcs, MII_BMSR);
- if (bmsr < 0)
- return;
-
- if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_LSTATUS))
- return;
-
- /* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001
- * for the MAC PCS in order to acknowledge the AN.
- */
- phy_write(pcs, MII_ADVERTISE, ADVERTISE_SGMII |
- ADVERTISE_LPACK);
-
- phy_write(pcs, ENETC_PCS_IF_MODE,
- ENETC_PCS_IF_MODE_SGMII_EN |
- ENETC_PCS_IF_MODE_USE_SGMII_AN);
-
- /* Adjust link timer for SGMII */
- phy_write(pcs, ENETC_PCS_LINK_TIMER1,
- ENETC_PCS_LINK_TIMER1_VAL);
- phy_write(pcs, ENETC_PCS_LINK_TIMER2,
- ENETC_PCS_LINK_TIMER2_VAL);
-
- phy_write(pcs, MII_BMCR, BMCR_ANRESTART | BMCR_ANENABLE);
- } else {
- int speed;
-
- if (state->duplex == DUPLEX_HALF) {
- phydev_err(pcs, "Half duplex not supported\n");
- return;
- }
- switch (state->speed) {
- case SPEED_1000:
- speed = ENETC_PCS_SPEED_1000;
- break;
- case SPEED_100:
- speed = ENETC_PCS_SPEED_100;
- break;
- case SPEED_10:
- speed = ENETC_PCS_SPEED_10;
- break;
- case SPEED_UNKNOWN:
- /* Silently don't do anything */
- return;
- default:
- phydev_err(pcs, "Invalid PCS speed %d\n", state->speed);
- return;
- }
-
- phy_write(pcs, ENETC_PCS_IF_MODE,
- ENETC_PCS_IF_MODE_SGMII_EN |
- ENETC_PCS_IF_MODE_SGMII_SPEED(speed));
-
- /* Yes, not a mistake: speed is given by IF_MODE. */
- phy_write(pcs, MII_BMCR, BMCR_RESET |
- BMCR_SPEED1000 |
- BMCR_FULLDPLX);
- }
-}
-
-/* 2500Base-X is SerDes protocol 7 on Felix and 6 on ENETC. It is a SerDes lane
- * clocked at 3.125 GHz which encodes symbols with 8b/10b and does not have
- * auto-negotiation of any link parameters. Electrically it is compatible with
- * a single lane of XAUI.
- * The hardware reference manual wants to call this mode SGMII, but it isn't
- * really, since the fundamental features of SGMII:
- * - Downgrading the link speed by duplicating symbols
- * - Auto-negotiation
- * are not there.
- * The speed is configured at 1000 in the IF_MODE and BMCR MDIO registers
- * because the clock frequency is actually given by a PLL configured in the
- * Reset Configuration Word (RCW).
- * Since there is no difference between fixed speed SGMII w/o AN and 802.3z w/o
- * AN, we call this PHY interface type 2500Base-X. In case a PHY negotiates a
- * lower link speed on line side, the system-side interface remains fixed at
- * 2500 Mbps and we do rate adaptation through pause frames.
- */
-static void vsc9959_pcs_init_2500basex(struct phy_device *pcs,
- unsigned int link_an_mode,
- const struct phylink_link_state *state)
-{
- if (link_an_mode == MLO_AN_INBAND) {
- phydev_err(pcs, "AN not supported on 3.125GHz SerDes lane\n");
- return;
- }
-
- phy_write(pcs, ENETC_PCS_IF_MODE,
- ENETC_PCS_IF_MODE_SGMII_EN |
- ENETC_PCS_IF_MODE_SGMII_SPEED(ENETC_PCS_SPEED_2500));
-
- phy_write(pcs, MII_BMCR, BMCR_SPEED1000 |
- BMCR_FULLDPLX |
- BMCR_RESET);
-}
-
-static void vsc9959_pcs_init_usxgmii(struct phy_device *pcs,
- unsigned int link_an_mode,
- const struct phylink_link_state *state)
-{
- if (link_an_mode != MLO_AN_INBAND) {
- phydev_err(pcs, "USXGMII only supports in-band AN for now\n");
- return;
- }
-
- /* Configure device ability for the USXGMII Replicator */
- phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_ADVERTISE,
- USXGMII_ADVERTISE_SPEED(USXGMII_SPEED_2500) |
- USXGMII_ADVERTISE_LNKS(1) |
- ADVERTISE_SGMII |
- ADVERTISE_LPACK |
- USXGMII_ADVERTISE_FDX);
+ pcs->an_restart(pcs, ocelot->ports[port]->phy_mode);
}
static void vsc9959_pcs_init(struct ocelot *ocelot, int port,
@@ -910,178 +731,37 @@ static void vsc9959_pcs_init(struct ocelot *ocelot, int port,
const struct phylink_link_state *state)
{
struct felix *felix = ocelot_to_felix(ocelot);
- struct phy_device *pcs = felix->pcs[port];
+ struct mdio_lynx_pcs *pcs = felix->pcs[port];
if (!pcs)
return;
- /* The PCS does not implement the BMSR register fully, so capability
- * detection via genphy_read_abilities does not work. Since we can get
- * the PHY config word from the LPA register though, there is still
- * value in using the generic phy_resolve_aneg_linkmode function. So
- * populate the supported and advertising link modes manually here.
- */
- linkmode_set_bit_array(phy_basic_ports_array,
- ARRAY_SIZE(phy_basic_ports_array),
- pcs->supported);
- linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, pcs->supported);
- linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pcs->supported);
- linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, pcs->supported);
- if (pcs->interface == PHY_INTERFACE_MODE_2500BASEX ||
- pcs->interface == PHY_INTERFACE_MODE_USXGMII)
- linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
- pcs->supported);
- if (pcs->interface != PHY_INTERFACE_MODE_2500BASEX)
- linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
- pcs->supported);
- phy_advertise_supported(pcs);
-
- switch (pcs->interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_QSGMII:
- vsc9959_pcs_init_sgmii(pcs, link_an_mode, state);
- break;
- case PHY_INTERFACE_MODE_2500BASEX:
- vsc9959_pcs_init_2500basex(pcs, link_an_mode, state);
- break;
- case PHY_INTERFACE_MODE_USXGMII:
- vsc9959_pcs_init_usxgmii(pcs, link_an_mode, state);
- break;
- default:
- dev_err(ocelot->dev, "Unsupported link mode %s\n",
- phy_modes(pcs->interface));
- }
-}
-
-static void vsc9959_pcs_link_state_resolve(struct phy_device *pcs,
- struct phylink_link_state *state)
-{
- state->an_complete = pcs->autoneg_complete;
- state->an_enabled = pcs->autoneg;
- state->link = pcs->link;
- state->duplex = pcs->duplex;
- state->speed = pcs->speed;
- /* SGMII AN does not negotiate flow control, but that's ok,
- * since phylink already knows that, and does:
- * link_state.pause |= pl->phy_state.pause;
- */
- state->pause = MLO_PAUSE_NONE;
-
- phydev_dbg(pcs,
- "mode=%s/%s/%s adv=%*pb lpa=%*pb link=%u an_enabled=%u an_complete=%u\n",
- phy_modes(pcs->interface),
- phy_speed_to_str(pcs->speed),
- phy_duplex_to_str(pcs->duplex),
- __ETHTOOL_LINK_MODE_MASK_NBITS, pcs->advertising,
- __ETHTOOL_LINK_MODE_MASK_NBITS, pcs->lp_advertising,
- pcs->link, pcs->autoneg, pcs->autoneg_complete);
+ pcs->config(pcs, link_an_mode, state->interface, state->advertising);
}
-static void vsc9959_pcs_link_state_sgmii(struct phy_device *pcs,
- struct phylink_link_state *state)
-{
- int err;
-
- err = genphy_update_link(pcs);
- if (err < 0)
- return;
-
- if (pcs->autoneg_complete) {
- u16 lpa = phy_read(pcs, MII_LPA);
-
- mii_lpa_to_linkmode_lpa_sgmii(pcs->lp_advertising, lpa);
-
- phy_resolve_aneg_linkmode(pcs);
- }
-}
-
-static void vsc9959_pcs_link_state_2500basex(struct phy_device *pcs,
- struct phylink_link_state *state)
+static void vsc9959_pcs_link_state(struct ocelot *ocelot, int port,
+ struct phylink_link_state *state)
{
- int err;
+ struct felix *felix = ocelot_to_felix(ocelot);
+ struct mdio_lynx_pcs *pcs = felix->pcs[port];
- err = genphy_update_link(pcs);
- if (err < 0)
+ if (!pcs)
return;
- pcs->speed = SPEED_2500;
- pcs->asym_pause = true;
- pcs->pause = true;
+ pcs->get_state(pcs, ocelot->ports[port]->phy_mode, state);
}
-static void vsc9959_pcs_link_state_usxgmii(struct phy_device *pcs,
- struct phylink_link_state *state)
-{
- int status, lpa;
-
- status = phy_read_mmd(pcs, MDIO_MMD_VEND2, MII_BMSR);
- if (status < 0)
- return;
-
- pcs->autoneg = true;
- pcs->autoneg_complete = USXGMII_BMSR_AN_CMPL(status);
- pcs->link = USXGMII_BMSR_LNKS(status);
-
- if (!pcs->link || !pcs->autoneg_complete)
- return;
-
- lpa = phy_read_mmd(pcs, MDIO_MMD_VEND2, MII_LPA);
- if (lpa < 0)
- return;
-
- switch (USXGMII_LPA_SPEED(lpa)) {
- case USXGMII_SPEED_10:
- pcs->speed = SPEED_10;
- break;
- case USXGMII_SPEED_100:
- pcs->speed = SPEED_100;
- break;
- case USXGMII_SPEED_1000:
- pcs->speed = SPEED_1000;
- break;
- case USXGMII_SPEED_2500:
- pcs->speed = SPEED_2500;
- break;
- default:
- break;
- }
-
- if (USXGMII_LPA_DUPLEX(lpa))
- pcs->duplex = DUPLEX_FULL;
- else
- pcs->duplex = DUPLEX_HALF;
-}
-
-static void vsc9959_pcs_link_state(struct ocelot *ocelot, int port,
- struct phylink_link_state *state)
+static void vsc9959_pcs_link_up(struct ocelot *ocelot, int port,
+ unsigned int mode, phy_interface_t interface,
+ int speed, int duplex)
{
struct felix *felix = ocelot_to_felix(ocelot);
- struct phy_device *pcs = felix->pcs[port];
+ struct mdio_lynx_pcs *pcs = felix->pcs[port];
if (!pcs)
return;
- pcs->speed = SPEED_UNKNOWN;
- pcs->duplex = DUPLEX_UNKNOWN;
- pcs->pause = 0;
- pcs->asym_pause = 0;
-
- switch (pcs->interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_QSGMII:
- vsc9959_pcs_link_state_sgmii(pcs, state);
- break;
- case PHY_INTERFACE_MODE_2500BASEX:
- vsc9959_pcs_link_state_2500basex(pcs, state);
- break;
- case PHY_INTERFACE_MODE_USXGMII:
- vsc9959_pcs_link_state_usxgmii(pcs, state);
- break;
- default:
- return;
- }
-
- vsc9959_pcs_link_state_resolve(pcs, state);
+ pcs->link_up(pcs, mode, interface, speed, duplex);
}
static int vsc9959_prevalidate_phy_mode(struct ocelot *ocelot, int port,
@@ -1130,6 +810,14 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
return -ENOMEM;
}
+ felix->pcs = devm_kcalloc(dev, felix->info->num_ports,
+ sizeof(struct mdio_lynx_pcs *),
+ GFP_KERNEL);
+ if (!felix->pcs) {
+ dev_err(dev, "failed to allocate array for Lynx PCS devices\n");
+ return -ENOMEM;
+ }
+
imdio_base = pci_resource_start(felix->pdev,
felix->info->imdio_pci_bar);
@@ -1177,18 +865,23 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
for (port = 0; port < felix->info->num_ports; port++) {
struct ocelot_port *ocelot_port = ocelot->ports[port];
- struct phy_device *pcs;
- bool is_c45 = false;
+ struct mdio_device *pcs_mdio;
- if (ocelot_port->phy_mode == PHY_INTERFACE_MODE_USXGMII)
- is_c45 = true;
+ if (dsa_is_unused_port(felix->ds, port))
+ continue;
+
+ if (ocelot_port->phy_mode == PHY_INTERFACE_MODE_INTERNAL)
+ continue;
- pcs = get_phy_device(felix->imdio, port, is_c45);
- if (IS_ERR(pcs))
+ pcs_mdio = mdio_device_create(felix->imdio, port);
+ if (IS_ERR(pcs_mdio))
continue;
- pcs->interface = ocelot_port->phy_mode;
- felix->pcs[port] = pcs;
+ felix->pcs[port] = mdio_lynx_pcs_create(pcs_mdio);
+ if (!felix->pcs[port]) {
+ mdio_device_free(pcs_mdio);
+ continue;
+ }
dev_info(dev, "Found PCS at internal MDIO address %d\n", port);
}
@@ -1202,12 +895,13 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
int port;
for (port = 0; port < ocelot->num_phys_ports; port++) {
- struct phy_device *pcs = felix->pcs[port];
+ struct mdio_lynx_pcs *pcs = felix->pcs[port];
if (!pcs)
continue;
- put_device(&pcs->mdio.dev);
+ mdio_device_free(pcs->dev);
+ mdio_lynx_pcs_free(pcs);
}
mdiobus_unregister(felix->imdio);
}
@@ -1415,6 +1109,7 @@ struct felix_info felix_info_vsc9959 = {
.pcs_init = vsc9959_pcs_init,
.pcs_an_restart = vsc9959_pcs_an_restart,
.pcs_link_state = vsc9959_pcs_link_state,
+ .pcs_link_up = vsc9959_pcs_link_up,
.prevalidate_phy_mode = vsc9959_prevalidate_phy_mode,
.port_setup_tc = vsc9959_port_setup_tc,
.port_sched_speed_set = vsc9959_sched_speed_set,
diff --git a/include/linux/fsl/enetc_mdio.h b/include/linux/fsl/enetc_mdio.h
index 4875dd38af7e..483679f53a91 100644
--- a/include/linux/fsl/enetc_mdio.h
+++ b/include/linux/fsl/enetc_mdio.h
@@ -6,27 +6,6 @@
#include <linux/phy.h>
-/* PCS registers */
-#define ENETC_PCS_LINK_TIMER1 0x12
-#define ENETC_PCS_LINK_TIMER1_VAL 0x06a0
-#define ENETC_PCS_LINK_TIMER2 0x13
-#define ENETC_PCS_LINK_TIMER2_VAL 0x0003
-#define ENETC_PCS_IF_MODE 0x14
-#define ENETC_PCS_IF_MODE_SGMII_EN BIT(0)
-#define ENETC_PCS_IF_MODE_USE_SGMII_AN BIT(1)
-#define ENETC_PCS_IF_MODE_SGMII_SPEED(x) (((x) << 2) & GENMASK(3, 2))
-
-/* Not a mistake, the SerDes PLL needs to be set at 3.125 GHz by Reset
- * Configuration Word (RCW, outside Linux control) for 2.5G SGMII mode. The PCS
- * still thinks it's at gigabit.
- */
-enum enetc_pcs_speed {
- ENETC_PCS_SPEED_10 = 0,
- ENETC_PCS_SPEED_100 = 1,
- ENETC_PCS_SPEED_1000 = 2,
- ENETC_PCS_SPEED_2500 = 2,
-};
-
struct enetc_hw;
struct enetc_mdio_priv {
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 3/5] net: mdiobus: add clause 45 mdiobus write accessor
From: Ioana Ciornei @ 2020-06-18 12:08 UTC (permalink / raw)
To: netdev, davem
Cc: vladimir.oltean, claudiu.manoil, alexandru.marginean, michael,
andrew, linux, f.fainelli, Ioana Ciornei
In-Reply-To: <20200618120837.27089-1-ioana.ciornei@nxp.com>
Add the locked variant of the clause 45 mdiobus write accessor -
mdiobus_c45_write().
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
include/linux/mdio.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index 36d2e0673d03..323f1d1fa271 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -357,6 +357,12 @@ static inline int mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
return mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum));
}
+static inline int mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad,
+ u16 regnum, u16 val)
+{
+ return mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum), val);
+}
+
int mdiobus_register_device(struct mdio_device *mdiodev);
int mdiobus_unregister_device(struct mdio_device *mdiodev);
bool mdiobus_is_registered_device(struct mii_bus *bus, int addr);
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 4/5] net: phy: add Lynx PCS MDIO module
From: Ioana Ciornei @ 2020-06-18 12:08 UTC (permalink / raw)
To: netdev, davem
Cc: vladimir.oltean, claudiu.manoil, alexandru.marginean, michael,
andrew, linux, f.fainelli, Ioana Ciornei
In-Reply-To: <20200618120837.27089-1-ioana.ciornei@nxp.com>
Add a Lynx PCS MDIO module which exposes the necessary operations to
drive the PCS using PHYLINK.
The majority of the code is extracted from the Felix DSA driver, which
will be also modified in a later patch, and exposed as a separate module
for code reusability purposes.
At the moment, USXGMII (only with in-band AN and speeds up to 2500),
SGMII, QSGMII and 2500Base-X (only w/o in-band AN) are supported by the
Lynx PCS MDIO module since these were also supported by Felix.
The module can only be enabled by the drivers in need and not user
selectable.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
MAINTAINERS | 7 +
drivers/net/phy/Kconfig | 6 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/mdio-lynx-pcs.c | 358 ++++++++++++++++++++++++++++++++
include/linux/mdio-lynx-pcs.h | 43 ++++
5 files changed, 415 insertions(+)
create mode 100644 drivers/net/phy/mdio-lynx-pcs.c
create mode 100644 include/linux/mdio-lynx-pcs.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 301330e02bca..febba4b0a1fd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10529,6 +10529,13 @@ F: Documentation/devicetree/bindings/net/ieee802154/mcr20a.txt
F: drivers/net/ieee802154/mcr20a.c
F: drivers/net/ieee802154/mcr20a.h
+MDIO LYNX PCS MODULE
+M: Ioana Ciornei <ioana.ciornei@nxp.com>
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/phy/mdio-lynx-pcs.c
+F: include/linux/mdio-lynx-pcs.h
+
MEASUREMENT COMPUTING CIO-DAC IIO DRIVER
M: William Breathitt Gray <vilhelm.gray@gmail.com>
L: linux-iio@vger.kernel.org
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index f25702386d83..6ea835e5d8ec 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -235,6 +235,12 @@ config MDIO_XPCS
This module provides helper functions for Synopsys DesignWare XPCS
controllers.
+config MDIO_LYNX_PCS
+ bool
+ help
+ This module provides helper functions for Lynx PCS enablement
+ representing the PCS as an MDIO device.
+
endif
endif
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index dc9e53b511d6..931d826b3a2b 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o
obj-$(CONFIG_MDIO_XGENE) += mdio-xgene.o
obj-$(CONFIG_MDIO_XPCS) += mdio-xpcs.o
+obj-$(CONFIG_MDIO_LYNX_PCS) += mdio-lynx-pcs.o
obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += mii_timestamper.o
diff --git a/drivers/net/phy/mdio-lynx-pcs.c b/drivers/net/phy/mdio-lynx-pcs.c
new file mode 100644
index 000000000000..becd01651500
--- /dev/null
+++ b/drivers/net/phy/mdio-lynx-pcs.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/* Copyright 2020 NXP
+ * Lynx PCS MDIO helpers
+ */
+
+#include <linux/mdio.h>
+#include <linux/phylink.h>
+#include <linux/mdio-lynx-pcs.h>
+
+#define SGMII_CLOCK_PERIOD_NS 8 /* PCS is clocked at 125 MHz */
+#define SGMII_LINK_TIMER_VAL(ns) ((u32)((ns) / SGMII_CLOCK_PERIOD_NS))
+
+#define SGMII_AN_LINK_TIMER_NS 1600000 /* defined by SGMII spec */
+
+#define SGMII_LINK_TIMER_LO 0x12
+#define SGMII_LINK_TIMER_HI 0x13
+#define SGMII_IF_MODE 0x14
+#define SGMII_IF_MODE_SGMII_EN BIT(0)
+#define SGMII_IF_MODE_USE_SGMII_AN BIT(1)
+#define SGMII_IF_MODE_SPEED(x) (((x) << 2) & GENMASK(3, 2))
+#define SGMII_IF_MODE_SPEED_MSK GENMASK(3, 2)
+#define SGMII_IF_MODE_DUPLEX BIT(4)
+
+#define USXGMII_ADVERTISE_LSTATUS(x) (((x) << 15) & BIT(15))
+#define USXGMII_ADVERTISE_FDX BIT(12)
+#define USXGMII_ADVERTISE_SPEED(x) (((x) << 9) & GENMASK(11, 9))
+
+#define USXGMII_LPA_LSTATUS(lpa) ((lpa) >> 15)
+#define USXGMII_LPA_DUPLEX(lpa) (((lpa) & GENMASK(12, 12)) >> 12)
+#define USXGMII_LPA_SPEED(lpa) (((lpa) & GENMASK(11, 9)) >> 9)
+
+enum usxgmii_speed {
+ USXGMII_SPEED_10 = 0,
+ USXGMII_SPEED_100 = 1,
+ USXGMII_SPEED_1000 = 2,
+ USXGMII_SPEED_2500 = 4,
+};
+
+enum sgmii_speed {
+ SGMII_SPEED_10 = 0,
+ SGMII_SPEED_100 = 1,
+ SGMII_SPEED_1000 = 2,
+ SGMII_SPEED_2500 = 2,
+};
+
+static void lynx_pcs_an_restart_usxgmii(struct mdio_device *pcs)
+{
+ mdiobus_c45_write(pcs->bus, pcs->addr,
+ MDIO_MMD_VEND2, MII_BMCR,
+ BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART);
+}
+
+static void lynx_pcs_an_restart(struct mdio_lynx_pcs *pcs, phy_interface_t ifmode)
+{
+ switch (ifmode) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
+ phylink_mii_c22_pcs_an_restart(pcs->dev);
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ lynx_pcs_an_restart_usxgmii(pcs->dev);
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ break;
+ default:
+ dev_err(&pcs->dev->dev, "Invalid PCS interface type %s\n",
+ phy_modes(ifmode));
+ break;
+ }
+}
+
+static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs,
+ struct phylink_link_state *state)
+{
+ struct mii_bus *bus = pcs->bus;
+ int addr = pcs->addr;
+ int status, lpa;
+
+ status = mdiobus_c45_read(bus, addr, MDIO_MMD_VEND2, MII_BMSR);
+ if (status < 0)
+ return;
+
+ state->link = !!(status & MDIO_STAT1_LSTATUS);
+ state->an_complete = !!(status & MDIO_AN_STAT1_COMPLETE);
+ if (!state->link || !state->an_complete)
+ return;
+
+ lpa = mdiobus_c45_read(bus, addr, MDIO_MMD_VEND2, MII_LPA);
+ if (lpa < 0)
+ return;
+
+ switch (USXGMII_LPA_SPEED(lpa)) {
+ case USXGMII_SPEED_10:
+ state->speed = SPEED_10;
+ break;
+ case USXGMII_SPEED_100:
+ state->speed = SPEED_100;
+ break;
+ case USXGMII_SPEED_1000:
+ state->speed = SPEED_1000;
+ break;
+ case USXGMII_SPEED_2500:
+ state->speed = SPEED_2500;
+ break;
+ default:
+ break;
+ }
+
+ if (USXGMII_LPA_DUPLEX(lpa))
+ state->duplex = DUPLEX_FULL;
+ else
+ state->duplex = DUPLEX_HALF;
+}
+
+static void lynx_pcs_get_state_2500basex(struct mdio_device *pcs,
+ struct phylink_link_state *state)
+{
+ struct mii_bus *bus = pcs->bus;
+ int addr = pcs->addr;
+ int bmsr, lpa;
+
+ bmsr = mdiobus_read(bus, addr, MII_BMSR);
+ lpa = mdiobus_read(bus, addr, MII_LPA);
+ if (bmsr < 0 || lpa < 0) {
+ state->link = false;
+ return;
+ }
+
+ state->link = !!(bmsr & BMSR_LSTATUS);
+ state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE);
+ if (!state->link)
+ return;
+
+ state->speed = SPEED_2500;
+ state->pause |= MLO_PAUSE_TX | MLO_PAUSE_RX;
+}
+
+static void lynx_pcs_get_state(struct mdio_lynx_pcs *pcs, phy_interface_t ifmode,
+ struct phylink_link_state *state)
+{
+ switch (ifmode) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
+ phylink_mii_c22_pcs_get_state(pcs->dev, state);
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ lynx_pcs_get_state_2500basex(pcs->dev, state);
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ lynx_pcs_get_state_usxgmii(pcs->dev, state);
+ break;
+ default:
+ break;
+ }
+
+ dev_dbg(&pcs->dev->dev,
+ "mode=%s/%s/%s link=%u an_enabled=%u an_complete=%u\n",
+ phy_modes(ifmode),
+ phy_speed_to_str(state->speed),
+ phy_duplex_to_str(state->duplex),
+ state->link, state->an_enabled, state->an_complete);
+}
+
+static int lynx_pcs_config_sgmii(struct mdio_device *pcs, unsigned int mode,
+ const unsigned long *advertising)
+{
+ struct mii_bus *bus = pcs->bus;
+ int addr = pcs->addr;
+ u16 if_mode;
+ int err;
+
+ /* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001
+ * for the MAC PCS in order to acknowledge the AN.
+ */
+ mdiobus_write(bus, addr, MII_ADVERTISE,
+ ADVERTISE_SGMII | ADVERTISE_LPACK);
+
+ if_mode = SGMII_IF_MODE_SGMII_EN;
+ if (mode == MLO_AN_INBAND) {
+ u32 link_timer;
+
+ if_mode |= SGMII_IF_MODE_USE_SGMII_AN;
+
+ /* Adjust link timer for SGMII */
+ link_timer = SGMII_LINK_TIMER_VAL(SGMII_AN_LINK_TIMER_NS);
+ mdiobus_write(bus, addr, SGMII_LINK_TIMER_LO, link_timer & 0xffff);
+ mdiobus_write(bus, addr, SGMII_LINK_TIMER_HI, link_timer >> 16);
+ }
+ mdiobus_modify(bus, addr, SGMII_IF_MODE,
+ SGMII_IF_MODE_SGMII_EN | SGMII_IF_MODE_USE_SGMII_AN,
+ if_mode);
+
+ err = phylink_mii_c22_pcs_config(pcs, mode, PHY_INTERFACE_MODE_SGMII,
+ advertising);
+ return err;
+}
+
+static int lynx_pcs_config_usxgmii(struct mdio_device *pcs, unsigned int mode,
+ const unsigned long *advertising)
+{
+ struct mii_bus *bus = pcs->bus;
+ int addr = pcs->addr;
+
+ /* Configure device ability for the USXGMII Replicator */
+ mdiobus_c45_write(bus, addr, MDIO_MMD_VEND2, MII_ADVERTISE,
+ USXGMII_ADVERTISE_SPEED(USXGMII_SPEED_2500) |
+ USXGMII_ADVERTISE_LSTATUS(1) |
+ ADVERTISE_SGMII |
+ ADVERTISE_LPACK |
+ USXGMII_ADVERTISE_FDX);
+ return 0;
+}
+
+static int lynx_pcs_config(struct mdio_lynx_pcs *pcs, unsigned int mode,
+ phy_interface_t ifmode,
+ const unsigned long *advertising)
+{
+ switch (ifmode) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
+ lynx_pcs_config_sgmii(pcs->dev, mode, advertising);
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ /* 2500Base-X only works without in-band AN,
+ * thus nothing to do here
+ */
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ lynx_pcs_config_usxgmii(pcs->dev, mode, advertising);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static void lynx_pcs_link_up_sgmii(struct mdio_device *pcs, unsigned int mode,
+ int speed, int duplex)
+{
+ struct mii_bus *bus = pcs->bus;
+ u16 if_mode = 0, sgmii_speed;
+ int addr = pcs->addr;
+
+ /* The PCS needs to be configured manually only
+ * when not operating on in-band mode
+ */
+ if (mode == MLO_AN_INBAND)
+ return;
+
+ if (duplex == DUPLEX_HALF)
+ if_mode |= SGMII_IF_MODE_DUPLEX;
+
+ switch (speed) {
+ case SPEED_1000:
+ sgmii_speed = SGMII_SPEED_1000;
+ break;
+ case SPEED_100:
+ sgmii_speed = SGMII_SPEED_100;
+ break;
+ case SPEED_10:
+ sgmii_speed = SGMII_SPEED_10;
+ break;
+ case SPEED_UNKNOWN:
+ /* Silently don't do anything */
+ return;
+ default:
+ dev_err(&pcs->dev, "Invalid PCS speed %d\n", speed);
+ return;
+ }
+ if_mode |= SGMII_IF_MODE_SPEED(sgmii_speed);
+
+ mdiobus_modify(bus, addr, SGMII_IF_MODE,
+ SGMII_IF_MODE_DUPLEX | SGMII_IF_MODE_SPEED_MSK,
+ if_mode);
+}
+
+/* 2500Base-X is SerDes protocol 7 on Felix and 6 on ENETC. It is a SerDes lane
+ * clocked at 3.125 GHz which encodes symbols with 8b/10b and does not have
+ * auto-negotiation of any link parameters. Electrically it is compatible with
+ * a single lane of XAUI.
+ * The hardware reference manual wants to call this mode SGMII, but it isn't
+ * really, since the fundamental features of SGMII:
+ * - Downgrading the link speed by duplicating symbols
+ * - Auto-negotiation
+ * are not there.
+ * The speed is configured at 1000 in the IF_MODE because the clock frequency
+ * is actually given by a PLL configured in the Reset Configuration Word (RCW).
+ * Since there is no difference between fixed speed SGMII w/o AN and 802.3z w/o
+ * AN, we call this PHY interface type 2500Base-X. In case a PHY negotiates a
+ * lower link speed on line side, the system-side interface remains fixed at
+ * 2500 Mbps and we do rate adaptation through pause frames.
+ */
+static void lynx_pcs_link_up_2500basex(struct mdio_device *pcs,
+ unsigned int mode,
+ int speed, int duplex)
+{
+ struct mii_bus *bus = pcs->bus;
+ int addr = pcs->addr;
+
+ if (mode == MLO_AN_INBAND) {
+ dev_err(&pcs->dev, "AN not supported for 2500BaseX\n");
+ return;
+ }
+
+ mdiobus_write(bus, addr, SGMII_IF_MODE,
+ SGMII_IF_MODE_SGMII_EN |
+ SGMII_IF_MODE_SPEED(SGMII_SPEED_2500));
+}
+
+static void lynx_pcs_link_up(struct mdio_lynx_pcs *pcs, unsigned int mode,
+ phy_interface_t interface,
+ int speed, int duplex)
+{
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
+ lynx_pcs_link_up_sgmii(pcs->dev, mode, speed, duplex);
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ lynx_pcs_link_up_2500basex(pcs->dev, mode, speed, duplex);
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ /* At the moment, only in-band AN is supported for USXGMII
+ * so nothing to do in link_up
+ */
+ break;
+ default:
+ break;
+ }
+}
+
+struct mdio_lynx_pcs *mdio_lynx_pcs_create(struct mdio_device *mdio_dev)
+{
+ struct mdio_lynx_pcs *pcs;
+
+ if (WARN_ON(!mdio_dev))
+ return NULL;
+
+ pcs = kzalloc(sizeof(*pcs), GFP_KERNEL);
+ if (!pcs)
+ return NULL;
+
+ pcs->dev = mdio_dev;
+ pcs->an_restart = lynx_pcs_an_restart;
+ pcs->get_state = lynx_pcs_get_state;
+ pcs->link_up = lynx_pcs_link_up;
+ pcs->config = lynx_pcs_config;
+
+ return pcs;
+}
+EXPORT_SYMBOL(mdio_lynx_pcs_create);
+
+void mdio_lynx_pcs_free(struct mdio_lynx_pcs *pcs)
+{
+ kfree(pcs);
+}
+EXPORT_SYMBOL(mdio_lynx_pcs_free);
diff --git a/include/linux/mdio-lynx-pcs.h b/include/linux/mdio-lynx-pcs.h
new file mode 100644
index 000000000000..480ae2e2ecd8
--- /dev/null
+++ b/include/linux/mdio-lynx-pcs.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/* Copyright 2020 NXP
+ * Lynx PCS MDIO helpers
+ */
+
+#ifndef __LINUX_MDIO_LYNX_PCS_H
+#define __LINUX_MDIO_LYNX_PCS_H
+
+#include <linux/phy.h>
+#include <linux/mdio.h>
+
+struct mdio_lynx_pcs {
+ struct mdio_device *dev;
+
+ void (*an_restart)(struct mdio_lynx_pcs *pcs, phy_interface_t ifmode);
+
+ void (*get_state)(struct mdio_lynx_pcs *pcs, phy_interface_t ifmode,
+ struct phylink_link_state *state);
+
+ int (*config)(struct mdio_lynx_pcs *pcs, unsigned int mode,
+ phy_interface_t ifmode,
+ const unsigned long *advertising);
+
+ void (*link_up)(struct mdio_lynx_pcs *pcs, unsigned int mode,
+ phy_interface_t ifmode, int speed, int duplex);
+};
+
+#if IS_ENABLED(CONFIG_MDIO_LYNX_PCS)
+struct mdio_lynx_pcs *mdio_lynx_pcs_create(struct mdio_device *mdio_dev);
+
+void mdio_lynx_pcs_free(struct mdio_lynx_pcs *pcs);
+#else
+static struct mdio_lynx_pcs *mdio_lynx_pcs_create(struct mdio_device *mdio_dev)
+{
+ return NULL;
+}
+
+static void mdio_lynx_pcs_free(struct mdio_lynx_pcs *pcs)
+{
+}
+#endif
+
+#endif /* __LINUX_MDIO_LYNX_PCS_H */
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 1/5] net: phylink: add interface to configure clause 22 PCS PHY
From: Ioana Ciornei @ 2020-06-18 12:08 UTC (permalink / raw)
To: netdev, davem
Cc: vladimir.oltean, claudiu.manoil, alexandru.marginean, michael,
andrew, linux, f.fainelli, Russell King, Ioana Ciornei
In-Reply-To: <20200618120837.27089-1-ioana.ciornei@nxp.com>
From: Russell King <rmk+kernel@armlinux.org.uk>
Add helper for clause 22 PCS configuration via the MII bus.
Apart from applying the advertisements, the pcs_config helper also sets
up the BMCR_ANENABLE depending on the in-band AN state.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
drivers/net/phy/phylink.c | 37 +++++++++++++++++++++++++++++++++++++
include/linux/phylink.h | 3 +++
2 files changed, 40 insertions(+)
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 0ab65fb75258..9670e8757fe1 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -2267,6 +2267,43 @@ int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs,
}
EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_set_advertisement);
+/**
+ * phylink_mii_c22_pcs_config() - configure clause 22 PCS
+ * @pcs: a pointer to a &struct mdio_device.
+ * @mode: link autonegotiation mode
+ * @interface: the PHY interface mode being configured
+ * @advertising: the ethtool advertisement mask
+ *
+ * Configure a Clause 22 PCS PHY with the appropriate negotiation
+ * parameters for the @mode, @interface and @advertising parameters.
+ * Returns negative error number on failure, zero if the advertisement
+ * has not changed, or positive if there is a change.
+ */
+int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode,
+ phy_interface_t interface,
+ const unsigned long *advertising)
+{
+ bool changed;
+ u16 bmcr;
+ int ret;
+
+ ret = phylink_mii_c22_pcs_set_advertisement(pcs, interface,
+ advertising);
+ if (ret < 0)
+ return ret;
+
+ changed = ret > 0;
+
+ bmcr = mode == MLO_AN_INBAND ? BMCR_ANENABLE : 0;
+ ret = mdiobus_modify(pcs->bus, pcs->addr, MII_BMCR,
+ BMCR_ANENABLE, bmcr);
+ if (ret < 0)
+ return ret;
+
+ return changed ? 1 : 0;
+}
+EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_config);
+
/**
* phylink_mii_c22_pcs_an_restart() - restart 802.3z autonegotiation
* @pcs: a pointer to a &struct mdio_device.
diff --git a/include/linux/phylink.h b/include/linux/phylink.h
index cc5b452a184e..d979832d0c71 100644
--- a/include/linux/phylink.h
+++ b/include/linux/phylink.h
@@ -410,6 +410,9 @@ void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs,
int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs,
phy_interface_t interface,
const unsigned long *advertising);
+int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode,
+ phy_interface_t interface,
+ const unsigned long *advertising);
void phylink_mii_c22_pcs_an_restart(struct mdio_device *pcs);
void phylink_mii_c45_pcs_get_state(struct mdio_device *pcs,
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 2/5] net: phylink: consider QSGMII interface mode in phylink_mii_c22_pcs_get_state
From: Ioana Ciornei @ 2020-06-18 12:08 UTC (permalink / raw)
To: netdev, davem
Cc: vladimir.oltean, claudiu.manoil, alexandru.marginean, michael,
andrew, linux, f.fainelli, Ioana Ciornei
In-Reply-To: <20200618120837.27089-1-ioana.ciornei@nxp.com>
The same link partner advertisement word is used for both QSGMII and
SGMII, thus treat both interface modes using the same
phylink_decode_sgmii_word() function.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
drivers/net/phy/phylink.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 9670e8757fe1..46f1e638b287 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -2186,6 +2186,7 @@ void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs,
break;
case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
phylink_decode_sgmii_word(state, lpa);
break;
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 0/5] net: phy: add Lynx PCS MDIO module
From: Ioana Ciornei @ 2020-06-18 12:08 UTC (permalink / raw)
To: netdev, davem
Cc: vladimir.oltean, claudiu.manoil, alexandru.marginean, michael,
andrew, linux, f.fainelli, Ioana Ciornei
Add support for the Lynx PCS as a separate module in drivers/net/phy/.
The advantage of this structure is that multiple ethernet or switch
drivers used on NXP hardware (ENETC, Felix DSA switch etc) can share the
same implementation of PCS configuration and runtime management.
The PCS is represented as a mdio_device and the callbacks exported are
highly tied with PHYLINK and can't be used without it.
The first 3 patches add some missing pieces in PHYLINK and the locked
mdiobus write accessor. Next, the Lynx PCS MDIO module is added as a
standalone module. The majority of the code is extracted from the Felix
DSA driver. The last patch makes the necessary changes in the Felix
driver in order to use the new common PCS implementation.
At the moment, USXGMII (only with in-band AN and speeds up to 2500),
SGMII, QSGMII and 2500Base-X (only w/o in-band AN) are supported by the
Lynx PCS MDIO module since these were also supported by Felix and no
funtional change is intended at this time.
Ioana Ciornei (4):
net: phylink: consider QSGMII interface mode in
phylink_mii_c22_pcs_get_state
net: mdiobus: add clause 45 mdiobus write accessor
net: phy: add Lynx PCS MDIO module
net: dsa: felix: use the Lynx PCS helpers
Russell King (1):
net: phylink: add interface to configure clause 22 PCS PHY
MAINTAINERS | 7 +
drivers/net/dsa/ocelot/Kconfig | 1 +
drivers/net/dsa/ocelot/felix.c | 5 +
drivers/net/dsa/ocelot/felix.h | 7 +-
drivers/net/dsa/ocelot/felix_vsc9959.c | 385 +++----------------------
drivers/net/phy/Kconfig | 6 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/mdio-lynx-pcs.c | 358 +++++++++++++++++++++++
drivers/net/phy/phylink.c | 38 +++
include/linux/fsl/enetc_mdio.h | 21 --
include/linux/mdio-lynx-pcs.h | 43 +++
include/linux/mdio.h | 6 +
include/linux/phylink.h | 3 +
13 files changed, 514 insertions(+), 367 deletions(-)
create mode 100644 drivers/net/phy/mdio-lynx-pcs.c
create mode 100644 include/linux/mdio-lynx-pcs.h
--
2.25.1
^ permalink raw reply
* Re: [PATCH 0/6] Add Microchip MCP25XXFD CAN driver
From: Manivannan Sadhasivam @ 2020-06-18 12:06 UTC (permalink / raw)
To: Marc Kleine-Budde; +Cc: wg, kernel, linux-can, netdev, linux-kernel
In-Reply-To: <fbbca009-3c53-6aa9-94ed-7e9e337c31a4@pengutronix.de>
Hi,
On 0611, Marc Kleine-Budde wrote:
> On 6/10/20 9:44 AM, Manivannan Sadhasivam wrote:
> > Hello,
> >
> > This series adds CAN network driver support for Microchip MCP25XXFD CAN
> > Controller with MCP2517FD as the target controller version. This series is
> > mostly inspired (or taken) from the previous iterations posted by Martin Sperl.
> > I've trimmed down the parts which are not necessary for the initial version
> > to ease review. Still the series is relatively huge but I hope to get some
> > reviews (post -rcX ofc!).
> >
> > Link to the origial series posted by Martin:
> > https://www.spinics.net/lists/devicetree/msg284462.html
> >
> > I've not changed the functionality much but done some considerable amount of
> > cleanups and also preserved the authorship of Martin for all the patches he has
> > posted earlier. This series has been tested on 96Boards RB3 platform by myself
> > and Martin has tested the previous version on Rpi3 with external MCP2517FD
> > controller.
>
> I initially started looking at Martin's driver and it was not using several
> modern CAN driver infrastructures. I then posted some cleanup patches but Martin
> was not working on the driver any more. Then I decided to rewrite the driver,
> that is the one I'm hoping to mainline soon.
>
> Can you give it a try?
>
> https://github.com/marckleinebudde/linux/commits/v5.6-rpi/mcp25xxfd-20200607-41
>
Tested this version on my board with MCP2518FD and it works fine. I'm okay with
moving forward with your version and would like to contribute. Please let me
know how we can move forward.
Thanks,
Mani
> Marc
>
> --
> Pengutronix e.K. | Marc Kleine-Budde |
> Embedded Linux | https://www.pengutronix.de |
> Vertretung West/Dortmund | Phone: +49-231-2826-924 |
> Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH] bpf: Allow small structs to be type of function argument
From: Jiri Olsa @ 2020-06-18 11:48 UTC (permalink / raw)
To: John Fastabend
Cc: Jiri Olsa, Alexei Starovoitov, Daniel Borkmann, netdev, bpf,
Yonghong Song, Martin KaFai Lau, Jakub Kicinski, David Miller,
Jesper Dangaard Brouer, Andrii Nakryiko, KP Singh,
Masanori Misono
In-Reply-To: <5eeaa556c7a0e_38b82b28075185c46a@john-XPS-13-9370.notmuch>
On Wed, Jun 17, 2020 at 04:20:54PM -0700, John Fastabend wrote:
> Jiri Olsa wrote:
> > This way we can have trampoline on function
> > that has arguments with types like:
> >
> > kuid_t uid
> > kgid_t gid
> >
> > which unwind into small structs like:
> >
> > typedef struct {
> > uid_t val;
> > } kuid_t;
> >
> > typedef struct {
> > gid_t val;
> > } kgid_t;
> >
> > And we can use them in bpftrace like:
> > (assuming d_path changes are in)
> >
> > # bpftrace -e 'lsm:path_chown { printf("uid %d, gid %d\n", args->uid, args->gid) }'
> > Attaching 1 probe...
> > uid 0, gid 0
> > uid 1000, gid 1000
> > ...
> >
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> > kernel/bpf/btf.c | 12 +++++++++++-
> > 1 file changed, 11 insertions(+), 1 deletion(-)
> >
> > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> > index 58c9af1d4808..f8fee5833684 100644
> > --- a/kernel/bpf/btf.c
> > +++ b/kernel/bpf/btf.c
> > @@ -362,6 +362,14 @@ static bool btf_type_is_struct(const struct btf_type *t)
> > return kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION;
> > }
> >
> > +/* type is struct and its size is within 8 bytes
> > + * and it can be value of function argument
> > + */
> > +static bool btf_type_is_struct_arg(const struct btf_type *t)
> > +{
> > + return btf_type_is_struct(t) && (t->size <= sizeof(u64));
>
> Can you comment on why sizeof(u64) here? The int types can be larger
> than 64 for example and don't have a similar check, maybe the should
> as well?
>
> Here is an example from some made up program I ran through clang and
> bpftool.
>
> [2] INT '__int128' size=16 bits_offset=0 nr_bits=128 encoding=SIGNED
>
> We also have btf_type_int_is_regular to decide if the int is of some
> "regular" size but I don't see it used in these paths.
so this small structs are passed as scalars via function arguments,
so the size limit is to fit teir value into register size which holds
the argument
I'm not sure how 128bit numbers are passed to function as argument,
but I think we can treat them separately if there's a need
jirka
>
> > +}
> > +
> > static bool __btf_type_is_struct(const struct btf_type *t)
> > {
> > return BTF_INFO_KIND(t->info) == BTF_KIND_STRUCT;
> > @@ -3768,7 +3776,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
> > /* skip modifiers */
> > while (btf_type_is_modifier(t))
> > t = btf_type_by_id(btf, t->type);
> > - if (btf_type_is_int(t) || btf_type_is_enum(t))
> > + if (btf_type_is_int(t) || btf_type_is_enum(t) || btf_type_is_struct_arg(t))
> > /* accessing a scalar */
> > return true;
> > if (!btf_type_is_ptr(t)) {
> > @@ -4161,6 +4169,8 @@ static int __get_type_size(struct btf *btf, u32 btf_id,
> > return sizeof(void *);
> > if (btf_type_is_int(t) || btf_type_is_enum(t))
> > return t->size;
> > + if (btf_type_is_struct_arg(t))
> > + return t->size;
> > *bad_type = t;
> > return -EINVAL;
> > }
> > --
> > 2.25.4
> >
>
>
^ permalink raw reply
* Re: [PATCH iproute2] tc: m_tunnel_key: fix geneve opt output
From: Davide Caratti @ 2020-06-18 11:25 UTC (permalink / raw)
To: Hangbin Liu, netdev; +Cc: lucien.xin, Simon Horman, Stephen Hemminger
In-Reply-To: <20200618104420.499155-1-liuhangbin@gmail.com>
On Thu, 2020-06-18 at 18:44 +0800, Hangbin Liu wrote:
> Commit f72c3ad00f3b changed the geneve option output from "geneve_opt"
> to "geneve_opts", which may break the program compatibility. Reset
> it back to geneve_opt.
>
> Fixes: f72c3ad00f3b ("tc: m_tunnel_key: add options support for vxlan")
> Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
> ---
> tc/m_tunnel_key.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/tc/m_tunnel_key.c b/tc/m_tunnel_key.c
> index bfec9072..0074f744 100644
> --- a/tc/m_tunnel_key.c
> +++ b/tc/m_tunnel_key.c
> @@ -534,7 +534,7 @@ static void tunnel_key_print_geneve_options(struct rtattr *attr)
> struct rtattr *i = RTA_DATA(attr);
> int ii, data_len = 0, offset = 0;
> int rem = RTA_PAYLOAD(attr);
> - char *name = "geneve_opts";
> + char *name = "geneve_opt";
> char strbuf[rem * 2 + 1];
> char data[rem * 2 + 1];
> uint8_t data_r[rem];
... by the way, this patch does not look good to me. It fixes program
compatibility for
# tc action show
but at the same time, I think it breaks program compatibility for
# tc -j action show
see below: looking at commit f72c3ad00f3b,
static void tunnel_key_print_tos_ttl(FILE *f, char *name,
@@ -519,8 +586,7 @@ static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
tb[TCA_TUNNEL_KEY_ENC_KEY_ID]);
tunnel_key_print_dst_port(f, "dst_port",
tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);
- tunnel_key_print_key_opt("geneve_opts",
- tb[TCA_TUNNEL_KEY_ENC_OPTS]);
+ tunnel_key_print_key_opt(tb[TCA_TUNNEL_KEY_ENC_OPTS])
here "name" was "geneve_opts", with the 's', and it was used here:
open_json_array(PRINT_JSON, name);
so, the proper way to restore script compatibility is to do something
like:
- print_string(PRINT_FP, name, "\t%s ", name);
+ print_string(PRINT_FP, NULL, "\t%s ", "geneve_opt");
yes, we can "harmonize" like Simon proposed, but then the fix in the
(currently broken) tdc test case should accept both 'geneve_opts' and
'geneve_opt'. Something similar has been done in the past for act_ife
see net.git commit 91fa038d9446 ("selftests: tc-testing: fix parsing of
ife type").
--
davide
^ permalink raw reply
* Re: mt7612 suspend/resume issue
From: Lorenzo Bianconi @ 2020-06-18 11:18 UTC (permalink / raw)
To: Oleksandr Natalenko
Cc: Lorenzo Bianconi, Felix Fietkau, Ryder Lee, Kalle Valo,
David S. Miller, Jakub Kicinski, Matthias Brugger, linux-wireless,
netdev, linux-mediatek, linux-kernel
In-Reply-To: <20200618090556.pepjdbnba2gqzcbe@butterfly.localdomain>
[-- Attachment #1: Type: text/plain, Size: 5362 bytes --]
> Hello, Lorenzo et al.
Hi Oleksandr,
>
> I'm using MT7612 mini-PCIE cards as both AP in a home server and as a client in
> a laptop. The AP works perfectly (after some fixing from your side; thanks for
> that!), and so does the client modulo it has issues during system resume.
>
[...]
>
> The Wi-Fi becomes unusable from this point. If I `modprobe -r` the "mt76x2e" module
> after this splat, the system hangs completely.
>
> If the system resumes fine, the resume itself takes quite some time (more than
> 10 seconds).
>
> I've found a workaround for this, though. It seems the system behaves fine if I
> do `modprobe -r mt76x2e` before it goes to sleep, and then `modprobe mt76x2e`
> after resume. Also, the resume time improves greatly.
>
> I cannot say if it is some regression or not. I've installed the card
> just recently, and used it with v5.7 kernel series only.
>
> Do you have any idea what could go wrong and how to approach the issue?
I have not reproduced the issue myself yet, but I guess we can try:
1- update to latest Felix's tree [1]
2- could you please try to apply the patch below? (compile-test only)
Regards,
Lorenzo
[1] https://github.com/nbd168/wireless
From 400268a0ee5843cf736308504dfbd2f20a291eaf Mon Sep 17 00:00:00 2001
Message-Id: <400268a0ee5843cf736308504dfbd2f20a291eaf.1592478809.git.lorenzo@kernel.org>
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 18 Jun 2020 13:10:11 +0200
Subject: [PATCH] mt76: mt76x2: fix pci suspend
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
.../net/wireless/mediatek/mt76/mt76x02_dma.h | 1 +
.../net/wireless/mediatek/mt76/mt76x02_mmio.c | 15 +++++
.../net/wireless/mediatek/mt76/mt76x2/pci.c | 58 +++++++++++++++++++
3 files changed, 74 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h
index 4aff4f8e87b6..6262f2ecded5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h
@@ -62,5 +62,6 @@ mt76x02_wait_for_wpdma(struct mt76_dev *dev, int timeout)
int mt76x02_dma_init(struct mt76x02_dev *dev);
void mt76x02_dma_disable(struct mt76x02_dev *dev);
void mt76x02_dma_cleanup(struct mt76x02_dev *dev);
+void mt76x02_dma_reset(struct mt76x02_dev *dev);
#endif /* __MT76x02_DMA_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index cbbe986655fe..e2631c964331 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -348,6 +348,21 @@ void mt76x02_dma_disable(struct mt76x02_dev *dev)
}
EXPORT_SYMBOL_GPL(mt76x02_dma_disable);
+void mt76x02_dma_reset(struct mt76x02_dev *dev)
+{
+ int i;
+
+ mt76x02_dma_disable(dev);
+ usleep_range(1000, 2000);
+
+ for (i = 0; i < __MT_TXQ_MAX; i++)
+ mt76_queue_tx_cleanup(dev, i, true);
+ mt76_for_each_q_rx(&dev->mt76, i)
+ mt76_queue_rx_reset(dev, i);
+
+ mt76x02_dma_enable(dev);
+}
+
void mt76x02_mac_start(struct mt76x02_dev *dev)
{
mt76x02_mac_reset_counters(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
index 53ca0cedf026..5543e242fb9b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
@@ -103,6 +103,60 @@ mt76pci_remove(struct pci_dev *pdev)
mt76_free_device(mdev);
}
+static int __maybe_unused
+mt76x2e_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct mt76_dev *mdev = pci_get_drvdata(pdev);
+ struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
+ int i, err;
+
+ napi_disable(&mdev->tx_napi);
+ tasklet_kill(&mdev->pre_tbtt_tasklet);
+ tasklet_kill(&mdev->tx_tasklet);
+
+ mt76_for_each_q_rx(mdev, i)
+ napi_disable(&mdev->napi[i]);
+
+ mt76x02_dma_reset(dev);
+
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), true);
+ pci_save_state(pdev);
+ err = pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ if (err)
+ goto restore;
+
+ return 0;
+
+restore:
+ mt76_for_each_q_rx(mdev, i)
+ napi_enable(&mdev->napi[i]);
+ napi_enable(&mdev->tx_napi);
+
+ return err;
+}
+
+static int __maybe_unused
+mt76x2e_resume(struct pci_dev *pdev)
+{
+ struct mt76_dev *mdev = pci_get_drvdata(pdev);
+ int i, err;
+
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err)
+ return err;
+
+ pci_restore_state(pdev);
+
+ mt76_for_each_q_rx(mdev, i) {
+ napi_enable(&mdev->napi[i]);
+ napi_schedule(&mdev->napi[i]);
+ }
+ napi_enable(&mdev->tx_napi);
+ napi_schedule(&mdev->tx_napi);
+
+ return 0;
+}
+
MODULE_DEVICE_TABLE(pci, mt76pci_device_table);
MODULE_FIRMWARE(MT7662_FIRMWARE);
MODULE_FIRMWARE(MT7662_ROM_PATCH);
@@ -113,6 +167,10 @@ static struct pci_driver mt76pci_driver = {
.id_table = mt76pci_device_table,
.probe = mt76pci_probe,
.remove = mt76pci_remove,
+#ifdef CONFIG_PM
+ .suspend = mt76x2e_suspend,
+ .resume = mt76x2e_resume,
+#endif /* CONFIG_PM */
};
module_pci_driver(mt76pci_driver);
--
2.26.2
>
> Thanks.
>
> --
> Best regards,
> Oleksandr Natalenko (post-factum)
> Principal Software Maintenance Engineer
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply related
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